三、SpringMVC 注解开发
3.1 基本步骤
3.1.1 前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 前端控制器 -->
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/views/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
3.1.2 mvc命名空间与标签规范
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
</beans>
3.1.3 组件扫描
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.newcapec.controller"/>
3.1.4 MVC注解驱动
SpringMVC使用 `<mvc:annotation-driven>` 自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器),并且默认加载了很多参数绑定的方法,比如json转换解析器。可用在springmvc.xml配置文件中使用`<mvc:annotation-driven>`替代注解处理器和适配器的配置。
<!-- 注解式的处理器映射器 -->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!-- 注解式的处理器适配器 -->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--
mvc注解驱动:默认加载了注解式的处理器映射器和处理器适配器,默认转化器的配置
-->
<mvc:annotation-driven/>
3.1.5 视图解析器
配置视图解析器的前缀和后缀,可简化视图的访问地址。
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图地址的前缀和后缀:简化视图地址 -->
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
配置视图解析器的前缀与后缀访问路径的变化:
-
物理视图名称:配置之前,视图的真实访问路径为,/views/success.jsp
-
逻辑视图名称:配置之后,视图的简化访问路径为,success
-
物理视图名 = 前缀 + 逻辑视图名 + 后缀
3.1.6 处理器
@Controller
public class UserController {
/**
* 新增请求
*
* @RequestMapping 位置:类和方法
* 作用:将请求路径与处理请求的方法关联
* 注意:在配置路径时,路径需要以/开头
*/
@RequestMapping("/addUser.do")
public ModelAndView addUser() {
System.out.println("新增用户请求...");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", "add user");
/**
* 配置视图解析器的前后缀之后访问路径的变化:/views/ /views/success.jsp .jsp
* 在ModelAndView对象中设置的视图地址:逻辑视图名称 != 视图访问路径(物理视图名称)
* 视图访问地址 = 前缀 + 逻辑视图名称 + 后缀
*/
//modelAndView.setViewName("/views/success.jsp");
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping("/editUser.do")
public ModelAndView editUser() {
System.out.println("编辑用户请求...");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", "edit user");
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping("/removeUser.do")
public ModelAndView removeUser() {
System.out.println("删除用户请求...");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", "remove user");
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping("/findUser.do")
public ModelAndView findUser() {
System.out.println("查询用户请求...");
//模拟数据
List<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("tom");
list.add("jerry");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("list", list);
modelAndView.setViewName("success");
return modelAndView;
}
}
3.1.7 视图
在webapp目录下建立“views”子目录,所有视图放置在“views”子目录中。
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>首页</h1>
<p><a href="addUser.do">新增用户</a></p>
<p><a href="editUser.do">编辑用户</a></p>
<p><a href="removeUser.do">删除用户</a></p>
<p><a href="findUser.do">查询用户</a></p>
<p><a href="url.do">路径映射1</a></p>
<p><a href="getUrl.do">路径映射2</a></p>
<p><a href="test.do">路径映射3</a></p>
<p><a href="api/add.do">路径前缀</a></p>
<p><a href="api/find.do">请求方法的限制</a></p>
<form action="api/find.do" method="post">
<button type="submit">提交</button>
</form>
<p><a href="forwardPage.do">请求转发到视图</a></p>
<p><a href="redirectPage.do">重定向到视图</a></p>
<p><a href="forwardController.do">请求转发到Controller</a></p>
<p><a href="redirectController.do">重定向到Controller</a></p>
<p><a href="returnVoid.do">无返回值</a></p>
<p><a href="modelParam.do">Model类型的形参</a></p>
<p><a href="views/simple.jsp">简单类型的形参</a></p>
<p><a href="requestParam.do?empno=20">@RequestParam</a></p>
<p><a href="dateTimeFormat.do?date=2022-03-21">@DateTimeFormat</a></p>
<p><a href="requestHeader.do">@RequestHeader</a></p>
<p><a href="setCookie.do">设置Cookie</a></p>
<p><a href="getCookie.do">获取Cookie</a></p>
<p><a href="views/pojo.jsp">POJO类型的形参</a></p>
<p><a href="getBirthday.do?birthday=1993-04-17">Converter</a></p>
<p><a href="getPoint.do?myPoint=125,369">Formatter</a></p>
<p><a href="views/array.jsp">数组类型的形参</a></p>
<p><a href="views/list.jsp">集合类型的形参</a></p>
<p><a href="getUser.do">SessionAttribute</a></p>
<p><a href="views/login.jsp">登录</a></p>
</div>
</body>
</html>
success.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>响应页面</h1>
<p>${message}</p>
<ul>
<c:forEach items="${list}" var="s">
<li>${s}</li>
</c:forEach>
</ul>
</div>
</body>
</html>
3.2 @ResquestMapping注解
一个控制器内有多个处理请求的方法,如 UserController 里通常有增加用户、修改用户信息、删除指定用户、根据条件获取用户列表等。每个方法负责不同的请求操作,而 @RequestMapping 就负责将请求映射到对应的控制器方法上。
在基于注解的控制器类中可以为每个请求编写对应的处理方法。使用 @RequestMapping 注解将请求与处理方法一 一对应即可。
@RequestMapping 注解可用于类或方法上。用于类上,表示类中的所有响应请求的方法都以该地址作为父路径。
@RequestMapping 注解常用属性如下:
1、value 属性
value 属性是 @RequestMapping 注解的默认属性,因此如果只有 value 属性时,可以省略该属性名,如果有其它属性,则必须写上 value 属性名称。
@RequestMapping(value="toUser")
@RequestMapping("toUser")
value 属性支持通配符匹配,如 @RequestMapping(value="toUser/*") 表示 http://localhost:8080/toUser/1 或 http://localhost:8080/toUser/hahaha 都能够正常访问。
2、path 属性
path 属性和 value 属性都用来作为映射使用。即 @RequestMapping(value="toUser") 和 @RequestMapping(path="toUser") 都能访问 toUser() 方法。
3、name 属性
name属性相当于方法的注释,使方法更易理解。如 @RequestMapping(value = "toUser",name = "获取用户信息")。
4、method 属性
method 属性用于表示该方法支持哪些 HTTP 请求。如果省略 method 属性,则说明该方法支持全部的 HTTP 请求。
5、params 属性
params 属性用于指定请求中规定的参数。
@RequestMapping(value = "toUser",params = "type")
以上代码表示请求中必须包含 type 参数时才能执行该请求。即 http://localhost:8080/toUser?type=xxx 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser 则不能正常访问 toUser() 方法。
@RequestMapping(value = "toUser",params = "type=1")
以上代码表示请求中必须包含 type 参数,且 type 参数为 1 时才能够执行该请求。即 http://localhost:8080/toUser?type=1 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser?type=2 则不能正常访问 toUser() 方法。
6、header 属性
header 属性表示请求中必须包含某些指定的 header 值。
@RequestMapping(value = "toUser",headers = "Referer=http://www.xxx.com") 表示请求的 header 中必须包含了指定的“Referer”请求头,以及值为“http://www.xxx.com”时,才能执行该请求。
7、consumers 属性
consumers 属性用于指定处理请求的提交内容类型(Content-Type),例如:application/json、text/html。如
@RequestMapping(value = "toUser",consumers = "application/json")。
8、produces 属性
produces 属性用于指定返回的内容类型,返回的内容类型必须是 request 请求头(Accept)中所包含的类型。如 @RequestMapping(value = "toUser",produces = "application/json")。
除此之外,produces 属性还可以指定返回值的编码。如 @RequestMapping(value = "toUser",produces = "application/json,charset=utf-8"),表示返回 utf-8 编码。
使用 @RequestMapping 来完成映射,具体包括 4 个方面的信息项:请求 URL、请求参数、请求方法和请求头。
3.2.1 url映射
对url(请求路径)和handler(处理器)的方法进行映射。
@Controller
public class RequestMappingController {
/**
* @RequestMapping
* 位置:方法
* 属性:value和path一致,都是配置映射的路径
* 注意:value和path的类型为字符串数组,在注解的属性中,如果类型为数组并且数组中的数据只有一个
* 可以不使用数组,仅使用数组中的数据类型
* 并且,多个请求路径可映射到同一个处理请求的方法上
*/
//@RequestMapping(path = "/url.do")
@RequestMapping(value = {"/url.do", "/getUrl.do" ,"/test.do"})
public ModelAndView url(){
System.out.println("测试@RequestMapping注解中的url映射功能...");
return new ModelAndView("success");
}
}
注意:
-
value的值可为字符串或字符串数组,可以将多个url映射到同一个方法。
-
请求路径的前斜杠,可加可不加,如果不加SpringMVC在查找映射时会自动加入,但是建议加上斜杠表示此字符串为路径。
3.2.2 请求前缀
在控制器handler类上添加@RequestMapping(url)指定通用请求前缀,限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
/**
* @RequestMapping
* 位置:类
* 作用:在该处理器中所有的方法映射路径前,都添加前缀
*
* 以前的路径:/add.do
* 添加前缀之后:/api/add.do
*
* 项目中使用:
* 用户模块:
* @RequestMapping("/user")
* /user/add.do
* /user/edit.do
* /user/remove.do
* /user/find.do
*/
@Controller
@RequestMapping("/api")
public class RequestMappingController {
@RequestMapping("/add.do")
public ModelAndView add(){
System.out.println("测试@RequestMapping注解使用在处理器的类上...");
return new ModelAndView("success");
}
}
3.2.3 限制http请求方法
出于安全性考虑,对http的链接进行方法限制。如果限制请求为post方法,进行get请求,会出现报错。
-
限定GET方法
/**
* @RequestMapping注解中的method属性
* 作用:用于限制http的请求方法
*
* method = RequestMethod.GET标签当前方法只能接收GET请求,其他请求方法会拒绝访问
* 响应状态码为405表示http请求的方式与处理请求方法的限制不匹配
*/
@RequestMapping(value = "/find.do", method = RequestMethod.GET)
public ModelAndView find(){
System.out.println("测试@RequestMapping注解对http协议中的请求方法的限制");
return new ModelAndView("success");
}
如果通过POST访问则报错:
-
限定POST方法
@RequestMapping(value = "/find.do", method = RequestMethod.POST)
public ModelAndView find(){
System.out.println("测试@RequestMapping注解对http协议中的请求方法的限制");
return new ModelAndView("success");
}
如果通过GET访问则报错:
-
GET和POST都可以
@RequestMapping(value = "/find.do", method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView find(){
System.out.println("测试@RequestMapping注解对http协议中的请求方法的限制");
return new ModelAndView("success");
}
3.3 Controller方法返回值
3.3.1 ModelAndView类型
需要方法结束时,定义ModelAndView,将model和view分别进行设置。
3.3.2 String类型
3.3.2.1 请求转发到视图
Controller方法返回字符串可以为逻辑视图名,通过视图解析器将其解析为物理视图地址:
@Controller
public class MethodReturnController {
/**
* 返回值类型为字符串String
*
* 回顾前奏知识:JavaWeb阶段两种页面跳转
* 请求转发:共享request对象,属于服务器行为,页面中url地址不会变化
* 重定向:不同的request对象,属于客户端行为,页面中url地址发生变化
*
* 1.请求转发到视图(JSP页面)
* 2.重定向到视图(JSP页面)
* 3.请求转发到处理器方法
* 4.重定向到处理器方法
*/
/**
* 1.请求转发到视图
* 方法的返回字符串:就是将要跳转的逻辑视图名称
*/
@RequestMapping("/forwardPage.do")
public String forwardPage(HttpServletRequest request){
System.out.println("请求转发到JSP...");
request.setAttribute("message", "hello");
return "ok"; //表示请求转发到/views/ok.jsp页面中
}
}
ok.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>跳转成功--ok.jsp</h1>
<p>从request域中获取数据为:${requestScope.message}</p>
</div>
</body>
</html>
3.3.2.2 重定向到视图
Controller方法返回字符串为:在跳转视图路径前,添加redirect:
前缀
@Controller
public class MethodReturnController {
/**
* 2.重定向到视图
* 在返回值字符串的前面添加redirect:的前缀
*/
@RequestMapping("/redirectPage.do")
public String redirectPage(HttpServletRequest request){
System.out.println("重定向到JSP...");
request.setAttribute("message", "hello");
return "redirect:/views/ok.jsp";
}
}
注意:在redirect:前缀之后不能使用逻辑视图名,必须使用物理视图名。
3.3.2.3 请求转发到处理器方法
请求转发到同一个或另一个处理器的方法中,Controller方法返回字符串为:在跳转视图路径前,添加forward:
前缀。
@Controller
public class MethodReturnController {
/**
* 3.请求转发到处理器方法
* 在返回值字符串的前面添加forward:的前缀
*
* 注意:在forward:前缀之后不能使用逻辑视图名,必须使用物理视图名
*/
@RequestMapping("/forwardController.do")
public String forwardController(HttpServletRequest request){
System.out.println("请求转发到另一个Controller的方法中....");
request.setAttribute("message", "hello other");
return "forward:/other.do";
}
}
OtherController.java:
@Controller
public class OtherController {
@RequestMapping("/other.do")
public String other(HttpServletRequest request){
System.out.println("OtherController处理器执行了....");
System.out.println("request域对象中的数据为:" + request.getAttribute("message"));
return "ok";
}
}
3.3.2.4 重定向到处理器方法
重定向到同一个或另一个处理器的方法中,Controller方法返回字符串为:在跳转视图路径前,添加redirect:
前缀。
@Controller
public class MethodReturnController {
/**
* 4.重定向到处理器方法
* 在返回值字符串的前面添加redirect:的前缀
*
* 注意:在redirect:前缀之后不能使用逻辑视图名,必须使用物理视图名
*/
@RequestMapping("/redirectController.do")
public String redirectController(HttpServletRequest request){
System.out.println("重定向到另一个Controller的方法中....");
request.setAttribute("message", "helloworld");
return "redirect:/other.do";
}
}
3.3.3 void无返回值
在Controller方法形参上可以定义request对象和response对象,使用request或response指定响应结果。
@RequestMapping("/returnVoid.do")
public void returnVoid(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("处理器中方法没有返回值...");
// request.getRequestDispatcher("").forward(request, response);
// response.sendRedirect("");
response.getWriter().println("<html><body><h1>success...</h1></body></html>");
}
3.4 参数绑定
3.4.1 SpringMVC参数绑定过程
客户端请求key/value数据,经过参数绑定,将key/value数据绑定到Controller方法的形参上。
注意:在SpringMVC中,接收页面提交的数据是通过方法的参数(形参)来接收,而不是在Controller类定义成员变量(实参)接收。
3.4.2 默认支持的类型
直接在controller方法形参上定义下边类型,就可以使用这些对象。在参数绑定过程中,如果遇到下边类型直接进行绑定。
HttpServletRequest,通过request对象获取请求信息。
HttpServletResponse,通过response处理响应信息。
HttpSession,通过session对象得到session中存放的对象。
Model/ModelMap,Model是一个接口,ModelMap是一个接口实现。作用:将model数据填充到request域。
@Controller
public class ParameterController {
/**
* 默认支持的类型
* Model替代request域对象
*/
@RequestMapping("/modelParam.do")
public String modelParam(Model model){
System.out.println("modelParam方法执行了...");
model.addAttribute("message", "hello model");
return "ok";
}
}
3.4.3 简单类型
通过处理器方法的形参接收请求参数,并且自动将其转换为指定的类型(基本数据,包装类,日期类型)。
@Controller
public class ParameterController {
/**
* 简单类型形参
* 通过处理器方法的形参接收请求参数,并且自动将其转换为指定的类型(基本数据,包装类,日期类型)
*
* 注意:
* 1.请求参数名称与形参名保持一致
* 2.日期类型默认格式为yyyy/MM/dd
* 3.如果类型转换出现问题,SpringMVC并不会抛出异常,而是一个警告日志,客户端会收到400的响应状态码
*/
@RequestMapping("/simple.do")
public String simple(Integer empno, String ename, String job, Double sal, Date hiredate){
System.out.println("员工编号:" + empno);
System.out.println("员工姓名:" + ename);
System.out.println("员工岗位:" + job);
System.out.println("员工薪资:" + sal);
System.out.println("入职日期:" + hiredate);
return "index";
}
}
simple.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>简单参数类型</h1>
<form action="simple.do" method="post">
<p>员工编号:<input type="text" name="empno"></p>
<p>员工姓名:<input type="text" name="ename"></p>
<p>员工岗位:<input type="text" name="job"></p>
<p>员工薪资:<input type="text" name="sal"></p>
<p>入职日期:<input type="text" name="hiredate"></p>
<p><button>提交</button></p>
</form>
</div>
</body>
</html>
注意:
-
请求参数名称与形参名保持一致。
-
日期类型默认格式为yyyy/MM/dd。
-
如果类型转换出现问题,SpringMVC并不会抛出异常,而是一个警告日志,客户端会收到400的响应状态码。
- @RequestParam
通过@RequestParam注解也可对简单类型的参数进行绑定:
-
使用@RequestParam,不用限制request传入参数名称和Controller方法的形参名称一致。
-
通过required属性指定参数是否必须要传入,如果设置为true,没有传入参数,报400错误。
-
可以使用defaultvalue设置默认值,即使required=true也可以不传参数值。
@Controller
public class ParameterController {
/**
* @RequestParam
* 位置:方法的形参
* 作用:
* 1.value/name: 请求参数与方法形参进行映射
* 2.required: 默认值为true,表示当前请求中必须带有该参数
* 3.defaultValue: 形参的默认值
*/
@RequestMapping("/requestParam.do")
public String requestParam(@RequestParam(value = "empno", required = false, defaultValue = "100") Integer id){
System.out.println("请求参数:" + id);
return "index";
}
}
- @DateTimeFormat
按照指定格式进行日期格式化:
@Controller
public class ParameterController {
/**
* @DateTimeFormat
* 位置:方法的形参,成员变量
* 作用:按照指定格式进行日期格式化
*/
@RequestMapping("/dateTimeFormat.do")
public String dateTimeFormat(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){
System.out.println("日期为:" + date);
return "index";
}
}
- @RequestHeader
获取指定的请求头信息:
@Controller
public class ParameterController {
/**
* @RequestHeader
* 位置:方法的形参
* 作用:获取指定的请求头信息
*/
@RequestMapping("/requestHeader.do")
public String requestHeader(@RequestHeader("Accept-Encoding") String encoding){
System.out.println("请求头信息:" + encoding);
return "index";
}
}
- @CookieValue
获取指定的Cookie值:
@Controller
public class ParameterController {
/**
* 设置Cookie
* 会话:HttpSession,存储在服务器端,Cookie存储HttpSession对象的唯一标识JSESSIONID
*/
@RequestMapping("/setCookie.do")
public String setCookie(HttpServletResponse response){
System.out.println("设置Cookie...");
Cookie myCookie = new Cookie("username", "xiaoming");
myCookie.setPath("/");
// 设置myCookie的有效期为一天
myCookie.setMaxAge(60 * 60 * 24);
response.addCookie(myCookie);
return "index";
}
/**
* @CookieValue
* 位置:方法的形参
* 作用:获取指定的Cookie值
*/
@RequestMapping("/getCookie.do")
public String getCookie(@CookieValue("username") String username){
System.out.println("Cookie:" + username);
return "index";
}
}
3.4.4 POJO类型
-
获取请求参数,并且创建指定POJO对象。
-
对象的成员变量名称与请求参数名称一致,就可以将请求参数值设置在POJO对象中。
-
对象的成员变量也是一个POJO对象时,那么请求参数的名称为:POJO类型的成员变量名.成员变量名。
POJO类:
public class Dept {
private Integer deptno;
private String dname;
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
'}';
}
}
public class Emp {
private Integer empno;
private String ename;
private String job;
private Double sal;
/**
* @DateTimeFormat可以用在形参,也可以用在字段、方法上,都是用来做日期格式化的
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date hiredate;
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", hiredate=" + hiredate +
", dept=" + dept +
'}';
}
}
处理器:
@Controller
public class ParameterController {
/**
* POJO类型的形参
* 要求:请求参数名称必须与POJO对象中成员名称保持一致
*
* springmvc获取请求参数,并且创建指定POJO对象,
* 根据请求参数名与POJO对象成员变量的名称,通过setter方法进行赋值
*/
@RequestMapping("/pojoParam.do")
public String pojoParam(Emp emp){
System.out.println(emp);
return "redirect:/views/index.jsp";
}
}
pojo.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>POJO参数类型</h1>
<form action="pojoParam.do" method="post">
<p>员工编号:<input type="text" name="empno"></p>
<p>员工姓名:<input type="text" name="ename"></p>
<p>员工岗位:<input type="text" name="job"></p>
<p>员工薪资:<input type="text" name="sal"></p>
<p>入职日期:<input type="text" name="hiredate"></p>
<p>部门:<select name="dept.deptno">
<option value="1">人力部</option>
<option value="2">研发部</option>
<option value="3">销售部</option>
</select></p>
<p><button>提交</button></p>
</form>
</div>
</body>
</html>
3.4.5 自定义类型转换器
-
SpringMVC中自带了很多转换器,可完成大多数Java类型的转换工作。
-
ConversionService是Spring类型转换体系的核心接口。
-
可以利用org.springframework.format.support.FormattingConversionServiceFactoryBean在IOC容器中定义一个ConversionService。SpringMVC将自动识别出ConversionService,并在处理器方法参数绑定等场合使用它进行数据类型的转换。
3.4.5.1 Converter接口
org.springframework.core.convert.converter.Converter接口,特点:可将任意类型转换为另一个任意类型。
实现类:
/**
* 自定义的全局日期格式转换器
* 实现Converter<S, T>接口
* S : 原有类型,待转换类型
* T : 转换之后的类型
*/
public class DateConverter implements Converter<String, Date> {
private String partten = "yyyy-MM-dd";
public void setPartten(String partten) {
this.partten = partten;
}
/**
* 日期格式转换
* @param source 待转换类型的字符串数据
* @return 转换之后的日期类型数据
*/
@Override
public Date convert(String source) {
System.out.println("全局日期格式转换工具执行了....");
SimpleDateFormat sdf = new SimpleDateFormat(partten);
try {
return sdf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
配置:
<mvc:annotation-driven conversion-service="formattingConversionService"/>
<!-- 配置格式化与转化服务 -->
<!--
FormattingConversionService: 提供自定义的数据格式化与类型转换服务对象
FormattingConversionService需要告知/配置给处理器适配器
-->
<bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!-- 注册自定义的全局日期格式转换工具 -->
<property name="converters">
<set>
<bean class="com.newcapec.util.DateConverter">
<!--<property name="partten" value="yyyy-MM-dd HH:mm:ss"/>-->
</bean>
</set>
</property>
</bean>
处理器:
@Controller
public class ParameterController {
@RequestMapping("/getBirthday.do")
public String getBirthday(Date birthday) {
System.out.println("生日:" + birthday);
return "index";
}
}
3.4.5.2 Formatter接口
org.springframework.format.Formatter接口,特点:可将任意指定类型转换为String类型,也可将String类型转换为任意指定类型。
自定义类型:
public class MyPoint {
private int x;
private int y;
public MyPoint() {
}
public MyPoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "MyPoint{" +
"x=" + x +
", y=" + y +
'}';
}
}
实现类:
/**
* 类型格式化器
* 实现Formatter<T>接口
* T : 转换之后的格式
*
* Converter与Formatter
* Converter可以实现任意两种类型之间的转换,单向转换,只能将第一个泛型的类型转换为第二个泛型的类型
* Formatter只能实现String与任意类型之间的格式化,双向转换
*/
public class MyPointFormatter implements Formatter<MyPoint> {
@Override
public MyPoint parse(String text, Locale locale) throws ParseException {
//125,369
String[] ss = text.split(",");
return new MyPoint(Integer.parseInt(ss[0]),Integer.parseInt(ss[1]));
}
@Override
public String print(MyPoint object, Locale locale) {
return null;
}
}
配置:
<bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.newcapec.util.MyPointFormatter"/>
</set>
</property>
</bean>
处理器:
@Controller
public class ParameterController {
@RequestMapping("/getPoint.do")
public String getPoint(MyPoint myPoint) {
System.out.println("坐标:" + myPoint);
return "index";
}
}
3.4.6 数组类型
将页面上通过多选框选中多个的id,传到Controller方法的形参,方法形参使用数组接收页面请求的多个id,实现批量删除。
@Controller
public class ParameterController {
/**
* 数组类型的参数
* 客户端的提交规则: 一个请求参数名称对应多个请求参数值
* 原生Servlet: String[] request.getParametervalues()
*
* 特殊情况:
* 当形参为数组类型,而请求参数值中的数据又是以逗号间隔,SpringMVC会按照逗号进行拆分,解析到数组中
* 例如:请求参数为 ids=1,2,3,4,5 形参: 数组{1,2,3,4,5}
*/
@RequestMapping("/removeBatch.do")
public String removeBatch(Integer[] ids){
System.out.println("批量删除的id为:" + Arrays.toString(ids));
return "index";
}
}
array.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>批量删除</h1>
<form action="removeBatch.do">
<table border="1" width="500" align="center">
<tr>
<th><input type="checkbox"></th>
<th>部门编码</th>
<th>部门名称</th>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="10"/></td>
<td>10</td>
<td>研发部</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="20"/></td>
<td>20</td>
<td>人力部</td>
</tr>
<tr>
<td><input type="checkbox" name="ids" value="30"/></td>
<td>30</td>
<td>企划部</td>
</tr>
</table>
<button>提交</button>
</form>
</div>
</body>
</html>
3.4.7 集合类型
SpringMVC无法直接绑定集合类型的形参,需要利用POJO对象才可实现。可将集合类型定义为一个POJO类的属性,该POJO类型作为Controller方法的形参。
POJO类:
public class CollectionBean {
private List<Dept> deptList;
public List<Dept> getDeptList() {
return deptList;
}
public void setDeptList(List<Dept> deptList) {
this.deptList = deptList;
}
}
Controller:
@Controller
public class ParameterController {
/**
* 集合类型的参数
* 注意:springmvc中集合类型不能直接作为形参
* 需要通过一个pojo对象包装,在一个pojo对象中含有一个集合类型的成员变量
*
* 批量新增或编辑数据
*/
// public String insertBatch(List<String> list){ //错误的,不支持的
//
// }
@RequestMapping("/insertBatch.do")
public String insertBatch(CollectionBean bean){
System.out.println("批量提交的部门:" + bean.getDeptList());
return "index";
}
}
list.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>批量新增</h1>
<form action="insertBatch.do" method="post">
<table border="1" width="500" align="center">
<tr>
<th>部门编码</th>
<th>部门名称</th>
</tr>
<tr>
<!-- 集合中的第一个元素:deptList.get(0) = deptList[0] -->
<td><input type="text" name="deptList[0].deptno"></td>
<td><input type="text" name="deptList[0].dname"></td>
</tr>
<tr>
<td><input type="text" name="deptList[1].deptno"></td>
<td><input type="text" name="deptList[1].dname"></td>
</tr>
<tr>
<td><input type="text" name="deptList[2].deptno"></td>
<td><input type="text" name="deptList[2].dname"></td>
</tr>
</table>
<button>提交</button>
</form>
</div>
</body>
</html>
3.4.8 @SessionAttribute
从HttpSession中获取指定对象数据。
@Controller
public class ParameterController {
/**
* @SessionAttribute
* 位置:方法的形参
* 作用:从HttpSession中获取指定对象数据
*/
@RequestMapping("/getUser.do")
public String getUser(@SessionAttribute("loginUser") User user){
System.out.println("登录用户:" + user);
return "index";
}
}
用户类:
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
登录Controller:
@Controller
public class LoginController {
@RequestMapping("/login.do")
public String login(User user, HttpSession session){
System.out.println("登录操作...");
session.setAttribute("loginUser", user);
return "index";
}
}
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>登录</h1>
<form action="login.do" method="post">
<p>用户名:<input type="text" name="username"></p>
<p>密 码:<input type="text" name="password"></p>
<p><button>提交</button></p>
</form>
</div>
</body>
</html>