MyBatis(三):自定义持久层框架实现

  1. 新建Maven工程

    架构端MyPersistent、使用端MyPersistentTest,使用端引入架构端Maven坐标

  2. MyPersistentTest使用端配置

    新增依赖

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <dependency>
            <groupId>com.rangers</groupId>
            <artifactId>MyPersistent</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
        </dependency>
    

    新建实体类User

    package com.rangers.entity;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class User {
    
        private int id;
    
        private String name;
    
        private String address;
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    

    定义查询数据接口IUserDao

    package com.rangers;
    
    import com.rangers.entity.User;
    
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description 用户数据库访问Dao
     * @Date 2021-03-07
     **/
    public interface IUserDao {
    
        /**
         * @Author Rangers
         * @Description 查询所有用户信息
         * @Date 2021/3/8 10:43 上午
         * @Return: java.util.List<com.rangers.entity.User>
         **/
        public List<User> selectList();
    
        /**
         * @Author Rangers
         * @Description 根据条件查询单个用户信息
         * @Date 2021/3/8 10:43 上午
         * @Param user:
         * @Return: com.rangers.entity.User
         **/
        public User selectOne(User user) ;
    }
    
    

    配置UserMapper.xml

    <mapper namespace="com.rangers.IUserDao">
    
        <select id="selectOne" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
            select * from user where id=#{id} and name=#{name}
        </select>
    
        <select id="selectList" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
            select * from user
        </select>
    </mapper>
    

    配置SqlMapConfig.xml,引入UserMapper.xml的路径

    <configuration>
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
        <property name="user" value="root"></property>
        <property name="password" value="111222"></property>
    
        <mapper resource="UserMapper.xml"/>
    </configuration>
    
  3. MyPersistent架构端

    新增依赖

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>1.6.1</version>
    </dependency>
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.2</version>
    </dependency>
    

    新建工具类Resources,加载XML文件为输入流

    package com.rangers.persistent.utils;
    
    import java.io.InputStream;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class Resources {
        /**
         * @Author: Rangers
         * @Description: 加载配置文件
         * @Date: 2021/3/7 4:50 下午
         * @Param path:
         * @Return: java.io.InputStream
         **/
        public static InputStream getResourceAsStream(String path){
            return Resources.class.getClassLoader().getResourceAsStream(path);
        }
    }
    

    新建实体MappedStatement类,对应XxMapper中的标签元素

    package com.rangers.persistent.config.pojo;
    
    /**
     * @Author Rangers
     * @Description 对应Mapper中标签的信息
     * @Date 2021-03-04
     **/
    public class MappedStatement {
        // id当前xml中的唯一标识
        private String id;
    
        // sql语句
        private String sql;
    
        // 参数类型
        private String paramterType;
    
        // 返回结果类型
        private String resultType;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getSql() {
            return sql;
        }
    
        public void setSql(String sql) {
            this.sql = sql;
        }
    
        public String getParamterType() {
            return paramterType;
        }
    
        public void setParamterType(String paramterType) {
            this.paramterType = paramterType;
        }
    
        public String getResultType() {
            return resultType;
        }
    
        public void setResultType(String resultType) {
            this.resultType = resultType;
        }
    }
    

    新建实体Configuration类,对应SqlMapConfig.xml中的元素

    package com.rangers.persistent.config.pojo;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author Rangers
     * @Description 对应SqlMapConfig.xml中的标签
     * @Date 2021-03-04
     **/
    public class Configuration {
    
        // 数据源信息
        private DataSource dataSource;
    
        // 存放Mapper中的所有标签 key为namespace+"."+id
        private Map<String,MappedStatement> mappedStatementMap = new HashMap<>();
    
        public DataSource getDataSource() {
            return dataSource;
        }
    
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        public Map<String, MappedStatement> getMappedStatementMap() {
            return mappedStatementMap;
        }
    
        public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
            this.mappedStatementMap = mappedStatementMap;
        }
    }
    

    新建XmlConfigurationBuilder类,解析SqlMapConfig.xml

    package com.rangers.persistent.config;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import com.rangers.persistent.utils.Resources;
    import com.rangers.persistent.config.pojo.Configuration;
    import org.apache.commons.collections.CollectionUtils;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.beans.PropertyVetoException;
    import java.io.InputStream;
    import java.util.List;
    import java.util.Properties;
    
    /**
     * @Author Rangers
     * @Description 解析SqlMapConfig.xml
     * @Date 2021-03-04
     **/
    public class XmlConfigurationBuilder {
        private Configuration configuration;
    
        public XmlConfigurationBuilder(Configuration configuration) {
            this.configuration = configuration;
        }
    
        public Configuration parseConfiguration(InputStream inputStream) throws PropertyVetoException,DocumentException {
            Document document = new SAXReader().read(inputStream);
            Element rootElement = document.getRootElement();
            // 数据库配置信息进configuration对象
            this.parseDatasource(rootElement);
            // 将Mapper读入configuration对象
            this.parseMappers(rootElement);
            return configuration;
        }
    
        private void parseMappers(Element rootElement) {
            XmlMapperBuilder xmlMapperBuilder = new XmlMapperBuilder(configuration);
            List<Element> mapperElements = rootElement.selectNodes("//mapper");
            if (CollectionUtils.isNotEmpty(mapperElements)){
                mapperElements.forEach(x->{
                    // 获取单个Mapper路径
                    String mapperPath = x.attributeValue("resource");
                    // 获取xml文件
                    InputStream mapperInputStream = Resources.getResourceAsStream(mapperPath);
                    // 解析xml文件存入configuration对象中的mappedStatementMap中
                    xmlMapperBuilder.parse(mapperInputStream);
                });
            }
        }
    
        private void parseDatasource(Element rootElement) throws PropertyVetoException {
            List<Element> propertyElements = rootElement.selectNodes("//property");
    
            Properties properties = new Properties();
            if (CollectionUtils.isNotEmpty(propertyElements)) {
                propertyElements.forEach(x->{
                    properties.setProperty(x.attributeValue("name"),x.attributeValue("value"));
                });
            }
    
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
            comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
            comboPooledDataSource.setUser(properties.getProperty("user"));
            comboPooledDataSource.setPassword(properties.getProperty("password"));
    
            configuration.setDataSource(comboPooledDataSource);
        }
    }
    

    新建XmlMapperBuilder解析XxMapper.xml

    package com.rangers.persistent.config;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import org.apache.commons.collections.CollectionUtils;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description 解析XxMapper.xml
     * @Date 2021-03-04
     **/
    public class XmlMapperBuilder {
        private Configuration configuration;
    
        public XmlMapperBuilder(Configuration configuration) {
            this.configuration = configuration;
        }
    
        public void parse(InputStream inputStream) {
            Document document = null;
            try {
                document = new SAXReader().read(inputStream);
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            Element rootElement = document.getRootElement();
    
            String namespace = rootElement.attributeValue("namespace");
            List<Element> selectElements = rootElement.selectNodes("select");
            if (CollectionUtils.isNotEmpty(selectElements)){
                selectElements.forEach(mapperElement->{
                    String id = mapperElement.attributeValue("id");
                    String sql = mapperElement.getTextTrim();
                    String parameterType = mapperElement.attributeValue("parameterType");
                    String resultType = mapperElement.attributeValue("resultType");
    
                    MappedStatement mappedStatement = new MappedStatement();
                    mappedStatement.setId(id);
                    mappedStatement.setSql(sql);
                    mappedStatement.setParamterType(parameterType);
                    mappedStatement.setResultType(resultType);
                    configuration.getMappedStatementMap().put(namespace+"."+id,mappedStatement);
                });
            }
        }
    
    }
    

    新建SqlSessionFactory、DefaultSqlSessionFactory、SqlSessionFactoryBuilder类生产SqlSessionFactory

    package com.rangers.persistent.sqlSessionFactory;
    
    import com.rangers.persistent.sqlSession.SqlSession;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public interface SqlSessionFactory {
        SqlSession openSession();
    }
    
    package com.rangers.persistent.sqlSessionFactory;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.sqlSession.DefaultSqlSession;
    import com.rangers.persistent.sqlSession.SqlSession;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class DefaultSqlSessionFactory implements SqlSessionFactory{
    
        private Configuration configuration;
    
        public DefaultSqlSessionFactory(Configuration configuration) {
            this.configuration = configuration;
        }
    
        @Override
        public SqlSession openSession() {
            return new DefaultSqlSession(configuration);
        }
    }
    
    package com.rangers.persistent.sqlSessionFactory;
    
    import com.rangers.persistent.config.XmlConfigurationBuilder;
    import com.rangers.persistent.config.pojo.Configuration;
    import org.dom4j.DocumentException;
    
    import java.beans.PropertyVetoException;
    import java.io.InputStream;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class SqlSessionFactoryBuilder {
        private Configuration configuration;
    
        public SqlSessionFactoryBuilder() {
            this.configuration = new Configuration();
        }
    
        public SqlSessionFactory build(InputStream inputStream) throws PropertyVetoException, DocumentException {
            XmlConfigurationBuilder xmlConfigurationBuilder = new XmlConfigurationBuilder(configuration);
            // 将XML文件分装为Configuration/MappedStatement对象中
            Configuration configuration = xmlConfigurationBuilder.parseConfiguration(inputStream);
            return new DefaultSqlSessionFactory(configuration);
        }
    }
    

    新建SqlSession、DefaultSqlSession

    package com.rangers.persistent.sqlSession;
    
    import java.beans.IntrospectionException;
    import java.lang.reflect.InvocationTargetException;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public interface SqlSession {
    
        <E> List<E> selectList(String statementId,Object...param) throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException;
    
        <T> T selectOne(String statementId,Object...param) throws Exception;
    
        void close() throws SQLException;
    
        <T> T getMapper(Class<T> t);
    }
    
    package com.rangers.persistent.sqlSession;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import com.rangers.persistent.executor.Executor;
    import com.rangers.persistent.executor.SimpleExecutor;
    import org.apache.commons.collections.CollectionUtils;
    
    import java.beans.IntrospectionException;
    import java.lang.reflect.*;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class DefaultSqlSession implements SqlSession{
    
        private Configuration configuration;
    
        public DefaultSqlSession(Configuration configuration) {
            this.configuration = configuration;
        }
    
        private Executor executor = new SimpleExecutor();
    
        @Override
        public <E> List<E> selectList(String statementId, Object... params) throws IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException {
            MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
            return executor.query(configuration,mappedStatement,params);
        }
    
        @Override
        public <T> T selectOne(String statementId, Object... params) throws Exception {
            List<Object> objects = this.selectList(statementId, params);
            if (CollectionUtils.isNotEmpty(objects)){
                if (objects.size() == 1){
                    return (T) objects.get(0);
                }else {
                    throw new Exception("存在多条记录");
                }
            }
            return null;
        }
    
        @Override
        public void close() throws SQLException {
            executor.close();
        }
    
        /**
         * @Author Rangers
         * @Description 使用JDK动态代理获取执行的Mapper对象
         **/
        @Override
        public <T> T getMapper(Class<T> t) {
            Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{t}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 全限定性类名==XxMapper.xml的namespace
                    String className = method.getDeclaringClass().getName();
                    // 接口的方法名称==XxMapper.xml的每个mapper标签的id
                    String methodName = method.getName();
    
                    // 1、构造statementID:namespace+"."+id
                    String statementId = className+"."+methodName;
    
                    // 2、定位方法执行,获取执行结果
                    Object result = new Object();
                    // 获取被调用方法的返回值
                    Type returnType = method.getGenericReturnType();
                    if (returnType instanceof ParameterizedType){
                        result = selectList(statementId, args);
                    }else{
                        result = selectOne(statementId,args);
                    }
                    return result;
                }
            });
            return (T) o;
        }
    }
    
    

    新建Executor、SimpleExecutor、BoundSql

    package com.rangers.persistent.executor;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    
    import java.beans.IntrospectionException;
    import java.lang.reflect.InvocationTargetException;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public interface Executor {
    
        <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object...param) throws SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException, ClassNotFoundException;
    
        void close() throws SQLException;
    }
    
    package com.rangers.persistent.executor;
    
    import com.mchange.v2.c3p0.impl.NewProxyPreparedStatement;
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import com.rangers.persistent.utils.GenericTokenParser;
    import com.rangers.persistent.utils.ParameterMapping;
    import com.rangers.persistent.utils.ParameterMappingTokenHandler;
    import org.apache.commons.collections.CollectionUtils;
    
    import java.beans.IntrospectionException;
    import java.beans.PropertyDescriptor;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class SimpleExecutor implements Executor {
    
        private Connection connnection = null;
    
    
        @Override
        public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException, ClassNotFoundException {
            // 1、获取数据库链接
            connnection = configuration.getDataSource().getConnection();
            // 2、解析SQL语句中的#/$,及参数列表,封装为BoundSql对象
            BoundSql boundSql = getBoundSQL(mappedStatement.getSql());
            // 替换后的SQL语句
            String finalSql = boundSql.getSqlText();
            // 3、获取PreparedStatement对象
            PreparedStatement preparedStatement = connnection.prepareStatement(finalSql);
    
            // 4、设置参数
            // 获取传入参数类型
            String parameterType = mappedStatement.getParamterType();
            Class<?> parameterTypeClazz = getClassType(parameterType);
            // 获取SQL语句中需要替换的的参数列表
            List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
            if (CollectionUtils.isNotEmpty(parameterMappingList)) {
                for (int i = 0; i < parameterMappingList.size(); i++) {
                    ParameterMapping parameterMapping = parameterMappingList.get(i);
                    // SQL语句中解析出的占位参数名称
                    String content = parameterMapping.getContent();
    
                    // 利用反射从入参列表中获取数据
                    Field declaredField = parameterTypeClazz.getDeclaredField(content);
                    // 设置暴力访问
                    declaredField.setAccessible(true);
                    // 此处默认传入参数类型为对象
                    Object param = declaredField.get(params[0]);
                    preparedStatement.setObject(i + 1, param);
                }
            }
    
            // 打印执行语句
            this.printSql(preparedStatement);
    
            // 5、执行SQL语句
            ResultSet resultSet = preparedStatement.executeQuery();
    
            // 6、封装返回结果集
            // 获取SQL的执行结果类型
            String resultType = mappedStatement.getResultType();
            Class<?> resultTypeClazz = getClassType(resultType);
            List<E> results = new ArrayList<>();
            // 遍历封装结果集为返回值类型
            while (resultSet.next()) {
                // 获取结果集的元数据
                ResultSetMetaData metaData = resultSet.getMetaData();
                E e = (E) resultTypeClazz.newInstance();
                if (metaData.getColumnCount() > 0) {
                    for (int i = 1; i <= metaData.getColumnCount(); i++) {
                        // 字段名称
                        String columnName = metaData.getColumnName(i);
                        // 字段值
                        Object columnValue = resultSet.getObject(columnName);
    
                        // 使用反射或者内省,根据数据库表与实体的对应关系,完成结果集封装
                        PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultTypeClazz);
                        Method writeMethod = propertyDescriptor.getWriteMethod();
                        writeMethod.invoke(e,columnValue);
                    }
                }
                results.add(e);
            }
            return results;
        }
    
        private void printSql(PreparedStatement preparedStatement) throws NoSuchFieldException, IllegalAccessException {
            NewProxyPreparedStatement tmpPs = (NewProxyPreparedStatement) preparedStatement;
            Field inner = preparedStatement.getClass().getDeclaredField("inner");
            inner.setAccessible(true);
            String sqlLog = inner.get(tmpPs).toString();
            System.out.println("执行SQL:"+sqlLog.substring(sqlLog.lastIndexOf(":")+1));
        }
    
        private Class<?> getClassType(String type) throws ClassNotFoundException {
            if (type != null && type!="") {
                return Class.forName(type);
            }
            return null;
        }
    
        private BoundSql getBoundSQL(String sql) {
            ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
            GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
            String parseSql = genericTokenParser.parse(sql);
            List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
            return new BoundSql(parseSql, parameterMappings);
        }
    
        @Override
        public void close() throws SQLException {
            connnection.close();
        }
    }
    
    package com.rangers.persistent.executor;
    
    
    import com.rangers.persistent.utils.ParameterMapping;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class BoundSql {
    
        private String sqlText; //解析过后的sql
    
        private List<ParameterMapping> parameterMappingList = new ArrayList<>();
    
        public BoundSql(String sqlText, List<ParameterMapping> parameterMappingList) {
            this.sqlText = sqlText;
            this.parameterMappingList = parameterMappingList;
        }
    
        public String getSqlText() {
            return sqlText;
        }
    
        public void setSqlText(String sqlText) {
            this.sqlText = sqlText;
        }
    
        public List<ParameterMapping> getParameterMappingList() {
            return parameterMappingList;
        }
    
        public void setParameterMappingList(List<ParameterMapping> parameterMappingList) {
            this.parameterMappingList = parameterMappingList;
        }
    }
    

    新增SQL解析工具类ParameterMapping、GenericTokenParser、TokenHandler、ParameterMappingTokenHandler

    package com.rangers.persistent.utils;
    
    public class ParameterMapping {
    
        private String content;
    
        public ParameterMapping(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    }
    
    package com.rangers.persistent.utils;
    
    /**
     * @author Clinton Begin
     */
    public class GenericTokenParser {
    
      private final String openToken; //开始标记
      private final String closeToken; //结束标记
      private final TokenHandler handler; //标记处理器
    
      public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
        this.openToken = openToken;
        this.closeToken = closeToken;
        this.handler = handler;
      }
    
      /**
       * 解析${}和#{}
       * @param text
       * @return
       * 该方法主要实现了配置文件、脚本等片段中占位符的解析、处理工作,并返回最终需要的数据。
       * 其中,解析工作由该方法完成,处理工作是由处理器handler的handleToken()方法来实现
       */
      public String parse(String text) {
        // 验证参数问题,如果是null,就返回空字符串。
        if (text == null || text.isEmpty()) {
          return "";
        }
    
        // 下面继续验证是否包含开始标签,如果不包含,默认不是占位符,直接原样返回即可,否则继续执行。
        int start = text.indexOf(openToken, 0);
        if (start == -1) {
          return text;
        }
    
       // 把text转成字符数组src,并且定义默认偏移量offset=0、存储最终需要返回字符串的变量builder,
        // text变量中占位符对应的变量名expression。判断start是否大于-1(即text中是否存在openToken),如果存在就执行下面代码
        char[] src = text.toCharArray();
        int offset = 0;
        final StringBuilder builder = new StringBuilder();
        StringBuilder expression = null;
        while (start > -1) {
         // 判断如果开始标记前如果有转义字符,就不作为openToken进行处理,否则继续处理
          if (start > 0 && src[start - 1] == '\\') {
            builder.append(src, offset, start - offset - 1).append(openToken);
            offset = start + openToken.length();
          } else {
            //重置expression变量,避免空指针或者老数据干扰。
            if (expression == null) {
              expression = new StringBuilder();
            } else {
              expression.setLength(0);
            }
            builder.append(src, offset, start - offset);
            offset = start + openToken.length();
            int end = text.indexOf(closeToken, offset);
            while (end > -1) {存在结束标记时
              if (end > offset && src[end - 1] == '\\') {//如果结束标记前面有转义字符时
                // this close token is escaped. remove the backslash and continue.
                expression.append(src, offset, end - offset - 1).append(closeToken);
                offset = end + closeToken.length();
                end = text.indexOf(closeToken, offset);
              } else {//不存在转义字符,即需要作为参数进行处理
                expression.append(src, offset, end - offset);
                offset = end + closeToken.length();
                break;
              }
            }
            if (end == -1) {
              // close token was not found.
              builder.append(src, start, src.length - start);
              offset = src.length;
            } else {
              //首先根据参数的key(即expression)进行参数处理,返回?作为占位符
              builder.append(handler.handleToken(expression.toString()));
              offset = end + closeToken.length();
            }
          }
          start = text.indexOf(openToken, offset);
        }
        if (offset < src.length) {
          builder.append(src, offset, src.length - offset);
        }
        return builder.toString();
      }
    }
    
    package com.rangers.persistent.utils;
    
    /**
     * @author Clinton Begin
     */
    public interface TokenHandler {
      String handleToken(String content);
    }
    
    package com.rangers.persistent.utils;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ParameterMappingTokenHandler implements TokenHandler {
       private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
    
       // context是参数名称 #{id} #{username}
    
       @Override
       public String handleToken(String content) {
          parameterMappings.add(buildParameterMapping(content));
          return "?";
       }
    
       private ParameterMapping buildParameterMapping(String content) {
          ParameterMapping parameterMapping = new ParameterMapping(content);
          return parameterMapping;
       }
    
       public List<ParameterMapping> getParameterMappings() {
          return parameterMappings;
       }
    
       public void setParameterMappings(List<ParameterMapping> parameterMappings) {
          this.parameterMappings = parameterMappings;
       }
    
    }
    
  4. 新建测试类MypersistentTest

    package com.rangers.mypersistent;
    
    import com.rangers.IUserDao;
    import com.rangers.entity.User;
    import com.rangers.persistent.sqlSession.SqlSession;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactory;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactoryBuilder;
    import com.rangers.persistent.utils.Resources;
    import org.dom4j.DocumentException;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.beans.PropertyVetoException;
    import java.io.InputStream;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * @Author Rangers
     * @Description
     * @Date 2021-03-04
     **/
    public class MypersistentTest {
    
        private SqlSession sqlSession;
    
        @Before
        public void before() throws PropertyVetoException, DocumentException {
            // 加载配置文件
            InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
            // 解析XML文件为对象,构造SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            sqlSession = sqlSessionFactory.openSession();
        }
    
        @Test
        public void selectList() throws Exception {
            List<User> users = sqlSession.selectList("com.rangers.entity.User.selectList", null);
            System.out.println(users.toString());;
        }
    
        @Test
        public void selectOne() throws Exception {
            User user = new User();
            user.setId(2);
            user.setName("莉莉");
            User result = sqlSession.selectOne("com.rangers.entity.User.selectOne", user);
            System.out.println(result.toString());
        }
    
        @Test
        public void mapperSelectOne() throws Exception {
            User userParam = new User();
            userParam.setId(2);
            userParam.setName("莉莉");
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
            User result = userDao.selectOne(userParam);
            System.out.println(result.toString());
        }
    
        @Test
        public void mapperSelectAll() throws Exception {
            IUserDao userDao = sqlSession.getMapper(IUserDao.class);
            List<User> result = userDao.selectList();
            System.out.println(result.toString());
        }
    
        @After
        public void after() throws SQLException {
            sqlSession.close();
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值