spring-data-jpa 自定义Spring验证器工作不正常

u5rb5r59  于 2022-11-10  发布在  Spring
关注(0)|答案(1)|浏览(154)

我 试图 通过 Spring 来 人为 地 违反 约束 , 而 不是 从 DB 中 抛出 异常 ( 一 位 Maven 说 DB 产生 的 错误 会 造成 很 高 的 性能 代价 ) :

import javax.validation.ConstraintViolation;
import javax.validation.Validator;

@Component
public class AccountValidator implements org.springframework.validation.Validator {

    @Autowired
    private Validator validator;

    private final AccountService accountService;
    public AccountValidator(@Qualifier("accountServiceAlias")AccountService accountService) {
        this.accountService = accountService;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return AccountRequestDTO.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {

        Set<ConstraintViolation<Object>> validates = validator.validate(target);
        for (ConstraintViolation<Object> constraintViolation : validates) {
            String propertyPath = constraintViolation.getPropertyPath().toString();
            String message = constraintViolation.getMessage();
            errors.rejectValue(propertyPath, "", message);
        }

        AccountRequestDTO account = (AccountRequestDTO) target;
        if(accountService.getPhone(account.getPhone()) != null){
            errors.rejectValue("phone", "", "Validator in action! This number is already in use.");
        }
    }

}

中 的 每 一 个
然而 , * * validate ( ) * * 方法 的 第 二 部分 由于 我 无法 理解 的 原因 而 始终 无法 工作 , 并且 总是 从 控制 器 传递 一 个 调用 , 以便 在 * * try-catch * * 块 中 处理 , 从而 从 DB 抛出 异常 :

public void saveAccount(AccountRequestDTO accountRequestDTO) throws Exception {

        LocalDate birthday = LocalDate.parse(accountRequestDTO.getBirthday());
        if (LocalDate.from(birthday).until(LocalDate.now(), ChronoUnit.YEARS) < 18) {
            throw new RegistrationException("You must be 18+ to register");
        }

        Account account = new Account(accountRequestDTO.getName(), accountRequestDTO.getSurname(),
                accountRequestDTO.getPhone(), birthday, BCrypt.hashpw
                (accountRequestDTO.getPassword(), BCrypt.gensalt(4)));
        account.addRole(Role.CLIENT);
        try {
            accountRepository.save(account);
        }
        catch (RuntimeException exc) {
            throw new PersistenceException("Database exception: this number is already in use.");
        }
    }

格式
下面 是 一 个 控制 器 方法 :

@PostMapping("/confirm")
    public String signIn(@ModelAttribute("account") @Valid AccountRequestDTO accountRequestDTO,
            BindingResult result, Model model) {

        accountValidator.validate(accountRequestDTO, result);
        if(result.hasErrors()) {
            return "/auth/register";
        }
        try {
            accountService.saveAccount(accountRequestDTO);
        }
        catch (Exception exc) {
            model.addAttribute("message", exc.getMessage());
            return "/auth/register";            
        }
        return "/auth/login";
    }

格式
服务 时 :

@Transactional(readOnly = true)
    public String getPhone(String phone){
        return accountRepository.getPhone(phone);
    }

格式
JpaRepository 查询 :

@Query("SELECT phone FROM Account accounts WHERE phone=:check")
    String getPhone(String check);

格式
测试 为 绿色 :

@BeforeAll
    static void prepare() {
        search = new String("0000000000");
    }

    @BeforeEach
    void set_up() {
        account = new Account
                ("Admin", "Adminov", "0000000000", LocalDate.of(2001, 01, 01), "superadmin");
        accountRepository.save(account);
    }

    @Test
    void check_if_phone_presents() {        
        assertThat(accountRepository.getPhone(search).equals(account.getPhone())).isTrue();
    }

    @Test
    void check_if_phone_not_presents() {
        String newPhone = "9999999999";
        assertThat(accountRepository.getPhone(newPhone)).isNull();
    }   

    @AfterEach
    void tear_down() {
        accountRepository.deleteAll();
        account = null;
    }

    @AfterAll
    static void clear() {
        search = null;
    }

格式

lxkprmvk

lxkprmvk1#

您需要注册您的验证器。
在定义了验证器之后,我们需要将其Map到一个特定的事件,该事件在请求被接受之后生成。
这可以通过三种方式实现:
添加名为“beforeCreateAccountValidator”的组件注解。Sping Boot 将识别前缀beforeCreate,该前缀确定我们要捕获的事件,并且它还将从组件名称中识别WebsiteUser类。

@Component("beforeCreateAccountValidator")
    public class AccountValidator implements Validator {
     ...
}

在应用程序上下文中创建带有@Bean注解的Bean:

@Bean
public AccountValidator beforeCreateAccountValidator () {
    return new AccountValidator ();
}

手动配准:

@SpringBootApplication
public class SpringDataRestApplication implements RepositoryRestConfigurer {
    public static void main(String[] args) {
        SpringApplication.run(SpringDataRestApplication.class, args);
    }

    @Override
    public void configureValidatingRepositoryEventListener(
      ValidatingRepositoryEventListener v) {
        v.addValidator("beforeCreate", new AccountValidator ());
    }
}

相关问题