我正在努力根据自己的需求定制javax.validation.ConstraintValidator
和javax.validation.ConstraintValidatorContext
。我从一个格式错误的请求体收到的响应消息总是这样:
<controller method name>.<input parameter>: <default message>, <controller method name>.<input parameter>: <specific validation message>
此消息也以500而不是400错误请求的形式返回。我还没能找到一个工作到解决方案来做以下事情:
- 仅包括
<specific validation message>
,即排除方法+输入名称 - 排除默认消息
- 始终将500更改为400,或可能允许自定义错误响应
我有以下代码:
控制器
import org.path.validation.ValidCreateThingRequest;
import org.path.service.ThingService;
// ... various other imports
@PostMapping("/things")
@ApiOperation(value = "Create a new thing")
@ApiResponse(code = 201, message = "Newly created thing", response = Thing.class)
@ResponseStatus(HttpStatus.CREATED)
public ThingResponseProto createThing(
@RequestBody @ValidCreateThingRequest final CreateThingRequestProto thingDto,
final HttpServletRequest httpServletRequest) {
final Context context = new RequestContext(httpServletRequest);
final Thing createdThing = thingService.createThing(thingDto);
return mapObjToProtoUtils.map(createdThing, ThingResponseProto.class);
}
用于创建验证接口的接口
@Constraint(validatedBy = CreateThingRequestValidator.class)
@Target({ METHOD,PARAMETER })
@Retention(RUNTIME)
@Documented
public @interface ValidCreateThingRequest {
String message() default "Request must be well-formed.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
接口中使用的验证器
public class CreateCodeRequestValidator
implements ConstraintValidator<ValidCreateThingRequest, CreateThingRequestProto> {
private static final Pattern FORBIDDEN_NAME_CHARACTERS_REGEX =
Pattern.compile("[\\/\t\n\r\f?;]");
@Override
public void initialize(ValidCreateCodeRequest constraintAnnotation) {};
@Override
public boolean isValid(final CreateThingRequestProto thingDto, ConstraintValidatorContext context) {
return isValidCharacters(thingDto, context)
&& isValidNameExists(thingDto, context)
}
boolean isValidCharacters(final CreateThingRequestProto thingDto, ConstraintValidatorContext context) {
final String name = thingDto.getName();
if (FORBIDDEN_NAME_CHARACTERS_REGEX.matcher(name).find()) {
context
.buildConstraintViolationWithTemplate("Name must not contain forbidden characters.")
.addConstraintViolation();
return false;
} else {
return true;
}
}
boolean isValidNameExists(final CreateThingRequestProto thingDto, ConstraintValidatorContext context) {
final String name = thingDto.getName();
if (name != null && !name.trim().isEmpty()) {
context
.buildConstraintViolationWithTemplate("Name must not be null or empty.")
.addConstraintViolation();
return false;
} else {
return true;
}
}
}
向上面的代码发送一个格式错误的有效载荷会导致一条消息,看起来像这样:
{
error: "Internal Server Error",
message: "createThing.thingDto: Request must be well-formed., createThing.thingDto: Name must not be null or empty.",
path: "/things"
status: 500
timestamp: 1607110364124
}
我希望能够收到这个:
{
error: "Bad Request",
message: "Name must not be null or empty.",
path: "/things"
status: 400
timestamp: 1607110364124
}
基于buildConstraintViolationWithTemplate()
,这可能吗??
也许你可以像一样使用@ControllerAdvice注释
@ControllerAdvice
public class ConstraintValidatorExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public void handleConstraintViolationException(ConstraintViolationException exception,
ServletWebRequest webRequest) throws IOException {
webRequest.getResponse().sendError(HttpStatus.BAD_REQUEST.value(), exception.getMessage());
}
}