Java springbootbean验证

Java springbootbean验证,java,spring,spring-boot,spring-validator,Java,Spring,Spring Boot,Spring Validator,在我的SpringBoot项目中,我有一个POJO类用于读取yaml配置文件 @Configuration @ConfigurationProperties("filenet") @Data public class ApplicationConfig { @NotNull(message = "Input directory cannot be null") @NotBlank(message = "Input directory cannot be blank") p

在我的SpringBoot项目中,我有一个POJO类用于读取yaml配置文件

@Configuration
@ConfigurationProperties("filenet")
@Data
public class ApplicationConfig {
    @NotNull(message = "Input directory cannot be null")
    @NotBlank(message = "Input directory cannot be blank")
    private String **inputDir**;
    @NotNull(message = "Working directory cannot be null")
    @NotBlank(message = "Working directory cannot be blank")
    private String **workingDir**;
    @Pattern(regexp = "[0-9]+",message = "Invalid value for SMTP port")
    private String port;
}
有时,inputDirworkingDir或配置文件的其他字段为空。我正在使用
javax.validation.constraints
检查是否为空。当应用程序启动时,我看到一条异常消息,程序终止。 例如:端口已验证它必须是一个数字。 我想做的是优雅地处理这个异常,并向相关团队发送电子邮件来处理它

我已经创建了一个类,我在其中验证配置文件的内容

@Component
public class ConfigParamValidation {

    public List<String>  validateApplicationConfigFile(ApplicationConfig applicationConfig) {

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<ApplicationConfig.ContentEngine>> contentEngineVoilations = validator.validate(applicationConfig.contentEngine);

        exceptionMessgae = contentEngineVoilations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());

        if(!exceptionMessgae.isEmpty()) {
            through new ConfigFileException(<by passing all required params>);
        }
    }
}
@组件
公共类配置参数验证{
公共列表验证应用程序配置文件(应用程序配置应用程序配置){
ValidatorFactory=Validation.buildDefaultValidatorFactory();
Validator Validator=factory.getValidator();
设置ContentEngineVillations=validator.validate(applicationConfig.contentEngine);
ExceptionMessageGae=contentEngineVoilations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
如果(!ExceptionMessageGae.isEmpty()){
通过新的ConfigFileException();
}
}
}
我试图创建一个扩展RuntimeException的类

public class ConfigFileException extends RuntimeException {

    private String message;
    private List<String> details;
    private String hint;
    private String nextActions;
    private String support;
    private HttpStatus httpStatus;
    private ZonedDateTime zonedDateTime;

    public ConfigFileException(String message) {
        super(message);
    }

    public ConfigFileException(String message, Throwable cause) {
        super(message, cause);
    }

    public ConfigFileException(String message, Throwable cause, List<String> details, String hint, String nextActions, String support, HttpStatus httpStatus, ZonedDateTime zonedDateTime) {
        super(message, cause);

        this.message = message;
        this.details=details;
        this.hint=hint;
        this.nextActions=nextActions;
        this.support=support;
        this.httpStatus=httpStatus;
        this.zonedDateTime = zonedDateTime;
    }
}
公共类ConfigFileException扩展RuntimeException{
私有字符串消息;
私人名单详情;
私有字符串提示;
私人字符串连接;
私有字符串支持;
私有HttpStatus HttpStatus;
私有ZonedDateTime ZonedDateTime;
公共ConfigFileException(字符串消息){
超级(信息);
}
公共ConfigFileException(字符串消息,可丢弃原因){
超级(消息、原因);
}
public ConfigFileException(字符串消息、可丢弃原因、列表详细信息、字符串提示、字符串下一步操作、字符串支持、HttpStatus HttpStatus、ZonedDateTime ZonedDateTime){
超级(消息、原因);
this.message=消息;
this.details=细节;
this.hint=hint;
this.nextActions=nextActions;
这个。支持=支持;
this.httpStatus=httpStatus;
this.zonedDateTime=zonedDateTime;
}
}
另一个带有@ExceptionHandler的类

@Data
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SupportTeamException {

    @ExceptionHandler(value = {ConfigFileException.class})
    public ResponseEntity<Object> handleConfigFileException(ConfigFileException e) {
        ConfigFileException configFileException = new ConfigFileException(e.getMessage(), e, e.getDetails(), e.getHint(), e.getNextActions(), e.getSupport(), e.getHttpStatus(), e.getZonedDateTime());
        return new ResponseEntity<Object>(configFileException,e.getHttpStatus());
    }
}
@数据
@控制器建议
@顺序(有序。最高优先级)
公共类SupportTeamException{
@ExceptionHandler(值={ConfigFileException.class})
公共响应handleConfigFileException(ConfigFileException e){
ConfigFileException ConfigFileException=新的ConfigFileException(e.getMessage(),e,e.getDetails(),e.getHint(),e.getNextActions(),e.getSupport(),e.getHttpStatus(),e.getZonedDateTime());
返回新的ResponseEntity(configFileException,例如getHttpStatus());
}
}
问题是由于某种原因,控制权没有传递给我的
SupportTeamException
类,我可以在该类中发送电子邮件


还是有更好的方法来处理这个问题?

据我所知,
@ControllerAdvice
仅适用于用
@Controller
@RestController
注释的组件

由于验证发生在spring boot应用程序启动时(而不是http请求的结果),因此它永远不会进入其中。您可以使用
@PostConstructor
方法创建一个组件。(见下文)我强烈建议您注入
验证器,而不是自己构建它(以充分利用Spring Boot的潜力)

我不完全理解的是,为什么您希望优雅地处理此异常。如果应用程序启动时没有必需的属性,那么当应用程序实际使用该属性时,它将进一步失败。如果根据情况(如环境),某些属性不需要存在,我建议使用

最后,small aside
@NotBlank
还将检查它是否为非空。您不需要同时使用这两种注释,除非您想对您的消息进行具体说明

package com.yourpackage;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.validation.ConstraintViolation;
import javax.validation.ValidationException;
import javax.validation.Validator;
import java.util.Set;

import static java.util.stream.Collectors.joining;

@Component
public class PropertiesValidator {

    private final Validator validator;
    public final YourProperties properties;

    public PropertiesValidator(final Validator validator, final YourProperties properties) {
        this.validator = validator;
        this.properties = properties;
    }

    @PostConstruct
    public void propertiesShouldBeValid() {
        final Set<ConstraintViolation<YourProperties>> constraintViolations = validator.validate(properties);
        if (!constraintViolations.isEmpty()) {
            final String message = constraintViolations.stream()
                .map(ConstraintViolation::getMessage)
                .collect(joining(","));
            throw new ValidationException(message); //Or send your email
        }
    }
}
package.com.yourpackage;
导入org.springframework.stereotype.Component;
导入javax.annotation.PostConstruct;
导入javax.validation.ConstraintViolation;
导入javax.validation.ValidationException;
导入javax.validation.Validator;
导入java.util.Set;
导入静态java.util.stream.Collectors.joining;
@组成部分
公共类属性验证器{
私人最终验证器;
公共财产;
公共属性验证器(最终验证器验证器,最终YourProperties属性){
this.validator=验证程序;
这个。属性=属性;
}
@施工后
公共无效属性应为有效(){
最终设置constraintViolations=validator.validate(属性);
如果(!constraintViolations.isEmpty()){
最终字符串消息=constraintViolations.stream()
.map(ConstraintViolation::getMessage)
.收取(加入(“,”);
抛出新的ValidationException(消息);//或发送电子邮件
}
}
}