导航

数据库访问(Java 反射) + Json(数据对象)

Posted on 2014-12-31 17:03  MatchBoxy  阅读(321)  评论(0)    收藏  举报

一、Java 反射机制

二、利用反射实现数据库操作

三、数据对象与json的转换

 

一、Java 反射机制

JAVA反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

 

二、利用反射实现数据库操作

数据库操作,反射的好处:

(1) dao 层只需要编写一次基础数据库类操作代码(比如,增删改查等等),就可以充分利用继承关系实现不同模型的数据库操作。

(2) 修改数据库的表字段基本上不用大的修改 dao 层的代码(比如 sql 语句等等)

本例工程的目录组织结构大致如下:

也可以将 LTBeanMapConverter.java 放到 dao.common 包中。

1、本实例使用 mysql 数据库。基础配置文件,请参考上一篇文章《MySQL + Tomcat 工程》 http://www.cnblogs.com/matchboxy/articles/4113834.html

2、编写 model 类,本例中为 LTNews.java 类。

  1 package com.matchbox.model.news;
  2 
  3 import java.io.Serializable;
  4 
  5 import javax.persistence.Column;
  6 import javax.persistence.GeneratedValue;
  7 import javax.persistence.GenerationType;
  8 import javax.persistence.Id;
  9 import javax.persistence.Table;
 10 
 11 
 12 /**
 13  * @author MATCH
 14  * @date 14-12-29
 15  */
 16 
 17 
 18 @Table(name="news")
 19 public class LTNews implements Serializable 
 20 {
 21     private long id;
 22     private long time;
 23     private String url;
 24     private String imgUrl;
 25     private String type;
 26     private String title;
 27     private String author;
 28     private String source;
 29     private String outline;
 30     private int language;
 31     private int favourite;
 32     private int comment;
 33     private int click;
 34     
 35     @Column(name="id")
 36     @Id
 37     @GeneratedValue(strategy = GenerationType.IDENTITY)
 38     public long getId() {
 39         return id;
 40     }
 41 
 42     public void setId(long id) {
 43         this.id = id;
 44     }
 45 
 46     @Column(name="time")
 47     public long getTime() {
 48         return time;
 49     }
 50 
 51     public void setTime(long time) {
 52         this.time = time;
 53     }
 54 
 55     @Column(name="url")
 56     public String getUrl() {
 57         return url;
 58     }
 59 
 60     public void setUrl(String url) {
 61         this.url = url;
 62     }
 63 
 64     @Column(name="imgUrl")
 65     public String getImgUrl() {
 66         return imgUrl;
 67     }
 68 
 69     public void setImgUrl(String imgUrl) {
 70         this.imgUrl = imgUrl;
 71     }
 72 
 73     @Column(name="type")
 74     public String getType() {
 75         return type;
 76     }
 77 
 78     public void setType(String type) {
 79         this.type = type;
 80     }
 81 
 82     @Column(name="title")
 83     public String getTitle() {
 84         return title;
 85     }
 86 
 87     public void setTitle(String title) {
 88         this.title = title;
 89     }
 90 
 91     @Column(name="author")
 92     public String getAuthor() {
 93         return author;
 94     }
 95 
 96     public void setAuthor(String author) {
 97         this.author = author;
 98     }
 99 
100     @Column(name="source")
101     public String getSource() {
102         return source;
103     }
104 
105     public void setSource(String source) {
106         this.source = source;
107     }
108 
109     @Column(name="outline")
110     public String getOutline() {
111         return outline;
112     }
113 
114     public void setOutline(String outline) {
115         this.outline = outline;
116     }
117 
118     @Column(name="language")
119     public int getLanguage() {
120         return language;
121     }
122 
123     public void setLanguage(int language) {
124         this.language = language;
125     }
126 
127     @Column(name="favourite")
128     public int getFavourite() {
129         return favourite;
130     }
131 
132     public void setFavourite(int favourite) {
133         this.favourite = favourite;
134     }
135 
136     @Column(name="comment")
137     public int getComment() {
138         return comment;
139     }
140 
141     public void setComment(int comment) {
142         this.comment = comment;
143     }
144 
145     @Column(name="click")
146     public int getClick() {
147         return click;
148     }
149 
150     public void setClick(int click) {
151         this.click = click;
152     }
153 }
LTNews.java

其中:@Table(name="news") 为 news 数据库表。

@Column(name="id")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

为表中列名为 id 的列为主键,自增长类型。每一个 @Column(name="***") 写在 get 方法前面,对应数据表中的列名到相应的属性,一般来讲属性名最好与列名一致。

3、编写基础接口类 dao.common.LTGenericDao.java ,主要声明一些要实现的数据库操作。

 1 package com.matchbox.dao.common;
 2 
 3 import java.io.Serializable;
 4 import java.util.List;
 5 import java.util.Map;
 6 
 7 
 8 /**
 9  * @author MATCH
10  * @date 14-12-30 
11  */
12 
13 
14 public interface LTGenericDao <T, ID extends Serializable>
15 {
16     public String getTableName();
17     public String getPk();
18     public List<T> getAll();
19     public long getCount();
20     
21     public ID insert(T object); 
22     public List<ID> insertBatch(List<T> listObject);
23     
24     public int delete(ID id);
25     public int deleteBatch(List<ID> listIds);
26     
27     public int update(T object);
28     
29     public T select(ID id);
30     public List<T> selectByIds(List<ID> ids); 
31     public List<T> selectByMap(Map<String, Object> map);
32 }
LTGenericDao.java

这里需要运用模板的知识,其中: T 为模型类的 class , ID 为模型类对应的表的主键类型。

4、编写基础实现类 dao.common.impl.LTGenericDaoImpl.java ,提供接口类的基础实现。

  1 package com.matchbox.dao.common.impl;
  2 
  3 import java.beans.BeanInfo;
  4 import java.beans.IntrospectionException;
  5 import java.beans.Introspector;
  6 import java.beans.PropertyDescriptor;
  7 import java.io.Serializable;
  8 import java.sql.Connection;
  9 import java.sql.PreparedStatement;
 10 import java.sql.SQLException;
 11 import java.sql.Statement;
 12 import java.sql.Types;
 13 import java.util.ArrayList;
 14 import java.util.Arrays;
 15 import java.util.Date;
 16 import java.util.HashMap;
 17 import java.util.List;
 18 import java.util.Map;
 19 
 20 import javax.persistence.Column;
 21 import javax.persistence.GeneratedValue;
 22 import javax.persistence.GenerationType;
 23 import javax.persistence.Id;
 24 import javax.persistence.Table;
 25 import javax.persistence.Transient;
 26 
 27 import org.apache.commons.beanutils.BeanUtils;
 28 import org.apache.commons.lang.StringUtils;
 29 import org.springframework.core.annotation.AnnotationUtils;
 30 import org.springframework.jdbc.core.JdbcTemplate;
 31 import org.springframework.jdbc.core.PreparedStatementCreator;
 32 import org.springframework.jdbc.core.support.JdbcDaoSupport;
 33 import org.springframework.jdbc.support.GeneratedKeyHolder;
 34 import org.springframework.jdbc.support.KeyHolder;
 35 
 36 import com.matchbox.dao.common.LTGenericDao;
 37 import com.matchbox.dao.common.LTModelPropertyRowMapper;
 38 import com.matchbox.utility.LTBeanMapConverter;
 39 
 40 
 41 /**
 42  * @author MATCH
 43  * @date 14-12-30
 44  */
 45 
 46 
 47 public abstract class LTGenericDaoImpl<T, ID extends Serializable>
 48         extends JdbcDaoSupport implements LTGenericDao<T, ID> 
 49 {
 50     private Class<T> persistentClass;
 51     private String tableName = "";
 52     private String pk = "";
 53     private GenerationType strategy;
 54     private Map<String, String> property2ColumnMap = new HashMap<String, String>();
 55     private Map<String, String> column2PropertyMap = new HashMap<String, String>();
 56     protected List<String> transientPropertys = new ArrayList<String>();
 57     
 58     protected LTGenericDaoImpl(Class<T> tClass)
 59     {
 60         this.persistentClass = tClass;
 61 
 62         Table table = AnnotationUtils.findAnnotation(tClass, Table.class);
 63         if(null == table)
 64         {
 65             //throw new DaoException(persistentClass.getName() + "没有定义@table");
 66         }
 67         
 68         this.tableName = (table==null) ? tClass.getName() : table.name();
 69         
 70         BeanInfo beanInfo = null;
 71         try
 72         {
 73             beanInfo = Introspector.getBeanInfo(persistentClass);
 74         }
 75         catch (IntrospectionException e) 
 76         {
 77             //throw new DaoException(e);
 78         }
 79         
 80         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
 81         for(PropertyDescriptor pd : pds)
 82         {
 83             Id id = AnnotationUtils.findAnnotation(pd.getReadMethod(), Id.class);
 84             if(null != id)
 85             {
 86                 Column idColumn = AnnotationUtils.findAnnotation(pd.getReadMethod(), Column.class);
 87                 this.pk = (idColumn == null) ? pd.getName() : idColumn.name();
 88                 
 89                 GeneratedValue gv = AnnotationUtils.findAnnotation(pd.getReadMethod(), GeneratedValue.class);
 90                 this.strategy = (gv == null) ? GenerationType.IDENTITY : gv.strategy();
 91             }
 92             
 93             Column column = AnnotationUtils.findAnnotation(pd.getReadMethod(), Column.class);
 94             property2ColumnMap.put(pd.getName(), (column == null) ? pd.getName() : column.name());
 95             column2PropertyMap.put((column == null) ? pd.getName() : column.name(), pd.getName());
 96             
 97             Transient transient_ = AnnotationUtils.findAnnotation(pd.getReadMethod(), Transient.class);
 98             if (null != transient_) 
 99             {
100                 transientPropertys.add(pd.getName());
101             }
102         }
103         
104         if ("".equals(this.getPk())) 
105         {
106             //throw new DaoException(persistentClass.getName() + "中没有在get方法上定义@Id");
107         }
108     }
109     
110     
111     @Override
112     public String getTableName()
113     {
114         return this.tableName;
115     }
116     
117     @Override
118     public String getPk()
119     {
120         return this.pk;
121     }
122     
123     @Override
124     public List<T> getAll()
125     {
126         return null;
127     }
128     
129     @Override
130     public long getCount()
131     {
132         StringBuilder sb = new StringBuilder("select count(*) from ");
133         sb.append(this.getTableName());
134         return this.getJdbcTemplate().queryForObject(sb.toString(), Long.class);
135     }
136     
137     /**
138      * 插入一条数据
139      */
140     @Override
141     public ID insert(T object)
142     {
143         if (null == object) 
144         {
145             //throw new DaoException("模型对象为空!保存失败");
146         }
147         
148         Map<String, Object> map = toModelMap(object);
149         for(String proterty : transientPropertys) 
150         {
151             map.remove(proterty);
152         }
153         
154         ID id = this.insertReturnIdByMap(map);
155         if(strategy.equals(GenerationType.IDENTITY)) 
156         {
157             try 
158             {
159                 BeanUtils.setProperty(object, column2PropertyMap.get(pk), id);
160             } 
161             catch(Exception e) 
162             {
163                 //log.error(persistentClass.getName() + "解析异常!", e);
164             }
165         }
166         return id;
167     }
168     
169     /**
170      * 根据列名与对应的属性值,添加一条记录。
171      * 返回添加的主键id
172      */
173     @SuppressWarnings("unchecked")
174     protected ID insertReturnIdByMap(Map<String, Object> map) 
175     {
176         if (map == null || map.size() == 0)
177             return null;
178         
179         if (this.strategy.equals(GenerationType.IDENTITY)) 
180         {
181             map.remove(this.getPk());
182         }
183         
184         StringBuilder sb = new StringBuilder("insert into ");
185         sb.append(this.getTableName());
186         
187         List<String> columns = new ArrayList<String>();
188         List<Object> values = new ArrayList<Object>();
189         
190         for (Map.Entry<String, Object> e : map.entrySet()) 
191         {
192             columns.add(e.getKey());
193             values.add(e.getValue());
194         }
195         
196         sb.append("(`");
197         sb.append(StringUtils.join(columns, "`,`"));
198         sb.append("`) values(");
199         String[] paras = new String[values.size()];
200         Arrays.fill(paras, "?");
201         sb.append(StringUtils.join(paras, ','));
202         sb.append(")");
203         
204         if(this.strategy.equals(GenerationType.IDENTITY)) //主键自增长
205         {
206             ID id = this.insertBySqlValuesIdentity(sb.toString(), values);
207             return (ID) id;
208         } 
209         else if(this.strategy.equals(GenerationType.AUTO)) //主键由程序控制
210         {
211             int count = this.insertBySqlValuesAuto(sb.toString(), values);
212             if(count != 0) 
213             {
214                 return (ID) map.get(this.getPk());
215             } 
216             else 
217             {
218                 return null;
219             }
220         }
221         return null;
222     }
223     
224     /**
225      * 根据sql和相关列值,插入一条记录。
226      * 主键自增长
227      * 返回主键值
228      */
229     @SuppressWarnings("unchecked")
230     //@Override
231     public ID insertBySqlValuesIdentity(final String sql, final List<Object> values) 
232     {
233         JdbcTemplate template = this.getJdbcTemplate();
234         KeyHolder keyHolder = new GeneratedKeyHolder();
235 
236         template.update(new PreparedStatementCreator() 
237         {
238             public PreparedStatement createPreparedStatement(Connection con) throws SQLException 
239             {
240                 int i = 0;
241                 PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
242                 for (i = 0; i < values.size(); i++) 
243                 {
244                     Object value = values.get(i);
245                     if (value != null) 
246                     {
247                         if (value instanceof Integer) {
248                             ps.setInt(i + 1, (Integer) value);
249                         } else if (value instanceof Long) {
250                             ps.setLong(i + 1, (Long) value);
251                         } else if (value instanceof Date) {
252                             ps.setDate(i + 1, new java.sql.Date(((Date) value).getTime()));
253                             ps.setTimestamp(i + 1, new java.sql.Timestamp(((Date) value).getTime()));
254                         } else if (value instanceof String) {
255                             ps.setString(i + 1, value.toString());
256                         } else if (value instanceof Double) {
257                             ps.setDouble(i + 1, (Double) value);
258                         } else if (value instanceof Byte) {
259                             ps.setByte(i + 1, (Byte) value);
260                         } else if (value instanceof Character) {
261                             ps.setString(i + 1, value.toString());
262                         } else if (value instanceof Float) {
263                             ps.setFloat(i + 1, (Float) value);
264                         } else if (value instanceof Boolean) {
265                             ps.setBoolean(i + 1, (Boolean) value);
266                         } else if (value instanceof Short) {
267                             ps.setShort(i + 1, (Short) value);
268                         } else {
269                             ps.setObject(i + 1, value);
270                         }
271                     } 
272                     else
273                     {
274                         ps.setNull(i + 1, Types.NULL);
275                     }
276                 }
277                 return ps;
278             }
279         }, keyHolder);
280         
281         return (ID) (Long) keyHolder.getKey().longValue();
282     }
283     
284     /**
285      * 根据sql和相关列值,插入一条记录。
286      * 主键值由程序设定
287      * 返回受影响的行数
288      */
289     protected int insertBySqlValuesAuto(final String sql, List<Object> values) 
290     {
291         if (StringUtils.isEmpty(sql))
292             return 0;
293         
294         if (values == null)
295             values = new ArrayList<Object>();
296         
297         return this.getJdbcTemplate().update(sql, values.toArray());
298     }
299     
300     /**
301      * 插入一组数据
302      */
303     @Override
304     public List<ID> insertBatch(List<T> listObject)
305     {
306         List<ID> listID = new ArrayList<ID>();
307         ID id;
308         
309         if(null == listObject)
310             return listID;
311         
312         for(T object : listObject)
313         {
314             id = this.insert(object);
315             if(null != id) 
316                 listID.add(id);
317         }
318         
319         return listID;
320     }
321 
322     /**
323      * 根据 id 删除一条数据
324      */
325     @Override
326     public int delete(ID id)
327     {
328         if(null == id)
329             return 0;
330         
331         StringBuilder sb = new StringBuilder("delete from ");
332         sb.append(this.getTableName());
333         sb.append(" where ");
334         sb.append(this.getPk());
335         sb.append("=?");
336         
337         List<Object> values = new ArrayList<Object>();
338         values.add(id);
339         
340         return this.deleteBySqlValues(sb.toString(), values); 
341     }
342     
343     /**
344      * 删除一组数据
345      */
346     @Override
347     public int deleteBatch(List<ID> listIds)
348     {
349         if((null == listIds) || listIds.isEmpty())
350             return 0;
351         
352         StringBuilder sb = new StringBuilder("delete from ");
353         sb.append(this.getTableName());
354         sb.append(" where ");
355         sb.append(this.getPk());
356         sb.append(" in (");
357         Serializable[] ss = new Serializable[listIds.size()];
358         Arrays.fill(ss, "?");
359         sb.append(StringUtils.join(ss, ','));
360         sb.append(")");
361         List<Object> values = new ArrayList<Object>();
362         values.addAll(listIds);
363         
364         return this.deleteBySqlValues(sb.toString(), values);
365     }
366     
367     /**
368      * 根据sql和相关列值,删除一条记录。
369      * 返回受影响的行数
370      */
371     protected int deleteBySqlValues(final String sql, final List<Object> values)
372     {
373         return this.getJdbcTemplate().update(sql, values.toArray());
374     }
375 
376     /**
377      * 修改一条数据
378      */
379     @Override
380     public int update(T object)
381     {
382         if (null == object) 
383         {
384             //throw new DaoException("模型对象为空!");
385         }
386         
387         Map<String, Object> map = null;
388         try 
389         {
390             map = toModelMap(object);
391             for(String proterty : transientPropertys) 
392             {
393                 map.remove(proterty);
394             }
395         } 
396         catch(Exception e)
397         {
398             //throw new DaoException(persistentClass.getName() + "解析异常!", e);
399         }
400         
401         int count = this.updateReturnIdByMap(map);
402         if(count == 0)
403         {
404             //throw new DaoException(persistentClass.getName() + "更新失败" + object);
405         }
406         return count;
407     }
408     
409     /**
410      * 根据列名与对应的属性值,更新一条记录。
411      * 返回更新的主键id
412      */
413     protected int updateReturnIdByMap(Map<String, Object> map)
414     {
415         if((null == map) || (map.size() == 0))
416             return 0;
417         
418         Serializable id = (Serializable) map.get(this.getPk());
419         if ((null == id) || "".equals(id))
420             return 0;
421         
422         List<Object> values = new ArrayList<Object>();
423         
424         StringBuilder sb = new StringBuilder("update ");
425         sb.append(this.getTableName());
426         sb.append(" set ");
427         
428         map.remove(this.getPk());
429         
430         for (Map.Entry<String, Object> e : map.entrySet())
431         {
432             sb.append('`').append(e.getKey()).append('`');
433             sb.append("=?, ");
434             values.add(e.getValue());
435         }
436         deleteLastStr(sb, ",");
437         sb.append(" where ");
438         sb.append(this.getPk());
439         sb.append("=?");
440         values.add(id);
441         map.put(this.getPk(), id);
442         
443         return this.updateBySqlValues(sb.toString(), values);
444     }
445     
446     /**
447      * 根据sql和相关列值,更新一条记录
448      * 返回受影响的行数
449      */
450     protected int updateBySqlValues(final String sql, List<Object> values)
451     {
452         if (StringUtils.isEmpty(sql))
453             return 0;
454         
455         if (null == values)
456             values = new ArrayList<Object>();
457         
458         return this.getJdbcTemplate().update(sql, values.toArray());
459     }
460 
461     /**
462      * 根据id查找一条数据
463      * 返回这条数据
464      */
465     @Override
466     public T select(ID id)
467     {
468         if(null == id)
469             return null;
470         
471         StringBuilder sb = new StringBuilder("select * from ");
472         sb.append(this.getTableName());
473         sb.append(" where ");
474         sb.append(this.getPk());
475         sb.append("=?");
476         
477         List<Object> values = new ArrayList<Object>();
478         values.add(id);
479         
480         List<T> list = this.selectBySqlValues(sb.toString(), values);
481         if (list == null || list.size() == 0)
482             return null;
483         else
484             return list.get(0);
485     }
486     
487     /**
488      * 根据一组id,查找相应一组数据。
489      * 返回找到的数据
490      */
491     @Override
492     public List<T> selectByIds(List<ID> ids)
493     {
494         if((null == ids) || ids.isEmpty())
495             return (new ArrayList<T>());
496                 
497         StringBuilder sb = new StringBuilder("select * from ");
498         sb.append(this.getTableName());
499         sb.append(" where ");
500         sb.append(this.getPk());
501         sb.append(" in (");
502         
503         Serializable[] ss = new Serializable[ids.size()];
504         Arrays.fill(ss, "?");
505         sb.append(StringUtils.join(ss, ','));
506         sb.append(")");
507         
508         List<Object> values = new ArrayList<Object>();
509         values.addAll(ids);
510  
511         return this.selectBySqlValues(sb.toString(), values);
512     }
513     
514     /**
515      * 根据给定的属性与属性值对查找记录 
516      * 返回找到的数据
517      */
518     @Override
519     public List<T> selectByMap(Map<String, Object> map)
520     {
521         if (map == null || map.isEmpty())
522             return null;
523         
524         @SuppressWarnings("unchecked")
525         ID id = (ID) map.get(this.getPk());
526         if (id != null) 
527         {
528             map.remove(id);
529         }
530         
531         List<String> removekeys = new ArrayList<String>();
532         for (Map.Entry<String, Object> entry : map.entrySet()) 
533         {
534             if (entry.getValue() == null) 
535             {
536                 removekeys.add(entry.getKey());
537             }
538         }
539         
540         for (String key : removekeys) 
541         {
542             map.remove(key);
543         }
544         
545         List<Object> values = new ArrayList<Object>();
546         StringBuilder sb = new StringBuilder("select * from ");
547         sb.append(this.getTableName());
548         if (map.size() != 0) 
549         {
550             sb.append(" where ");
551             for (Map.Entry<String, Object> entry : map.entrySet()) 
552             {
553                 sb.append('`').append(entry.getKey()).append('`');
554                 sb.append("=? ");
555                 values.add(entry.getValue());
556                 sb.append(" and ");
557             }
558             this.deleteLastStr(sb, "and");
559         }
560         return this.selectBySqlValues(sb.toString(), values);
561     }
562     
563     /**
564      * 根据sql和相关列值,选择数据
565      * 返回受影响的行数
566      */
567     protected List<T> selectBySqlValues(final String sql, List<Object> values)
568     {
569         if (StringUtils.isEmpty(sql))
570             return new ArrayList<T>();
571         
572         if (values == null)
573             values = new ArrayList<Object>();
574          
575         List<T> list = this.getJdbcTemplate().query(sql, values.toArray(),
576                 new LTModelPropertyRowMapper<T>(this.persistentClass, property2ColumnMap));
577         
578         return (list == null) ? new ArrayList<T>() : list;
579     }
580     
581     
582     /**
583      * 删除给定字符之后的字符串
584      *
585      * @param sb
586      * @param str
587      */
588     private void deleteLastStr(StringBuilder sb, String str) 
589     {
590         int index = sb.lastIndexOf(str);
591         if (index != -1) 
592         {
593             sb.delete(index, index + str.length());
594         }
595     }
596     
597     /**
598      * 用于将Model转变成Map,key为属性对应的列名,value为属性对应的值。
599      *
600      * @param object
601      * @return
602      */
603     private Map<String, Object> toModelMap(T object) {
604         Map<String, Object> modelMap = null;
605         try 
606         {
607             Map<String, Object> map = LTBeanMapConverter.convertMapFromBean(object);
608             modelMap = new HashMap<String, Object>();
609             for (Map.Entry<String, Object> e : map.entrySet()) 
610             {
611                 modelMap.put(property2ColumnMap.get(e.getKey()), e.getValue());
612             }
613         } 
614         catch (Exception e) 
615         {
616             //throw new DaoException(persistentClass.getName() + "解析异常!", e);
617         }
618         return modelMap;
619     }
620 }
LTGenericDaoImpl.java

public abstract class LTGenericDaoImpl<T, ID extends Serializable>
extends JdbcDaoSupport implements LTGenericDao<T, ID>

抽象类,继承 JdbcDaoSupport ,实现接口 LTGenericDao 。

这里只提供最基础的一些操作实现,其他复杂操作,可针对项目的需求,在接口里面添加方法,然后在这里实现。具体方法实现,可参考本类中其他方法。

5、步骤 4 中的实现类里面,需要有两个类的支持:

 1 package com.matchbox.utility;
 2 
 3 import java.beans.BeanInfo;
 4 import java.beans.IntrospectionException;
 5 import java.beans.Introspector;
 6 import java.beans.PropertyDescriptor;
 7 import java.lang.reflect.InvocationTargetException;
 8 import java.lang.reflect.Method;
 9 import java.util.HashMap;
10 import java.util.Map;
11 
12 public class LTBeanMapConverter 
13 {
14     /**
15      * 静态方法,将 model bean 转化为 map
16      */
17     public static Map<String, Object> convertMapFromBean(Object bean) 
18             throws IntrospectionException, IllegalAccessException, 
19             IllegalArgumentException, InvocationTargetException
20     {
21         if(null == bean)
22         {
23             return (new HashMap<String, Object>());
24         }
25         
26         BeanInfo info = Introspector.getBeanInfo(bean.getClass());
27         PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
28         
29         Map<String, Object> description = new HashMap<String, Object>();
30         Object value;
31         
32         for (int i = 0; i < descriptors.length; i++) 
33         {
34             String name = descriptors[i].getName();
35             Method reader = descriptors[i].getReadMethod();
36             if (reader != null) 
37             {
38 //                Object[] os = new Object[0];
39 //                value = reader.invoke(bean, os); 
40                 
41                 value = reader.invoke(bean);
42                 description.put(name, value);
43             }
44         }
45         description.remove("class");
46         return description;
47     }
48 }
LTBeanMapConverter.java
  1 package com.matchbox.dao.common;
  2 
  3 import java.beans.PropertyDescriptor;
  4 import java.sql.ResultSet;
  5 import java.sql.ResultSetMetaData;
  6 import java.sql.SQLException;
  7 import java.util.HashMap;
  8 import java.util.HashSet;
  9 import java.util.Map;
 10 import java.util.Set;
 11 
 12 import org.springframework.beans.BeanUtils;
 13 import org.springframework.beans.BeanWrapper;
 14 import org.springframework.beans.NotWritablePropertyException;
 15 import org.springframework.beans.PropertyAccessorFactory;
 16 import org.springframework.beans.TypeMismatchException;
 17 import org.springframework.jdbc.core.RowMapper;
 18 import org.springframework.jdbc.support.JdbcUtils;
 19 
 20 
 21 /**
 22  * @author MATCH
 23  * @date 14-12-31
 24  */
 25 
 26 
 27 public class LTModelPropertyRowMapper<T> implements RowMapper<T> 
 28 {
 29     private Class<T> mappedClass;
 30     private Map<String, PropertyDescriptor> mappedFields;
 31     private Set<String> mappedProperties;
 32 
 33     public LTModelPropertyRowMapper(Class<T> mappedClass, Map<String, String> property2ColumnMap) 
 34     {
 35         initialize(mappedClass, property2ColumnMap);
 36     }
 37 
 38     protected void initialize(Class<T> mappedClass, Map<String, String> property2ColumnMap) 
 39     {
 40         this.mappedClass = mappedClass;
 41         this.mappedFields = new HashMap<String, PropertyDescriptor>();
 42         this.mappedProperties = new HashSet<String>();
 43         PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
 44         
 45         for(PropertyDescriptor pd : pds) 
 46         {
 47             if(pd.getWriteMethod() != null) 
 48             {
 49                 this.mappedFields.put(pd.getName().toLowerCase(), pd);
 50                 String underscoredName = underscoreName(pd.getName());
 51                 if(!pd.getName().toLowerCase().equals(underscoredName)) 
 52                 {
 53                     this.mappedFields.put(underscoredName, pd);
 54                 }
 55                 mappedFields.put(property2ColumnMap.get(pd.getName()), pd);
 56                 this.mappedProperties.add(pd.getName());
 57             }
 58         }
 59     }
 60 
 61     /**
 62      * 将实例的属性,转变为带有下标的形式。
 63      * @param name
 64      * @return
 65      */
 66     private String underscoreName(String name) 
 67     {
 68         StringBuilder result = new StringBuilder();
 69         if ((null != name) && (name.length() > 0)) 
 70         {
 71             result.append(name.substring(0, 1).toLowerCase());
 72             for (int i=1; i<name.length(); i++) 
 73             {
 74                 String s = name.substring(i, i + 1);
 75                 if (s.equals(s.toUpperCase())) 
 76                 {
 77                     result.append("_");
 78                     result.append(s.toLowerCase());
 79                 }
 80                 else 
 81                 {
 82                     result.append(s);
 83                 }
 84             }
 85         }
 86         return result.toString();
 87     }
 88 
 89     /**
 90      * 必须要重写的方法,指定查找的某行数据
 91      */
 92     public T mapRow(ResultSet rs, int rowNumber) throws SQLException 
 93     {
 94         T mappedObject = BeanUtils.instantiate(this.mappedClass);
 95         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
 96 
 97         ResultSetMetaData rsmd = rs.getMetaData();
 98         int columnCount = rsmd.getColumnCount();
 99 
100         for (int index = 1; index <= columnCount; index++) {
101             String column = JdbcUtils.lookupColumnName(rsmd, index);
102             PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase());
103             if(pd != null) 
104             {
105                 try 
106                 {
107                     Object value = getColumnValue(rs, index, pd);
108                     if(value == null)
109                     {
110                         continue;
111                     }
112                     try 
113                     {
114                         bw.setPropertyValue(pd.getName(), value);
115                     }
116                     catch(TypeMismatchException e) 
117                     {
118                         //throw new DaoException("模型类"+this.mappedClass.getName()+"的属性匹配异常", e);
119                     }
120                 }
121                 catch (NotWritablePropertyException ex) 
122                 {
123                     //throw new DaoException("模型类"+this.mappedClass.getName()+"中没有定义"+pd.getName()+"的set方法", ex);
124                 }
125             }
126         }
127         return mappedObject;
128     }
129 
130     protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) 
131             throws SQLException 
132     {
133         return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
134     }
135 }
LTModelPropertyRowMapper.java

其中: LTBeanMapConverter 类是 model bean 和 map 的转换。 LTModelPropertyRowMapper 类是 select 方法需要的,将一行数据转化为 model 。

6、编写 news 数据处理接口类 dao.news.LTNewsDao.java ,向外部提供操作 news 数据模型类的接口。

 1 package com.matchbox.dao.news;
 2 
 3 import java.util.List;
 4 
 5 import com.matchbox.model.news.LTNews;
 6 
 7 
 8 /**
 9  * @author MATCH
10  * @date 14-12-30
11  */
12 
13 
14 public interface LTNewsDao
15 {
16     public long insertNews(LTNews news);
17     public List<Long> insertNewsBatch(List<LTNews> listNews);
18     
19     public int deleteNews(long id);
20     public int deleteNewsBatch(List<Long> listIds);
21     
22     public int updateNews(LTNews news);
23     
24     public LTNews selectNews(long id);
25     public List<LTNews> selectNewsBatch(List<Long> listIds);
26 }
LTNewsDao.java

7、编写 news 数据处理实现类 dao.news.impl.LTNewsDaoImpl.java ,提供 news 模型类操作的实现。

 1 package com.matchbox.dao.news.impl;
 2 
 3 import java.util.List;
 4 
 5 import com.matchbox.dao.common.impl.LTGenericDaoImpl;
 6 import com.matchbox.dao.news.LTNewsDao;
 7 import com.matchbox.model.news.LTNews;
 8 
 9 
10 /**
11  * @author MATCH
12  * @date 14-12-30
13  */
14 
15 
16 public class LTNewsDaoImpl extends LTGenericDaoImpl<LTNews, Long> implements LTNewsDao 
17 {
18     protected LTNewsDaoImpl()
19     {
20         super(LTNews.class); 
21     }
22 
23     @Override
24     public long insertNews(LTNews news)
25     {
26         return this.insert(news); 
27     }
28     
29     @Override
30     public List<Long> insertNewsBatch(List<LTNews> listNews)
31     {
32         return this.insertBatch(listNews);
33     }
34     
35     @Override
36     public int deleteNews(long id)
37     {
38         return this.delete(id);
39     }
40     
41     @Override
42     public int deleteNewsBatch(List<Long> listIds)
43     {
44         return this.deleteBatch(listIds);
45     }
46 
47     @Override
48     public int updateNews(LTNews news)
49     {
50         return this.update(news);
51     }
52     
53     @Override
54     public LTNews selectNews(long id)
55     {
56         return this.select(id);
57     }
58     
59     @Override
60     public List<LTNews> selectNewsBatch(List<Long> listIds)
61     {
62         return this.selectByIds(listIds);
63     }
64 }
LTNewsDaoImpl.java

其中: public class LTNewsDaoImpl extends LTGenericDaoImpl<LTNews, Long> implements LTNewsDao { ... }

需要指定扩展类的模板 <LTNews, Long> 表示数据模型为 LTNews 类,主键为 Long 类型的。

8、编写 api 转发类 LTNewsController.java 

  1 package com.matchbox.api;
  2 
  3 import javax.servlet.http.HttpServletRequest;
  4 import javax.servlet.http.HttpServletResponse;
  5 
  6 import org.springframework.beans.factory.annotation.Autowired;
  7 import org.springframework.stereotype.Controller;
  8 import org.springframework.http.HttpStatus;
  9 import org.springframework.web.bind.annotation.PathVariable;
 10 import org.springframework.web.bind.annotation.RequestMapping;
 11 import org.springframework.web.bind.annotation.RequestMethod;
 12 import org.springframework.web.bind.annotation.ResponseBody;
 13 import org.springframework.web.bind.annotation.ResponseStatus;
 14 
 15 import com.matchbox.dao.news.LTNewsDao;
 16 import com.matchbox.model.news.LTNews;
 17 
 18 
 19 //rootPath = http://127.0.0.1:8080/api
 20 @Controller
 21 @RequestMapping("/news")    //rootPath += "/news"
 22 public class LTNewsController
 23 {
 24     @Autowired
 25     private LTNewsDao newsDao;
 26     
 27     //rootPath += "/insert"
 28     @RequestMapping(value="/insert", method=RequestMethod.GET)
 29     @ResponseStatus(HttpStatus.OK)
 30     @ResponseBody
 31     public String insert()
 32     {
 33         //time, url, imgUrl, type, title, author, source, outline, language, favourite, comment, click
 34         
 35         LTNews news = new LTNews();
 36         news.setTime(1419927688);
 37         news.setUrl("http://insertByNewsController/url_1");
 38         news.setImgUrl("");
 39         news.setType("1,2,3");
 40         news.setTitle("题目 insertByNewsController1");
 41         news.setAuthor("");
 42         news.setSource("来源");
 43         news.setOutline("<html><body>内容 insertByNewsController1</body></html>");
 44         news.setLanguage(1);
 45         news.setFavourite(0);
 46         news.setComment(0);
 47         news.setClick(0);
 48         
 49         return "insert test id: " + this.newsDao.insertNews(news); 
 50     }
 51     
 52     //rootPath += "/delete"
 53     @RequestMapping(value="/delete/{newsId}", method=RequestMethod.GET)
 54     @ResponseStatus(HttpStatus.OK)
 55     @ResponseBody
 56     public String deleteById(@PathVariable String newsId)
 57     {        
 58         this.newsDao.deleteNews(Long.valueOf(newsId));
 59         
 60         return "delete id: " + newsId; 
 61     }
 62     
 63     //rootPath += "/update"
 64     @RequestMapping(value="/update", method=RequestMethod.GET)
 65     @ResponseStatus(HttpStatus.OK)
 66     @ResponseBody
 67     public String update()
 68     {
 69         //time, url, imgUrl, type, title, author, source, outline, language, favourite, comment, click
 70         
 71         long id = 5;
 72         
 73         LTNews news = new LTNews();
 74         news.setId(id);
 75         news.setTime(1419927688);
 76         news.setUrl("http://insertByNewsController/url_1修改");
 77         news.setImgUrl("修改");
 78         news.setType("1,2,3");
 79         news.setTitle("题目 修改222222");
 80         news.setAuthor("修改");
 81         news.setSource("来源修改");
 82         news.setOutline("<html><body>内容 insertByNewsController1</body></html>");
 83         news.setLanguage(1);
 84         news.setFavourite(0);
 85         news.setComment(0);
 86         news.setClick(0);
 87         
 88         this.newsDao.updateNews(news);
 89         
 90         return "update by id: " + id; 
 91     }
 92     
 93     //rootPath += "/select"
 94     @RequestMapping(value="/select/{newsId}", method=RequestMethod.GET)
 95     @ResponseStatus(HttpStatus.OK)
 96     @ResponseBody
 97     public LTNews select(@PathVariable String newsId)
 98     {        
 99         LTNews news = this.newsDao.selectNews(Long.valueOf(newsId));
100         
101         return news;
102     }
103 }
LTNewsController.java

@Autowired
private LTNewsDao newsDao;

表示要自动装配 LTNewsDao bean 类,需要在配置文件中进行配置,如下。

9、修改配置文件 spring-api.xml 、 spring-dao.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:mvc="http://www.springframework.org/schema/mvc"
 6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
 7 
 8     <context:component-scan base-package="com.matchbox.api" />
 9     
10     <!-- http.get 的时候,如果uri中带中文参数,需要设置get方法的header的Content-Type为utf-8 -->
11     <mvc:annotation-driven>
12         <mvc:message-converters> 
13             <!-- StringHttpMessageConverter 默认采用的是 text/plain;charset=ISO-8859-1 -->
14                <!-- RESTClient 响应 Content-Type: text/plain;charset=UTF-8 -->
15             <bean class="org.springframework.http.converter.StringHttpMessageConverter">
16                 <property name="supportedMediaTypes">
17                     <list>
18                         <value>text/plain;charset=UTF-8</value>
19                     </list>
20                 </property>
21             </bean>
22             
23             <!-- json格式的自动转换-->
24             <!-- RESTClient 响应 Content-Type: application/json;charset=UTF-8 -->
25             <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
26         </mvc:message-converters> 
27     </mvc:annotation-driven>  
28     
29 </beans>
spring-api.xml

<context:component-scan base-package="com.matchbox.api" /> 表示在 com.match.api 这个包下面寻找 servlet 的入口 uri 。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5 
 6     <bean id="genericDao" class="com.matchbox.dao.common.impl.LTGenericDaoImpl" abstract="true">
 7         <property name="dataSource" ref="dataSource" />
 8     </bean>
 9     
10     <bean id="newsDao" class="com.matchbox.dao.news.impl.LTNewsDaoImpl" parent="genericDao"></bean>
11 
12 </beans>
spring-dao.xml

要把 dao bean 类添加进去,这样才能正常运行。后面添加其他的 dao 类时,要同样添加进去。

10、修改数据库,建立 news 表

 1 -- database
 2 CREATE DATABASE
 3 IF NOT EXISTS bishe_db DEFAULT CHARACTER
 4 SET utf8;
 5 
 6 USE bishe_db;
 7 
 8 
 9 
10 -- table news
11 DROP TABLE IF EXISTS news;
12 
13 CREATE TABLE
14 IF NOT EXISTS news (
15     id BIGINT NOT NULL auto_increment PRIMARY KEY,
16     time BIGINT,
17     url VARCHAR (200),
18     imgUrl VARCHAR (200),
19     type VARCHAR (100),
20     title TEXT,
21     author VARCHAR (100),
22     source VARCHAR (100),
23     outline TEXT,
24     language int,
25     favourite int,
26     comment int,
27     click int
28 ) auto_increment = 1;
create table news

11、启动 mysql 服务器和 tomcat 服务器,可以通过浏览器访问 uri 来操作数据库 news 类。

 

三、数据对象与json的转换

其实 @ResponseBody 这项工作就已经自动将模型对象与 json 文本数据进行转化了,但是前提是需要添加一些配置, spring-api.xml 中已经添加过了,步骤二中的第九步,已经将 json 数据转化 xml 配置过了,同时还需要添加一些包的支持, maven 的 pom.xml 中也已经添加过 json 的支持包。