1. 程式人生 > 實用技巧 >基於Mybatis原理實現的自定義持久框架

基於Mybatis原理實現的自定義持久框架

本次演示主基於mybatis原理實現,用Java+jdbc進行封裝的一個持久類框架;


pom.xml


<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>ipersistent</groupId>
    <artifactId>Ipersistence</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.release>1.8</maven.compiler.release>
    </properties>
    <dependencies>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>

        <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>
        <pluginManagement>
            <plugins>
                <!--This plugin's configuration is used to store Eclipse m2e settings 
                    only. It has no influence on the Maven build itself. -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-toolchains-plugin</artifactId>
                    <configuration>
                        <toolchains>
                            <jdk>
                                <version>1.8</version>
                                <vendor>mysql</vendor>
                            </jdk>
                        </toolchains>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>toolchain</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

            </plugins>
        </pluginManagement>
    </build>
</project>


SqpMapConfig.xml(相當於mybatis.xml)

<?xml version="1.0" encoding="UTF-8" ?> <configuration> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/lin_xu_db"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> <mapper resource="UserMapper.xml"></mapper> </configuration> UserMapper.xml(相當於mybatis的mapper)
<?xml version="1.0" encoding="UTF-8"?> <mapper namespace="com.test.UserDao"> <select id="selectUser" paramterType="com.test.User" resultType="com.test.User" autocommit="false"> select * from user_tb </select> </mapper> 配置解析 import java.util.HashMap; import
java.util.Map; import javax.sql.DataSource; /** * * @author linxu * */ public class Configuration { private DataSource dataSource; private Map<String, MappedStatement> mappedStatement = new HashMap<String, MappedStatement>(); public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public Map<String, MappedStatement> getMappedStatement() { return mappedStatement; } public void setMappedStatement(Map<String, MappedStatement> mappedStatement) { this.mappedStatement = mappedStatement; } } package com.Ipersistence.configuration; /** * * @author linxu * */ public class MappedStatement { private String id;// id標識 private Class<?> resultType;// 返回值型別 private Class<?> paramterType;// 引數型別 private String sql;// SQL private String dbAction;// updata/insert/select/delete標識 private boolean autoCommit;// public MappedStatement(Builder builder) { this.id = builder.id; this.resultType = builder.resultType; this.paramterType = builder.paramterType; this.sql = builder.sql; this.dbAction = builder.dbAction; this.autoCommit=builder.autoCommit; } public boolean isAutoCommit() { return autoCommit; } public void setAutoCommit(boolean autoCommit) { this.autoCommit = autoCommit; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Class<?> getResultType() { return resultType; } public void setResultType(Class<?> resultType) { this.resultType = resultType; } public Class<?> getParamterType() { return paramterType; } public void setParamterType(Class<?> paramterType) { this.paramterType = paramterType; } public String getSql() { return sql; } public void setSql(String sql) { this.sql = sql; } public String getDbAction() { return dbAction; } public void setDbAction(String dbAction) { this.dbAction = dbAction; } public static class Builder { private String id;// id標識 private Class<?> resultType;// 返回值型別 private Class<?> paramterType;// 引數型別 private String sql;// SQL private String dbAction; private boolean autoCommit;// public Builder putId(String id) { this.id = id; return this; } public Builder putResultType(Class<?> resultType) { this.resultType = resultType; return this; } public Builder putParamterType(Class<?> paramterType) { this.paramterType = paramterType; return this; } public Builder putSql(String sql) { this.sql = sql; return this; } public Builder putDbAction(String dbAction) { this.dbAction = dbAction; return this; } public MappedStatement builder() { return new MappedStatement(this); } public Builder putAutoCommit(boolean autoCommit) { this.autoCommit=autoCommit; return this; } } } package com.Ipersistence.configuration; import java.beans.PropertyVetoException; import java.io.InputStream; import java.util.List; import java.util.Properties; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.Ipersistence.io.Resources; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * * @author linxu * */ public class XMLConfigerBuilder { private Configuration configuration; public XMLConfigerBuilder() { this.configuration = new Configuration(); } public Configuration getConfiguration() { return configuration; } public void setConfiguration(Configuration configuration) { this.configuration = configuration; } @SuppressWarnings("unchecked") public Configuration parseConfig(InputStream inputStream) throws DocumentException, PropertyVetoException { Document document = new SAXReader().read(inputStream); Element rootElement = document.getRootElement(); List<Element> configElement = rootElement.selectNodes("property"); Properties properties = new Properties(); for (Element element : configElement) { String nameproperty = element.attributeValue("name"); String valueProperty = element.attributeValue("value"); properties.setProperty(nameproperty, valueProperty); } ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setUser(properties.getProperty("user")); comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl")); comboPooledDataSource.setPassword(properties.getProperty("password")); comboPooledDataSource.setDriverClass(properties.getProperty("driverClass")); configuration.setDataSource(comboPooledDataSource); // 解析mapper.xml檔案 List<Element> mapperElement = rootElement.selectNodes("//mapper"); XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration); for (Element element : mapperElement) { String mapperResource = element.attributeValue("resource"); InputStream mapperInputStream = Resources.getResourceAsStream(mapperResource); xmlMapperBuilder.parseMapper(mapperInputStream); } return configuration; } } package com.Ipersistence.configuration; import java.io.InputStream; import java.util.List; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * * @author linxu * */ public class XMLMapperBuilder { Configuration configuration; public XMLMapperBuilder(Configuration configuration) { this.configuration = configuration; } public void parseMapper(InputStream inputStream) throws DocumentException { parseXml(new SAXReader().read(inputStream).getRootElement(), "select", "insert", "delete", "update"); } @SuppressWarnings("unchecked") public void parseXml(Element rootElement, String... dbActions) { String namespace = rootElement.attributeValue("namespace"); for (int i = 0; i < dbActions.length; i++) { List<Element> elements = rootElement.selectNodes(dbActions[i]); if (elements != null && !elements.isEmpty()) { for (Element element : elements) { String id = element.attributeValue("id"); String paramterType = element.attributeValue("paramterType"); String resultType = element.attributeValue("resultType"); String sqlText = element.getTextTrim(); String autoVommit = element.attributeValue("autocommit").trim(); configuration.getMappedStatement().put(namespace + "." + id, new MappedStatement.Builder().putId(id).putParamterType(getClassType(paramterType)) .putResultType(getClassType(resultType)).putSql(sqlText).putDbAction(dbActions[i]) .putAutoCommit(autoVommit.isEmpty() ? true : autoVommit.equals("true")).builder()); } } } } private Class<?> getClassType(String className) { if (!className.isEmpty()) { try { return Class.forName(className); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } } Session工廠(實現類似mybatis的session訪問,利用動態代理實現類似mybatis的介面式開發) package com.Ipersistence.session; import java.sql.SQLException; import java.util.List; /** * * @author linxu * */ public interface SqlSession { public <E> List<E> selectList(String statementId, Object... params)throws SecurityException, SQLException, Exception; public <E> E selectOne(String statementId, Object... params) throws SecurityException, SQLException, Exception; public int executeUpdate(String statementId, Object... params) throws SecurityException, SQLException, Exception; public int update(String statementId, Object... params) throws SecurityException, SQLException, Exception; public int insert(String statementId, Object... params) throws SecurityException, SQLException, Exception; public int delete(String statementId, Object... params) throws SecurityException, SQLException, Exception; public void close(); public <T> T getMapper(Class<?> mapperClass); public void commit(); } package com.Ipersistence.session; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Proxy; import java.sql.SQLException; import java.util.List; import com.Ipersistence.configuration.Configuration; import com.Ipersistence.configuration.MappedStatement; import com.Ipersistence.executor.BaseExecutor; import com.Ipersistence.executor.Executor; /** * * @author ;linxu * */ public class DefaultSession implements SqlSession { private Configuration configuration; public DefaultSession(Configuration configuration) { this.configuration = configuration; } Executor baseExecutor = new BaseExecutor(); @Override public <E> List<E> selectList(String statementId, Object... params) throws SecurityException, SQLException, Exception { final MappedStatement mappedStatement = configuration.getMappedStatement().get(statementId); if (mappedStatement != null) { return baseExecutor.query(configuration, mappedStatement, params); } return null; } @Override public <E> E selectOne(String statementId, Object... params) throws SecurityException, SQLException, Exception { List<E> list = selectList(statementId, params); if (list != null && list.size() == 1) { return list.get(0); } else { throw new RuntimeException("查詢資料為Null或則查詢資料過多:"); } } @Override public int executeUpdate(String statementId, Object... params) throws SecurityException, SQLException, Exception { final MappedStatement mappedStatement = configuration.getMappedStatement().get(statementId); if (mappedStatement == null) { return this.baseExecutor.executeUpdate(configuration, mappedStatement, params); } return 0; } @Override public int update(String statementId, Object... params) throws SecurityException, SQLException, Exception { // TODO Auto-generated method stub return this.executeUpdate(statementId, params); } @Override public int insert(String statementId, Object... params) throws SecurityException, SQLException, Exception { // TODO Auto-generated method stub return this.executeUpdate(statementId, params); } @Override public int delete(String statementId, Object... params) throws SecurityException, SQLException, Exception { // TODO Auto-generated method stub return this.executeUpdate(statementId, params); } @SuppressWarnings("unchecked") @Override public <T> T getMapper(Class<?> mapperClass) { Object proxy = Proxy.newProxyInstance(DefaultSession.class.getClassLoader(), new Class[] { mapperClass }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] params) throws Throwable { // 方法名字 String methodname = method.getName(); // 獲取介面類 String className = method.getDeclaringClass().getName(); String statementId = className + "." + methodname; java.lang.reflect.Type resultType = method.getGenericReturnType(); MappedStatement mappedStatement = configuration.getMappedStatement().get(statementId); if (mappedStatement == null) { throw new RuntimeException("sql配置不存在:" + DefaultSession.class.getName()); } if (mappedStatement.getDbAction().equals("select")) { // 如果返回值型別是泛型,呼叫selectList,否則selectOne if (resultType instanceof ParameterizedType) { return selectList(statementId, params); } else { return selectOne(statementId, params); } } else if (mappedStatement.getDbAction().equals("insert") || mappedStatement.getDbAction().equals("delete") || mappedStatement.getDbAction().equals("update")) { return executeUpdate(statementId, params); } else { throw new RuntimeException("mapper配置檔案錯誤:"); } } }); return (T) proxy; } @Override public void close() { try { baseExecutor.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void commit() { try { baseExecutor.commit(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package com.Ipersistence.session; /** * SqlSessionFactory工廠類:生產SqlSession * @author linxu * */ public interface SqlSessionFactory{ public SqlSession openSession(); } package com.Ipersistence.session; import com.Ipersistence.configuration.Configuration; /** * * @author linxu * */ public class DefaultSqlSessionFactory implements SqlSessionFactory { private Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } @Override public SqlSession openSession() { // TODO Auto-generated method stub return new DefaultSession(configuration); } } package com.Ipersistence.session; import java.beans.PropertyVetoException; import java.io.InputStream; import org.dom4j.DocumentException; import com.Ipersistence.configuration.Configuration; import com.Ipersistence.configuration.XMLConfigerBuilder; /** * SqlSessionFactoryBuilder,利用配置構建個SqlSessionFactory工廠 * * @author linxu * */ public class SqlSessionFactoryBuilder { private Configuration configuration; /** * * @param inputStream * @return * @throws PropertyVetoException * @throws DocumentException */ public SqlSessionFactory builder(InputStream inputStream) throws DocumentException, PropertyVetoException { XMLConfigerBuilder xMLConfigerBuilder = new XMLConfigerBuilder(); this.configuration = xMLConfigerBuilder.parseConfig(inputStream); DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration); return defaultSqlSessionFactory; } } Io讀取 package com.Ipersistence.io; import java.io.InputStream; /** * * @author linxu * */ public class Resources { /** * * @param path * @return */ public static InputStream getResourceAsStream(String path) { return Resources.class.getClassLoader().getResourceAsStream(path); } } Executor實現(主要封裝了jdbc對資料庫的操作) package com.Ipersistence.executor; import java.sql.SQLException; import java.util.List; import com.Ipersistence.boundsql.BoundSql; import com.Ipersistence.configuration.Configuration; import com.Ipersistence.configuration.MappedStatement; /** * * @author linxu * */ public interface Executor { public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, Exception, SecurityException; public int executeUpdate(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, Exception, SecurityException; // 關閉連線操作 public void close() throws SQLException; public BoundSql getBoundSql(String sql); public void commit() throws SQLException; } package com.Ipersistence.executor; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.Ipersistence.boundsql.BoundSql; import com.Ipersistence.configuration.Configuration; import com.Ipersistence.configuration.MappedStatement; import com.Ipersistence.utils.GenericTokenParser; import com.Ipersistence.utils.ParameterMapping; import com.Ipersistence.utils.ParameterMappingTokenHandler; /** * * @author linxu * */ public class BaseExecutor implements Executor { private Connection connection; @SuppressWarnings("unchecked") @Override public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, Exception, SecurityException { this.connection = configuration.getDataSource().getConnection(); String sql = mappedStatement.getSql(); BoundSql boundSql = getBoundSql(sql); PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); if(parameterMappings!=null&&!parameterMappings.isEmpty()) { for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); String valuename = parameterMapping.getContent(); // 鎷垮埌榪欎釜瀛楁瀵矽薄 Field field = mappedStatement.getParamterType().getDeclaredField(valuename); // 璁劇疆鏉冮檺 field.setAccessible(true); Object o = field.get(params[0]); preparedStatement.setObject(i + 1, o); } } // 鎵ц鏁版嵁鏌ヨ ResultSet resultSet = preparedStatement.executeQuery(); // 瑙f瀽鏁版嵁 List<E> result_list = new ArrayList<>(); while (resultSet.next()) { ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); E e = (E) mappedStatement.getResultType().newInstance(); for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { String columnname = resultSetMetaData.getColumnName(i); Object value = resultSet.getObject(columnname); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnname, mappedStatement.getResultType()); Method method = propertyDescriptor.getWriteMethod(); method.invoke(e, value); } result_list.add(e); } return result_list; } @Override public int executeUpdate(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, Exception, SecurityException { // 瀹屾垚瀵規暟鎹簱鑳¤闂� // 1鑾峰彇榪炴帴 connection = configuration.getDataSource().getConnection(); // 鍒ゆ柇鏄惁鏄緗嚜鍔ㄦ彁浜� if (mappedStatement.isAutoCommit()) connection.setAutoCommit(true); // 鍏抽棴鑷姩鎻愪氦 connection.setAutoCommit(false); // 2鑾峰彇Sql String sql = mappedStatement.getSql(); // 3杞崲sql,灝嗚В鏋� BoundSql boundSql = getBoundSql(sql); // 4鑾峰彇棰勫鐞嗗璞reparedStatement PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText()); // 鑾峰彇鍙傛暟瀵矽薄綾誨瀷 Class<?> parameterClass = mappedStatement.getParamterType(); // 鏁版嵁鍙傛暟璁劇疆 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); String content = parameterMapping.getContent(); // 鑾峰彇灞炴�у璞� Field field = parameterClass.getDeclaredField(content); // 璁劇疆鏉冮檺 field.setAccessible(true); // 鑾峰彇灞炴�у璞″�� Object o = field.get(params[0]); // 璦疆鍙傛暟 preparedStatement.setObject(i + 1, o); } // 鎵цsql return preparedStatement.executeUpdate(); } @Override public void close() throws SQLException { if (connection != null) { this.connection.close(); } } @Override public BoundSql getBoundSql(String sql) { final ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler(); final GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler); String sqlText = genericTokenParser.parse(sql); List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings(); return new BoundSql.Builder().putSqlText(sqlText).putParameterMappings(parameterMappings).builder(); } @Override public void commit() throws SQLException { // 濡傛灉宸茬粡璁劇疆涓鴻嚜鍔ㄦ彁浜や簡錛屽氨娌″繀瑕佸啀閲嶅鎻愪氦 if (connection != null) { if (connection.getAutoCommit() == true) { return; } try { connection.commit(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } sql轉換(和mybatis原理一致) package com.Ipersistence.boundsql; import java.util.List; import com.Ipersistence.utils.ParameterMapping; /** * 轉換sql * @author linxu * */ public class BoundSql { private String sqlText; private List<ParameterMapping> parameterMappings; public String getSqlText() { return sqlText; } public void setSqlText(String sqlText) { this.sqlText = sqlText; } public List<ParameterMapping> getParameterMappings() { return parameterMappings; } public void setParameterMappings(List<ParameterMapping> parameterMappings) { this.parameterMappings = parameterMappings; } public BoundSql(Builder builder) { this.sqlText = builder.sqlText; this.parameterMappings = builder.parameterMappings; } public static class Builder { private String sqlText; private List<ParameterMapping> parameterMappings; public Builder putSqlText(String sql) { this.sqlText = sql; return this; } public Builder putParameterMappings(List<ParameterMapping> parameterMappings) { this.parameterMappings = parameterMappings; return this; } public BoundSql builder() { return new BoundSql(this); } } } 以下工具類是我從mybatis拷貝而來的,也貼上 /** * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.Ipersistence.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.Ipersistence.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.Ipersistence.utils; import java.util.ArrayList; import java.util.List; public class ParameterMappingTokenHandler implements TokenHandler { private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>(); // context是引數名�? #{id} #{username} 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; } } /** * Copyright 2009-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.Ipersistence.utils; /** * @author Clinton Begin */ public interface TokenHandler { String handleToken(String content); } 測試: package com.test; public class User { private int id; private String username; private String userid; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", userid=" + userid + ", getId()=" + getId() + ", getUsername()=" + getUsername() + ", getUserid()=" + getUserid() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString() + "]"; } } //dao介面 package com.test; import java.util.List; public interface UserDao { public List<User>selectUser(User user); } package com.test; import java.beans.PropertyVetoException; import org.dom4j.DocumentException; import com.Ipersistence.io.Resources; import com.Ipersistence.session.SqlSession; import com.Ipersistence.session.SqlSessionFactory; import com.Ipersistence.session.SqlSessionFactoryBuilder; public class UserTest { public static void main(String[] args) throws DocumentException, PropertyVetoException { SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .builder(Resources.getResourceAsStream("SqlMapConfig.xml")); SqlSession sqlSession = sqlSessionFactory.openSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); User user=new User(); System.err.println(userDao.selectUser(user).toString()); sqlSession.close(); } }