让JAVA的JDBC支持命名参数的SQL语句
------------恢复内容开始------------
第三方依赖
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> <scope>compile</scope> </dependency>
命名参数解析类
package com.plopco.jdbc.core.sql; import com.plopco.jdbc.core.SQLParameter; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @program: com.plopco * @description: java命名参数解析器 * @author: plopco **/ public class SqlNamedParamParser { private String sql; private List<String> names; private NamedParamParser(String sql, List<String> names) { this.sql = sql; this.names = names; } public String getSql() { return sql; } public List<String> getNames() { return names; } /** * 校验是否为 NoSql * * @param sql * @return */ public static boolean isNamedParamSql(String sql) { //去除单引号内的内容与单个问好 sql = sql.replaceAll("(\\'(.*?)\\')|(\\?$)", ""); Pattern pattern = Pattern.compile(".*((\\?|:).+)"); Matcher matcher = pattern.matcher(sql); while (matcher.find()) { return true; } return false; } /** * 解析 ?xx 单值命名占位符,:xx 集合命名占位符(目前仅支持List) * * @param sql * @param sqlParameters * @return */ public static NamedParamParser parse(String sql, SQLParameter[] sqlParameters) { if (sql == null) { throw new NullPointerException("SQL String is null"); } Map<String, SQLParameter> sqlParameterMap = null; if (sqlParameters != null) { sqlParameterMap = Arrays.asList(sqlParameters).stream().collect(Collectors.toMap(SQLParameter::getName, param -> param)); } char c; List<String> names = new ArrayList<>(); StringBuilder sql_builder = new StringBuilder(); StringBuilder name_builder = new StringBuilder(); boolean isGroup = false; for (int index = 0; index < sql.length(); index++) { c = sql.charAt(index); sql_builder.append(c); if ('\'' == c) {//固定值 boolean existEndChar = false;//固定值结束符 //进入 if 条件为字符=“'”故此处默认值得1 int endCharAmount = 1; while (++index < sql.length()) { c = sql.charAt(index); sql_builder.append(c); if (c == '\'') { existEndChar = true; ++endCharAmount; } if (/*处理固定值参数内存在单引号的情况*/endCharAmount % 2 == 0 && ((/*出现固定值结束符,且存在列或参数分隔符*/existEndChar && c == ',') || (/*非处于分组内,出现固定值结束符*/!isGroup && existEndChar) || (/*处于分组内,出现分组结束符且存在固定值结束符*/isGroup && existEndChar && c == ')'))) { break; } } } else if (c == '(') {//组开始 isGroup = true; } else if (c == ')') {//组结束 isGroup = false; } else if ('?' == c || ':' == c) { boolean is_param_array = false; if (':' == c) { is_param_array = true; sql_builder.replace(sql_builder.length() - 1, sql_builder.length(), new Character('?').toString()); } StringBuilder sql_inner_builder = new StringBuilder(); while (++index < sql.length()) { c = sql.charAt(index); if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) { name_builder.append(c); } else { sql_inner_builder.append(c); break; } } names.add(name_builder.toString()); name_builder.setLength(0); if (is_param_array && sqlParameterMap != null) { SQLParameter param_value = sqlParameterMap.get(names.get(names.size() - 1)); if (null != param_value) { List<?> param_list = (List<?>) param_value.getValue(); List<String> pre_char_list = new ArrayList<>(); for (int i = 0, len = param_list.size() - 1; i < len; i++) { pre_char_list.add(new Character('?').toString()); } if (pre_char_list.size() > 0) { sql_builder.append(',' + StringUtils.join(pre_char_list, ',')); } } } sql_builder.append(sql_inner_builder.toString()); } } return new NamedParamParser(sql_builder.toString(), names); } public static void main(String[] args) { System.out.println(NamedParamParser.parse("select a in(:aaa)", new SQLParameter[]{ new SQLParameter("aaa", Arrays.asList(new String[]{"1", "2", "3"})) }).getSql()); System.out.println("=================================="); System.out.println("select a= '?' isNamedParamSql======" + isNamedParamSql("select a= '?'")); System.out.println("select a= ? isNamedParamSql======" + isNamedParamSql("select a= ?")); System.out.println("select a = :a isNamedParamSql======" + isNamedParamSql("select a = :a")); System.out.println("select a = ?a isNamedParamSql======" + isNamedParamSql("select a = ?a")); System.out.println("=================================="); System.out.println(NamedParamParser.parse("select 'a',b,c from dual where a = ?c", null).getSql()); System.out.println(NamedParamParser.parse("select 'a',b,c from dual where a = ?c", null).getNames()); System.out.println("=================================="); System.out.println(NamedParamParser.parse("select 'a','?b',c from dual where a = ?c", null).getSql()); System.out.println(NamedParamParser.parse("select 'a','?b',c from dual where a = ?c", null).getNames()); System.out.println("=================================="); System.out.println(NamedParamParser.parse("insert into(a,b,c) select '<?xml charset='utf-8' version='1.1'><body></body>',?b,?c from dual where d = ?d)", null).getSql()); System.out.println(NamedParamParser.parse("insert into(a,b,c) select '<?xml charset='utf-8' version='1.1'><body></body>',?b,?c from dual where d = ?d)", null).getNames()); System.out.println("=================================="); System.out.println(NamedParamParser.parse("insert into(a,b,c) values('<?xml charset='utf-8' version='1.1'><body></body>',?b,?c)", null).getSql()); System.out.println(NamedParamParser.parse("insert into(a,b,c) values('<?xml charset='utf-8' version='1.1'><body></body>',?b,?c)", null).getNames()); System.out.println("=================================="); String sql = "select b.table_name as slave_table_name,c.table_name as master_table_name from user_constraints a left join" + " user_cons_columns b on a.constraint_name = b.constraint_name" + " left join user_cons_columns c on a.r_constraint_name = c.constraint_name" + " where a.constraint_type = 'R' and a.table_name in(:tableNames)"; System.out.println(NamedParamParser.parse(sql, null).getSql()); System.out.println(NamedParamParser.parse(sql, null).getNames()); System.out.println("=================================="); String sql2 = "SELECT '456789' AS USERID,\n" + " 'GZ-1' AS FACTORYCODE,\n" + " '20201126102001' AS CREATEDATE,\n" + " '1111111' AS PAPERNO,\n" + " '200516065-0-7-6' AS WORKNO,\n" + " '1' AS DEFECT,\n" + " 'GRTRBC' AS SCRAPPROCCODE,\n" + " 'GDCCB' AS DUTYPROCCODE,\n" + " '5' AS STEP,\n" + " '测试' AS REMARK,\n" + " '10' AS SCRAPQTY,\n" + " '10' AS SCRAPSETQTY,\n" + " '10' AS SCRAPPNLQTY\n" + "FROM DUAL"; System.out.println(NamedParamParser.parse(sql2, null).getSql()); System.out.println(NamedParamParser.parse(sql2, null).getNames()); } }
参数类
package com.plopco.jdbc.core; import java.sql.SQLException; /** * @program: com.plopco * @description: 数据库参数类 * @author: plopco **/ public class SQLParameter { public static final int INPUT = 1; public static final int OUT = 2; public static final int INPUT_OUT= 3; public static final int RETURN_VALUE = 6; private int type;//参数类型,输出|输入 private String name;//名称 private Object value;//值 private Integer sqlType;//对应的sql类型java.sql.Types,输入参数可选 public SQLParameter() { super(); } /** * 输入参数可用 * @param name 名称 * @param value 值 */ public SQLParameter(String name, Object value) { this.name = name; this.value = value; } /** * 输入参数可用 * @param type 参数类型,输出|输入 * @param name 名称 * @param value 值 */ public SQLParameter(int type, String name, Object value) { this.type = type; this.name = name; this.value = value; } /** * 通用 * @param type //参数类型,输出|输入 * @param name //名称 * @param value //值 * @param sqlType 对应的sql类型java.sql.Types,输入参数可选 * @throws SQLException */ public SQLParameter(int type, String name, Object value, Integer sqlType) { this.type = type; this.name = name; this.value = value; this.sqlType = sqlType; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } public Integer getSqlType() { return sqlType; } public void setSqlType(Integer sqlType) { this.sqlType = sqlType; } @Override public String toString() { return "SQLParameter [type=" + type + ", name=" + name + ", value=" + value + ", sqlType=" + sqlType + "]"; } }
数据库操作类
/** * 扩展实现 ?xx 命名占位符 * <p> * 简单值占位符:“?xxx”,集合占位符:“:xxx” * </p> * @param connection * @param sql * @param sqlParameters * @return * @throws SQLException */ private PreparedStatement createNamedParamSqlPreparedStatement(final Connection connection, final String sql, final SQLParameter[] sqlParameters) throws SQLException { NamedParamParser noSql = NamedParamParser.parse(sql, sqlParameters); PreparedStatement preparedStatement = connection.prepareStatement(noSql.getSql()); if (sqlParameters != null) { Map<String, SQLParameter> sqlParameterMap = Arrays.asList(sqlParameters).stream().collect(Collectors.toMap(SQLParameter::getName, param -> param)); int paramIndex = 1; for (int i = 0, len = noSql.getNames().size(); i < len; i++) { SQLParameter param = sqlParameterMap.get(noSql.getNames().get(i)); if (param == null) { log.info("noSql.getNames().get(i):" + noSql.getNames().get(i)); } Object value = param.getValue(); if (value instanceof List) { if (null != value) { List<?> param_list = (List<?>) value; for (int j = 0, len2 = param_list.size(); j < len2; j++) { preparedStatement.setObject(paramIndex, param_list.get(j)); paramIndex++; } } continue; } else { if (param.getValue() instanceof byte[]) { preparedStatement.setBytes(paramIndex, (byte[]) param.getValue()); } else { preparedStatement.setObject(paramIndex, param.getValue()); } } paramIndex++; } } return preparedStatement; }
------------恢复内容结束------------