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

相关文章
|
12天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
30 4
|
26天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
35 1
SpringBoot入门(3) - 对Hello world进行MVC分层
|
24天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
本文介绍了如何在Spring Boot项目中实现MVC分层架构,通过将代码划分为controller、service、dao和entity四个部分,实现高内聚低耦合的设计。示例项目包括用户增删查改功能,详细展示了各层的具体实现及运行测试。
32 11
|
20天前
|
前端开发 Java Spring
SpringBoot项目thymeleaf页面支持词条国际化切换
SpringBoot项目thymeleaf页面支持词条国际化切换
50 2
|
23天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
19 2
|
1月前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
1月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
57 2
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
121 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
2月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
1月前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
下一篇
无影云桌面