温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用Spring MVC怎么对参数进行校验

发布时间:2020-11-30 17:34:35 来源:亿速云 阅读:311 作者:Leah 栏目:编程语言

本篇文章为大家展示了使用Spring MVC怎么对参数进行校验,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

1. 内嵌异常处理

如果只是这个controller的异常做单独处理,那么就适合绑定这个controller本身的异常。

具体做法是使用注解@ExceptionHandler.

在这个controller中添加一个方法,并添加上述注解,并指明要拦截的异常。

@RequestMapping(value = "saveOrUpdate", method = RequestMethod.POST) public String saveOrUpdate(HttpServletResponse response, @RequestBody Order order){  CodeMsg result = null;  try {  result = orderService.saveOrUpdate(order);  } catch (Exception e) {  logger.error("save failed.", e);  return this.renderString(response, CodeMsg.error(e.getMessage()));  }  return this.renderString(response, result); } @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(HttpMessageNotReadableException.class) public CodeMsg messageNotReadable(HttpMessageNotReadableException exception, HttpServletResponse response){  LOGGER.error("请求参数不匹配。", exception);  return CodeMsg.error(exception.getMessage()); }

这里saveOrUpdate是我们想要拦截一样的请求,而messageNotReadable则是处理异常的代码。
@ExceptionHandler(HttpMessageNotReadableException.class)表示我要拦截何种异常。在这里,由于springmvc默认采用jackson作为json序列化工具,当反序列化失败的时候就会抛出HttpMessageNotReadableException异常。具体如下:

{  "code": 1,  "msg": "Could not read JSON: Failed to parse Date value '2017-03-' (format: \"yyyy-MM-dd HH:mm:ss\"): Unparseable date: \"2017-03-\" (through reference chain: com.test.modules.order.entity.Order[\"serveTime\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to parse Date value '2017-03-' (format: \"yyyy-MM-dd HH:mm:ss\"): Unparseable date: \"2017-03-\" (through reference chain: com.test.modules.order.entity.Order[\"serveTime\"])",  "data": "" }

这是个典型的jackson反序列化失败异常,也是造成我遇见过的400原因最多的。通常是日期格式不对。

另外, @ResponseStatus(HttpStatus.BAD_REQUEST)这个注解是为了标识这个方法返回值的HttpStatus code。我设置为400,当然也可以自定义成其他的。

2. 批量异常处理

看到大多数资料写的是全局异常处理,我觉得对我来说批量更合适些,因为我只是希望部分controller被拦截而不是全部。

springmvc提供了@ControllerAdvice来做批量拦截。

第一次看到注释这么少的源码,忍不住多读几遍。

Indicates the annotated class assists a "Controller".

表示这个注解是服务于Controller的。

Serves as a specialization of {@link Component @Component}, allowing for implementation classes to be autodetected through classpath scanning.

用来当做特殊的Component注解,允许使用者扫描发现所有的classpath。

It is typically used to define {@link ExceptionHandler @ExceptionHandler},  * {@link InitBinder @InitBinder}, and {@link ModelAttribute @ModelAttribute}  * methods that apply to all {@link RequestMapping @RequestMapping} methods.

典型的应用是用来定义xxxx.

One of {@link #annotations()}, {@link #basePackageClasses()},  * {@link #basePackages()} or its alias {@link #value()}  * may be specified to define specific subsets of Controllers  * to assist. When multiple selectors are applied, OR logic is applied -  * meaning selected Controllers should match at least one selector.

这几个参数指定了扫描范围。

the default behavior (i.e. if used without any selector),  * the {@code @ControllerAdvice} annotated class will  * assist all known Controllers.

默认扫描所有的已知的的Controllers。

Note that those checks are done at runtime, so adding many attributes and using  * multiple strategies may have negative impacts (complexity, performance).

注意这个检查是在运行时做的,所以注意性能问题,不要放太多的参数。

说的如此清楚,以至于用法如此简单。

@ResponseBody @ControllerAdvice("com.api") public class ApiExceptionHandler extends BaseClientController {  private static final Logger LOGGER = LoggerFactory.getLogger(ApiExceptionHandler.class);  /**   *   * @param exception UnexpectedTypeException   * @param response   * @return   */  @ResponseStatus(HttpStatus.BAD_REQUEST)  @ExceptionHandler(UnexpectedTypeException.class)  public CodeMsg unexpectedType(UnexpectedTypeException exception, HttpServletResponse response){   LOGGER.error("校验方法太多,不确定合适的校验方法。", exception);   return CodeMsg.error(exception.getMessage());  }  @ResponseStatus(HttpStatus.BAD_REQUEST)  @ExceptionHandler(HttpMessageNotReadableException.class)  public CodeMsg messageNotReadable(HttpMessageNotReadableException exception, HttpServletResponse response){   LOGGER.error("请求参数不匹配,request的json格式不正确", exception);   return CodeMsg.error(exception.getMessage());  }  @ResponseStatus(HttpStatus.BAD_REQUEST)  @ExceptionHandler(Exception.class)  public CodeMsg ex(MethodArgumentNotValidException exception, HttpServletResponse response){   LOGGER.error("请求参数不合法。", exception);   BindingResult bindingResult = exception.getBindingResult();   String msg = "校验失败";   return new CodeMsg(CodeMsgConstant.error, msg, getErrors(bindingResult));  }  private Map<String, String> getErrors(BindingResult result) {   Map<String, String> map = new HashMap<>();   List<FieldError> list = result.getFieldErrors();   for (FieldError error : list) {    map.put(error.getField(), error.getDefaultMessage());   }   return map;  } }

3. Hibernate-validate

使用参数校验如果不catch异常就会返回400. 所以这个也要规范一下。

3.1 引入hibernate-validate

<dependency>   <groupId>org.hibernate</groupId>   <artifactId>hibernate-validator</artifactId>   <version>5.0.2.Final</version>  </dependency>
<mvc:annotation-driven validator="validator" /> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">  <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>  <property name="validationMessageSource" ref="messageSource"/> </bean>

3.2 使用

在实体类字段上标注要求

public class AlipayRequest {  @NotEmpty  private String out_trade_no;  private String subject;  @DecimalMin(value = "0.01", message = "费用最少不能小于0.01")  @DecimalMax(value = "100000000.00", message = "费用最大不能超过100000000")  private String total_fee;  /**   * 订单类型   */  @NotEmpty(message = "订单类型不能为空")  private String business_type;  //.... }

controller里添加@Valid

@RequestMapping(value = "sign", method = RequestMethod.POST)  public String sign(@Valid @RequestBody AlipayRequest params  ){   ....  }

4.错误处理

前面已经提到,如果不做处理的结果就是400,415. 这个对应Exception是MethodArgumentNotValidException,也是这样:

@ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(Exception.class) public CodeMsg ex(MethodArgumentNotValidException exception, HttpServletResponse response){  LOGGER.error("请求参数不合法。", exception);  BindingResult bindingResult = exception.getBindingResult();  String msg = "校验失败";  return new CodeMsg(CodeMsgConstant.error, msg, getErrors(bindingResult)); } private Map<String, String> getErrors(BindingResult result) {  Map<String, String> map = new HashMap<>();  List<FieldError> list = result.getFieldErrors();  for (FieldError error : list) {   map.put(error.getField(), error.getDefaultMessage());  }  return map; }

返回结果:

{  "code": 1,  "msg": "校验失败",  "data": {  "out_trade_no": "不能为空",  "business_type": "订单类型不能为空"  } }

大概有这么几个限制注解:

/**  * Bean Validation 中内置的 constraint    * @Null 被注释的元素必须为 null    * @NotNull 被注释的元素必须不为 null    * @AssertTrue  被注释的元素必须为 true    * @AssertFalse 被注释的元素必须为 false  +  * @Min(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    * @Max(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    * @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值    * @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值    * @Size(max=, min=) 被注释的元素的大小必须在指定的范围内    * @Digits (integer, fraction)  被注释的元素必须是一个数字,其值必须在可接受的范围内    * @Past 被注释的元素必须是一个过去的日期    * @Future  被注释的元素必须是一个将来的日期    * @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式    * Hibernate Validator 附加的 constraint    * @NotBlank(message =) 验证字符串非null,且长度必须大于0    * @Email 被注释的元素必须是电子邮箱地址    * @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内    * @NotEmpty 被注释的字符串的必须非空    * @Range(min=,max=,message=) 被注释的元素必须在合适的范围内   */

上述内容就是使用Spring MVC怎么对参数进行校验,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI