当前位置: 首页 > news >正文

有经验的武进网站建设哪里有学网页设计

有经验的武进网站建设,哪里有学网页设计,wordpress下载类插件,桂林做网站文章目录 一、目标#xff1a;参数处理器二、设计#xff1a;参数处理器三、实现#xff1a;参数处理器3.1 工程结构3.2 参数处理器关系图3.3 入参数校准3.4 参数策略处理器3.4.1 JDBC枚举类型修改3.4.2 类型处理器接口3.4.3 模板模式#xff1a;类型处理器抽象基类3.4.4 类… 文章目录 一、目标参数处理器二、设计参数处理器三、实现参数处理器3.1 工程结构3.2 参数处理器关系图3.3 入参数校准3.4 参数策略处理器3.4.1 JDBC枚举类型修改3.4.2 类型处理器接口3.4.3 模板模式类型处理器抽象基类3.4.4 类型处理器具体的子类实现3.4.5 类型处理器注册机 3.5 参数构建3.5.1 参数映射类的修改3.5.2 SQL源码构建器 3.6 参数使用3.6.1 参数处理器接口3.6.2 默认参数处理器 3.7 参数处理器的使用3.7.1 脚本语言驱动3.7.2 XML语言驱动器3.7.3 映射器语句类修改添加脚本语言驱动3.7.4 修改配置类3.7.5 语句处理器抽象基类3.7.6 预处理语句处理器3.7.7 默认sqlSession实现类添加日志描述 四、测试参数处理器4.1 修改 DAO 接口4.2 修改 User 实体类4.3 配置Mapper文件4.4 单元测试4.4.1 提取初始化SqlSession4.4.2 基本类型参数4.4.3 对象类型参数 五、总结参数处理器 一、目标参数处理器 结合参数的提取对执行的 SQL 进行参数的自动化设置而不是像我们之前那样把参数写成固定的。 在流程上通过 DefaultSqlSession#selectOne 方法调用执行器并通过预处理语句处理器 PreparedStatementHandler 执行参数设置和结果查询。这个流程中我们处理的参数信息也就是每个 SQL 执行时那些 ?号 需要被替换的地方目前是通过硬编码的方式进行处理的。使用策略模式处理硬编码为自动化类型设置。 二、设计参数处理器 在 SQL 拆解出参数类型之后怎么根据不同的参数进行不同的类型设置 在自动化解析 XML 中 SQL 拆分出所有的参数类型后则应该根据不同的参数进行不同的类型设置 Long 调用 ps.setLongString 调用 ps.setString 这里使用 策略模式封装进去类型处理器(也就是实现 TypeHandler 接口的过程)。 其实关于参数的处理因为有很多的类型(Long\String\Object\...)所以这里最重要的体现则是 策略模式 的使用。 包括构建参数时根据类型选择对应的策略类型处理器填充到参数映射集合中。 另一方面参数的使用也就是在执行 DefaultSqlSession#selectOne 的链路中。 包括参数的设置按照参数不同类型获取出对应的处理器以及入参。注意由于入参值可能是一个对象中的属性所以我们使用反射工具类 MetaObject 进行值的获取避免由于动态的对象没法硬编码获取属性值。 三、实现参数处理器 3.1 工程结构 mybatis-step-09 |-src|-main| |-java| |-com.lino.mybatis| |-binding| | |-MapperMethod.java| | |-MapperProxy.java| | |-MapperProxyFactory.java| | |-MapperRegistry.java| |-builder| | |-xml| | | |-XMLConfigBuilder.java| | | |-XMLMapperBuilder.java| | | |-XMLStatementBuilder.java| | |-BaseBuilder.java| | |-ParameterExpression.java| | |-SqlSourceBuilder.java| | |-StaticSqlSource.java| |-datasource| | |-druid| | | |-DruidDataSourceFacroty.java| | |-pooled| | | |-PooledConnection.java| | | |-PooledDataSource.java| | | |-PooledDataSourceFacroty.java| | | |-PoolState.java| | |-unpooled| | | |-UnpooledDataSource.java| | | |-UnpooledDataSourceFacroty.java| | |-DataSourceFactory.java| |-executor| | |-parameter| | | |-ParameterHandler.java| | |-resultset| | | |-DefaultResultSetHandler.java| | | |-ResultSetHandler.java| | |-statement| | | |-BaseStatementHandler.java| | | |-PreparedStatementHandler.java| | | |-SimpleStatementHandler.java| | | |-StatementHandler.java| | |-BaseExecutor.java| | |-Executor.java| | |-SimpleExecutor.java| |-io| | |-Resources.java| |-mapping| | |-BoundSql.java| | |-Environment.java| | |-MappedStatement.java| | |-ParameterMapping.java| | |-SqlCommandType.java| | |-SqlSource.java| |-parsing| | |-GenericTokenParser.java| | |-TokenHandler.java| |-reflection| | |-factory| | | |-DefaultObjectFactory.java| | | |-ObjectFactory.java| | |-invoker| | | |-GetFieldInvoker.java| | | |-Invoker.java| | | |-MethodInvoker.java| | | |-SetFieldInvoker.java| | |-property| | | |-PropertyNamer.java| | | |-PropertyTokenizer.java| | |-wrapper| | | |-BaseWrapper.java| | | |-BeanWrapper.java| | | |-CollectionWrapper.java| | | |-DefaultObjectWrapperFactory.java| | | |-MapWrapper.java| | | |-ObjectWrapper.java| | | |-ObjectWrapperFactory.java| | |-MetaClass.java| | |-MetaObject.java| | |-Reflector.java| | |-SystemMetaObject.java| |-scripting| | |-defaults| | | |-DefaultParameterHandler.java| | | |-RawSqlSource.java| | |-xmltags| | | |-DynamicContext.java| | | |-MixedSqlNode.java| | | |-SqlNode.java| | | |-StaticTextSqlNode.java| | | |-XMLLanguageDriver.java| | | |-XMLScriptBuilder.java| | |-LanguageDriver.java| | |-LanguageDriverRegistry.java| |-session| | |-defaults| | | |-DefaultSqlSession.java| | | |-DefaultSqlSessionFactory.java| | |-Configuration.java| | |-ResultHandler.java| | |-SqlSession.java| | |-SqlSessionFactory.java| | |-SqlSessionFactoryBuilder.java| | |-TransactionIsolationLevel.java| |-transaction| | |-jdbc| | | |-JdbcTransaction.java| | | |-JdbcTransactionFactory.java| | |-Transaction.java| | |-TransactionFactory.java| |-type| | |-BaseTypeHandler.java| | |-IntegerTypeHandler.java| | |-JdbcType.java| | |-LongTypeHandler.java| | |-StringTypeHandler.java| | |-TypeAliasRegistry.java| | |-TypeHandler.java| | |-TypeHandlerRegistry.java|-test|-java| |-com.lino.mybatis.test| |-dao| | |-IUserDao.java| |-po| | |-User.java| |-ApiTest.java|-resources|-mapper| |-User_Mapper.xml|-mybatis-config-datasource.xml3.2 参数处理器关系图 策略模式核心处理主要分为三块类型处理、参数设置、参数使用。 定义 TypeHandler 类型处理器策略接口实现不同的处理策略包括Long、String、Integer 等。类型策略处理器实现完成后需要注册到处理器注册机中后续其他模块参数的设置的使用都是从 Configuration 中获取到 TypeHandlerRegistry 进行使用。有了策略处理器之后在进行操作解析 SQL 时就可以按照不同的类型把对应的策略处理器设置到 BoundSql#parameterMappings 参数里。 3.3 入参数校准 针对参数的传递 这里的参数传递后需要获取第0个参数而且是硬编码固定。 这是为什么呢这个第0个参数是哪来的我们接口调用的方法参数不是一个吗就像 User queryUserInfoById(Long id). 其实这个参数来自映射器代理类 MapperProxy#invoke 中因为 invoke 反射调用的方法入参中是 Object[] args所以这个参数被传递到后续的参数设置中。而我们的 DAO 测试类是一个已知的固定参数所以后面硬编码获取了第0个参数。 JDK 反射调用方法操作固定方法入参。 现在我们需要根据方法的信息给方法做签名操作以便于转换入参信息为方法的信息。比如数组转换为对应的对象。 MapperMethod.java package com.lino.mybatis.binding;import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.mapping.SqlCommandType; import com.lino.mybatis.session.Configuration; import com.lino.mybatis.session.SqlSession; import com.mysql.fabric.xmlrpc.base.Param; import javassist.bytecode.SignatureAttribute; import java.lang.reflect.Method; import java.util.*;/*** description: 映射器方法*/ public class MapperMethod {private final SqlCommand command;private final MethodSignature method;public MapperMethod(Class? mapperInterface, Method method, Configuration configuration) {this.command new SqlCommand(configuration, mapperInterface, method);this.method new MethodSignature(configuration, method);}public Object execute(SqlSession sqlSession, Object[] args) {Object result null;switch (command.getType()) {case INSERT:break;case DELETE:break;case UPDATE:break;case SELECT:Object param method.convertArgsToSqlCommandParam(args);result sqlSession.selectOne(command.getName(), param);break;default:throw new RuntimeException(Unknown execution method for: command.getName());}return result;}/*** SQL 指令*/public static class SqlCommand {private final String name;private final SqlCommandType type;public SqlCommand(Configuration configuration, Class? mapperInterface, Method method) {String statementName mapperInterface.getName() . method.getName();MappedStatement ms configuration.getMappedStatement(statementName);this.name ms.getId();this.type ms.getSqlCommandType();}public String getName() {return name;}public SqlCommandType getType() {return type;}}/*** 方法签名*/public static class MethodSignature {private final SortedMapInteger, String params;public MethodSignature(Configuration configuration, Method method) {this.params Collections.unmodifiableSortedMap(getParams(method));}public Object convertArgsToSqlCommandParam(Object[] args) {final int paramCount params.size();if (args null || paramCount 0) {// 如果没参数return null;} else if (paramCount 1) {return args[params.keySet().iterator().next().intValue()];} else {// 否则返回一个ParamMap 修改参数名参数名就是其位置final MapString, Object param new ParamMap();int i 0;for (Map.EntryInteger, String entry : params.entrySet()) {// 1.先加一个#{0}#{1}#{2}...参数param.put(entry.getValue(), args[entry.getKey().intValue()]);// issue #71, add param names as param1, param2...but ensure backward compatibilityfinal String genericParamName param (i 1);if (!param.containsKey(genericParamName)) {/*2.再加一个#{param1},#{param2}...参数你可以传递多个参数给一个映射器方法。默认情况下它们将会以它们在参数列表中的位置来命名比如#{param1},#{param2}等如果你想改变参数的名称(只在多参数情况下)那么你可以在参数上使用Param(paramName)注解*/param.put(genericParamName, args[entry.getKey()]);}i;}return param;}}private SortedMapInteger, String getParams(Method method) {// 用一个TreeMap这样就保证还是按参数的先后顺序final SortedMapInteger, String params new TreeMap();final Class?[] argTypes method.getParameterTypes();for (int i 0; i argTypes.length; i) {String paramName String.valueOf(params.size());// 不做 Param 的实现这部分不处理。params.put(i, paramName);}return params;}/*** 参数map静态内部类更严格的get方法如果没有相应的key报错*/public static class ParamMapV extends HashMapString, V {private static final long serialVersionUID -2212268410512043556L;Overridepublic V get(Object key) {if (!super.containsKey(key)) {throw new RuntimeException(Parameter key not found. Available parameters are keySet());}return super.get(key);}}} }在映射器方法中 MapperMethod#execute 将原来的直接将参数 args 传递给 SqlSession#selectOne 方法调整为转换后再传递对象。这里的转换操作就是来自于 Method#getParameterTypes 对参数的获取和处理于 args 进行对比。 如果是单个参数则直接返回参数 Tree 树结构下的对应节点值。非单个类型则需要进行循环处理这样转换后的参数才能被直接使用。 3.4 参数策略处理器 Mybatis 的源码包中type 包下所提供的就是一套参数的处理策略集合。它通过定义类型处理器接口、由抽象模板实现并定义标准流程定义提取抽象方法交予给子类实现这些之类就是各个类型处理器的具体实现。 3.4.1 JDBC枚举类型修改 JdbcType.java package com.lino.mybatis.type;import java.sql.Types; import java.util.HashMap; import java.util.Map;/*** description: JDBC枚举类型* author: lingjian* createDate: 2022/11/5 17:10*/ public enum JdbcType {// JDBC枚举类型INTEGER(Types.INTEGER),FLOAT(Types.FLOAT),DOUBLE(Types.DOUBLE),DECIMAL(Types.DECIMAL),VARCHAR(Types.VARCHAR),CHAR(Types.CHAR),TIMESTAMP(Types.TIMESTAMP);public final int TYPE_CODE;private static MapInteger, JdbcType codeLookup new HashMap();static {for (JdbcType type : JdbcType.values()) {codeLookup.put(type.TYPE_CODE, type);}}JdbcType(int code) {this.TYPE_CODE code;}public static JdbcType forCode(int code) {return codeLookup.get(code);} }添加 CHAR(Typcs.CHAR) 字符类型 3.4.2 类型处理器接口 TypeHandler.java package com.lino.mybatis.type;import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: 类型处理器*/ public interface TypeHandlerT {/*** 设置参数** param ps 预处理语言* param i 次数* param parameter 参数对象* param jdbcType JDBC类型* throws SQLException SQL异常*/void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; }首先定义一个类型处理器的接口。这里设置参数也是一样所有不同类型的参数都可以被提取出来这些标准的参数字段和异常后续的子类按照这个标准实现即可。 3.4.3 模板模式类型处理器抽象基类 BaseTypeHandler.java package com.lino.mybatis.type;import com.lino.mybatis.session.Configuration; import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: 类型处理器的基类*/ public abstract class BaseTypeHandlerT implements TypeHandlerT {protected Configuration configuration;public void setConfiguration(Configuration configuration) {this.configuration configuration;}Overridepublic void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {// 定义抽象方法由子类实现不同类型的属性设置setNonNullParameter(ps, i, parameter, jdbcType);}/*** 属性设置抽象方法由子类实现** param ps 预处理语言* param i 次数* param parameter 参数对象* param jdbcType JDBC类型* throws SQLException SQL异常*/protected abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; }通过抽象基类的流程模板定义便于一些参数的判断和处理。 3.4.4 类型处理器具体的子类实现 IntegerTypeHandler.java package com.lino.mybatis.type;import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: Integer类型处理器*/ public class IntegerTypeHandler extends BaseTypeHandlerInteger {Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) throws SQLException {ps.setInt(i, parameter);} }LongTypeHandler.java package com.lino.mybatis.type;import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: Long类型处理器*/ public class LongTypeHandler extends BaseTypeHandlerLong {Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {ps.setLong(i, parameter);} }StringTypeHandler.java package com.lino.mybatis.type;import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: String类型处理器*/ public class StringTypeHandler extends BaseTypeHandlerString {Overrideprotected void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter);} }这里的接口实现暂时实现了3个分别是 IntegerTypeHandler、LongTypeHandler、StringTypeHandler。在 Mybatis 中源码还有30个其他类型可以参照源码阅读。 3.4.5 类型处理器注册机 TypeHandlerRegistry.java package com.lino.mybatis.type;import java.lang.reflect.Type; import java.util.EnumMap; import java.util.HashMap; import java.util.Map;/*** description: 类型处理器注册机*/ public final class TypeHandlerRegistry {private final MapJdbcType, TypeHandler? JDBC_TYPE_HANDLER_MAP new EnumMap(JdbcType.class);private final MapType, MapJdbcType, TypeHandler? TYPE_HANDLER_MAP new HashMap(16);private final MapClass?, TypeHandler? ALL_TYPE_HANDLER_MAP new HashMap(16);public TypeHandlerRegistry() {register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(String.class, new StringTypeHandler());register(String.class, JdbcType.CHAR, new StringTypeHandler());register(String.class, JdbcType.VARCHAR, new StringTypeHandler());}private T void register(Type javaType, TypeHandler? extends T typeHandler) {register(javaType, null, typeHandler);}private void register(Type javaType, JdbcType jdbcType, TypeHandler? handler) {if (null ! javaType) {MapJdbcType, TypeHandler? map TYPE_HANDLER_MAP.computeIfAbsent(javaType, k - new HashMap(16));map.put(jdbcType, handler);}ALL_TYPE_HANDLER_MAP.put(handler.getClass(), handler);}SuppressWarnings(unchecked)public TypeHandler? getTypeHandler(Class? type, JdbcType jdbcType) {return getTypeHandler((Type) type, jdbcType);}public boolean hasTypeHandler(Class? javaType) {return hasTypeHandler(javaType, null);}public boolean hasTypeHandler(Class? javaType, JdbcType jdbcType) {return javaType ! null getTypeHandler((Type) javaType, jdbcType) ! null;}private T TypeHandlerT getTypeHandler(Type type, JdbcType jdbcType) {MapJdbcType, TypeHandler? jdbcHandlerMap TYPE_HANDLER_MAP.get(type);TypeHandler? handler null;if (jdbcHandlerMap ! null) {handler jdbcHandlerMap.get(jdbcType);if (handler null) {handler jdbcHandlerMap.get(null);}}// type driver generics herereturn (TypeHandlerT) handler;} }这里在构造函数中新增加了 LongTypeHandler、IntegerTypeHandler、StringTypeHandler 三种类型的注册机。同时注意到无论是对象类型还是基本类型都是一个类型处理器。只不过在注册的时候多注册了一个。 这种操作方式和我们平常的业务开发中也是一样的。一种是多注册另外一种是判断处理。 3.5 参数构建 需要对 SqlSourceBuilder 源码构建器中创建参数映射 ParameterMapping 需要添加参数处理器的内容。 因为只有这样才能方便的从参数映射中获取到对应类型的处理器进行使用。 需要完善 ParameterMappping 添加 TypeHandler 属性信息。 以及在 ParameterMappingTokenHandler#buildParameterMapping 处理参数映射时构建出参数的映射。 3.5.1 参数映射类的修改 ParameterMapping.java package com.lino.mybatis.mapping;import com.lino.mybatis.session.Configuration; import com.lino.mybatis.type.JdbcType; import com.lino.mybatis.type.TypeHandler; import com.lino.mybatis.type.TypeHandlerRegistry;/*** description: 参数映射 #{property,javaTypeint,jdbcTypeNUMERIC}*/ public class ParameterMapping {private Configuration configuration;/*** property*/private String property;/*** javaType int*/private Class? javaType Object.class;/*** javaType NUMERIC*/private JdbcType jdbcType;/*** 类型处理器*/private TypeHandler? typeHandler;private ParameterMapping() {}public static class Builder {private ParameterMapping parameterMapping new ParameterMapping();public Builder(Configuration configuration, String property, Class? javaType) {parameterMapping.configuration configuration;parameterMapping.property property;parameterMapping.javaType javaType;}public Builder javaType(Class? javaType) {parameterMapping.javaType javaType;return this;}public Builder jdbcType(JdbcType jdbcType) {parameterMapping.jdbcType jdbcType;return this;}public ParameterMapping build() {if (parameterMapping.typeHandler null parameterMapping.javaType ! null) {Configuration configuration parameterMapping.configuration;TypeHandlerRegistry typeHandlerRegistry configuration.getTypeHandlerRegistry();parameterMapping.typeHandler typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);}return parameterMapping;}}public Configuration getConfiguration() {return configuration;}public String getProperty() {return property;}public Class? getJavaType() {return javaType;}public JdbcType getJdbcType() {return jdbcType;}public TypeHandler? getTypeHandler() {return typeHandler;} }在 build 添加类型处理器的处理判断 3.5.2 SQL源码构建器 SqlSourceBuilder.java package com.lino.mybatis.builder;import com.lino.mybatis.mapping.ParameterMapping; import com.lino.mybatis.mapping.SqlSource; import com.lino.mybatis.parsing.GenericTokenParser; import com.lino.mybatis.parsing.TokenHandler; import com.lino.mybatis.reflection.MetaClass; import com.lino.mybatis.reflection.MetaObject; import com.lino.mybatis.session.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.Map;/*** description: SQL源码构建器*/ public class SqlSourceBuilder extends BaseBuilder {private static Logger logger LoggerFactory.getLogger(SqlSourceBuilder.class);private static final String parameterProperties javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName;public SqlSourceBuilder(Configuration configuration) {super(configuration);}public SqlSource parse(String originalSql, Class? parameterType, MapString, Object additionalParameters) {ParameterMappingTokenHandler handler new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);GenericTokenParser parser new GenericTokenParser(#{, }, handler);String sql parser.parse(originalSql);// 返回静态SQLreturn new StaticSqlSource(configuration, sql, handler.getParameterMappings());}private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {private ListParameterMapping parameterMappings new ArrayList();private Class? parameterType;private MetaObject metaParameters;public ParameterMappingTokenHandler(Configuration configuration, Class? parameterType, MapString, Object additionalParameters) {super(configuration);this.parameterType parameterType;this.metaParameters configuration.newMetaObject(additionalParameters);}public ListParameterMapping getParameterMappings() {return parameterMappings;}Overridepublic String handleToken(String content) {parameterMappings.add(buildParameterMapping(content));return ?;}/*** 构建参数映射** param content 参数* return 参数映射*/private ParameterMapping buildParameterMapping(String content) {// 先解析参数映射就是转化成一个 HashMap | #{favouriteSection,jdbcTypeVARCHAR}MapString, String propertiesMap new ParameterExpression(content);String property propertiesMap.get(property);Class? propertyType;if (typeHandlerRegistry.hasTypeHandler(parameterType)) {propertyType parameterType;} else if (property ! null) {MetaClass metaClass MetaClass.forClass(parameterType);if (metaClass.hasGetter(property)) {propertyType metaClass.getGetterType(property);} else {propertyType Object.class;}} else {propertyType Object.class;}logger.info(构建参数映射 property{} propertyType{}, property, propertyType);ParameterMapping.Builder builder new ParameterMapping.Builder(configuration, property, propertyType);return builder.build();}} }这部分就是对参数的细化处理构建出参数的映射关系。 首先是 if 判断对应的参数类型是否在 TypeHandlerRegistry 注册器中。如果不在则拆解对象按属性进行获取 propertyType 的操作。 这一块也用到了 MetaClass 反射工具类的使用。 3.6 参数使用 参数构建完成后就可以在 DefaultSqlSession#selectOne 调用时设置参数使用了。 链路Executor#query - SimpleExecutor#doQuery - StatementHandler#parameterize - PreparedStatementHandler#parameterize - ParameterHandler#setParameters。到 ParameterHandler#setParameters 就可以看到了根据参数的不同处理器循环设置参数。 3.6.1 参数处理器接口 ParameterHandler.java package com.lino.mybatis.executor.parameter;import java.sql.PreparedStatement; import java.sql.SQLException;/*** description: 参数处理器*/ public interface ParameterHandler {/*** 获取参数** return 参数*/Object getParameterObject();/*** 设置参数** param ps 预处理语句对象* throws SQLException sql异常*/void setParameters(PreparedStatement ps) throws SQLException; }3.6.2 默认参数处理器 DefaultParameterHandler.java package com.lino.mybatis.scripting.defaults;import com.alibaba.fastjson.JSON; import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.mapping.ParameterMapping; import com.lino.mybatis.reflection.MetaObject; import com.lino.mybatis.session.Configuration; import com.lino.mybatis.type.JdbcType; import com.lino.mybatis.type.TypeHandler; import com.lino.mybatis.type.TypeHandlerRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List;/*** description: 默认参数处理器*/ public class DefaultParameterHandler implements ParameterHandler {private Logger logger LoggerFactory.getLogger(DefaultParameterHandler.class);private final TypeHandlerRegistry typeHandlerRegistry;private final MappedStatement mappedStatement;private final Object parameterObject;private BoundSql boundSql;private Configuration configuration;public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {this.mappedStatement mappedStatement;this.configuration mappedStatement.getConfiguration();this.typeHandlerRegistry mappedStatement.getConfiguration().getTypeHandlerRegistry();this.parameterObject parameterObject;this.boundSql boundSql;}Overridepublic Object getParameterObject() {return parameterObject;}Overridepublic void setParameters(PreparedStatement ps) throws SQLException {ListParameterMapping parameterMappings boundSql.getParameterMappings();if (null ! parameterMappings) {for (int i 0; i parameterMappings.size(); i) {ParameterMapping parameterMapping parameterMappings.get(i);String propertyName parameterMapping.getProperty();Object value;if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value parameterObject;} else {// 通过 MetaObject.getValue 反射取得值设置进去MetaObject metaObject configuration.newMetaObject(parameterObject);value metaObject.getValue(propertyName);}JdbcType jdbcType parameterMapping.getJdbcType();// 设置参数logger.info(根据每个ParameterMapping中的TypeHandler设置对应的参数信息 value{}, JSON.toJSONString(value));TypeHandler typeHandler parameterMapping.getTypeHandler();typeHandler.setParameter(ps, i 1, value, jdbcType);}}} }每一个循环的参数设置都是从 BoundSql 中获取 ParameterMapping 集合进行循环操作而这个集合参数就是我们前面 ParameterMappingTokenHandler#buildParameterMapping 构建参数映射时处理的。设置参数时根据参数的 parameterObject 入参信息判断是否基本类型如果不是则从对象中进行拆解获取(也就是一个对象A中包括对象B)处理完成后就可以准确拿到对应的入参值。 入参值在 MapperMethod 中已经处理了一遍 方法签名。 基本信息获取完成后则根据参数类型获取到对应的 TypeHandler 类型处理器也就是找到 IntegerTypeHandler、LongTypeHandler、StringTypeHandler 等确定找到以后则可以进行对应的参数设置。 typeHandler.setParameter(ps, i 1, value, jdbcType) 通过这样的方式把我们之前硬编码的操作进行解耦。 3.7 参数处理器的使用 3.7.1 脚本语言驱动 LanguageDriver.java package com.lino.mybatis.scripting;import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.mapping.SqlSource; import com.lino.mybatis.session.Configuration; import org.dom4j.Element;/*** description: 脚本语言驱动*/ public interface LanguageDriver {/*** 创建SQL源** param configuration 配置项* param script 元素* param parameterType 参数类型* return SqlSource SQL源码*/SqlSource createSqlSource(Configuration configuration, Element script, Class? parameterType);/*** 创建参数处理器** param mappedStatement 映射器语句类* param parameterObject 参数对象* param boundSql sql语句* return ParameterHandler 参数处理器*/ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql); }添加创建参数处理器接口 3.7.2 XML语言驱动器 XMLLanguageDriver.java package com.lino.mybatis.scripting.xmltags;import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.mapping.SqlSource; import com.lino.mybatis.scripting.LanguageDriver; import com.lino.mybatis.scripting.defaults.DefaultParameterHandler; import com.lino.mybatis.session.Configuration; import org.dom4j.Element;/*** description: XML 语言驱动器*/ public class XMLLanguageDriver implements LanguageDriver {Overridepublic SqlSource createSqlSource(Configuration configuration, Element script, Class? parameterType) {// 用XML脚本构建器解析XMLScriptBuilder builder new XMLScriptBuilder(configuration, script, parameterType);return builder.parseScriptNode();}Overridepublic ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);} }3.7.3 映射器语句类修改添加脚本语言驱动 MappedStatement.java package com.lino.mybatis.mapping;import com.lino.mybatis.scripting.LanguageDriver; import com.lino.mybatis.session.Configuration;/*** description: 映射器语句类*/ public class MappedStatement {private Configuration configuration;private String id;private SqlCommandType sqlCommandType;private SqlSource sqlSource;Class? resultType;private LanguageDriver lang;public MappedStatement() {}public static class Builder {private MappedStatement mappedStatement new MappedStatement();public Builder(Configuration configuration, String id, SqlCommandType sqlCommandType, SqlSource sqlSource, Class? resultType) {mappedStatement.configuration configuration;mappedStatement.id id;mappedStatement.sqlCommandType sqlCommandType;mappedStatement.sqlSource sqlSource;mappedStatement.resultType resultType;mappedStatement.lang configuration.getDefaultScriptingLanguageInstance();}public MappedStatement build() {assert mappedStatement.configuration ! null;assert mappedStatement.id ! null;return mappedStatement;}}public Configuration getConfiguration() {return configuration;}public String getId() {return id;}public SqlCommandType getSqlCommandType() {return sqlCommandType;}public SqlSource getSqlSource() {return sqlSource;}public Class? getResultType() {return resultType;}public LanguageDriver getLang() {return lang;} }3.7.4 修改配置类 Configuration.java package com.lino.mybatis.session;import com.lino.mybatis.binding.MapperRegistry; import com.lino.mybatis.datasource.druid.DruidDataSourceFactory; import com.lino.mybatis.datasource.pooled.PooledDataSourceFactory; import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory; import com.lino.mybatis.executor.Executor; import com.lino.mybatis.executor.SimpleExecutor; import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.executor.resultset.DefaultResultSetHandler; import com.lino.mybatis.executor.resultset.ResultSetHandler; import com.lino.mybatis.executor.statement.PreparedStatementHandler; import com.lino.mybatis.executor.statement.StatementHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.Environment; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.reflection.MetaObject; import com.lino.mybatis.reflection.factory.DefaultObjectFactory; import com.lino.mybatis.reflection.factory.ObjectFactory; import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory; import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory; import com.lino.mybatis.scripting.LanguageDriver; import com.lino.mybatis.scripting.LanguageDriverRegistry; import com.lino.mybatis.scripting.xmltags.XMLLanguageDriver; import com.lino.mybatis.transaction.Transaction; import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory; import com.lino.mybatis.type.TypeAliasRegistry; import com.lino.mybatis.type.TypeHandlerRegistry; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;/*** description: 配置项*/ public class Configuration {/*** 环境*/protected Environment environment;/*** 映射注册机*/protected MapperRegistry mapperRegistry new MapperRegistry(this);/*** 映射的语句存在Map里*/protected final MapString, MappedStatement mappedStatements new HashMap(16);/*** 类型别名注册机*/protected final TypeAliasRegistry typeAliasRegistry new TypeAliasRegistry();/*** 脚本语言注册器*/protected final LanguageDriverRegistry languageRegistry new LanguageDriverRegistry();/*** 类型处理器注册机*/protected final TypeHandlerRegistry typeHandlerRegistry new TypeHandlerRegistry();/*** 对象工厂*/protected ObjectFactory objectFactory new DefaultObjectFactory();/*** 对象包装工厂*/protected ObjectWrapperFactory objectWrapperFactory new DefaultObjectWrapperFactory();/*** 准备资源列表*/protected final SetString loadedResources new HashSet();/*** 数据库ID*/protected String databaseId;public Configuration() {typeAliasRegistry.registerAlias(JDBC, JdbcTransactionFactory.class);typeAliasRegistry.registerAlias(DRUID, DruidDataSourceFactory.class);typeAliasRegistry.registerAlias(UNPOOLED, UnpooledDataSourceFactory.class);typeAliasRegistry.registerAlias(POOLED, PooledDataSourceFactory.class);languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);}public void addMappers(String packageName) {mapperRegistry.addMappers(packageName);}public T void addMapper(ClassT type) {mapperRegistry.addMapper(type);}public T T getMapper(ClassT type, SqlSession sqlSession) {return mapperRegistry.getMapper(type, sqlSession);}public boolean hasMapper(Class? type) {return mapperRegistry.hasMapper(type);}public void addMappedStatement(MappedStatement ms) {mappedStatements.put(ms.getId(), ms);}public MappedStatement getMappedStatement(String id) {return mappedStatements.get(id);}public TypeAliasRegistry getTypeAliasRegistry() {return typeAliasRegistry;}public Environment getEnvironment() {return environment;}public void setEnvironment(Environment environment) {this.environment environment;}public String getDatabaseId() {return databaseId;}/*** 生产执行器** param transaction 事务* return 执行器*/public Executor newExecutor(Transaction transaction) {return new SimpleExecutor(this, transaction);}/*** 创建语句处理器** param executor 执行器* param mappedStatement 映射器语句类* param parameter 参数* param resultHandler 结果处理器* param boundSql SQL语句* return StatementHandler 语句处理器*/public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, ResultHandler resultHandler, BoundSql boundSql) {return new PreparedStatementHandler(executor, mappedStatement, parameter, resultHandler, boundSql);}/*** 创建结果集处理器** param executor 执行器* param mappedStatement 映射器语句类* param boundSql SQL语句* return ResultSetHandler 结果集处理器*/public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, BoundSql boundSql) {return new DefaultResultSetHandler(executor, mappedStatement, boundSql);}/*** 创建元对象** param object 原对象* return 元对象*/public MetaObject newMetaObject(Object object) {return MetaObject.forObject(object, objectFactory, objectWrapperFactory);}/*** 创建类型处理器注册机** return TypeHandlerRegistry 类型处理器注册机*/public TypeHandlerRegistry getTypeHandlerRegistry() {return typeHandlerRegistry;}/*** 是否包含资源** param resource 资源* return 是否*/public boolean isResourceLoaded(String resource) {return loadedResources.contains(resource);}/*** 添加资源** param resource 资源*/public void addLoadedResource(String resource) {loadedResources.add(resource);}/*** 获取脚本语言注册机** return languageRegistry 脚本语言注册机*/public LanguageDriverRegistry getLanguageRegistry() {return languageRegistry;}/*** 获取参数处理器** param mappedStatement 映射器语言类型* param parameterObject 参数对象* param boundSql SQL语句* return ParameterHandler参数处理器*/public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {// 创建参数处理器ParameterHandler parameterHandler mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);return parameterHandler;}/*** 获取默认脚本语言驱动** return 脚本语言驱动*/public LanguageDriver getDefaultScriptingLanguageInstance() {return languageRegistry.getDefaultDriver();} }添加获取默认脚本语言驱动 getDefaultScriptingLanguageInstance添加获取参数处理器 newParameterHandler 3.7.5 语句处理器抽象基类 BaseStatementHandler.java package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor; import com.lino.mybatis.executor.parameter.ParameterHandler; import com.lino.mybatis.executor.resultset.ResultSetHandler; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.session.Configuration; import com.lino.mybatis.session.ResultHandler; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement;/*** description: 语句处理器抽象基类*/ public abstract class BaseStatementHandler implements StatementHandler {protected final Configuration configuration;protected final Executor executor;protected final MappedStatement mappedStatement;protected final Object parameterObject;protected final ResultSetHandler resultSetHandler;protected final ParameterHandler parameterHandler;protected BoundSql boundSql;public BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultHandler, BoundSql boundSql) {this.configuration mappedStatement.getConfiguration();this.executor executor;this.mappedStatement mappedStatement;this.parameterObject parameterObject;this.boundSql boundSql;this.parameterHandler configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler configuration.newResultSetHandler(executor, mappedStatement, boundSql);}Overridepublic Statement prepare(Connection connection) {Statement statement null;try {// 实例化 Statementstatement instantiateStatement(connection);// 参数设置可以被抽取提供配置statement.setQueryTimeout(350);statement.setFetchSize(10000);return statement;} catch (Exception e) {throw new RuntimeException(Error prepare statement. Cause: e, e);}}protected abstract Statement instantiateStatement(Connection connection) throws SQLException;}添加 ParameterHandler 参数处理器 3.7.6 预处理语句处理器 PreparedStatementHandler.java package com.lino.mybatis.executor.statement;import com.lino.mybatis.executor.Executor; import com.lino.mybatis.mapping.BoundSql; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.session.ResultHandler; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.util.List;/*** description: 预处理语句处理器PREPARED*/ public class PreparedStatementHandler extends BaseStatementHandler {public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultSetHandler, BoundSql boundSql) {super(executor, mappedStatement, parameterObject, resultSetHandler, boundSql);}Overrideprotected Statement instantiateStatement(Connection connection) throws SQLException {String sql boundSql.getSql();return connection.prepareStatement(sql);}Overridepublic void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);}Overridepublic E ListE query(Statement statement, ResultHandler resultHandler) throws SQLException {PreparedStatement ps (PreparedStatement) statement;ps.execute();return resultSetHandler.handleResultSets(ps);} }3.7.7 默认sqlSession实现类添加日志描述 DefaultSqlSession.java package com.lino.mybatis.session.defaults;import com.alibaba.fastjson.JSON; import com.lino.mybatis.executor.Executor; import com.lino.mybatis.mapping.MappedStatement; import com.lino.mybatis.session.Configuration; import com.lino.mybatis.session.SqlSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List;/*** description: 默认sqlSession实现类*/ public class DefaultSqlSession implements SqlSession {private Logger logger LoggerFactory.getLogger(DefaultSqlSession.class);...Overridepublic T T selectOne(String statement, Object parameter) {logger.info(执行查询 statement{} parameter{}, statement, JSON.toJSONString(parameter));MappedStatement ms configuration.getMappedStatement(statement);ListT list executor.query(ms, parameter, Executor.NO_RESULT_HANDLER, ms.getSqlSource().getBoundSql(parameter));return list.get(0);}... } 四、测试参数处理器 4.1 修改 DAO 接口 IUserDao.java package com.lino.mybatis.test.dao;import com.lino.mybatis.test.po.User;/*** Description: 用户持久层*/ public interface IUserDao {/*** 根据ID查询用户信息** param uId ID* return User 用户*/User queryUserInfoById(Long uId);/*** 根据用户对象查询用户信息* param user 用户* return User 用户*/User queryUserInfo(User user); }4.2 修改 User 实体类 User.java package com.lino.mybatis.test.po;import java.util.Date;/*** description: 用户实例类*/ public class User {private Long id;/*** 用户ID*/private String userId;/*** 头像*/private String userHead;/*** 用户名称*/private String userName;/*** 创建时间*/private Date createTime;/*** 更新时间*/private Date updateTime;public User() {}public User(Long id, String userId) {this.id id;this.userId userId;}// getter/setter }4.3 配置Mapper文件 User_Mapper.xml ?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.lino.mybatis.test.dao.IUserDaoselect idqueryUserInfoById parameterTypejava.lang.Long resultTypecom.lino.mybatis.test.po.UserSELECT id, userId, userName, userHeadFROM userWHERE id #{id}/selectselect idqueryUserInfo parameterTypecom.lino.mybatis.test.po.User resultTypecom.lino.mybatis.test.po.UserSELECT id, userId, userName, userHeadFROM userwhere id #{id} and userId #{userId}/select /mapper4.4 单元测试 4.4.1 提取初始化SqlSession ApiTest.java private SqlSession sqlSession;Before public void init() throws IOException {// 1.从SqlSessionFactory中获取SqlSessionSqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(mybatis-config-datasource.xml));sqlSession sqlSessionFactory.openSession(); }因为接下来需要验证两种不同入参的单元测试所以提取 从SqlSessionFactory中获取SqlSession。 4.4.2 基本类型参数 ApiTest.java Test public void test_queryUserInfoId() {// 1.获取映射器对象IUserDao userDao sqlSession.getMapper(IUserDao.class);// 2.测试验证: 基本参数User user userDao.queryUserInfoById(1L);logger.info(测试结果{}, JSON.toJSONString(user)); }测试结果 10:06:48.775 [main] INFO c.l.mybatis.builder.SqlSourceBuilder - 构建参数映射 propertyid propertyTypeclass java.lang.Long 10:06:48.934 [main] INFO c.l.m.s.defaults.DefaultSqlSession - 执行查询 statementcom.lino.mybatis.test.dao.IUserDao.queryUserInfoById parameter1 10:06:49.805 [main] INFO c.l.m.d.pooled.PooledDataSource - Created connention 1043208434. 10:06:49.815 [main] INFO c.l.m.s.d.DefaultParameterHandler - 根据每个ParameterMapping中的TypeHandler设置对应的参数信息 value1 10:06:49.838 [main] INFO com.lino.mybatis.test.ApiTest - 测试结果{id:1,userHead:1_04,userId:10001,userName:小灵哥}从测试过程中可以在 DefaultParameterHandler#setParameters 中打断点验证方法参数以及获得到的类型处理器。这里测试可以通过可以满足基本类型对象的入参信息。 4.4.3 对象类型参数 ApiTest.java Test public void test_queryUserInfo() {// 1.获取映射器对象IUserDao userDao sqlSession.getMapper(IUserDao.class);// 2.测试验证: 对象参数User user userDao.queryUserInfo(new User(1L, 10001));logger.info(测试结果{}, JSON.toJSONString(user)); }测试结果 10:10:05.878 [main] INFO c.l.mybatis.builder.SqlSourceBuilder - 构建参数映射 propertyid propertyTypeclass java.lang.Long 10:10:05.878 [main] INFO c.l.mybatis.builder.SqlSourceBuilder - 构建参数映射 propertyuserId propertyTypeclass java.lang.String 10:10:05.947 [main] INFO c.l.m.s.defaults.DefaultSqlSession - 执行查询 statementcom.lino.mybatis.test.dao.IUserDao.queryUserInfo parameter{id:1,userId:10001} 10:10:06.574 [main] INFO c.l.m.d.pooled.PooledDataSource - Created connention 1107024580. 10:10:06.590 [main] INFO c.l.m.s.d.DefaultParameterHandler - 根据每个ParameterMapping中的TypeHandler设置对应的参数信息 value1 10:10:06.590 [main] INFO c.l.m.s.d.DefaultParameterHandler - 根据每个ParameterMapping中的TypeHandler设置对应的参数信息 value10001 10:10:06.590 [main] INFO com.lino.mybatis.test.ApiTest - 测试结果{id:1,userHead:1_04,userId:10001,userName:小灵哥}从测试结果验证对象参数 User 中包含两个属性时检查我们的代码处理过程验证是否可以正确获取到两个类型处理器分别设置参数的过程。从测试结果看可以看到测试通过并打印了相关参数的构建和使用。 五、总结参数处理器 已经把一个 ORM 框架的基本流程串联起来了包含的分包结构构建、绑定、映射、反射、执行、类型、事务、数据源等。参数类型的策略化设计通过策略解耦模板定义流程让我们整个参数设置变得更加清晰。还有一些细节的功能点MapperMethod 中添加方法签名、类型处理器创建和使用时都使用了 MetaObject 反射器工具类进行处理。
http://www.dnsts.com.cn/news/278553.html

相关文章:

  • 做产品网站营销推广wordpress4.5注册插件
  • 格尔木哪里有做网站的互动营销型网站建设
  • 怎么样做一家装修竞标网站怎样做自己的网站
  • seo托管seo关键词排名
  • 正规网站建设费用做网站软件排名
  • 乐清建设网站哪家好做的做的比较好的网站
  • led 网站建设龙岩做网站开发哪家做的好
  • jsp简述网站开发流程图电商入门基础知识
  • 个人免费网站建设模板网站域名在哪里查询
  • 哪里有做网站公司的广州门户网站建设
  • 成都的教育品牌网站建设wordpress显示切换到桌面版
  • win7下asp网站搭建网站建设制度都有哪些
  • 网站地图用什么格式单页网站模板修改吗
  • 网站开发软件著作权归谁wifi网络优化软件
  • 织梦移动端网站模板下载地址洛阳哪里做网站
  • 网站开发单位php网站的开发背景
  • 做网站的html框架丝路建设网站
  • 服务网站建设企业品牌营销策划怎么写
  • 网站登录记录怎么删除一级域名和二级域名怎么区分
  • 找公司的软件有哪些谷歌seo文章
  • 广州站是指哪个站工程资质加盟分公司
  • 潍坊网站建设一品网络小程序PHP 网站搜索怎么做
  • 韩都衣舍网站建设的改进做网站需要工商执照吗
  • 做外贸比较好的网站有哪些做go分析和kegg分析网站
  • 南平建设集团网站珠宝商城网站模板免费下载
  • 十堰北京网站建设辽宁网站建设排名
  • wordpress最多文章seo网站外链平台
  • 权重7以上的网站长沙网站建设方面
  • 做网站开发需要考什么证书千图网免费素材图库背景
  • 南宁做网站费用网站首页设计总结