spring boot 设置创建用户和修改用户总结
前言
对于设置修改和创建用户博主耽误了挺长时间的,此次也是对于教程装饰器模式有了一个更深的理解。
需求描述
在每个实体上都增加createUser
和updateUser
字段,分别代表的是创建当前数据的用户和更新当前数据的用户。
难点分析:
1.找到注解使在数据在创建和更新时执行相应的操作
2.获取当前登陆用户
踩坑过程
1.在更新或者创建执行操作
通过关键字在google查询首先看到的是@PrePersist
和@PreUpdate
@PrePersist:该注解用在方法上可以使该方法在执行持久化操作之前执行
@PreUpdate:该注解用在方法上可以使该方法在执行数据更新并保存操作之前执行
文章图片
2.获取当前登陆用户
描述:在@PrePersist
和@PreUpdate
注解的方法上获取当前登陆用户并进行createUser
和updateUser
设置。
第一想法:
1.直接调用userService
的getCurrentLoginUser
(获取当前登陆用户)方法
@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();
}
结果:陷入死循环
文章图片
其他尝试:
使用@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
依然会循环。由于我们调用的是
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 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
来获取当前登陆用户,最终是在老师的引导下启用了装饰器的模式,经过此次也是对于自己的编程思想有了一个提升,也感谢老师的指导。推荐阅读
- 第6.2章(设置属性)
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- 15、IDEA学习系列之其他设置(生成javadoc、缓存和索引的清理等)
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存