1.2版本中添加了一个新插入的方法:
/**
* 在Web开发中struts框架中,页数数据在被存入数据库时会被包装在一个formbean对象中
* 在把这些数据存入数据库时,需要把formbean中值取出来,在插入数据库中这样很麻烦
* 所以我设计了这个方法,只需要一个sql语句(sql语句字段名必须和数据库中的完全一致,字段顺序可以随便)
* 和一个封装好数据对象。
* 这个方法对页面数据提交在存入数据库,有很大方便。
* 在这里插入主键时,主键值也应当包含那个封装对象中
* 思想:主要是对sql语句进行分析,解析出要插入字段名称,在利用反射技术将值set到preparedStatement对象中。
* @param sql 数据库插入 sql语句
* @param obj 已经封装好数据对象
* @return 新增成功记录数
* @throws Exception
*/
public int insert(String sql, Object obj) throws Exception {
if(obj==null){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String [] fieldNames=resolveSQL(sql);
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<fieldNames.length;i++){
Object o=valueFromObject(fieldNames[i],obj);
PreparedStatementSetValue(ps,o,i+1);
}
return ps.executeUpdate();
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
=================================================================
package daoUtil.daoTemplate;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import jdbcUtil.JdbcUtil;
import daoUtil.PrimaryKeyer;
import daoUtil.RowMapper;
/**
* 在写jdbc程序是可以清楚的知道
* 在程序中只有sql语句和其参数值是变化
* 其余程序代码几乎类似(获得连接,关闭连接)
* 在这里我对以前所写jdbc程序进行了一下改进
* 将获得连接和关闭连接的程序代码交给一个模板类去做
* 再写jdbc程序时,调用模板类中相应的方法,传入sql语句和其参数值
* 这样大大简化jdbc程序,给我们带来方便
* 程序新版本往后日子会不断更新,渴望javaeye里面高手多多给我指点
* @author kevin.wangwei
* Email:wanwei.234@163.com
* 2010-1-30
*/
public class DAOTemplate{
/**jdbc工具类*/
private JdbcUtil jdbcUtil=JdbcUtil.getInstance();
/**
* 数据库删除操作
* @param sql 删除操作sql语句
* @param args 删除操作sql语句参数值数组
* @return 删除记录条数
* @throws SQLException
*/
public int delete(String sql, Object[] args) throws SQLException {
if(args==null||args.length==0){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);//在这里我们应该调用下面的PreparedStatementSetValue方法,
//不过这样写亦可以,但它不可以处理null值
}
return ps.executeUpdate();
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 数据库更新操作
* @param sql 更新操作sql语句
* @param args sql语句参数值数组
* @return 更新记录条数
* @throws SQLException
*/
public int update(String sql, Object[] args) throws SQLException {
if(args==null||args.length==0){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
return ps.executeUpdate();
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 数据库查询操作 采用反射来给包装sql语句参数赋值
* @param sql 查询操作sql语句
* @param args 删除操作sql语句数组数值
* @return 结果对象
* @throws SQLException
*/
public Object find(String sql, Object[] args,RowMapper rowMapper) throws SQLException {
if(args==null||args.length==0){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
try {
PreparedStatementSetValue(ps,args[i],i+1);
} catch (Exception e) {
e.printStackTrace();
}
}
rs=ps.executeQuery();
Object obj=null;
while(rs.next()){
obj=rowMapper.rowMapping(rs);
}
return obj;
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 获得表中记录数
* @param sql sql语句
* @param args 参数数组
* @return 表中记录数
* @throws SQLException
*/
public int getRecordCount(String sql, Object[] args) throws SQLException {
if(args==null||args.length==0){
return 0;
}
int count=0;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
rs=ps.executeQuery();
if(rs.next()){
count=rs.getInt(1);
}
}finally{
jdbcUtil.free(rs,ps,conn);
}
return count;
}
/**
* 根据数据库表名,找到该表中所有记录数
* @param tableName 要查询的表
* @return 表中记录数
* @throws SQLException
*/
public int getRecordCount(String tableName) throws SQLException {
if(tableName==null||tableName.equals("")){
return 0;
}
int count=0;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
String sql="select count(*) from "+tableName;
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
if(rs.next()){
count=rs.getInt(1);
}
}finally{
jdbcUtil.free(rs,ps,conn);
}
return count;
}
/**
* 数据库插入操作(这是采用接口回调技术,由调用程序来给主键赋值)
* @param sql 插入操作 sql语句
* @param args 插入数
* @param primaryIndex 主键在sql语句中位置(小于-1表示用数据自动生成主键不需要插入)
* @return 插入记录数
* @throws Exception
*/
public int insert(String sql, Object[] args, int primaryKeyIndex,PrimaryKeyer primaryKeyer) throws Exception {
if(args==null||args.length==0){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
if(primaryKeyIndex<=-1){
for(int i=0;i<args.length;i++){
try {
PreparedStatementSetValue(ps,args[i],i+1);
} catch (Exception e) {
e.printStackTrace();
}
}
}else if(primaryKeyIndex>-1&&primaryKeyIndex<args.length){
for(int i=0;i<args.length;i++){
if(i==primaryKeyIndex){
PreparedStatementSetValue(ps,primaryKeyer.getPrimaryKey(),i+1);
//ps.setObject(i+1,primaryKeyer.getPrimaryKey());
}else{
PreparedStatementSetValue(ps,args[i],i+1);
}
}
}else{
throw new IllegalArgumentException("设置主键位置不正确!");
}
return ps.executeUpdate();
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 在Web开发中struts框架中,页数数据在被存入数据库时会被包装在一个formbean对象中
* 在把这些数据存入数据库时,需要把formbean中值取出来,在插入数据库中这样很麻烦
* 所以我设计了这个方法,只需要一个sql语句(sql语句字段名必须和数据库中的完全一致,字段顺序可以随便)
* 和一个封装好数据对象。
* 这个方法对页面数据提交在存入数据库,有很大方便。
* 在这里插入主键时,主键值也应当包含那个封装对象中
* 思想:主要是对sql语句进行分析,解析出要插入字段名称,在利用反射技术将值set到preparedStatement对象中。
* @param sql
* @param obj
* @return
* @throws Exception
*/
public int insert(String sql, Object obj) throws Exception {
if(obj==null){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
String [] fieldNames=resolveSQL(sql);
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<fieldNames.length;i++){
Object o=valueFromObject(fieldNames[i],obj);
PreparedStatementSetValue(ps,o,i+1);
}
return ps.executeUpdate();
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 查找符合条件所有记录(这也是采用接口回调技术,由调用程序来决定结果set到什么对象中)
* @param sql 查询sql语句
* @param args 查询参数
* @param rowMapper 结果集映射器
* @return Collection 记录集
* @throws SQLException
*/
public Collection ObjectList(String sql, Object[] args,RowMapper rowMapper) throws SQLException {
if(args==null||args.length==0){
return null;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
Collection list=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
list=new ArrayList();
rs=ps.executeQuery();
while(rs.next()){
Object obj=rowMapper.rowMapping(rs);
list.add(obj);
}
}finally{
jdbcUtil.free(rs,ps,conn);
}
return list;
}
/**
* 依据与表对应的JavaBean的Class(采用反射技术将结果集set到JavaBean对象中)
* 将查询结果封装为一个JavaBean的对象返回
* @param sql 查询sql语句
* @param args 查询参数
* @param javaBeanClass JavaBean的Class
* @return 返回获得JavaBean对象
* @throws Exception
*/
public Object find(String sql, Object[] args,Class javaBeanClass) throws Exception {
if(args==null||args.length==0){
return 0;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
rs=ps.executeQuery();
String[] names=jdbcUtil.getResultSetFieldName(rs);
Object obj=null;
while(rs.next()){
obj=rowMapper(javaBeanClass,rs,names);
}
return obj;
}finally{
jdbcUtil.free(rs,ps,conn);
}
}
/**
* 依据与表对应的JavaBean的Class(上面方法重载方法,采用了不同实现机制)
* 将查询结果封装为一个包含JavaBean的集合对象返回
* @param sql 查询sql语句
* @param args 查询参数
* @param javaBeanClass javaBeanClass JavaBean的Class
* @return 记录集
* @throws Exception
*/
public Collection ObjectList(String sql, Object[] args,Class javaBeanClass) throws Exception {
if(args==null||args.length==0){
return null;
}
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
Collection list=null;
try {
conn=jdbcUtil.getConnection();
ps=jdbcUtil.scrollReadOnlyResultSet(sql,conn);
for(int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
list=new ArrayList();
rs=ps.executeQuery();
String[] names=jdbcUtil.getResultSetFieldName(rs);
while(rs.next()){
Object obj=rowMapper(javaBeanClass,rs,names);
list.add(obj);
}
}finally{
jdbcUtil.free(rs,ps,conn);
}
return list;
}
/**
* 这个方法是通过反射来将数据库表中对应的javaBean对象set值
* 该JavaBean对象必须有一个无参数的构造函数
* @param clazz javabean 超类
* @param rs 数据库结果集
* @return Object 对象
* @throws Exception
*/
private Object rowMapper(Class clazz,ResultSet rs,String[] names) throws Exception{
Object obj=clazz.newInstance();
for(int i=0;i<names.length;i++){
String columnName=toUpperCaseFirstLetterForSet(names[i]);
Method[] m=clazz.getMethods();
for(int j=0;j<m.length;j++){
String methodName=m[j].getName();
if(columnName.equals(methodName)){
m[j].invoke(obj,rs.getObject(i+1));
break;
}
}
}
return obj;
}
/**
* 将字符串一个字母转换为大写
* @param name
* @return
*/
private String toUpperCaseFirstLetterForSet(String name){
if(name!=null&&name.length()>0){
return "set"+name.substring(0,1).toUpperCase()+name.substring(1);
}
return "";
}
/**
* 这是采用反射的方法来给PreparedStatement包装sql 语句参数赋值
* @param ps
* @param obj 数组中对象
* @param index 参数索引位置
* @throws Exception
*/
private void PreparedStatementSetValue(PreparedStatement ps,Object obj,int index) throws Exception{
String name=getMethodName(obj);
Method[] m=ps.getClass().getMethods();
for(int i=0;i<m.length;i++){
String methodName=m[i].getName();
if(name.equals(methodName)){
//System.out.println(methodName+"===========");
m[i].invoke(ps,index,obj);
break;
}
}
}
/**
* 通过反射获得数组中每个元素类型,
* 从而获得PreparedStatement对象setxxx方法名称
* @param obj sql语句参数值
* @return PreparedStatement对象要调用setxxx方法名称
*/
private String getMethodName(Object obj){
if(obj==null){
return null;
}
//System.out.println(obj+"===========");
String className=obj.getClass().getName();
String[] names=className.split("\\.");
className=names[names.length-1];
if(className.equalsIgnoreCase("Integer")){
className="Int";
}
className="set"+className;
return className;
}
/**
* 从sql语句中解析出我们需要字段名称
* @param sql 必须是一个有效 sql插入语句(最好不要用别名)
* @return 字段名称数组
*/
private String[] resolveSQL(String sql){
sql=sql.toLowerCase();
int left_brackets=sql.indexOf("(");
int right_brackets=sql.indexOf(")");
String fieldString=sql.substring(left_brackets+1,right_brackets);
String[] fieldNames=fieldString.split(",");
return fieldNames;
}
/**
* 根据字段名从包装数据对象中取出于该字段相对应的值
* 通过反射用get方法来获得
* @param fieldName
* @return
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws Exception
*/
private Object valueFromObject(String fieldName,Object formBean) throws Exception{
String methodName=toUpperCaseFirstLetterForGet(fieldName);
Method[] methods=formBean.getClass().getMethods();
for(Method m:methods){
String mName=m.getName();
if(methodName.equals(mName)){
Object value=m.invoke(formBean);
return value;
}
}
return null;
}
/**
* 将字符串一个字母转换为大写
* @param name
* @return
*/
private String toUpperCaseFirstLetterForGet(String name){
if(name!=null&&name.length()>0){
name=name.trim();
return "get"+name.substring(0,1).toUpperCase()+name.substring(1);
}
return "";
}
}