日常项目中经常有这样的需求,即需要几个紧密相关的内容存储起来,例如,xxx省xxx市xxx区等等。

 

例如下图:

  

Json还可以这样用_json

 

这些紧密相关的内容可能会经常增加或者减少某项内容,在数据库应用中,当然可以设计几个字段来存储或者设计一个专门的key-value表来存储这些可变内容,但是对于这类不会直接用条件进行检索的紧密关联的内容来讲,保存在一个字段traffic_description中似乎更为妥帖一点。既然要存储在一个字段中那么就涉及到如何分割和组装的问题。

 

  一个比较直接的做法就是使用分号对每项值进行分割存储,这种方式属于一种平面的结构,还有一个更好的办法就是将这些字段组装成一个json 字符串,格式如{'key1':value1,'key2':['value2','value21']},这样就可以直接利用现成的对象存储方式来保存,当前就有很多第三方包对json提供了支持,如:java中提供了json-lib.jar,其他语言支持包见 www.json.org

 

   下面提供一种简单的实现:

  

1. import java.lang.annotation.ElementType;  
2. import java.lang.annotation.Retention;  
3. import java.lang.annotation.RetentionPolicy;  
4. import java.lang.annotation.Target;  
5. import java.lang.reflect.Field;  
6. import java.util.Collection;  
7. import java.util.HashMap;  
8. import java.util.Iterator;  
9. import java.util.Map;  
10. import java.util.Set;  
11. import net.sf.json.JSONArray;  
12. import net.sf.json.JSONObject;  
13. import org.apache.commons.beanutils.BeanUtils;  
14. import org.apache.commons.beanutils.PropertyUtils;  
15. import org.apache.commons.lang.builder.ToStringBuilder;  
16. import com.alibaba.common.logging.Logger;  
17. import com.alibaba.common.logging.LoggerFactory;  
18. /**
19.  *
20.  * <p>
21.  * json 字符串生成和解析base类
22.  * </p>
23.  *
24.  * @author <a href="mailto:qingxu@taobao.com" mce_href="mailto:qingxu@taobao.com">清虚</a>
25.  * @since 2.0 2009-10-19上午10:42:57
26.  *
27.  */  
28. public class JsonDO {  
29. private static final Logger log = LoggerFactory.getLogger("JsonDO");  
30. /**
31.      * json 属性标注 ,表示该属性需要放入json对象
32.      */  
33. @Retention(RetentionPolicy.RUNTIME)  
34. @Target(ElementType.FIELD)  
35. public @interface JsonField {  
36.     }  
37. private String value;// json字符串,一般存储在数据库中  
38. /**
39.      * 调用该方法会设置value属性,该方法一般在保存数据库时调用
40.      *
41.      * @return the value
42.      */  
43. public String getValue() {  
44.         encode();  
45. return value;  
46.     }  
47. /**
48.      * 调用该方法会解析value字符串,并设置相应的java 属性,该方法一般在从数据库中load时调用
49.      *
50.      * @param value
51.      *            the value to set
52.      */  
53. public void setValue(String value) {  
54. this.value = value;  
55.         decode();  
56.     }  
57. /**
58.      *
59.      *
60.      * <p>
61.      * 将value json中的属性值设置到对应的java DO属性中去,java 属性必须有JsonField 标注才会被设置
62.      * </p>
63.      *
64.      * @author <a href="mailto:qingxu@taobao.com" mce_href="mailto:qingxu@taobao.com">清虚</a>
65.      * @since 2.0 2009-10-19下午02:39:56
66.      *
67.      */  
68. @SuppressWarnings("unchecked")  
69. protected void decode() {  
70. if (this.value == null || this.value.trim().equals("")) {  
71. return;  
72.         }  
73. new HashMap<String, Class>();  
74.         Field[] fs = getClass().getDeclaredFields();  
75. for (Field f : fs) {  
76. if (f.isAnnotationPresent(JsonField.class)) {  
77.                 classMap.put(f.getName(), f.getClass());  
78.             }  
79.         }  
80. if (classMap.isEmpty()) {  
81. return;  
82.         }  
83. this.value);  
84.         JsonDO o = (JsonDO) JSONObject.toBean(json, getClass(), classMap);  
85.         Set<String> set = classMap.keySet();  
86.         Iterator<String> it = set.iterator();  
87. while (it.hasNext()) {  
88.             String name = it.next();  
89. try {  
90.                 Object value = PropertyUtils.getSimpleProperty(o, name);  
91. this, name, value);  
92. catch (Exception e) {  
93. "copy prorperty error src=" + this.value, e);  
94.             }  
95.         }  
96.     }  
97. /**
98.      *
99.      *
100.      * <p>
101.      * 将JsonField 标注了的基本属性组装成json字符串保存在value中
102.      * </p>
103.      *
104.      * @author <a href="mailto:qingxu@taobao.com" mce_href="mailto:qingxu@taobao.com">清虚</a>
105.      * @since 2.0 2009-10-19下午02:41:27
106.      *
107.      */  
108. @SuppressWarnings("unchecked")  
109. protected void encode() {  
110. new JSONObject();  
111.         Field[] fs = getClass().getDeclaredFields();  
112. for (Field f : fs) {  
113. if (f.isAnnotationPresent(JsonField.class)) {  
114.                 String name = f.getName();  
115. null;  
116. try {  
117. this, name);  
118. //value = f.get(this);  
119. catch (Exception e) {  
120. "get field value failed! fieldName=" + name, e);  
121.                 }  
122. if (value == null) {  
123. continue;  
124.                 }  
125.                 Class type = f.getType();  
126. if (Collection.class.isAssignableFrom(type)) {  
127.                     Collection it = (Collection) value;  
128. for (Object v : it) {  
129.                         json.accumulate(name, v);  
130.                     }  
131. else if (type.isArray()) {  
132.                     json.put(name, JSONArray.fromObject(value));  
133. else {  
134.                     json.put(name, value);  
135.                 }  
136.             }  
137.         }  
138. this.value=json.toString();  
139. //setValue(json.toString());  
140.     }  
141. /*
142.      * (non-Javadoc)
143.      *
144.      * @see java.lang.Object#toString()
145.      */  
146. @Override  
147. public String toString() {  
148. return ToStringBuilder.reflectionToString(this);  
149.     }

 

使用方式如下:

 


1. public class TrafficDO extends JsonDO {  
2. /**
3.      *序列号
4.      */  
5. private static final long serialVersionUID = -5673233152393642499L;  
6. @JsonField  
7. private String invoiceTitle;                            //发票抬头  
8. @JsonField  
9. private String fullName;                                //配送人姓名  
10. @JsonField  
11. private String mobileTel;                               //配送手机号码  
12. @JsonField  
13. private String province;                                //省  
14. @JsonField  
15. private String city;                                    //市  
16. @JsonField  
17. private String section;                                 //区  
18. @JsonField  
19. private String address;                                 //详细地址  
20. @JsonField  
21. private String post;                                    //邮编  
22. private int shipmentType;                               //配送方式  
23. public static final int BY_MAIL_TYPE = 0;               //挂号信邮寄方式  
24. public static final int BY_NOTNEED = -1;                //不需要行程单  
25.   
26.   
27. /**
28.      * @return the shipmentType
29.      */  
30. public int getShipmentType() {  
31. return shipmentType;  
32.     }  
33. /**
34.      * @param shipmentType the shipmentType to set
35.      */  
36. public void setShipmentType(int shipmentType) {  
37. this.shipmentType = shipmentType;  
38.     }  
39. /**
40.      * @return the fullName
41.      */  
42. public String getFullName() {  
43. return fullName;  
44.     }  
45. /**
46.      * @param fullName the fullName to set
47.      */  
48. public void setFullName(String fullName) {  
49. this.fullName = fullName;  
50.     }  
51. /**
52.      * @return the mobile
53.      */  
54. public String getMobileTel() {  
55. return mobileTel;  
56.     }  
57. /**
58.      * @param mobile the mobile to set
59.      */  
60. public void setMobileTel(String mobile) {  
61. this.mobileTel = mobile;  
62.     }  
63. /**
64.      * @return the province
65.      */  
66. public String getProvince() {  
67. return province;  
68.     }  
69. /**
70.      * @param province the province to set
71.      */  
72. public void setProvince(String province) {  
73. this.province = province;  
74.     }  
75. /**
76.      * @return the city
77.      */  
78. public String getCity() {  
79. return city;  
80.     }  
81. /**
82.      * @param city the city to set
83.      */  
84. public void setCity(String city) {  
85. this.city = city;  
86.     }  
87. /**
88.      * @return the section
89.      */  
90. public String getSection() {  
91. return section;  
92.     }  
93. /**
94.      * @param section the section to set
95.      */  
96. public void setSection(String section) {  
97. this.section = section;  
98.     }  
99. /**
100.      * @return the address
101.      */  
102. public String getAddress() {  
103. return address;  
104.     }  
105. /**
106.      * @param address the address to set
107.      */  
108. public void setAddress(String address) {  
109. this.address = address;  
110.     }  
111. /**
112.      * @return the post
113.      */  
114. public String getPost() {  
115. return post;  
116.     }  
117. /**
118.      * @param post the post to set
119.      */  
120. public void setPost(String post) {  
121. this.post = post;  
122.     }  
123. /**
124.      * 邮寄
125.      *
126.      * @return
127.      */  
128. public boolean isMail() {  
129. return this.shipmentType == BY_MAIL_TYPE;  
130.     }  
131. /**
132.      * 不需要
133.      *
134.      * @author qingxu
135.      * @since 2007-10-25下午04:48:12
136.      *
137.      * @return
138.      */  
139. public boolean isNotNeed() {  
140. return this.shipmentType == BY_NOTNEED;  
141.     }  
142. public String getInvoiceTitle() {  
143. return invoiceTitle;  
144.     }  
145. public void setInvoiceTitle(String invoiceTitle) {  
146. this.invoiceTitle = invoiceTitle;  
147.     }  
148. }


 

@JsonField标注支持 基本类型和数组、collection类型域。

 

 

在从DB中load出traffic_description的值后

通过setValue()方法设置进去,那么所有的json域都会被填充好。同样的,如果填充了相应的json域,

在存储在数据库中时,可以调用getValue()得到字符串持久化到数据库中。

 

   通过getValue()得到的字符串形式如下:

 

1. {"section":"马龙县","fullName":"叮当","address":"vvvvvv","province":"云南省","invoiceTitle":"vvvvvv","mobileTel":"136**622627","post":"310014","city":"曲靖市"}


 

    这种处理方式的好处是,可以方便的定义你自己要存储的内容,你所有做的仅仅是在新增一个field,然后在上面打上@JsonField标注即可。

    而它的缺点也是明显的,1、这种方式明显增加了存储内容的长度 2、由于存储的key是属性的名称,如果名称不匹配也会找不到对应的值。3、如果要对其中的内容进行条件检索,只有进行文本匹配,如果有这种需求,这种方式不推荐。