目录
一、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;
}
}
Spring Boot中针对Validation和国际化有两个自动配置类:
1、ValidationAutoConfiguration
2、MessageSourceAutoConfiguration
其中MessageSourceAutoConfiguration会自动实例化一个MessageSource实例,如下:
3、application.properties
#国际化配置,basename可以用全限定类名,如下,也可以是i18n/message
spring.messages.basename=i18n.messages
spring.messages.encoding=UTF-8
4、国际化资源文件
注意:我们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
messages_zh_CN.properties
NotNull=[{0}]不能为空
NotBlank=[{0}]不能为空
Length=[{0}]最小长度为{2},最大长度为{1}
Positive=[{0}]必须大于
Pattern.UserReqDTO.phone=手机号格式不正确,必须为全数字,长度为11位
4、测试用例
(1)简单对象UserReqDTO测试
语言为中文:
语言为英文:
(2)包含List集合对象的ChargeRuleReqDTO测试
语言为中文:
语言为英文: