使用过MyBatis的小伙伴们应该知道,MyBatis支持SQL拦截的功能,如果项目使用JFinal,也想使用SQL拦截功能,读JFinal源码发现,JFinal目前还不支持此功能,仅仅只是在Config类中调用SqlReporter在控制台输出SQL。于是,参考这个SqlReporter简单实现了SQL拦截的功能,供有需要的小伙伴参考。
SQL拦截代理类:
/** * 基于JDK Proxy实现SQL拦截 * @param <T> */ public class JdkProxy<T> implements InvocationHandler { private final Set<String> methods = new HashSet<>(Arrays.asList("getDataSource", "getConnection", "prepareStatement")); private T target; public JdkProxy(T target) { this.target = target; } @SuppressWarnings("unchecked") public T newProxyInstance() { Class<?> clazz = target.getClass(); Class<?>[] classes; if (clazz.isInterface()) { classes = new Class[]{clazz}; } else { classes = clazz.getInterfaces(); } return (T) Proxy.newProxyInstance(clazz.getClassLoader(), classes, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (methods.contains(method.getName())) { if (("getDataSource".equals(method.getName()) || "getConnection".equals(method.getName())) && (args == null || args.length == 0)) { return new JdkProxy<Object>(method.invoke(target, args)).newProxyInstance(); } if ("prepareStatement".equals(method.getName()) && args != null && args.length > 0) { // 拦截变更sql args[0] = modifySql(String.valueOf(args[0])); } } return method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } /** * 修改sql * @param originSql * @return */ private String modifySql(String originSql) { originSql = originSql.trim(); // SQL语句类型:SELECT、INSERT、UPDATE、DELETE、TRUNCATE、ALTER、CREATE、。。。 String sqlType = originSql.substring(0, originSql.indexOf(" ")).toUpperCase(); String sql = simplifySql(originSql); String datetime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(Instant.now()); switch(sqlType) { case "DELETE": // 【拦截删除操作,禁止任何物理删除操作】 sql = "UPDATE" + sql.substring(11, sql.length()); sql = sql.substring(0, sql.toUpperCase().indexOf(" WHERE ")) + " SET deleteFlag = '1', updateAt='" + datetime + "' " + sql.substring(sql.toUpperCase().indexOf(" WHERE "), sql.length()); break; case "UPDATE": sql = sql.substring(0, sql.toUpperCase().indexOf(" WHERE ")) + ", updateAt='" + datetime + "' " + sql.substring(sql.toUpperCase().indexOf("WHERE "), sql.length()); break; case "INSERT": String upperSql = sql.toUpperCase(); if (upperSql.contains("VALUES")) { String[] valuesStrArray = {") VALUES(", ") VALUES (", ")VALUES(", ")VALUES ("}; int index = -1; for (String str : valuesStrArray) { index = upperSql.indexOf(str); if (index > 0) { // TODO 获取当前用户ID String deptId = ""; sql = sql.substring(0, index) + ",statusCode,updateAt,createBy,createByDeptId) " + sql.substring(index + 1, sql.length()); sql = sql.substring(0, sql.length() - 1) + ",'1','" + datetime + "','" + getCurrentUser() + "','" + deptId + "')"; break; } } if (index <= 0) { System.err.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>非法的INSERT SQL语句:" + sql.replaceAll("(?m)^\\s*$(\\n|\\r\\n)", "")); } } break; default: return sql; } System.out.println("变更前sql:" + originSql + "\n变更后sql:" + sql); return sql; } /** * 获取当前用户ID * @return */ private String getCurrentUser() { return "74897C57832941ABBB2E596017504C334R92R1SH"; } /** * 将SQL语句变成一条语句,并且每个单词的间隔都是1个空格 * @param sql * @return */ private String simplifySql(String sql) { return sql.replaceAll("[\r\n]", " ").replaceAll("\\s{2,}", " "); } }
JFinalConfig中使用:
public class Config extends JFinalConfig { @Override public void configConstant(Constants me) {} @Override public void configEngine(Engine me) {} @Override public void configRoute(Routes me) {} @Override public void configHandler(Handlers me) {} @Override public void configInterceptor(Interceptors me) {} @Override public void configPlugin(Plugins me) { IDataSourceProvider dbPlugin = addDbPlugin(me); // 配置ActiveRecord插件 ActiveRecordPlugin arp = new ActiveRecordPlugin(dbPlugin); me.add(arp); } /** * 创建DruidPlugin * @param me * @return */ private IDataSourceProvider addDbPlugin(Plugins me) { DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, jdbcUser, jdbcPassword, jdbcDriver); me.add(new JdkProxy<>(druidPlugin).newProxyInstance()); // 【注意】不能直接返回druidPlugin return (IDataSourceProvider) me.getPluginList().get(me.getPluginList().size() - 1); } @Override public void onStart() {} @Override public void onStop() {} }
结束。