zoukankan      html  css  js  c++  java
  • SpringMVC 参数绑定

    默认的参数绑定类型

    在 SpringMVC 框架的 Controller 方法(配置了@RequestMapping或其他请求映射)中,我们可以使用的默认参数类型主要有:

    • HttpServletRequest
    • HttpServletResponse
    • HttpSession
    • HttpMethod
    • Model

    我们只需要在方法的参数列表中添加上述类型的参数,那么在处理请求时,SpringMVC 就会自动绑定与该请求相关的对象,正确传递给方法。

    举个最简单的栗子:

    @PostMapping("/user")
    public String login(HttpServletRequest request) {
        // 获取请求参数
        String name = request.getParameter("username");
        String pwd = request.getParameter("password");
        // 调用业务方法
        Boolean status = userService.login(name, pwd);
        // 返回状态
        if (status) {
            return "登录成功";
        } else {
            return "登录失败";
        }
    }
    

    除了上面列举的各个请求都通用的类型,我们也可以添加其他类型的形参,比如 Integer,String,用来接收具体请求携带的参数,免去了request.getParameter的频繁使用。但是请注意,这么做必须保证请求参数的 key 与形参的名称相同,SpringMVC 才能识别并绑定。

    相似的例子:

    @PostMapping("/user")
    public String login(String username, String password) {
        Boolean status = userService.login(username, password);
        if (status) {
            return "登录成功";
        } else {
            return "登录失败";
        }
    }
    

    POJO 类也可以自动识别,但还是那条规则:请求参数的 key 必须与该 POJO 类型的字段名称相同;另外如果参数的 key 出现了这种形式address.provinceName,那就意味着包含了另一个 POJO 类,字段名也必须相同:

    public class User {
        private Long id;
        private String name;
        private String password;
        private Address address; // 包含了Address类型
    }
    
    public class Address {
        private String provinceName;
        private String cityName;
    }
    

    参数绑定的注解

    1. @RequestParam

    你可能觉得请求参数与方法形参必须保证名称相同的限制有点严格,那么请使用@RequestParam注解,可以将指定的请求参数赋值给方法中的形参,并提供更灵活的选项。它有 3 个可使用的属性:

    • value:指定请求参数的名称
    • required:指定参数是否必须绑定,默认 true
    • defaultValue:当请求不携带该参数时使用的默认值
    @GetMapping("/category")
    public Category findById(@RequestParam(value = "id", 
                            required = true, defaultValue = "1") categoryId) {
        Category = categoryService.findById(categoryId);
        return Category;
    }
    

    另外请注意,不管你的方法形参是直接使用还是加上@RequestParam注解,都只能接收 Content-Type 为 application/x-www-form-urlencoded 编码的内容,JSON 格式的数据会被拒绝。

    2. @RequestBody

    使用@RequestBody注解在参数上就可以接收非 application/x-www-form-urlencoded 编码格式了,用于处理HttpEntity中的数据。由于 GET 请求没有请求体,所以不适用;对 POST 请求,SpringMVC 就会通过处理适配器HandlerAdapter中配置的HttpMessageConverters来解析HttpEntity的数据,然后绑定到相应的 POJO 上。

    @PostMapping("/book")
    public void saveBook(@RequestBody book) { 
        bookService.save(book);
    }
    

    通过@RequestBody获取的是整个请求体的数据,这也就是说:(敲重点)如果你想要同时接收两个 POJO 类型对象,那么只能用另一个 POJO 类包含它们。

    3. @PathVariable

    @PathVariable注解可以绑定 URL 中的动态参数,该注解只有一个 value 属性,类型为 String,表示 URL 中需要绑定的参数名称;如果省略,则默认绑定与形参相同的名称。比较适合传递 id 或 name 等能够标识一个资源的数据。

    栗子:

    @GetMapping("/user/{userId}/articles")
    public List<Article> findArticleByUser(@PathVariable("userId") Long id) { 
        return articleService.findArticleByUserId(id);
    }
    

    4. @RequestHeader

    @RequestHeader注解可以绑定请求的报头信息(数据),有 3 个可用的属性:

    • value:指定请求头的字段名称
    • required:是否必须绑定
    • defaultValue:当该字段不存在时使用的默认值

    回顾一下 HTTP 的知识,一般的请求报头信息有下面这些字段(这里截取了在「简书」浏览一篇文章时发出的其中一个请求):

    我们现在想要获取 Accept-Encoding 的信息,用@RequestHeader就可以一步搞定:

    @GetMapping("/article/{id}")
    public Article findArticle(@PathVariable Long id,
                               @RequestHeader("Accept-Encoding") String[] encoding) { // 这里注意是字符串数组
        // ...
    }
    

    5. @CookieValue

    @CookieValue注解可以绑定请求的 Cookie 信息,同样有 3 个可用的属性:

    • value:指定 Cookie 的 key
    • required:是否必须绑定
    • defaultValue:不存在该 Cookie 时的默认值

    示例:

    @GetMapping("/article/{id}")
    public Article findArticle(@PathVariable Long id,
                               @CookieValue("JSESSIONID") String cookie) {
        // ...
    }
    

    PS:JSESSIONID 是 Servlet 容器(tomcat,jetty)用来记录用户 session 的默认 Cookie 名称

    PS*2:调用request.isRequestedSessionIdFromCookie判断 Cookie 是否可用,逻辑就是读取 request 里面有没有 JSESSIONID 这个 Cookie。

    自定义参数转换

    我们已经知道 SpringMVC 在参数绑定和类型转换方面提供了不少的支持,那么有没有什么地方是需要我们自定义参数转换的呢?最典型的场景是日期类型转换(字符串转 java.util.Date 类型),对于这个问题,解决方案有两个:实现Converter接口或Formatter接口。

    1. Converter

    先看Converter,需要指定两个泛型,前者为要转换的类型,后者为转换后的类型,只有一个convert方法需要实现:

    public class DateConverter implements Converter<String, Date> {
        // 日期的数据格式
        private String dataPattern = "yyyy-MM-dd HH:mm:ss";
        @Override
        public Date convert(String source) {
            try {
                // 进行日期转换
                return new SimpleDateFormat(dataPattern).parse(source);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    2. Formatter

    再来看Formatter接口,只需要指定一个泛型,即转换后的类型,而待转换的类型必须是 String,需要实现两个方法:parseprint,前一个方法规定了如何将字符串转换成指定类型,后一个方法规定了如何以字符串形式输出指定类型:

    public class DateFormatter implements Formatter<Date> {
        // 日期的数据格式
        private String dataPattern = "yyyy-MM-dd HH:mm:ss";
        @Override
        public Date parse(String s, Locale locale) throws ParseException {
            // 将字符串转换成Date
            return new SimpleDateFormat(dataPattern).parse(s);
        }
        @Override
        public String print(Date date, Locale locale) {
            // 将Date转换成字符串
            return new SimpleDateFormat(dataPattern).format(date);
        }
    }
    

    3. 配置

    接下来就是配置了,假设你用的是mvc:annotation-driven

    <!-- 配置自定义的日期类型转换器 -->
    <mvc:annotation-driven conversion-service="dataConverterService"/>
    <bean id="dataConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!-- 使用Convert接口-->
        <property name="converters">
            <set>
                <bean class="cn.cna.convert.DateConverter"/>
            </set>
        </property>
    </bean>
    
    <mvc:annotation-driven conversion-service="dataConverterService"/>
    <bean id="dataConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!-- 使用Formatter接口-->
        <property name="formatters">
            <set>
                <bean class="cn.cna.convert.DateConverter"/>
            </set>
        </property>
    </bean>
    

    比较:

    • Converter是一种任意类型转换另一种任意类型,具有普遍性;
    • Formatter是 String 转换另一种,更符合 web 层的特点,比较适合在 springMVC 中使用。

    END

    整理自:SpringMVC+Mybatis快速开发与项目实战,黄文毅,清华大学出版社
    其他参考:
    一文读懂SpringMVC中的数据绑定,Wizey,简书
    SpringMVC|参数绑定,GGarrett,简书
    springmvc formatter,抱明月,博客园

  • 相关阅读:
    过滤器实例——字符编码Filter
    pcap文件格式分析
    jsp常见获取地址函数之间的不同
    将抓到的pcap文件中Http包转换为可读的txt格式
    DBA入门之Oracle数据库参数文件
    查询session status各项统计数据的前三名
    查询正在做的排序操作
    DBUtils的handler
    DBA入门之认识检查点(Checkpoint)
    show_space_by_tom
  • 原文地址:https://www.cnblogs.com/zzzt20/p/12457057.html
Copyright © 2011-2022 走看看