美文网首页
【Java】类Mybatis的自定义查询语句的实现

【Java】类Mybatis的自定义查询语句的实现

作者: 慕凌峰 | 来源:发表于2019-06-14 16:40 被阅读0次

    1、场景描述

    • 从表fsmworkorder 中获取 工单编码、工单状态、创建时间信息
    • 查询第一页数据,每页数据10条
    • 可以通过条件:tenantIdstatusCodeworkOrderNo动态查询,且tenantId为必传字段,statusCodeworkOrderNo可不传
    自定义查询逻辑

    2、SQL语句如下

    SELECT
        t1.workOrderNo AS '工单编码',
        t1.createTime AS '创建时间',
        t2.statusName AS '工单状态'
    FROM
        fsmworkorder t1
    JOIN fsmworkorderstatus t2 ON t1.tenantId = t2.tenantId AND t1.statusCode = t2.statusCode
    WHERE
        t1.tenantId = #{tenantId}
    <if test="statusCode != null and statusCode!=''">
        AND t1.statusCode=#{statusCode}
    </if>
    <if test="workOrderNo!= null and workOrderNo!=''">
        AND t1.workOrderNo=#{workOrderNo}
    </if>
    

    3、代码实现

    package com.antscity.kernel.biz.service.general.impl;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.ibatis.datasource.pooled.PooledDataSource;
    import org.apache.ibatis.jdbc.SqlRunner;
    import org.apache.ibatis.mapping.BoundSql;
    import org.apache.ibatis.mapping.Environment;
    import org.apache.ibatis.mapping.ParameterMapping;
    import org.apache.ibatis.mapping.SqlSource;
    import org.apache.ibatis.reflection.MetaObject;
    import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
    import org.apache.ibatis.session.Configuration;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.apache.ibatis.transaction.TransactionFactory;
    import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
    import org.apache.ibatis.type.TypeHandlerRegistry;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.text.DateFormat;
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class Test {
    
        // 直接注入
        // @Autowired
        // private SqlSessionFactory sqlSessionFactory;
    
        public static void main(String[] args) {
            Test test = new Test();
    
            /*
             SELECT
             t1.workOrderNo AS '工单编码',
             t1.createTime AS '创建时间',
             t2.statusName AS '工单状态'
             FROM
             fsmworkorder t1
             JOIN fsmworkorderstatus t2 ON t1.tenantId = t2.tenantId AND t1.statusCode = t2.statusCode
             WHERE
             t1.tenantId = #{tenantId}
             <if test="statusCode != null and statusCode!=''">
             AND t1.statusCode=#{statusCode}
             </if>
             <if test="workOrderNo!= null and workOrderNo!=''">
             AND t1.workOrderNo=#{workOrderNo}
             </if>
             */
            String prepareSql = "SELECT\n" +
                    "\tt1.workOrderNo AS '工单编码',\n" +
                    "\tt1.createTime AS '创建时间',\n" +
                    "t2.statusName AS '工单状态'\n" +
                    "FROM\n" +
                    "\tfsmworkorder t1\n" +
                    "JOIN fsmworkorderstatus t2 ON t1.tenantId = t2.tenantId AND t1.statusCode = t2.statusCode\n" +
                    "WHERE\n" +
                    "\tt1.tenantId = #{tenantId}\n" +
                    "<if test=\"statusCode != null and statusCode!=''\">\n" +
                    "    AND t1.statusCode=#{statusCode}\n" +
                    "</if>\n" +
                    "<if test=\"workOrderNo!= null and workOrderNo!=''\">\n" +
                    "    AND t1.workOrderNo=#{workOrderNo}\n" +
                    "</if>";
    
            Map<String, Object> condition = new HashMap<>();
            condition.put("tenantId",1);
            condition.put("statusCode","45000");
            condition.put("start", 1);
            condition.put("limit", 10);
    
            try {
                test.execSql(prepareSql, condition);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 配置数据库信息,获取SqlSessionFactory
         * @return
         */
        private SqlSessionFactory createSqlSessionFactory() {
    
            String driver = "com.mysql.jdbc.Driver";
            String url = "jdbc:mysql://localhost:3306/test?useUnicode=yes&characterEncoding=UTF-8";
            String username = "root";
            String password = "root";
            //创建连接池
            DataSource dataSource = new PooledDataSource(driver, url, username, password);
            //事务
            TransactionFactory transactionFactory = new JdbcTransactionFactory();
            //创建环境
            Environment environment = new Environment("development", transactionFactory, dataSource);
            //创建配置
            Configuration configuration = new Configuration(environment);
            //开启驼峰规则
            configuration.setMapUnderscoreToCamelCase(true);
            //加入资源(Mapper接口)
            // configuration.addMapper(UserMapper.class);
            //
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
    
            return sqlSessionFactory;
        }
    
        public Map<String, Object> execSql(String prepareSql, Map<String, Object> condition) throws Exception {
    
            Map<String, Object> page = new HashMap<>();
            SqlSession sqlSession = null;
    
    
            try {
                SqlSessionFactory sqlSessionFactory = this.createSqlSessionFactory();
                sqlSession = sqlSessionFactory.openSession();
                Connection connection = sqlSession.getConnection();
                SqlRunner sqlRunner = new SqlRunner(connection);
                String realSql = this.toSql(prepareSql, condition);
    
                // 获取查询数量
                Integer sqlCount = this.searchSqlCount(prepareSql, condition);
                page.put("count", sqlCount);
    
                if (sqlCount < 1) {
                    page.put("results", Collections.EMPTY_LIST);
                    return page;
                }
    
                // 当查询语句中添加了LIMIT 时,使用sql语句中自带的
                if (!realSql.contains("limit")
                        && !realSql.contains("limit".toUpperCase())
                        && condition.containsKey("limit")
                        && condition.containsKey("start")) {
                    realSql += " LIMIT " + condition.get("start") + "," + condition.get("limit");
                }
    
                // TODO:执行后的SQL语句
                /*
                SELECT t1.workOrderNo AS '工单编码', t1.createTime AS '创建时间', t2.statusName AS '工单状态'
                FROM fsmworkorder t1
                JOIN fsmworkorderstatus t2 ON t1.tenantId = t2.tenantId AND t1.statusCode = t2.statusCode
                WHERE t1.tenantId = 1 AND t1.statusCode='45000'
                LIMIT 1,10
                 */
                System.out.println("===SQL 语句===:");
                System.out.println(realSql);
    
                // TODO:正式执行时放开
                // page.put("results", sqlRunner.selectAll(realSql));
                return page;
                //return sqlRunner.selectAll(realSql);
            } catch (SQLException e) {
                e.printStackTrace();
                throw new Exception("");
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
        }
    
        public Integer searchSqlCount(String prepareSql, Map<String, Object> condition) throws Exception {
    
            SqlSessionFactory sqlSessionFactory = this.createSqlSessionFactory();
            SqlSession sqlSession = sqlSessionFactory.openSession();
            Connection connection = sqlSession.getConnection();
            SqlRunner sqlRunner = new SqlRunner(connection);
            String sql = toSql(prepareSql, condition);
    
            if (StringUtils.isEmpty(sql)) {
                return 0;
            }
    
            // 将sql中前面的select 和 from 之间的信息替换成count(1),用于查询数量
            int start = 0, end = 0;
            Pattern patternSelect = Pattern.compile("SELECT", Pattern.CASE_INSENSITIVE);
            Matcher matcherSelect = patternSelect.matcher(sql);
    
            while (matcherSelect.find()) {
                start = matcherSelect.end();
                break;
            }
    
            // 获取from的位置
            Pattern patternFrom = Pattern.compile("FROM" , Pattern.CASE_INSENSITIVE);
            Matcher matcherFrom = patternFrom.matcher(sql);
    
            while (matcherFrom.find()) {
                end = matcherFrom.start();
                break;
            }
    
            String sqlCount = StringUtils.replaceOnce(sql, sql.substring(start, end), " COUNT(1) ");
    
            // TODO:查询数量语句
            /*
            SELECT COUNT(1)
            FROM fsmworkorder t1
            JOIN fsmworkorderstatus t2 ON t1.tenantId = t2.tenantId AND t1.statusCode = t2.statusCode
            WHERE t1.tenantId = 1 AND t1.statusCode='45000'
             */
            System.out.println("===查询条数 SQL===:");
            System.out.println(sqlCount);
    
            return 0;
    
            // TODO:正式执行时放开
            /*
            try {
                return Integer.parseInt(String.valueOf(sqlRunner.selectAll(sqlCount).get(0).get("COUNT(1)")));
            } catch (SQLException e) {
                e.printStackTrace();
                throw new Exception("");
            } finally {
                if (sqlSession != null) {
                    sqlSession.close();
                }
            }
            */
        }
    
        private String toSql(String prepareSql, Map<String, Object> condition) throws Exception {
    
            XMLLanguageDriver driver = new XMLLanguageDriver();
            String script = "<script>" + prepareSql + "</script>";
            SqlSource sqlSource;
            BoundSql boundSql;
            SqlSessionFactory sqlSessionFactory = this.createSqlSessionFactory();
            try {
                sqlSource = driver.createSqlSource(sqlSessionFactory.getConfiguration(), script, condition.getClass());
                boundSql = sqlSource.getBoundSql(condition);
            } catch (Exception e) {
                e.printStackTrace();
                throw new Exception("");
            }
    
            Configuration configuration = sqlSessionFactory.getConfiguration();
            Object parameterObject = boundSql.getParameterObject();
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
    
            if (parameterMappings.size() == 0 || parameterObject == null) {
                return sql;
            }
    
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
                sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));
            } else {
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                for (ParameterMapping parameterMapping : parameterMappings) {
                    String propertyName = parameterMapping.getProperty();
                    if (metaObject.hasGetter(propertyName)) {
                        Object obj = metaObject.getValue(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        Object obj = boundSql.getAdditionalParameter(propertyName);
                        sql = sql.replaceFirst("\\?", getParameterValue(obj));
                    }
                }
            }
            return sql;
        }
    
        private static String getParameterValue(Object obj) {
            String value;
            if (obj instanceof String) {
                value = "'" + obj.toString() + "'";
            } else if (obj instanceof Date) {
                DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
                value = "'" + formatter.format(obj) + "'";
            } else if (obj instanceof String[]){
                String str = "";
                for(String s :(String[]) obj){
                    str += "'" + s.trim() + "',";
                }
                value = str.substring(0,str.length()-1);
            }else {
                if (obj != null) {
                    value = obj.toString();
                } else {
                    value = "";
                }
            }
            return value;
        }
    }
    
    
    查询结果效果图

    相关文章

      网友评论

          本文标题:【Java】类Mybatis的自定义查询语句的实现

          本文链接:https://www.haomeiwen.com/subject/daupfctx.html