简体   繁体   中英

How do I reference a Foreign Key instead of a username for auditing using Spring Data JPA?

Intro

I have set up an auditing feature using Spring Data JPA for a project. It is working fine, I am getting back the CreatedBy , CreatedDate , LastModifiedBy , and LastModifiedDate properties with no issue.

The Question

The thing is CreatedBy and LastModifiedBy are returning the username property value from the logged in user, which was what I intended in the first place, but now I need to return a foreign key for that user instead of their username .

I honestly have no idea how to implement this, please bear in mind this is my first semi-professional (irrelevant long story there) project. I've searched everywhere and couldn't find an answer. I don't know if I am using StackOverflow correctly, this is my first post, so if my question is silly or not that relevant, keep in mind I'm new here, please be helpful and help me find my way around.

Project Setup

For this project I am using the Spring Framework and Kotlin .

I've got the following files:

  • ServiceModel.kt
  • EmployeeModel.kt
  • AuditModel.kt (extensible class containing auditing properties)
  • AuditorAwareImpl.kt

Files

ServiceModel.kt

import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.math.BigDecimal
import java.util.*
import javax.persistence.*

@Entity
@EntityListeners(AuditingEntityListener::class)
@Table(name = "SERVICE")
class ServiceModel(): AuditModel() {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long? = null

    @Column(nullable = false)
    lateinit var description: String

    @Column(nullable = false)
    lateinit var duration: String

    @Column(nullable = false)
    lateinit var price: BigDecimal

    @Column(length = 255, nullable = false)
    lateinit var title: String

    @Column(length = 255)
    val image: String? = null

    @Column(length = 255)
    lateinit var comments: String

}

EmployeeModel.kt

import org.springframework.data.jpa.domain.support.AuditingEntityListener
import javax.persistence.*

@Entity
@EntityListeners(AuditingEntityListener::class)
@Table(name = "EMPLOYEE")
class EmployeeModel(): AuditModel() {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long? = null

    @Column(nullable = false, length = 255)
    lateinit var fullName: String

    @Column(nullable = false, unique = true, length = 14)
    lateinit var document: String

    @Column(nullable = false, length = 16)
    lateinit var phoneNumber: String

    @Column(length = 255, nullable = false)
    lateinit var email: String

    @Column(nullable = false, length = 10)
    lateinit var zipCode: String

    @Column(nullable = false, length = 255)
    lateinit var address: String

    @Column(nullable = false, length = 255)
    lateinit var country: String

    @Column(nullable = false, length = 255)
    lateinit var city: String

    @Column(nullable = false, length = 255)
    lateinit var province: String

    @ManyToOne(optional = true)
    @JoinColumn(name = "fk_company", nullable = true)
    val company : CompanyModel? = null
}

AuditModel.kt

import org.springframework.data.annotation.CreatedBy
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedBy
import org.springframework.data.annotation.LastModifiedDate
import java.util.*
import javax.persistence.Column

abstract class AuditModel {
    @CreatedBy
    @Column(name = "created_by")
    lateinit var createdBy: String

    @CreatedDate
    @Column(name = "created_at")
    lateinit var createdAt: Date

    @LastModifiedBy
    @Column(name = "updated_by")
    lateinit var updatedBy: String

    @LastModifiedDate
    @Column(name = "updated_at")
    lateinit var updatedAt: Date
}

AuditorAwareImpl.kt

import org.springframework.data.domain.AuditorAware
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.stereotype.Component
import java.util.*

@Component
class AuditorAwareImpl : AuditorAware<String> {

    override fun getCurrentAuditor(): Optional<String> {
        var loggedInUser: String = SecurityContextHolder.getContext().authentication.name
        return Optional.of(loggedInUser)
    }

}

What I Have Tried

I have tried to get the foreign key property instead of the username in the AuditorAwareImpl.kt file from the SecurityContextHolder class, but to no avail.


I hope I've provided enough for someone to be able to help, otherwise let me know and I'll further contribute. Thank you very much in advance.

I'm sorry I'm not able to answer you in Kotlin but maybe you can work with my Java answer as well. You could declare your own EntityListener and set the audited fields manually. The problem is that you can't override the property which the @CreatedBy respectively the @LastModifiedBy accesses.
A custom entity listener could look like this:

@Component
@RequiredArgsConstructor
public class EmployeeModelListener {

    @PrePersist
    public void prePersist(EmployeeModel employee) {
        employee.setCreatedBy(); // access the foreign key
        employee.setCreatedAt(ZonedDateTime.now());
        employee.setUpdatedBy(employee.getCreatedBy());
        employee.setUpdatedAt(employee.getCreatedAt());
    }

    @PreUpdate
    public void preUpdate(EmployeeModel employee) {
        employee.setUpdatedBy(); // access the foreign key
        employee.setUpdatedAt(ZonedDateTime.now());
    }

}

Note that this is a component, therefore allowing the injection of beans if necessary (I don't know how you obtain said foreign key but if you needed a repository for example, you could autowire it in here and use it to retrieve the desired data).

You then need to remove the auditing annotations like @CreatedBy and @CreatedDate from your AuditModel and change the @EntityListeners(AuditingEntityListener::class) to @EntityListeners(EmployeeModelListener::class) in your EmployeeModel .

You can also try if a hybrid model works where you leave the @CreatedDate and @LastModifiedDate annotations on the AuditModel and don't set it manually in the EmployeeModelListener .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM