spring boot 设置创建用户和修改用户总结

前言 对于设置修改和创建用户博主耽误了挺长时间的,此次也是对于教程装饰器模式有了一个更深的理解。
需求描述
在每个实体上都增加createUserupdateUser字段,分别代表的是创建当前数据的用户和更新当前数据的用户。
难点分析:
1.找到注解使在数据在创建和更新时执行相应的操作
2.获取当前登陆用户
踩坑过程
1.在更新或者创建执行操作 通过关键字在google查询首先看到的是@PrePersist@PreUpdate
@PrePersist:该注解用在方法上可以使该方法在执行持久化操作之前执行
@PreUpdate:该注解用在方法上可以使该方法在执行数据更新并保存操作之前执行
spring boot 设置创建用户和修改用户总结
文章图片

2.获取当前登陆用户 描述:在@PrePersist@PreUpdate注解的方法上获取当前登陆用户并进行createUserupdateUser设置。
第一想法:
1.直接调用userServicegetCurrentLoginUser(获取当前登陆用户)方法

@Override public Optional getCurrentLoginUser() { logger.debug("根据认证获取当前登录用户名,并获取该用户"); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null) { logger.debug("根据username调用userRepository获取用户") Optional user = this.userRepository.findByUsername(authentication.getName()); return user; }logger.debug("认证用户在数据库中不存在"); return Optional.empty(); }

结果:陷入死循环
spring boot 设置创建用户和修改用户总结
文章图片

其他尝试:
使用@Transient想着将在实体使用到的userRepository设置为实体不存在的属性,结果:又出了其他更多错。
@CreateBy and @LastModifiedBy
@CreateBy:设置创建数据的用户
@LastModifiedBy:设置最近修改数据的用户
注:@CreateBy@LastModifiedBy通常搭配AuditorAware使用
Auditing
【spring boot 设置创建用户和修改用户总结】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 auditorProvider() { return new SpringSecurityAuditorAware(); }private static class SpringSecurityAuditorAware implements AuditorAware {@Autowired UserService userService; @Override public Optional getCurrentAuditor() { // 获取当前登陆用户 } } }

@MappedSuperclass public class BaseEntity implements AuditorAware { @Override public Optional 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 authorities, User user) { super(username, password, authorities); this.user = user; }public User getUser() { return user; } }@Override public Optional 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来获取当前登陆用户,最终是在老师的引导下启用了装饰器的模式,经过此次也是对于自己的编程思想有了一个提升,也感谢老师的指导。

    推荐阅读