畢設問題(2) fastjson 的過濾器使用(SSH hibernate)以及轉換對象出現 $ref

  畢業設計,用SSH框架,可是想要作出異步請求數據的效果,使用了ajax方式,其中數據傳遞的類型爲json。ajax使用用的jQuery的ajax。其實struts裏也支持ajax功能,可是我以爲用太多struts的自帶標籤,想使用bootstrap的定義風格就很差了,頁面效果會打折扣,另外我的以爲如今的更普遍的是前端的寫前端的,儘可能不要前臺的也須要知道struts如何寫,以後重構也更麻煩。[補充,搜索過一個有個插包使在struts能夠用bootstrap,可是以爲可能支持的bootstrap的版本會低於當前]html

  言歸正傳,使用json的話須要使用工具,有java自帶的JSONArray、JSONObject,可是使用的時候回提示存在類沒法初始化,即指用到的類並不存在,須要引入其餘的jar包,後來網上去查了下,導入了一些包,可是仍是有問題,多是沒有徹底。以爲麻煩就放棄了用這個。因而找了fastjson,自稱是最快的,轉換速度比gson(google)的快6倍。目前的項目你只有到github上去下載最新的,網上的不少之前的文章給出的連接已經失效。github地址:https://github.com/alibaba/fastjson   說明一句文檔實在太過簡略。前端

  官方的常見問題:https://github.com/alibaba/fastjson/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98java

經常使用的方法是:git

public static final String toJSONString(Object object);
public static final <T> T parseObject(String text, Class<T> clazz, Feature... features);

其實參考官方的說明,更加清楚,有中文解釋,這裏說一下,官方沒有提到的問題。
1.過濾器的使用
  問題:
  對hibernate反向工程生成的類,如有引用其餘的表的主鍵作外鍵,就會產生一個那張表的反向工程的類,這樣咱們對經過查詢獲得的記錄,我是用Criteria方式查詢,返回一個list對象。咱們知道,hibernate查詢如果採用lazy延遲方式加載(eager方式循環引用,好像容易出問題),在session關閉,再想獲取未加載的數據時,會出現異常no session。不幸的是,直接使用fastjson轉化對象成爲json的時候就會查詢未加載的對象,從而產生異常。
  解決辦法:
  舉個例子咱們有一個專業培養計劃表,裏面又一個屬性叫專業id,hibernate會生成一個專業類和專業培養計劃類,培養計劃類中有個成員對象是專業類對象,事實上咱們並不須要專業類的其餘屬性,知道專業id便可,這是咱們可使用過濾器,使本身只對專業id進行序列化。這樣就不會引發hibernate異常。
  過濾的方式,我喜歡的方式有兩種,一種是配置簡單過濾器,另外一種是註解方式聲明不序列某屬性。各有優缺點,建議結合使用。
a.
配置簡單過濾器
   
List<Professioncultivationplan> list = professioncultivationplanDao
                    .query(professioncultivationplan);
// JSON過濾
SimplePropertyPreFilter filter = new SimplePropertyPreFilter(
            Profession.class, "id");
 //fastjosn的自帶簡單過濾器,容許配置只序列化那個屬性,這裏是序列化id,這樣對於在Professioncultivationplan裏的profession的其餘屬性就不會去序列化生成json字符串

result = JSON.toJSONString(list, filter,SerializerFeature.DisableCircularReferenceDetect);//注意SerializerFeature.DisableCircularReferenceDetect是標題的第二問題的解決方案

  b. 註解github

    private Integer id;
    @JSONField(serialize = false)
    private Profession profession;
    private String groupcourseCode;
    private String groupcourseCategory;
    private Float credit;
    @JSONField(serialize = false)
    private Set<Coursecultivationplan> coursecultivationplans = new HashSet<Coursecultivationplan>(
            0);
//這裏我對private Profession profession;private Set<Coursecultivationplan> coursecultivationplans...使用了不進行序列haunted的聲明,使用註解能夠不用反覆使用過濾,可是明顯咱們也沒法使用profession裏的id了,如果這個id沒有什麼用使用註解方式是能夠的,不然應該使用第一種方式,其中第一種方式只是簡單的配置過濾器,還有實現一個接口,本身寫一個過濾器,更加豐富是定製過濾方式,通常而言簡單過濾器就能夠解決了

2.轉換hibernate對象出現 $ref ajax

  使用fastjson,當進行toJSONString的時候,默認若是重用對象的話,會使用引用的方式進行引用對象。也就是指,hibernate爲咱們的profession對象是在java裏是同一個的話,序列化就會獲得一個引用。還有一種叫循環引用——咱們須要序列化的對象中存在循環引用,在許多的json庫中,這會致使stackoverflow——的狀況也會出現 $ref 。
  在個人畢業設計裏面並無出現循環引用(A包含B,B有包含A),可是我獲取一個專業培養計劃表的時候,如果有多條結果,從第二條開始就會出現profession的序列化並非第一個的記錄的同樣,而是引用第一個結果,因此傳遞到前端頁面循環顯示記錄的時候,從第二條開始,專業id那一列變成了undefined,或許有其餘的讀取這個一列的方式,可是我想生成一樣的結果,會比較方便和一致性,因此須要設置增長參數
SerializerFeature.DisableCircularReferenceDetect,禁止以引用方式引用對象。
一下是未設置的轉換出來的json結果:
[{"corediscipline":"計算機科學與技術change","dlsjCompulsoryratio":0,"dlsjCredit":35,"dlsjElectiveratio":0,"dlsjPeriod":0,"id":1,"profession":{"id":5},"tsjyCompulsoryratio":30.9,"tsjyCredit":69.5,"tsjyElectiveratio":10.8,"tsjyPeriod":1042,"zyjcCompulsoryratio":32.4,"zyjcCredit":63,"zyjcElectiveratio":5.4,"zyjcPeriod":945,"zykCompulsoryratio":9.6,"zykCredit":36,"zykElectiveratio":10.8,"zykPeriod":510},
{"corediscipline":"計算機科學與技術save","dlsjCompulsoryratio":0,"dlsjCredit":35,"dlsjElectiveratio":0,"dlsjPeriod":0,"id":8,"profession":{"$ref":"$[0].profession"},"tsjyCompulsoryratio":30.9,"tsjyCredit":69.5,"tsjyElectiveratio":10.8,"tsjyPeriod":1042,"zyjcCompulsoryratio":32.4,"zyjcCredit":63,"zyjcElectiveratio":5.4,"zyjcPeriod":945,"zykCompulsoryratio":9.6,"zykCredit":36,"zykElectiveratio":10.8,"zykPeriod":510}]

-------------------------------------------------------
更新時間:2016年5月6日16:18:32

內容:對過濾器的補充

在以前的fastjson的SimplePropertyPreFilter基礎之上,有的人編寫了一個比較好的過濾器,能夠過濾多個類及屬性條件。
做者出處: 晨風²º¹⁴ 2013年09月13日 於 愛Java 發表  http://aijava.cn/597.html

這裏貼一下所編寫的過濾器以及用法:
  1 import java.util.HashMap;
  2 import java.util.Map;
  3 
  4 import com.alibaba.fastjson.JSON;
  5 import com.alibaba.fastjson.serializer.JSONSerializer;
  6 import com.alibaba.fastjson.serializer.PropertyPreFilter;
  7 import com.alibaba.fastjson.serializer.SerializerFeature;
  8 
  9 public class ComplexPropertyPreFilter implements PropertyPreFilter {
 10 
 11     private Map<Class<?>, String[]> includes = new HashMap<>();
 12     private Map<Class<?>, String[]> excludes = new HashMap<>();
 13           
 14     public Map<Class<?>, String[]> getIncludes() {
 15         return includes;
 16     }
 17 
 18     public void setIncludes(Map<Class<?>, String[]> includes) {
 19         this.includes = includes;
 20     }
 21 
 22     public Map<Class<?>, String[]> getExcludes() {
 23         return excludes;
 24     }
 25 
 26     public void setExcludes(Map<Class<?>, String[]> excludes) {
 27         this.excludes = excludes;
 28     }
 29 
 30     static {
 31         JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
 32     }
 33           
 34     public ComplexPropertyPreFilter() {
 35               
 36     }
 37           
 38     public ComplexPropertyPreFilter(Map<Class<?>, String[]> includes) {
 39         super();
 40         this.includes = includes;
 41     }
 42     @Override
 43     public boolean apply(JSONSerializer serializer, Object source, String name) {
 44         // TODO Auto-generated method stub
 45         
 46         //對象爲空。直接放行
 47         if (source == null) {
 48             return true;
 49         }
 50      // 獲取當前須要序列化的對象的類對象
 51         Class<?> clazz = source.getClass();
 52      // 無需序列的對象、尋找須要過濾的對象,能夠提升查找層級
 53         // 找到不須要的序列化的類型
 54         for (Map.Entry<Class<?>, String[]> item : this.excludes.entrySet()) {
 55             // isAssignableFrom(),用來判斷類型間是否有繼承關係
 56             if (item.getKey().isAssignableFrom(clazz)) {
 57                 String[] strs = item.getValue();
 58                       
 59                 // 該類型下 此 name 值無需序列化
 60                 if (isHave(strs, name)) {
 61                     return false;
 62                 }
 63             }
 64         }
 65               
 66         // 須要序列的對象集合爲空 表示 所有須要序列化
 67         if (this.includes.isEmpty()) {
 68             return true;
 69         }
 70               
 71         // 須要序列的對象
 72         // 找到不須要的序列化的類型  改正:找到須要序列化的類型
 73         for (Map.Entry<Class<?>, String[]> item : this.includes.entrySet()) {
 74             // isAssignableFrom(),用來判斷類型間是否有繼承關係
 75             if (item.getKey().isAssignableFrom(clazz)) {
 76                 String[] strs = item.getValue();
 77                 // 該類型下 此 name 值無需序列化  改正:須要序列化
 78                 if (isHave(strs, name)) {
 79                     return true;
 80                 }
 81             }
 82         }
 83         
 84         
 85         
 86         return false;
 87     }
 88 
 89     /*
 90      * 此方法有兩個參數,第一個是要查找的字符串數組,第二個是要查找的字符或字符串
 91      */
 92     public static boolean isHave(String[] strs, String s) {
 93               
 94         for (int i = 0; i < strs.length; i++) {
 95             // 循環查找字符串數組中的每一個字符串中是否包含全部查找的內容
 96             if (strs[i].equals(s)) {
 97                 // 查找到了就返回真,不在繼續查詢
 98                 return true;
 99             }
100         }
101               
102         // 沒找到返回false
103         return false;
104     }
105     
106     
107     
108 }
 

上面是原做者的過濾器,原文章裏對使用,測試不夠詳細,這裏介紹兩種用法:redis

            List<SubgradCourseRelation> list = subgradCourseRelationDao
                    .query(subgradCourseRelation);
            // 有兩個類須要設置過濾course與Subgraduationrequirement
            ComplexPropertyPreFilter filter2 = new ComplexPropertyPreFilter();
            //設置不須要序列化的類及其屬性
            // filter2.setExcludes(new HashMap<Class<?>, String[]>() {
            // {
            // put(Course.class, new String[] { "coursename",
            // "totalcredit", "totalperiod", "lecture",
            // "experiment", "oncomputer", "extracurricular",
            // "evaluationmethod","coursetype" });
            // put(Subgraduationrequirement.class, new String[] {
            // "graduationrequirement", "sgrCode", "sgrContent" });
            // }
            // });
            //設置想要序列化的類及其屬性
            filter2.setIncludes(new HashMap<Class<?>, String[]>() {
                {
                    put(SubgradCourseRelation.class, new String[] { "id",
                            "weight", "arrivedFirst", "arrivedSecond",
                            "arrivedThrid", "coursefeedback", "course",
                            "subgraduationrequirement" });
                    put(Course.class, new String[] { "id" });
                    put(Subgraduationrequirement.class, new String[] { "id" });
                }
            });
            /* 設置ex和includes序列化的結果都是:
             [{"arrivedFirst":0,"arrivedSecond":0,"arrivedThrid":0,"course":{"id":1},"coursefeedback":0,"id":1,"subgraduationrequirement":{"id":1},"weight":15},
             {"arrivedFirst":0,"arrivedSecond":0,"arrivedThrid":0,"course":{"id":10},"coursefeedback":0,"id":2,"subgraduationrequirement":{"id":1},"weight":15},
             {"arrivedFirst":40,"arrivedSecond":0,"arrivedThrid":0,"course":{"id":11},"coursefeedback":0,"id":3,"subgraduationrequirement":{"id":1},"weight":15},
             {"arrivedFirst":0,"arrivedSecond":0,"arrivedThrid":0,"course":{"id":85},"coursefeedback":0,"id":4,"subgraduationrequirement":{"id":1},"weight":15},
             {"arrivedFirst":0,"arrivedSecond":0,"arrivedThrid":0,"course":{"id":22},"coursefeedback":0,"id":5,"subgraduationrequirement":{"id":1},"weight":20},
             {"arrivedFirst":0,"course":{"id":30},"coursefeedback":0,"id":6,"subgraduationrequirement":{"id":1},"weight":20}] //這裏存在某些值爲null,因此缺項並未序列化
             * */

            result = JSON.toJSONString(list, filter2,
                    SerializerFeature.DisableCircularReferenceDetect);
相關文章
相關標籤/搜索