【SpringMVC从入门到实战教程】第三章 SpringMVC 注解开发

三、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>密&emsp;码:<input type="text" name="password"></p>
            <p><button>提交</button></p>
        </form>
    </div>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/ligonglanyuan/article/details/125167057