[SpringMVC from entry to actual combat tutorial] Chapter 3 SpringMVC Annotation Development

3. SpringMVC annotation development

3.1 Basic steps

3.1.1 Front-end controller

<?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 namespace and tag specification

<?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 Component scanning

<!-- 开启组件扫描 -->
<context:component-scan base-package="com.newcapec.controller"/>

3.1.4 MVC annotation driven

    SpringMVC uses `<mvc:annotation-driven>` to automatically load RequestMappingHandlerMapping (processor mapper) and RequestMappingHandlerAdapter (processor adapter), and loads many parameter binding methods by default, such as json conversion parser. You can use `<mvc:annotation-driven>` in the springmvc.xml configuration file to replace the configuration of annotation processors and adapters.

<!-- 注解式的处理器映射器 -->
<!--<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 View resolver

    Configure the prefix and suffix of the view resolver to simplify the access address of the view.

<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 配置视图地址的前缀和后缀:简化视图地址 -->
    <property name="prefix" value="/views/"/>
    <property name="suffix" value=".jsp"/>
</bean>

Configure the changes in the prefix and suffix access paths of the view resolver:

  • Physical view name: Before configuration, the real access path of the view is /views/success.jsp

  • Logical view name: After configuration, the simplified access path of the view is success

  • Physical view name = prefix + logical view name + suffix

3.1.6 Processor

@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 Views

    Create a "views" subdirectory under the webapp directory, and place all views in the "views" subdirectory.

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 @RequestMapping annotation

    There are multiple methods for processing requests in a controller, such as adding users, modifying user information, deleting specified users, and obtaining user lists according to conditions, etc. in UserController. Each method is responsible for different request operations, and @RequestMapping is responsible for mapping the request to the corresponding controller method.

    In the annotation-based controller class, you can write the corresponding processing method for each request. Use the @RequestMapping annotation to match the request with the processing method one by one.

    The @RequestMapping annotation can be used on classes or methods. Used on a class, it means that all methods in the class that respond to requests use this address as the parent path.

The common attributes of @RequestMapping annotation are as follows:

    1. The value attribute
        The value attribute is the default attribute of the @RequestMapping annotation, so if there is only the value attribute, the attribute name can be omitted, and if there are other attributes, the value attribute name must be written.
            @RequestMapping(value="toUser")
            @RequestMapping("toUser")
        The value attribute supports wildcard matching, such as @RequestMapping(value="toUser/*") means http://localhost:8080/toUser/1 or http:/ /localhost:8080/toUser/hahaha can be accessed normally.
    
    2. The path attribute
        Both the path attribute and the value attribute are used as a mapping. That is, both @RequestMapping(value="toUser") and @RequestMapping(path="toUser") can access the toUser() method.
        
    3. The name attribute
        The name attribute is equivalent to the comment of the method, which makes the method easier to understand. Such as @RequestMapping(value = "toUser", name = "Get user information" ).
        
    4. The method attribute
        The method attribute is used to indicate which HTTP requests the method supports. If the method attribute is omitted, the method supports all HTTP requests.
    
    5. params attribute
        The params attribute is used to specify the parameters specified in the request.
            @RequestMapping(value = "toUser", params = "type") 
            The code above indicates that the request must contain the type parameter before the request can be executed. That is, http://localhost:8080/toUser?type=xxx can access the toUser() method normally, but http://localhost:8080/toUser cannot access the toUser() method normally.
            @RequestMapping(value = "toUser", params = "type=1")
            The above code indicates that the request must contain the type parameter, and the request can only be executed when the type parameter is 1. That is, http://localhost:8080/toUser?type=1 can access the toUser() method normally, but http://localhost:8080/toUser?type=2 cannot access the toUser() method normally.
       
    6. The header attribute
        The header attribute indicates that some specified header values ​​must be included in the request.
        @RequestMapping(value = "toUser", headers = "Referer=http://www.xxx.com") indicates that the request header must contain the specified "Referer" request header, and the value is "http://www .xxx.
        

        The consumers attribute is used to specify the submitted content type (Content-Type) for processing the request, for example: application/json, text/html. Such as 
        @RequestMapping(value = "toUser", consumers = "application/json").
        
    8. The produces attribute
        The produces attribute is used to specify the returned content type, and the returned content type must be the type contained in the request header (Accept). Such as @RequestMapping(value = "toUser", produces = "application/json").

        In addition, the produces attribute can also specify the encoding of the return value. Such as @RequestMapping(value = "toUser", produces = "application/json, charset=utf-8"), which means return utf-8 encoding.

    Use @RequestMapping to complete the mapping, including four information items: request URL, request parameters, request method and request header.

3.2.1 URL mapping

    Map the method of url (request path) and handler (processor).

@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");
    }
}

Notice:

  • The value of value can be a string or an array of strings, and multiple urls can be mapped to the same method.

  • The forward slash of the request path can be added or not. If not added, SpringMVC will automatically add it when looking for the mapping, but it is recommended to add a slash to indicate that this string is a path.

3.2.2 Request prefix

    Add @RequestMapping(url) to the controller handler class to specify a general request prefix, restricting all methods under this class to request URLs must start with the request prefix, and classify and manage URLs through this method.

/**
 * @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 Limit http request method

    For security reasons, method restrictions are imposed on http links. If the request is restricted to the post method and a get request is made, an error will occur.

  • Limit the GET method

/**
 * @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");
}

If accessed through POST, an error will be reported:

  • Limit the POST method

@RequestMapping(value = "/find.do", method = RequestMethod.POST)
public ModelAndView find(){
    System.out.println("测试@RequestMapping注解对http协议中的请求方法的限制");
    return new ModelAndView("success");
}

If accessed through GET, an error will be reported:

  • Both GET and POST are OK

@RequestMapping(value = "/find.do", method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView find(){
    System.out.println("测试@RequestMapping注解对http协议中的请求方法的限制");
    return new ModelAndView("success");
}

3.3 Controller method return value

3.3.1 ModelAndViewType

    When the method needs to end, define ModelAndView, and set the model and view respectively.

3.3.2 String type

3.3.2.1 Request forwarding to view

The string returned by the Controller method can be a logical view name, which can be resolved into a physical view address by the view resolver:

@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 Redirecting to Views

The return string of the Controller method is: before jumping to the view path, add redirect:a prefix

@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";
    }
}

Note: Logical view names cannot be used after the redirect: prefix, physical view names must be used.

3.3.2.3 Request forwarding to handler method

The request is forwarded to the same or another method of the processor, and the Controller method returns a string of: add a prefix before the jump view path 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 Redirection to handler method

In the method of redirecting to the same or another handler, the return string of the Controller method is: before the jump view path, add redirect:a prefix.

@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 has no return value

The request object and response object can be defined on the Controller method parameter, and the response result can be specified by using request or 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 Parameter binding

3.4.1 SpringMVC parameter binding process

    The client requests key/value data, and binds the key/value data to the formal parameters of the Controller method through parameter binding.

Note: In SpringMVC, the data submitted by the receiving page is received through the parameters (formal parameters) of the method, rather than the member variables (actual parameters) defined in the Controller class.

3.4.2 Types supported by default

    These objects can be used by defining the following types directly on the controller method parameters. In the process of parameter binding, if you encounter the following types, bind directly.

    HttpServletRequest, get the request information through the request object.
    
    HttpServletResponse, process response information through response.
    
    HttpSession, through the session object to get the object stored in the session.
    
    Model/ModelMap, Model is an interface, and ModelMap is an interface implementation. Function: Fill the model data into the request field.

@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 Simple types

    Receive request parameters through the formal parameters of the processor method, and automatically convert them to the specified type (basic data, wrapper class, date type).

@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>

Note :

  • The name of the request parameter is consistent with the name of the formal parameter.

  • The default format of date type is yyyy/MM/dd.

  • If there is a problem with the type conversion, SpringMVC will not throw an exception, but a warning log, and the client will receive a 400 response status code.

  • @RequestParam

Parameters of simple types can also be bound through the @RequestParam annotation:

  • Using @RequestParam, there is no need to restrict the name of the parameter passed in to the request to be the same as the formal parameter name of the Controller method.

  • Use the required attribute to specify whether the parameter must be passed in. If it is set to true, if no parameter is passed in, a 400 error will be reported.

  • You can use defaultvalue to set the default value, even if required=true, you can not pass the parameter value.

@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

Format the date according to the specified format:

@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

Get the specified request header information:

@Controller
public class ParameterController {
    /**
     * @RequestHeader
     * 位置:方法的形参
     * 作用:获取指定的请求头信息
     */
    @RequestMapping("/requestHeader.do")
    public String requestHeader(@RequestHeader("Accept-Encoding") String encoding){
        System.out.println("请求头信息:" + encoding);
        return "index";
    }
}
  • @CookieValue

Get the specified cookie value:

@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 types

  • Get the request parameters and create the specified POJO object.

  • If the member variable name of the object is consistent with the request parameter name, the request parameter value can be set in the POJO object.

  • When the member variable of the object is also a POJO object, the name of the request parameter is: POJO type member variable name.Member variable name.

POJOs:

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 +
                '}';
    }
}

processor:

@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 Custom type converters

  • SpringMVC comes with many converters that can complete most Java type conversions.

  • ConversionService is the core interface of the Spring type conversion system.

  • You can use org.springframework.format.support.FormattingConversionServiceFactoryBean to define a ConversionService in the IOC container. SpringMVC will automatically recognize ConversionService and use it to convert data types in occasions such as processor method parameter binding.

3.4.5.1 Converter interface

    org.springframework.core.convert.converter.Converter interface, features: any type can be converted to another arbitrary type.

Implementation class:

/**
 * 自定义的全局日期格式转换器
 * 实现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;
    }
}

Configuration:

<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>

processor:

@Controller
public class ParameterController {
    
    @RequestMapping("/getBirthday.do")
    public String getBirthday(Date birthday) {
        System.out.println("生日:" + birthday);
        return "index";
    }
}

3.4.5.2 Formatter interface

    org.springframework.format.Formatter interface, features: any specified type can be converted to String type, and String type can also be converted to any specified type.

Custom type:

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 +
                '}';
    }
}

Implementation class:

/**
 * 类型格式化器
 * 实现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;
    }
}

Configuration:

<bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <set>
            <bean class="com.newcapec.util.MyPointFormatter"/>
        </set>
    </property>
</bean>

processor:

@Controller
public class ParameterController {
    @RequestMapping("/getPoint.do")
    public String getPoint(MyPoint myPoint) {
        System.out.println("坐标:" + myPoint);
        return "index";
    }
}

3.4.6 Array types

    Select multiple ids on the page through the multi-selection box and pass them to the formal parameters of the Controller method. The method formal parameters use an array to receive multiple ids requested by the page to achieve batch deletion.

@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 Collection types

    SpringMVC cannot directly bind the formal parameters of the collection type, and it needs to use POJO objects to realize it. The collection type can be defined as an attribute of a POJO class, and the POJO type is used as a formal parameter of the Controller method.

POJOs:

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

    Get the specified object data from HttpSession.

@Controller
public class ParameterController {
    /**
     * @SessionAttribute
     * 位置:方法的形参
     * 作用:从HttpSession中获取指定对象数据
     */
    @RequestMapping("/getUser.do")
    public String getUser(@SessionAttribute("loginUser") User user){
        System.out.println("登录用户:" + user);
        return "index";
    }
}

User class:

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 + '\'' +
                '}';
    }
}

Login to 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>

Guess you like

Origin blog.csdn.net/ligonglanyuan/article/details/125167057