一、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 packagecom.matchbox.model.news;2
3 importjava.io.Serializable;4
5 importjavax.persistence.Column;6 importjavax.persistence.GeneratedValue;7 importjavax.persistence.GenerationType;8 importjavax.persistence.Id;9 importjavax.persistence.Table;10
11
12 /**
13 *@authorMATCH14 * @date 14-12-2915 */
16
17
18 @Table(name="news")19 public class LTNews implementsSerializable20 {21 private longid;22 private longtime;23 privateString url;24 privateString imgUrl;25 privateString type;26 privateString title;27 privateString author;28 privateString source;29 privateString outline;30 private intlanguage;31 private intfavourite;32 private intcomment;33 private intclick;34
35 @Column(name="id")36 @Id37 @GeneratedValue(strategy =GenerationType.IDENTITY)38 public longgetId() {39 returnid;40 }41
42 public void setId(longid) {43 this.id =id;44 }45
46 @Column(name="time")47 public longgetTime() {48 returntime;49 }50
51 public void setTime(longtime) {52 this.time =time;53 }54
55 @Column(name="url")56 publicString getUrl() {57 returnurl;58 }59
60 public voidsetUrl(String url) {61 this.url =url;62 }63
64 @Column(name="imgUrl")65 publicString getImgUrl() {66 returnimgUrl;67 }68
69 public voidsetImgUrl(String imgUrl) {70 this.imgUrl =imgUrl;71 }72
73 @Column(name="type")74 publicString getType() {75 returntype;76 }77
78 public voidsetType(String type) {79 this.type =type;80 }81
82 @Column(name="title")83 publicString getTitle() {84 returntitle;85 }86
87 public voidsetTitle(String title) {88 this.title =title;89 }90
91 @Column(name="author")92 publicString getAuthor() {93 returnauthor;94 }95
96 public voidsetAuthor(String author) {97 this.author =author;98 }99
100 @Column(name="source")101 publicString getSource() {102 returnsource;103 }104
105 public voidsetSource(String source) {106 this.source =source;107 }108
109 @Column(name="outline")110 publicString getOutline() {111 returnoutline;112 }113
114 public voidsetOutline(String outline) {115 this.outline =outline;116 }117
118 @Column(name="language")119 public intgetLanguage() {120 returnlanguage;121 }122
123 public void setLanguage(intlanguage) {124 this.language =language;125 }126
127 @Column(name="favourite")128 public intgetFavourite() {129 returnfavourite;130 }131
132 public void setFavourite(intfavourite) {133 this.favourite =favourite;134 }135
136 @Column(name="comment")137 public intgetComment() {138 returncomment;139 }140
141 public void setComment(intcomment) {142 this.comment =comment;143 }144
145 @Column(name="click")146 public intgetClick() {147 returnclick;148 }149
150 public void setClick(intclick) {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 packagecom.matchbox.dao.common;2
3 importjava.io.Serializable;4 importjava.util.List;5 importjava.util.Map;6
7
8 /**
9 *@authorMATCH10 * @date 14-12-3011 */
12
13
14 public interface LTGenericDao
15 {16 publicString getTableName();17 publicString getPk();18 public ListgetAll();19 public longgetCount();20
21 publicID insert(T object);22 public List insertBatch(ListlistObject);23
24 public intdelete(ID id);25 public int deleteBatch(ListlistIds);26
27 public intupdate(T object);28
29 publicT select(ID id);30 public List selectByIds(Listids);31 public List selectByMap(Mapmap);32 }
LTGenericDao.java
这里需要运用模板的知识,其中: T 为模型类的 class , ID 为模型类对应的表的主键类型。
4、编写基础实现类 dao.common.impl.LTGenericDaoImpl.java ,提供接口类的基础实现。
1 packagecom.matchbox.dao.common.impl;2
3 importjava.beans.BeanInfo;4 importjava.beans.IntrospectionException;5 importjava.beans.Introspector;6 importjava.beans.PropertyDescriptor;7 importjava.io.Serializable;8 importjava.sql.Connection;9 importjava.sql.PreparedStatement;10 importjava.sql.SQLException;11 importjava.sql.Statement;12 importjava.sql.Types;13 importjava.util.ArrayList;14 importjava.util.Arrays;15 importjava.util.Date;16 importjava.util.HashMap;17 importjava.util.List;18 importjava.util.Map;19
20 importjavax.persistence.Column;21 importjavax.persistence.GeneratedValue;22 importjavax.persistence.GenerationType;23 importjavax.persistence.Id;24 importjavax.persistence.Table;25 importjavax.persistence.Transient;26
27 importorg.apache.commons.beanutils.BeanUtils;28 importorg.apache.commons.lang.StringUtils;29 importorg.springframework.core.annotation.AnnotationUtils;30 importorg.springframework.jdbc.core.JdbcTemplate;31 importorg.springframework.jdbc.core.PreparedStatementCreator;32 importorg.springframework.jdbc.core.support.JdbcDaoSupport;33 importorg.springframework.jdbc.support.GeneratedKeyHolder;34 importorg.springframework.jdbc.support.KeyHolder;35
36 importcom.matchbox.dao.common.LTGenericDao;37 importcom.matchbox.dao.common.LTModelPropertyRowMapper;38 importcom.matchbox.utility.LTBeanMapConverter;39
40
41 /**
42 *@authorMATCH43 * @date 14-12-3044 */
45
46
47 public abstract class LTGenericDaoImpl
48 extends JdbcDaoSupport implements LTGenericDao
49 {50 private ClasspersistentClass;51 private String tableName = "";52 private String pk = "";53 privateGenerationType strategy;54 private Map property2ColumnMap = new HashMap();55 private Map column2PropertyMap = new HashMap();56 protected List transientPropertys = new ArrayList();57
58 protected LTGenericDaoImpl(ClasstClass)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 @Override112 publicString getTableName()113 {114 return this.tableName;115 }116
117 @Override118 publicString getPk()119 {120 return this.pk;121 }122
123 @Override124 public ListgetAll()125 {126 return null;127 }128
129 @Override130 public longgetCount()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 @Override141 publicID insert(T object)142 {143 if (null ==object)144 {145 //throw new DaoException("模型对象为空!保存失败");
146 }147
148 Map 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 returnid;167 }168
169 /**
170 * 根据列名与对应的属性值,添加一条记录。171 * 返回添加的主键id172 */
173 @SuppressWarnings("unchecked")174 protected ID insertReturnIdByMap(Mapmap)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 columns = new ArrayList();188 List values = new ArrayList();189
190 for (Map.Entrye : 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 = newString[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 Listvalues)232 {233 JdbcTemplate template = this.getJdbcTemplate();234 KeyHolder keyHolder = newGeneratedKeyHolder();235
236 template.update(newPreparedStatementCreator()237 {238 public PreparedStatement createPreparedStatement(Connection con) throwsSQLException239 {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 instanceofInteger) {248 ps.setInt(i + 1, (Integer) value);249 } else if (value instanceofLong) {250 ps.setLong(i + 1, (Long) value);251 } else if (value instanceofDate) {252 ps.setDate(i + 1, newjava.sql.Date(((Date) value).getTime()));253 ps.setTimestamp(i + 1, newjava.sql.Timestamp(((Date) value).getTime()));254 } else if (value instanceofString) {255 ps.setString(i + 1, value.toString());256 } else if (value instanceofDouble) {257 ps.setDouble(i + 1, (Double) value);258 } else if (value instanceofByte) {259 ps.setByte(i + 1, (Byte) value);260 } else if (value instanceofCharacter) {261 ps.setString(i + 1, value.toString());262 } else if (value instanceofFloat) {263 ps.setFloat(i + 1, (Float) value);264 } else if (value instanceofBoolean) {265 ps.setBoolean(i + 1, (Boolean) value);266 } else if (value instanceofShort) {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 returnps;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, Listvalues)290 {291 if(StringUtils.isEmpty(sql))292 return 0;293
294 if (values == null)295 values = new ArrayList();296
297 return this.getJdbcTemplate().update(sql, values.toArray());298 }299
300 /**
301 * 插入一组数据302 */
303 @Override304 public List insertBatch(ListlistObject)305 {306 List listID = new ArrayList();307 ID id;308
309 if(null ==listObject)310 returnlistID;311
312 for(T object : listObject)313 {314 id = this.insert(object);315 if(null !=id)316 listID.add(id);317 }318
319 returnlistID;320 }321
322 /**
323 * 根据 id 删除一条数据324 */
325 @Override326 public intdelete(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 values = new ArrayList();338 values.add(id);339
340 return this.deleteBySqlValues(sb.toString(), values);341 }342
343 /**
344 * 删除一组数据345 */
346 @Override347 public int deleteBatch(ListlistIds)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 = newSerializable[listIds.size()];358 Arrays.fill(ss, "?");359 sb.append(StringUtils.join(ss, ','));360 sb.append(")");361 List values = new ArrayList();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 Listvalues)372 {373 return this.getJdbcTemplate().update(sql, values.toArray());374 }375
376 /**
377 * 修改一条数据378 */
379 @Override380 public intupdate(T object)381 {382 if (null ==object)383 {384 //throw new DaoException("模型对象为空!");
385 }386
387 Map 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 returncount;407 }408
409 /**
410 * 根据列名与对应的属性值,更新一条记录。411 * 返回更新的主键id412 */
413 protected int updateReturnIdByMap(Mapmap)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 values = new ArrayList();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.Entrye : 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, Listvalues)451 {452 if(StringUtils.isEmpty(sql))453 return 0;454
455 if (null ==values)456 values = new ArrayList();457
458 return this.getJdbcTemplate().update(sql, values.toArray());459 }460
461 /**
462 * 根据id查找一条数据463 * 返回这条数据464 */
465 @Override466 publicT 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 values = new ArrayList();478 values.add(id);479
480 List 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 @Override492 public List selectByIds(Listids)493 {494 if((null == ids) ||ids.isEmpty())495 return (new ArrayList());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 = newSerializable[ids.size()];504 Arrays.fill(ss, "?");505 sb.append(StringUtils.join(ss, ','));506 sb.append(")");507
508 List values = new ArrayList();509 values.addAll(ids);510
511 return this.selectBySqlValues(sb.toString(), values);512 }513
514 /**
515 * 根据给定的属性与属性值对查找记录516 * 返回找到的数据517 */
518 @Override519 public List selectByMap(Mapmap)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 removekeys = new ArrayList();532 for (Map.Entryentry : 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 values = new ArrayList();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.Entryentry : 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 selectBySqlValues(final String sql, Listvalues)568 {569 if(StringUtils.isEmpty(sql))570 return new ArrayList();571
572 if (values == null)573 values = new ArrayList();574
575 List list = this.getJdbcTemplate().query(sql, values.toArray(),576 new LTModelPropertyRowMapper(this.persistentClass, property2ColumnMap));577
578 return (list == null) ? new ArrayList() : list;579 }580
581
582 /**
583 * 删除给定字符之后的字符串584 *585 *@paramsb586 *@paramstr587 */
588 private voiddeleteLastStr(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 *@paramobject601 *@return
602 */
603 private MaptoModelMap(T object) {604 Map modelMap = null;605 try
606 {607 Map map =LTBeanMapConverter.convertMapFromBean(object);608 modelMap = new HashMap();609 for (Map.Entrye : 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 returnmodelMap;619 }620 }
LTGenericDaoImpl.java
public abstract class LTGenericDaoImpl
extends JdbcDaoSupport implements LTGenericDao
抽象类,继承 JdbcDaoSupport ,实现接口 LTGenericDao 。
这里只提供最基础的一些操作实现,其他复杂操作,可针对项目的需求,在接口里面添加方法,然后在这里实现。具体方法实现,可参考本类中其他方法。
5、步骤 4 中的实现类里面,需要有两个类的支持:
1 packagecom.matchbox.utility;2
3 importjava.beans.BeanInfo;4 importjava.beans.IntrospectionException;5 importjava.beans.Introspector;6 importjava.beans.PropertyDescriptor;7 importjava.lang.reflect.InvocationTargetException;8 importjava.lang.reflect.Method;9 importjava.util.HashMap;10 importjava.util.Map;11
12 public classLTBeanMapConverter13 {14 /**
15 * 静态方法,将 model bean 转化为 map16 */
17 public static MapconvertMapFromBean(Object bean)18 throwsIntrospectionException, IllegalAccessException,19 IllegalArgumentException, InvocationTargetException20 {21 if(null ==bean)22 {23 return (new HashMap());24 }25
26 BeanInfo info =Introspector.getBeanInfo(bean.getClass());27 PropertyDescriptor[] descriptors =info.getPropertyDescriptors();28
29 Map description = new HashMap();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 returndescription;47 }48 }
LTBeanMapConverter.java
1 packagecom.matchbox.dao.common;2
3 importjava.beans.PropertyDescriptor;4 importjava.sql.ResultSet;5 importjava.sql.ResultSetMetaData;6 importjava.sql.SQLException;7 importjava.util.HashMap;8 importjava.util.HashSet;9 importjava.util.Map;10 importjava.util.Set;11
12 importorg.springframework.beans.BeanUtils;13 importorg.springframework.beans.BeanWrapper;14 importorg.springframework.beans.NotWritablePropertyException;15 importorg.springframework.beans.PropertyAccessorFactory;16 importorg.springframework.beans.TypeMismatchException;17 importorg.springframework.jdbc.core.RowMapper;18 importorg.springframework.jdbc.support.JdbcUtils;19
20
21 /**
22 *@authorMATCH23 * @date 14-12-3124 */
25
26
27 public class LTModelPropertyRowMapper implements RowMapper
28 {29 private ClassmappedClass;30 private MapmappedFields;31 private SetmappedProperties;32
33 public LTModelPropertyRowMapper(Class mappedClass, Mapproperty2ColumnMap)34 {35 initialize(mappedClass, property2ColumnMap);36 }37
38 protected void initialize(Class mappedClass, Mapproperty2ColumnMap)39 {40 this.mappedClass =mappedClass;41 this.mappedFields = new HashMap();42 this.mappedProperties = new HashSet();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 *@paramname64 *@return
65 */
66 privateString underscoreName(String name)67 {68 StringBuilder result = newStringBuilder();69 if ((null != name) && (name.length() > 0))70 {71 result.append(name.substring(0, 1).toLowerCase());72 for (int i=1; i
81 {82 result.append(s);83 }84 }85 }86 returnresult.toString();87 }88
89 /**
90 * 必须要重写的方法,指定查找的某行数据91 */
92 public T mapRow(ResultSet rs, int rowNumber) throwsSQLException93 {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 returnmappedObject;128 }129
130 protected Object getColumnValue(ResultSet rs, intindex, PropertyDescriptor pd)131 throwsSQLException132 {133 returnJdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());134 }135 }
LTModelPropertyRowMapper.java
其中: LTBeanMapConverter 类是 model bean 和 map 的转换。 LTModelPropertyRowMapper 类是 select 方法需要的,将一行数据转化为 model 。
6、编写 news 数据处理接口类 dao.news.LTNewsDao.java ,向外部提供操作 news 数据模型类的接口。
1 packagecom.matchbox.dao.news;2
3 importjava.util.List;4
5 importcom.matchbox.model.news.LTNews;6
7
8 /**
9 *@authorMATCH10 * @date 14-12-3011 */
12
13
14 public interfaceLTNewsDao15 {16 public longinsertNews(LTNews news);17 public List insertNewsBatch(ListlistNews);18
19 public int deleteNews(longid);20 public int deleteNewsBatch(ListlistIds);21
22 public intupdateNews(LTNews news);23
24 public LTNews selectNews(longid);25 public List selectNewsBatch(ListlistIds);26 }
LTNewsDao.java
7、编写 news 数据处理实现类 dao.news.impl.LTNewsDaoImpl.java ,提供 news 模型类操作的实现。
1 packagecom.matchbox.dao.news.impl;2
3 importjava.util.List;4
5 importcom.matchbox.dao.common.impl.LTGenericDaoImpl;6 importcom.matchbox.dao.news.LTNewsDao;7 importcom.matchbox.model.news.LTNews;8
9
10 /**
11 *@authorMATCH12 * @date 14-12-3013 */
14
15
16 public class LTNewsDaoImpl extends LTGenericDaoImpl implementsLTNewsDao17 {18 protectedLTNewsDaoImpl()19 {20 super(LTNews.class);21 }22
23 @Override24 public longinsertNews(LTNews news)25 {26 return this.insert(news);27 }28
29 @Override30 public List insertNewsBatch(ListlistNews)31 {32 return this.insertBatch(listNews);33 }34
35 @Override36 public int deleteNews(longid)37 {38 return this.delete(id);39 }40
41 @Override42 public int deleteNewsBatch(ListlistIds)43 {44 return this.deleteBatch(listIds);45 }46
47 @Override48 public intupdateNews(LTNews news)49 {50 return this.update(news);51 }52
53 @Override54 public LTNews selectNews(longid)55 {56 return this.select(id);57 }58
59 @Override60 public List selectNewsBatch(ListlistIds)61 {62 return this.selectByIds(listIds);63 }64 }
LTNewsDaoImpl.java
其中: public class LTNewsDaoImpl extends LTGenericDaoImpl implements LTNewsDao { ... }
需要指定扩展类的模板 表示数据模型为 LTNews 类,主键为 Long 类型的。
8、编写 api 转发类 LTNewsController.java
1 packagecom.matchbox.api;2
3 importjavax.servlet.http.HttpServletRequest;4 importjavax.servlet.http.HttpServletResponse;5
6 importorg.springframework.beans.factory.annotation.Autowired;7 importorg.springframework.stereotype.Controller;8 importorg.springframework.http.HttpStatus;9 importorg.springframework.web.bind.annotation.PathVariable;10 importorg.springframework.web.bind.annotation.RequestMapping;11 importorg.springframework.web.bind.annotation.RequestMethod;12 importorg.springframework.web.bind.annotation.ResponseBody;13 importorg.springframework.web.bind.annotation.ResponseStatus;14
15 importcom.matchbox.dao.news.LTNewsDao;16 importcom.matchbox.model.news.LTNews;17
18
19 //rootPath =http://127.0.0.1:8080/api
20 @Controller21 @RequestMapping("/news") //rootPath += "/news"
22 public classLTNewsController23 {24 @Autowired25 privateLTNewsDao newsDao;26
27 //rootPath += "/insert"
28 @RequestMapping(value="/insert", method=RequestMethod.GET)29 @ResponseStatus(HttpStatus.OK)30 @ResponseBody31 publicString insert()32 {33 //time, url, imgUrl, type, title, author, source, outline, language, favourite, comment, click
34
35 LTNews news = newLTNews();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("
内容 insertByNewsController1");44 news.setLanguage(1);45 news.setFavourite(0);46 news.setComment(0);47 news.setClick(0);4849 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 @ResponseBody56 publicString 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 @ResponseBody67 publicString update()68 {69 //time, url, imgUrl, type, title, author, source, outline, language, favourite, comment, click
70
71 long id = 5;72
73 LTNews news = newLTNews();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("
内容 insertByNewsController1");83 news.setLanguage(1);84 news.setFavourite(0);85 news.setComment(0);86 news.setClick(0);8788 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 @ResponseBody97 publicLTNews select(@PathVariable String newsId)98 {99 LTNews news = this.newsDao.selectNews(Long.valueOf(newsId));100
101 returnnews;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
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
9
10
11
12
13
14
15
16
17
18 text/plain;charset=UTF-8
19
20
21
22
23
24
25
26
27
28
29
spring-api.xml
表示在 com.match.api 这个包下面寻找 servlet 的入口 uri 。
1 <?xml version="1.0" encoding="UTF-8"?>
2
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
7
8
9
10
11
12
spring-dao.xml
要把 dao bean 类添加进去,这样才能正常运行。后面添加其他的 dao 类时,要同样添加进去。
10、修改数据库,建立 news 表
1 --database
2 CREATE DATABASE
3 IF NOT EXISTS bishe_db DEFAULT CHARACTER
4 SETutf8;5
6 USEbishe_db;7
8
9
10 --table news
11 DROP TABLE IF EXISTSnews;12
13 CREATE TABLE
14 IF NOT EXISTSnews (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 的支持包。