代码已上传至码云: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. WPF 之路由事件和附加事件(六)

    一.消息驱动与直接事件模型 ​ 事件的前身是消息(Message).Windows 是消息驱动的系统,运行其上的程序也遵循这个原则.消息的本质就是一条数据,这条消息里面包含着消息的类别,必要的时候还记 ...

  2. 浅谈Webpack模块打包工具三

    Source Map 生产代码与开发代码完全不同,如果需要调试应用的话会非常的麻烦,错误信息无法定位,Soutce Map就会逆向得到源代码, 须在打包之后的代码文件的末尾位置例如添加//# sour ...

  3. 在.NET中体验GraphQL

    前言 以前需要提供Web服务接口的时候,除了标准的WEBAPI形式,还考虑了OData.GraphQL等形式,虽然实现思路上有很大的区别,但对使用方来说,都是将查询的主动权让渡给了前端,让调用方能够更 ...

  4. 解决M1 MacBook无法使用pip安装Numpy

    问题描述 Python官方已发布支持M1 Apple Silicon的版本,但是在使用pip包管理工具安装一些依赖时发生了错误,这里面就包括在科学计算领域常用的numpy.pandas等.目前可以通过 ...

  5. [视频] Docker 安装 nginx + rtmp

    目录 拉取镜像 创建并运行容器,映射出两个端口1935.80 将视频文件推流至rtmp服务器 使用ffplay播放rtmp流 拉取镜像 docker pull alfg/nginx-rtmp 创建并运 ...

  6. Shpfile文件的字段类型说明

    Shpfile文件的字段类型设置如下表所示: 字段类型 字符 字段长度 长整型 N 9 短整型 N 4 浮点型 F 13 双精度 F 19 文本 C 50 特别需要注意的是字段长度,在导出SHP的时候 ...

  7. codeforces 1016C - Vasya And The Mushrooms 【构造 + 思维】

    题目链接:戳这里 题意:从(1,1)出发,一遍把格子走完,每个格子只能走一次.问怎么走总和最大. 解题思路:画图可知,总共就3种走法的混合. dw: 样例1的走法 up: 样例1反过来的走法 lp: ...

  8. 信号量解决理发师问题(barber)

    问题描述及思路         代码 一些细节见注释 这里ret应该用int..忘了改了.         运行结果 因为座位数和到来最大间隔的原因,没有出现全部椅子被占用的情况  

  9. 读js DOM编程艺术总结

    第一章主要介绍一些历史性问题,javascript是Netcape和sun公司合作开发的. 第二章JavaScript语法: 1,数据类型:(弱类型)字符串,数值,布尔值(只有true和false,不 ...

  10. HHVM的全称是"HipHop for PHP",开放源代码。采用PHP许可证授权!

    http://hhvm.com/ https://github.com/xgqfrms/hhvm 什么是HHVM高性能服务器? HHVM是由Facebook公司出品的高性能开源服务器,用来执行hack ...