代码已上传至码云:https://gitee.com/rangers-sun/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();
    }
    }

MyBatis(三):自定义持久层框架实现的更多相关文章

  1. MyBatis(四):自定义持久层框架优化

    本文所有代码已上传至码云:https://gitee.com/rangers-sun/mybatis 修改IUserDao.UserMapper.xml package com.rangers; im ...

  2. MyBatis(二):自定义持久层框架思路分析

    使用端 引入架构端Maven依赖 SqlMapConfig.xml-数据库配置信息(数据库连接jar名称.连接URL.用户名.密码),引入Mapper.xml的路径 XxMapper.xml-SQL配 ...

  3. Mybatis学习之自定义持久层框架(三) 自定义持久层框架:读取并解析配置文件

    前言 前两篇文章分别讲解了JDBC和Mybatis的基本知识,以及自定义持久层框架的设计思路,从这篇文章开始,我们正式来实现一个持久层框架. 新建一个项目 首先我们新建一个maven项目,将其命名为I ...

  4. Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架

    目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPersistence_Test编写 1.3.1 XXXMapper.xml详解 1.3.2 ...

  5. 【笔记】拉勾Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架

    以下笔记是我看完视频之后总结整理的,部分较为基础的知识点也做了补充,如有问题欢迎沟通. 目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPe ...

  6. Mybatis学习之自定义持久层框架(六) 自定义持久层框架:完善CRUD方法并进行测试

    前言 没想到会等到半年以后才来写这篇文章,我已经不记得当初自己想要在这篇文章中写什么了,还好有一些零散的笔记留着,就对照着上一篇文章及零散的笔记,把内容给补充完吧. 完善CRUD方法 完善Defaul ...

  7. Mybatis学习之自定义持久层框架(二) 自定义持久层框架设计思路

    前言 上一篇文章讲到了JDBC的基本用法及其问题所在,并提出了使用Mybatis的好处,那么今天这篇文章就来说一下该如何设计一个类似Mybatis这样的持久层框架(暂时只讲思路,具体的代码编写工作从下 ...

  8. Mybatis学习之自定义持久层框架(七) 自定义持久层框架优化

    前言 接上文,这里只是出于强迫症,凭借着半年前的笔记来把之前没写完的文章写完,这里是最后一篇了. 前面自定义的持久层框架存在的问题 Dao层若使用实现类,会存在代码重复,整个操作的过程模版重复(加载配 ...

  9. Mybatis学习之自定义持久层框架(一) 为什么要用框架而不直接用JDBC?

    前言 说起Mybatis,相信大家都不会感到陌生,它是一款优秀的持久层框架,应用于java后端开发中,为客户端程序提供访问数据库的接口. 我们都知道,JDBC是Java语言中用来规范客户端程序如何来访 ...

随机推荐

  1. WSL ubuntu重置密码

    1. 在powershell中切换到root: 2. 进入ubuntu: 3. 修改制定用户的密码: 4. 切换回默认的用户:

  2. CF1474-A. Puzzle From the Future

    CF1474-A. Puzzle From the Future 题意: 有两个由\(0,1\)组成的.长度相等字符串\(a, b\),两个字符串按位相加得到一个新的字符串\(s\),对\(s\)取\ ...

  3. kafka——集群安裝部署(自带zookeeper)

    kafka系列文章 第一章 linux单机安装kafka 第二章 kafka--集群安裝部署(自带zookeeper) 一.kafka简介 kafka官网:http://kafka.apache.or ...

  4. c++ cin 读入txt的问题

    源程序 #include <iostream> using namespace std; struct Stack { int tos; int stackarray[1000]; }; ...

  5. 洛谷p2216 多次单调队列,扫描矩阵中的最大值减去最小值最的固定大小子矩阵

    #include <iostream> #include <cstdio> #include <cstring> using namespace std; int ...

  6. 快速搞懂.NET 5/.NET Core应用程序的发布部署

    .NET Framework时代,.NET 应用程序大多直接部署运行在Windows服务器上,当然也可以通过Mono部署运行在Linux上.无论部署exe,还是IIS站点.或是Windows Serv ...

  7. Storybook 最新教程

    Storybook 最新教程 Storybook is the most popular UI component development tool for React, Vue, and Angul ...

  8. git branch All In One

    git branch All In One Git Branch Management https://git-scm.com/book/en/v2/Git-Branching-Branch-Mana ...

  9. Arctic Code Vault Contributor

    Arctic Code Vault Contributor GitHub Archive Program https://archiveprogram.github.com/ Preserving o ...

  10. Flutter Vignettes

    Flutter Vignettes Flutter Animation https://flutter.gskinner.com/ https://github.com/gskinnerTeam/fl ...