zoukankan      html  css  js  c++  java
  • 个人知识管理系统Version1.0开发记录(10)

    物理分页

          这次我们运用Mybatis拦截器来实现物理分页,后面会运用动态sql来实现,或者运用Map/CollectionUtils/StringUtils编写工具类来实现。oracle是运用的rownum,mysql是运用的limit offset,pagesize。代码中有大量注释,可以参考Mybatis基本原理一起阅读。后面,我们会根据一些实际开发需要,把物理分页功能的代码封装成jar包,以后直接调用就好了,比如Mybatis+Spring3的运行环境,可以采用Mybatis动态sql来实现分页,也可以采用Mybatis插件。

    1、项目备份。一定要勤于备份。我们永远不知道我们什么时候,会把早上还跑得通的一个项目,到晚上都还找不到哪里被玩坏了。是的,我们在编写控制层的时候,交互使用了struts2和springmvc,想看看他们之间的差异,然后,就迷糊了,由于忘记备份struts2版本的,到了晚上就只好还原到昨天的去了。很晕很晕。

    2、Mybatis插件类,实现拦截器,实现sql重写。每一个拦截器必须实现三个方法。

      1 package com.dyl.util;
      2 
      3 import java.lang.reflect.Field;
      4 import java.sql.Connection;
      5 import java.sql.PreparedStatement;
      6 import java.sql.ResultSet;
      7 import java.sql.SQLException;
      8 import java.util.List;
      9 import java.util.Map;
     10 import java.util.Properties;
     11 
     12 import javax.xml.bind.PropertyException;
     13 
     14 import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;
     15 import org.apache.ibatis.executor.ErrorContext;
     16 import org.apache.ibatis.executor.ExecutorException;
     17 import org.apache.ibatis.executor.statement.BaseStatementHandler;
     18 import org.apache.ibatis.executor.statement.RoutingStatementHandler;
     19 import org.apache.ibatis.executor.statement.StatementHandler;
     20 import org.apache.ibatis.mapping.BoundSql;
     21 import org.apache.ibatis.mapping.MappedStatement;
     22 import org.apache.ibatis.mapping.ParameterMapping;
     23 import org.apache.ibatis.mapping.ParameterMode;
     24 import org.apache.ibatis.plugin.Interceptor;
     25 import org.apache.ibatis.plugin.Intercepts;
     26 import org.apache.ibatis.plugin.Invocation;
     27 import org.apache.ibatis.plugin.Plugin;
     28 import org.apache.ibatis.plugin.Signature;
     29 import org.apache.ibatis.reflection.MetaObject;
     30 import org.apache.ibatis.reflection.property.PropertyTokenizer;
     31 import org.apache.ibatis.session.Configuration;
     32 import org.apache.ibatis.type.TypeHandler;
     33 import org.apache.ibatis.type.TypeHandlerRegistry;
     34 /**
     35  * 拦截器签名
     36  * 要拦截的目标类型是StatementHandler(注意:type只能配置成接口类型),拦截的方法是,名称为prepare,参数为Connection类型的方法。
     37  * @author dyl
     38  * @date 2014-7-12
     39  */
     40 @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
     41 public class PagePlugin implements Interceptor {
     42     /**
     43      * Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的)。
     44      * 
     45      * 每一个拦截器都必须实现的三个方法。
     46      * (1)Object intercept(Invocation ivk),实现拦截逻辑的地方,内部要通过invocation.proceed()显式地推进责任链前进,
     47      *  也就是调用下一个拦截器拦截目标方法。
     48      * (2)Object plugin(Object target),用当前这个拦截器生成对目标target的代理,实际是通过Plugin.wrap(target,this)来完成的,
     49      *  把目标target和拦截器this传给了包装函数。
     50      * (3)void setProperties(Properties p),设置额外的参数,参数配置在拦截器的Properties节点里。
     51      * 
     52      * Mybatis配置的插件,运行时发生。
     53      * (1)所有可能被拦截的处理类都会生成一个代理。
     54      * (2)处理类代理在执行对应方法时,判断要不要执行插件中的拦截方法。
     55      * (3)执行插接中的拦截方法后,推进目标的执行。
     56      */
     57     private static String dialect = "";
     58     private static String pageSqlId = "";
     59 /*
     60  * intercept的实现
     61  * 实现拦截逻辑的地方,内部要通过invocation.proceed()显式地推进责任链前进,也就是调用下一个拦截器拦截目标方法。
     62  * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
     63  */
     64     @SuppressWarnings("unchecked")
     65     public Object intercept(Invocation ivk) throws Throwable {
     66         /**
     67          * StatementHandler的默认实现类是RoutingStatementHandler,因此拦截的实际对象是它。
     68          * RoutingStatementHandler的主要功能是分发,它根据配置Statement类型创建真正执行数据库操作的StatementHandler,并将其保存到delegate属性里。
     69          * 由于delegate是一个私有属性并且没有提供访问它的方法,因此需要借助ReflectHelper的帮忙。
     70          * 通过ReflectHelper的封装后我们可以轻易的获得想要的属性。
     71          */
     72         if (ivk.getTarget() instanceof RoutingStatementHandler) {
     73             RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();
     74             BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");
     75             MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement");
     76             
     77             // 只重写需要分页的sql语句。通过MappedStatement的ID匹配,默认重写以Page结尾的MappedStatement的sql。
     78             if (mappedStatement.getId().matches(pageSqlId)) {
     79                 BoundSql boundSql = delegate.getBoundSql();
     80                 Object parameterObject = boundSql.getParameterObject();
     81                 if (parameterObject == null) {
     82                     throw new NullPointerException("parameterObject error");
     83                 } else {
     84                     Connection connection = (Connection) ivk.getArgs()[0];
     85                     String sql = boundSql.getSql();
     86                     // 记录总记录数
     87                     String countSql = "select count(0) from (" + sql + ") myCount";
     88                     // System.out.println("总数sql 语句:" + countSql);
     89                     PreparedStatement countStmt = connection.prepareStatement(countSql);
     90                     BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
     91                             boundSql.getParameterMappings(), parameterObject);
     92                     // 重设分页参数里的总页数等
     93                     setParameters(countStmt, mappedStatement, countBS, parameterObject);
     94                     
     95                     ResultSet rs = countStmt.executeQuery();
     96                     int count = 0;
     97                     if (rs.next()) {
     98                         count = rs.getInt(1);
     99                     }
    100                     rs.close();
    101                     countStmt.close();
    102                     
    103                     // 分页参数作为参数对象parameterObject的一个属性
    104                     PageInfo page = null;
    105                     if (parameterObject instanceof PageInfo) {
    106                         page = (PageInfo) parameterObject;
    107                         page.setTotalResult(count);
    108                     } else if (parameterObject instanceof Map) {
    109                         Map<String, Object> map = (Map<String, Object>) parameterObject;
    110                         page = (PageInfo) map.get("page");
    111                         if (page == null)
    112                             page = new PageInfo();
    113                         page.setTotalResult(count);
    114                     } else {
    115                         Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "page");
    116                         if (pageField != null) {
    117                             page = (PageInfo) ReflectHelper.getValueByFieldName(parameterObject, "page");
    118                             if (page == null)
    119                                 page = new PageInfo();
    120                             page.setTotalResult(count);
    121                             ReflectHelper.setValueByFieldName(parameterObject, "page", page);
    122                         } else {
    123                             throw new NoSuchFieldException(parameterObject.getClass().getName());
    124                         }
    125                     }
    126                     // 重写sql
    127                     String pageSql = generatePageSql(sql, page);
    128                     System.out.println("page sql:" + pageSql);
    129                     ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql);
    130                 }
    131             }
    132         }
    133         // 将执行权交给下一个拦截器,完成调用链的推进。
    134         return ivk.proceed();
    135     }
    136     /**
    137      * 重设分页参数里的总页数等
    138      * @param ps
    139      * @param mappedStatement
    140      * @param boundSql
    141      * @param parameterObject
    142      * @throws SQLException
    143      */
    144     private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) 
    145             throws SQLException {
    146         ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    147         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    148         if (parameterMappings != null) {
    149             Configuration configuration = mappedStatement.getConfiguration();
    150             TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    151             MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
    152             for (int i = 0; i < parameterMappings.size(); i++) {
    153                 ParameterMapping parameterMapping = parameterMappings.get(i);
    154                 if (parameterMapping.getMode() != ParameterMode.OUT) {
    155                     Object value;
    156                     String propertyName = parameterMapping.getProperty();
    157                     PropertyTokenizer prop = new PropertyTokenizer(propertyName);
    158                     if (parameterObject == null) {
    159                         value = null;
    160                     } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
    161                         value = parameterObject;
    162                     } else if (boundSql.hasAdditionalParameter(propertyName)) {
    163                         value = boundSql.getAdditionalParameter(propertyName);
    164                     } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) 
    165                             && boundSql.hasAdditionalParameter(prop.getName())) {
    166                         value = boundSql.getAdditionalParameter(prop.getName());
    167                         if (value != null) {
    168                             value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));
    169                         }
    170                     } else {
    171                         value = metaObject == null ? null : metaObject.getValue(propertyName);
    172                     }
    173                     TypeHandler typeHandler = parameterMapping.getTypeHandler();
    174                     if (typeHandler == null) {
    175                         throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName + " of statement "
    176                                         + mappedStatement.getId());
    177                     }
    178                     typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
    179                 }
    180             }
    181         }
    182     }
    183     /**
    184      * sql重写,在原始的sql语句上加入分页的参数,目前支持mysql和oracle两种数据库的分页。
    185      * @param sql
    186      * @param page
    187      * @return
    188      */
    189     private String generatePageSql(String sql, PageInfo page) {
    190         if (page != null && (dialect != null || !dialect.equals(""))) {
    191             StringBuffer pageSql = new StringBuffer();
    192             //StringBuilder pageSql = new StringBuilder();
    193             if ("mysql".equals(dialect)) {
    194                 //pageSql=generatePageSqlForMysql(sql,page);
    195                 pageSql.append(sql);
    196                 pageSql.append(" limit " + page.getCurrentResult() + "," + page.getShowCount());
    197             } else if ("oracle".equals(dialect)) {
    198                 //pageSql = generatePageSqlForOracle(sql, page);
    199                 pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");
    200                 pageSql.append(sql);
    201                 pageSql.append(")  tmp_tb where ROWNUM<=");
    202                 //pageSql.append(page.getCurrentResult() + page.getShowCount());
    203                 pageSql.append(page.getCurrentPage()*page.getShowCount());
    204                 pageSql.append(") where row_id>");
    205                 //pageSql.append(page.getCurrentResult());
    206                 pageSql.append((page.getCurrentPage() - 1) * page.getShowCount());
    207             }
    208             return pageSql.toString();
    209         } else {
    210             return sql;
    211         }
    212     }
    213     /**
    214      * mysql的分页实现
    215      * @param sql
    216      * @param page
    217      * @return
    218      */
    219     public StringBuilder generatePageSqlForMysql(String sql, PageInfo page) {
    220         StringBuilder pageSql = new StringBuilder(100);
    221         String beginrow = String.valueOf((page.getCurrentPage() - 1) * page.getShowCount());
    222         pageSql.append(sql);
    223         pageSql.append(" limit " + beginrow + "," + page.getShowCount());
    224         return pageSql;
    225     }
    226     /**
    227      * oracle的分页实现
    228      * @param sql
    229      * @param page
    230      * @return
    231      */
    232     public StringBuilder generatePageSqlForOracle(String sql, PageInfo page) {
    233         StringBuilder pageSql = new StringBuilder(100);
    234         String beginrow = String.valueOf((page.getCurrentPage() - 1) * page.getShowCount());
    235         String endrow = String.valueOf(page.getCurrentPage() * page.getShowCount());
    236         pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
    237         pageSql.append(sql);
    238         pageSql.append(" ) temp where rownum <= ").append(endrow);
    239         pageSql.append(") where row_id > ").append(beginrow);
    240         return pageSql;
    241     }
    242     /**
    243      * plugin的实现
    244      * 用当前这个拦截器生成对目标target的代理,实际是通过Plugin.wrap(target,this)来完成的,把目标target和拦截器this传给了包装函数。
    245      */
    246     public Object plugin(Object target) {
    247         // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数。
    248         if (target instanceof StatementHandler) {
    249             return Plugin.wrap(target, this);
    250         } else {
    251             return target;
    252         }
    253     }
    254     /**
    255      * 设置额外的参数,参数配置在拦截器的Properties节点里。
    256      */
    257     public void setProperties(Properties p) {
    258         dialect = p.getProperty("dialect");
    259         if (dialect == null || dialect.equals("")) {
    260             try {
    261                 throw new PropertyException("dialect property is not found!");
    262             } catch (PropertyException e) {
    263                 e.printStackTrace();
    264             }
    265         }
    266         pageSqlId = p.getProperty("pageSqlId");
    267         if (dialect == null || dialect.equals("")) {
    268             try {
    269                 throw new PropertyException("pageSqlId property is not found!");
    270             } catch (PropertyException e) {
    271                 e.printStackTrace();
    272             }
    273         }
    274     }
    275 }
    View Code

    3、页面实体类,把页面相关属性封装成一个类,方便数据传输。----------------------------上面的属性是用于拦截器的,下面的属性是用于动态sql和工具类的。

      1 package com.dyl.util;
      2 
      3 import java.io.Serializable;
      4 import java.util.List;
      5 /**
      6  * 页面
      7  * @author dyl
      8  * @date 2014-7-12
      9  */
     10 public class PageInfo implements Serializable {
     11     private static final long serialVersionUID = -7404704191471426656L;
     12     // pagesize,每一页显示多少
     13     private int showCount = 3;
     14     // 总页数
     15     private int totalPage;
     16     // 总记录数
     17     private int totalResult;
     18     // 当前页数
     19     private int currentPage;
     20     // 当前显示到的ID,在mysql limit 中就是第一个参数。
     21     private int currentResult;
     22     private String sortField;
     23     private String order;
     24     
     25     // ----------------------------------------------------------------------
     26     
     27     // 分页结果
     28     private List<?> result;
     29     
     30     // 查询条件
     31     private List<?> conditions;
     32     
     33     // 开始页码
     34     private int start;
     35 
     36     // 每页多少
     37     private int limit;
     38     
     39     // 成功与否
     40     private boolean success;
     41     
     42     // 总记录数
     43     private int totalProperty;
     44 
     45     public int getTotalProperty() {
     46         return totalProperty;
     47     }
     48 
     49     public void setTotalProperty(int totalProperty) {
     50         this.totalProperty = totalProperty;
     51     }
     52 
     53     public boolean isSuccess() {
     54         return success;
     55     }
     56 
     57     public void setSuccess(boolean success) {
     58         this.success = success;
     59     }
     60 
     61     public int getStart() {
     62         return start;
     63     }
     64 
     65     public void setStart(int start) {
     66         this.start = start;
     67     }
     68 
     69     public int getLimit() {
     70         return limit;
     71     }
     72 
     73     public void setLimit(int limit) {
     74         this.limit = limit;
     75     }
     76 
     77     public List<?> getConditions() {
     78         return conditions;
     79     }
     80 
     81     public void setConditions(List<?> conditions) {
     82         this.conditions = conditions;
     83     }
     84 
     85     public List<?> getResult() {
     86         return result;
     87     }
     88 
     89     public void setResult(List<?> result) {
     90         this.result = result;
     91     }
     92 
     93     public int getShowCount() {
     94         return showCount;
     95     }
     96 
     97     public void setShowCount(int showCount) {
     98         this.showCount = showCount;
     99     }
    100 
    101     public int getTotalPage() {
    102         return totalPage;
    103     }
    104 
    105     public void setTotalPage(int totalPage) {
    106         this.totalPage = totalPage;
    107     }
    108 
    109     public int getTotalResult() {
    110         return totalResult;
    111     }
    112 
    113     public void setTotalResult(int totalResult) {
    114         this.totalResult = totalResult;
    115     }
    116 
    117     public int getCurrentPage() {
    118         return currentPage;
    119     }
    120 
    121     public void setCurrentPage(int currentPage) {
    122         this.currentPage = currentPage;
    123     }
    124 
    125     public int getCurrentResult() {
    126         return currentResult;
    127     }
    128 
    129     public void setCurrentResult(int currentResult) {
    130         this.currentResult = currentResult;
    131     }
    132 
    133     public String getSortField() {
    134         return sortField;
    135     }
    136 
    137     public void setSortField(String sortField) {
    138         this.sortField = sortField;
    139     }
    140 
    141     public String getOrder() {
    142         return order;
    143     }
    144 
    145     public void setOrder(String order) {
    146         this.order = order;
    147     }
    148 }
    View Code

    4、delegate是一个私有属性并且没有提供访问它的方法,因此我们需要写一个工具类来访问它,这个工具类封装了和它相关的一些方法。

     1 package com.dyl.util;
     2 
     3 import java.lang.reflect.Field;
     4 
     5 /**
     6  * 辅助类
     7  * 
     8  * StatementHandler的默认实现类是RoutingStatementHandler,因此拦截的实际对象是它。
     9  * RoutingStatementHandler的主要功能是分发,它根据配置Statement类型创建真正执行数据库操作的StatementHandler,并将其保存到delegate属性里。
    10  * 由于delegate是一个私有属性并且没有提供访问它的方法,因此需要借助ReflectHelper的帮忙。
    11  * 通过ReflectHelper的封装后我们可以轻易的获得想要的属性。
    12  * 
    13  * @author dyl
    14  * @date 2014-07-12
    15  */
    16 public class ReflectHelper {
    17     public static Field getFieldByFieldName(Object obj, String fieldName) {
    18         // 从拦截器的注解中获取拦截的类名
    19         for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
    20             try {
    21                 return superClass.getDeclaredField(fieldName);
    22             } catch (NoSuchFieldException e) {
    23             }
    24         }
    25         return null;
    26     }
    27 
    28     /**
    29      * Obj fieldName 获取属性值
    30      * 
    31      * @param obj
    32      * @param fieldName
    33      * @return
    34      * @throws SecurityException
    35      * @throws NoSuchFieldException
    36      * @throws IllegalArgumentException
    37      * @throws IllegalAccessException
    38      */
    39     public static Object getValueByFieldName(Object obj, String fieldName) throws SecurityException, NoSuchFieldException,
    40             IllegalArgumentException, IllegalAccessException {
    41         Field field = getFieldByFieldName(obj, fieldName);
    42         Object value = null;
    43         if (field != null) {
    44             if (field.isAccessible()) {
    45                 value = field.get(obj);
    46             } else {
    47                 field.setAccessible(true);
    48                 value = field.get(obj);
    49                 field.setAccessible(false);
    50             }
    51         }
    52         return value;
    53     }
    54 
    55     /**
    56      * Obj fieldName 设置属性值
    57      * 
    58      * @param obj
    59      * @param fieldName
    60      * @param value
    61      * @throws SecurityException
    62      * @throws NoSuchFieldException
    63      * @throws IllegalArgumentException
    64      * @throws IllegalAccessException
    65      */
    66     public static void setValueByFieldName(Object obj, String fieldName, Object value) throws SecurityException, NoSuchFieldException,
    67             IllegalArgumentException, IllegalAccessException {
    68         Field field = obj.getClass().getDeclaredField(fieldName);
    69         if (field.isAccessible()) {
    70             field.set(obj, value);
    71         } else {
    72             field.setAccessible(true);
    73             field.set(obj, value);
    74             field.setAccessible(false);
    75         }
    76     }
    77 }
    View Code

    5、休息一下,我们测试一下性能。在插件类中,重写sql方法,我们运用了StringBuffer、StringBuilder类。根据单线程或多线程的场景使用StringBuilder或StringBuffer。

      1 package com.dyl.test;
      2 
      3 import java.util.ArrayList;
      4 import java.util.Iterator;
      5 import java.util.List;
      6 /**
      7  * String,StringBuffer,StringBuilder的区别。
      8  * String,字符串常量,不可变对象。
      9  * StringBuffer,字符串变量,线程安全。
     10  * StringBuilder,字符串变量,非线程安全。
     11  * 性能:String<StringBuffer<StringBuilder。
     12  * @author Administrator
     13  *
     14  */
     15 public class StringBuilderTest {
     16     private static final String base = " base string. ";
     17     private static final int count = 2000000;
     18 
     19     public static void stringTest() {
     20         long begin, end;
     21         begin = System.currentTimeMillis();
     22         String test = new String(base);
     23         for (int i = 0; i < count / 100; i++) {
     24             test = test + " add ";
     25         }
     26         end = System.currentTimeMillis();
     27         System.out.println((end - begin)
     28                 + " millis has elapsed when used String. ");
     29     }
     30 
     31     public static void stringBufferTest() {
     32         long begin, end;
     33         begin = System.currentTimeMillis();
     34         StringBuffer test = new StringBuffer(base);
     35         for (int i = 0; i < count; i++) {
     36             test = test.append(" add ");
     37         }
     38         end = System.currentTimeMillis();
     39         System.out.println((end - begin)
     40                 + " millis has elapsed when used StringBuffer. ");
     41     }
     42 
     43     public static void stringBuilderTest() {
     44         long begin, end;
     45         begin = System.currentTimeMillis();
     46         StringBuilder test = new StringBuilder(base);
     47         for (int i = 0; i < count; i++) {
     48             test = test.append(" add ");
     49         }
     50         end = System.currentTimeMillis();
     51         System.out.println((end - begin)
     52                 + " millis has elapsed when used StringBuilder. ");
     53     }
     54 
     55     public static String appendItemsToStringBuiler(List list) {
     56         StringBuilder b = new StringBuilder();
     57         for (Iterator i = list.iterator(); i.hasNext();) {
     58             b.append(i.next()).append(" ");
     59         }
     60         return b.toString();
     61     }
     62 
     63     public static void addToStringBuilder() {
     64         List list = new ArrayList();
     65         list.add(" I ");
     66         list.add(" play ");
     67         list.add(" Bourgeois ");
     68         list.add(" guitars ");
     69         list.add(" and ");
     70         list.add(" Huber ");
     71         list.add(" banjos ");
     72         System.out.println(StringBuilderTest.appendItemsToStirngBuffer(list));
     73     }
     74 
     75     public static String appendItemsToStirngBuffer(List list) {
     76         StringBuffer b = new StringBuffer();
     77         for (Iterator i = list.iterator(); i.hasNext();) {
     78             b.append(i.next()).append(" ");
     79         }
     80         return b.toString();
     81     }
     82 
     83     public static void addToStringBuffer() {
     84         List list = new ArrayList();
     85         list.add(" I ");
     86         list.add(" play ");
     87         list.add(" Bourgeois ");
     88         list.add(" guitars ");
     89         list.add(" and ");
     90         list.add(" Huber ");
     91         list.add(" banjos ");
     92         System.out.println(StringBuilderTest.appendItemsToStirngBuffer(list));
     93     }
     94 
     95     public static void main(String[] args) {
     96         stringTest();
     97         stringBufferTest();
     98         stringBuilderTest();
     99         addToStringBuffer();
    100         addToStringBuilder();
    101     }
    102 }
    View Code

    6、在<configuration>中,配置实现了拦截器的插件。Configuration就像是Mybatis的总管,Mybatis的所有配置信息都存放在这里,此外,它还提供了设置这些配置信息的方法。Configuration可以从配置文件里获取属性值,也可以通过程序直接设置。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
     3 <configuration>
     4 
     5 <!-- The content of element type "configuration" must match 
     6  "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,
     7  environments?,databaseIdProvider?,mappers?)". 
     8  Mybaits配置文件校验,节点位置有要求。 -->
     9     
    10     <!-- properties里配置的属性将被存放在Configuration的variables变量里,供Mybatis使用。 -->
    11     <properties resource="jdbc.properties"></properties>
    12     
    13     <!-- 别名是为Java类型命名一个短的名字。它只用在XML配置文件里,用来减少类完全限定名的多余部分。 -->
    14     <typeAliases>
    15         <typeAlias alias="Company" type="com.dyl.entity.Company"/>
    16         <typeAlias alias="Dep" type="com.dyl.entity.Dep"/>
    17         <typeAlias alias="Duty" type="com.dyl.entity.Duty"/>
    18         <typeAlias alias="Staff" type="com.dyl.entity.Staff"/>
    19     </typeAliases>
    20     
    21     <!-- 自定义拦截模式,配置插件PagePlugin。属性dialect指示数据库类型,目前只支持mysql和oracle两种数据库。
    22     属性pageSqlId指示拦截的规则,以正则方式匹配。元字符.点,匹配除“
    ”之外的任何单个字符。元字符*,匹配前面的子表达式零次或多次(大于等于0次)。 -->
    23     <plugins>
    24         <plugin interceptor="com.dyl.util.PagePlugin">
    25             <property name="dialect" value="oracle"/>
    26             <property name="pageSqlId" value=".*ListPage.*"/>
    27         </plugin>
    28     </plugins>
    29     
    30     <!-- environments里可以配置多个environment,每个environment对应一个数据库环境。 -->
    31     <environments default="development">
    32         <environment id="development">
    33             <transactionManager type="JDBC" />
    34             <dataSource type="POOLED">
    35                 <property name="driver" value="${jdbc.driver}" />
    36                 <property name="url" value="${jdbc.url}" />
    37                 <property name="username" value="${jdbc.user}" />
    38                 <property name="password" value="${jdbc.pwd}" />
    39             </dataSource>
    40         </environment>
    41     </environments>
    42     
    43     <!-- Mappers用于告诉Mybatis去哪里寻找sql映射文件。 -->
    44     <mappers>
    45         <mapper resource="com/dyl/entity/xml/Company.xml" />
    46         
    47     </mappers>
    48 
    49 </configuration>
    View Code

    7、Company类和数据库表company一一对应。在Company的映射文件Company.xml中增加分页查询测试。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
     3 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     4 
     5 <mapper namespace="com.dyl.dao.ICompanyDao">
     6 
     7     <select id="selectCompanyById" parameterType="BigDecimal" resultType="Company">
     8         select * from company where companyid = #{id}
     9     </select>
    10 
    11     <!-- 为了返回list 类型而定义的returnMap -->
    12     <resultMap type="Company" id="resultListCompany">
    13         <id column="companyId" property="companyId" />
    14         <result column="companyName" property="companyName" />
    15         <result column="address" property="address" />
    16         <result column="telephone" property="telephone" />
    17         <result column="leader" property="leader" />
    18         <result column="mobilePhone" property="mobilePhone" />
    19         <result column="remark" property="remark" />
    20     </resultMap>
    21 
    22     <!-- 返回list 的select 语句,注意 resultMap 的值是指向前面定义好的 -->
    23     <select id="selectCompanys" parameterType="string" resultMap="resultListCompany">
    24         select * from company where companyName like #{companyName} order by companyid
    25     </select>
    26 
    27     <!--执行增加操作的SQL语句。id和parameterType分别与ICompanyDao接口中的addCompany方法的名字和参数类型一致。以#{name}的形式引用Company参数 
    28         的name属性,MyBatis将使用反射读取Company参数的此属性。#{name}中name大小写敏感。引用其他的gender等属性与此一致。useGeneratedKeys设置 
    29         为"true",表明要MyBatis获取由数据库自动生成的主键;keyProperty="companyid"指定把获取到的主键值注入到Company的companyid属性 -->
    30     <insert id="addCompany" parameterType="Company" useGeneratedKeys="true" keyProperty="companyid">
    31         insert into company(companyName,address,telephone,leader,mobilePhone,remark) values
    32         (#{companyName},#{address},#{telephone},#{leader},#{mobilePhone},#{remark})
    33     </insert>
    34 
    35     <update id="updateCompany" parameterType="Company">
    36         update company set companyName=#{companyName},address=#{address},telephone=#{telephone},
    37         leader=#{leader},mobilePhone=#{mobilePhone},remark=#{remark} where companyId=#{companyId}
    38     </update>
    39 
    40     <delete id="deleteCompany" parameterType="BigDecimal">
    41         delete from company where companyid=#{id}
    42     </delete>
    43     
    44     <!-- 分页查询测试 -->    
    45     <select id="selectCompanyListPage" resultMap="resultListCompany">
    46         select * from company
    47     </select>
    48     
    49 </mapper>
    View Code

    8、在Company.xml的<mapper namespace="com.dyl.dao.ICompanyDao">dao接口中增加分页查询测试。映射文件Company.xml和接口ICompanyDao,三个一致,接口名字一致,方法名字一致,方法参数类型一致。

     1 package com.dyl.dao;
     2 
     3 import java.math.BigDecimal;
     4 import java.util.List;
     5 
     6 import com.dyl.entity.Company;
     7 import com.dyl.util.PageInfo;
     8 
     9 /**
    10  * dao接口
    11  * @author dyl
    12  * @date 2014-7-13
    13  */
    14 public interface ICompanyDao {
    15     /**
    16      * 根据分公司id查找分公司
    17      * 
    18      * @param id
    19      * @return
    20      */
    21     public Company selectCompanyById(BigDecimal id);
    22 
    23     /**
    24      * 查找分公司
    25      * 
    26      * @param companyName
    27      * @return
    28      */
    29     public List<Company> selectCompanys(String companyName);
    30 
    31     /**
    32      * 增加分公司
    33      * 
    34      * @param company
    35      */
    36     public void addCompany(Company company);
    37 
    38     /**
    39      * 修改分公司
    40      * 
    41      * @param company
    42      */
    43     public void updateCompany(Company company);
    44 
    45     /**
    46      * 删除分公司
    47      * 
    48      * @param id
    49      */
    50     public void deleteCompany(BigDecimal id);
    51 
    52     /**
    53      * 分页查询测试
    54      * 
    55      * @param page
    56      * @return
    57      */
    58     public List<Company> selectCompanyListPage(PageInfo page);
    59     
    60     /**
    61      * 分页查找
    62      * @param page 条件
    63      * @return
    64      */
    65     public List<?> findByPage(PageInfo page);
    66 
    67     /**
    68      * 分页查找的总记录
    69      * @param page 条件
    70      * @return
    71      */
    72     public int findByCount(PageInfo page);
    73     
    74     /**
    75      * 修改公司信息
    76      * @param company
    77      * @return
    78      * @throws Exception 
    79      */
    80     public Integer update(Company company) throws Exception;
    81 }
    View Code

    9、测试。在测试前,我们运用Classloader 类加载器美化一下项目工程结构,在Java Resources在新建config,与src并行,把可以用Java类加载的配置文件移动到config。测试类中,有增加公司测试,可以看到Company类的属性,companyId是oracle主键自增长的(前面章节完成)。

      1 package com.dyl.test;
      2 
      3 import java.io.InputStream;
      4 import java.io.Reader;
      5 import java.math.BigDecimal;
      6 import java.util.List;
      7 
      8 import org.apache.ibatis.io.Resources;
      9 import org.apache.ibatis.session.SqlSession;
     10 import org.apache.ibatis.session.SqlSessionFactory;
     11 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     12 
     13 import com.dyl.dao.ICompanyDao;
     14 import com.dyl.entity.Company;
     15 import com.dyl.util.PageInfo;
     16 /**
     17  * 测试类
     18  * @author dyl
     19  * @date 2014-7-12
     20  */
     21 public class CompanyXmlTest {
     22     private static SqlSessionFactory sqlSessionFactory;
     23     private static Reader reader;
     24     // private static InputStream reader;
     25     
     26     /**
     27      * Classloader 类加载器,用来加载 Java 类到 Java 虚拟机中。
     28      * 
     29      * (1)Class.getResourceAsStream(String path) : path不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。
     30      * 其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
     31      * 
     32      * (2)Class.getClassLoader.getResourceAsStream(String path):默认则是从ClassPath根下获取,path不能以’/'开头, 
     33      * 最终是由ClassLoader获取资源。 
     34      * 
     35      * (3)Resources 类加载资源。
     36      * 对于简单的只读文本数据,加载为Reader。
     37      * 对于简单的只读二进制或文本数据,加载为 Stream。 
     38      * 对于可读写的二进制或文本文件,加载为 File。
     39      * 对于只读的配置属性文件,加载为 Properties。 
     40      * 对于只读的通用资源,加载为 URL。 
     41      * 按以上的顺序,Resources类加载资源的方法如下: 
     42      * Reader getResourceAsReader(String resource); 
     43      * Stream getResourceAsStream(String resource); 
     44      * File getResourceAsFile(String resource); 
     45      * Properties getResourceAsProperties(String resource); 
     46      * Url getResourceAsUrl(String resource);
     47      * 默认则是从ClassPath根下获取,resource不能以’/'开头,最终是由ClassLoader获取资源。 
     48      */
     49     
     50     static {
     51         try {
     52             reader = Resources.getResourceAsReader("sqlMap-config.xml");
     53             // reader = Resources.class.getResourceAsStream("/sqlMap-config.xml");
     54             // reader = Resources.class.getClassLoader().getResourceAsStream("sqlMap-config.xml");
     55             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
     56         } catch (Exception e) {
     57             e.printStackTrace();
     58         }
     59     }
     60 
     61     public static SqlSessionFactory getSession() {
     62         return sqlSessionFactory;
     63     }
     64     
     65     /**
     66      * 查找分公司
     67      * @param companyName
     68      */
     69     public void getCompanyList(String companyName){
     70         SqlSession session = sqlSessionFactory.openSession();
     71         try {
     72             ICompanyDao companyDao=session.getMapper(ICompanyDao.class);           
     73             List<Company> companys = companyDao.selectCompanys(companyName);
     74             for(Company company:companys){
     75                 System.out.println(company.getCompanyId().toString()+","+company.getCompanyName()+","
     76                         +company.getAddress());
     77             }  
     78         } finally {
     79             session.close();
     80         }
     81     }
     82     
     83     /**
     84      * 测试增加,增加后,必须提交事务,否则不会写入到数据库。
     85      */
     86     public void addCompany(){       
     87         Company company=new Company();
     88         company.setCompanyName("妖灵科技");
     89         company.setAddress("四川成都");
     90         company.setTelephone("028-88888888");
     91         company.setLeader("妖灵");
     92         company.setMobilePhone("18888888888");
     93         company.setRemark("HO");     
     94         SqlSession session = sqlSessionFactory.openSession();
     95         try {
     96             ICompanyDao companyDao=session.getMapper(ICompanyDao.class);
     97             companyDao.addCompany(company);
     98             session.commit();
     99         } finally {
    100             session.close();
    101         }
    102     }
    103     /**
    104      * 先得到公司,然后修改,提交。
    105      */
    106     public void updateCompany(){
    107         SqlSession session = sqlSessionFactory.openSession();
    108         try {            
    109             ICompanyDao companyDao=session.getMapper(ICompanyDao.class);
    110             Company company=companyDao.selectCompanyById(new BigDecimal(2));
    111             company.setAddress("北京");
    112             companyDao.updateCompany(company);
    113             session.commit(); 
    114         } finally {
    115             session.close();
    116         }
    117     }
    118     
    119     /**
    120      * 删除数据,删除一定要commit。
    121      * @param id
    122      */
    123     public void deleteCompany(BigDecimal id){
    124         SqlSession session = sqlSessionFactory.openSession();
    125         try {            
    126             ICompanyDao companyDao=session.getMapper(ICompanyDao.class);
    127             companyDao.deleteCompany(id);
    128             session.commit();            
    129         } finally {
    130             session.close();
    131         }
    132     }
    133     
    134     public static void main(String[] args) {
    135         SqlSession session = sqlSessionFactory.openSession();
    136         try {
    137             ICompanyDao companyDao=session.getMapper(ICompanyDao.class);
    138             
    139 //            // 根据分公司id查找分公司
    140 //            Company company=companyDao.selectCompanyById(new BigDecimal(5));
    141 //            System.out.println(company.getCompanyName());
    142 //            System.out.println(company.getAddress());
    143 //            System.out.println();
    144             
    145 //            // 查找分公司
    146 //            CompanyXmlTest companyTest=new CompanyXmlTest();
    147 //            companyTest.getCompanyList("%");
    148 //            System.out.println();
    149             
    150 //            // 增加分公司
    151 //            Company company=new Company();
    152 //            company.setCompanyName("海口分公司");
    153 //            company.setAddress("海南海口");
    154 //            company.setTelephone("0898-88888888");
    155 //            company.setLeader("碧波");
    156 //            company.setMobilePhone("18888888888");
    157 //            company.setRemark("东方夏威夷");     
    158 //            companyDao.addCompany(company);
    159 //            session.commit();
    160 //            System.out.println("当前增加的公司名称为:"+company.getCompanyName());
    161             
    162 //            // 修改分公司
    163 //            Company company=companyDao.selectCompanyById(new BigDecimal(4));
    164 //            company.setAddress("天津");
    165 //            company.setCompanyName("天津分公司");
    166 //            company.setLeader("闻其");
    167 //            company.setMobilePhone("18888888888");
    168 //            company.setRemark("首都门户");
    169 //            company.setTelephone("022-88888888");
    170 //            companyDao.updateCompany(company);
    171 //            session.commit();
    172 //            System.out.println("修改成功");
    173             
    174 //            // 删除分公司
    175 //            companyDao.deleteCompany(new BigDecimal(5));
    176 //            session.commit();
    177 //            System.out.println("删除成功");
    178             
    179             // 分页查询测试
    180             PageInfo page=new PageInfo();
    181             page.setShowCount(5);// 每一页显示多少
    182             //page.setCurrentResult(5);// 当前显示到的id
    183             page.setCurrentPage(2);// 当前页数
    184             List<Company>companys=companyDao.selectCompanyListPage(page);
    185             for(Company company:companys){
    186                 System.out.println(company.getCompanyId().toString()+","+company.getCompanyName()+","
    187                         +company.getAddress());
    188             }
    189                     
    190         } finally {
    191             session.close();
    192         }
    193     }
    194 }
    View Code

    10、项目工程图。

         接下来,(1)我们需要根据实际开发需求选择使用struts2或者springmvc来实现控制层,选择前需要大概了解一下她们的差异,她们各自擅长什么。(2)确定框架组合后,碰到一些常用功能就封装成jar包,方便复用。(3)适当暂停,整理整理,测试测试,备份备份,休息休息,思考思考。很晕很晕。一定要勤于备份,一定要备份。OK,我们下次见。

  • 相关阅读:
    Kafka 生产者 自定义分区策略
    同步互斥
    poj 1562 Oil Deposits(dfs)
    poj 2386 Lake Counting(dfs)
    poj 1915 KnightMoves(bfs)
    poj 1664 放苹果(dfs)
    poj 1543 Perfect Cubes (暴搜)
    poj 1166 The Clocks (暴搜)
    poj 3126 Prime Path(bfs)
    处理机调度
  • 原文地址:https://www.cnblogs.com/youla/p/3841998.html
Copyright © 2011-2022 走看看