现在的位置: 首页 > 综合 > 正文

java防sql注入的sql语句拼接工具sqlHandle

2017年12月13日 ⁄ 综合 ⁄ 共 5046字 ⁄ 字号 评论关闭

     我在做网站的时候有一个需要在不同的插入时间改变查询的逻辑结构,这个时候用PreparedStatement就不太适合了灵活性太差。所以我就写了一个sql拼接工具。它的原理是将sql语句段与值绑定在一起,然后在最后拼接的时候把值按顺序传人给PreparedStatement。这样我们任意拼接我们的sql语句还可以防止sql注入的困扰。

 
 平时我都是用Hibernate进行操作,但有时我多表查询是Hibernate的灵活性就也受到了限制,所以sqlHandle还是适用不少情况的。

 
我已经将代码上传到osc代码托管服务了http://git.oschina.net/plug/sqlHandle 欢迎有兴趣的同学可以加入进来来优化一下。

package com.sql.db;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
/**
 * sql拼接代码
 * 一个完整的sql语句可以有多个sqlHandle拼接而成
 * sqlHandle分sql语句 与 sql值,在sql语句中值由?
 * 替代在最后运行是值将依此赋值给hibernate
 * @author 梁前武 
 * www.apkplug.com
 */
public class sqlHandle {
	public String strSql="%s";
	public Object fsql="";
	public String type="";
	public Object[] v=null;
	public List<sqlHandle> list=null;
	public sqlHandle(String strSql,Object fsql,String type,Object[] v){
		this.strSql=strSql;
		this.fsql=fsql;
		this.type=type;
		this.v=v;
	}
	public sqlHandle(Object fsql,String type,Object[] v){
		this.fsql=fsql;
		this.type=type;
		this.v=v;
	}
	public sqlHandle(){
	}
	public  SQLQuery handle(Session session){
		//拼接本sqlHandle sql字符串
		String sql=addWhereSql(strSql,fsql,type);
		for (int i=0;i<list.size();i++) {
			//依此拼接子sqlHandle
			sqlHandle sqlHandle = (sqlHandle) list.get(i);
			sql+=addWhereSql(sqlHandle.strSql,sqlHandle.fsql,sqlHandle.type);
		}
		System.out.println(sql);
		SQLQuery query=session.createSQLQuery(sql);
		//赋值
		setV(query,0);
		return query;
	}
	/**
	 * 将sql中?代替的值依此赋值给hibernate
	 * @param q
	 * @param i  传递值索引位置
	 * @return
	 */
	public int  setV(SQLQuery q,int i){
		if(v!=null)
		for(int j=0;j<v.length;j++){
			if(v[j]!=null){
				//System.out.println("添加参数");
				setV(q,i,v[j]);
				i++;
			}
		}
		if(fsql!=null&&fsql instanceof sqlHandle)
			i=((sqlHandle)fsql).setV(q, i);
		if(list!=null)
		for (int j=0;j<list.size();j++) {
			sqlHandle sqlHandle = (sqlHandle) list.get(j);
			i=sqlHandle.setV(q, i);
		}
		return i;
	}
	/**
	 * 将sql中?代替的值依此赋值给hibernate
	 * @param q
	 * @param i   值索引位置
	 * @param v   值
	 */
	public  void setV(SQLQuery q,int i,Object v){
		if(v instanceof String){
			q.setString(i, (String)v);
		}else if(v instanceof Integer){
			q.setInteger(i, (Integer)v);
		}else if(v instanceof Float){
			q.setFloat(i, (Float)v);
		}else if(v instanceof Double){
			q.setDouble(i, (Double)v);
		}else if(v instanceof Date){
			q.setDate(i, (Date)v);
		}else if(v instanceof java.sql.Date){
			q.setDate(i, (Date)v);
		}else if(v instanceof Boolean){
			q.setBoolean(i, (Boolean)v);
		}else if(v instanceof byte[]){
			q.setBinary(i, (byte[])v);
		}else if(v instanceof Byte){
			q.setByte(i, (Byte)v);
		}else if(v instanceof Calendar){
			q.setCalendar(i, (Calendar)v);
		}
	}
	
	/**
	 * 拼接sql字符串
	 * @param strSql 连接字符串 如 in(%s)
	 * @param sqlOne 实体字符串 如 select * user  可以是字符串也可以是sqlHandle
	 * @param type   连接类型   如 and,or
	 * @return 返回 如 and in(select * user)
	 */
	private static String addWhereSql(String strSql,Object sqlOne,String type){
		return  " "+type+" "+String.format(strSql, sqlOne)+" ";	
	}
	/**
	 * 添加多个sql参数值
	 * @param fsql  sql语句段   如 name=?
	 * @param type  sql连接类型  如 and
	 * @param v                 Object[]{"liming"} 如无值便为null
	 * @return
	 */
	public  sqlHandle AddMore(Object fsql,String type,Object[] v){
		if (list==null)
			list=new ArrayList<sqlHandle>();
		sqlHandle sql=new sqlHandle(fsql,type,v);
		list.add(sql);
		return this;
	}
	/**
	 * 添加0-1个sql参数
	 * @param fsql    sql语句段   如 name=?
	 * @param type    sql连接类型  如 and
	 * @param v       "liming" 如无值便为null
	 * @return
	 */
	public  sqlHandle Add(Object fsql,String type,Object v){
		AddMore( fsql, type,new Object[]{v});
		return this;
	}
	/**
	 * 添加多个sql参数值
	 * 多一共 strSql字符 有时我们需要 in(sql...) 这种情况。
	 * 我们可以通过设置 strSql=in(%s) fsql=sql... 这种形式来实现
	 * strSql默认为"%s"
	 * @param strSql  替代副
	 * @param fsql
	 * @param type
	 * @param v
	 * @return
	 */
	public  sqlHandle AddMoreAndRep(String strSql,Object fsql,String type,Object[] v){
		if (list==null)
			list=new ArrayList<sqlHandle>();
		sqlHandle sql=new sqlHandle(strSql,fsql,type,v);
		list.add(sql);
		return this;
	}
	/**
	 * 添加多个sql参数值
	 * 多一共 strSql字符 有时我们需要 in(sql...) 这种情况。
	 * 我们可以通过设置 strSql=in(%s) fsql=sql... 这种形式来实现
	 * strSql默认为"%s"
	 * @param strSql
	 * @param fsql
	 * @param type
	 * @param v
	 * @return
	 */
	public  sqlHandle AddAndRep(String strSql,Object fsql,String type,Object v){
		AddMoreAndRep(strSql, fsql, type,new Object[]{v});
		return this;
	}
	/**
	 * 生成自身sql语句
	 */
	public String toString(){
		String sql="";
		for (int i=0;i<list.size();i++) {
			sqlHandle sqlHandle = (sqlHandle) list.get(i);
			sql+=addWhereSql(sqlHandle.strSql,sqlHandle.fsql,sqlHandle.type);
		}
		return sql;
	}
}

01 package com.sql.db;
02 /**
03  *
sql拼接测试代码
04  *
@author 梁前武
05  *
www.apkplug.com
06  */
07 public class test
{
08  
09     /**
10      *
@param args
11      */
12     public static void main(String[]
args) {
13          //1
14          sqlHandle
sql1=
new sqlHandle();
15          sql1.Add("select
* from user where "
 ,"",null).
16          Add("name=?","""liling").
17          Add("age=?","and"10);
18          System.out.println(sql1);  
19          //select
* from user where    name=?  and age=?
20          sql1.AddMore("LIMIT
?,?"
""new Object[]{1,2});
21          System.out.println(sql1);
22          //select
* from user where    name=?  and age=?   LIMIT ?,?
23           
24          //2
25          sqlHandle
sql2=
new sqlHandle();
26          sql2.Add("select
* from friend where "
 ,"",null).
27          Add("myfriend=?","""liling");
28          System.out.println(sql2);
29          //
select * from friend where    myfriend=?
30          sql1.AddMoreAndRep("
in(%s) "
,sql2, "and"null);
31          System.out.println(sql1);
32          //select
* from user where    name=?  and age=?   LIMIT ?,?  and 
33          //in( 
select * from friend where    myfriend=? ) 
34          //很明显sqlHandle添加时的顺序很关键
35           
36     }
37  
38 }

抱歉!评论已关闭.