前言
对于设置批改和创立用户博主耽搁了挺长时间的,此次也是对于教程装璜器模式有了一个更深的了解。
需要形容
在每个实体上都减少 createUser
和updateUser
字段,别离代表的是创立以后数据的用户和更新以后数据的用户。
难点剖析:
1. 找到注解使在数据在创立和更新时执行相应的操作
2. 获取以后登陆用户
踩坑过程
1. 在更新或者创立执行操作
通过关键字在 google 查问首先看到的是 @PrePersist
和@PreUpdate
@PrePersist: 该注解用在办法上能够使该办法在执行长久化操作之前执行
@PreUpdate:该注解用在办法上能够使该办法在执行数据更新并保留操作之前执行
2. 获取以后登陆用户
形容:在 @PrePersist
和@PreUpdate
注解的办法上获取以后登陆用户并进行 createUser
和updateUser
设置。
第一想法:
1. 间接调用 userService
的getCurrentLoginUser
(获取以后登陆用户)办法
@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
仍然会循环。
因为咱们调用的是 UserRepository
的findByUsername
办法,它实质上调用 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
来获取以后登陆用户,最终是在老师的疏导下启用了装璜器的模式,通过此次也是对于本人的编程思维有了一个晋升,也感激老师的领导。