MyBatis攔截器實(shí)現(xiàn)分頁(yè)功能實(shí)例
由于業(yè)務(wù)關(guān)系 巴拉巴拉巴拉
好吧 簡(jiǎn)單來(lái)說(shuō)就是
原來(lái)的業(yè)務(wù)是 需要再實(shí)現(xiàn)類(lèi)里寫(xiě) selectCount 和selectPage兩個(gè)方法才能實(shí)現(xiàn)分頁(yè)功能
現(xiàn)在想要達(dá)到效果是 只通過(guò)一個(gè)方法就可以實(shí)現(xiàn) 也就是功能合并 所以就有了下面的實(shí)踐
既然是基于MyBatis 所以就先搭建一個(gè)Mybatis的小項(xiàng)目
1.01導(dǎo)入 mybatis和mysql的包
1.02.配置文件 Configuration.xml 中添加
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root"/> <property name="password" value=""/> </dataSource> </environment> </environments>
2.01.然后創(chuàng)建一個(gè)模塊user 創(chuàng)建user表
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` char(32) NOT NULL, `t1` char(32) DEFAULT NULL, `t2` char(32) DEFAULT NULL, `t3` char(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
3.01.寫(xiě)對(duì)應(yīng)bean:User.java
package lqb.bean; public class User extends Common{ private String id; private String name; private String t1; private String t2; private String t3; //省略get set }
3.02.對(duì)應(yīng)的mapper: UserMapper.java和UserMapper.xml
簡(jiǎn)單實(shí)現(xiàn)下CRUD
public interface UserMapper { public User selectByID(int id); public List<User> select(); public int insert(User u); public int update(User u); public int delete(User u); }
<mapper namespace="lqb.mapper.UserMapper"> <select id="selectByID" parameterType="int" resultType="lqb.bean.User"> select * from `user` where id = #{id} </select> <select id="select" resultType="lqb.bean.User" parameterType="lqb.bean.User"> select * from `user` </select> <insert id="insert" parameterType="lqb.bean.User"> insert into user (id,name,t1,t2,t3) values (#{id},#{name},#{t1},#{t2},#{t3}) </insert> <update id="update" parameterType="lqb.bean.User"> update user set name=#{name},t1=#{t1},t2=#{t2},t3=#{t3} where id=#{id} </update> <delete id="delete" parameterType="lqb.bean.User"> delete from user where id=#{id} </delete> </mapper>
3.03.然后 在配置文件Configuration.xml中添加user的配置
<mappers> <mapper resource="lqb/mapper/UserMapper.xml"/> </mappers>
3.04.然后是實(shí)現(xiàn):UserService.java
public class UserService { private static SqlSessionFactory sqlSessionFactory; private static Reader reader; static{ try{ reader = Resources.getResourceAsReader("Configuration.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); }catch(Exception e){ e.printStackTrace(); } } public static SqlSessionFactory getSession(){ return sqlSessionFactory; } }
4.01 好 然后是重點(diǎn)了
思路: 截獲查詢的sql 然后拼成 sqlPage和sqlCount 再進(jìn)行查找取值 然后賦傳入對(duì)象
所以我們就需要?jiǎng)?chuàng)建一個(gè)基礎(chǔ)類(lèi)來(lái)讓user.java來(lái)繼承
public class Common { private int pagesize; private int pageid; private int pagebegin; private int count; //省略 get set }
4.02 然后 讓User繼承Common
public class User extends Common{
4.03 那怎么截獲sql呢 我們就要寫(xiě)一個(gè)mybatis的攔截器 用來(lái)攔截sql請(qǐng)求 PageInterceptor
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}), @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) }) public class PageInterceptor implements Interceptor { //插件運(yùn)行的代碼,它將代替原有的方法 @Override public Object intercept(Invocation invocation) throws Throwable { } // 攔截類(lèi)型StatementHandler @Override public Object plugin(Object target) { } @Override public void setProperties(Properties properties) { }
4.04 首先 設(shè)置攔截類(lèi)型 重寫(xiě)plugin方法
@Override public Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } else { return target; } }
4.05 然后 就要重寫(xiě)最重要的intercept了
這里我們有一個(gè)設(shè)定 如果查詢方法含有searchpage 就進(jìn)行分頁(yè) 其他方法無(wú)視
所以就要獲取方法名
StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement=(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); String selectId=mappedStatement.getId();
4.06 然后判斷下 如果含有searchpage 就獲取sql
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); // 分頁(yè)參數(shù)作為參數(shù)對(duì)象parameterObject的一個(gè)屬性 String sql = boundSql.getSql(); Common co=(Common)(boundSql.getParameterObject());
4.07 然后 根據(jù)這個(gè)sql 重新拼寫(xiě)countsql和pagesql
String countSql=concatCountSql(sql); String pageSql=concatPageSql(sql,co); ... public String concatCountSql(String sql){ StringBuffer sb=new StringBuffer("select count(*) from "); sql=sql.toLowerCase(); if(sql.lastIndexOf("order")>sql.lastIndexOf(")")){ sb.append(sql.substring(sql.indexOf("from")+4, sql.lastIndexOf("order"))); }else{ sb.append(sql.substring(sql.indexOf("from")+4)); } return sb.toString(); } public String concatPageSql(String sql,Common co){ StringBuffer sb=new StringBuffer(); sb.append(sql); sb.append(" limit ").append(co.getPagebegin()).append(" , ").append(co.getPagesize()); return sb.toString(); }
4.08 然后 通過(guò)jdbc查詢count 然后把值綁定給common
Connection connection = (Connection) invocation.getArgs()[0]; PreparedStatement countStmt = null; ResultSet rs = null; int totalCount = 0; try { countStmt = connection.prepareStatement(countSql); rs = countStmt.executeQuery(); if (rs.next()) { totalCount = rs.getInt(1); } } catch (SQLException e) { System.out.println("Ignore this exception"+e); } finally { try { rs.close(); countStmt.close(); } catch (SQLException e) { System.out.println("Ignore this exception"+ e); } } //綁定count co.setCount(totalCount);
4.09 再把pagesql賦給元BoundSql
metaStatementHandler.setValue("delegate.boundSql.sql", pageSql);
4.10 最后在配置文件中添加攔截器配置
<plugins> <plugin interceptor="lqb.interceptor.PageInterceptor"/> </plugins>
4.11 好然后 在UserMapper.java和UserMapper.xml中添加分頁(yè)代碼
<select id="selectPage" parameterType="lqb.bean.User" resultType="lqb.bean.User"> select * from `user` where id in(3,4,6,8) order by id </select>
public List<User> selectPage(User u);
5.01 最后是測(cè)試了
main...請(qǐng)?jiān)试S本人的懶 就姑且在main方法測(cè)下吧
User u=new User(); u.setPagebegin(2); u.setPagesize(3); System.out.println("-u.getCount()------"+u.getCount()); List<User> l=userService.selectPage(u); System.out.println(l.size()); System.out.println("-u.getCount()------"+u.getCount());
5.02 結(jié)果 略 然后就成功了
下面附上攔截器的代碼
package lqb.interceptor; import java.util.Properties; import org.apache.ibatis.executor.resultset.ResultSetHandler; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.SystemMetaObject; import java.sql.*; import lqb.bean.Common; @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}), @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}) }) public class PageInterceptor implements Interceptor { private static final String SELECT_ID="selectpage"; //插件運(yùn)行的代碼,它將代替原有的方法 @Override public Object intercept(Invocation invocation) throws Throwable { System.out.println("PageInterceptor -- intercept"); if (invocation.getTarget() instanceof StatementHandler) { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement=(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); String selectId=mappedStatement.getId(); if(SELECT_ID.equals(selectId.substring(selectId.lastIndexOf(".")+1).toLowerCase())){ BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); // 分頁(yè)參數(shù)作為參數(shù)對(duì)象parameterObject的一個(gè)屬性 String sql = boundSql.getSql(); Common co=(Common)(boundSql.getParameterObject()); // 重寫(xiě)sql String countSql=concatCountSql(sql); String pageSql=concatPageSql(sql,co); System.out.println("重寫(xiě)的 count sql :"+countSql); System.out.println("重寫(xiě)的 select sql :"+pageSql); Connection connection = (Connection) invocation.getArgs()[0]; PreparedStatement countStmt = null; ResultSet rs = null; int totalCount = 0; try { countStmt = connection.prepareStatement(countSql); rs = countStmt.executeQuery(); if (rs.next()) { totalCount = rs.getInt(1); } } catch (SQLException e) { System.out.println("Ignore this exception"+e); } finally { try { rs.close(); countStmt.close(); } catch (SQLException e) { System.out.println("Ignore this exception"+ e); } } metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); //綁定count co.setCount(totalCount); } } return invocation.proceed(); } /** * 攔截類(lèi)型StatementHandler */ @Override public Object plugin(Object target) { if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } else { return target; } } @Override public void setProperties(Properties properties) { } public String concatCountSql(String sql){ StringBuffer sb=new StringBuffer("select count(*) from "); sql=sql.toLowerCase(); if(sql.lastIndexOf("order")>sql.lastIndexOf(")")){ sb.append(sql.substring(sql.indexOf("from")+4, sql.lastIndexOf("order"))); }else{ sb.append(sql.substring(sql.indexOf("from")+4)); } return sb.toString(); } public String concatPageSql(String sql,Common co){ StringBuffer sb=new StringBuffer(); sb.append(sql); sb.append(" limit ").append(co.getPagebegin()).append(" , ").append(co.getPagesize()); return sb.toString(); } public void setPageCount(){ } }
最后是下載地址:mybatisResolve_jb51.rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java面試常見(jiàn)模式問(wèn)題---代理模式
代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類(lèi)與委托類(lèi)有同樣的接口,代理類(lèi)主要負(fù)責(zé)為委托類(lèi)預(yù)處理消息、過(guò)濾消息、把消息轉(zhuǎn)發(fā)給委托類(lèi),以及事后處理消息2021-06-06java中BigDecimal的介紹及使用教程BigDecimal格式化及BigDecimal常見(jiàn)問(wèn)題
BigDecimal是Java在java.math包中提供的線程安全的API類(lèi),用來(lái)對(duì)超過(guò)16位有效位的數(shù)進(jìn)行精確的運(yùn)算,這篇文章主要介紹了java中BigDecimal的介紹及使用,BigDecimal格式化,BigDecimal常見(jiàn)問(wèn)題,需要的朋友可以參考下2023-08-08修改SpringBoot 中MyBatis的mapper.xml文件位置的過(guò)程詳解
由于MyBatis默認(rèn)的mapper.xml的掃描位置是resource文件下,但是不可能整個(gè)項(xiàng)目的mapper.xml文件都放在resource下,如果文件較少還行,但是如果文件比較多,太麻煩了,所以本文給大家介紹了修改SpringBoot 中MyBatis的mapper.xml文件位置的過(guò)程,需要的朋友可以參考下2024-08-08Java 獲取服務(wù)器環(huán)境的實(shí)例詳解
這篇文章主要介紹了Java 獲取服務(wù)器環(huán)境的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例和輸出結(jié)果,希望能幫助大家理解,需要的朋友可以參考下2017-07-07Java微信公眾平臺(tái)開(kāi)發(fā)(2) 微信服務(wù)器post消息體的接收
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺(tái)開(kāi)發(fā)第二步,微信服務(wù)器post消息體的接收,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04SocketIo+SpringMvc實(shí)現(xiàn)文件的上傳下載功能
這篇文章主要介紹了SocketIo+SpringMvc實(shí)現(xiàn)文件的上傳下載功能,socketIo不僅可以用來(lái)做聊天工具,也可以實(shí)現(xiàn)局域網(wǎng)。文中給出了實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-08-08java網(wǎng)絡(luò)之基于UDP的聊天程序示例解析
這篇文章主要介紹了java網(wǎng)絡(luò)之基于UDP的聊天程序示例解析,文中通過(guò)步驟及示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08