我有一个要求,我必须在其中存储每次插入/更新/删除的审核信息。要存储的信息将是更新时间和用户ID。
我从this tutorial中学到了可以使用实体侦听器和@PrePersist
之类的回调方法。
我知道如何在回调方法内处理更新时间,但是我不知道如何在回调方法内的实体中设置userId:
@PrePersist
private void prePersist() {
this.updateTime = new Date();
this.userId = ???;
}
如何将当前用户的ID传递给回调方法?
最佳答案
您不能直接使用Hibernate或JPA API将任何信息传递给回调方法。
但是还有另一个常见的解决方案:ThreadLocal
ThreadLocal
为当前正在运行的线程存储静态变量。由于请求通常在一个线程中执行,因此您可以从回调方法/侦听器访问该信息。一些UI框架已经为您创建了ThreadLocal
。
例如,JSF为FacesContext.getCurrentInstance()
提供了一个。因此,在JSF中,您可以调用:
FacesContext.getCurrentInstance().getExternalContext().getRemoteUser()
或在春季使用
RequestContextHolder
:((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRemoteUser()
如果没有这样的框架,则可以构建自己的
ThreadLocal
:public final class UserIdHelper {
// You can add the static ThreadLocal to any class, just as an example
private static final ThreadLocal<String> userIds = new ThreadLocal<>();
public static void setCurrentUserId(String userId) {
userIds.set(userId);
}
public static String getCurrentUserId() {
return userIds.get();
}
public static void removeCurrentUserId() {
userIds.remove();
}
}
现在,您可以在
Filter
或JPA调用附近设置userId:UserIdHelper.setCurrentUserId(request.getRemoteUser());
try {
// ... Execute your JPA calls ...
} finally {
UserIdHelper.removeCurrentUserId();
}
删除
finally
块中的userId很重要-否则,在同一线程中运行的后续请求可能会“劫持”您先前的userId。要在您的回调方法中访问该信息:
@PrePersist
private void prePersist() {
this.createdBy = UserIdHelper.getCurrentUserId();
}