Spring-MVC、Hibernate:从域对象创建 DTO 对象
Spring-MVC, Hibernate : Creating DTO objects from Domain objects
我正在开发一个 Spring-MVC 应用程序,我试图在其中搜索数据库中的 GroupNotes 列表。我项目中的映射是 GroupCanvas 与 GroupSection 一对多映射,GroupSection 与 GroupNotes 一对多映射。由于这些映射,我得到了 LazyInitializationException。正如 SO 所建议的那样,我应该将对象转换为 DTO 对象以进行传输。我在网上查过,但找不到合适的翻译方式。
我刚刚创建了一个新列表来避免这个错误,但是一个字段仍然给我一个错误。如果有人告诉我如何修复此错误或将对象转换为 DTO 对象以便传输它们,我将不胜感激。
控制器代码:
@RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public @ResponseBody List<GroupNotes> findGroupNotesByDays(@PathVariable("days")int days, @PathVariable("canvasid")int canvasid){
List<GroupNotes> groupNotesList = this.groupNotesService.findGroupNotesByDays(days,canvasid);
List<GroupNotes> toSendList = new ArrayList<>();
for(GroupNotes groupNotes : groupNotesList){
GroupNotes toSendNotes = new GroupNotes();
toSendNotes.setMnotecolor(groupNotes.getMnotecolor());
toSendNotes.setNoteCreationTime(groupNotes.getNoteCreationTime());
toSendNotes.setMnotetag(groupNotes.getMnotetag());
toSendNotes.setMnotetext(groupNotes.getMnotetext());
toSendNotes.setAttachCount(groupNotes.getAttachCount());
toSendNotes.setNoteDate(groupNotes.getNoteDate());
toSendList.add(toSendNotes);
}
return toSendList;
}
GroupNotesDAOImpl :
@Override
public List<GroupNotes> searchNotesByDays(int days, int mcanvasid) {
Session session = this.sessionFactory.getCurrentSession();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
GroupCanvas groupCanvas = (GroupCanvas) session.get(GroupCanvas.class,mcanvasid);
Query query = session.createQuery("from GroupSection as n where n.currentcanvas.mcanvasid=:mcanvasid");
query.setParameter("mcanvasid", mcanvasid);
List<GroupSection> sectionList = query.list();
List<GroupNotes> notesList = new ArrayList<GroupNotes>();
for (GroupSection e : sectionList) {
System.out.println("Section name is "+e.getMsectionname());
GroupSection groupSection = (GroupSection) session.get(GroupSection.class,e.getMsectionid());
Query query1 = session.createQuery("from GroupNotes as gn where gn.ownednotes.msectionid=:msectionid and gn.noteCreationTime >:limit");
query1.setParameter("limit", nowMinusDaysAsTimestamp);
query1.setParameter("msectionid",e.getMsectionid());
notesList.addAll(query1.list());
}
// I am getting the data below, but I get JSON errors.
for(GroupNotes groupNotes : notesList){
System.out.println("Group notes found are "+groupNotes.getMnotetext());
}
return notesList;
}
GroupCanvas 模型:
@Entity
@Table(name = "membercanvas")
public class GroupCanvas{
@OneToMany(mappedBy = "currentcanvas",fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupSection> ownedsection = new HashSet<>();
@JsonIgnore
public Set<GroupSection> getOwnedsection() {
return this.ownedsection;
}
public void setOwnedsection(Set<GroupSection> ownedsection) {
this.ownedsection = ownedsection;
}
}
GroupSection 模型:
@Entity
@Table(name = "membersection")
public class GroupSection{
@OneToMany(mappedBy = "ownednotes", fetch = FetchType.EAGER,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
public Set<GroupNotes> getSectionsnotes(){
return this.sectionsnotes;
}
public void setSectionsnotes(Set<GroupNotes> sectionsnotes){
this.sectionsnotes=sectionsnotes;
}
}
GroupNotes 型号:
@Entity
@Table(name="groupnotes")
public class GroupNotes{
@Id
@Column(name="mnoteid")
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "mnote_gen")
@SequenceGenerator(name = "mnote_gen",sequenceName = "mnote_seq")
@org.hibernate.annotations.Index(name = "mnoticesidindex")
private int mnoticesid;
@Column(name = "mnotetext")
private String mnotetext;
@Column(name = "mnoteheadline")
private String mnotetag;
@Column(name = "mnotecolor")
private String mnotecolor;
@Column(name = "mnoteorder")
private double mnoteorder;
@Column(name = "attachmentcount")
private int attachCount;
@Column(name = "notedate")
private String noteDate;
@Column(name = "uploader")
private String uploader;
@Column(name = "activeedit")
private boolean activeEdit;
@Column(name = "notedisabled")
private boolean noteDisabled;
@Column(name = "noteinactive")
private boolean noteInActive;
@Column(name = "notecreatoremail")
private String noteCreatorEmail;
@Column(name = "prefix")
private String prefix;
@Column(name = "timestamp")
private Timestamp noteCreationTime;
@Transient
private boolean notRead;
@Transient
private String tempNote;
@Transient
private String canvasUrl;
@ManyToOne
@JoinColumn(name = "msectionid")
@JsonIgnore
private GroupSection ownednotes;
@JsonIgnore
public GroupSection getOwnednotes(){return this.ownednotes;}
public void setOwnednotes(GroupSection ownednotes){this.ownednotes=ownednotes;}
@JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
@OneToMany(mappedBy = "mnotedata",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupAttachments> mattachments = new HashSet<>();
public Set<GroupAttachments> getMattachments() {
return this.mattachments;
}
public void setMattachments(Set<GroupAttachments> mattachments) {
this.mattachments = mattachments;
}
@OneToMany(mappedBy = "mhistory",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupNoteHistory> groupNoteHistorySet = new HashSet<>();
public Set<GroupNoteHistory> getGroupNoteHistorySet(){
return this.groupNoteHistorySet;
}
public void setGroupNoteHistorySet(Set<GroupNoteHistory> groupNoteHistorySet){
this.groupNoteHistorySet = groupNoteHistorySet;
}
@OneToMany(mappedBy = "unreadNotes",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<UnreadNotes> unreadNotesSet = new HashSet<>();
public Set<UnreadNotes> getUnreadNotesSet(){
return this.unreadNotesSet;
}
public void setUnreadNotesSet(Set<UnreadNotes> unreadNotesSet){
this.unreadNotesSet = unreadNotesSet;
}
//getters and setters ignored
}
错误日志:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"])
请告诉我该怎么做,因为一段时间以来我一直被这个错误所困扰。
我认为 Jackson 试图根据 getter 方法序列化层次结构中的所有字段。在某些情况下 NullPointerException
会在以下方法中抛出:
@JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
替换成下面的方法:
@JsonIgnore
public int getOwnedSectionId(){
if(this.ownednotes != null)
return this.ownednotes.getMsectionid();
return 1;
}
我无法解释为什么 jackson 会尝试在 @JsonIgnore 上市时将其序列化,但您可以尝试我的建议
I would appreciate if anyone tells me either how to fix this error or convert the objects to a DTO objects so they can be transferred.
为此,我们在工作中使用 DozerMapper。
与其手动执行该映射,不如看看 Blaze-Persistence Entity Views,它可用于通过 JPA 有效地实现 DTO 模式。这里有一个快速代码示例如何解决您的问题
首先将 DTO 定义为实体视图
@EntityView(GroupNotes.class)
public interface GroupNoteView {
@IdMapping("mnoticesid") int getId();
String getMnotecolor();
String getMnotetag();
String getMnotetext();
String getNoteDate();
Timestamp getNoteCreationTime();
int getAttachCount();
}
接下来调整您的 DAO 以使用它
@Override
public List<GroupNoteView> searchNotesByDays(int days, int mcanvasid) {
EntityManager entityManager = // get the entity manager from somewhere
CriteriaBuilderFactory cbf = // factory for query building from Blaze-Persistence
EntityViewManager evm = // factory for applying entity views on query builders
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
CriteriaBuilder<GroupNotes> cb = cbf.create(entityManager, GroupNotes.class, "note")
.where("noteCreationTime").gt(nowMinusDaysAsTimestamp)
.where("ownednotes.ownedcanvas.mcanvasid").eq(mcanvasid);
return evm.applySetting(EntityViewSetting.create(GroupNoteView.class), cb)
.getResultList();
}
最后是调用代码
@RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public @ResponseBody List<GroupNoteView> findGroupNotesByDays(@PathVariable("days")int days, @PathVariable("canvasid")int canvasid){
return this.groupNotesService.findGroupNotesByDays(days, canvasid);
}
我正在开发一个 Spring-MVC 应用程序,我试图在其中搜索数据库中的 GroupNotes 列表。我项目中的映射是 GroupCanvas 与 GroupSection 一对多映射,GroupSection 与 GroupNotes 一对多映射。由于这些映射,我得到了 LazyInitializationException。正如 SO 所建议的那样,我应该将对象转换为 DTO 对象以进行传输。我在网上查过,但找不到合适的翻译方式。
我刚刚创建了一个新列表来避免这个错误,但是一个字段仍然给我一个错误。如果有人告诉我如何修复此错误或将对象转换为 DTO 对象以便传输它们,我将不胜感激。
控制器代码:
@RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public @ResponseBody List<GroupNotes> findGroupNotesByDays(@PathVariable("days")int days, @PathVariable("canvasid")int canvasid){
List<GroupNotes> groupNotesList = this.groupNotesService.findGroupNotesByDays(days,canvasid);
List<GroupNotes> toSendList = new ArrayList<>();
for(GroupNotes groupNotes : groupNotesList){
GroupNotes toSendNotes = new GroupNotes();
toSendNotes.setMnotecolor(groupNotes.getMnotecolor());
toSendNotes.setNoteCreationTime(groupNotes.getNoteCreationTime());
toSendNotes.setMnotetag(groupNotes.getMnotetag());
toSendNotes.setMnotetext(groupNotes.getMnotetext());
toSendNotes.setAttachCount(groupNotes.getAttachCount());
toSendNotes.setNoteDate(groupNotes.getNoteDate());
toSendList.add(toSendNotes);
}
return toSendList;
}
GroupNotesDAOImpl :
@Override
public List<GroupNotes> searchNotesByDays(int days, int mcanvasid) {
Session session = this.sessionFactory.getCurrentSession();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
GroupCanvas groupCanvas = (GroupCanvas) session.get(GroupCanvas.class,mcanvasid);
Query query = session.createQuery("from GroupSection as n where n.currentcanvas.mcanvasid=:mcanvasid");
query.setParameter("mcanvasid", mcanvasid);
List<GroupSection> sectionList = query.list();
List<GroupNotes> notesList = new ArrayList<GroupNotes>();
for (GroupSection e : sectionList) {
System.out.println("Section name is "+e.getMsectionname());
GroupSection groupSection = (GroupSection) session.get(GroupSection.class,e.getMsectionid());
Query query1 = session.createQuery("from GroupNotes as gn where gn.ownednotes.msectionid=:msectionid and gn.noteCreationTime >:limit");
query1.setParameter("limit", nowMinusDaysAsTimestamp);
query1.setParameter("msectionid",e.getMsectionid());
notesList.addAll(query1.list());
}
// I am getting the data below, but I get JSON errors.
for(GroupNotes groupNotes : notesList){
System.out.println("Group notes found are "+groupNotes.getMnotetext());
}
return notesList;
}
GroupCanvas 模型:
@Entity
@Table(name = "membercanvas")
public class GroupCanvas{
@OneToMany(mappedBy = "currentcanvas",fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupSection> ownedsection = new HashSet<>();
@JsonIgnore
public Set<GroupSection> getOwnedsection() {
return this.ownedsection;
}
public void setOwnedsection(Set<GroupSection> ownedsection) {
this.ownedsection = ownedsection;
}
}
GroupSection 模型:
@Entity
@Table(name = "membersection")
public class GroupSection{
@OneToMany(mappedBy = "ownednotes", fetch = FetchType.EAGER,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
public Set<GroupNotes> getSectionsnotes(){
return this.sectionsnotes;
}
public void setSectionsnotes(Set<GroupNotes> sectionsnotes){
this.sectionsnotes=sectionsnotes;
}
}
GroupNotes 型号:
@Entity
@Table(name="groupnotes")
public class GroupNotes{
@Id
@Column(name="mnoteid")
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "mnote_gen")
@SequenceGenerator(name = "mnote_gen",sequenceName = "mnote_seq")
@org.hibernate.annotations.Index(name = "mnoticesidindex")
private int mnoticesid;
@Column(name = "mnotetext")
private String mnotetext;
@Column(name = "mnoteheadline")
private String mnotetag;
@Column(name = "mnotecolor")
private String mnotecolor;
@Column(name = "mnoteorder")
private double mnoteorder;
@Column(name = "attachmentcount")
private int attachCount;
@Column(name = "notedate")
private String noteDate;
@Column(name = "uploader")
private String uploader;
@Column(name = "activeedit")
private boolean activeEdit;
@Column(name = "notedisabled")
private boolean noteDisabled;
@Column(name = "noteinactive")
private boolean noteInActive;
@Column(name = "notecreatoremail")
private String noteCreatorEmail;
@Column(name = "prefix")
private String prefix;
@Column(name = "timestamp")
private Timestamp noteCreationTime;
@Transient
private boolean notRead;
@Transient
private String tempNote;
@Transient
private String canvasUrl;
@ManyToOne
@JoinColumn(name = "msectionid")
@JsonIgnore
private GroupSection ownednotes;
@JsonIgnore
public GroupSection getOwnednotes(){return this.ownednotes;}
public void setOwnednotes(GroupSection ownednotes){this.ownednotes=ownednotes;}
@JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
@OneToMany(mappedBy = "mnotedata",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupAttachments> mattachments = new HashSet<>();
public Set<GroupAttachments> getMattachments() {
return this.mattachments;
}
public void setMattachments(Set<GroupAttachments> mattachments) {
this.mattachments = mattachments;
}
@OneToMany(mappedBy = "mhistory",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<GroupNoteHistory> groupNoteHistorySet = new HashSet<>();
public Set<GroupNoteHistory> getGroupNoteHistorySet(){
return this.groupNoteHistorySet;
}
public void setGroupNoteHistorySet(Set<GroupNoteHistory> groupNoteHistorySet){
this.groupNoteHistorySet = groupNoteHistorySet;
}
@OneToMany(mappedBy = "unreadNotes",fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JsonIgnore
private Set<UnreadNotes> unreadNotesSet = new HashSet<>();
public Set<UnreadNotes> getUnreadNotesSet(){
return this.unreadNotesSet;
}
public void setUnreadNotesSet(Set<UnreadNotes> unreadNotesSet){
this.unreadNotesSet = unreadNotesSet;
}
//getters and setters ignored
}
错误日志:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownedSectionId"])
请告诉我该怎么做,因为一段时间以来我一直被这个错误所困扰。
我认为 Jackson 试图根据 getter 方法序列化层次结构中的所有字段。在某些情况下 NullPointerException
会在以下方法中抛出:
@JsonIgnore
public int getOwnedSectionId(){
return this.ownednotes.getMsectionid();
}
替换成下面的方法:
@JsonIgnore
public int getOwnedSectionId(){
if(this.ownednotes != null)
return this.ownednotes.getMsectionid();
return 1;
}
我无法解释为什么 jackson 会尝试在 @JsonIgnore 上市时将其序列化,但您可以尝试我的建议
I would appreciate if anyone tells me either how to fix this error or convert the objects to a DTO objects so they can be transferred.
为此,我们在工作中使用 DozerMapper。
与其手动执行该映射,不如看看 Blaze-Persistence Entity Views,它可用于通过 JPA 有效地实现 DTO 模式。这里有一个快速代码示例如何解决您的问题
首先将 DTO 定义为实体视图
@EntityView(GroupNotes.class)
public interface GroupNoteView {
@IdMapping("mnoticesid") int getId();
String getMnotecolor();
String getMnotetag();
String getMnotetext();
String getNoteDate();
Timestamp getNoteCreationTime();
int getAttachCount();
}
接下来调整您的 DAO 以使用它
@Override
public List<GroupNoteView> searchNotesByDays(int days, int mcanvasid) {
EntityManager entityManager = // get the entity manager from somewhere
CriteriaBuilderFactory cbf = // factory for query building from Blaze-Persistence
EntityViewManager evm = // factory for applying entity views on query builders
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, -days);
long daysAgo = cal.getTimeInMillis();
Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
CriteriaBuilder<GroupNotes> cb = cbf.create(entityManager, GroupNotes.class, "note")
.where("noteCreationTime").gt(nowMinusDaysAsTimestamp)
.where("ownednotes.ownedcanvas.mcanvasid").eq(mcanvasid);
return evm.applySetting(EntityViewSetting.create(GroupNoteView.class), cb)
.getResultList();
}
最后是调用代码
@RequestMapping(value = "/findgroupnotes/{days}/{canvasid}")
public @ResponseBody List<GroupNoteView> findGroupNotesByDays(@PathVariable("days")int days, @PathVariable("canvasid")int canvasid){
return this.groupNotesService.findGroupNotesByDays(days, canvasid);
}