当前位置:   article > 正文

Spring Boot MVC请求参数通用校验及国际化支持_@notnull(message = "{}")国际化

@notnull(message = "{}")国际化

一、Validation及国际化配置

1、添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4

2、校验失败提示消息国际化配置

@Configuration
public class ValidationConfig {

	@Bean
	public LocalValidatorFactoryBean defaultValidator(MessageSource messageSource) {
		LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
		factoryBean.setValidationMessageSource(messageSource);
		return factoryBean;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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
  • 1
  • 2
  • 3

更多配置可参考:
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties-integration.
在这里插入图片描述

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);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

备注:关于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);
	}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

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();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

备注:如果请求参数DTO中实例变量为List集合对象,则要加上@Valid注解,否则校验不会生效。

3、多语言属性文件

messages.properties

NotNull=
NotBlank=
Length=
Positive=
Pattern.UserReqDTO.phone=
  • 1
  • 2
  • 3
  • 4
  • 5

备注:文件内容为空即可

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
  • 1
  • 2
  • 3
  • 4
  • 5

messages_zh_CN.properties

NotNull=[{0}]不能为空
NotBlank=[{0}]不能为空
Length=[{0}]最小长度为{2},最大长度为{1}
Positive=[{0}]必须大于
Pattern.UserReqDTO.phone=手机号格式不正确,必须为全数字,长度为11位
  • 1
  • 2
  • 3
  • 4
  • 5

4、测试用例

(1)简单对象UserReqDTO测试

语言为中文:
在这里插入图片描述
在这里插入图片描述
语言为英文:
在这里插入图片描述
在这里插入图片描述

(2)包含List集合对象的ChargeRuleReqDTO测试

语言为中文:
在这里插入图片描述
在这里插入图片描述

语言为英文:
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/262862
推荐阅读
相关标签
  

闽ICP备14008679号