前言

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

需要形容

在每个实体上都减少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@EnableJpaAuditingpublic 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() {            // 获取以后登陆用户        }    }}
@MappedSuperclasspublic 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来获取以后登陆用户,最终是在老师的疏导下启用了装璜器的模式,通过此次也是对于本人的编程思维有了一个晋升,也感激老师的领导。