实现sql的集中管理,简单的把一些固定长度的sql移植进xml很简单,这没有什么好多说的,关键问题是我们平时处理的sql,有大量是动态长度的,比如说最常见的就是多条件的分页查询,往往我们会在代码中写大量的if else,想把这些移植进xml就比较困难了,完全仿制ibatis来做xml标签工作量太大,最省事的处理方法就是能不能直接把Java代码的逻辑处理方式移植进xml,然后对逻辑代码进行解析,绕开那一大堆的xml标签定义,下面就是jfinaluib中的处理方式:
1.0 暂时还是用的拼接,没有预处理,难点就是不是做到解析sql中表字段的类型对应的Java数据类型
<?xml version="1.0" encoding="UTF-8"?>
<sql-statement namespace="pingtai.user">
<!-- 动态SQL处理 -->
<sql id="splitPage">
<![CDATA[
from pt_user u
left join pt_userinfo ui on u.userinfoids = ui.ids
left join pt_department d on u.departmentids = d.ids
where 1=1
<% if(!isEmpty(userClass)){ %>
and u.userClass = '#userClass#'
<% } %>
<% if(!isEmpty(userName)){ %>
and u.userName like '%#userName#%'
<% } %>
<% if(!isEmpty(names)){ %>
and ui.names like '%#names#%'
<% } %>
]]>
</sql>
</sql-statement>
下面是调用xml中sql进行解析的方法,语法解析是用的beetl模板进行的,当然你可以换成freemark或者velocity也行,语法按他们的来就行
/**
* 获取SQL,动态SQL
* @param sqlId
* @param param
* @return
*/
public static String getSql(String sqlId, Map<String, Object> param) {
String sqlTemplete = sqlMap.get(sqlId);
if(null == sqlTemplete || sqlTemplete.isEmpty()){
log.error("sql语句不存在:sql id是" + sqlId);
}
String sql = BeetlKit.render(sqlTemplete, param);
Set<String> keySet = param.keySet();
for (String key : keySet) {
String value = (String) param.get(key);
sql = sql.replace("#" + key + "#", value);
}
return sql.trim();
}
下面是调用方式
Map<String, Object> param = new HashMap<String, Object>();
param.put("userClass", "0");
param.put("userName", "huajian");
String sql = ToolSqlXml.getSql("pingtai.user.splitPage", param);
输出sql:
from pt_user u
left join pt_userinfo ui on u.userinfoids = ui.ids
left join pt_department d on u.departmentids = d.ids
where 1=1 and u.userClass = '0' and u.userName like '%huajian%'
这里存在sql注入的问题:只能用不友好的处理方式来处理,字符串的验证和过滤了,可以查看ToolSqlXml中的stringVali方法
2.0 正在测试中的方法,由于很难得到sql中字典的数据类型,所以做预处理存在难度,但是下面的方法几乎已经验证是可行的,能做到半预处理方法,
此方法存在唯一不足的是对整形的处理,直接用的拼接,然后字符串使用预处理,不用担心存在sql注入,因为中间对整形的数据值做了数据类型转换的测试,
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.beetl.core.BeetlKit;
public class Sql {
public static void main(String[] args) {
String sqlTemplete = "from pt_user u left join pt_userinfo ui on u.userinfoids = ui.ids left join pt_department d on u.departmentids = d.ids " +
" where 1=1 " +
"<% if(!isEmpty(userClass)){ %>"+
" and u.userClass = #'$userClass$'# "+
"<% } %>"+
"<% if(!isEmpty(userName)){ %>"+
" and u.userName like #'%$userName$%'# "+
"<% } %>"+
"<% if(!isEmpty(names)){ %>"+
" and ui.names like #'%$names$%'# "+
"<% } %>"+
"<% if(!isEmpty(status)){ %>"+
" and ui.status = #$status$# "+
"<% } %>";
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("userClass", "0");
paramMap.put("userName", "aa");
paramMap.put("names", "bb");
paramMap.put("status", "1");
String sql = BeetlKit.render(sqlTemplete, paramMap);
Pattern pattern = Pattern.compile("#[\\w\\d\\$\\'\\%\\_]+#"); //#[\\w\\d]+# \\$
Pattern pattern2 = Pattern.compile("\\$[\\w\\d\\_]+\\$"); //#[\\w\\d]+# \\$
Matcher matcher = pattern.matcher(sql);
List<String> listPram = new LinkedList<>();
while (matcher.find()) {
String clounm = matcher.group(0); // #'%$names$%'#
Matcher matcher2 = pattern2.matcher(clounm);
matcher2.find();
String clounm2 = matcher2.group(0); // $names$
if(clounm.equals("#"+clounm2+"#")){//整形
String clounm3 = clounm2.replace("$", "");
try {
String val = (String) paramMap.get(clounm3);
Integer.parseInt(val);
sql = sql.replace(clounm, val);
//listPram.add(val);
} catch (NumberFormatException e) {
throw new RuntimeException("查询参数值异常");
}
}else{//字符串
String clounm3 = clounm2.replace("$", "");
String val = (String) paramMap.get(clounm3);
String clounm4 = clounm.replace("#", "").replace("'", "").replace(clounm2, val);
listPram.add(clounm4);
sql = sql.replace(clounm, "?");
}
}
System.out.println("预处理sql:" + sql);
for (String param : listPram) {
System.out.println("预处理sql参数:" + param);
}
}
}
最后输出的结果是:
预处理sql:from pt_user u left join pt_userinfo ui on u.userinfoids = ui.ids left join pt_department d on u.departmentids = d.ids where 1=1 and u.userClass = ? and u.userName like ? and ui.names like ? and ui.status = 1
预处理sql参数:0
预处理sql参数:%aa%
预处理sql参数:%bb%
此方法存在的不足就是对整形的数据没做预处理,就是ui.status = 1,但是通过#$status$#能确定他是整形,却不知道到底是int、long、bigdecimal
userClass是char
userName是varchar
names是varchar
JfinalUIB中的实现类 ToolSqlXml.java
来源:oschina
链接:https://my.oschina.net/u/99629/blog/300356