版权声明:【分享也是一种提高】个人转载请在正文开头明显位置注明出处,未经作者同意禁止企业/组织转载,禁止私自更改原文,禁止用于商业目的。 https://blog.csdn.net/u010887744/article/details/64216979
SpringJDBC无疑极大的方便了我们访问数据库,但是有一个小问题,每次查询操作返回的实体对象不一样,难道我们每次都要重新实现RowMapper吗?利用泛型,可以方便处理这样的操作。
开发环境:Windows10、eclipse、SpringJDBC4.3.7。文末含项目源码下载链接。
1、自我实现RowMapper
/*
* 文件名:LocalRowMapper.java
* 版权:Copyright 2007-2017 517na Tech. Co. Ltd. All Rights Reserved.
* 描述: LocalRowMapper.java
* 修改人:xiaofan
* 修改时间:2017年3月19日
* 修改内容:新增
*/
package com.zxiaofan.dubboProvidder.rowMapper;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import org.springframework.jdbc.core.RowMapper;
/**
*
* @author xiaofan
*/
public class LocalRowMapper<T> implements RowMapper<T> {
/**
* 添加字段注释.
*/
private Class<?> targetClazz;
/**
* 添加字段注释.
*/
private HashMap<String, Field> fieldMap;
/**
* 构造函数.
*
* @param targetClazz
* .
*/
public LocalRowMapper(Class<?> targetClazz) {
this.targetClazz = targetClazz;
fieldMap = new HashMap<>();
Field[] fields = targetClazz.getDeclaredFields();
for (Field field : fields) {
// 同时存入大小写,如果表中列名区分大小写且有列ID和列iD,则会出现异常。
// 阿里开发公约,建议表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。
fieldMap.put(field.getName(), field);
// fieldMap.put(getFieldNameUpper(field.getName()), field);
}
}
/**
* {@inheritDoc}.
*/
@Override
public T mapRow(ResultSet rs, int arg1) throws SQLException {
T obj = null;
try {
obj = (T) targetClazz.newInstance();
final ResultSetMetaData metaData = rs.getMetaData();
int columnLength = metaData.getColumnCount();
String columnName = null;
for (int i = 1; i <= columnLength; i++) {
columnName = metaData.getColumnName(i);
Class fieldClazz = fieldMap.get(columnName).getType();
Field field = fieldMap.get(columnName);
field.setAccessible(true);
// fieldClazz == Character.class || fieldClazz == char.class
if (fieldClazz == int.class || fieldClazz == Integer.class) { // int
field.set(obj, rs.getInt(columnName));
} else if (fieldClazz == boolean.class || fieldClazz == Boolean.class) { // boolean
field.set(obj, rs.getBoolean(columnName));
} else if (fieldClazz == String.class) { // string
field.set(obj, rs.getString(columnName));
} else if (fieldClazz == float.class) { // float
field.set(obj, rs.getFloat(columnName));
} else if (fieldClazz == double.class || fieldClazz == Double.class) { // double
field.set(obj, rs.getDouble(columnName));
} else if (fieldClazz == BigDecimal.class) { // bigdecimal
field.set(obj, rs.getBigDecimal(columnName));
} else if (fieldClazz == short.class || fieldClazz == Short.class) { // short
field.set(obj, rs.getShort(columnName));
} else if (fieldClazz == Date.class) { // date
field.set(obj, rs.getDate(columnName));
} else if (fieldClazz == Timestamp.class) { // timestamp
field.set(obj, rs.getTimestamp(columnName));
} else if (fieldClazz == Long.class || fieldClazz == long.class) { // long
field.set(obj, rs.getLong(columnName));
}
field.setAccessible(false);
}
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
/**
* 方法首字母大写.
*
* @param fieldName
* 字段名.
* @return 字段名首字母大写.
*/
private String getFieldNameUpper(String fieldName) {
char[] cs = fieldName.toCharArray();
cs[0] -= 32; // 方法首字母大写
return String.valueOf(cs);
}
}
定义一个
LocalRowMapper<T> 类,implements
RowMapper<T>,在这里需要注意fieldMap缓存字段名,由于不同的人表字段命名规则不一样,有的习惯于首字母小写,有的习惯于首字母大写。这里以阿里巴巴开发公约为准(
【强制】表名、字段名必须使用小写字母或数字;禁止出现数字开头,禁止两个下划线中间只出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。)。如果你的表字段是大写开头,请注释掉fieldMap.put(field.getName(), field);同时放开fieldMap.put(getFieldNameUpper(field.getName()), field);这行的注释。
2、相关数据库表设计
#建库字符编码为utf8的库studydb
CREATE DATABASE IF NOT EXISTS StudyDB DEFAULT CHARACTER SET utf8;
#建表user
CREATE TABLE
IF NOT EXISTS USER (
id INT (10) NOT NULL auto_increment,
userName VARCHAR (20) NOT NULL,
age INT (4),
addTime DATETIME,
modifyTime TIMESTAMP,
isDelete INT(4),
PRIMARY KEY (id)
) ENGINE = INNODB DEFAULT CHARSET = utf8;
3、定义model
package com.zxiaofan.dubboProvidder.model;
import java.util.Date;
/**
* 用户表.
*
* @author xiaofan
*/
public class UserDo {
private String tableName;
private Integer id;
private String userName;
private Integer age;
private Date addTime;
private Date modifyTime;
private int isDelete;
// get/set方法略
@Override
public String toString() {
return "UserDo [tableName=" + tableName + ", id=" + id + ", userName=" + userName + ", age=" + age + ", addTime=" + addTime + ", modifyTime=" + modifyTime + ", isDelete=" + isDelete + "]";
}
}
此处加入了数据库没有的字段tableName,方便数据库操作时传入表名,同时重写了toString()方法,便于返回值查看。
3、数据库相关配置及注入jdbcTemplate
app-context-dataSource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- oracle.jdbc.driver.OracleDriver -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}">
</property>
<property name="url" value="${jdbc.url}">
</property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
abstract="false" lazy-init="false" autowire="default">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
</beans>
4、具体使用
package com.zxiaofan.dubboProvidder.business.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import com.zxiaofan.dubboProvidder.business.IUserBusiness;
import com.zxiaofan.dubboProvidder.model.UserDo;
import com.zxiaofan.dubboProvidder.rowMapper.LocalRowMapper;
/**
*
* @author xiaofan
*/
@Component
public class UserBusinessImpl implements IUserBusiness {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* {@inheritDoc}.
*/
@Override
public int insert(UserDo userDo) {
String sqlStr = "insert into " + userDo.getTableName() + " (userName,age,addTime,isDelete) values(?,?,?,?)";
int result = jdbcTemplate.update(sqlStr, userDo.getUserName(), userDo.getAge(), userDo.getAddTime(), userDo.getIsDelete());
return result;
}
/**
* {@inheritDoc}.
*/
@Override
public UserDo selectByID(UserDo userDo) {
String sqlStr = "select * from " + userDo.getTableName() + " where id=?";
List<UserDo> dos = jdbcTemplate.query(sqlStr, new LocalRowMapper(UserDo.class), userDo.getId());
if (null != dos && !dos.isEmpty()) {
return dos.get(0);
}
return null;
}
/**
* {@inheritDoc}.
*/
@Override
public int update(UserDo userDo) {
String sqlStr = "update " + userDo.getTableName() + " set userName=? where id=?";
int result = jdbcTemplate.update(sqlStr, userDo.getUserName(), userDo.getId());
return result;
}
/**
* {@inheritDoc}.
*/
@Override
public int delete(UserDo userDo) {
String sqlStr = "delete from " + userDo.getTableName() + " where userName=?";
int result = jdbcTemplate.update(sqlStr, userDo.getUserName());
return result;
}
}
注意 UserDo
selectByID(UserDo userDo) 方法,jdbcTemplate.
query(sqlStr,
new LocalRowMapper(UserDo.class), userDo.getId());入参为sql、重写的
LocalRowMapper、实际参数id,这里我们传入了返回实体对象UserDo的的类类型UserDo.class。待数据返回后将自动映射成我们的model。
查看单元测试情况,这里只展示根据KeyID查询的,其他请自行执行测试类。
下图是测试暴露的HTTP服务,详见另一篇博文《 dubbo使用教程,可直接应用于企业开发》
源码地址:https://github.com/zxiaofan/OpenSource_Study/tree/master/dubbo/DubboProvider,以上代码来源于个人学习项目dubbo,项目OpenSource_Study下包含了本人各类开源软件、框架学习的相关demo,包含Apache、Thrift、Guava、quartz等项目,持续学习ing。
有任何问题,欢迎留言讨论。
欢迎个人转载,但须在文章页面明显位置给出原文连接;
未经作者同意必须保留此段声明、不得随意修改原文、不得用于商业用途,否则保留追究法律责任的权利。
【 CSDN 】:csdn.zxiaofan.com
【GitHub】:github.zxiaofan.com
如有任何问题,欢迎留言。祝君好运!
Life is all about choices!
将来的你一定会感激现在拼命的自己!