- home page
- special column
- springboot
- Article details
spring boot settings create user and modify user summary
preface
The blogger took a long time to modify the settings and create users. This is also for the tutorial Decorator mode With a deeper understanding.
Requirement description
The createUser and updateUser fields are added to each entity, representing the user who created the current data and the user who updated the current data respectively.
Difficulty analysis:
1. Find the annotation to perform the corresponding operation when the data is created and updated
2. Get the current login user
Pit stepping process
1. Perform operations during update or creation
The first thing you can see in google query by keyword is @ PrePersist and @ PreUpdate
@PrePersist: this annotation is used on a method to make the method execute before the persistence operation
@PreUpdate: this annotation is used on a method to enable the method to execute before performing data update and save operations
2. Get the current login user
Description: obtain the current login user on the @ PrePersist and @ PreUpdate annotation methods and set createUser and updateUser.
First thought:
1. Directly call getCurrentLoginUser (get current login user) method of userService
@Override public Optional<User> getCurrentLoginUser() { logger.debug("Obtain the current login user name according to the authentication and obtain the user name"); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null) { logger.debug("according to username call userRepository Get user") Optional<User> user = this.userRepository.findByUsername(authentication.getName()); return user; } logger.debug("The authenticated user does not exist in the database"); return Optional.empty(); }
Result: it falls into a dead circle
Other attempts:
Use @ Transient to set the userRepository used in the entity to the attribute that does not exist in the entity. As a result, there are more errors.
@CreateBy and @LastModifiedBy
@CreateBy: sets the user who creates the data
@LastModifiedBy: sets the user who recently modified the data
Note: @ CreateBy and @ LastModifiedBy are usually used with AuditorAware
Auditing
What is database Auditing?
It keeps a track of who created or changed an entity and when the change happened.
so: AuditorAware is an interface that spring has this function
The three are used together
1. The fields of the specified entity use @ CreateBy and @ 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. Add @ EntityListeners(AuditingEntityListener.class) annotation ① on the entity (or directly instantiate the AuditorAware interface with the entity) ②
@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() { // Get current login user } } }
@MappedSuperclass public class BaseEntity implements AuditorAware<User> { @Override public Optional<User> getCurrentAuditor() { // Get current login user } }
effect
ERROR: when calling userRepository, it will still loop.
Since we call the findByUsername method of UserRepository, it essentially calls the method of CurdRepository. So why does it get the user and think that the data is created or updated, and then cycle? Because this method is not written by ourselves, there are many unknowns.
solve
Start with UserDetails: write your own UserDetails
Originally, UserDetails has no user field
Add user s to solve problems
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("Obtain the current login user name according to the authentication and obtain the user name"); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null) { UserDetailImpl userDetail; if (authentication instanceof UsernamePasswordAuthenticationToken) { logger.debug("The first method is to obtain the current login user after logging in. It is recommended to pick out this situation and verify it again with the method"); userDetail = (UserDetailImpl) authentication.getPrincipal(); } else if (authentication instanceof UserDetailImpl) { logger.debug("The second login user exists and is modifying data or adding new data"); userDetail = (UserDetailImpl) authentication; } else if (authentication instanceof AnonymousAuthenticationToken) { logger.debug("The third is to modify or add data without login, such as changing password with mobile phone verification code"); return Optional.empty(); } else { throw new RuntimeException("Incorrect get type"); } return Optional.of(userDetail.getUser()); } logger.debug("The authenticated user does not exist in the database"); return Optional.empty(); }
Explanation: its essence is to use Decorator mode , define your own UserDetails and add a snapshot of the currently logged in user.
Effect: it is equivalent to giving each login user a snapshot. Take a chestnut: if the current login user is Zhang San, Zhang San will take a picture of Zhang San after logging in. Then it is assumed that Zhang San has had a facelift in the next few days, but the photos taken when Zhang San logs in have not changed, and so is the idea here
summary
As for the implementation of this requirement, I mainly focused on how to get the current login user without calling the findByUsername of UserRepository. Finally, I enabled the decorator mode under the guidance of the teacher. This time, I also improved my programming idea, and thank the teacher for his guidance.