Spring Web MVC
官方文档的介绍:
The Spring Web model-view-controller (MVC) framework is designed around a DispatcherServlet that dispatches requests to handlers, with configurable handler mappings, view resolution, locale, time zone and theme resolution as well as support for uploading files. The default handler is based on the @Controller and @RequestMapping annotations, offering a wide range of flexible handling methods.
要想深入理解还需要多看官方文档,多实践操作才行,这里只是简单的介绍哈,对我们入门来说只要了解这么多就可以了。
Spring Web MVC最核心的几个几部分包括:
前端控制器:DispatcherServlet;
应用控制器:HandlerMapping(处理映射)、ViewResolver(视图解析);
页面控制器:ModelAndView
一般我们用到这几个就可以了,当然复杂的还要了解许多其他的。
下面我们来写一个小例子:
新建一个项目,然后了加入如下的jar包:
新建HelloController.java
package cn.ailot.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/spring")
public class HelloController{
@RequestMapping("/hello.form")
public String execute() throws Exception{
System.out.println("执行HelloController");
//这里返回的hello就是试图解析器里面的hello.jsp页面
return "hello";
}
}
然后在src文件夹下面新建一个名为sping-mvc.xml的文件,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 开启@RequestMapping注解映射 -->
<mvc:annotation-driven/>
<!--开启组件扫描定义-->
<context:component-scan base-package="cn.ailot.web"></context:component-scan>
<!-- 定义视图解析器ViewResolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
接下来配置web.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>springmvc</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 处理编码问题 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- 加载sping配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</context-param>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--启动容器的时候初始化改servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--servlet映射-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
现在就可以启动服务试试,看能否正常启动,如果可以就表示配置没错。
地址栏里输入:http://localhost:8080/springmvc/spring/hello.form
会看到hello.jsp的内容:
以上就是一个简单的Spring MVC的例子。
下面我们来做一个登录的案例,Sping MVC接受参数有好多种方法,最常用到的有:
1、HttpServletRequest获取;
2、@RequestParam注解;
3、封装成实体参数。
下面我们来一个一个的实现,
实体user.java
package cn.ailot.entity;
public class User {
private int id;
private String name;
private String pwd;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
接口UserDao.java
package cn.ailot.dao;
import cn.ailot.entity.User;
/**
* 用户数据访问接口
* @author litao
*
*/
public interface UserDao {
/**
* 根据用户名查找系统用户
* @param name
* @return
*/
public User findByName(String name);
}
异常捕获:
用户名或密码错:
NameOrPwdException.java
package cn.ailot.service;
public class NameOrPwdException extends Exception {
public NameOrPwdException(){}
public NameOrPwdException(String message){
super(message);
}
public NameOrPwdException(Throwable cause){
super(cause);
}
public NameOrPwdException(String message,Throwable cause){
super(message,cause);
}
}
空值异常:
NullParamException.java
package cn.ailot.service;
public class NullParamException extends Exception{
public NullParamException(){}
public NullParamException(String message){
super(message);
}
public NullParamException(String message,Throwable cause){
super(message,cause);
}
}
业务实现UserService.java
package cn.ailot.service;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.ailot.dao.UserDao;
import cn.ailot.entity.User;
@Service
public class UserService {
@Autowired
private UserDao userDao;
/**
* 登录系统
* @throws NameOrPwdException
* @throws NullParamException
*/
public User login(String name,String pwd) throws NameOrPwdException, NullParamException{
if(name==null||name.equals("") || pwd == null|| pwd.equals("")){
throw new NullParamException("登录参数不能为空!");
}
User user = userDao.findByName(name);
if(user != null && pwd.equals(user.getPwd())){
return user;
}
throw new NameOrPwdException("用户名或密码错误");
}
}
配置数据库连接:
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
user=root
pwd=root
数据库脚本:
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` varchar(10) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`pwd` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (‘1‘, ‘admin‘, ‘admin‘);
spring-mvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 实例化本地数据库连接参数 -->
<util:properties id="jdbcProps" location="classpath:db.properties"/>
<!-- 开启@RequestMapping注解映射 -->
<mvc:annotation-driven/>
<!--开启组件扫描定义-->
<context:component-scan base-package="cn.ailot"></context:component-scan>
<!-- 定义视图解析器ViewResolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
创建数据库连接:
package cn.ailot.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class JdbcDataSource{
private String driver;
@Value("#{jdbcProps.url}")
private String url;
@Value("#{jdbcProps.user}")
private String user;
@Value("#{jdbcProps.pwd}")
private String pwd;
public String getDriver() {
return driver;
}
/*必须写在set方法上,否则注入无效*/
@Value("#{jdbcProps.driver}")
public void setDriver(String driver) {
try{
Class.forName(driver);
this.driver = driver;
}catch(Exception e){
throw new RuntimeException(e);
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Connection getConnection() throws SQLException{
Connection conn = DriverManager.getConnection(url,user,pwd);
return conn;
}
public void close(Connection conn){
if(conn!=null){
try {
conn.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
执行数据库操作:
MysqlUserDao.java
package cn.ailot.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import cn.ailot.entity.User;
@Repository("userDao") //必须指定Bean ID,否则默认加载的是mysqlUserDao
public class MysqlUserDao implements UserDao{
@Autowired
private JdbcDataSource dataSource;
/**
* 根据唯一用户名查询系统用户,如果没有找到用户信息返回null
*/
@Override
public User findByName(String name) {
// TODO Auto-generated method stub
System.out.println("利用JDBC技术");
String sql = "select id,name,pwd from users where name=?";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
User user = null;
while(rs.next()){
user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPwd(rs.getString("pwd"));
}
rs.close();
ps.close();
return user;
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}finally{
dataSource.close(conn);
}
}
}
接下来写一个JUnit测试,
TestCase.java
package cn.ailot.test;
import java.util.Properties;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.ailot.dao.JdbcDataSource;
import cn.ailot.entity.User;
import cn.ailot.service.UserService;
public class TestCase {
@Test
public void testUserService() throws Exception{
String cfg = "spring-mvc.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(cfg);
//打印加载的bean名称
System.out.println(java.util.Arrays.toString(ac.getBeanDefinitionNames()));
Properties obj = ac.getBean("jdbcProps",Properties.class);
JdbcDataSource ds = ac.getBean("jdbcDataSource",JdbcDataSource.class);
System.out.println(obj);
System.out.println(ds);
System.out.println(ds.getConnection());
UserService service = ac.getBean("userService",UserService.class);
User user = service.login("admin", "admin");
System.out.println(user);
}
}
然后右键->Run As->JUnit Test
如果代码无误,会出现如下显示:
接下就要构建登录的具体方法了(类似struts中的action):
LoginController.java
(同时写了三种接受参数的方法)
package cn.ailot.controller;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import cn.ailot.entity.User;
import cn.ailot.service.NameOrPwdException;
import cn.ailot.service.NullParamException;
import cn.ailot.service.UserService;
@Controller
@RequestMapping("/login")
public class LoginController{
@Resource //请求sping注入资源userService
private UserService userService;
@RequestMapping("/login.form")
public String loginForm(){
//可以向表单传递一些参数
return "loginForm"; //映射到loginForm.jsp
}
/**
* 利用HttpServletRequest对象进行传参
* @param req
* @return
*/
@RequestMapping("/loginAction1.form")
//spring MVC自动参数注入HttpServletRequest
public String checLogin1(HttpServletRequest req){
System.out.println("--方法一--");
//优点,直接简洁,缺点,需要自己处理数据类型转换
String name = req.getParameter("name");
String pwd = req.getParameter("pwd");
System.out.println(name);
System.out.println(pwd);
try {
User user = userService.login(name, pwd);
//登录成功将登录信息保存到当前会话中
req.getSession().setAttribute("user", user);
return "success"; //映射到登录成功的success.jsp
} catch (NameOrPwdException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "loginForm"; //映射到登录页面loginForm.jsp
} catch (NullParamException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "redirect:login.form";//重定向
} catch (RuntimeException e){
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "error";
}
}
/**
* 使用@RequestParam注解获取请求参数的值
* @param name
* @param pwd
* @param req
* @return
*/
@RequestMapping("/loginAction2.form")
public String checLogin2(
String name,
@RequestParam("pwd")String pwd, //映射表单属性不同的参数
HttpServletRequest req){
System.out.println("--方法二--");
//优点,自动转换数据类型,缺点,可能出现数据类型转换异常
System.out.println(name);
System.out.println(pwd);
try {
User user = userService.login(name, pwd);
//登录成功将登录信息保存到当前会话中
req.getSession().setAttribute("user", user);
return "success"; //映射到success.jsp
} catch (NameOrPwdException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "loginForm";
} catch (NullParamException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "loginForm";
} catch (RuntimeException e){
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "error";
}
}
/**
* 使用自动机制封装成实体参数的方式获取请求参数的值
* @param user
* @param req
* @return
*/
@RequestMapping("/loginAction3.form")
public String checLogin3(User user,HttpServletRequest req){
System.out.println("--方法三--");
//自动填充到bean对象
System.out.println(user);
try {
user = userService.login(user.getName(), user.getPwd());
//登录成功将登录信息保存到当前会话中
req.getSession().setAttribute("user", user);
return "success"; //映射到success.jsp
} catch (NameOrPwdException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "loginForm";
} catch (NullParamException e) {
// TODO: handle exception
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "loginForm";
} catch (RuntimeException e){
e.printStackTrace();
req.setAttribute("message", e.getMessage());
return "error";
}
}
}
登录页面:
loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!-- 获取项目基本路径 -->
<c:url var="base" value="/"></c:url>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>LoginForm</title>
<link rel="stylesheet" type="text/css" href="${base }css/style.css">
</head>
<body>
<h6>${message }</h6>
<%-- <h6>${next }</h6> --%>
<form method="post" action="${base }login/loginAction1.form">
<div>
<h2>登录 loginAction1.form</h2>
<p><label>用户</label><input type="text" name="name"></p>
<p><label>密码</label><input type="password" name="pwd"></p>
<h3><input type="submit" value="登录"></h3>
</div>
</form>
<form method="post" action="${base }login/loginAction2.form">
<div>
<h2>登录 loginAction2.form</h2>
<p><label>用户</label><input type="text" name="name"></p>
<p><label>密码</label><input type="password" name="pwd"></p>
<h3><input type="submit" value="登录"></h3>
</div>
</form>
<form method="post" action="${base }login/loginAction3.form">
<div>
<h2>登录 loginAction3.form</h2>
<p><label>用户</label><input type="text" name="name"></p>
<p><label>密码</label><input type="password" name="pwd"></p>
<h3><input type="submit" value="登录"></h3>
</div>
</form>
</body>
</html>
需要注意的是,这里我用到的是JSTL标签,所以在lib里面要引入jstl.jar、standard.jar这个两个包。
样式文件style.css
*{
margin:0;
padding:0;
}
h6{
text-align: center;
color: red;
padding:10px;
font-size:14px;
}
form{
padding:10px;
float:left;
}
form div{
border:1px gray solid;
width:320px;
padding:8px;
}
form p input{
widht:180px;
}
form h2 input {
text-align:center;
}
form h2{
background: black;
color:white;
padding:4px;
}
form p{
background:#ddd;
padding:4px 8px 0 8px;
}
form h3{
background: #ddd;
padding:8px;
}
在浏览器里输入http://localhost:8080/springmvc/login/login.form
运行结果如图所示:
添加登录成功的页面success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:url var="base" value="/"></c:url>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>success</title>
<link rel="stylesheet" type="text/css" href="${base }css/style.css">
</head>
<body>
<center>
<h2>${user.name }登录成功</h2>
</center>
</body>
</html>
输入用户名和密码admin登录就可以看到登录成功的界面。
源码:下载地址