(3)、@GetMapping 入参注解注意事项
GET 请求当使用 @RequestParm 注解和不加注解时,只能接收到 params 携带的参数 ,参数放在请求头 和请求体中均接受不到。
GET 请求 不可以使用 @RequestBody 注解
11、@PostMapping注解说明
(1)、@PostMapping是@RequestMapping(method = RequestMethod.POST) 快捷方式
(2)、@GetMapping 入参注解注意事项
POST请求 当使用 @RequestParm 注解 和 不加注解时,只能接收到 params 和请求体xxx格式携带的参数,加注解无法接收到对象参数。
POST请求 当使用 @RequestBody注解 ,只能接收到请求体JSON格式和表单携带的参数 其他类型参数均接受不到
POST请求接收一个参数 不可以使用 @RequestBody 注解。
二、参数接收
1、Body参数
Body参数一般是POST请求,主要有两种方式
- 以JSON格式接收可通过@RequestBody获取对应的参数
- 以form表单形式提交的,暂无注解适配,可直接对象接收
(1)、JSON参数接收
例如:添加用户的接口, 前端PostMan 请求信息如下:
后端接收代码1:
@PostMapping(value = "/user/map") public ResultVO createUser(@RequestBody Map<String,Object> user) { String name=user.get("name").toString(); return RV.success(user); }
后端接收代码2:
@PostMapping(value = "/user") public ResultVO createUser2(@RequestBody User user) { System.out.println("User Info:"+user.toString()); return RV.success(user); }
(2)、FORM 参数接收
form方式提交,在PostMan中对应参数如下
对应后端接收代码:
@PostMapping(value = "/user/form") public ResultVO createUser3(User user) { System.out.println("User Info:"+user.toString()); return RV.success(user); }
2、请求头和Cookie参数
- @RequestHeader,是直接获取请求头HttpServletRequest对象里面Header中的参数
- @CookieValue 可以直接获取HttpServletRequest对象里面Cookies中的参数
通过注解的方式获取,分别如下
@GetMapping("demo3") public void demo3(@RequestHeader(name = "myHeader") String myHeader, @CookieValue(name = "myCookie") String myCookie) { System.out.println("myHeader=" + myHeader); System.out.println("myCookie=" + myCookie); }
通过硬编码的获取方式为
@GetMapping("/demo3") public void demo3(HttpServletRequest request) { System.out.println(request.getHeader("myHeader")); for (Cookie cookie : request.getCookies()) { if ("myCookie".equals(cookie.getName())) { System.out.println(cookie.getValue()); } } }
由上可以看出,通过注解的方式可以极大简化编码,使我们的代码变得美观大方,如果通过request对象直接获取,也是可以的,这个主要是看什么样的需求,一般情况下,通过注解的方式基本上能满足我们的绝大部分需求,所以在项目中我们比较推荐直接通过注解的方式获取参数。
3、文件上传参数
文件上传主要是基于@RequestParam 结合MultipartFile对象;如下示例;
这里需要注意,前端的传入需要用表单方式提交,并且在Head的Content-Type里面加入,如下信息
Content-Type: application/x-www-form-urlencoded
对应后端代码如下
@Value("${file.upload.url}") private String filePath; @RequestMapping("/upload") public ResultVO httpUpload(@RequestParam("files") MultipartFile files[]){ for(int i=0;i<files.length;i++) { String fileName = files[i].getOriginalFilename(); // 文件名 File dest = new File(filePath+'/'+fileName); if (!dest.getParentFile().exists()) { dest.getParentFile().mkdirs(); } try { files[i].transferTo(dest); } catch (Exception e) { log.error("{}",e); return RV.result(ErrorCode.UPLOAD_FILE_ERROR,e); } } return RV.success(null); }
三、参数校验
在Controller层的参数校验可以分为两种场景,单个参数校验和实体参数校验
(1)、单个参数校验
后端代码如下
@RestControllerpublic class ValidateController { @GetMapping("/getUser") @Validated public ResultVO getUserStr(@NotNull(message = "name 不能为空") String name, @Max(value = 99, message = "不能大于99岁") Integer age) { return RV.success("name: " + name + " ,age:" + age); } }
在Postman请求如下,可以看到请求后,返回了系统异常,应该是被全局异常拦截了.
我们再看后台打印的日志:
如果我们系统中有很多地方都用到了参数校验,那么我们最好是能够在全局异常拦截处直接拦截ConstraintViolationException异常,并进行统一处理,可以在我们前面章节讲到的,在加了@RestControllerAdvice注解的GlobalException类中加入如下拦截的新方法;由于ConstraintViolationException继承了ValidationException异常类,所以我们可以直接拦截父类异常,直接进行多个不同的校验异常进行处理.
@RestControllerAdvice public class GlobalException { @ExceptionHandler(value = ValidationException.class) public ResultVO validationException(ValidationException e){ Map map=new HashMap(); if(e instanceof ConstraintViolationException){ ConstraintViolationException exs = (ConstraintViolationException) e; Set<ConstraintViolation>> violations = exs.getConstraintViolations(); for (ConstraintViolation> item : violations) { //打印验证不通过的信息 System.out.println(item.getMessage()); map.put(item.getPropertyPath(),item.getMessage()); } } return RV.result(ErrorCode.FORM_VALIDATION_ERROR,map) ; } }
同样,再通过Postman请求后,得到如下结果
(2、)实体参数校验
一般我们在传入参数比较少的情况下,就直接用上面的方法进行了验证了,但是,如果我们传入的是一个对象,直接在方法上一个一个属性设置,就显得有点不美观了,因此我们一般都是封装一个接收参数的对象。如下面实例提供的,添加用户接口,我们对用户对象的变量设置了校验规则,如下
@Dataclass Person { @NotNull(message = "名称不能为空") @Max(value = 30, message = "名称不能超过30个字符") String name; @Max(value = 200, message = "年龄不能超过200岁吧") @NotNull(message = "年龄不能为空") Integer age; @NotNull(message = "地址信息不能为空") String address; }
在Controller类中我们增加添加用户的方法,这里我们需要注意,我们只需要在方法对应的参数Person对象前面加上@Valid注解即可
@PostMapping(value = "/person") public ResultVO<Person> addPerson(@RequestBody @Valid Person person) { //此处略过处理业务的代码... return RV.success(person); }
其实大家可能就会问,那要是参数校验不同过,这里应该是抛出什么异常呢,当我们执行如上代码,设定超出范围的参数后,在后端可以看到异常如下
可以看到,这里抛出的MethodArgumentNotValidException与上面的异常截然不同;相同道理,我依然在GlobalException类中加入对MethodArgumentNotValidException异常的全局拦截即可
@ExceptionHandler(value = MethodArgumentNotValidException.class) public ResultVO methodArgumentNotValidException(MethodArgumentNotValidException e){ List<ObjectError> errors = e.getBindingResult().getAllErrors(); String[] errMessage=new String[errors.size()]; for (int i = 0; i < errors.size(); i++) { ObjectError error=errors.get(i); errMessage[i]=error.getDefaultMessage(); System.out.println(error.getCode()+":"+error.getDefaultMessage()); } return RV.result(ErrorCode.METHOD_ARGS_VALID_ERROR,errMessage) ; }
Validated与Valid区别
- @Validated: 用在方法的入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
- @Valid:用在方法入的参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
如上Person对象,如果里面再有一个对象,比如还是Person,在提交的过程中,需要这种嵌套验证,就需要通过使用Valid的嵌套验证功能,即可将代码修改如下;
@Dataclass Person { @NotNull(message = "名称不能为空") @Size(min = 2,max = 30, message = "名称长度限定在2-30之间的长度") String name; @Max(value = 200, message = "年龄不能超过200岁吧") @NotNull(message = "年龄不能为空") Integer age; @NotNull(message = "地址信息不能为空") String address; @Valid Person p; }
常用参数校验的注解
这里我们主要介绍在springboot中的几种参数校验方式。常用的用于参数校验的注解如下:
- @AssertFalse 所注解的元素必须是Boolean类型,且值为false
- @AssertTrue 所注解的元素必须是Boolean类型,且值为true
- @DecimalMax 所注解的元素必须是数字,且值小于等于给定的值
- @DecimalMin 所注解的元素必须是数字,且值大于等于给定的值
- @Digits 所注解的元素必须是数字,且值必须是指定的位数
- @Future 所注解的元素必须是将来某个日期
- @Max 所注解的元素必须是数字,且值小于等于给定的值
- @Min 所注解的元素必须是数字,且值小于等于给定的值
- @Range 所注解的元素需在指定范围区间内
- @NotNull 所注解的元素值不能为null
- @NotBlank 所注解的元素值有内容
- @Null 所注解的元素值为null
- @Past 所注解的元素必须是某个过去的日期
- @PastOrPresent 所注解的元素必须是过去某个或现在日期
- @Pattern 所注解的元素必须满足给定的正则表达式
- @Size 所注解的元素必须是String、集合或数组,且长度大小需保证在给定范围之内
- @Email 所注解的元素需满足Email格式