为@CreatedBy添加更多信息。

huangapple go评论67阅读模式
英文:

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&lt;String&gt; {

    public static final String SYSTEM_USER = &quot;system&quot;;

    @Override
    public Optional&lt;String&gt; 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 类,其中包含诸如 userIduserFullName 之类的字段,并将其标注为 @Embeddable(如果需要,还可以使用 @AttributeOverrides 来声明您想要的表列的名称)。然后,在您的实体中,您可以有一个用 @CreatedBy@Embedded 注释的 AuditUser 字段,结合一个实现了 AuditorAware<AuditUser> 接口的实现。有关嵌入式对象的更多信息,请参阅此博文(Baeldung)。

如果您需要更具体的内容,您可以考虑创建一些自定义内容,灵感来自于 Spring 如何实现 JPA 审计(查看类 AuditingEntityListenerAuditingHandlerAnnotationAuditingMetadata)。

英文:

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&lt;AuditUser&gt;. 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).

huangapple
  • 本文由 发表于 2020年9月12日 16:21:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/63858341.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定