我正在使用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的问题:是的,春天数据JPA配置正确 - 其他一切正常 - 我真的不想发布配置因为你需要很多空间。
我的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字段:(
它也没有得到学校的价值(因为它与当前正在编辑的用户有关,因此我的表格中没有包含该值)所以我需要从SecurityContext再次获取它...我做错了什么?
Update 3 :供参考,不要在评论中遗漏:主要问题是我需要将@SessionAttributes注释包含在我的控制器中。
答案 0 :(得分:7)
使用 @Column 注释的可更新属性,如下所示。
@Column(name = "created_date", updatable = false)
private Date createdDate;
这将保留更新操作的创建日期。
答案 1 :(得分: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将完成所有的升降,你的所有领域/关系都将被正确设置。
答案 2 :(得分:0)
在我的情况下,@CreatedDate 和 @CreatedBy 字段在更新期间没有从数据库中删除,但没有被 @Repository findOne 方法查询。 改变
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
进入
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Entity 类对此有所帮助。