精华内容
下载资源
问答
  • 文章目录动态拼装请求参数使用全局变量 动态拼装请求参数 定义一个data.json文件,存放请求参数,格式 [{ "id": "8B47A1FF-F2C2-4066-91D3-178D076097A1" },{ "id": "8B47A1FF-F2C2-4066-91D3-178D076097A1...

    动态拼装请求参数

    1. 定义一个data.json文件,存放请求参数,格式
    [{
    		"id": "8B47A1FF-F2C2-4066-91D3-178D076097A1"
    		},{
    		"id": "8B47A1FF-F2C2-4066-91D3-178D076097A1"
    }]
    
    1. postman调用方式{{id}}
      在这里插入图片描述
    2. 打开run-collection runner,选择刚才定义的data.json文件
      在这里插入图片描述
      Iterations:循环次数
      Delay: 循环间隔
      Data:参数模板文件
      Data File Type:按照自己定义的格式选择即可,编者是使用的application/json
      Preview: 可以预查询以下data.json的数据
      设置完以上参数,直接Run Test 即可

    使用全局变量

    在使用Postman调用接口的时候,会遇到类似token的参数,只需要在一个地方统一配置即可,不需要在每个接口里面单独配置,要是接口多的话,一个一个的配置,会累屎的。这个使用就用到全局变量功能

    1. 点击接口右上角的锯齿状的按钮,里面可以设置全局变量,如下图,调用使用{{自定义参数名}}即可
      在这里插入图片描述
    展开全文
  • spring后台的controller提供了@RequestParam、@RequestBody等参数注解,使用不同的注解,对于允许的前台请求格式也不一样,下面就列出不同格式的请求实例:  本环境使用spring-boot搭建后台接口服务,前台采用ajax...

     spring后台的controller提供了@RequestParam、@RequestBody等参数注解,使用不同的注解,对于允许的前台请求格式也不一样,下面就列出不同格式的请求实例:

     本环境使用spring-boot搭建后台接口服务,前台采用ajax形式发送数据,数据的传递使用Bean实体类接收,在参数接收时,如果出现日期格式无法解析的情况,参见本人的另一篇文章

    spring-boot 接口请求之Date、LocalDate、LocalDateTime日期类型转换处理

    本文所用的实体Bean为:

    public class Ajax implements Serializable{
        private Long id;
        private String name;
        private String path;
        private Date createdDate;
        private LocalDateTime createdTime;
    }

    第一种:controller参数为不带注解的形式:

    后台controller接口:

    /***
     * 实体类无注解接收参数
     * @return
     */
     @RequestMapping(value = "/getOfBean")
     @ApiOperation("Bean实体参数")
     public Ajax getOfBean(Ajax ajax) throws Exception{
        logger.info("异步参数接收:{}",ajax.toString());
        return ajax;
     }
    ajax请求方式:

    var param1={
        id:1234,
        name:'名称',
        path:'路径',
        createdDate:'2017-01-05 12:45:32',
        createdTime:'2017-01-05 12:45:32'
    };
    $.get("http://127.0.0.1:8888/ajaxApi/getOfBean",param, function(result){
         console.info("result:"+JSON.stringify(result));
         alert(JSON.stringify(result));
    });
    【*】使用无注解的形式接收参数,前台发送json格式数据,使用get和Post方式都可以正常发送、接收数据

    第二种:controller使用@RequestBody注解接收参数

    后台controller接口:

    /***
       * 实体类 @RequestBody注解 接收参数
       * @param ajax
       * @return
       * @throws Exception
       */
        @RequestMapping(value = "/getOfBeanRequestBody")
        @ApiOperation("Bean实体参数@RequestBody注解")
        public Ajax getOfBeanRequestBody(@RequestBody Ajax ajax) throws Exception{
          logger.info("异步参数接收:{}",ajax.toString());
          return ajax;
        }
    ajax请求方式:

    $.ajax({
        type: "post",
        url: "http://127.0.0.1:8888/ajaxApi/getOfBeanRequestBody",
        data: JSON.stringify(param),
        contentType: "application/json; charset=utf-8",
        success: function (result) {
            console.info("result:"+JSON.stringify(result));
            alert(JSON.stringify(result));
        }
    });
    【*】注意:后台使用@RequestBody朱解释,ajax有如下显示

    1.必须使用POST方式提交;
    2.contentType必须设置为 application/json 格式;
    3.发送的参数为json字符串形式,必须使用JSON.stringify(Param) 将json对象转为字符串


    第三种:controller使用@RequestParam注解

    后台controller接口:

    /***
         * 实体类 @RequestBody注解 接收参数
         * @param ajax
         * @return
         * @throws Exception
         */
        @RequestMapping(value = "/getOfBeanRequestParam")
        @ApiOperation("Bean实体参数@RequestPatam注解")
        public Ajax getOfBeanRequestParam(@RequestParam Ajax ajax) throws Exception{
          logger.info("异步参数接收:{}",ajax.toString());
          return ajax;
        }
    ajax请求:

    $.ajax({
       type: "post",
       url: "http://127.0.0.1:8888/ajaxApi/getOfBeanRequestBody",
       data: JSON.stringify(param),
       contentType: "application/json; charset=utf-8",
       success: function (result) {
       console.info("result:"+JSON.stringify(result));
          alert(JSON.stringify(result));
       }
    });

    【*】注意:后台使用@RequestParam注释,和@RequestBody相同,ajax有如下显示

    1.必须使用POST方式提交
    2.contentType必须设置为 application/json 格式;
    3.发送的参数为json字符串形式,必须使用JSON.stringify(Param) 将json对象转为字符串;



    文章为本人测试后所写,欢迎各位留言交流,如有不对请指正,欢迎大家留言


    展开全文
  • SpringMVC请求参数接收总结

    千次阅读 2018-08-07 09:51:22
    在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结。SpringMVC中处理控制器参数的接口是HandlerMethodArgumentResolver,此接口有众多子类,分别处理不同(注解类型)...

    前提

    在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结。SpringMVC中处理控制器参数的接口是HandlerMethodArgumentResolver,此接口有众多子类,分别处理不同(注解类型)的参数,下面只列举几个子类:

    • RequestParamMethodArgumentResolver:解析处理使用了@RequestParam注解的参数、MultipartFile类型参数和Simple类型(如long、int)参数。
    • RequestResponseBodyMethodProcessor:解析处理@RequestBody注解的参数。
    • PathVariableMapMethodArgumentResolver:解析处理@PathVariable注解的参数。

    实际上,一般在解析一个控制器的请求参数的时候,用到的是HandlerMethodArgumentResolverComposite,里面装载了所有启用的HandlerMethodArgumentResolver子类。而HandlerMethodArgumentResolver子类在解析参数的时候使用到HttpMessageConverter(实际上也是一个列表,进行遍历匹配解析)子类进行匹配解析,常见的如MappingJackson2HttpMessageConverter。而HandlerMethodArgumentResolver子类到底依赖什么HttpMessageConverter实例实际上是由请求头中的ContentType(在SpringMVC中统一命名为MediaType,见org.springframework.http.MediaType)决定的,因此我们在处理控制器的请求参数之前必须要明确外部请求的ContentType到底是什么。上面的逻辑可以直接看源码AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters,思路是比较清晰的。在@RequestMapping注解中,produces和consumes就是和请求或者响应的ContentType相关的:

    • consumes:指定处理请求的提交内容类型(ContentType),例如application/json, text/html,只有命中了才会接受该请求。
    • produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回,如果返回的是JSON数据一般使用application/json;charset=UTF-8。

    另外提一点,SpringMVC中默认使用Jackson作为JSON的工具包,如果不是完全理解透整套源码的运作,一般不是十分建议修改默认使用的MappingJackson2HttpMessageConverter(例如有些人喜欢使用FastJson,实现HttpMessageConverter引入FastJson做转换器)。

    SpringMVC请求参数接收

    其实一般的表单或者JSON数据的请求都是相对简单的,一些复杂的处理主要包括URL路径参数、文件上传、数组或者列表类型数据等。另外,关于参数类型中存在日期类型属性(例如java.util.Date、java.sql.Date、java.time.LocalDate、java.time.LocalDateTime),解析的时候一般需要自定义实现的逻辑实现String->日期类型的转换。其实道理很简单,日期相关的类型对于每个国家、每个时区甚至每个使用者来说认知都不一定相同。在演示一些例子主要用到下面的模特类:

    @Data
    public class User {
    
        private String name;
        private Integer age;
        private List<Contact> contacts;
    }
    
    @Data
    public class Contact {
    
        private String name;
        private String phone;
    }

    表单参数

    非对象类型单个参数接收:

    这种是最常用的表单参数提交,ContentType指定为application/x-www-form-urlencoded,也就是会进行URL编码。

    spmvc-p-1

    对应的控制器如下:

    @PostMapping(value = "/post")
    public String post(@RequestParam(name = "name") String name,
                       @RequestParam(name = "age") Integer age) {
        String content = String.format("name = %s,age = %d", name, age);
        log.info(content);
        return content;
    }

    说实话,如果有毅力的话,所有的复杂参数的提交最终都可以转化为多个单参数接收,不过这样做会产生十分多冗余的代码,而且可维护性比较低。这种情况下,用到的参数处理器是RequestParamMapMethodArgumentResolver。

    对象类型参数接收:

    我们接着写一个接口用于提交用户信息,用到的是上面提到的模特类,主要包括用户姓名、年龄和联系人信息列表,这个时候,我们目标的控制器最终编码如下:

    @PostMapping(value = "/user")
    public User saveUser(User user) {
        log.info(user.toString());
        return user;
    }

    我们还是指定ContentType为application/x-www-form-urlencoded,接着我们需要构造请求参数:

    spmvc-p-2

    因为没有使用注解,最终的参数处理器为ServletModelAttributeMethodProcessor,主要是把HttpServletRequest中的表单参数封装到MutablePropertyValues实例中,再通过参数类型实例化(通过构造反射创建User实例),反射匹配属性进行值的填充。另外,请求复杂参数里面的列表属性请求参数看起来比较奇葩,实际上和在.properties文件中添加最终映射到Map类型的参数的写法是一致的。那么,能不能把整个请求参数塞在一个字段中提交呢?

    spmvc-p-3

    直接这样做是不行的,因为实际提交的form表单,key是user,value实际上是一个字符串,缺少一个String->User类型的转换器,实际上RequestParamMethodArgumentResolver依赖WebConversionService中Converter列表进行参数转换:

    spmvc-p-4

    解决办法还是有的,添加一个org.springframework.core.convert.converter.Converter实现即可:

    @Component
    public class StringUserConverter implements Converter<String, User> {
    
        private static final ObjectMapper MAPPER = new ObjectMapper();
    
        @Override
        public User convert(String source) {
            try {
                return MAPPER.readValue(source, User.class);
            } catch (IOException e) {
                throw new IllegalArgumentException(e);
            }
        }
    }

    上面这种做法属于曲线救国的做法,不推荐使用在生产环境,但是如果有些第三方接口的对接无法避免这种参数,可以选择这种实现方式。

    JSON参数

    一般来说,直接POST一个JSON字符串这种方式对于SpringMVC来说是比较友好的,只需要把ContentType设置为application/json,提交一个原始的JSON字符串即可:

    spmvc-p-5

    后端控制器的代码也比较简单:

    @PostMapping(value = "/user-2")
    public User saveUser2(@RequestBody User user) {
        log.info(user.toString());
        return user;
    }

    因为使用了@RequestBody注解,最终使用到的参数处理器为RequestResponseBodyMethodProcessor,实际上会用到MappingJackson2HttpMessageConverter进行参数类型的转换,底层依赖到Jackson相关的包。

    URL参数

    URL参数,或者叫请求路径参数是基于URL模板获取到的参数,例如/user/{userId}是一个URL模板(URL模板中的参数占位符是{}),实际请求的URL为/user/1,那么通过匹配实际请求的URL和URL模板就能提取到userId为1。在SpringMVC中,URL模板中的路径参数叫做PathVariable,对应注解@PathVariable,对应的参数处理器为PathVariableMethodArgumentResolver。注意一点是,@PathVariable的解析是按照value(name)属性进行匹配,和URL参数的顺序是无关的。举个简单的例子:

    spmvc-p-6

    后台的控制器如下:

    @GetMapping(value = "/user/{name}/{age}")
    public String findUser1(@PathVariable(value = "age") Integer age,
                            @PathVariable(value = "name") String name) {
        String content = String.format("name = %s,age = %d", name, age);
        log.info(content);
        return content;
    }

    这种用法被广泛使用于Representational State Transfer(REST)的软件架构风格,个人觉得这种风格是比较灵活和清晰的(从URL和请求方法就能完全理解接口的意义和功能)。下面再介绍两种相对特殊的使用方式。

    带条件的URL参数
    其实路径参数支持正则表达式,例如我们在使用/sex/{sex}接口的时候,要求sex必须是F(Female)或者M(Male),那么我们的URL模板可以定义为/sex/{sex:M|F},代码如下:

    @GetMapping(value = "/sex/{sex:M|F}")
    public String findUser2(@PathVariable(value = "sex") String sex){
        log.info(sex);
        return sex;
    }

    只有/sex/F或者/sex/M的请求才会进入findUser2控制器方法,其他该路径前缀的请求都是非法的,会返回404状态码。这里仅仅是介绍了一个最简单的URL参数正则表达式的使用方式,更强大的用法可以自行摸索。

    @MatrixVariable的使用
    MatrixVariable也是URL参数的一种,对应注解@MatrixVariable,不过它并不是URL中的一个值(这里的值指定是两个"/"之间的部分),而是值的一部分,它通过";"进行分隔,通过"="进行K-V设置。说起来有点抽象,举个例子:假如我们需要打电话给一个名字为doge,性别是男,分组是码畜的程序员,GET请求的URL可以表示为:/call/doge;gender=male;group=programmer,我们设计的控制器方法如下:

    @GetMapping(value = "/call/{name}")
    public String find(@PathVariable(value = "name") String name,
                       @MatrixVariable(value = "gender") String gender,
                       @MatrixVariable(value = "group") String group) {
        String content = String.format("name = %s,gender = %s,group = %s", name, gender, group);
        log.info(content);
        return content;
    }

    当然,如果你按照上面的例子写好代码,尝试请求一下该接口发现是报错的:400 Bad Request - Missing matrix variable 'gender' for method parameter of type String。这是因为@MatrixVariable注解的使用是不安全的,在SpringMVC中默认是关闭对其支持。要开启对@MatrixVariable的支持,需要设置RequestMappingHandlerMapping#setRemoveSemicolonContent方法为false:

    @Configuration
    public class CustomMvcConfiguration implements InitializingBean {
    
        @Autowired
        private RequestMappingHandlerMapping requestMappingHandlerMapping;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            requestMappingHandlerMapping.setRemoveSemicolonContent(false);
        }
    }

    除非有很特殊的需要,否则不建议使用@MatrixVariable。

    文件上传

    文件上传在使用POSTMAN模拟请求的时候需要选择form-data,POST方式进行提交:

    spmvc-p-8

    假设我们在D盘有一个图片文件叫doge.jpg,现在要通过本地服务接口把文件上传,控制器的代码如下:

    @PostMapping(value = "/file1")
    public String file1(@RequestPart(name = "file1") MultipartFile multipartFile) {
        String content = String.format("name = %s,originName = %s,size = %d",
                multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getSize());
        log.info(content);
        return content;
    }

    控制台输出是:

    name = file1,originName = doge.jpg,size = 68727

    可能有点疑惑,参数是怎么来的,我们可以用Fildder抓个包看下:

    spmvc-p-7

    可知MultipartFile实例的主要属性分别来自Content-Disposition、content-type和content-length,另外,InputStream用于读取请求体的最后部分(文件的字节序列)。参数处理器用到的是RequestPartMethodArgumentResolver(记住一点,使用了@RequestPart和MultipartFile一定是使用此参数处理器)。在其他情况下,使用@RequestParam和MultipartFile或者仅仅使用MultipartFile(参数的名字必须和POST表单中的Content-Disposition描述的name一致)也可以接收上传的文件数据,主要是通过RequestParamMethodArgumentResolver进行解析处理的,它的功能比较强大,具体可以看其supportsParameter方法,这两种情况的控制器方法代码如下:

    @PostMapping(value = "/file2")
    public String file2(MultipartFile file1) {
        String content = String.format("name = %s,originName = %s,size = %d",
                    file1.getName(), file1.getOriginalFilename(), file1.getSize());
        log.info(content);
        return content;
    }
    
    @PostMapping(value = "/file3")
    public String file3(@RequestParam(name = "file1") MultipartFile multipartFile) {
        String content = String.format("name = %s,originName = %s,size = %d",
                multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getSize());
        log.info(content);
        return content;
    }

    其他参数

    其他参数主要包括请求头、Cookie、Model、Map等相关参数,还有一些并不是很常用或者一些相对原生的属性值获取(例如HttpServletRequest、HttpServletResponse等)不做讨论。

    请求头

    请求头的值主要通过@RequestHeader注解的参数获取,参数处理器是RequestHeaderMethodArgumentResolver,需要在注解中指定请求头的Key。简单实用如下:

    spmvc-p-9

    控制器方法代码:

    @PostMapping(value = "/header")
    public String header(@RequestHeader(name = "Content-Type") String contentType) {
       return contentType;
    }

    Cookie的值主要通过@CookieValue注解的参数获取,参数处理器为ServletCookieValueMethodArgumentResolver,需要在注解中指定Cookie的Key。控制器方法代码如下:

    @PostMapping(value = "/cookie")
    public String cookie(@CookieValue(name = "JSESSIONID") String sessionId) {
        return sessionId;
    }

    Model类型参数

    Model类型参数的处理器是ModelMethodProcessor,实际上处理此参数是直接返回ModelAndViewContainer实例中的Model(ModelMap类型),因为要桥接不同的接口和类的功能,因此回调的实例是BindingAwareModelMap类型,此类型继承自ModelMap同时实现了Model接口。举个例子:

    @GetMapping(value = "/model")
    public String model(Model model, ModelMap modelMap) {
        log.info("{}", model == modelMap);
        return "success";
    }

    注意调用此接口,控制台输出Info日志内容为:true。ModelMap或者Model中添加的属性项会附加到HttpRequestServlet中带到页面中进行渲染。

    @ModelAttribute参数

    @ModelAttribute注解处理的参数处理器为ModelAttributeMethodProcessor,@ModelAttribute的功能源码的注释如下:

    Annotation that binds a method parameter or method return value to a named model attribute, exposed to a web view.

    简单来说,就是通过key-value形式绑定方法参数或者方法返回值到Model(Map)中,区别下面三种情况:

    • 1、@ModelAttribute使用在方法(返回值)上,方法没有返回值(void类型), Model(Map)参数需要自行设置。
    • 2、@ModelAttribute使用在方法(返回值)上,方法有返回值(非void类型),返回值会添加到Model(Map)参数,key由@ModelAttribute的value指定,否则会使用返回值类型字符串(首写字母变为小写)。
    • 3、@ModelAttribute使用在方法参数中。

    在一个控制器(使用了@Controller)中,如果存在一到多个使用了@ModelAttribute的方法,这些方法总是在进入控制器方法之前执行,并且执行顺序是由加载顺序决定的(具体的顺序是不带参数的优先,并且按照方法首字母升序排序),举个例子:

    @Slf4j
    @RestController
    public class ModelAttributeController {
    
        @ModelAttribute
        public void before(Model model) {
            log.info("before..........");
            model.addAttribute("before", "beforeValue");
        }
    
        @ModelAttribute(value = "beforeArg")
        public String beforeArg() {
            log.info("beforeArg..........");
            return "beforeArgValue";
        }
    
        @GetMapping(value = "/modelAttribute")
        public String modelAttribute(Model model, @ModelAttribute(value = "beforeArg") String beforeArg) {
            log.info("modelAttribute..........");
            log.info("beforeArg..........{}", beforeArg);
            log.info("{}", model);
            return "success";
        }
    
        @ModelAttribute
        public void after(Model model) {
            log.info("after..........");
            model.addAttribute("after", "afterValue");
        }
    
        @ModelAttribute(value = "afterArg")
        public String afterArg() {
            log.info("afterArg..........");
            return "afterArgValue";
        }
    }

    调用此接口,控制台输出日志如下:

    after..........
    before..........
    afterArg..........
    beforeArg..........
    modelAttribute..........
    beforeArg..........beforeArgValue
    {after=afterValue, before=beforeValue, afterArg=afterArgValue, beforeArg=beforeArgValue}

    可以印证排序规则和参数设置、获取。

    Errors或者BindingResult参数

    Errors其实是BindingResult的父接口,BindingResult主要用于回调JSR参数校验异常的属性项,如果JSR校验异常,一般会抛出MethodArgumentNotValidException异常,并且会返回400(Bad Request),见全局异常处理器DefaultHandlerExceptionResolver。Errors类型的参数处理器为ErrorsMethodArgumentResolver。举个例子:

    @PostMapping(value = "/errors")
    public String errors(@RequestBody @Validated ErrorsModel errors, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            for (ObjectError objectError : bindingResult.getAllErrors()) {
                log.warn("name={},message={}", objectError.getObjectName(), objectError.getDefaultMessage());
            }
        }
        return errors.toString();
    }
    
    //ErrorsModel
    @Data
    @NoArgsConstructor
    public class ErrorsModel {
        @NotNull(message = "id must not be null!")
        private Integer id;
        @NotEmpty(message = "errors name must not be empty!")
        private String name;
    }

    调用接口控制台Warn日志如下:

    name=errors,message=errors name must not be empty!

    一般情况下,不建议用这种方式处理JSR校验异常的属性项,因为会涉及到大量的重复的硬编码工作,建议直接继承ResponseEntityExceptionHandler,覆盖对应的方法。

    @Value参数

    控制器方法的参数可以是@Value注解修饰的参数,会从Environment中装配和转换属性值到对应的参数中(也就是参数的来源并不是请求体),参数处理器为ExpressionValueMethodArgumentResolver。举个例子:

    @GetMapping(value = "/value")
    public String value(@Value(value = "${spring.application.name}") String name) {
        log.info("spring.application.name={}", name);
        return name;
    }

    Map类型参数

    Map类型参数的范围相对比较广,对应一系列的参数处理器,注意区别使用了上面提到的部分注解的Map类型和完全不使用注解的Map类型参数,两者的处理方式不相同。下面列举几个相对典型的Map类型参数处理例子。

    不使用任何注解的Map<String,Object>参数
    这种情况下参数实际上直接回调ModelAndViewContainer中的ModelMap实例,参数处理器为MapMethodProcessor,往Map参数中添加的属性将会带到页面中。

    使用@RequestParam注解的Map<String,Object>参数
    这种情况下的参数处理器为RequestParamMapMethodArgumentResolver,使用的请求方式需要指定ContentType为x-www-form-urlencoded,不能使用application/json的方式:

    spmvc-p-10

    控制器代码为:

    @PostMapping(value = "/map")
    public String mapArgs(@RequestParam Map<String, Object> map) {
        log.info("{}", map);
        return map.toString();
    }

    使用@RequestHeader注解的Map<String,Object>参数
    这种情况下的参数处理器为RequestHeaderMapMethodArgumentResolver,作用是获取请求的所有请求头的Key-Value。

    使用@PathVariable注解的Map<String,Object>参数
    这种情况下的参数处理器为PathVariableMapMethodArgumentResolver,作用是获取所有路径参数封装为Key-Value结构。

    MultipartFile集合-批量文件上传

    批量文件上传的时候,我们一般需要接收一个MultipartFile集合,可以有两种选择:

    • 1、使用MultipartHttpServletRequest参数,直接调用getFiles方法获取MultipartFile列表。
    • 2、使用@RequestParam注解修饰MultipartFile列表,参数处理器是RequestParamMethodArgumentResolver,其实就是第一种的封装而已。

    spmvc-p-11

    控制器方法代码如下:

    @PostMapping(value = "/parts")
    public String partArgs(@RequestParam(name = "file") List<MultipartFile> parts) {
        log.info("{}", parts);
        return parts.toString();
    }

    日期类型参数处理

    日期处理个人认为是请求参数处理中最复杂的,因为一般日期处理的逻辑不是通用的,过多的定制化处理导致很难有一个统一的标准处理逻辑去处理和转换日期类型的参数。不过,这里介绍几个通用的方法,以应对各种奇葩的日期格式。下面介绍的例子中全部使用Jdk8中引入的日期时间API,围绕java.util.Date为核心的日期时间API的使用方式类同。

    一、统一以字符串形式接收

    这种是最原始但是最奏效的方式,统一以字符串形式接收,然后自行处理类型转换,下面给个小例子:

    @PostMapping(value = "/date1")
    public String date1(@RequestBody UserDto userDto) {
        UserEntity userEntity = new UserEntity();
        userEntity.setUserId(userDto.getUserId());
        userEntity.setBirthdayTime(LocalDateTime.parse(userDto.getBirthdayTime(), FORMATTER));
        userEntity.setGraduationTime(LocalDateTime.parse(userDto.getGraduationTime(), FORMATTER));
        log.info(userEntity.toString());
        return "success";
    }
    
    @Data
    public class UserDto {
    
        private String userId;
        private String birthdayTime;
        private String graduationTime;
    }
    
    @Data
    public class UserEntity {
    
        private String userId;
        private LocalDateTime birthdayTime;
        private LocalDateTime graduationTime;
    }

    spmvc-p-12

    二、使用注解@DateTimeFormat或者@JsonFormat

    @DateTimeFormat注解配合@RequestBody的参数使用的时候,会发现抛出InvalidFormatException异常,提示转换失败,这是因为在处理此注解的时候,只支持form提交(ContentType为x-www-form-urlencoded),例子如下:

    spmvc-p-13

    @Data
    public class UserDto2 {
    
        private String userId;
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime birthdayTime;
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime graduationTime;
    }
    
    
    @PostMapping(value = "/date2")
    public String date2(UserDto2 userDto2) {
        log.info(userDto2.toString());
        return "success";
    }
    
    //或者像下面这样
    @PostMapping(value = "/date2")
    public String date2(@RequestParam("name"="userId")String userId,
                        @RequestParam("name"="birthdayTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime birthdayTime,
                        @RequestParam("name"="graduationTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime graduationTime) {
        return "success";
    }

    而@JsonFormat注解可使用在form或者Json请求参数的场景,因此更推荐使用@JsonFormat注解,不过注意需要指定时区(timezone属性,例如在中国是东八区"GMT+8"),否则有可能导致出现"时差",举个例子:

    @PostMapping(value = "/date2")
    public String date2(@RequestBody UserDto2 userDto2) {
        log.info(userDto2.toString());
        return "success";
    }
    
    @Data
    public class UserDto2 {
    
        private String userId;
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private LocalDateTime birthdayTime;
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
        private LocalDateTime graduationTime;
    }

    三、Jackson序列化和反序列化定制

    因为SpringMVC默认使用Jackson处理@RequestBody的参数转换,因此可以通过定制序列化器和反序列化器来实现日期类型的转换,这样我们就可以使用application/json的形式提交请求参数。这里的例子是转换请求Json参数中的字符串为LocalDateTime类型,属于Json反序列化,因此需要定制反序列化器:

    @PostMapping(value = "/date3")
    public String date3(@RequestBody UserDto3 userDto3) {
        log.info(userDto3.toString());
        return "success";
    }
    
    @Data
    public class UserDto3 {
    
        private String userId;
        @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
        private LocalDateTime birthdayTime;
        @JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
        private LocalDateTime graduationTime;
    }
    
    public class CustomLocalDateTimeDeserializer extends LocalDateTimeDeserializer {
    
        public CustomLocalDateTimeDeserializer() {
            super(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
    }

    四、最佳实践

    前面三种方式都存在硬编码等问题,其实最佳实践是直接修改MappingJackson2HttpMessageConverter中的ObjectMapper对于日期类型处理默认的序列化器和反序列化器,这样就能全局生效,不需要再使用其他注解或者定制序列化方案(当然,有些时候需要特殊处理定制),或者说,在需要特殊处理的场景才使用其他注解或者定制序列化方案。使用钩子接口Jackson2ObjectMapperBuilderCustomizer可以实现ObjectMapper的属性定制:

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
        return customizer->{
            customizer.serializerByType(LocalDateTime.class,new LocalDateTimeSerializer(
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            customizer.deserializerByType(LocalDateTime.class,new LocalDateTimeDeserializer(
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        };
    }

    这样就能定制化MappingJackson2HttpMessageConverter中持有的ObjectMapper,上面的LocalDateTime序列化和反序列化器对全局生效。

    请求URL匹配

    前面基本介绍完了主流的请求参数处理,其实SpringMVC中还会按照URL的模式进行匹配,使用的是Ant路径风格,处理工具类为org.springframework.util.AntPathMatcher,从此类的注释来看,匹配规则主要包括下面四点:

    • 1、?匹配1个字符。
    • 2、*匹配0个或者多个字符
    • 3、**匹配路径中0个或者多个目录
    • 4、{spring:[a-z]+}将正则表达式[a-z]+匹配到的值,赋值给名为spring的路径变量。

    举些例子:

    ?形式的URL

    @GetMapping(value = "/pattern?")
    public String pattern() {
        return "success";
    }
    
    /pattern  404 Not Found
    /patternd  200 OK
    /patterndd  404 Not Found
    /pattern/  404 Not Found
    /patternd/s  404 Not Found

    *形式的URL

    @GetMapping(value = "/pattern*")
    public String pattern() {
        return "success";
    }
    
    /pattern  200 OK
    /pattern/  200 OK
    /patternd  200 OK
    /pattern/a  404 Not Found

    **形式的URL

    @GetMapping(value = "/pattern/**/p")
    public String pattern() {
        return "success";
    }
    
    /pattern/p  200 OK
    /pattern/x/p  200 OK
    /pattern/x/y/p  200 OK

    {spring:[a-z]+}形式的URL

    @GetMapping(value = "/pattern/{key:[a-c]+}")
    public String pattern(@PathVariable(name = "key") String key) {
        return "success";
    }
    
    /pattern/a  200 OK
    /pattern/ab  200 OK
    /pattern/abc  200 OK
    /pattern  404 Not Found
    /pattern/abcd  404 Not Found

    上面的四种URL模式可以组合使用,千变万化。

    URL匹配还遵循精确匹配原则,也就是存在两个模式对同一个URL都能够匹配成功,则选取最精确的URL匹配,进入对应的控制器方法,举个例子:

    @GetMapping(value = "/pattern/**/p")
    public String pattern1() {
        return "success";
    }
    
    @GetMapping(value = "/pattern/p")
    public String pattern2() {
        return "success";
    }

    上面两个控制器,如果请求URL为/pattern/p,最终进入的方法为pattern2

    最后,org.springframework.util.AntPathMatcher作为一个工具类,可以单独使用,不仅仅可以用于匹配URL,也可以用于匹配系统文件路径,不过需要使用其带参数构造改变内部的pathSeparator变量,例如:

    AntPathMatcher antPathMatcher = new AntPathMatcher(File.separator);

    小结

    笔者在前一段时间曾经花大量时间梳理和分析过Spring、SpringMVC的源码,但是后面一段很长的时间需要进行业务开发,对架构方面的东西有点生疏了,毕竟东西不用就会生疏,这个是常理。这篇文章基于一些SpringMVC的源码经验总结了请求参数的处理相关的一些知识,希望帮到自己和大家。

    参考资料:

    • spring-boot-web-starter:2.0.3.RELEASE源码。

    (本文完)

    展开全文
  • 为了严格按照接口进行开发,提高效率,对请求及响应格式进行规范化。 1、get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。 2、Post请求时,可以提交form表单数据...

     一.接口开发规范

    1.1 Api请求及响应规范

    为了严格按照接口进行开发,提高效率,对请求及响应格式进行规范化。

    1get 请求时,采用key/value格式请求,SpringMVC可采用基本类型的变量接收,也可以采用对象接收。

    2Post请求时,可以提交form表单数据(application/x-www-form-urlencoded)和Json数据(Content- Type=application/json),文件等多部件类型(multipart/form-data)三种数据格式,SpringMVC接收Json数据  使用@RequestBody注解解析请求的json数据。

    4、响应结果统一信息为:是否成功、操作代码、提示信息及自定义数据。

    5、响应结果统一格式为json

    1.2 Api定义约束

    Api定义使用SpringMVC来完成,由于此接口后期将作为微服务远程调用使用,在定义接口时有如下限制:

    1@PathVariable 统一指定参数名称,如:@PathVariable("id")

    2@RequestParam统一指定参数名称,如: @RequestParam"id"

    二.接口返回模板

    2.1 demo1

    import lombok.Data;
    
    @Data
    public class ResultVO<T> {
    
        /** 错误码. */
        private Integer code;
    
        /** 提示信息. */
        private String msg;
    
        /** 具体内容. */
        private T data;
    }
    
    
    public class ResultVOUtil {
    
        public static ResultVO success(Object object) {
            ResultVO resultVO = new ResultVO();
            resultVO.setData(object);
            resultVO.setCode(0);
            resultVO.setMsg("成功");
            return resultVO;
        }
    
        public static ResultVO success() {
            return success(null);
        }
    
        public static ResultVO error(Integer code, String msg) {
            ResultVO resultVO = new ResultVO();
            resultVO.setCode(code);
            resultVO.setMsg(msg);
            return resultVO;
        }
    }

    2.2 demo2

    .....................

    展开全文
  • 常用接口文档模板

    2018-12-04 20:49:00
    接口规范说起来大,其实也就那么几个部分,接口规范、接口管理工具、接口文档编写、...六:请求参数规范 七:列表请求特殊规范 八:返回数据规范 九:接口文档规范 十:接口管理工具使用教程 参...
  • 前提在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结。SpringMVC中处理控制器参数的接口是HandlerMethodArgum...
  • RESTFul API 接口文档模板

    万次阅读 2019-01-13 16:01:08
    修订记录 发布日期 修改说明 2019-01-01 第一次发布 ...若请求消息体中的参数支持中文,则中文字符必须为UTF-8编码。 时间与日期 日期与时间的表示有多种方式。为统一起见,除非是约定俗...
  • 在flask-restplus下统一接口返回格式 背景 在使用flask+flask-restplus时,业务正常时接口函数返回一个可以json序列化的对象 @ns.route('/hello') class Hello(Resource): def get(self): return ['hello', 'hi'] ...
  • 文章目录构建FeignClient接口实现动态url带参数请求带动态参数请求下载文件的请求请求体的请求 官方使用文档:链接 构建FeignClient接口实现 public static final <T> T getFeignClient(Class<T> ...
  • 1、直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交。 /** * 1.直接把表单的参数写在Controller相应的方法的形参中 * @param username * @param password * @...
  • https://gitee.com/xxssyyyyssxx/httpclient ... 我们项目中可能会使用很多的http请求的库,比如URLConnection、ApacheClient、OkHttp库等。每个库的操作方式都不一样,这是一个巨大的困扰。如果需要换...
  • 这个接口中的银联支付接口实际也是走的支付宝接口,不需要单独申请银联了。但是!支付宝的这个接口已经下架了,以前已经接入的此接口还可以照常使用,新接入的不能再使用银联接口。这个demo发出来已经比较久了,后面...
  • 针对上一篇文章的接口设计,提供了三种实现URLConnection、ApacheHttpClient、OkHttp3。 现给出三种实现的继承树。 HTTPURLConnection ApacheHttp OkHttp3 首先每种实现都需要实现模板方法HttpTemplate。...
  • php 写http请求接口供第三方平台调用

    千次阅读 2018-07-19 16:32:11
    接口参数要求 传递过来的参数为json格式。如: { "code": "XXXX_接口创建的验证码", "status": "rejected", "remarks": "模板内容不符合规范,...
  • 请求参数型注解 1、组件型注解 2、请求参数型注解 2.1 @RestController 2.2 @RequestMapping 2.3 @PathVariable 2.4 @RequestParam 2.5 @RequestBody 3、总结 前言 SpringBoot的MVC 支持主要来自于实地项目开发...
  • 接口测试提测--接口文档规范

    万次阅读 2016-06-28 17:57:40
    接口测试的依据,往往不是需求文档,而是接口文档。 那么,接口文档的准确性便至关重要,本文推荐两种形式的接口文档,供大家参考。...接口名称接口类型输入参数  每个参数名;  每个参数类型;
  • 微信新更新的sendUniformMessage接口也叫下发小程序和公众号统一的服务消息,可以支持小程序服务通知和微信公众号模板消息的发送,并且如果小程序与公众号相互关联还可根据通知进行页面的跳转交互,好吧 话不多说...
  • 软件开发 接口文档

    2019-07-19 09:11:47
    接口文档没有固定的样式,只要把相关的信息显示出来就可以 ... 请求参数 返回参数 错误码(一般大批量的接口都使用统一的错误码来返回) 下面是本人使用过的接口文档样式 这是腾讯官方的接口文档 ...
  • SprinBoot:简述SpringBoot控制层的统一异常处理(Rest接口) 《 SprinBoot:简述SpringBoot控制层的统一异常处理(错误页面) 》 《 SprinBoot:简述SpringBoot控制层的统一异常处理(Rest接口) 》  实际...
  • Spring Cloud中如何优雅的使用Feign调用接口

    万次阅读 多人点赞 2017-11-30 10:37:45
    JAVA 项目中接口调用怎么做 ? Httpclient Okhttp Httpurlconnection RestTemplate 上面是最常见的几种用法,...Feign提供了HTTP请求模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求参数、格式、地址
  • 小程序群发模板消息

    千次阅读 2019-07-16 19:54:51
    场景: 微信小程序一键群发模板消息(针对所有使用过小程序的用户),发送消息提醒用户,进入指定页面。 实现步骤: 利用form表单的按钮收集用户的formId存入数据库(如果当前没有formId,就直接存,如果有formId...
  • Vue中进行异步请求

    万次阅读 2018-09-06 17:49:50
    前端的数据均是通过接口请求拿到的,而Vue本身不支持ajax请求,那么该怎么解决Vue中的异步请求呢?这儿提供了几种方法,希望对大家有所帮组。 一、axios实现异步请求 1.项目中安装axiox npm install –...
  • 整理:对接收的数据与返回数据进行统一的封装整理,方便处理接收与返回数据,并对数据进行验证,通过C#的特性对token进行验证,并通过时间戳的方式统一处理接收与返回的时间格式。 请求Json格式: { "Cmd": ...
  • SpringMVC处理请求的流程

    千次阅读 2016-10-09 09:38:53
    Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发...
  • 如何设计出高可用、高性能的接口

    千次阅读 2019-03-02 14:24:46
    发起这个 Chat 只是一时兴起,想了一些点就写出来了,但自己一读,感觉一点干货都没有,真是汗颜。但还是也希望此拙文能带来一些你的思考,欢迎... 请求参数。 支持的协议。 TPS、并发数、响应时长。 ...
  • 高可用、高性能? 接口设计的 16 个原则

    万次阅读 多人点赞 2017-12-04 00:00:00
    本文来自作者 LY 在 GitChat 上分享「如何设计出高可用、高性能的接口」,「阅读原文」查看交流实录 「文末高能」 编辑 | 嘉仔 ...发起这个 Chat 只是一时兴起,想了一些点就写...请求参数。 支持的协议。
  • SpringMVC请求处理流程

    千次阅读 2017-04-10 16:29:44
     1、DispatchServlet:Spring MVC的核心控制器,作为SpringMVC请求处理以及请求返回的统一入口,进行全局的流程控制。    2、HandlerMapping:处理映射器,根据请求的url映射到对应的处理器(Controller)的某个...
  • Jmeter接口测试+压力测试

    万次阅读 多人点赞 2017-05-14 14:01:50
    jmeter是apache公司基于java开发的一款开源压力测试工具,体积小,功能全,使用方便,是一个比较轻量级的测试工具,使用起来非常简单。因为jmeter是java开发的,所以运行的时候必须先要安装...其中接口测试的简单操作
  • freemarker模板加载器

    千次阅读 2015-10-27 17:49:33
    FreeMarker 为模版文件加载器定义了一个统一接口 —— TemplateLoader ,该接口有以下四个方法: closeTemplateSource 关闭模版资源 findTemplateSource 根据名称返回指定的...
  • 该类的实例是twig模板系统的中心枢纽,也叫环境对象,用于保存配置、twig扩展、加载模板等,在她内部调度twig系统的各个类,可以说她是系统的对外使用接口,代表整个twig系统,因此通常用$twig变量名来表示她(在本....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,162
精华内容 17,264
关键字:

统一接口请求参数模板