这篇博客主要是依赖前三篇博客进行展开的处理,如果没有看前三篇建议先看完三篇后再浏览这篇。这三篇博客分别是:自研究一套返回结构体,异常处理返回结构体做到全局统一,系统接口未找到报404异常统一返回处理
我们都知道对请求参数的校验可以使用spring-boot-starter-validation依赖用于请求参数的校验。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
比如:
@Data
public class ProjectDTO {
@NotBlank(message = "id参数为空", groups = {TestValidGroup.Update.class})
private String id;
@NotBlank(message = "strValue参数为空")
private String strValue;
@Min(value = -99, message = "intValue参数值必须大于等于-99")
@Max(value = 100, message = "intValue参数值必须小于等于100")
private Integer intValue;
}
在ProjectDTO类成员中使用validation校验注解都要手动写message提示信息,而且这些提示信息样式非常相似,那么如果有很多这样的请求类处理就需要在成员注解中手动写message提示信息,那么这样是相当麻烦的,首先我很懒,我是不会这样去做的,我会这样去做,让它自动帮忙处理,而且很规范。
成员变量包括:
String类型枚举名称的code
String类型的中文提示模板message
String类型的英文提示模板enMessage
实现如下:
@Getter
public enum ValidatedEnum {
TEMP("Temp", "", ""), //临时对象,避免模板提示信息中占位符被使用,因枚举对象属于全局对象
NULL("Null", "%s参数值必须是空.", "The %s parameter value must be null."),
NOT_NULL("NotNull", "%s参数为空.", "The %s parameter is empty."),
NOT_BLANK("NotBlank", "%s参数为空.", "The %s parameter is empty."),
NOT_EMPTY("NotEmpty", "%s参数为空.", "The %s parameter is empty."),
MIN("Min", "%s参数必须大于等于%s.", "The %s parameter must be greater than or equal to %s."),
MAX("Max", "%s参数必须小于等于%s.", "The %s parameter must be less than or equal to %s."),
SIZE("Size", "%s参数字符长度必须不大于%s且不小于%s.", "The character length of the %s parameter must not be greater than %s and not less than %s."),
;
/**
* 验证枚举名称
*/
private String code;
/**
* 中文提示模板
*/
private String message;
/**
* 英文提示模板
*/
private String enMessage;
public ValidatedEnum setCode(String code) {
this.code = code;
return this;
}
public ValidatedEnum setMessage(String message) {
this.message = message;
return this;
}
public ValidatedEnum setEnMessage(String enMessage) {
this.enMessage = enMessage;
return this;
}
ValidatedEnum(String code, String message, String enMessage) {
this.code = code;
this.message = message;
this.enMessage = enMessage;
}
/**
* 通过验证成员变量错误信息获取对应枚举对象并合成信息
*
* @param fieldError
* @return
* @author rufeng
* @date 2023/12/18 15:22
*/
public static ValidatedEnum getInstanceByFieldError(FieldError fieldError) {
ValidatedEnum[] validatedEnums = values();
ValidatedEnum ve = TEMP;
for (ValidatedEnum validatedEnum : validatedEnums) {
if (validatedEnum.getCode().equals(fieldError.getCode())) {
//获取到code注解的值,数组个数一定要与占位符数相同
Object[] arugments = fieldError.getArguments();
arugments[0] = fieldError.getField();
ve.setCode(validatedEnum.getCode()).setMessage(String.format(validatedEnum.getMessage(), arugments))
.setEnMessage(String.format(validatedEnum.getEnMessage(), arugments));
return ve;
}
}
return null;
}
}
通过FieldError的成员code获取该枚举类中的对应对象,然后就可以获取到枚举对象的中英文提示模板,最后对中英文提示模板赋值,得到一个完整的对象返回出去。
针对validation校验注解发生的异常有个异常处理类:MethodArgumentNotValidException,通过它就可找到FieldError哪个成员属性发生了异常。
代码处理如下:
/**
* 自定义验证异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultBody handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("发生MethodArgumentNotValidException...", e);
BindingResult bindingResult = e.getBindingResult();
ErrorCode errorCode = ErrorCode.FAIL;
if (bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null) {
ValidatedEnum validatedEnum = ValidatedEnum.getInstanceByFieldError(fieldError);
if (StringUtils.isNotNull(validatedEnum)) {
//存在ValidatedEnum枚举对象中,使用对应提示
errorCode.setMessage(validatedEnum.getMessage()).setEnMessage(validatedEnum.getEnMessage());
} else {
//不存在则使用默认提示或者使用手动编写message提示
errorCode.setMessage(fieldError.getDefaultMessage()).setEnMessage(fieldError.getDefaultMessage());
}
}
}
return ResultBodyUtils.fail(errorCode);
}
请求类:
@Data
public class LoginBody {
/**
* 用户名
*/
@NotEmpty
private String username;
/**
* 用户密码
*/
@NotEmpty
private String password;
/**
* 验证码
*/
@NotEmpty
@Size(min = 3, max = 10)
private String code;
/**
* 唯一标识
*/
@Null
private String uuid;
@Min(2)
@Max(100)
private int age;
}
失败请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": "123",
"code":"213",
"age":10
}
失败返回报文:
{
"code": -1,
"message": "uuid参数值必须是空.",
"data": null
}
成功请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": null,
"code":"213",
"age":10
}
成功返回报文:
{
"code": 200,
"message": "成功",
"data": {
"token": "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjhkMzg4M2EyLWQwMjEtNDFhNC04MzljLTBjOWM5NzIzNGNiMCJ9.So2e5w-8oGCZk4OnT_bsbJNqzmEgaI3Jr3nq7VYhvb0Sc_vi2MVUvndxS0_rk_fovnshYDvX3w68lItDQC99_A"
}
}
失败请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": null,
"code":"",
"age":10
}
失败返回报文:
{
"code": -1,
"message": "code参数为空.",
"data": null
}
失败请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": null,
"code":"12",
"age":10
}
失败返回报文:
{
"code": -1,
"message": "code参数字符长度必须不大于10且不小于3.",
"data": null
}
失败请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": null,
"code":"123",
"age":1
}
失败返回报文:
{
"code": -1,
"message": "age参数必须大于等于2.",
"data": null
}
失败请求参数:
{
"username":"admin",
"password":"admin123",
"uuid": null,
"code":"123",
"age":101
}
失败返回报文:
{
"code": -1,
"message": "age参数必须小于等于100.",
"data": null
}
综上实践:通过枚举类的模板信息处理就可省去很多工作量,而且提示信息可做到标准化,当然上述只是枚举了一些常用的验证注解,如果需要其它可手动加入并适配,不加,提示信息会直接使用默认的。切换到英文也一样。