首页 文章

Spring JPA Auditing empty createdBy

提问于
浏览
2

我正在使用auditing capabilities of 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;
...

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

但是,我的问题是,当我更新对象时,我将丢失createdBy和createdDate的值 . 所以,当我第一次创建对象时,我有四个值,但是当我更新它时,createdBy和createdDate都无效!我也在使用Hibernate envers来保存域对象的历史记录 .

你知道为什么我会这样做吗?当我更新域对象时,为什么createdBy和createdDate为空?

更新:要回答@ m-deinum 's questions: Yes spring data JPA is configured correctly - everything else works fine - I really wouldn' t喜欢发布配置,因为当你完成它需要很大的空间 .

我的AuditorAwareImpl是这样的

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

    @Autowired
    ProfileService profileService;

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

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

@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";  
}

更新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";  
     }

当我做更新时,这仍然会使createdBy和createdDate字段变空:(

此外,它没有得到学校的 Value (由于它与当前正在编辑的用户有关,因此不包含在我的表格中)所以我需要从SecurityContext再次获取它...我做错了什么?

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

2 回答

  • 3

    你的(@)Controller类中的方法效率不高 . 您不希望(手动)检索对象并将所有字段,关系等复制到其中 . 在具有复杂对象的旁边,您将更快或更改遇到大麻烦 .

    你想要的是你的第一个方法(用于显示表单的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";  
        }
    }
    

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

    这样你就不必复制对象等了,Spring将完成所有的升降,你的所有场/关系都将被正确设置 .

  • 4

    使用 @Column 注释的 updatable 属性,如下所示 .

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

    这将在更新操作上保留创建日期 .

相关问题