更新时,未在返回的实体上设置标记为updatable = false的spring数据审核字段

时间:2018-09-07 21:37:02

标签: java spring spring-data-jpa auditing

我正在使用Spring Data的注释将审计数据添加到保存或更新的实体中。创建实体时,createdBycreatedDatelastModifiedBylastModifiedDate在由repository.save()返回的对象上设置。

ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=2018-09-07T21:11:25.797, lastModifiedDate=2018-09-07T21:11:25.797, createdBy=5855070b-866f-4bc4-a18f-26b54f896a4b, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)

不幸的是,当我调用repository.save()更新现有实体时,返回的对象没有设置createdBycreatedDate

 ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=null, lastModifiedDate=2018-09-07T21:12:01.953, createdBy=null, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)

在数据库中正确设置了所有字段,并且对服务类外部的repository.findOne()的调用返回了一个具有正确设置所有字段的对象。

ResourceEntity(id=ebbe1f3d-3359-4295-8c83-63eab21c4753, createdDate=2018-09-07T21:11:25.797, lastModifiedDate=2018-09-07T21:12:01.953, createdBy=5855070b-866f-4bc4-a18f-26b54f896a4b, lastModifiedBy=5855070b-866f-4bc4-a18f-26b54f896a4b)

但是,如果我在调用repository.findOne()以更新实体后立即在服务中调用repository.save(),我也会得到一个createdBy并且createdDate设置为null的对象。 / p>

这是我的实体:

@Entity(name = "resource")
@EntityListeners(AuditingEntityListener.class)
@Table(name = "resource")
@Data
@EqualsAndHashCode(of = "id")
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ResourceEntity {

@Id
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID id;

@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdDate;

@LastModifiedDate
private LocalDateTime lastModifiedDate;

@CreatedBy
@Column(nullable = false, updatable = false)
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID createdBy;

@LastModifiedBy
@org.hibernate.annotations.Type(type = "org.hibernate.type.PostgresUUIDType")
private UUID lastModifiedBy;
}

这是我的服务

@Component
public class ResourceService {
@Autowired
private ResourceRepository resourceRepository;

public ResourceEntity createResource(ResourceEntity resourceEntity) {
    return saveResource(resourceEntity);
}

public ResourceEntity updateResource(ResourceEntity resourceEntity) {
    return saveResource(resourceEntity);
}

public ResourceEntity getResource(UUID resourceId) {
    return resourceRepository.findOne(resourceId);
}

private ResourceEntity saveResource(ResourceEntity resourceEntity) {
    ResourceEntity savedResourceEntity = resourceRepository.save(resourceEntity);
    return savedResourceEntity;
}
}

这是我的考试:

def "Test update"() {
    given:
    UUID id = aRandom.uuid()
    Resource resource = aRandom.resource().id(id).build()
    Resource savedResource = resourceClient.createResource(resource)

    when:
    Resource updatedResource = aRandom.resource().id(id).build()
    updatedResource = resourceClient.updateResource(updatedResource)

    then:
    Resource result = resourceClient.getResource(id)
    assert result.id == updatedResource.id
    assert result.createdBy == updatedResource.createdBy
    assert result.creationDate == updatedResource.creationDate
    assert result.lastModifiedBy == updatedResource.lastModifiedBy
    assert result.lastModifiedDate == updatedResource.lastModifiedDate
}

2 个答案:

答案 0 :(得分:0)

我需要添加审核信息时就这样尝试过。

我有一个DataConfig类,

@Configuration
@EnableJpaAuditing
public class DataConfig {

    @Bean
    public AuditorAware<UUID> auditorProvider() {
        return new YourSecurityAuditAware();
    }

    @Bean
    public DateTimeProvider dateTimeProvider() {
        return () -> Optional.of(Instant.from(ZonedDateTime.now()));
    }
}

现在,您需要AuditorAware类来获取审核信息。 所以这个班级将会是这样;

public class XPorterSecurityAuditAware implements AuditorAware<UUID> {

    @Override
    public Optional<UUID> getCurrentAuditor() {
        //you can change UUID format as well
        return Optional.of(UUID.randomUUID());
    }
}

希望这会对您有所帮助。

答案 1 :(得分:0)

在最初的问题多年后,它仍然是一个问题。

虽然不是完美的解决方案,但我最终获取(通过 findById())现有实体并在执行更新之前手动设置新实体的 @CreatedBy@CreatedDate 字段。 JPA 的审计框架没有自动处理这个问题或提供更好的方法来完成它,这既令人惊讶又令人沮丧。