面向对象的设计:
面向对象的设计:
a)类的定义
能独立描述一个信息,比如说:配置文件信息、映射文件信息、学生、老师
能独立针对描述的信息,提供对应的功能
b)类的粒度划分
根据业务(用户【VIP用户/普通用户/高端用户】)
根据经验(借鉴别人经验,要有试错精神)
c)类的复用性考虑
类的拆分的
d)类的隔离性
当某些功能发生改变的时候,我们是不想将影响范围扩大的。
注意事项:基本上牵扯到设计层面的东西,都不是一锤子能搞定的事情。
比如说需求设计、UI设计、面向对象设计等设计是一个不断优化,不断积累经验的过程。
mybatis3.0版本分析
a)解析流程
* 全局配置文件 解析类 XMLConfigBuilder(configuration根标签)
<environments>
<mappers>
* 映射配置文件 解析类 XMLMapperBuilder(mapper根标签)
<select> Statement解析 XMLStatementBuilder(select标签)
SQL文本和动态标签 XMLScriptBuilder
<update> Statement解析
SQL文件
动态标签
* 解析工具类 Dom解析相关的工具类 ,专门封装的第三方的API
b) 执行流程(考虑框架设计的初衷)
* 对外提供方便程序员调用的执行接口(程序员不想关注JDBC或者mybatis处理细节) --- 设计接口(对外提供CRUD操作)
* SqlSession内部去执行JDBC处理逻辑
* 执行JDBC代码的逻辑,可以封装到一个专业的类去处理 ---- Executor
* Executor分为使用二级缓存去处理、使用一级缓存去处理、不使用缓存去处理 --- CachingExecutor、BaseExecutor(抽象类)、SimpleExecutor、BatchExecutor
各类分析
封装数据的类
Configuration:封装数据、提供对该数据操作的功能接口
MappedStatement
SqlSource:封装数据、提供对该数据操作的功能接口
...
SqlNode:封装数据、提供对该数据操作的功能接口
...
BoundSql
ParameterMapping
封装业务功能的类
解析流程
XMLConfigBuilder:????
XMLMapperBuilder:????
XMLStatementBuilder:????
XMLScriptBuilder:????
SqlSourceParser:封装#{}解析功能,便于复用
执行流程
SqlSessionFactoryBuilder类(构建者模式)
SqlSessionFactoty接口(工厂方法设计模式)
???
SqlSession接口
???
Executor接口:四大组件之一
CachingExecutor:缓存执行器,主要针对二级缓存
BaseExecutor:抽取共性的一级缓存功能(抽象模板方法设计模式)
SimpleExecutor:简单执行器
ReuseExecutor:Statement可重用的执行器
BatchExecutor:可批处理的执行器
Executor--->StatementHandler---->ParameterHandler\ParameterHandler
StatementHandler接口(策略模式):将statement的相关操作进行抽象并封装
PreparedStatementHandler:专门去执行statementType为prepared
SimpleStatementHandler:专门去执行statementType为simple
CallableStatementHandler:专门去执行statementType为callable
ParameterHandler:专门去处理参数设置的
DeafultParameterHandler
ResultSetHandler:
DefaultResultSetHandler
全局配置文件
<configuration>
<!-- mybatis 数据源环境配置 -->
<environments default="dev">
<environment id="dev">
<!-- 配置数据源信息 -->
<dataSource type="DBCP">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://XXX"></property>
<property name="username" value="XXX"></property>
<property name="password" value="XXX"></property>
</dataSource>
</environment>
</environments>
<!-- 映射文件加载 -->
<mappers>
<!-- resource指定映射文件的类路径 -->
<mapper resource="mapper/UserMapper.xml"></mapper>
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
<!-- <mapper resource="mapper/UserMapper.xml"></mapper> -->
</mappers>
</configuration>
映射文件
<mapper namespace="test">
<!-- select标签,封装了SQL语句信息、入参类型、结果映射类型 -->
<select id="findUserById"
parameterType="com.kkb.mybatis.po.User"
resultType="com.kkb.mybatis.po.User" statementType="prepared">
SELECT * FROM user WHERE id = #{id}
<!-- SELECT * FROM user WHERE id = #{id} AND username like '%${username}' -->
<!-- and sex = #{sex} AND username like '%${username}' -->
<if test="username != null and username !='' ">
AND username like '%${username}'
<if test="username != null and username !=''">
AND 1=1
</if>
</if>
</select>
</mapper>
测试代码
根据测试代码,debug模式一步步按照调用顺序贴出来
@Test
public void testQueryUserById() {
// 1.指定全局配置文件路径
String location = "mybatis-config.xml";
// 2.加载配置文件成InputStream
// 思考:到底想根据路径获取的是字节流还是字符流
InputStream inputStream = Resources.getResourceAsStream(location);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// SqlSession表示一个SQL会话,每次都new,如果对于SqlSession的创建细节,程序员不想关注
// 此时可以将SqlSession交给专业的Factory去生产
SqlSession sqlSession = sqlSessionFactory.openSqlSession();
String statementId = "test" + "." + "findUserById";
User user = new User();
user.setId(1);
// user.setUsername("王五");
List<User> users = sqlSession.selectList(statementId, user);
System.out.println(users);
}
mybatis.io包下
Resources 类
public class Resources {
public static InputStream getResourceAsStream(String location) {
return Resources.class.getClassLoader().getResourceAsStream(location);
}
public static Reader getResourceAsReader(String location) {
// TODO
return null;
}
}
mybatis.sqlsession 包
SqlSessionFactoryBuilder 类
- 使用构建者模式
public class SqlSessionFactoryBuilder {
// 构建者通过这个public的api去接收外部的建造条件
public SqlSessionFactory build(InputStream inputStream) {
Document document = DocumentUtils.loadDocument(inputStream);
XMLConfigBuilder configBuilder = new XMLConfigBuilder();
Configuration configuration = configBuilder.parse(document.getRootElement());
return build(configuration);
}
public SqlSessionFactory build(Reader reader) {
return null;
}
private SqlSessionFactory build(Configuration configuration) {
return new DefaultSqlSessionFactory(configuration);
}
}
SqlSessionFactory 接口
public interface SqlSessionFactory {
SqlSession openSqlSession();
}
SqlSessionFactory 类,实现DefaultSqlSessionFactory 接口
- 职责只是创建SqlSession对象,不负责配置文件的解析工作
public class DefaultSqlSessionFactory implements SqlSessionFactory {
// 我既然不负责Configuration的解析,那么我就需要被外部注入一个configuration
private Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
@Override
public SqlSession openSqlSession() {
return new DefaultSqlSession(configuration);
}
}
SqlSession 接口
public interface SqlSession {
<T> T selectOne(String statementId, Object param);
<T> List<T> selectList(String statementId, Object param);
int insert(String statementId, Object param);
}
DefaultSqlSession 实现 Sqlsession接口
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
}
@SuppressWarnings("unchecked")
@Override
public <T> T selectOne(String statementId, Object param) {
List<Object> list = this.selectList(statementId, param);
if (list != null && list.size() == 1) {
return (T) list.get(0);
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public <T> List<T> selectList(String statementId, Object param) {
MappedStatement mappedStatement = configuration.getMappedStatementById(statementId);
if (mappedStatement == null) {
return null;
}
try {
// TODO Executor executor = new CachingExecutor();
Executor executor = configuration.newExecutor();
return (List<T>) executor.query(configuration, mappedStatement, param, null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public int insert(String statementId, Object param) {
// TODO Auto-generated method stub
return 0;
}
}
mybatis.mapping 包
Configuration 类
- 封装XML配置文件中的信息 封装mybatis-config.xml和*mapper.xml中存储的数据
public class Configuration {
private boolean useCache = true;
// 封装MappedStatement对象集合
private Map<String, MappedStatement> mappedStatements = new HashMap<String, MappedStatement>();
// 封装数据源对象
private DataSource dataSource;
public MappedStatement getMappedStatementById(String statementId) {
return this.mappedStatements.get(statementId);
}
public void addMappedStatement(String statementId, MappedStatement mappedStatement) {
this.mappedStatements.put(statementId, mappedStatement);
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Executor newExecutor() {
Executor executor = null;
// 可以通过配置文件,去指定使用哪种Executor
// 默认创建的是SimpleExecutor
executor = new SimpleExecutor();
// 默认优先使用二级缓存执行器CachingExecutor
if (useCache) {
executor = new CachingExecutor(executor);
}
return executor;
}
public StatementHandler newStatementHandler(Configuration configuration, MappedStatement mappedStatement,
BoundSql boundSql) {
StatementHandler statementHandler = null;
switch (mappedStatement.getStatementType()) {
case "prepared":
statementHandler = new PreparedStatementHandler(configuration, mappedStatement, boundSql);
break;
case "simple":
// statementHandler = new SimpleStatementHandler(mappedStatement, boundSql);
break;
default:
break;
}
return statementHandler;
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, BoundSql boundSql) {
return new DefaultParameterHandler(mappedStatement, boundSql);
}
public ResultSetHandler newResultSetHandler(MappedStatement mappedStatement) {
return new DefaultResultSetHandler(mappedStatement);
}
}
MappedStatement 类
- 用来封装映射文件中的CRUD标签脚本内容,比如select标签
public class MappedStatement {
private String statementId;
private SqlSource sqlSource;
private String statementType;
private Class<?> parameterTypeClass;
private Class<?> resultTypeClass;
public MappedStatement(String statementId, Class<?> parameterTypeClass, Class<?> resultTypeClass,
String statementType, SqlSource sqlSource) {
this.statementId = statementId;
this.parameterTypeClass = parameterTypeClass;
this.resultTypeClass = resultTypeClass;
this.statementType = statementType;
this.sqlSource = sqlSource;
}
public SqlSource getSqlSource() {
return sqlSource;
}
public void setSqlSource(SqlSource sqlSource) {
this.sqlSource = sqlSource;
}
public String getStatementType() {
return statementType;
}
public void setStatementType(String statementType) {
this.statementType = statementType;
}
public String getStatementId() {
return statementId;
}
public void setStatementId(String statementId) {
this.statementId = statementId;
}
public Class<?> getParameterTypeClass() {
return parameterTypeClass;
}
public void setParameterTypeClass(Class<?> parameterTypeClass) {
this.parameterTypeClass = parameterTypeClass;
}
public Class<?> getResultTypeClass() {
return resultTypeClass;
}
public void setResultTypeClass(Class<?> resultTypeClass) {
this.resultTypeClass = resultTypeClass;
}
}
DynamicContext 类
- 动态上下文,就是封装的入参信息,解析过程中的SQL信息
public class DynamicContext {
private StringBuffer sb = new StringBuffer();
private HashMap<String, Object> bindings = new HashMap<>();
public DynamicContext(Object param) {
bindings.put("_parameter", param);
}
public String getSql() {
return sb.toString();
}
public void appendSql(String sqlText) {
this.sb.append(sqlText);
this.sb.append(" ");
}
public HashMap<String, Object> getBindings() {
return bindings;
}
public void addBinding(String name, Object param) {
this.bindings.put(name, param);
}
}
ParameterMapping 类
- 从#{}中解析出来的参数信息,包括参数名称和类型
public class ParameterMapping {
private String name;
private Class<?> type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public ParameterMapping(String name) {
super();
this.name = name;
}
}
BoundSql 类
- 封装解析之后的SQL信息,以及解析占位符?时产生的参数信息
public class BoundSql {
// 解析之后的SQL语句
private String sql;
// 解析过程中产生的SQL参数信息
private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
public BoundSql(String sql, List<ParameterMapping> parameterMappings) {
this.sql = sql;
this.parameterMappings = parameterMappings;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public List<ParameterMapping> getParameterMappings() {
return parameterMappings;
}
public void addParameterMappings(ParameterMapping parameterMapping) {
this.parameterMappings.add(parameterMapping);
}
}
mybatis.builder 包
XMLConfigBuilder 类
- 解析全局配置文件
public class XMLConfigBuilder {
private Configuration configuration;
public XMLConfigBuilder() {
configuration = new Configuration();
}
public Configuration parse(Element rootElement) {
Element environments = rootElement.element("environments");
parseEnvironments(environments);
Element mappers = rootElement.element("mappers");
parseMappers(mappers);
return configuration;
}
@SuppressWarnings("unchecked")
private void parseMappers(Element mappers) {
List<Element> mapperElements = mappers.elements("mapper");
for (Element mapperElement : mapperElements) {
parseMapper(mapperElement);
}
}
private void parseMapper(Element mapperElement) {
String resource = mapperElement.attributeValue("resource");
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
Document document = DocumentUtils.loadDocument(inputStream);
// 解析映射文件XMLMapperBuilder
XMLMapperBuilder mapperBuilder = new XMLMapperBuilder(configuration);
mapperBuilder.parse(document.getRootElement());
}
@SuppressWarnings("unchecked")
private void parseEnvironments(Element environments) {
String def = environments.attributeValue("default");
List<Element> elements = environments.elements("environment");
for (Element envElement : elements) {
String id = envElement.attributeValue("id");
if (id.equals(def)) {
parseEnvironment(envElement);
}
}
}
private void parseEnvironment(Element envElement) {
Element dataSource = envElement.element("dataSource");
parseDataSource(dataSource);
}
@SuppressWarnings("unchecked")
private void parseDataSource(Element dataSourceElement) {
String type = dataSourceElement.attributeValue("type");
if ("DBCP".equals(type)) {
BasicDataSource dataSource = new BasicDataSource();
Properties properties = new Properties();
List<Element> propertyElements = dataSourceElement.elements();
for (Element prop : propertyElements) {
String name = prop.attributeValue("name");
String value = prop.attributeValue("value");
properties.put(name, value);
}
dataSource.setDriverClassName(properties.getProperty("driver"));
dataSource.setUrl(properties.getProperty("url"));
dataSource.setUsername(properties.getProperty("username"));
dataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(dataSource);
}
}
}
XMLMapperBuilder 类
- 解析映射文件
public class XMLMapperBuilder {
private Configuration configuration;
private String namespace;
public XMLMapperBuilder(Configuration configuration) {
this.configuration = configuration;
}
@SuppressWarnings("unchecked")
public void parse(Element rootElement) {
// 为了方便管理statement,需要使用statement唯一标识
namespace = rootElement.attributeValue("namespace");
//其他mapper映射文件中的标签
//select标签的处理
List<Element> selectElements = rootElement.elements("select");
for (Element selectElement : selectElements) {
XMLStatementBuilder builder = new XMLStatementBuilder(configuration);
builder.parseStatementElement(selectElement,namespace);
}
}
}
XMLStatementBuilder 类
- 解析crud标签
public class XMLStatementBuilder {
private Configuration configuration;
public XMLStatementBuilder(Configuration configuration) {
this.configuration = configuration;
}
public void parseStatementElement(Element selectElement, String namespace) {
String statementId = selectElement.attributeValue("id");
if (statementId == null || selectElement.equals("")) {
return;
}
// 一个CURD标签对应一个MappedStatement对象
// 一个MappedStatement对象由一个statementId来标识,所以保证唯一性
// statementId = namespace + "." + CRUD标签的id属性
statementId = namespace + "." + statementId;
String parameterType = selectElement.attributeValue("parameterType");
Class<?> parameterClass = resolveType(parameterType);
String resultType = selectElement.attributeValue("resultType");
Class<?> resultClass = resolveType(resultType);
String statementType = selectElement.attributeValue("statementType");
statementType = statementType == null || statementType == "" ? "prepared" : statementType;
// 解析SQL信息
SqlSource sqlSource = createSqlSource(selectElement);
// TODO 建议使用构建者模式去优化
MappedStatement mappedStatement = new MappedStatement(statementId, parameterClass, resultClass, statementType,
sqlSource);
configuration.addMappedStatement(statementId, mappedStatement);
}
private SqlSource createSqlSource(Element selectElement) {
// 去解析select等CURD标签中的SQL脚本信息
XMLScriptBuilder builder = new XMLScriptBuilder();
SqlSource sqlSource = builder.parseScriptNode(selectElement);
return sqlSource;
}
private Class<?> resolveType(String parameterType) {
try {
Class<?> clazz = Class.forName(parameterType);
return clazz;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
XMLScriptBuilder 类
- 解析sql脚本信息
public class XMLScriptBuilder {
private boolean isDynamic;
public SqlSource parseScriptNode(Element selectElement) {
// 1.解析出来所有的SqlNode信息
MixedSqlNode rootSqlNode = parseDynamicTags(selectElement);
// isDynamic是parseDynamicTags过程中,得到的值
// 如果包含${}或者包含动态标签,则isDynamic为true
SqlSource sqlSource;
// 2.将SqlNode信息封装到SqlSource中,并且要根据是否动态节点去选择不同的SqlSource
// 如果isDynamic为true,则说明SqlNode集合信息里面包含${}SqlNode节点信息或者动态标签的节点信息
if (isDynamic) {
sqlSource = new DynamicSqlSource(rootSqlNode);
} else {
sqlSource = new RawSqlSource(rootSqlNode);
}
return sqlSource;
}
private MixedSqlNode parseDynamicTags(Element selectElement) {
List<SqlNode> sqlNodes = new ArrayList<>();
int nodeCount = selectElement.nodeCount();
// 获取select标签的子标签
for (int i = 0; i < nodeCount; i++) {
Node node = selectElement.node(i);
// 区分是文本标签还是元素标签
if (node instanceof Text) {
String sqlText = node.getText().trim();
if (sqlText == null || "".equals(sqlText)) {
continue;
}
TextSqlNode textSqlNode = new TextSqlNode(sqlText);
if (textSqlNode.isDynamic()) {
// 设置是否动态为true
isDynamic = true;
sqlNodes.add(textSqlNode);
} else {
sqlNodes.add(new StaticTextSqlNode(sqlText));
}
} else if (node instanceof Element) {
// 获取动态标签的标签名称
String nodeName = node.getName();
// TODO 设计模式优化
if ("if".equals(nodeName)) {
// 封装成IfSqlNode(test信息、子标签信息)
Element element = (Element) node;
// if标签的test属性信息
String test = element.attributeValue("test");
// if标签的子标签信息
MixedSqlNode rootSqlNode = parseDynamicTags(element);
// IfSqlNode就是封装if标签信息的
IfSqlNode ifSqlNode = new IfSqlNode(test, rootSqlNode);
sqlNodes.add(ifSqlNode);
}
isDynamic = true;
}
}
return new MixedSqlNode(sqlNodes);
}
}
mybatis.executor 包
Executor 接口
- 执行JDBC代码
public interface Executor {
Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
throws Exception;
}
BaseExecutor 实现 Executor 接口
- 只处理一级缓存的逻辑
public abstract class BaseExecutor implements Executor {
@Override
public Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
throws Exception {
// 如果一级缓存没有,则直接查询数据库
// 查询数据库的方式有多种:批量查询、简单查询
return queryFromDataBase(configuration, mappedStatement, param, boundSql);
}
public abstract Object queryFromDataBase(Configuration configuration, MappedStatement mappedStatement, Object param,
BoundSql boundSql);
}
CachingExecutor 实现 Executor
public class CachingExecutor implements Executor {
// 一级缓存
// TODO private Executor delegate = new SimpleExecutor();
private Executor delegate;
public CachingExecutor(Executor executor) {
this.delegate = executor;
}
@Override
public Object query(Configuration configuration, MappedStatement mappedStatement, Object param, BoundSql boundSql)
throws Exception {
// 如果没有二级缓存key:BoundSql+其他
// 获取SqlSource
SqlSource sqlSource = mappedStatement.getSqlSource();
// 执行SqlSource去获取Sql信息
boundSql = sqlSource.getBoundSql(param);
// 委托一级缓存去处理
return delegate.query(configuration, mappedStatement, param, boundSql);
}
}
SimpleExecutor 继承 BaseExecutor
public class SimpleExecutor extends BaseExecutor {
@Override
public Object queryFromDataBase(Configuration configuration, MappedStatement mappedStatement, Object param,
BoundSql boundSql) {
Connection connection = null;
Statement statement = null;
try {
// 1、获取Connection
connection = getConnection(configuration);
// 2、获取可以JDBC执行的SQL语句
if (mappedStatement == null) {
return null;
}
// 获取JDBC可以直接执行的SQL语句
// TODO String sql = boundSql.getSql();
StatementHandler statementHandler = configuration.newStatementHandler(configuration, mappedStatement,
boundSql);
// 去创建Statement
statement = statementHandler.prepare(connection);
// 参数设置
statementHandler.parameterize(statement, param);
// 执行Statement
return statementHandler.query(statement);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放资源
/*
* if (rs != null) { try { rs.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) { // TODO Auto-generated catch block e.printStackTrace(); } }
*/
}
return null;
}
private Connection getConnection(Configuration configuration) throws Exception {
DataSource dataSource = configuration.getDataSource();
Connection connection = dataSource.getConnection();
return connection;
}
}
mybatis.handler 包
StatementHandler 接口
- 处理Statement信息
public interface StatementHandler {
Statement prepare(Connection connection);
void parameterize(Statement statement, Object param);
<E> List<E> query(Statement statement);
}
PreparedStatementHandler 实现 StatementHandler接口
public class PreparedStatementHandler implements StatementHandler {
private BoundSql boundSql;
private ParameterHandler parameterHandler;
private ResultSetHandler resultSetHandler;
public PreparedStatementHandler(Configuration configuration, MappedStatement mappedStatement, BoundSql boundSql) {
this.boundSql = boundSql;
// 初始化一个参数处理器,专门处理预处理的参数
parameterHandler = configuration.newParameterHandler(mappedStatement, boundSql);
resultSetHandler = configuration.newResultSetHandler(mappedStatement);
}
@Override
public Statement prepare(Connection connection) {
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(boundSql.getSql());
} catch (SQLException e) {
e.printStackTrace();
}
return statement;
}
@Override
public void parameterize(Statement statement, Object param) {
parameterHandler.handleParameter(statement, param);
// handleParameter(preparedStatement, mappedStatement, boundSql, param);
}
@Override
public <E> List<E> query(Statement statement) {
try {
PreparedStatement preparedStatement = (PreparedStatement) statement;
ResultSet rs = preparedStatement.executeQuery();
// 6、处理结果集
// handleResultSet(rs, mappedStatement)
return resultSetHandler.handleResultSet(rs);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
ParameterHandler 接口
- 设置参数接口
public interface ParameterHandler {
void handleParameter(Statement statement, Object param);
}
DefaultParameterHandler 实现ParameterHandler接口
public class DefaultParameterHandler implements ParameterHandler {
private MappedStatement mappedStatement;
private BoundSql boundSql;
public DefaultParameterHandler(MappedStatement mappedStatement, BoundSql boundSql) {
this.mappedStatement = mappedStatement;
this.boundSql = boundSql;
}
@Override
public void handleParameter(Statement statement, Object param) {
try {
PreparedStatement preparedStatement = (PreparedStatement) statement;
// 从mappedStatement获取入参的类型
Class<?> parameterTypeClass = mappedStatement.getParameterTypeClass();
// 如果入参是8种基本类型和String类型
if (SimpleTypeRegistry.isSimpleType(parameterTypeClass)) {
preparedStatement.setObject(1, param);
} else if (parameterTypeClass == Map.class) {
// 如果入参是Map类型
// ....
} else {
// 如果入参是POJO类型(比如User类型)
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 封装的#{}里面的属性名称
String name = parameterMapping.getName();
// 利用反射去入参对象根据属性名称获取指定的属性值
Field field = parameterTypeClass.getDeclaredField(name);
field.setAccessible(true);
Object value = field.get(param);
// TODO 可以使用ParameterMapping里面的type对Object类型的value进行类型处理
// 设置statement占位符中的值
preparedStatement.setObject(i + 1, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ResultSetHandler 接口
- 处理结果集
public interface ResultSetHandler {
<E> List<E> handleResultSet(ResultSet rs);
}
DefaultResultSetHandler 实现 ResultSetHandler接口
public class DefaultResultSetHandler implements ResultSetHandler {
private MappedStatement mappedStatement;
public DefaultResultSetHandler(MappedStatement mappedStatement) {
this.mappedStatement = mappedStatement;
}
@SuppressWarnings("unchecked")
@Override
public <E> List<E> handleResultSet(ResultSet rs) {
try {
List<Object> results = new ArrayList<Object>();
Class<?> resultTypeClass = mappedStatement.getResultTypeClass();
while (rs.next()) {
// 遍历一次是一行,也对应一个对象,利用反射new一个对象
Object result = resultTypeClass.newInstance();
// 要获取每一列的值,然后封装到结果对象中对应的属性名称上
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 0; i < columnCount; i++) {
// 获取每一列的值
Object value = rs.getObject(i + 1);
// 列的名称
String columnName = metaData.getColumnName(i + 1);
// 列名和属性名称要严格一致
Field field = resultTypeClass.getDeclaredField(columnName);
field.setAccessible(true);
// 给映射的对象赋值
field.set(result, value);
}
results.add(result);
}
return (List<E>) results;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
mybatis.utils 包(工具类)
TokenHandler 接口
public interface TokenHandler {
String handleToken(String content);
}
ParameterMappingTokenHandler 实现 TokenHandler
public class ParameterMappingTokenHandler implements TokenHandler {
private List<ParameterMapping> parameterMappings = new ArrayList<>();
// content是参数名称
// content 就是#{}中的内容
@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;
}
}
DocumentUtils 类
public class DocumentUtils {
public static Document loadDocument(InputStream inputStream) {
try {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(inputStream);
return document;
} catch (DocumentException e) {
e.printStackTrace();
}
return null;
}
}
OgnlUtils 类
- 根据Ongl表达式,获取指定对象的参数值
public class OgnlUtils {
/**
* 根据Ongl表达式,获取指定对象的参数值
* @param expression
* @param paramObject
* @return
*/
public static Object getValue(String expression, Object paramObject) {
try {
OgnlContext context = new OgnlContext();
context.setRoot(paramObject);
//mybatis中的动态标签使用的是ognl表达式
//mybatis中的${}使用的是ognl表达式
Object ognlExpression = Ognl.parseExpression(expression);// 构建Ognl表达式
Object value = Ognl.getValue(ognlExpression, context, context.getRoot());// 解析表达式
return value;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 通过Ognl表达式,去计算boolean类型的结果
* @param expression
* @param parameterObject
* @return
*/
public static boolean evaluateBoolean(String expression, Object parameterObject) {
Object value = OgnlUtils.getValue(expression, parameterObject);
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof Number) {
return new BigDecimal(String.valueOf(value)).compareTo(BigDecimal.ZERO) != 0;
}
return value != null;
}
}
SimpleTypeRegistry 类
public class SimpleTypeRegistry {
private static final Set<Class<?>> SIMPLE_TYPE_SET = new HashSet<>();
static {
SIMPLE_TYPE_SET.add(String.class);
SIMPLE_TYPE_SET.add(Byte.class);
SIMPLE_TYPE_SET.add(Short.class);
SIMPLE_TYPE_SET.add(Character.class);
SIMPLE_TYPE_SET.add(Integer.class);
SIMPLE_TYPE_SET.add(Long.class);
SIMPLE_TYPE_SET.add(Float.class);
SIMPLE_TYPE_SET.add(Double.class);
SIMPLE_TYPE_SET.add(Boolean.class);
SIMPLE_TYPE_SET.add(Date.class);
SIMPLE_TYPE_SET.add(Class.class);
SIMPLE_TYPE_SET.add(BigInteger.class);
SIMPLE_TYPE_SET.add(BigDecimal.class);
}
public static boolean isSimpleType(Class<?> clazz) {
return SIMPLE_TYPE_SET.contains(clazz);
}
}