首页 > 解决方案 > 在 Spring REST api 中验证 multipart/form-data

问题描述

我最近遇到了一个与验证有关的问题。通常,我正在构建一个允许用户创建包括头像在内的帐户的 REST api。当用户单击注册按钮时,应提交所有信息。因此,我的服务器将收到一个请求,其中包含一些字段,例如name (string), birthday (datetime), ... and avatar (multipart file). 因此,问题是如何验证接收到的文件是真实的图像并且具有允许的大小,同时验证其他文件(电子邮件、密码)是否也有效。

对于所有字段都是文本的情况,我们可以使用这样的注释组合轻松验证它们

控制器

@PostMapping(path = "")
public ResponseEntity<?> createNewAccount(@RequestBody @Valid RegisterRequest registerRequest) {
    Long resourceId = service.createNewCoderAccount(registerRequest);

    return ResponseEntity.created(location(resourceId)).build();
}

请求 DTO

@ConfirmedPassword
public class RegisterRequest extends BaseRequest implements ShouldConfirmPassword {
    @NotBlank(message = "Field 'email' is required but not be given")
    @Email
    @Unique(message = "Email has been already in use", service = UserValidatorService.class, column = "email")
    private String email;

    @NotBlank(message = "Field 'password' is required but not be given")
    @Size(min = 6, message = "Password should contain at least 6 characters")
    private String password;

    @NotBlank(message = "Field 'confirmPassword' is required but not be given")
    private String confirmPassword;

    @NotBlank(message = "Field 'firstName' is required but not be given")
    private String firstName;

    @NotBlank(message = "Field 'lastName' is required but not be given")
    private String lastName;
}

或者如果请求只包含文件,我们绝对可以这样做

控制器

@PostMapping(path = "/{id}")
public ResponseEntity<?> editChallengeMetadata(
    @ModelAttribute ChallengeMetadataRequest request,
    BindingResult bindingResult,
    @PathVariable("id") Long id,
    @CurrentUser User user
) throws BindException {
    challengeMetadataRequestValidator.validate(request, bindingResult);

    if (bindingResult.hasErrors()) {
        throw new BindException(bindingResult);
    }

    Long challengeId = service.updateChallengeMetadata(id, request, user);

    return ResponseEntity.ok(RestResponse.build(challengeId, HttpStatus.OK));
}

验证器

public class ChallengeMetadataRequestValidator implements Validator {
    @Override
    public boolean supports(@NonNull Class<?> aClass) {
        return ChallengeMetadataRequest.class.isAssignableFrom(aClass);
    }

    @Override
    public void validate(@NonNull Object o, @NonNull Errors errors) {
        ChallengeMetadataRequest request = (ChallengeMetadataRequest) o;

        if (request.getBanner() != null && !request.getBanner().isEmpty()) {
            if (!List.of("image/jpeg", "image/png").contains(request.getBanner().getContentType())) {
                errors.rejectValue("banner", "challenge.mime-type.not-supported", new String[]{request.getBanner().getContentType()}, "Mime-type is not supported");
            }
        }
    }
}

正如您在上面看到的,如果我将所有数据(包括头像)包装在一个 DTO 类中,我肯定会编写它自己的验证器。但是如果我必须手动编写数百个这样的验证器会发生什么。

那么,有没有人对此有任何想法,通常,使multipart/form-datarequest 变得与application/jsonrequest 相似?

谢谢并恭祝安康,

标签: javaspringspring-bootrestmultipartform-data

解决方案


推荐阅读