原 spring boot集成jsr303
版权声明:本文为博主原创文章,请尊重他人的劳动成果,转载请附上原文出处链接和本声明。
本文链接:https://www.91mszl.com/zhangwuji/article/details/1283
我们看下如下的代码,我们判断字段非空,要写一堆的代码,代码很臃肿,有没有一个工具来帮助我们简化开发呢,答案是有的。
@PostMapping("/update/point")
public ResultMessage updateRegionInfo(@RequestBody UpdatePickPointVO uv){
ResultMessage result=null;
if(StringUtils.isNotBlank(uv.getPrePlanNo()) && StringUtils.isNotBlank(uv.getRouteNo()) && StringUtils.isNotBlank(uv.getPrecinctNo())
&& null!=uv.getStoreList() && 0!=uv.getTimes() && StringUtils.isNotBlank(uv.getVisitWeek()) && StringUtils.isNotBlank(uv.getVisitWeekDay())){
result=batchPickPointService.updateRegionInfo(uv);
} else if(StringUtils.isBlank(uv.getPrePlanNo())){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_PREPLANNO);
} else if(StringUtils.isBlank(uv.getRouteNo())){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_ROUTENO);
} else if(StringUtils.isBlank(uv.getPrecinctNo())){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_PRECINCTNO);
} else if(null==uv.getStoreList()){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_STORELIST);
} else if(0==uv.getTimes()){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_TIMES);
} else if(StringUtils.isBlank(uv.getVisitWeek())){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_VISITWEEK);
} else if(StringUtils.isBlank(uv.getVisitWeekDay())){
result=ResultMessage.fail(PlanRevisionMsg.NOTEMPTY_VISITWEEKDAY);
} else{
result=ResultMessage.fail(PlanRevisionMsg.NETWORK_ANOMALY);
}
return result;
}
2.1 引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
2.2 在controller的方法上加上@Valid ,注意这是post请求
@PostMapping("/update/point")
public ResultMessage updateRegionInfo(@Valid @RequestBody UpdatePickPointVO uv){
ResultMessage result=batchPickPointService.updateRegionInfo(uv);
return result;
}
2.3 在vo类上加上必填注解。
public class UpdatePickPointVO {
@ApiModelProperty(value = "预计划编号")
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_PREPLANNO)
private String prePlanNo;
@ApiModelProperty(value = "片区编号")
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_PRECINCTNO)
private String precinctNo;
}
注解 | 描述 |
---|---|
@Null | 验证对象是否为null |
@NotNull | 验证对象是否不为 null,无法检验长度为0的字符串 |
@AssertTrue | 验证Boolean对象是否为true |
@AssertFalse | 验证Boolean对象是否为false |
@Min(value) | 值必须小于value,支持BigDecimal、BigInteger,byte、shot、int、long及其包装类 |
@Max(value) | 值必须大于value,支持BigDecimal、BigInteger,byte、shot、int、long及其包装类 |
@DecimalMin(value) | 值必须小于value,支持BigDecimal、BigInteger、CharSequence,byte、shot、int、long及其包装类 |
@DecimalMax(value) | 值必须大于value,支持BigDecimal、BigInteger、CharSequence,byte、shot、int、long及其包装类 |
@Size(max=, min=) | 验证对象(CharSequence、Collection、Map、Array)长度是否在给定的范围之内 |
@Digits(integer=, fraction=) | 必须是一个数字,integer表示该数字最多多少位,如:10,fraction表示小数位上限,如:2,表示最多10位,并最多2位小数 |
@Negative | 必须是一个负数 |
@NegativeOrZero | 必须是一个负数或0 |
@Positive | 必须是一个正数 |
@PositiveOrZero(message = ) | 必须是个正数或0 |
@Past | 验证Date和 Calendar对象是否在当前时间之前 |
@PastOrPresent | 必须是一个过去的或当前的日期 |
@Future | 验证Date和Calendar对象是否在当前时间之后 |
@FutureOrPresent | 必须是一个未来的或当前的日期 |
@Pattern(regexp) | 必须符合指定的正则表达式 |
@NotBlank(message = ) | 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格 |
必须是电子邮箱地址 | |
@NotEmpty | 检查约束元素是否为NULL或者是EMPTY |
@Length(min = , max = , message = ) | 设置字段的最小长度和最大长度 |
4.1 验证int类型使用 @NotNull ,并使用Integer,不要使用int,因为使用int默认值为0,如下所示。
@NotNull(message = "xxx不能为空")
private Integer times;
4.2 验证String类型,使用 @NotBlank
@NotBlank(message = "xxx不能为空")
private String precinctNo;
4.3 验证List<String>中是否为空,使用 @NotEmpty
@NotEmpty(message = "xxList不能为空")
private List<String> storeList;
4.4 验证嵌套List<
@Data
public class UpdateSalesInfo {
@ApiModelProperty(value = "xxlist")
@Valid
@NotEmpty(message = "xxList不能为空")
private List<SalesInfoVO> salesinfoList;
}
@Data
public class SalesInfoVO {
@ApiModelProperty(value = "xx编号")
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_PRECINCTNO)
private String precinctNo;
@ApiModelProperty(value = "xxcode")
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_EMPNO)
private String empNo;
@ApiModelProperty(value = "xx名称")
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_EMPNAME)
private String empName;
}
4.5 使用正则验证,isExport字段不能为空,且只能输入Y或N
@ApiModelProperty(value = "是否导出: N为不导出; Y为导出")
@Pattern(regexp="^[Y|N]$", message = "只能输入N或Y")
@NotBlank(message = RodeoConstants.NOTEMPTY_ISEXPORT)
private String isExport;
4.6 设置字段长度限制
@Length(min = 0, max = 30, message = "最大长度为30")
private String bookmarkName;
4.7 设置只能输入指定的参数
@Pattern(regexp="(GET|POST|DELETE|PUT)", message = "请求方式只能输入GET、POST、DELETE、PUT")
@NotBlank(message="请求方式不能为空")
private String requestMethod;
4.8 设置只能输入年月日时分秒这种日期格式
@Pattern(regexp="([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))([ ])([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])", message = "调用时间格式只能为年月日时分秒")
@NotBlank(message="调用时间不能为空")
private String startDate;
5.1 post请求:如果我们请求是post的话,按照本节2.2, 2.3 的步骤去做即可。
5.2 get请求:有两种方式。
5.3 方式一:将传参一个个的列在方法上,并加上验证规则之类的,还需要Controller上加上@Validated,
注意:@Validated必须加在类上,加在方法上会不生效。
@Validated
@RestController
@RequestMapping("/product/brand")
public class BrandController {
@GetMapping("/select/info")
public ResultMessage selectStoreInfo(@NotBlank(message = PlanRevisionMsg.NOTEMPTY_PREPLANNO) String prePlanNo,
@NotBlank(message = PlanRevisionMsg.NOTEMPTY_STOREID) String storeId) {
SelectStoreInfoVO sv = new SelectStoreInfoVO();
sv.setPrePlanNo(prePlanNo);
sv.setStoreId(storeId);
ResultMessage result = storeDetailsService.selectStoreInfo(sv);
return result;
}
}
@GetMapping("/select/info")
public ResultMessage selectStoreInfo(@Validated SelectStoreInfoVO sv){
ResultMessage result=storeDetailsService.selectStoreInfo(sv);
return result;
}
如果直接这样写的话,调用接口会返回如下图所示:
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors\nField error in object 'selectStoreInfoVO' on field 'storeId': rejected value [null]; codes [NotBlank.selectStoreInfoVO.storeId,NotBlank.storeId,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [selectStoreInfoVO.storeId,storeId]; arguments []; default message [storeId]]; default message [预计划编号不能为空!]\nField error in object 'selectSto
这样返回给前端肯定不友好。我们需要在统一异常处理里面拦截 BindException,然后给用户一个清晰的提示。
5.5 配置jsr config注解。(我在spring boot 项目中需要配置,但在spring cloud alibab项目中,不配置貌似也没问题,get方法也能正常使用)
package com.mszl.web.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
/**
* 描述:jsr303
*/
@Configuration
public class ValidationConfig {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
5.6 统一异常处理里面:
package com.mszl.blog.exception;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Set;
import com.mszl.blog.utils.ReturnMsgUtils;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
/**
* 全局统一异常处理
*/
@ControllerAdvice
@Slf4j
public class GlobalDefultExceptionHandler {
// 声明要捕获的异常
@ExceptionHandler(Exception.class)
@ResponseBody
public ReturnMsgUtils defultExcepitonHandler(Exception ex) {
ReturnMsgUtils result=null;
if(ex instanceof BusinessException) {
BusinessException businessException = (BusinessException)ex;
result=new ReturnMsgUtils(businessException.getCode(), businessException.getMessage());
return result;
} else if(ex instanceof BindException){ // 解决jsr 303 get请求,多个参数封装到vo的统一异常处理
BindingResult bindResult=((BindException) ex).getBindingResult();
List<ObjectError> errorList=bindResult.getAllErrors();
String message=errorList.get(0).getDefaultMessage(); // 取第一条错误信息进行展示
return ReturnMsgUtils.fail(message);
} else{
Throwable tb = ex;
StringWriter stringWriter= new StringWriter();
PrintWriter writer= new PrintWriter(stringWriter);
tb.printStackTrace(writer);
StringBuffer buffer= stringWriter.getBuffer();
log.error(buffer.toString());
result=ReturnMsgUtils.fail(buffer.toString());
return result;
}
}
// jsr303处理@RequestParam校验不通过异常:解决get请求单个参数,统一异常处理。
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
public ReturnMsgUtils validationError(ConstraintViolationException ex) {
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
String kk=violations.iterator().next().getMessage();
return ReturnMsgUtils.fail(kk);
}
}
参考资料:
https://blog.csdn.net/haibo_bear/article/details/90265741
https://www.cnblogs.com/mr-yang-localhost/p/7812038.html
https://blog.csdn.net/weixin_43137625/article/details/83181397
请教大神指导的贴:
https://blog.csdn.net/yuxiao97/article/details/98309120#comments_136550702020-10-29 15:22:18 阅读(974)
名师出品,必属精品 https://www.91mszl.com
博主信息