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

相关文章
|
15天前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
26 4
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
129 2
|
3月前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
3月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
65 2
|
3月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
221 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
3月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
193 1
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
126 62
|
18天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
91 13
|
26天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
116 2