1. 程式人生 > >Json序列化,有多對一和多對多關系時出現的問題

Json序列化,有多對一和多對多關系時出現的問題

oca lan util 一對一 屬性。 sans 雙向 rate stat

/**  
     * 這是一張  單表中的雙向一對多,多對一 關系。自己跟自己一對多多對一
*/  
@Entity
@Table(name="tb_test")
public class CreditsEventBean implements Serializable{
    private static final long serialVersionUID = 1L;
     
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id; //序號
    
    
    /**
* 上級分類 */ @ManyToOne @JoinColumn(name = "pid") private CreditsEventBean pid; /** * 下級分類 */ @OneToMany(mappedBy="pid") private List<CreditsEventBean> creditsEventBean;

※ 上面的實體被使用時會出現死循環的問題 如圖:

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
    at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:
478) ~[tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.sendServerError(DefaultHandlerExceptionResolver.java:488) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMessageNotWritable(DefaultHandlerExceptionResolver.java:
402) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException(DefaultHandlerExceptionResolver.java:146) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:137) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.handler.HandlerExceptionResolverComposite.resolveException(HandlerExceptionResolverComposite.java:74) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1182) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1020) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-embed-websocket-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.jasig.cas.client.util.AssertionThreadLocalFilter.doFilter(AssertionThreadLocalFilter.java:50) [cas-client-core-3.3.3.jar:3.3.3] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.jasig.cas.client.util.HttpServletRequestWrapperFilter.doFilter(HttpServletRequestWrapperFilter.java:70) [cas-client-core-3.3.3.jar:3.3.3] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:238) [cas-client-core-3.3.3.jar:3.3.3] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:152) [cas-client-core-3.3.3.jar:3.3.3] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) [tomcat-embed-core-8.0.30.jar:8.0.30] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) [tomcat-embed-core-8.0.30.jar:8.0.30] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.30.jar:8.0.30] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]

解決方法:

@Entity
@Table(name="tb_test")
public class CreditsEventBean implements Serializable{
    private static final long serialVersionUID = 1L;
     
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id; //序號
    


/**
@JsonBackReference和@JsonManagedReference:這兩個標註通常配對使用,通常用在父子關系中。
*/


    /**  
     * 上級分類  
     */ 
    @JsonBackReference //標註的屬性在序列化(serialization,即將對象轉換為json數據)時,會被忽略(即結果中的json數據不包含該屬性的內容)
    @ManyToOne
        @JoinColumn(name = "pid")
        private CreditsEventBean pid;    
        
    /**  
     * 下級分類  
     */  
        @JsonManagedReference//標註的屬性則會被序列化。
    @OneToMany(mappedBy="pid") 
    private List<CreditsEventBean>  creditsEventBean;    

如果想不忽略 pid字段 (註意:被忽略的字段前端是拿不到值的)則:

@Entity
@Table(name="tb_test")
public class CreditsEventBean implements Serializable{
    private static final long serialVersionUID = 1L;
     
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id; //序號
   


    /**  
     * 上級分類  
     */ 
    @ManyToOne
        @JoinColumn(name = "pid")
        private CreditsEventBean pid;    
        
    /**  
     * 下級分類  
     */  

    @OneToMany(mappedBy="pid") 
    @JsonIgnoreProperties("pid") //指定字段不會被序列化
    private List<CreditsEventBean>  creditsEventBean; 

除此之外還可以:
@JsonIgnore:直接忽略某個屬性,以斷開無限遞歸,序列化或反序列化均忽略。當然如果標註在get、set方法中,則可以分開控制,序列化對應的是get方法,反序列化對應的是set方法。

@JsonIgnore跟@JsonBackReference和@JsonManagedReference最大的區別:在父子關系中,當反序列化時,@JsonIgnore不會自動註入被忽略的屬性值(父或子)

後記:在序列化時,@JsonBackReference的作用相當於@JsonIgnore,此時可以沒有@JsonManagedReference。但在反序列化(deserialization,即json數據轉換為對象)時,如果沒有@JsonManagedReference,則不會自動註入@JsonBackReference標註的屬性(被忽略的父或子);如果有@JsonManagedReference,則會自動註入自動註入@JsonBackReference標註的屬性。

@Entity
@Table(name="tb_credits_event")
public class CreditsEventBean implements Serializable{
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id; //序號
private String imagePath;//圖片路徑
private String title; //標題
private String content; //內容
private String eventRule; //活動規則
private Integer credit; //積分值
private Integer creditStatus;//事件類型 0消費,1獲取
private Integer activityShop;//屬於活動的商品 0:常規商品 1:活動商品
private Integer isShopEvent; //是商品兌換還是活動兌換 0商品兌換 1活動兌換
private String activityStartCreditsDT;//開始時間
private String activityEndCreditsDT;//結束時間
private String userName; //創建者
private String creteateTime;//創建時間 (活動發布時間)
private String cutOffTime;//活動報名截止日期
private String address;//兌換(參與)地址
private Integer maxPlayers; //活動限制人數
private Integer remaining; //剩余人數
private Integer sort = 1;//排序 -- 用於內容展示時 過期內容的下沈(默認為1)
@OneToOne
@JoinColumn(name="role_id")//與權限表一對一
private CreditsRoleBean roleBean;//活動有權限設置


/**
* 上級分類
*/
// @JsonBackReference
@ManyToOne
@JoinColumn(name = "pid")
private CreditsEventBean pid;

/**
* 下級分類
*/
// @JsonManagedReference
@OneToMany(mappedBy="pid")
// @JsonIgnoreProperties("pid") //指定字段不會被序列化
private List<CreditsEventBean> creditsEventBean;//活動跟商品之間關聯

Json序列化,有多對一和多對多關系時出現的問題