目录
场景再现:
怎么做?
遇到了什么问题?
怎么实现?
某API接口接受加密的json字符串,接受字符串之后先进行解密处理,解密完成之后还要进行参数校验处理,如果参数不合规范会直接返回提示信息。
我们完全可以中规中矩的,先在controller层接受字符串,然后解密,然后在serivce层参数校验,但是这里有个问题,那就是解密后的json字符串将变成一个对象,然后这个对象中的字段却十分的多几十来个,如果使用普通的方法校验,每个参数都需要一个if语句,那该是多磨的可怕呀!!所以我考虑借助Validated 辅助我进行参数校验。
问题就是我们平常使用Validated 参数校验是是直接在controller层进行校验的比如这样。
@PostMapping("/resume-info")
public ResponseResult
insertResumeInfo(@Validated(ValidatedGroup.Insert.class) @RequestBody ResumeMainInfoDTO dto) {
return resumeInfoService.InsertInfo(dto);
}
@Data @NoArgsConstructor @AllArgsConstructor public class ResumeMainInfoDTO { @NotBlank(message = "!",groups = ValidatedGroup.Update.class) private Long id; /** * 姓名 */ @Length(max = 20,message ="!",groups = ValidatedGroup.Select.class) @NotBlank(message = "!",groups = ValidatedGroup.Insert.class) @NotBlank(message = "!",groups = ValidatedGroup.Update.class) private String userName; }
我使用同样的方式对service使用,但是失效了。那我们相对service层使用应该怎么做呀?
controller层接受字符串参数,并转换为对象
@Autowired
ss service;
@PostMapping("/getJson")
public ResponseResult getJson(@RequestBody String dto) {
RequestDTO requestDTO = JSON.parseObject(dto, RequestDTO.class);
return service.startTask(requestDTO);
}
service层接口
public ResponseResult startTask(@Valid @RequestBody RequestDTO dto);
接口实现
@Validated
在当前类的头上加上
@Override
public ResponseResult startTask(@Valid @RequestBody RequestDTO dto) {
// 校验完成后的其他代码
return start(dto);
}
ok以上是关键的代码,下面的不关键
注意关键部分
1 service层类上加上@Validated
2 被校验的对象前加上@Valid @RequestBody(注意接口,以及接口的实现都要有)
3 在controller使用注入的方式调用即可
4 在dto里定义判断校验
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
部分dto代码
@Length(min = 1, max = 6, message = "申请类型不合法!提示:xx")
String approve_type;
// xx
Integer port_type;
@NotNull(message = "创建人id不能为空!")
// @Range(min = 1,message = "创建人id不能为空!")
Long create_user_id;
@Length(max = 32, message = "创建人名称过长!")
String create_user_name;
全局异常处理
// 1:使用PathVariable并且是get请求的参数错误。
// 2:使用RequestParam并且是from-data方式提交的post请求的参数错误。
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResult handleBindGetException(ConstraintViolationException e) {
log.error("{}", e.getMessage(), e);
List defaultMsg = e.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList());
return Params_Common_Res(defaultMsg);
}
// 错误情况:
//1 使用了ResponseBody并且是json数据类型的post请求
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("{}", e.getMessage(), e);
List defaultMsg = e.getBindingResult().getFieldErrors()
.stream()
.map(fieldError -> "【" + fieldError.getField() + "】" + fieldError.getDefaultMessage())
.collect(Collectors.toList());
return Params_Common_Res(defaultMsg);
}
/**
* 兼容Validation校验框架:忽略参数异常处理器
*/
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
log.error("{}", e.getMessage(), e);
log.error("ParameterName: {}", e.getParameterName());
log.error("ParameterType: {}", e.getParameterType());
return Params_Common_Res();
}
// 前端并没有提交必要的参数信息
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResult error(HttpMessageNotReadableException e){
log.error("{}", e.getMessage(), e);
return ErrorResult.build(new ErrorResult( false,ErrorEnum.Params_Lack_Err.getMessage(),ErrorEnum.Params_Lack_Err.getCode()), e.getMessage());
}
效果: