如何在Spring Boot+MongoDB中自动填充CreatedBy与LastModifiedBy字段
利用Spring Data MongoDB审计机制自动填充用户字段
你完全可以借助Spring Data MongoDB的审计扩展来自动填充CreatedBy和LastModifiedBy字段,不用在服务层手动编写重复代码,具体实现步骤如下:
1. 实现AuditorAware接口
创建一个类实现AuditorAware,用来提供当前操作的用户ID,这个类会被Spring自动调用以填充审计字段:
@Component public class SpringSecurityAuditorAware implements AuditorAware<String> { @Override public Optional<String> getCurrentAuditor() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // 处理未登录或匿名用户的情况,可根据业务需求调整逻辑 if (auth == null || !auth.isAuthenticated() || auth instanceof AnonymousAuthenticationToken) { return Optional.empty(); } // 假设你的Authentication中存储的是User对象(已实现UserDetails) User currentUser = (User) auth.getPrincipal(); return Optional.of(currentUser.getId()); // 如果Authentication中只有用户名,需查询用户ID的话,可注入UserRepository: // String username = auth.getName(); // return userRepository.findByUsername(username) // .map(User::getId); } }
2. 启用Mongo审计并指定AuditorBean
在Spring Boot启动类上,修改@EnableMongoAuditing注解,指定刚才实现的AuditorAware bean:
@SpringBootApplication @EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware") public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
3. 在实体类中添加审计注解
在Project实体的对应字段上添加@CreatedBy和@LastModifiedBy注解,配合已有的日期审计注解:
@Document(collection = "projects") public class Project { // 其他字段... @CreatedBy private String createdBy; @LastModifiedBy private String lastModifiedBy; @CreatedDate private LocalDateTime createdDate; @LastModifiedDate private LocalDateTime lastModifiedDate; // 建议把active字段的默认值放到实体类中,避免在服务层重复设置 private boolean active = true; // getter、setter... }
4. 简化服务层代码
现在可以去掉服务层中手动设置createdBy和lastModifiedBy的代码,方法会变得更简洁:
public Project create(Project project) { getByName(project.getName()).ifPresent(existing -> { throw new ProjectAlreadyExistsException(existing.getName()); }); // 无需手动设置createdBy、lastModifiedBy,审计机制会自动处理 return projectRepository.save(project); }
额外说明
- 这种方式遵循关注点分离原则,把审计逻辑统一封装到
AuditorAware中,所有需要审计的实体都能复用这套逻辑,避免重复代码。 - 如果涉及异步方法,需要确保
SecurityContext能传递到异步线程中,可以在配置类中设置:@Configuration public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setTaskDecorator(runnable -> { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); return () -> { try { SecurityContextHolder.getContext().setAuthentication(auth); runnable.run(); } finally { SecurityContextHolder.clearContext(); } }; }); executor.initialize(); return executor; } }
内容的提问来源于stack exchange,提问作者Aymen Maamri
相关产品推荐
相关产品推荐

