-
其他相关代码: @Message.xml <select id=”queryMessageListByPage” parameterType=”java.util.Map” resultMap=”MessageResult”> select <include refid=”columns”></include> from MESSAGE <where> <if test=”message.command != null and !”“.equals(message.command.trim())”> and COMMAND=#{message.command} </if> <if test=”message.description != null and !”“.equals(message.description.trim())”> and DESCRIPTION like ‘%’ #{message.description} ‘%’ </if> </where> order by ID </select> @Configuration.xml <plugins> <!— <plugin interceptor=”com.imooc.interceptor.PageInterceptor” ></plugin> 如果不需要初始化参数(setProperties()),则直接这条语句即可 —> <plugin interceptor=”com.imooc.interceptor.PageInterceptor”> <property name=”test” value=”abc”></property> </plugin> </plugins> Ps:一个拦截器对应一个<plugin>。查看全部
-
在使用拦截器开发分页的时候,拦截器的参数(Invocation)中保存了拦截器所拦截的所有对象,根据方法签名,这里仅仅只是对statementHandler中的关键信息进行处理,原理就是使用分页的sql替换拦截到的原始sql,拦截对象类型是StatementHandler,由方法签名决定的,StatementHandler将对配置文件中的sql语句进行处理(sql语句在MappedStatement中),但是在StatementHandler中,所有的对象属性均为受保护的以及私有的,首先想到的是通过反射读写信息,幸好Mybatis已经有一个类MetaObject,有个方法 MetaObject.forObject(statementHandler,__,__)可以对注解的拦截方法签名所对应的对象进行包装,这样我们得到的是被包装的statementHandler,它可以通过getValue("delegate.mappedStatement")方法,得到想要任何属性;当我们得到原始sql并拼接page参数的时候,通过原始sql对象的BoundSql.getParameterObject()便可以拿到page参数,这样分页sql就可以拼接完成了,但是还需要给page对象设置总页数,总页数是个难点,需要在原始的sql语句上拼接 select count(*),这里的问题在于sql是否能执行以及如何执行,需要connection对象,而此对象就是方法签名的参数,可以通过invocation.getArgs()[0]获得,然后通过connection.prepareStatement(countSql)将拼接好的sql语句进行预编译,并执行,就可以获得结果,由于此结果是统计总数的,只有一条记录,将此记录转换为int类型,并赋值给page对象。查看全部
-
使用BoundSql的getParameterObject()的方法,里面的入参就是正常调用Mapper的方法,获取查询结果对象的的参数,这里就是Map<String,Object>parameter,通过BoundSql的getParameterObject()的方法,可以获得入参对象,由于这个对象是一个map,封装了xml配置文件中执行sql语句时候的参数,所以可以这个对象获得分页查询limit关键字所需要的(起始页)和(每页显示记录数)parameter.getKey().查看全部
-
通过BoundSql获得原始的sql语句之后,再次使用的是BoundSql的getParameterObject()来获取配置文件中的参数,因为得到的参数是一个map,调用对象的get方法得到Page对象,得到page对象之后就可以拼接分页sql了。metaObject.setValue(“delegate.boundSql.sql”,pageSql)修改原本不可以修改的值,修改原来的属性值为新的sql。 mybatis通过Invocation这个参数的proceed()方法交回主权,这个方法的源码 return method.invoke(target,args)查看全部
-
mybatis的拦截器实现分页(动态代理) 拦截sql语句来实现分页 1.拦截什么样的对象(以page作为参数传入;page对象) 2.拦截对象什么行为 3.什么时候拦截 (在prepareStatement的时候拦截) 1.RoutingStatementHandler 2.通过RoutingStatementHandler对象的属性delegate找到statement实现类BaseStatementHandler 3.通过BaseStatementHandler类的反射得到对象的MappedStatement对象 4.通过MappedStatement的属性getID得到配置文件sql语句的ID 5.通过BaseStatementHandler属性得到原始sql语句 6.拼接分页sql 6.1.需要查询总数的sql 6.2.通过拦截Connection对象得到PrepareStatement对象 6.3.得到对应的参数 6.4.把参数设到prepareStatement对象里的?(该?号在配置文件以#{}形式存在,mybatis会把它转为?号) 6.5.执行sql语句 6.6.得到总数 7.把属性值为新的sql查看全部
-
关键代码: -->Intercepts.class @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Intercepts { Signature[] value(); } -->Signature.class @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Signature { Class<?> type();//拦截主文件(接口).class String method();//拦截主文件中的方法 Class<?>[] args();//拦截主文件中该方法的参数类型.class } Ps1: Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number(数值类型) ? - 表示不确定的java类型 S、U、V - 2nd、3rd、4th types Object跟这些标记符代表的java类型有啥区别呢? Object是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。 Ps2:若通过执行plugin()方法,返回本身(不需要代理的对象),则不会执行intercept()方法(因为没有获取代理权);若返回代理对象,则会执行intercept()方法。 Ps3:如果不清楚导入哪个包,可以查看返回类型并点击该类型就可知道是哪个包。查看全部
-
实现拦截器需要实现三个方法:①intercept(Invocation invacation)<br> ② plugin(Object target)方法参数就是被拦截的对象target,返回的就是满足条件的代理类,Plugin.wrap(target,this):this也就是自定义拦截器实例,通过获取注解得到要拦截的类型,比较target的类型与this获取的要拦截的类型是不是一致,如果满足条件就获取代理对象(获得代理权),并执行intercept方法;如果条件不一致,没有获取代理对象的将直接返回(没有获得代理权),不会经过intercept方法。查看全部
-
mybatis获取statement其实是在statementHandler中,这是一个处理接口,有个prepare方法,返回Statement,这个方法是在BaseStatementHandler中实现的,statement是在instantiateStatement这个方法中获取的,这个方法是一个抽象方法,看它的PrepareStatementHandler实现,在这里边看到了connection.prepareStatement(sql,PreparedStatement.),也就是和JDBC类似的代码了,这就是分页拦截器要拦截的位置了。如何实现拦截呢?mybatis提供了相应的注解:@Intercept({@Signnature(type=StatementHandler.class),method=“prepare”,args={Connection.class}}) ①type指向要连接的接口class,这里指向StatementHandler.class, ②Method指向要拦截的方法,这里是prepare ③args[]拦截的方法的参数类型,这里是Connection.class 这样就准确描述了要拦截StatementHandler接口下的prepare方法。目标确定,接下来就可以做手脚了,在PrepareStatementHandler拿到sql语句之前将这个sql语句改装成我们的分页sql,然后在塞回去,让程序继续执行,这样就成功了。查看全部
-
mybatis拦截器实现分页查看全部
-
<select id="queryMessageList" parameterType="com.imooc.bean.Message" resultMap="MessageResult"> select <include refid="columns"/> from message <where> <if test="command!=null and !"".equals(command.trim())"> and COMMAND=#{command} </if> </where> </select> //对比上下代码 <select id="queryMessageList" parameterType="java.util.Map" resultMap="MessageResult"> select <include refid="columns"/> from message <where> <if test="message.command!=null and !"".equals(message.command.trim())"> and COMMAND=#{message.command} </if> </where> order by ID limit #{page.dbIndex},#{page.dbNumber} </select> Q1:为何选择java.util.Map?不用实体类? 因为里面代码涉及到两个实体类,所以选择一个它们通用的类型。 Q2:为何选择java.util.Map?不用Lits等之类的? 从parameterType来看字面意思是:参数类型,所以如下代码: parameter.put("message", message); parameter.put("page", page); 传过来的参数parameter来使用。所以接下来的属性前加上message.xxx;page.xxx;(key值对应)。 注意:过早过迟的拦截都不合适。所以在PreparedStatement pstmt=conn.prepareStatement(sql.toString());之前拦截即可(把SQL语句处理再放进去提交)。查看全部
-
@list.jsp部分代码 <div class='page fix'> 共 <b>${page.totalNumber}</b> 条 <c:if test="${page.currentPage != 1}"> <a href="javascript:changeCurrentPage('1')" class='first'>首页</a> <a href="javascript:changeCurrentPage('${page.currentPage-1}')" class='pre'>上一页</a> </c:if> 当前第<span>${page.currentPage}/${page.totalPage}</span>页 <c:if test="${page.currentPage != page.totalPage}"> <a href="javascript:changeCurrentPage('${page.currentPage+1}')" class='next'>下一页</a> <a href="javascript:changeCurrentPage('${page.totalPage}')" class='last'>末页</a> </c:if> 跳至 <input id="currentPageText" type='text' value='${page.currentPage }' class='allInput w28' /> 页 <a href='javascript:changeCurrentPage($(' #currentPageText').val()') class='go'>GO</a> </div> <!--js代码--> /** * 修改当前页码,调用后台重新查询 */ function changeCurrentPage(currentPage){ $("#currentPage").val(currentPage); $("#mainForm").submit(); }查看全部
-
@SQL语句里的limit使用方法 SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了上面这样一个功能。 LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。 mysql> SELECT * FROM table LIMIT 5,10; //检索记录行6-15 //为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1: mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. //如果只给定一个参数,它表示返回最大的记录行数目: mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行 //换句话说,LIMIT n 等价于 LIMIT 0,n。 案例: SELECT * FROM table LIMIT 0,5;//0、1、2、3、4 SELECT * FROM table LIMIT 5,5;//5、6、7、8、9 SELECT * FROM table LIMIT 10,5;//10、11、12、13、14查看全部
-
面向接口编程---源码详细步骤 加载配置信息... 通过配置信息加载一个代理工厂Map: 这个Map存放的是接口Class与对应的代理工厂 通过接口的Class从代理工厂取出对应的代理工厂 通过代理工厂实例化一个代理类 用这个代理类将代理实例返回出去 通过接口与method获取对应的配置文件信息: 接口名.方法名==namspace.id 通过配置文件中的信息获取SQL语句类型 根据SQL语句类型调用sqlSession对应的增删改查方法 当SQL语句类型是查询时: 根据返回值类型是List,Map,Object 分别调用selectList,selectMap,selectObject方法 3查看全部
-
IMessage imessage=sqlSession.getMapper(IMessage.class);//获取到的就是代理实例 messageList =imessage.queryMessageList(parameter);//代理实例执行接口方法时,就会触发调用处理程序,也就是第三个参数对象的invoke()方法,MapperProxy是实现了InvocationHandler接口的 MapperProxyFactory.newInstance(MapperProxy<T> mapperProxy){ --return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader()//通过接口获取类加载器,new Class[]{mapperInterface}//代理类实现的接口数组,mapperProxy//调用代理实例的处理程序) --} 解决了三个问题: 1、为什么只定义了一个接口,没有实现类的情况下,接口方法可以被调用,因为动态代理。 2、为什么sqlSession.getMapper(.class)可以根据传入的参数,返回一个对应的类型,因为泛型。 3、Mybatis加载文件时,利用namespace加载了一个class,然后把这个class与代码中传入接口的class进行匹配,方法执行所需要的信息就是来自于已经匹配成功的配置文件中,当结果与配置文件对应上后,调用接口的方法执行sql语句。查看全部
-
在为Mybatis配置文件的sql标签传递参数时,sql语句的参数定义在dao方法的参数中. 然后在Mybatis的sql语句标签中使用parameterType或者parameterMap来定义传递的参数是什么类型. 然后在sql标签中直接使用#{dao方法参数名}获取参数值. 如果是map类型.则使用#{key}. 如果是model类型,则直接使用#{属性名} 如果参数不止一个,则应该把参数封装到map类型中即可. parameterMap一般用于调用存储过程时使用. parameterMap指定参数关联对象.然后配置文件中配置该关联对象: <parameterMap id="t" type=""> <parameter property="map的key" mode="IN/OUT(存储过程参数类型)" jdbcType=""/> //表示map中的某个属性名的值,对应存储过程的IN/OUT参数. </parameterMap> <insert id="" parameterMap="t" statementType="CALLABLE"> call 存储过程(?,?,?...) </insert> 然后在serviceImp中配置该map然后作为dao方法的参数.查看全部
举报
0/150
提交
取消