英文:
Add more information to @CreatedBy
问题
我有一个Spring Boot 2.3的应用程序。所有我的实体都继承自一个抽象实体,该实体具有一些审计字段,如下所示:
@CreatedBy
@Column(updatable = false)
protected String createdBy;
@CreatedDate
@Column(nullable = false, updatable = false)
protected Instant createdDate;
我实现了AuditorAware
:
public class SpringSecurityAuditorAware implements AuditorAware<String> {
public static final String SYSTEM_USER = "system";
@Override
public Optional<String> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return Optional.of(SYSTEM_USER);
}
Object principal = authentication.getPrincipal();
/**
* If the principal is a CustomUserDetail I access to the name property
*/
if (principal instanceof CustomUserDetail) {
CustomUserDetail user = (CustomUserDetail) principal;
// the sid of the user if not null or the username instead
String sid = user.getSid() != null ? user.getSid() : user.getUsername();
return Optional.ofNullable(sid);
}
return Optional.of(authentication.getName());
}
}
在createdBy
字段中,我保存了用户的sid(标识符)。通过这种方式,我可以引用源表并保持所有更改与用户之间的关联。然而,出于性能原因,我想在每个实体中也保存用户的全名。有没有一种干净的方法来实现这个目标?我唯一能想到的是使用EntityListener
,并在@PrePersist
上设置createdByName
,例如:
@Component
public class MyEntityListener {
@PrePersist
private void onPrePersist(MyAbstractEntity entity) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal instanceof CustomUserDetail) {
CustomUserDetail user = (CustomUserDetail) principal;
entity.setCreatedByName(user.getFullName());
}
}
}
}
你对此有何看法?是否有更好/更干净的方法?
英文:
I've a Spring Boot 2.3 application. All my entities extends an abtract entity that has some auditing fields like:
@CreatedBy
@Column(updatable = false)
protected String createdBy;
@CreatedDate
@Column(nullable = false, updatable = false)
protected Instant createdDate;
I implemented AuditorAware
:
public class SpringSecurityAuditorAware implements AuditorAware<String> {
public static final String SYSTEM_USER = "system";
@Override
public Optional<String> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return Optional.of(SYSTEM_USER);
}
Object principal = authentication.getPrincipal();
/**
* If the principal is a CustomUserDetail I access to the name property
*/
if (principal instanceof CustomUserDetail) {
CustomUserDetail user = (CustomUserDetail) principal;
// the sid of the user if not null or the username instead
String sid = user.getSid() != null ? user.getSid() : user.getUsername();
return Optional.ofNullable(sid);
}
return Optional.of(authentication.getName());
}
}
In createdBy
field I save the sid (identifier) of the user. In this way I've a reference to the source table and I can keep a link between all changes and the user.
However, for performance reasons, I'd like to save also the full name of the user in each entity.
Is there a clean way to reach this goal? The only thing I can think of is to use an EntityListener
and set createdByName
on @PrePersist
for example.
@Component
public class MyEntityListener {
@PrePersist
private void onPrePersist(MyAbstractEntity entity) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal instanceof CustomUserDetail) {
CustomUserDetail user = (CustomUserDetail) principal;
entity.setCreatedByName(user.getFullName());
}
}
}
}
What do you think about? Do you have any other better/clean approach?
答案1
得分: 0
被标注为 @CreatedBy
的字段可以是任何类型。我认为一种方法是创建一个 AuditUser
类,其中包含诸如 userId
和 userFullName
之类的字段,并将其标注为 @Embeddable
(如果需要,还可以使用 @AttributeOverrides
来声明您想要的表列的名称)。然后,在您的实体中,您可以有一个用 @CreatedBy
和 @Embedded
注释的 AuditUser
字段,结合一个实现了 AuditorAware<AuditUser>
接口的实现。有关嵌入式对象的更多信息,请参阅此博文(Baeldung)。
如果您需要更具体的内容,您可以考虑创建一些自定义内容,灵感来自于 Spring 如何实现 JPA 审计(查看类 AuditingEntityListener
、AuditingHandler
和 AnnotationAuditingMetadata
)。
英文:
The field annotated as @CreatedBy
can be of any type. I think that one approach could be to create an AuditUser
class having fields like userId
and userFullName
, and annotate it as @Embeddable
(in case, also with @AttributeOverrides
to declare how you want your table columns to be named). Then, in your entity you can have an AuditUser
field annotated with @CreatedBy
and @Embedded
, combined with an implementation of AuditorAware<AuditUser>
. More info on embeddable objects in this blog post (Baeldung).
If you needed something more specific, you could think of creating something custom, inspired from how Spring implemented the JPA auditing (looking at the classes AuditingEntityListener
, AuditingHandler
, and AnnotationAuditingMetadata
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论