以下是我对AuditAware的实施。
@Component
public class AuditorAwareImpl implements AuditorAware<String> {
@Log
private Logger logger;
@Override
public String getCurrentAuditor() {
String user = "SYSTEM";
try {
final Subject subject = SecurityUtils.getSubject();
if (subject != null) {
final Session session = subject.getSession(false);
if (session != null) {
final User userObj = (User) session.getAttribute("user");
if (userObj != null) {
user = userObj.getUsername();
}
}
}
} catch (final Exception e) {
this.logger.error("getCurrentAuditor", "No logged in user information found.", e);
}
return user;
}
}
我们知道,由Spring注入的AuditorAwareImpl返回的用户值在@CreatedBy注释标记的属性中如下所示。
@CreatedBy
@Column(name = "CREATED_BY", length = 150, nullable = false, updatable = false)
private String createdBy;
我想解决两个问题。
我在单个对象级别尝试了一件事,使用以下代码,
@Transient
private String overRiddenUser;
@PrePersist
public void updateCreatedBy(){
if(overRiddenUser!=null){
this.createdBy=overRiddenUser;
}
}
每当我想在createBy中覆盖spring注入的用户并使用PrePersist方法覆盖它时,我就显式设置了overRiddenUser="Admin"
。但是即使这样做也没有用,因为在我覆盖这个值之前,spring尝试使用AuditAware返回的值来填充。如果会话已经过期,则过程出错!我该如何解决这个问题?
答案 0 :(得分:0)
我找到了上述问题的解决方案如下。
第1步
我在下面定义了一个包含HashMap的bean。此映射将当前线程名称存储为键,并将映射的用户名存储为值。
public class OverRiddenUser {
Map<String,String> userThreadMap= new HashMap<>();
//add getters/setters
}
第2步
在@Configuration
注释的类中启动时初始化此bean。
@Bean("overRiddenUser")
public OverRiddenUser overRideUser(){
OverRiddenUser obj = new OverRiddenUser();
return obj;
// Singleton implementation can be done her if required
}
第3步
在我要覆盖会话用户的impl类中自动连接此bean。
@Autowired
OverRiddenUser overRiddenUser;
为当前正在运行的线程分配了一个随机名称。
RandomString randomThreadName = new RandomString(9);
Thread.currentThread().setName(randomThreadName.toString());
然后在hashmap中为当前线程添加所需的用户名,如下所示。
try {
if(overRiddenUser!=null){
overRiddenUser.getUserThreadMap().put(Thread.currentThread().getName(),"My Over ridden username");
}
// Entire Database related code here
} catch (Exception e){
// handle the exceptions thrown by code
} finally {
//Perform clean up here
if(overRiddenUser!=null){
overRiddenUser.getUserThreadMap().remove(Thread.currentThread().getName());
}
}
}
第4步
然后我修改了AuditAwareImpl,如下所示。
@Component
public class AuditorAwareImpl implements AuditorAware<String> {
@Log
private Logger logger;
@Autowired
OverRiddenUser overRiddenUser;
@Override
public String getCurrentAuditor() {
String user = "SYSTEM";
try {
if(overRiddenUser!=null && overRiddenUser.getUserThreadMap()!=null && overRiddenUser.getUserThreadMap().get(Thread.currentThread().getName())!=null){
user=overRiddenUser.getUserThreadMap().get(Thread.currentThread().getName());
}else{
final Subject subject = SecurityUtils.getSubject();
if (subject != null) {
final Session session = subject.getSession(false);
if (session != null) {
final User userObj = (User) session.getAttribute("user");
if (userObj != null) {
user = userObj.getUsername();
}
}
}
}
} catch (final Exception e) {
this.logger.error("getCurrentAuditor", "No logged in user information found.", e);
}
return user;
}
}
因此,如果当前正在运行的线程访问AuditAwareImpl,那么它将获得为该线程设置的自定义用户名。如果这是null,则它会像之前那样从会话中提取用户名。希望有所帮助。