我有几个JPA实体,每个实体都有一个数据库用户列,我必须在该列中存储对表中特定行进行更改的用户。
我创建了一个所有实体都将从中扩展的"MappedSuperclass"Bean,这就是MappedSuperclass。
@MappedSuperclass
public abstract class AuditableBean {
@Column(name = "modifier_user", nullable = false)
private String modifier_user;
// Getters and Setters
}
这是一个从"MappedSuperclass"扩展而来的实体。
@Entity
@Table(name = "nm_area_ref")
public class ServingAreaReferenceBean extends AuditableBean {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "nm_area_ref_id")
private UUID id;
@Column(name = "nm_srv_area_desc", nullable = false)
private String description;
@Column(name = "nm_retired", nullable = false)
private boolean retired;
// Getters and Setters
}
而且,所有Beans都有一个相应的服务方法,用于将数据保存在数据库中,这是服务类之一(每个服务都为CRUD操作注入一个存储库(。
// Service
@Component
public class ServingAreaReferenceBO {
@Inject private ServingAreaReferenceRepository repository; //repository injection
@Inject private CloudContextProvider cloudContextProvider;
public List<ServingAreaReferenceBean> getAllServingAreaReferences() {
return Lists.newArrayList(repository.findAll());
}
public Optional<ServingAreaReferenceBean> findById(UUID id) {
return repository.findById(id);
}
public ServingAreaReferenceBean create(ServingAreaReferenceBean servingAreaReference) {
Optional<CloudContext> cloudContext = Optional.ofNullable(cloudContextProvider.get());// line 1
servingAreaReference.setUpdaterUser(cloudContext.map(CloudContext::getUserId).orElse(null));// line 2
return repository.save(servingAreaReference);// line 3
}
}
// Repository - It extends from CrudRepository (insert, update, delete operations)
@Repository
public interface ServingAreaReferenceRepository extends CrudRepository<ServingAreaReferenceBean, UUID> {
boolean existsByDescription(String description);
boolean existsByDescriptionAndIdIsNot(String description, UUID id);
}
当"repository.save(("(第3行(执行时,它成功地存储了用户,但我在执行save方法之前放入了用户逻辑(第1、2行(。因此,我不认为在每个服务上重复这两行是最好的方法,相反,我希望实现一个通用方法或一个通用类,在执行save方法之前为所有Bean实体设置用户。
这可能吗?更好的方法是什么?
我想实现这样的东西,但不确定如何使其通用?
@Component
public class AuditableBeanHandler {
@Inject private CloudContextProvider cloudContextProvider;
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setUpdaterUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
}
根据我的理解,您必须在实体的每次保存调用之前设置用户:
这可以通过使用一种众所周知的设计模式来解决;模板法设计模式";。
只需为服务类创建一个父类:
public abstract class AbstractService<T extends AuditableBean> {
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setLastUpdatedByUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
public absract T save(T areaReference);
public final T create(T t) {
t = populateAuditInformation(t);
return save(t);
}
在您的服务类中扩展了这个抽象服务并添加了保存方法:
public class AreaReferenceService extends AbstractService<AreaReferenceBean> {
public AreaReferenceBean save(AreaReferenceBean AreaReference) {
return repository.save(AreaReference);
}
}
在调用服务方法时,请调用create()
方法。希望这能解决你的问题,你也可以阅读更多关于模板方法设计模式的内容。
我认为您已经非常接近AuditableBean了。
添加以下配置以启用审核:
// Annotate a configuration class with this
@EnableJpaAuditing(auditorAwareRef = "auditAware")
添加此";auditAware";bean,您将需要对其进行调整以匹配您正在使用的任何身份验证机制。它的唯一目的是返回经过身份验证的用户的用户名,Spring将使用它。
@Bean
public AuditorAware<String> auditAware() {
return () -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return Optional.of(authentication.getPrincipal());
};
}
在您的modified_user字段(@LastModifiedBy
(中再添加一个注释。这个消息告诉Spring,当实体上发生更新时,将该字段设置为从AuditAware
bean返回的值。
@Column(name = "modifier_user", nullable = false)
@LastModifiedBy
private String modifier_user;
有关可用审计字段的更多信息,请参阅Spring Data JPA文档。