SpringMVC

1.入门程序
1.1导入jar包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <properties> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies>
|
1.2配置核心的控制器(配置DispatcherServlet)
在web.xml配置文件中核心控制器DispatcherServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
1.3编写springmvc.xml的配置文件
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.itheima"></context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
|
1.4编写index.jsp和HelloController控制器类
index.jsp
1 2 3 4
| <body> <h3>入门案例</h3> <a href="${ pageContext.request.contextPath }/hello">入门案例</a> </body>
|
HelloController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package cn.itcast.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class HelloController {
@RequestMapping(path="/hello") public String sayHello() { System.out.println("Hello SpringMVC!!"); return "success"; } }
|
1.5在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
1 2 3
| <body> <h3>入门成功!!</h3> </body>
|
1.6启动Tomcat服务器,进行测试
1.7SpringMVC 的请求响应流程

2.RequestMapping 注解
作用:用于建立请求 URL 和处理请求方法之间的对应关系
出现位置:
类上:请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它出现的目的是为了使我们的 URL 可以按照模块化管理:
例如:
账户模块:
/account/add
/account/update
/account/delete
订单模块:
/order/add
/order/update
/order/delete
红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
方法上:
请求 URL 的第二级访问目录。
属性:
value
:用于指定请求的 URL。它和 path 属性的作用是一样的。
method
:用于指定请求的方式。
params
:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
例如:
params = {“accountName”},表示请求参数必须有 accountName
params = {“moeny!100”},表示请求参数中 money 不能是 100。
headers
:用于指定限制请求消息头的条件。
注意:
以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。
举例:请求地址为/account/findAccount
1 2 3 4 5 6 7 8 9 10 11 12 13
| 控制器代码:
@Controller("accountController") @RequestMapping("/account") public class AccountController { @RequestMapping("/findAccount") public String findAccount() { System.out.println("查询了账户。。。。"); return "success"; } }
|
method 属性的示例:
1 2 3 4 5 6 7 8 9
|
@RequestMapping(value="/saveAccount",method=RequestMethod.POST) public String saveAccount() { System.out.println("保存了账户"); return "success"; }
|
params 属性的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@RequestMapping(value="/removeAccount",params= {"accountName","money>100"}) public String removeAccount() { System.out.println("删除了账户"); return "success"; } <a href="account/removeAccount?accountName=aaa&money>100">删除账户,金额 100</a> <br/> <a href="account/removeAccount?accountName=aaa&money>150">删除账户,金额 150</a>
|
当我们点击第一个超链接时,可以访问成功。
当我们点击第二个超链接时,无法访问。如下图:

3 .请求参数的绑定
1 2 3 4 5 6 7 8 9 10 11 12
| <a href="account/findAccount?accountId=10">查询账户</a> 中请求参数是: accountId=10
@RequestMapping("/findAccount") public String findAccount(Integer accountId) { System.out.println("查询了账户。。。。"+accountId); return "success"; }
|
支持的数据类型:
基本类型参数:包括基本类型和 String 类型
POJO 类型参数:包括实体类,以及关联的实体类
数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
使用要求:
如果是基本类型或者 String 类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO 类型,或者它的关联对象:
要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
如果是集合类型,有两种方式:
第一种:
要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。
第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
3.1基本类型和 String 类型作为参数
1 2 3 4 5 6 7 8 9 10 11 12 13
| jsp 代码: <!-- 基本类型示例 --> <a href="account/findAccount?accountId=10&accountName=zhangsan">查询账户</a> 控制器代码:
@RequestMapping("/findAccount") public String findAccount(Integer accountId,String accountName) { System.out.println("查询了账户。。。。"+accountId+","+accountName); return "success"; }
|
3.2POJO 类型作为参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| 实体类代码:
public class Account implements Serializable { private Integer id; private String name; private Float money; private Address address; }
public class Address implements Serializable { private String provinceName; private String cityName; }
jsp 代码: <!-- pojo 类型演示 --> <form action="account/saveAccount" method="post"> 账户名称:<input type="text" name="name" ><br/> 账户金额:<input type="text" name="money" ><br/> 账户省份:<input type="text" name="address.provinceName" ><br/> 账户城市:<input type="text" name="address.cityName" ><br/> <input type="submit" value="保存"> </form> 控制器代码:
@RequestMapping("/saveAccount") public String saveAccount(Account account) { System.out.println("保存了账户。。。。"+account); return "success"; }
|
3.3POJO 类中包含集合类型参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| 实体类代码:
public class User implements Serializable { private String username; private String password; private Integer age; private List<Account> accounts; private Map<String,Account> accountMap; @Override public String toString() { return "User [username=" + username + ", password=" + password + ", age="+ age + ",\n accounts=" + accounts+ ",\n accountMap=" + accountMap + "]"; } }
jsp 代码: <!-- POJO 类包含集合类型演示 --> <form action="account/updateAccount" method="post"> 用户名称:<input type="text" name="username" ><br/> 用户密码:<input type="password" name="password" ><br/> 用户年龄:<input type="text" name="age" ><br/> 账户 1 名称:<input type="text" name="accounts[0].name" ><br/> 账户 1 金额:<input type="text" name="accounts[0].money" ><br/> 账户 2 名称:<input type="text" name="accounts[1].name" ><br/> 账户 2 金额:<input type="text" name="accounts[1].money" ><br/> 账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/> 账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/> 账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/> 账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/> <input type="submit" value="保存"> </form> 控制器代码:
@RequestMapping("/updateAccount") public String updateAccount(User user) { System.out.println("更新了账户。。。。"+user); return "success"; }
|

3.4自定义类型转换器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!-- 特殊情况之:类型转换问题 --> <a href="account/deleteAccount?date=2018-01-01">根据日期删除账户</a> 控制器代码:
@RequestMapping("/deleteAccount") public String deleteAccount(String date) { System.out.println("删除了账户。。。。"+date); return "success"; } 运行结果
|

1 2 3 4 5 6 7 8 9 10 11
| 当我们把控制器中方法参数的类型改为 Date 时
@RequestMapping("/deleteAccount") public String deleteAccount(Date date) { System.out.println("删除了账户。。。。"+date); return "success"; } 运行结果:
|

3.4.1使用步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 第一步:定义一个类,实现 Converter 接口,该接口有两个泛型。 public interface Converter<S, T> {
@Nullable T convert(S source); }
public class StringToDateConverter implements Converter<String, Date> {
@Override public Date convert(String source) { DateFormat format = null; try { if(StringUtils.isEmpty(source)) { throw new NullPointerException("请输入要转换的日期"); } format = new SimpleDateFormat("yyyy-MM-dd"); Date date = format.parse(source); return date; } catch (Exception e) { throw new RuntimeException("输入日期有误"); } } }
|
第二步:在 spring 配置文件中配置类型转换器。
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <bean id="converterService"class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters"> <array> <bean class="com.itheima.web.converter.StringToDateConverter"></bean> </array> </property> </bean> 第三步:在 annotation-driven 标签中引用配置的类型转换服务 <mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
|
4常用注解
4.1RequestParam
作用:把请求中指定名称的参数给控制器中的形参赋值。
属性:value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| jsp 中的代码: <!-- requestParams 注解的使用 --> <a href="springmvc/useRequestParam?name=test">requestParam 注解</a> 控制器中的代码:
@RequestMapping("/useRequestParam") public String useRequestParam(@RequestParam("name")String username,@RequestParam(value="age",required=false)Integer age){ System.out.println(username+","+age); return "success"; }
|
4.2RequestBody
作用:用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。
get 请求方式不适用。
属性:required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| post 请求 jsp 代码: <!-- request body 注解 --> <form action="springmvc/useRequestBody" method="post"> 用户名称:<input type="text" name="username" ><br/> 用户密码:<input type="password" name="password" ><br/> 用户年龄:<input type="text" name="age" ><br/> <input type="submit" value="保存"> </form> get 请求 jsp 代码: <a href="springmvc/useRequestBody?body=test">requestBody 注解 get 请求</a> 控制器代码:
@RequestMapping("/useRequestBody") public String useRequestBody(@RequestBody(required=false) String body){ System.out.println(body); return "success"; }
|

4.3PathVaribale
作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/**{id},这个{id}**就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| jsp 代码: <!-- PathVariable 注解 --> <a href="springmvc/usePathVariable/100">pathVariable 注解</a>
控制器代码:
@RequestMapping("/usePathVariable/{id}") public String usePathVariable(@PathVariable("id") Integer id){ System.out.println(id); return "success"; }
|
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| jsp 中代码: <!-- RequestHeader 注解 --> <a href="springmvc/useRequestHeader">获取请求消息头</a> 控制器中代码:
@RequestMapping("/useRequestHeader") public String useRequestHeader(@RequestHeader(value="Accept-Language",required=false)String requestHeader){ System.out.println(requestHeader); return "success"; }
|
4.5CookieValue
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| jsp 中的代码: <!-- CookieValue 注解 --> <a href="springmvc/useCookieValue">绑定 cookie 的值</a> 控制器中的代码:
@RequestMapping("/useCookieValue") public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) String cookieValue){ System.out.println(cookieValue); return "success"; }
|
4.6ModelAttribute
作用:
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可
以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
4.6.1 基于 POJO 属性的基本使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| jps 代码: <!-- ModelAttribute 注解的基本使用 --> <a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a> 控制器代码:
@ModelAttribute public void showModel(User user) { System.out.println("执行了 showModel 方法"+user.getUsername()); }
@RequestMapping("/testModelAttribute") public String testModelAttribute(User user) { System.out.println("执行了控制器的方法"+user.getUsername()); return "success"; }
|

4.6.2 基于 Map 的应用场景示例
ModelAttribute 修饰方法带返回值
需求:
修改用户信息,要求用户的密码不能修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| jsp 的代码: <!-- 修改用户信息 --> <form action="springmvc/updateUser" method="post"> 用户名称:<input type="text" name="username" ><br/> 用户年龄:<input type="text" name="age" ><br/> <input type="submit" value="保存"> </form> 控制的代码:
@ModelAttribute public User showModel(String username) { User abc = findUserByName(username); System.out.println("执行了 showModel 方法"+abc); return abc; }
@RequestMapping("/updateUser") public String testModelAttribute(User user) { System.out.println("控制器中处理请求的方法:修改用户:"+user); return "success"; }
private User findUserByName(String username) { User user = new User(); user.setUsername(username); user.setAge(19); user.setPassword("123456"); return user; }
|

ModelAttribute 修饰方法不带返回值
需求:
修改用户信息,要求用户的密码不能修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| jsp 中的代码: <!-- 修改用户信息 --> <form action="springmvc/updateUser" method="post"> 用户名称:<input type="text" name="username" ><br/> 用户年龄:<input type="text" name="age" ><br/> <input type="submit" value="保存"> </form> 控制器中的代码:
@ModelAttribute public void showModel(String username,Map<String,User> map) { User user = findUserByName(username); System.out.println("执行了 showModel 方法"+user); map.put("abc",user); }
@RequestMapping("/updateUser") public String testModelAttribute(@ModelAttribute("abc")User user) { System.out.println("控制器中处理请求的方法:修改用户:"+user); return "success"; }
private User findUserByName(String username) { User user = new User(); user.setUsername(username); user.setAge(19); user.setPassword("123456"); return user; }
|

4.7SessionAttribute
作用:
用于多次执行控制器方法间的参数共享。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| jsp 中的代码: <!-- SessionAttribute 注解的使用 --> <a href="springmvc/testPut">存入 SessionAttribute</a> <hr/> <a href="springmvc/testGet">取出 SessionAttribute</a> <hr/> <a href="springmvc/testClean">清除 SessionAttribute</a> 控制器中的代码:
@Controller("sessionAttributeController") @RequestMapping("/springmvc") @SessionAttributes(value ={"username","password"},types={Integer.class}) public class SessionAttributeController {
@RequestMapping("/testPut") public String testPut(Model model){ model.addAttribute("username", "泰斯特"); model.addAttribute("password","123456"); model.addAttribute("age", 31); return "success"; } @RequestMapping("/testGet") public String testGet(ModelMap model){ System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a ge")); return "success"; } @RequestMapping("/testClean") public String complete(SessionStatus sessionStatus){ sessionStatus.setComplete(); return "success"; } }
|

5.响应数据和结果视图
5.1返回值分类
字符串
1 2 3 4 5
| @RequestMapping("/testReturnString") public String testReturnString() { System.out.println("AccountController 的 testReturnString 方法执行了。。。。"); return "success"; }
|
void
1 2 3 4
| @RequestMapping("/testReturnVoid") public void testReturnVoid(HttpServletRequest request,HttpServletResponse response) throws Exception { }
|
在 controller 方法形参上可以定义 request 和 response,使用 request 或 response 指定响应结果:
1、使用 request 转向页面,如下:
1
| request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
|
2、也可以通过 response 页面重定向:
1
| response.sendRedirect("testRetrunString")
|
3、也可以通过response 指定响应结果,例如响应 json 数据:
1 2 3
| response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json 串");
|
ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 示例代码:
@RequestMapping("/testReturnModelAndView") public ModelAndView testReturnModelAndView() { ModelAndView mv = new ModelAndView(); mv.addObject("username", "张三"); mv.setViewName("success"); return mv; }
响应的 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"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>执行成功</title> </head> <body> 执行成功! ${requestScope.username} </body> </html>
|

5.2转发和重定向
forward 转发
1 2 3 4 5 6 7 8 9 10 11 12 13
| controller 方法在提供了 String 类型的返回值之后,默认就是请求转发。我们也可以写成:
@RequestMapping("/testForward") public String testForward() { System.out.println("AccountController 的 testForward 方法执行了。。。。"); return "forward:/WEB-INF/pages/success.jsp"; } 需要注意的是,如果用了 formward:则路径必须写成实际视图 url,不能写逻辑视图。 它相当于“request.getRequestDispatcher("url").forward(request,response)”。使用请求 转发,既可以转发到 jsp,也可以转发到其他的控制器方法。
|
Redirect 重定向
1 2 3 4 5 6 7 8 9 10 11 12
| contrller 方法提供了一个 String 类型返回值之后,它需要在返回值里使用:redirect:
@RequestMapping("/testRedirect") public String testRedirect() { System.out.println("AccountController 的 testRedirect 方法执行了。。。。"); return "redirect:testReturnModelAndView"; } 它相当于“response.sendRedirect(url)”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不 能写在 WEB-INF 目录中,否则无法找到。
|
5.3ResponseBody 响应 json 数据
作用:
该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如:json,xml 等,通过 Response 响应给客户端
需求:
使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端。
前置知识点:
Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| jsp 中的代码: <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script> <script type="text/javascript"> $(function(){ $("#testJson").click(function(){ $.ajax({ type:"post", url:"${pageContext.request.contextPath}/testResponseJson", contentType:"application/json;charset=utf-8", data:'{"id":1,"name":"test","money":999.0}', dataType:"json", success:function(data){ alert(data); } }); }); }) </script> <!-- 测试异步请求 --> <input type="button" value="测试 ajax 请求 json 和响应 json" id="testJson"/> 控制器中的代码:
@Controller("jsonController") public class JsonController {
@RequestMapping("/testResponseJson") public @ResponseBody Account testResponseJson(@RequestBody Account account) { System.out.println("异步请求:"+account); return account; } }
|