Java Spring JPA 审计空 createdBy

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19090258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 14:00:15  来源:igfitidea点击:

Spring JPA Auditing empty createdBy

javaspringspring-dataauditing

提问by Serafeim

I am using the auditing capabilities of Spring Dataand have a class similar to this:

我正在使用Spring Data审计功能,并且有一个类似的类:

@Entity
@Audited
@EntityListeners(AuditingEntityListener.class)
@Table(name="Student")
public class Student {
    @Id
    @GeneratedValue (strategy = GenerationType.AUTO)
    private Long id;

    @CreatedBy
    private String createdBy;

    @CreatedDate
    private Date createdDate;

    @LastModifiedBy
    private String lastModifiedBy;

    @LastModifiedDate
    private Date lastModifiedDate;
...

Now, I believe I have configured auditing fine because I can see that createdBy, createdDate, lastModifiedBy and lastModifiedDate all are getting the correct values when I update the domain objects.

现在,我相信我已经很好地配置了审计,因为当我更新域对象时,我可以看到 createdBy、createdDate、lastModifiedBy 和 lastModifiedDate 都获得了正确的值。

However, my problem is that when I update an object I am losing the values of createdBy and createdDate. So, when I first create the object I have all four values, but when I update it createdBy and createdDate are nullified ! I am also using the Hibernate envers to keep a history of the domain objects.

但是,我的问题是,当我更新对象时,我丢失了 createdBy 和 createdDate 的值。因此,当我第一次创建对象时,我拥有所有四个值,但是当我更新它时 createdBy 和 createdDate 被取消了!我还使用 Hibernate envers 来保存域对象的历史记录。

Do you know why do I get this behavior ? Why do createdBy and createdDate are empty when I update the domain object ?

你知道我为什么会有这种行为吗?为什么在更新域对象时 createdBy 和 createdDate 为空?

Update: To answer @m-deinum 's questions: Yes spring data JPA is configured correctly - everything else works fine - I really wouldn't like to post the configuration because as you udnerstand it will need a lot of space.

更新:回答@m-deinum 的问题:是的,spring 数据 JPA 配置正确-其他一切正常-我真的不想发布配置,因为在您看来它需要很多空间。

My AuditorAwareImpl is this

我的 AuditorAwareImpl 是这个

@Component
public class AuditorAwareImpl implements AuditorAware {
    Logger logger = Logger.getLogger(AuditorAwareImpl.class);

    @Autowired
    ProfileService profileService;

    @Override
    public String getCurrentAuditor() {
        return profileService.getMyUsername();
    }
}

Finally, here's my update controller implementation:

最后,这是我的更新控制器实现:

    @Autowired  
    private StudentFormValidator validator;
    @Autowired
    private StudentRepository studentRep;

@RequestMapping(value="/edit/{id}", method=RequestMethod.POST)  
public String updateFromForm(
         @PathVariable("id")Long id,
         @Valid Student student, BindingResult result,
         final RedirectAttributes redirectAttributes)   {  

     Student s =  studentRep.secureFind(id); 
     if(student == null || s == null) {
         throw new ResourceNotFoundException();
     }
     validator.validate(student, result);
     if (result.hasErrors()) {  
         return "students/form";
     } 
     student.setId(id);
     student.setSchool(profileService.getMySchool());
     redirectAttributes.addFlashAttribute("message", "Επιτυχ?? προσθ?κη!");
     studentRep.save(student);
     return "redirect:/students/list";  
}  

Update 2: Please take a look at a newer version

更新 2: 请看看更新的版本

@RequestMapping(value="/edit/{id}", method=RequestMethod.GET)  
     public ModelAndView editForm(@PathVariable("id")Long id)  {  
         ModelAndView mav = new ModelAndView("students/form");  
         Student student =  studentRep.secureFind(id); 
         if(student == null) {
             throw new ResourceNotFoundException();
         }
         mav.getModelMap().addAttribute(student);
         mav.getModelMap().addAttribute("genders", GenderEnum.values());
         mav.getModelMap().addAttribute("studentTypes", StudEnum.values());
         return mav;  
     }  

     @RequestMapping(value="/edit/{id}", method=RequestMethod.POST)  
     public String updateFromForm(
             @PathVariable("id")Long id,
             @Valid @ModelAttribute Student student, BindingResult result,
             final RedirectAttributes redirectAttributes, SessionStatus status)   {  

         Student s =  studentRep.secureFind(id); 
         if(student == null || s == null) {
             throw new ResourceNotFoundException();
         }

         if (result.hasErrors()) {  
             return "students/form";
         } 
         //student.setId(id);
         student.setSchool(profileService.getMySchool());
         studentRep.save(student);
         redirectAttributes.addFlashAttribute("message", "Επιτυχ?? προσθ?κη!");
         status.setComplete();
         return "redirect:/students/list";  
     }  

This stillleaves empty the createdBy and createdDate fields when I do an update :(

当我进行更新时,这仍然使 createdBy 和 createdDate 字段为空:(

Also it does not get the School value (which is not contained in my form because it is related to the user currently editing) so I need to get it again from the SecurityContext... Have I done anything wrong ?

它也没有得到 School 值(它没有包含在我的表单中,因为它与当前编辑的用户有关)所以我需要从 SecurityContext 再次获取它......我做错了什么吗?

Update 3: For reference and to not miss it in the comments: The main problem was that I needed to include the @SessionAttributes annotation to my controller.

更新 3:供参考,不要在评论中错过:主要问题是我需要将 @SessionAttributes 注释包含到我的控制器中。

采纳答案by M. Deinum

Your method in your (@)Controller class is not that efficient. You don't want to (manually) retrieve the object and copy all the fields, relationships etc. over to it. Next to that with complex objects you will sooner or alter run into big trouble.

您的 (@)Controller 类中的方法效率不高。您不想(手动)检索对象并将所有字段、关系等复制到它。除了复杂的对象,你会很快或改变遇到大麻烦。

What you want is on your first method (the GET for showing the form) retrieve the user and store it in the session using @SessionAttributes. Next you want an @InitBinderannotated method to set your validator on the WebDataBinderso that spring will do the validation. This will leave your updateFromFormmethod nice and clean.

您想要的是在您的第一个方法(用于显示表单的 GET)中检索用户并将其存储在会话中使用@SessionAttributes. 接下来,您需要一个带@InitBinder注释的方法来设置验证器,WebDataBinder以便 spring 进行验证。这将使您的updateFromForm方法干净整洁。

@Controller
@RequestMapping("/edit/{id}")
@SessionAttributes("student")
public EditStudentController

    @Autowired  
    private StudentFormValidator validator;

    @Autowired
    private StudentRepository studentRep;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.setValidator(validator);
    }

    @RequestMapping(method=RequestMethod.GET)
    public String showUpdateForm(Model model) {
        model.addObject("student", studentRep.secureFind(id));
        return "students/form";
    }

    @RequestMapping(method=RequestMethod.POST)
    public String public String updateFromForm(@Valid @ModelAttribute Student student, BindingResult result, RedirectAttributes redirectAttributes, SessionStatus status)   {  
        // Optionally you could check the ids if they are the same.
        if (result.hasErrors()) {  
            return "students/form";
        } 
        redirectAttributes.addFlashAttribute("message", "?p?t???? p??s????!");
        studentRep.save(student);
        status.setComplete(); // Will remove the student from the session
        return "redirect:/students/list";  
    }
}  

You will need to add the SessionStatusattribute to the method and mark the processing complete, so that Spring can cleanup your model from the session.

您需要将SessionStatus属性添加到该方法并将处理标记为完成,以便 Spring 可以从会话中清除您的模型。

This way you don't have to copy around objects, etc. and Spring will do all the heave lifting and all your fields/relations will be properly set.

通过这种方式,您不必复制对象等,Spring 将完成所有举重工作,并且您的所有字段/关系都将被正确设置。

回答by Maz

Use updatableattribute of @Columnannotation like below.

使用@Column注释的可更新属性,如下所示。

@Column(name = "created_date", updatable = false)
private Date createdDate;

This will retain the created date on update operation.

这将保留更新操作的创建日期。