Spring Boot MVC请求参数通用校验及国际化支持

简介: 目录一、Validation及国际化配置1、添加依赖2、校验失败提示消息国际化配置3、application.properties4、国际化资源文件二、代码演示1、全局异常处理2、MessageUtils工具类3、响应VO2、测试Controller和请求DTO3、多语言属性文件4、测试用例(1)简单对象UserReqDTO测试(2)包含List集合对象的ChargeRuleReqDTO测试

目录

一、Validation及国际化配置

1、添加依赖

2、校验失败提示消息国际化配置

3、application.properties

4、国际化资源文件

二、代码演示

1、全局异常处理

2、MessageUtils工具类

3、响应VO

2、测试Controller和请求DTO

3、多语言属性文件

4、测试用例

(1)简单对象UserReqDTO测试

(2)包含List集合对象的ChargeRuleReqDTO测试

一、Validation及国际化配置


1、添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2、校验失败提示消息国际化配置

@Configuration
public class ValidationConfig {
  @Bean
  public LocalValidatorFactoryBean defaultValidator(MessageSource messageSource) {
    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    factoryBean.setValidationMessageSource(messageSource);
    return factoryBean;
  }
}


image.png

3、application.properties

#国际化配置,basename可以用全限定类名,如下,也可以是i18n/message
spring.messages.basename=i18n.messages
spring.messages.encoding=UTF-8


20210326165023150.png

4、国际化资源文件

20210326174324625.png

注意:我们basename的配置为:spring.messages.basename=i18n.messages

因此在类路径下新建i18n的文件夹即可,而不是i18n/messages文件夹,文件夹内必须有一个文件名称为message.properties的属性文件,不然会有问题。多语言以messages_语言_国家.properties命名。

二、代码演示



1、全局异常处理

public class GlobalExceptionHandler {
  @ResponseBody
  @ExceptionHandler(MethodArgumentNotValidException.class)
  public ApiRespVO<?> handleException(MethodArgumentNotValidException e) {
    FieldError fieldError = e.getBindingResult().getFieldError();
    // 校验注解名称
    String code = fieldError.getCode();
    // 校验字段名称
    String field = fieldError.getField();
    // 检验失败默认消息
    String defaultMessage = fieldError.getDefaultMessage();
    List<Object> args = Arrays.stream(Optional.ofNullable(fieldError.getArguments()).orElse(new Object[] {}))
      .filter(argument -> !(argument instanceof DefaultMessageSourceResolvable))
      .map(Object::toString)
      .collect(Collectors.toList());
    args.add(0, field);
    // 默认根据注解名称取,如果没有则取默认消息
    String errorMsg = MessageUtils.getMessage(code, args.toArray(), LocaleContextHolder.getLocale(), StringUtils.EMPTY);
    if (StringUtils.isNotBlank(errorMsg)) {
      return ApiRespVO.failure(ErrorCode.INVALID_PARAM, errorMsg);
    }
    return ApiRespVO.failure(ErrorCode.INVALID_PARAM, defaultMessage);
  }
}


备注:关于LocalContextHolder,每次web请求到来时,Spring中的RequestContextFilter会将Locale实例注入到LocalContextHolder。

2、MessageUtils工具类

public class MessageUtils {
  private static MessageSource messageSource = WebApplicationContextHolder.getBean(MessageSource.class);
  public static String getMessage(String code, Object[] args, Locale locale, String defaultValue) {
    return messageSource.getMessage(code, args, defaultValue, locale);
  }
  public static String getMessage(String code, Object[] args, Locale locale) {
    return messageSource.getMessage(code, args, locale);
  }
}

3、响应VO

public class ApiRespVO<T> {
  private static final String SUCCESS = "00000";
  private static final String FAILURE = "99999";
  private String code;
  private String message;
  private T data;
  public static <T> ApiRespVO<T> success() {
    return success(null);
  }
  public static <T> ApiRespVO<T> success(T data) {
    ApiRespVO<T> apiRespDTO = new ApiRespVO<>();
    apiRespDTO.setCode(SUCCESS);
    apiRespDTO.setData(ObjectUtils.defaultIfNull(data, (T) new Object()));
    return apiRespDTO;
  }
  public static <T> ApiRespVO<T> failure(String code) {
    return failure(code, new Object[] {});
  }
  public static <T> ApiRespVO<T> failure(String code, Object[] args) {
    String errorMsg = MessageUtils.getMessage(code, args, LocaleContextHolder.getLocale());
    return failure(FAILURE, errorMsg);
  }
  public static <T> ApiRespVO<T> failure(String code, String message) {
    ApiRespVO<T> apiRespDTO = new ApiRespVO<>();
    apiRespDTO.setCode(code);
    apiRespDTO.setMessage(message);
    return apiRespDTO;
  }
  public String getCode() {
    return code;
  }
  public void setCode(String code) {
    this.code = code;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
  public T getData() {
    return data;
  }
  public void setData(T data) {
    this.data = data;
  }
  @Override
  public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
  }
}

2、测试Controller和请求DTO

@RestController
public class ValidationController {
  @Autowired
  private MessageSource messageSource;
  @RequestMapping("/validate")
  public ApiRespVO<?> hanldeRequest(@Validated @RequestBody UserReqDTO userDTO) {
    return ApiRespVO.success();
  }
  @RequestMapping("/validate-list")
  public ApiRespVO<?> validateListParam(@Validated @RequestBody ChargeRuleReqDTO request) {
    return ApiRespVO.success();
  }
}
public class UserReqDTO {
  @NotNull
  private String username;
  @NotBlank
  @Length(min = 5,max = 8)
  private String password;
  @Size(max = 1)
  private String gender;
  @Positive
  private int age;
  @NotBlank
  @Pattern(regexp = "^\\d{11}$", message = "{Pattern.UserReqDTO.phone}")
  private String phone;
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getPassword() {
    return password;
  }
  public void setPassword(String password) {
    this.password = password;
  }
  public String getGender() {
    return gender;
  }
  public void setGender(String gender) {
    this.gender = gender;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public String getPhone() {
    return phone;
  }
  public void setPhone(String phone) {
    this.phone = phone;
  }
}
public class ChargeRuleReqDTO {
  @NotBlank
  private String appId;
  @Valid
  private List<ChannelChargeInfo> chargeInfo;
  private static class ChannelChargeInfo {
    @NotBlank
    private String channelCode;
    @NotNull
    private BigDecimal channelCharge;
    public String getChannelCode() {
      return channelCode;
    }
    public void setChannelCode(String channelCode) {
      this.channelCode = channelCode;
    }
    public BigDecimal getChannelCharge() {
      return channelCharge;
    }
    public void setChannelCharge(BigDecimal channelCharge) {
      this.channelCharge = channelCharge;
    }
  }
  public String getAppId() {
    return appId;
  }
  public void setAppId(String appId) {
    this.appId = appId;
  }
  public List<ChannelChargeInfo> getChargeInfo() {
    return chargeInfo;
  }
  public void setChargeInfo(List<ChannelChargeInfo> chargeInfo) {
    this.chargeInfo = chargeInfo;
  }
}


备注:如果请求参数DTO中实例变量为List集合对象,则要加上@Valid注解,否则校验不会生效。

3、多语言属性文件

messages.properties

NotNull=
NotBlank=
Length=
Positive=
Pattern.UserReqDTO.phone=

messages_en_US.properties

NotNull=[{0}] cannot be null
NotBlank=[{0}] cannot be blank
Length=[{0}] minimum length is {2},maximum length is {1}
Positive=[{0}] must be greater than 0
Pattern.UserReqDTO.phone=phone number format is invalid and must be digit. maximum length is 11
NotNull=[{0}]不能为空
NotBlank=[{0}]不能为空
Length=[{0}]最小长度为{2},最大长度为{1}
Positive=[{0}]必须大于
Pattern.UserReqDTO.phone=手机号格式不正确,必须为全数字,长度为11位

4、测试用例

(1)简单对象UserReqDTO测试

语言为中文:20210426110130665.png20210426110200287.png20210426115249771.png20210426115306548.png

(2)包含List集合对象的ChargeRuleReqDTO测试2021042612090852.png20210426120931423.png20210426120841477.png20210426115306548.png

相关文章
|
7天前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
我以为我对Spring MVC很了解,直到我遇到了...
|
16天前
|
前端开发 Java Spring
Spring MVC中使用ModelAndView传递数据
Spring MVC中使用ModelAndView传递数据
|
9天前
|
XML 前端开发 Java
Spring Boot与Spring MVC的区别和联系
Spring Boot与Spring MVC的区别和联系
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
|
20天前
|
JSON 前端开发 数据格式
SpringMVC的数据响应-直接回写json字符串
SpringMVC的数据响应-直接回写json字符串
|
2月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
115 0
|
2月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
44 0
|
11月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
140 0
|
12月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
79 0
|
12月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
[回馈]ASP.NET Core MVC开发实战之商城系统(一)
138 0