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

相关文章
|
3天前
|
Java 数据安全/隐私保护 网络架构
一个简单的示例在spring boot中实现国际化
一个简单的示例在spring boot中实现国际化
|
2天前
|
设计模式 前端开发 Java
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
【Spring MVC】快速学习使用Spring MVC的注解及三层架构
6 1
|
2天前
|
前端开发 Dubbo Java
spring面试题_spring mvc面试题_springboot面试题库
spring面试题_spring mvc面试题_springboot面试题库
|
4天前
|
JSON 前端开发 Java
【JavaEE进阶】 关于Spring MVC 响应
【JavaEE进阶】 关于Spring MVC 响应
14 3
|
5天前
|
缓存 NoSQL Java
在 SSM 架构(Spring + SpringMVC + MyBatis)中,可以通过 Spring 的注解式缓存来实现 Redis 缓存功能
【6月更文挑战第18天】在SSM(Spring+SpringMVC+MyBatis)中集成Redis缓存,涉及以下步骤:添加Spring Boot的`spring-boot-starter-data-redis`依赖;配置Redis连接池(如JedisPoolConfig)和连接工厂;在Service层使用`@Cacheable`注解标记缓存方法,指定缓存名和键生成策略;最后,在主配置类启用缓存注解。通过这些步骤,可以利用Spring的注解实现Redis缓存。
23 2
|
5天前
|
前端开发 Java Maven
如何在Spring MVC中实现图片的上传和下载功能
如何在Spring MVC中实现图片的上传和下载功能
|
10天前
|
前端开发 Java Spring
Spring MVC 请求处理流程
Spring MVC 请求处理流程
12 0
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的轻院网购商城管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的轻院网购商城管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
28 5
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的隔离人员的管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的隔离人员的管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
21 3
|
2天前
|
JavaScript Java 测试技术
基于SpringBoot+Vue的采购管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的采购管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
19 3