SpringMVC——处理器方法参数的处理


一、处理器方法参数的处理

如何在Controller中获取(前端传过来的数据)请求中的信息呢?

1、Servlet API 参数

@Controller
@RequestMapping("/request")
public class HandleRequestController {
    // 也可以通过DI注入的方式,因为Controller是单例的,多线程不安全(不建议使用)
    @Autowired
    private ServletContext servletContext;

    // 可以通过参数来操作Servlet的api
    @RequestMapping("/test1")
    public void test1(HttpServletRequest request, HttpServletResponse responser, HttpSession session) {
        System.out.println(request.getParameter("username"));
        System.out.println(request);
        System.out.println(responser);
        System.out.println(session);
        System.out.println(this.servletContext);
    }
}

2、简单类型参数

  • @RequestParam注解
@Controller
@RequestMapping("/request")
public class HandleRequestController {
 // 获取请求参数,保证请求参数名称和Controller方法的形参(入参)同名;
    // 这样就可以获得请求的参数内容; 名字不同,得不到
    @RequestMapping("/test2")
    public void test2(String username, int age) {
        System.out.println("username:" + username);
        System.out.println("age:" + age);
    }

    // 如果请求参数名称和形参名称不同 ==> 使用RequestParam注解
    // 使用@RequestMapping注解后,名字不同,也可以获取,请求参数的内容
    @RequestMapping("/test3")
    public void test3(@RequestParam("name") String username, @RequestParam(value = "age") Integer age) {
        System.out.println("username:" + username);
        System.out.println("age:" + age);
    }
}

测试如下:
同名:


不同名:

3、POST请求时中文乱码问题

在web.xml中配置

<!-- 针对POST请求设置编码过滤器,GET请求,框架已经帮我们做好了 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <!-- 如果有编码格式,设置强制使用上面我们设置的编码格式-->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4、RESTful风格传参

  • @PathVariable注解
/delete?id=11   以前的方式
/delete/11      RESTfull方式
@PathVariable: 可以将URL中占位符绑定到方法的形参中



    // 请求地址为 http://localhost:8080/request/delete/3
    @RequestMapping("delete/{id}")
    public void test4(@PathVariable("id") Long id){
        System.out.println(id);
    }

测试如下:

5、数组和List类型的参数(一个参数多个值的情况)

// 接受一个参数有多个值的情况
    // 批量删除; /batchDelete?ids=10&ids=20&ids=30
    // 使用数组: 可以直接接收传递的多个参数
    @RequestMapping("/batchDelete")
    public void batchDelete(Long[] ids){
        System.out.println(Arrays.asList(ids));
    }
    // 使用集合List: 不能直接接受,可以在对象中存在一个集合
    @RequestMapping("/batchDelete2")
    public void batchDelete2(FormBean fb){
        System.out.println(fb.getIds());
    }
    //操作一个参数有多个值的情况,一般直接使用数组接受就可以了,或者使用JavaBean对象来封装数据.

6、JavaBean类型的参数

//把数据直接封装到JavaBean对象
    @RequestMapping("/test4")
    public void test4(User u) {
        System.out.println(u);
    }

测试如下:


默认会把符合类型参数共享到视图中,共享的key名为参数类型首字母小写; 如果要修改共享数据的key名; 使用ModelAttribute注解

7、ModelAttribute注解

ModelAttribute注解

  • 给共享的Model数据设置key名,贴在形参上,也可以贴在方法上针对复合类型(非简单类型)参数,缺省情况下就会放到model中(共享),缺省的key就是类型首字母小写
  • 我们也可以在参数上贴@ModelAttribute,设置一个model的key名;
@RequestMapping("/zy1")
    public String test1(User u){
        System.out.println(u);
        return "welcome";
    }
    @RequestMapping("/zy2")
    public String test2(@ModelAttribute("zyuser") User u){
        System.out.println(u);
        return "welcome";
    }

welcome.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>welcome</title>
</head>
<body>

    retult:
        ${user}<br>
        ${zyuser}<br>
</body>
</html>

测试如下:

8、请求头信息、Coolie等

// 操作其他的请求信息
@Controller
@RequestMapping("/other")
@SessionAttributes("errorMsg")
public class OtherController {

    // 获取请求头中的User-Agent和Cookie信息
    // 以前的方式
    @RequestMapping("zy1")
    public void test0(HttpServletRequest request){
        String header = request.getHeader("User-Agent");
        String jsessionid = request.getHeader("Cookie");
        System.out.println(header);
        System.out.println(jsessionid);
    }

    // 现在的方式
    @RequestMapping("zy2")
    public void test1(@RequestHeader("User-Agent") String userAgent, @CookieValue("JSESSIONID") String cookieName){
        System.out.println("User-Agent:" + userAgent);
        System.out.println("cookieName" + cookieName);
    }


    // 操作HttpSession;
    // 默认情况下Model数据是放到request中共享的,如果我想在session共享---->SessionAttributes注解
    @RequestMapping("/zy3")
    public String test2(Model model){
        model.addAttribute("errorMsg", "错误信息!");
        //默认肯定不能共享数据的,因为是重定向;之前讲过的那个Flash共享也仅仅只是在Controller之间共享
        return "redirect:/abc.jsp";
    }
}

abc.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    result:
            ${requestScope.errorMsg}<br>
            ${sessionScope.errorMsg}<br>
            ${errorMsg}<br>

</body>
</html>

测试如下:

9、数据绑定流程


SpringMVC通过反射机制对目标处理方法的签名进行分析,将请求信息绑定到处理方法的形参中,数据绑定的核心组件是 DataBinder类

数据绑定流程:

1、框架把ServletRequest对象和请求参数传递给DataBinder ;

2、DataBinder 首先调用Spring Web环境中的ConversionService组件,进行数据类型转换和格式化等操作,将ServletRequest中的信息填充到形参对象中;

3、DataBinder 然后调用Validator组件对已经绑定了请求消息数据的形参对象进行数据合法性校验;

4、DataBinder 最后输出数据绑定结果对象BindingResult.

BindingResult包含了已完成数据绑定的形参对象和校验错误信息对象。
最终SpringMVC框架会把BindingResult中的数据,分别赋给相应的处理方法。

10、多对象封装传递参数

  • 当需要把表单数据封装到多个不同对象中去的时候,如果各个对象中都有相同的属性如name ,此时请求参数name就不清楚到底该把值封装到哪一个对象中去。 更何况缺省情况下SpringMVC也不支持Struts2中类似于对象名.属性名传参方式。

此时需要我们来对象数据设置绑定规则。

InitBinder注解:自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;

由@InitBinder注解标注的方法,可以对WebDataBinder对象进行初始化。而WebDataBinder是DataBinder的子类,用于完成由请求参数到JavaBean的属性绑定。

注意点:
@InitBinder标注的方法不能有返回值,它必须声明为void。
@InitBinder标注的方法的参数通常是WebDataBinder.

input.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
</head>
<body>
<form action="/save" method="POST">
    狗狗姓名:<input type="text" name="dog.name"/><br/>
    狗狗年龄:<input type="text" name="dog.age"/><br/>
    猫猫姓名:<input type="text" name="cat.name"/><br/>
    猫猫年龄:<input type="text" name="cat.age"/><br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>

Java代码

// 处理多个对象的封装
@Controller
public class MultiObjectParamController {

    /*
        需要把表单数据封装到多个对象中去,如果各个对象都有相同的属性,此时要出问题.
            不知道该把哪一个参数封装到哪一个对象中去.

     */
    // 参数-->对象,封装规则需要我们来设置

    // 把以dog.开头的参数封装到dog对象中
    @InitBinder("dog") // 自定义数据绑定注册,用于将请求参数转换到对应的对象的属性中去
    public void initBinderDogyType(WebDataBinder binder){
        binder.setFieldDefaultPrefix("dog.");
    }

    @InitBinder("cat")
    public void initBinderCatType(WebDataBinder binder){
        binder.setFieldDefaultPrefix("cat.");
    }

    @RequestMapping("/save")
    public ModelAndView save(Cat cat, Dog dog){
        System.out.println(cat);
        System.out.println(dog);
        return null;
    }
}

测试如下:


11、JSON数据处理

Jackson

Jackson 是一个Java开源的JSON工具库,性能很高,可以轻松将Java对象转换成Json对象xml文档,同样也可以将json、xml转换成Java对象

首先导入Jackson的Maven依赖

<dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.9.10</version>
 </dependency>
 <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-core</artifactId>
     <version>2.9.10</version>
 </dependency>
 <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-annotations</artifactId>
     <version>2.9.10</version>
 </dependency>


Java代码测试

// 处理JSON
@Controller
@RequestMapping("/json")
public class HandleJsonController {

    /*
        处理JSON的注解:
            ResponseBody: 处理响应,把对象转换为JSON字符串.
                贴到方法上:只针对当前方法做JSON处理.
                贴到类上   : 会对当前类中所有的方法做JSON处理.

            RestController = Controller + ResponseBody

            RequestBody: 处理请求,用于读取HTTP请求的内容,把JSON格式的请求数据封装成对象.

            一般的请求的数据格式:
                application/x-www-form-urlencoded: 传统的key-value格式,处理起来非常方便. 不需要RequestBody都可以,贴上也可以.
                application/multipart:文件上传的请求,SpringMVC装设设计模式,.既能处理文件上传,也能处理普通表单数据.
                application/json:   参数是JSON格式的,此时必须使用RequestBody.

     */

    // 把单个对象/Map转换为JSON格式
    @RequestMapping("/test1")
    @ResponseBody
    public User test1() {
        User u = new User();
        u.setUsername("桂朝阳");
        u.setAge(22);
        return u;
    }

    // 把集合转为JSON格式
    @RequestMapping("/test2")
    @ResponseBody
    public List<User> test2() {
        User u = new User();
        u.setUsername("桂阳");
        u.setAge(22);
        return Arrays.asList(u, u, u);
    }

注意 : Jackson包导入后可能没有加载上,后台会报500错误; 注意看这个地方是否有jar包

12、日期类型处理

方式一

@Controller
@RequestMapping("/date")
public class HandleDateController {
    // 从前台--->后台传递参数: String ---> java.util.Date  // http://localhost:8080/date/test1?d=2010-11-1
    @RequestMapping("/test1")
    public ModelAndView test1(@DateTimeFormat(pattern = "yyyy-MM-dd") Date d){
        System.out.println(d);
        return null;
    }
}

方式二

@Data
public class User {
    private Long id;
    private String username;
    private Integer age;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date hiredate;
}

@Controller
@RequestMapping("/date")
public class HandleDateController {
    // http://localhost:8080/date/test1?id=2&username=zy&age=23&hiredate=2020-2-1
    @RequestMapping("/test2")
    public ModelAndView test2(User user){
        System.out.println(user);
        return null;
    }
}

方式三
@ControllerAdvice注解

@Data
public class User {
    private Long id;
    private String username;
    private Integer age;
    private Date hiredate;
}

@ControllerAdvice
public class DateFormatAdvice {
    //如果不想每次都在Date类型上@DateTimeFormat
    @InitBinder
    public void initBinderDateType(WebDataBinder binder) {
        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.applyPattern("yyyy-MM-dd");
        binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(sdf, true));
    }
}

测试如下:


// 处理JSON
@Controller
@RequestMapping("/json")
public class HandleJsonController {

    @RequestMapping("/test3")
    @ResponseBody
    public User test3(){
        User user = new User();
        user.setUsername("will");
        user.setAge(82);
        user.setHiredate(new Date());
        return user;
    }
}

测试如下:


原文链接:https://blog.csdn.net/m0_37989980/article/details/104691093?utm_source=blogxgwz7