java - 如何从方法中提取依赖于类上下文的变量以避免重复代码?

标签 java spring spring-boot validation refactoring

我有两个类。

主类是 GraphQL 查询解析器:

@Component
@AllArgsConstructor
class UserProfileQuery implements GraphQLQueryResolver {

    private final UserProfileRepository userProfileRepository;
    private final AddressRepository addressRepository;
    private final UserRepository userRepository;
    private final UserProfileAccessValidator validator;

    @PreAuthorize("hasAuthority('ACCOUNT_OWNER')")
    public Optional<List<UserProfile>> getUserProfiles(Long accountId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAccess(user, accountId);
        return userProfileRepository.findMatchingAccountId(accountId);
    }

    @PreAuthorize("hasAuthority('ACCOUNT_OWNER')")
    public Optional<UserProfile> getUserProfile(Long userProfileId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findByUserProfileId(userProfileId).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAccess(user, checkedUser);
        return userProfileRepository.findById(userProfileId);
    }

    @PreAuthorize("hasAnyAuthority('ACCOUNT_OWNER','USER')")
    public Set<Address> getAddresses(Long userProfileId) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findByUserProfileId(userProfileId).orElseThrow(() -> new NotFoundException(User.class));
        validator.validateAccountOwnerAndUserAccess(user, checkedUser);
        return Optional.of(addressRepository.findByUserProfileId(userProfileId)).orElseThrow(() -> new NotFoundException(UserProfile.class));
    }

}

第二个类是 validator :

@Component
@AllArgsConstructor
public class UserProfileAccessValidator {

    private final UserRepository userRepository;

    public void validateAccessForUserCreation(CreateUserProfileCommand command) {
        User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        User checkedUser = userRepository.findById(command.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
        validateAccountOwnerAndUserAccess(user, checkedUser);
    }

    public void validateAccountOwnerAndUserAccess(User user, User checkedUser) {
        if (AccessValidationHelper.isAccountOwnerAndHasSameAccount(user, checkedUser)
                || AccessValidationHelper.isUserAndHasSameUserProfileId(user, checkedUser)) {
            throw new IllegalOperationException();
        }
    }

    public void validateAccountOwnerAccess(User user, User checkedUser) {
        if (AccessValidationHelper.isAccountOwnerAndHasSameAccount(user, checkedUser)) {
            throw new IllegalOperationException();
        }
    }

    public void validateAccountOwnerAccess(User user, Long accountId) {
        if (!user.getAccount().getId().equals(accountId)) {
            throw new IllegalOperationException();
        }
    }

}

正如您所看到的,用户获取中有很多代码重复。

    User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));
    User checkedUser = userRepository.findById(command.getUserId()).orElseThrow(() -> new NotFoundException(User.class));

如何重构这两个类以避免代码重复?或者至少避免重复:

    User user = userRepository.findById(LoggedUserHolder.getUserId()).orElseThrow(() -> new NotFoundException(User.class));

因为它正在从 Spring 上下文持有者中获取用户。我在这个问题上坐了一个小时,但没有好的解决方案来实现......

最佳答案

如果登录用户是主体,您可以使用 @PreAuthorize 表达式。如果这对您有用,那么您可以使用元注释。通过元注释,您可以减少代码量。这是一个关于如何使用它们的很好的教程:https://www.baeldung.com/spring-security-method-security

关于java - 如何从方法中提取依赖于类上下文的变量以避免重复代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58594304/

相关文章:

java - 使用 Jooq 和 JPA 的 @Column 注释验证字段长度

java - pom.xml(Maven 多模块项目)中的 <sonar.exclusions> 在本地工作但不在公司服务器上工作

java - 传输方案未识别 : [tcp]

java - 具有数据库驱动执行日期的计划任务

mysql - 如何在不依赖数据库的情况下启动spring-boot应用程序?

docker - 使用 Docker 映射 Compute Engine 中的端口

html - 如何使用 Spring 和 Thymeleaf 在属性文件中存储 URL 并在模板中访问它们

java - Spring Boot 管理服务器 : App Specific Email Notification

java - 如何从 Bash shell 脚本优雅地关闭 Java 服务?

Java - 如何在不同的类中调用 add() 方法