1 背景
服务端的接口经常要进行参数校验,传统的在方法里面校验的方式会产生很多冗余代码,因此可以使用一些工具来帮我们解决这个问题
例如 hibernate-validator
引入jar包
hibernate-validator.6.5.0.Final.jar
validation-api-1.0.0.GA.jar
使用如下
在需要校验的参数对象上加上约束注解
在controller 方法里面加上 @Valid ,使校验生效
@ApiModel
public class UserCreateRequest {
@ApiModelProperty(name = "手机验证码")
@NotBlank
private String code;
@ApiModelProperty(name = "手机号")
@NotBlank
private String phone;
private String username;
@ApiModelProperty(name = "密码")
@NotBlank
private String password;
}
@ApiOperation(value = "检验")
@PostMapping(value = "/check")
public String create(@RequestBody @Valid UserCreateRequest request) {
return null;
}
2 去掉 BindingResult
经过上面的配置,如果请求的参数校验不通过,返回的信息是这样的,这些信息没有经过整理,对前端来说很难处理 因此我们要重新整理这 些校验不通过的提示信息
通用的有一种方式,就是方法里面加上 BindingResult 参数,校验结果会存放到这个参数里面, 然后拿到异常信息返回
@ApiOperation(value = "检验")
@PostMapping(value = "/check")
public String create(@RequestBody @Valid UserCreateRequest request, BindingResult bindingResult) {
if (bindingResult.hasErrors()){
return bindingResult.getFieldError().getDefaultMessage();
}
return null;
}
尼玛这么写代码,得在每个校验的方法里面加上这个,很不爽,看我的。
异常处理机制要这么配置
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver, Ordered {
private static final Log log = LogFactory.getLog(CustomExceptionResolver.class);
@Override
public int getOrder() {
return 0;
}
// 这里将捕获到的异常做统一处理,不直接在接口返回异常的堆栈信息
@ResponseBody
@Nullable
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
@Nullable Object handler,
Exception ex) {
log.error("捕获到异常 ", ex);
ModelAndView modelAndView = new ModelAndView();
MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
Map attributes = new HashMap<>(2);
attributes.put("succeed", false);
//把校验不通过的信息重新整理返回
if (ex instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException validException = (MethodArgumentNotValidException) ex;
FieldError fieldError = validException.getBindingResult().getFieldErrors().get(0);
attributes.put("message", fieldError.getField() + " " + fieldError.getDefaultMessage());
}
mappingJackson2JsonView.setAttributesMap(attributes);
modelAndView.setView(mappingJackson2JsonView);
return modelAndView;
}
}
全局的异常处理,如果不实现 Ordered 接口并且把顺序调到最先,这个异常处理会被spring 的DefaultHandlerExceptionResolver 拦截并直接返回,你自己配置的异常处理是无法捕获校验不通过的异常的。
按照上面的方式配置好后,接口就可以返回自定义的信息啦,炒鸡方便,呵呵哒
3 实现根据浏览器的语言返回对应语言的校验不通过的信息
- 配置消息转换器 MessageInterpolator
public class MessageInterpolatorAdapter implements MessageInterpolator {
private MessageInterpolator defaultInterpolator;
public MessageInterpolatorAdapter(MessageInterpolator interpolator) {
this.defaultInterpolator = interpolator;
}
/**
* 将用户的 locale 信息传递给消息解释器,而不是使用默认的 JVM locale 信息
*/
@Override
public String interpolate(String message, Context context) {
return defaultInterpolator.interpolate(message, context, getRequestLocale());
}
@Override
public String interpolate(String message, Context context, Locale locale) {
return defaultInterpolator.interpolate(message, context, locale);
}
//getRequestLocale()方法拿到了浏览器的语言设置,请求一次执行一次
private Locale getRequestLocale() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (null == requestAttributes) {
throw new BizException("getLocale");
}
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
String acceptLang = request.getHeader("Accept-Language");
if (StringUtils.isBlank(acceptLang)) {
throw new BizException("getLocale");
}
acceptLang = acceptLang.substring(0,2);
if (acceptLang.equals("zh")) {
return new Locale("zh");
}
else {
return new Locale("en");
}
}
}
- 配置自定义的验证器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public Validator validator() {
return Validation.byDefaultProvider()
.configure()
.messageInterpolator(new MessageInterpolatorAdapter(new ResourceBundleMessageInterpolator()))
.buildValidatorFactory()
.getValidator();
}
}
验证器配置好之后用 postman 测试
-
模拟浏览器的不同语言
经过测试,这种方式可以实现根据浏览器的不同语言来返回对应的信息,完美实现web参数校验国际化
弄完这个发现自己很优秀,哈哈