畢業設計,用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);