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

相关文章
|
8月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
1575 0
|
11月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
779 0
|
11月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
334 0
|
11月前
|
JSON 前端开发 Java
第05课:Spring Boot中的MVC支持
第05课:Spring Boot中的MVC支持
426 0
|
11月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1390 0
|
12月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1262 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
563 0
|
8月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
619 4
|
8月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
1147 3

热门文章

最新文章