日常项目中经常有这样的需求,即需要几个紧密相关的内容存储起来,例如,xxx省xxx市xxx区等等。
例如下图:
这些紧密相关的内容可能会经常增加或者减少某项内容,在数据库应用中,当然可以设计几个字段来存储或者设计一个专门的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、如果要对其中的内容进行条件检索,只有进行文本匹配,如果有这种需求,这种方式不推荐。