一、自定义持久层框架

1.分析JDBC操作问题

package com.cookie.jdbc.test;import com.cookie.jdbc.domain.User;
import java.sql.*;public class TestJdbc {public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {// 加载数据库驱动Class.forName("com.mysql.jdbc.Driver");// 通过驱动管理类获取数据库链接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "123456");// 定义sql语句?表示占位符String sql = "select * from user where username = ?";// 获取预处理statementpreparedStatement = connection.prepareStatement(sql);// 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值preparedStatement.setString(1,"tom");// 向数据库发出sql执⾏查询,查询出结果集resultSet = preparedStatement.executeQuery();while(resultSet.next()){User user = new User();int id = resultSet.getInt("id");String username = resultSet.getString("username");// 封装Useruser.setId(id);user.setUsername(username);System.out.println(user);}} catch (Exception e) {e.printStackTrace();}finally {//释放资源if (resultSet != null){try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (preparedStatement != null){try {preparedStatement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null){try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

sql:

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) DEFAULT NULL,`password` varchar(50) DEFAULT NULL,`birthday` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'lucy', '123', '2019-12-12');
INSERT INTO `user` VALUES ('2', 'tom','123', '2019-12-12');

JDBC问题总结:
原始jdbc开发存在的问题如下:
1、 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。
2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大, sql变动需要改变 java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名), sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便

2.问题解决思路

①使用数据库连接池初始化连接资源
②将sql语句抽取到xml配置文件中
③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射

3.自定义框架设计

3.1 使用端:

  • 引入持久层框架的jar包
  • 提供两部分配置信息,数据库信息、sql配置信息(sql语句、参数类型、返回值类型)
  • 提供核心配置文件:①sqlMapConfig.xml :存放数据源信息,引入mapper.xml,存放mapper.xml的全路径②Mapper.xml:sql语句的配置文件信息

3.2 框架端:

  1. 加载读取配置文件:根据配置文件的路径加载文件成字节输入流,存储在内存中

创建Resources类,方法:InputStream getResourceAsSteam(String path)

  1. 创建2个javaBean,存放的是配置文件解析出来的内容
    1. Configuration:核心配置类,存放sqlMapConfig.xml解析出来的内容
    2. MappedStatement:映射配置类,存放Mapper.xml解析出来的内容
  2. 解析配置文件:dom4j
    1. 创建类:SqlSessionFactoryBuilder 方法:build(InputStream in)
    2. 1.使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
    3. 2.创建SqlSessionFactory 对象,产生sqlSession:会话对象(工厂模式)
  3. 创建SqlSessionFactory 接口及实现类DefaultSqlSessionFactory
    1. 1.openSession(): 生产sqlSession
  4. 创建sqlSession接口及实现类DefaultSqlSession
    1. 定义对数据库的crud操作:selectList() selectOne() update() delete()
  5. 创建Executor接口及实现类SimpleExecutor实现类
    1. query(Configuration,MappedStatement,Object…param):执行JDBC代码

4. 自定义框架实现

在使用端项目中创建配置配置文件创建 sqlMapConfig.xml

<configuration><dataSource><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property><property name="username" value="root"></property><property name="password" value="123456"></property></dataSource><!--存放mapper.xml的全路径--><mapper resource = "UserMapper.xml"></mapper>
</configuration>
<mapper namespace="user"><!--sql的唯一标识:namespace.id组成 :statementId --><select id="selectList" resultType="com.cookie.pojo.User">select * from user</select><!--多个参数传递封装对象--><select id="selectOne" resultType="com.cookie.pojo.User" paramType="com.cookie.pojo.User">select * from user where id = #{id} and username = #{username}</select>
</mapper>
package com.cookie.pojo;public class User {private Integer id;private String username;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +'}';}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>mybatis</artifactId><groupId>com.cookie</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>simple-mybatis-test</artifactId><dependencies><dependency><groupId>com.cookie</groupId><artifactId>simple-mybatis</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
package com.cookie.test;import com.cookie.io.Resources;
import com.cookie.pojo.User;
import com.cookie.sqlSession.SqlSession;
import com.cookie.sqlSession.SqlSessionFactory;
import com.cookie.sqlSession.SqlSessionFactoryBuilder;
import org.dom4j.DocumentException;
import org.junit.Test;import java.beans.IntrospectionException;
import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;public class SimpleTest {@Testpublic void test() throws DocumentException, PropertyVetoException, ClassNotFoundException, IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {InputStream inputStream = Resources.getResourceAsSteam("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();User user = new User();user.setId(2);user.setUsername("tom");User u = sqlSession.selectOne("user.selectOne", user);System.out.println(u);}
}

再创建一个Maven子工程并且导入需要用到的依赖坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>mybatis</artifactId><groupId>com.cookie</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>simple-mybatis</artifactId><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.17</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.10</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><dependency><groupId>jaxen</groupId><artifactId>jaxen</artifactId><version>1.1.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>7</source><target>7</target></configuration></plugin></plugins></build>
</project>
package com.cookie.pojo;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;public class Configuration {private DataSource dataSource;private Map<String,MapperStatement> map = new HashMap<>();public DataSource getDataSource() {return dataSource;}public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}public Map<String, MapperStatement> getMap() {return map;}public void setMap(Map<String, MapperStatement> map) {this.map = map;}
}
package com.cookie.pojo;public class MapperStatement {//id标识private String id;//返回值private String resultType;//参数值类型private String paramType;//sql语句private String sql;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getResultType() {return resultType;}public void setResultType(String resultType) {this.resultType = resultType;}public String getParamType() {return paramType;}public void setParamType(String paramType) {this.paramType = paramType;}public String getSql() {return sql;}public void setSql(String sql) {this.sql = sql;}
}
package com.cookie.io;import java.io.InputStream;public class Resources {public static InputStream getResourceAsSteam(String path){//根据配置文件的路径将配置文件加载成字节输入流InputStream inputStream = Resources.class.getClassLoader().getResourceAsStream(path);return inputStream;}
}
package com.cookie.sqlSession;import com.cookie.config.XMLConfigBuilder;
import com.cookie.pojo.Configuration;
import org.dom4j.DocumentException;import java.beans.PropertyVetoException;
import java.io.InputStream;public class SqlSessionFactoryBuilder {public SqlSessionFactory build(InputStream in) throws PropertyVetoException, DocumentException, ClassNotFoundException {//第一,使用dom4j解析配置文件,将解析出来的内容封装到Configuration中XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();Configuration configuration = xmlConfigBuilder.parseConfig(in);//第二、创建sqlSessionFactory对象 工厂类:生产sqlSession:会话对象DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);return defaultSqlSessionFactory;}}
package com.cookie.config;import com.cookie.io.Resources;
import com.cookie.pojo.Configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
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;public class XMLConfigBuilder {private Configuration configuration;public XMLConfigBuilder() {this.configuration = new Configuration();}/*** 该方法就是将配置文件进行解析,封装Configuration* @param inputStream* @return*/public Configuration parseConfig(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException {Document document = new SAXReader().read(inputStream);Element rootElement = document.getRootElement();List<Element> list = rootElement.selectNodes("//property");Properties properties = new Properties();for (Element element : list) {String name = element.attributeValue("name");String value = element.attributeValue("value");properties.setProperty(name,value);}ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));comboPooledDataSource.setUser(properties.getProperty("username"));comboPooledDataSource.setPassword(properties.getProperty("password"));configuration.setDataSource(comboPooledDataSource);List<Element> mapperElements = rootElement.selectNodes("//mapper");XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);for (Element mapperElement : mapperElements) {String resource = mapperElement.attributeValue("resource");InputStream resourceAsSteam = Resources.getResourceAsSteam(resource);xmlMapperBuilder.parse(resourceAsSteam);}return configuration;}
}
package com.cookie.config;import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;
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;public class XMLMapperBuilder {private Configuration configuration;public XMLMapperBuilder(Configuration configuration) {this.configuration = configuration;}public void parse(InputStream inputStream) throws DocumentException, ClassNotFoundException {Document document = new SAXReader().read(inputStream);Element rootElement = document.getRootElement();String namespace = rootElement.attributeValue("namespace");List<Element> select = rootElement.selectNodes("select");for (Element element : select) {String id = element.attributeValue("id");String paramType = element.attributeValue("paramType");String resultType = element.attributeValue("resultType");String sql = element.getTextTrim();
/*//输入参数classClass<?> paramterTypeClass = getClassType(paramterType);//返回结果classClass<?> resultTypeClass = getClassType(resultType);
*///statementIdString key = namespace + "." +id;//封装 mappedStatementMapperStatement mapperStatement = new MapperStatement();mapperStatement.setId(id);mapperStatement.setResultType(resultType);mapperStatement.setParamType(paramType);mapperStatement.setSql(sql);configuration.getMap().put(key, mapperStatement);}}private Class<?> getClassType(String paramterType) throws ClassNotFoundException {Class<?> aClass = Class.forName(paramterType);return aClass;}
}
package com.cookie.sqlSession;public interface SqlSessionFactory {SqlSession openSession();}
package com.cookie.sqlSession;import com.cookie.pojo.Configuration;public class DefaultSqlSessionFactory implements SqlSessionFactory {private Configuration configuration;public DefaultSqlSessionFactory(Configuration configuration) {this.configuration = configuration;}@Overridepublic SqlSession openSession() {return new DefaultSqlSession(configuration);}
}
package com.cookie.sqlSession;import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;public interface SqlSession {//查询所有<E> List<E> selectList(String statementid,Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException;//根据条件查询单个<T> T selectOne(String statementid,Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException;}
package com.cookie.sqlSession;import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;public class DefaultSqlSession implements SqlSession {private Configuration configuration;public DefaultSqlSession(Configuration configuration) {this.configuration = configuration;}@Overridepublic <E> List<E> selectList(String statementid, Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException {//完成simpleExecutor里的MapperStatement mapperStatement = configuration.getMap().get(statementid);SimpleExecutor simpleExecutor = new SimpleExecutor();List<Object> list = simpleExecutor.query(configuration, mapperStatement, params);return (List<E>) list;}@Overridepublic <T> T selectOne(String statementid, Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {List<Object> objects = selectList(statementid, params);if (objects.size() == 1){return (T)objects.get(0);}else {throw new RuntimeException("查询结果为空或返回结果过多");}}
}
package com.cookie.sqlSession;import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;public interface Executor {<E> List<E> query(Configuration configuration, MapperStatement mapperStatement,Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException;
}
package com.cookie.sqlSession;import com.cookie.config.BoundSql;
import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;
import com.cookie.utils.GenericTokenParser;
import com.cookie.utils.ParameterMapping;
import com.cookie.utils.ParameterMappingTokenHandler;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;public class SimpleExecutor implements Executor {@Overridepublic <E> List<E> query(Configuration configuration, MapperStatement mapperStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException {//1.注册驱动,获取链接Connection connection = configuration.getDataSource().getConnection();//2.获取sql语句 :select * from user where id = #{id} and username = #{username}//转换sql语句   select * from where id = ? and username = ?//转换过程中对#{}里的值解析存储String sql = mapperStatement.getSql();BoundSql boundSql = getBoundSql(sql);//3.获取预处理对象:preparedStatementPreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());//4.设置参数String paramType = mapperStatement.getParamType();Class<?> paramTypeClass = getClassType(paramType);List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();for (int i = 0; i < parameterMappingList.size(); i++) {ParameterMapping parameterMapping = parameterMappingList.get(i);String content = parameterMapping.getContent();//反射Field declaredField = paramTypeClass.getDeclaredField(content);//暴力访问declaredField.setAccessible(true);Object o = declaredField.get(params[0]);preparedStatement.setObject(i+1,o);}//5.执行sqlResultSet resultSet = preparedStatement.executeQuery();//6.封装返回结果值String resultType = mapperStatement.getResultType();Class<?> resultTypeClass = getClassType(resultType);ArrayList<Object> objects = new ArrayList<>();while(resultSet.next()){Object o = resultTypeClass.newInstance();ResultSetMetaData metaData = resultSet.getMetaData();for (int i = 1;i <= metaData.getColumnCount(); i++){//字段名String columnName = metaData.getColumnName(i);//字段的值Object object = resultSet.getObject(columnName);//使用反射或者内省,根据数据库表和实体的对应关系完成封装PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);Method writeMethod = propertyDescriptor.getWriteMethod();writeMethod.invoke(o,object);}objects.add(o);}return (List<E>) objects;}/*** 完成对#{}的解析 1.将#{}使用?进行代替 2.将#{}的值进行存储* @param sql* @return*/private BoundSql getBoundSql(String sql) {//标记处理类:配合标记解析器来对标记占位符来进行处理工作ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);//解析出来的sqlString parse = genericTokenParser.parse(sql);//#{}里解析出来的参数名称List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();BoundSql boundSql = new BoundSql(parse,parameterMappings);return boundSql;}private Class<?> getClassType(String paramterType) throws ClassNotFoundException {Class<?> aClass = Class.forName(paramterType);return aClass;}
}
package com.cookie.config;import com.cookie.utils.ParameterMapping;import java.util.ArrayList;
import java.util.List;public class BoundSql {private String sqlText;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;}
}

5. 自定义框架优化

自定义框架解决了JDBC操作数据库带来的一些问题:例如频繁创建释放数据库连接,硬编码,手动封装返回结果集等问题。
自定义框架代码,仍有如下问题:

  1. dao的实现类中存在重复的代码,整个操作的过程模板重复(创建sqlsession,调用sqlsession方法,关闭sqlsession)
  2. dao的实现类中存在硬编码,调用sqlsession的方法时,参数statement的id硬编码

解决:使用代理模式来创建接口的代理对象(不用Dao接口实现类)

public interface SqlSession {//查询所有<E> List<E> selectList(String statementid,Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException;//根据条件查询单个<T> T selectOne(String statementid,Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException;//为Dao接口生成代理实现类<T> T getMapper(Class<?> mapperClass);}
public class DefaultSqlSession implements SqlSession {private Configuration configuration;public DefaultSqlSession(Configuration configuration) {this.configuration = configuration;}@Overridepublic <E> List<E> selectList(String statementid, Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException {//完成simpleExecutor里的MapperStatement mapperStatement = configuration.getMap().get(statementid);SimpleExecutor simpleExecutor = new SimpleExecutor();List<Object> list = simpleExecutor.query(configuration, mapperStatement, params);return (List<E>) list;}@Overridepublic <T> T selectOne(String statementid, Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {List<Object> objects = selectList(statementid, params);if (objects.size() == 1){return (T)objects.get(0);}else {throw new RuntimeException("查询结果为空或返回结果过多");}}@Overridepublic <T> T getMapper(Class<?> mapperClass) {//使用JDK动态代理来为Dao接口生成代理对象,并返回Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//底层还是执行JDBC代码 //根据不同情况,来调用selectList或者selectOne//准备参数 1:statementId : sql语句的唯一标识:namespace.id=接口全限定名.方法名//方法名:findAllString methedName = method.getName();String className = method.getDeclaringClass().getName();String statementId = className + "." + methedName;//准备参数2:params:args//获取被调用方法的返回值类型Type returnType = method.getGenericReturnType();//判断是否进行了泛型类型参数化if (returnType instanceof ParameterizedType){List<Object> objects = selectList(statementId, args);return objects;}return selectOne(statementId, args);}});return (T)o;}
}
public interface UserDao {//查询所有List<User> findAll() throws Exception;//根据条件查询单个User findByCondition(User user) throws Exception;}
<mapper namespace="com.cookie.dao.UserDao"><!--sql的唯一标识:namespace.id组成 :statementId --><select id="findAll" resultType="com.cookie.pojo.User">select * from user</select><!--多个参数传递封装对象--><select id="findByCondition" resultType="com.cookie.pojo.User" paramType="com.cookie.pojo.User">select * from user where id = #{id} and username = #{username}</select></mapper>
    @Testpublic void testMappeer() throws Exception {InputStream inputStream = Resources.getResourceAsSteam("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();User user = new User();user.setId(2);user.setUsername("tom");UserDao userDao = sqlSession.getMapper(UserDao.class);List<User> all = userDao.findAll();all.forEach(System.out::println);User user1 = userDao.findByCondition(user);System.out.println(user1);}