当前位置: 首页 > 知识库问答 >
问题:

服务层验证(SpringBoot)

姬和歌
2023-03-14

我有一个DTO,它在控制器层通过BeanValidation(javax.validation)和定制验证器(org.springframework.validation.Validator)的组合进行验证。通过这种方式,我可以检查提供的输入是否有效,然后转换实体中的DTO并将其转发到服务层。

    @Data
    public class UserDTO {

            @NotBlank
            @Size(max = 25)
            private String name;

            @NotNull
            private Date birthday;

            @NotNull
            private Date startDate;

            private Date endDate;

            private Long count;

    }

    public class UserDTOValidator implements Validator {
        private static final String START_DATE= "startDate";
        private static final String END_DATE= "endDate";
        private static final String COUNT= "count";

        @Override
        public boolean supports(Class<?> clazz) {
            return UserDTO.class.isAssignableFrom(clazz);
        }
        @Override
        public void validate(Object target, Errors errors) {

            UserDTO vm = (UserDTO) target;

            if (vm.getEndDate() != null) {
               if (vm.getStartDate().after(vm.getEndDate())) {
                errors.rejectValue(START_DATE, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
               }

               if (vm.getEndDate().equals(vm.getStartDate()) || vm.getEndDate().before(vm.getStartDate())) {
                errors.rejectValue(END_DATE, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
               }
            }

            if (vm.getCount() < 1) {
             errors.rejectValue(COUNT, ErrorCode.ILLEGAL_ARGUMENT.toString(), ErrorCode.ILLEGAL_ARGUMENT.description());
            }
            .....

        }

    }


public class UserController {
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new UserDTOValidator());
    }
    @PostMapping()
    public ResponseEntity<UserDTO> create(@RequestBody @Valid UserDTO userDTO) {
       .....
    }
    .....
}

然后是业务逻辑验证。例如:@Entity用户的startDate必须在某个事件发生之后,如果最后创建的用户的生日在夏季,则计数必须大于某个X,否则,用户服务应丢弃该实体。

@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private SomeEventService someEventService ;

    @Override
    public User create(User entity) {
        String error = this.validateUser(entity);
        if (StringUtils.isNotBlank(error)) {
            throw new ValidationException(error);
        }

        return this.userRepository.save(entity);
    }
    ....
    private String validateUser(User entity) {
        SomeEvent someEvent = this.someEventService.get(entity.getName()); 
        if (entity.getStartDate().before(someEvent.getDate())) {
            return "startDate";
        }
        User lastUser = this.userRepository.findLast();
        ....
    }

}

然而,我觉得这不是处理业务逻辑验证的最佳方法。我该怎么办?ConstraintValidator/HibernateValidator/JPA事件侦听器?它们可以在@Entity类级别工作,还是我必须为每个不同的字段检查创建X个?你们是如何在实际的生产应用程序中做到这一点的?

共有1个答案

孔磊
2023-03-14

在我的建议中,

  1. 使用@Valid的经典字段级验证

样品

void myservicemethod(@Valid UserDTO user)

样品

class UserDTO {
    //fields and getter setter
    void validate() throws ValidationException {
        //your entity level business logic
    }
}

此策略将有助于将特定于实体的验证逻辑保留在实体内

这将有助于将您的验证逻辑与服务层分离,并使其具有可移植性和模块化

 类似资料:
  • 我过去认为,在分层应用程序(控制器或服务)中,将验证逻辑放在何处并不重要,但最近正在开发需要事务的服务(使用spring)。Spring使用方面创建代理,Spring代码如下所示: org.springframework.transaction.interceptor.事务支持 所以从我这里看到的,spring首先打开事务,然后执行代码。考虑到验证可能会失败,并且根本不需要DB调用,这是否意味着将

  • 环境:Java,泽西,jackson,汤卡特。 我有一个rest服务从客户端获取JSON输入。我想验证输入,如果它是JSON,然后它是JSON,然后JSON输入中的键是预期的或不是。如果是,那么它将产生HTTP400-bad请求。 比如-- 例如-非json输入如 null 我的代码适用于前面提到的情况2,但我希望它也适用于情况1。当非JSON输入存在时,我希望它将凭据对象设置为null,然后我可

  • 在相当长的一段时间里,我试图找出在Spring MVC应用程序中应该在哪里对用户输入进行验证。在许多在线博客和教程中,我基本上读到控制器应该验证用户的输入,如果无效,则通过显示包含错误消息的页面来响应用户。然而,我目前对Spring和Spring MVC分层系统的理解是,控制器只是应用程序逻辑(服务层)和“Web世界”之间的一个浅层接口,允许从Web使用服务层。而且,就我所见,Spring MVC

  • 我正在使用Spring-3.1.0.ga开发一个服务(不是web应用程序)。我想使用hibernate-validator和Spring来验证我的服务输入。 我启用了bean验证支持: 我已经用@validated和@notnull、@size、@valid等方法参数注释了我的服务接口,它工作得很好。 我不能在接口级别注释@validate(group1.class),因为各种方法对各种组进行操作

  • 我被难倒了....对于获得向缺少什么,有什么想法吗?