實現sql的集中管理,簡單的把一些固定長度的sql移植進xml很簡單,這沒有什麼好多說的,關鍵問題是咱們平時處理的sql,有大量是動態長度的,好比說最多見的就是多條件的分頁查詢,每每咱們會在代碼中寫大量的if else,想把這些移植進xml就比較困難了,徹底仿製ibatis來作xml標籤工做量太大,最省事的處理方法就是能不能直接把Java代碼的邏輯處理方式移植進xml,而後對邏輯代碼進行解析,繞開那一大堆的xml標籤訂義,下面就是jfinaluib中的處理方式:java
1.0 暫時仍是用的拼接,沒有預處理,難點就是否是作到解析sql中表字段的類型對應的Java數據類型git
<?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,動態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:ui
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%'spa
這裏存在sql注入的問題:只能用不友好的處理方式來處理,字符串的驗證和過濾了,能夠查看ToolSqlXml中的stringVali方法.net
2.0 正在測試中的方法,因爲很可貴到sql中字典的數據類型,因此作預處理存在難度,可是下面的方法幾乎已經驗證是可行的,能作到半預處理方法,code
此方法存在惟一不足的是對整形的處理,直接用的拼接,而後字符串使用預處理,不用擔憂存在sql注入,由於中間對整形的數據值作了數據類型轉換的測試,orm
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); } } }
最後輸出的結果是:xml
預處理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