实现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 代码笔记 (4)--- 高仿ibatis(mybatis)实现sql的集中管理,布布扣,bubuko.com