超级简单的sqlmap工具
以前也写过一个,
这一把加入了动态sql,全部重写了
与ibatis类似
#param_name# 使用参数 ?(暂时不支持)
$param_name$ 直接替换
本工具特点:
提供了对ibatis常见功能的支持
核心类只有一个sqlmap.java
本工具适用与综合查询 (insert与update不推荐使用)
动态sql语句只支持 <notempty> 条件 (这个最常用了)
//根据 <notempty name="xxx">content</notempty> 动态生成 sql
//参数xxx不为空时,才输出 content,实现动态sql
//目前只支持常见的notempty判断
//可使用模板来动态生成sql语句,这样将非常强大,常见的模板工具有 freemark,velocity等
//只是一个简单的查询工具,就不使用第三方的模板工具了
//{xxx} xxx 参数名
配置文件使用纯文本格式,而非xml格式(有些特殊字符xml里搞来搞去很无趣)
配置文件格式 ajf_sql_map(xxx)=select * from x ,xxx表示sql name
传入参数直接替换,参数封装在map中
查询返回结果,记录行映射为map,key值从resultset的元数据中获取,且全部为小写,可参考作后的 rs2list部分代码
其他代码不一一给出,稍微搞一下即能整出来
sql-map配置文件只提供一个(统一配置管理,分散配置,各有所长了)
/web-inf/classes/ajf_sql_map.config
/**
* zju ee && cs
* 国产偶像top3 毛泽东,邓小平,周恩来
* nba偶像no.1 tim duncan
* 头号足球偶像 罗纳尔多
* 小牛踏青 giscat@163.com
**/
一个简单的例子
ajf_sql_map.config配置文件
支持//开头的单行注释
ajf_sql_map(q1)=select * from t_user
ajf_sql_map(q2)=select * from t_user where name like '%{name}%'
ajf_sql_map(q3)=select * from t_user where 2>1
<notempty name="name"> and name like '%{name}%' </notempty>
////ajf_sql_map(q1)=select * from t_user
///
/////ajf_sql_map(q1)=select * from t_user
///
ajf_sql_map(q4)=select * from t_user
ajf_sql_map(q5)=select * from t_user
测试代码
map map = jsputil.getrequestmodel(request);//把请求参数封装到map中
list list = null;
try{
list = sqlmap.query("q1",map);
out.println(list.size());
}catch(exception e){
out.println(e);
}
try{
list = sqlmap.query("q2",map);
out.println(list.size());
}catch(exception e){
out.println(e);
}
try{
list = sqlmap.query("q3",map);
out.println(list.size());
}catch(exception e){
out.println(e);
}
try{
list = sqlmap.query("q4",map);
out.println(list.size());
}catch(exception e){
out.println(e);
}
sqlmap.java原代码
package com.zjuee;
import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.regex.*;
//import org.apache.commons.beanutils.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* zju ee && cs
* 国产偶像top3 毛泽东,邓小平,周恩来
* nba偶像no.1 tim duncan
* 头号足球偶像 罗纳尔多
* 小牛踏青 giscat@163.com
**/
public class sqlmap
{
static properties config = null;
//static string sql_config_file = "/ajf_sql.properties";
static string sql_config_file = "/ajf_sql_map.config";
static class c = sqlmap.class;
static string sep = "ajf_sql_map\\(";
static string sql_config_string=null;
//------------
private sqlmap()
{
}
//clear the note,start with // ,single line
//去掉注释,只支持以//开头的单行注释
public static string getconfigstring(string s)
throws exception{
if(s==null){return "";}
s=s.replaceall("//[^\\r\\n]{0,2000}[\\r\\n]{1,100}","");
return s;
}
//参数替换,指定参数名
public static string setparamsingle(string sql, string param, string v)
throws exception {
if (v == null)
v = "";
if (param == null)
param = "";
param = param.trim();
if (param.length() == 0)
throw new exception("\u53c2\u6570\u540d\u4e0d\u80fd\u4e3a\u7a7a");
string s = "{" + param + "}";
int ipos = 0;
int len = 0;
len = s.length();
string head = null;
string tail = null;
stringbuffer sql2 = new stringbuffer();
ipos = sql.indexof(s);
tail = sql;
for (; ipos >= 0; ipos = sql.indexof(s)) {
head = sql.substring(0, ipos);
tail = sql.substring(ipos + len);
sql2.append(head).append(v);
sql = tail;
}
sql2.append(tail);
return sql2.tostring();
//return stringutil.setparam(sql,param,v);
}
//--------------
public static properties getsqlconfigprop()throws exception{
if(config!=null){return config;}
return getsqlconfigpropinternal();
}
//读取配置文件
//配置文件格式 ajf_sql_map(xxx)=select * from x ,xxx表示sql name
public synchronized static properties getsqlconfigpropinternal()throws exception{
if(config!=null){return config;}
inputstream is = null;
inputstreamreader ir = null;
stringbuffer sb = new stringbuffer();
properties prop = null;
string msg = null;
msg = "error when read ajf sql map config file [ web-inf/classes"+sql_config_file;
msg=msg+" ],please check is it exist";
//system.out.println("1");
is = c.getresourceasstream(sql_config_file);
// system.out.println("2");
if(is==null){
throw new exception(msg);
}
// if(is==null){system.out.println("is is null");}
ir = new inputstreamreader(is);
int ch = 0;
if(ir==null){
throw new exception(msg);
}
ch = ir.read();
// if(ir==null){system.out.println("ir is null");}
while(ch>0){
// system.out.println(ch);
sb.append((char)ch);
ch = ir.read();
}
string s = sb.tostring();
s=getconfigstring(s);
sql_config_string = s+"";
//system.out.println(sql_config_string);
int i =0;
int num =0;
string name = null;
int pos = 0;
int start = 0;
int end = 0;
string[]arr=null;
string ss = null;
string sql = null;
arr=s.split(sep);
num=arr.length;
prop = new properties();
for(i=0;i<num;i++){
ss=arr[i];
pos = ss.indexof(")=");
if(pos<=0){continue;}
name=ss.substring(0,pos);
if(name==null){continue;}
name=name.trim();
if(name.length()<1){continue;}
sql=ss.substring(pos+2);
if(stringutil.isempty(sql)){
continue;
}
sql=sql.trim();
if(!stringutil.isempty(prop.getproperty(name))){
throw new exception("duplicate sql name["+name+"]");
}
prop.setproperty(name,sql);
}
return prop;
}
//获取所有参数 {xxx} xxx为参数名
public static list getparamnames(string s) throws exception {
//list list = new arraylist();
list list = null;
map map = new hashmap();
if (s == null) {
return new arraylist();
}
pattern p = pattern.compile("\\{([0-9a-za-z._-]{0,50})\\}");
matcher m = p.matcher(s);
string paramname = null;
while (m.find()) {
paramname = m.group(1);
//list.add(paramname);
map.put(paramname,"1");
}
//return list;
return stringutil.getmapkey(map);
}
//替换参数,全部替换
public static string setparam(string s, map map)
throws exception {
if (map == null) {
return s;
}
list list = getparamnames(s);
if (list == null) {
return s;
}
int i = 0;
int num = 0;
string paramname = null;
string v = null;
object obj = null;
num = list.size();
for (i = 0; i < num; i++) {
paramname = (string) list.get(i);
//system.out.println(paramname);
obj = map.get(paramname);
if(obj==null){
v="";
}else{
v = obj+"";
}
//s = setparamsingle(s, paramname, (string)map.get(paramname));
//system.out.println(v);
//s = stringutil.setparam(s, paramname, v);
s = setparamsingle(s, paramname, v);
//system.out.println(s);
}
return s;
}
//根据 <notempty name="xxx">content</notempty> 动态生成 sql
//参数xxx不为空时,才输出 content,实现动态sql
//目前只支持常见的notempty判断
//可使用模板来动态生成sql语句,这样将非常强大,常见的模板工具有 freemark,velocity等
//还是比较喜欢简单,就不使用第三方的模板工具了
public static string getparamsql(string s,map map)throws exception{
if(s==null){return "null";}
if(map==null){return s;}
string ps = "<notempty[\\s]{1,100}name=\\\"([0-9a-za-z._-]{1,50})\\\">([^/]{1,500})</notempty>";
pattern p = pattern.compile(ps);
matcher m = p.matcher(s);
stringbuffer sb = new stringbuffer();
string v = null;
string rs = null;
string name = null;
while (m.find()) {
name=m.group(1);
rs=m.group(2);
v = (string)map.get(name);
if(stringutil.isempty(v)){
m.appendreplacement(sb, "");
}else{
m.appendreplacement(sb, rs);
}
}
m.appendtail(sb);
return sb.tostring();
}
//根据名称获取原始的sql语句
public static string getsqlbyname(string name)
throws exception{
string s = null;
if(stringutil.isempty(name)){
throw new exception("sql name is empty");
}
s = getsqlconfigprop().getproperty(name);
if(stringutil.isempty(s)){
throw new exception("no sql names ["+name+"]");
}
return s;
}
//根据名称获取sql语句,动态生成,参数替换后的sql,可直接执行
public static string getsqlbyname(string name,map map)
throws exception{
string sql = null;
sql = getsqlbyname(name);
sql=getparamsql(sql,map);
if(map==null){return sql;}
return getsql(sql,map);
}
public static string getsql(string s,map map)throws exception{
if(map==null){return s;}
if(map.isempty()){return s;}
list list = getparamnames(s);
return setparam(s,map);
}
//读取配置内容,文件内容 和 sql map 语句
public static string getsqlconfigcontent()throws exception{
string s = null;
properties prop = getsqlconfigprop();
s=proputil.dump(prop)+"\n\n\n"+sql_config_string;
return s;
}
//--------sql map jdbc
// executeupdate不推荐使用
public static int executeupdate(connection cn,
string name,map map)
throws exception{
if(cn==null){
throw new exception("cn is null");
}
int num = 0;
string sql = null;
statement stmt = null;
sql = getsqlbyname(name,map);
//sql = getparamsql(sql,map);
//getsql(sql,map);
try{
stmt = cn.createstatement();
num = dbutil.executeupdate(stmt,sql);
return num;
}catch(exception e){
throw new exception(e+","+sql);
}finally{dbutil.close(stmt);}
}
public static int executeupdate(
string name,map map)
throws exception{
connection cn = null;
try{
cn = dbutil.getconn();
return executeupdate(cn,name,map);
}catch(exception e){
throw e;
}finally{
dbutil.close(cn);
}
}
public static list query(connection cn,
string name,map map)
throws exception{
if(cn==null){
throw new exception("cn is null");
}
string sql = null;
statement stmt = null;
resultset rs = null;
sql = getsqlbyname(name,map);
//sql = getparamsql(sql,map);
//getsql(sql,map);
try{
stmt = cn.createstatement();
rs = dbutil.executequery( stmt,sql);
return dbutil.rs2list(rs);//把resultset 映射成map
//rs2list代码见最后
//支持结果集分页,参考 rs2list代码
}catch(exception e){
throw new exception(e+","+sql);
}finally{
dbutil.close(rs);
dbutil.close(stmt);
}
}
public static list query(
string name,map map)
throws exception{
connection cn = null;
try{
cn = dbutil.getconn();
return query(cn,name,map);
}catch(exception e){
throw e;
}finally{
dbutil.close(cn);
}
}
public static map queryone(connection cn,string name,map map)
throws exception{
if(cn==null){
throw new exception("cn is null");
}
string sql = null;
sql = getsqlbyname(name,map);
//sql = getparamsql(sql,map);
//getsql(sql,map);
return queryone(cn, sql,null);
}
public static map queryone(string name,map map)
throws exception{
connection cn = null;
try{
cn = dbutil.getconn();
return queryone(cn,name,map);
}catch(exception e){
throw e;
}finally{
dbutil.close(cn);
}
}
}//end class
rs2list 相关代码
public static list rs2list(resultset rs) throws exception {
list list = new arraylist();
if (rs == null) {
return list;
}
string[] arr = null;
map map = null;
arr = getcolname(rs);
int i = 0;
int num = 0;
string v = null;
if (arr != null) {
num = arr.length;
while (rs.next()) {
map = new hashmap();
for (i = 1; i <= num; i++) {
v = rs.getstring(i);
if (v == null) {
v = "";
}
map.put(arr[i - 1], v);
}// end for
list.add(map);
}// end while
}// end if
return list;
}
//支持分页,基于结果集的通用"假"分页
//把结果集全部装载到内存,(数据量不大时完全可以这么做)
//对于大数据量查询,请设置statementset的setmaxrows参数,限制resultset大小即可
//要不然会很慢且吃内存
public static list rs2list(resultset rs, int skip, int page_size)
throws exception {
list list = new arraylist();
if (rs == null) {
return list;
}
string[] arrcolname = null;
string colname = null;
int colnum = 0;
int pos = 0;
int i = 0;
int j = 0;
map map = null;
string v = null;
resultsetmetadata rsmd = null;
rsmd = rs.getmetadata();
colnum = rsmd.getcolumncount();
arrcolname = new string[colnum];
for (i = 1; i <= colnum; i++) {
arrcolname[i - 1] = rsmd.getcolumnname(i).tolowercase();
}
if (page_size == 0) {
page_size = 10000000;
}
while ((rs.next()) && (j < page_size)) {
if (pos < skip) {
pos++;
continue;
}
map = new hashmap();
for (i = 0; i < colnum; i++) {
v = rs.getstring(i + 1);
if (v == null) {
v = "";
}
map.put(arrcolname[i], v);
}
j++;
list.add(map);
}// end while
return list;
}
public static string[] getcolname(resultset rs) throws exception {
if (rs == null) {
return null;
}
int num = 0;
int i = 0;
string colname = null;
string[] arr = null;
resultsetmetadata rsmd = null;
rsmd = rs.getmetadata();
num = rsmd.getcolumncount();
arr = new string[num];
for (i = 1; i <= num; i++) {
colname = rsmd.getcolumnname(i);
colname = colname.tolowercase();
arr[i - 1] = colname;
}
return arr;
}
以前也写的sqlmap可参考这里
http://www.javaresearch.org/article/50600.htm
enjoy!
giscat,2006.12.21