乐趣区

关于springboot:spring-boot-设置创建用户和修改用户总结

前言

对于设置批改和创立用户博主耽搁了挺长时间的,此次也是对于教程装璜器模式有了一个更深的了解。

需要形容

在每个实体上都减少 createUserupdateUser字段,别离代表的是创立以后数据的用户和更新以后数据的用户。

难点剖析:

1. 找到注解使在数据在创立和更新时执行相应的操作
2. 获取以后登陆用户

踩坑过程

1. 在更新或者创立执行操作

通过关键字在 google 查问首先看到的是 @PrePersist@PreUpdate

@PrePersist: 该注解用在办法上能够使该办法在执行长久化操作之前执行
@PreUpdate:该注解用在办法上能够使该办法在执行数据更新并保留操作之前执行

2. 获取以后登陆用户

形容:在 @PrePersist@PreUpdate注解的办法上获取以后登陆用户并进行 createUserupdateUser设置。

第一想法:
1. 间接调用 userServicegetCurrentLoginUser(获取以后登陆用户)办法

@Override
  public Optional<User> getCurrentLoginUser() {logger.debug("依据认证获取以后登录用户名,并获取该用户");
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication != null) {logger.debug("依据 username 调用 userRepository 获取用户")
      Optional<User> user = this.userRepository.findByUsername(authentication.getName());
      return user;
    }

    logger.debug("认证用户在数据库中不存在");
    return Optional.empty();}

后果:陷入死循环

其余尝试:
应用 @Transient 想着将在实体应用到的 userRepository 设置为实体不存在的属性,后果:又出了其余更多错。

@CreateBy and @LastModifiedBy

@CreateBy:设置创立数据的用户
@LastModifiedBy:设置最近批改数据的用户
注:@CreateBy@LastModifiedBy通常搭配 AuditorAware 应用

Auditing

What is database Auditing?
It keeps a track of who created or changed an entity and when the change happened.
so:AuditorAware 是 spring 领有该性能的一个接口

三者搭配应用

1. 指定实体的字段应用 @CreateBy@LastModifiedBy:

  @ManyToOne
  @JsonView(CreateUserJsonView.class)
  @NotFound(action = NotFoundAction.IGNORE)
  @CreatedBy
  private User createUser;

  @ManyToOne
  @JsonView(UpdateUserJsonView.class)
  @NotFound(action = NotFoundAction.IGNORE)
  @LastModifiedBy
  private User updateUser;

2. 在实体上加上 @EntityListeners(AuditingEntityListener.class) 注解①(或者能够间接用实体实例化 AuditorAware 接口)②

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class YourClass{
}

@EnableWebMvc
@Configuration
@EnableJpaAuditing
public class WebConfig implements WebMvcConfigurer {
@Bean
    public AuditorAware<User> auditorProvider() {return new SpringSecurityAuditorAware();
    }

    private static class SpringSecurityAuditorAware implements AuditorAware<User> {

        @Autowired
        UserService userService;

        @Override
        public Optional<User> getCurrentAuditor() {// 获取以后登陆用户}
    }
}
@MappedSuperclass
public class BaseEntity implements AuditorAware<User> {
  @Override
  public Optional<User> getCurrentAuditor() {// 获取以后登陆用户}
}

成果

ERROR:当调用 userRepository 仍然会循环。
因为咱们调用的是 UserRepositoryfindByUsername办法,它实质上调用 CurdRepository 的办法。那么它为啥会获取 user 后认为数据被创立或更新,进而循环呢?因为该办法并不是本人写的,故有很多未知。

解决

从 UserDetails 下手:书写本人的UserDetails

原来 UserDetails 是没有 user 字段的
减少 user 解决问题

public class UserDetailImpl extends org.springframework.security.core.userdetails.User implements UserDetails {
  private User user;
  public UserDetailImpl(String username, String password, Collection<? extends GrantedAuthority> authorities, User user) {super(username, password, authorities);
    this.user = user;
  }

  public User getUser() {return user;}
}

@Override
  public Optional<User> getCurrentLoginUserFirst() {logger.debug("依据认证获取以后登录用户名,并获取该用户");
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication != null) {
      UserDetailImpl userDetail;
      if (authentication instanceof UsernamePasswordAuthenticationToken) {logger.debug("第一种登陆后获取以后登陆用户,倡议将这种状况摘出来,从新用办法验证");
        userDetail = (UserDetailImpl) authentication.getPrincipal();} else if (authentication instanceof UserDetailImpl) {logger.debug("第二种登陆用户存在,且在批改数据或新增状况");
        userDetail = (UserDetailImpl) authentication;
      } else if (authentication instanceof AnonymousAuthenticationToken) {logger.debug("第三种未登陆状况下批改或新增数据状况,如应用手机验证码批改明码");
        return Optional.empty();} else {throw new RuntimeException("获取类型不正确");
      }
      return Optional.of(userDetail.getUser());
    }

    logger.debug("认证用户在数据库中不存在");
    return Optional.empty();}

解释:其本质是就是使用装璜器模式,定义本人的 UserDetails 减少一个以后登陆用户 user 的快照。

成果:相当于给每个登陆用户一个快照,举个栗子:如果以后登陆用户为张三,那么张三登陆后便给张三照张相,那么在接下来这几天假如张三整容了,然而张三登陆的时候拍的照片是没有变动的,此处的思维也是如此

总结

对于这个需要的实现,我次要卡在了如何不调用 UserRepository 的 findByUsername 来获取以后登陆用户,最终是在老师的疏导下启用了装璜器的模式,通过此次也是对于本人的编程思维有了一个晋升,也感激老师的领导。

退出移动版