美文网首页
一起来学习Mybatis:第二篇

一起来学习Mybatis:第二篇

作者: __y | 来源:发表于2018-05-28 22:03 被阅读80次

    上次我们了解了Mybatis的一些基本操作,接下来我们继续学习Mybatis更多知识

    1.接口式编程

    什么是接口式编程?简单来说就是利用接口的形式去编码。为什么要使用接口式编码呢?我们来看以下的案例

       messageList = sqlSession.selectList("Message.queryMessageList",message);
    

    让我们分析这行代码,在实际开发中,我们很难避免没有写错"Message.queryMessageList"或者说,我们也有可能会命名相同的命名空间或者相同的id,而参数部分传入的是对象,我们也很难避免不会穿入其他错的值。如果我们犯错了,编译器是不会给我们找出错误,而需要我们在执行的时候才能发现错误。这样会效率低下,这时候就需要利用接口式编程帮我们规避这些错误
    创建一个接口
    返回的类型和xml中对应,名字和ID相同

    package com.mybatis.dao;
    
    import com.mybatis.entity.Message;
    
    import java.util.List;
    
    public interface IMessage {
        public List<Message> queryMessageList (Message message);
    }
    
    
    

    修改命名空间,内容为包名.接口的名字

      <mapper namespace="com.mybatis.dao.IMessage">
    

    DAO层修改

    //messageList = sqlSession.selectList("Message.queryMessageList",message);
            IMessage iMessage = sqlSession.getMapper(IMessage.class);//获得代理实例,不需要做强转,后台已经实现
            messageList = iMessage.queryMessageList(message);
            sqlSession.close();
    

    测试结果:

    image.png
    分析:
    1.接口的实例不用我们操心,Mybatis会自己帮我们实现,我们直接调用就好了
    2.看起来我们代码还比以前多了,但是以后跟spring集合的话,sqlSession会交给spring托管,这样我们会少了很多代码,增加了开发效率
    IMssage.queryMessageList();
    MapperProxy.invoke() == sqlSession.selectList()?
    IMssage imssage = Proxy.newProxyInstance();

    2.分页功能的介绍

    说到分页我们先来捋一捋有几项我们值得注意的参数:

    • 条件
    • 显示多少条
    • 一共有多少条
    • 当前第几页
    • 一共有多少页
      创建一个page类
    package com.mybatis.util;
    
    /**
     * 分页查询的工具类
     */
    public class Page {
        private int totalNumber;//总条数
        private int currentPage;//当前第几页
        private int totalPage;//总页数
        private int pageNumber = 5;//每页显示多少条
        private int start;//从第几条开始取
        private int number;//取多少条
    
        public void count(){
            //计算总页数
            int totalPageTemp = totalNumber / pageNumber;
            //是否要增加一页
            int plus = (totalNumber % pageNumber == 0) ? 0 : 1;
            totalPageTemp = totalPageTemp + plus;
            //如果是只有一页,就设为1
            if(totalPageTemp <= 0) {
                totalPageTemp = 1;
            }
            //设置总页数
            this.totalPage = totalPageTemp;
    
            //设置当前页数
            // 总页数小于当前页数,应将当前页数设置为总页数
            if(this.totalPage < this.currentPage) {
                this.currentPage = this.totalPage;
            }
            // 当前页数小于1设置为1
            if(this.currentPage < 1) {
                this.currentPage = 1;
            }
            //设置limit的数值
            this.start = (this.currentPage - 1) * pageNumber;
            this.number = pageNumber;
        }
    
        public int getTotalNumber() {
            return totalNumber;
        }
    
        public void setTotalNumber(int totalNumber) {
            this.totalNumber = totalNumber;
            count();
        }
    
        public int getCurrentPage() {
            return currentPage;
        }
    
        public void setCurrentPage(int currentPage) {
            this.currentPage = currentPage;
        }
    
        public int getTotalPage() {
            return totalPage;
        }
    
        public void setTotalPage(int totalPage) {
            this.totalPage = totalPage;
        }
    
        public int getPageNumber() {
            return pageNumber;
        }
    
        public void setPageNumber(int pageNumber) {
            this.pageNumber = pageNumber;
        }
    
        public int getStart() {
            return start;
        }
    
        public void setStart(int start) {
            this.start = start;
        }
    
        public int getNumber() {
            return number;
        }
    
        public void setNumber(int number) {
            this.number = number;
        }
    }
    
    

    Message.xml

    <!--分页查询-->
    <select id="queryMessageList" parameterType="java.util.Map" resultMap="MessageResult">
            select ID,COMMAND,DESCRIPTION,CONTENT from MESSAGE
            <where>
                <if test="command != null and !&quot;&quot;.equals(command.trim())">
                    and COMMAND like '%' #{message.command} '%'
                </if>
                <if test="description != null and !&quot;&quot;.equals(description.trim())">
                    and DESCRIPTION like '%' #{message.description} '%'
                </if>
            </where>
            order by id limit #{page.start},#{page.number}
        </select>
    <!--增加-->
    <select id="count" parameterType="com.mybatis.entity.Message" resultType="int">
            select count(*) from MESSAGE
            <where>
                <if test="command != null and !&quot;&quot;.equals(command.trim())">
                    and COMMAND like '%' #{command} '%'
                </if>
                <if test="description != null and !&quot;&quot;.equals(description.trim())">
                    and DESCRIPTION like '%' #{description} '%'
                </if>
            </where>
    
        </select>
    

    我们可以看到上面queryMessageList需要两个对象的参数,我们可以用Map实现
    IMessage

    public interface IMessage {
        public List<Message> queryMessageList (Map<String,Object> parameter);
        public int count(Message message);
    }
    

    DAO层

      public List<Message> queryMessageList (Map<String, Object> parameter) {
            //获得数据库的sqlsession,通过sqlsess进行数据库的操作
            SqlSession sqlSession = DBUtil.getSqlSession();
            List<Message> messageList;
            //调用Message.xml中的queryMessageList查询
            //messageList = sqlSession.selectList("Message.queryMessageList",message);
            IMessage iMessage = sqlSession.getMapper(IMessage.class);//获得代理实例
            messageList = iMessage.queryMessageList(parameter);
            sqlSession.close();
            return  messageList;
        }
    

    service层

    public class MessageService {
        public List<Message> getMessageList( Message message, Page page) {
            MessageDao md = new MessageDao();
            int count = md.count(message);//获得总条数
            page.setTotalNumber(count);
            Map<String ,Object> parameter = new HashMap<String, Object>();
            parameter.put("message",message);
            parameter.put("page",page);
            List<Message> list = md.queryMessageList(parameter);
            return list;
        }
    }
    

    servlet层

    public class ListServlet extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            
            //这里的“/”表示整个web应用程序
            //编码问题,如果不是就会???
            request.setCharacterEncoding("UTF-8");
            String command = request.getParameter("command");
            String description = request.getParameter("description");
            String currentPage = request.getParameter("currentPage");
            Page page = new Page();
            Pattern pattern = Pattern.compile("[0-9]{1,9}");
            if(currentPage == null || !pattern.matcher(currentPage).matches()) {
                page.setCurrentPage(1);
            }else {
                page.setCurrentPage(Integer.valueOf(currentPage));
            }
            System.out.println("currentPage is " + currentPage);
            MessageService ms = new MessageService();
            Message message = new Message();
            message.setCommand(command);
            message.setDescription(description);
            System.out.println(command + " ------" + description);
            request.setAttribute("messageList",ms.getMessageList(message,page));
            request.setAttribute("page",page);
            request.getRequestDispatcher("/WEB-INF/jsp/back/list.jsp").forward(request,response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    }
    

    部分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>
                        跳至&nbsp;<input id="currentPageText" type='text' value='${page.currentPage}' class='allInput w28' />&nbsp;页&nbsp;
                        <a href="javascript:changeCurrentPage($('#currentPageText').val())" class='go'>GO</a>
                    </div>
                </div>
    

    JS

    /**
     * 修改当前页码,调用后台重新查询
     */
    function changeCurrentPage(currentPage) {
        $("#currentPage").val(currentPage);
        $("#mainForm").submit();
    }
    

    效果:


    image.png image.png
    image.png

    3.拦截器实现分页

    上面我们实现了分页的功能。但是如果我们以后开发越来越多的页面,每次都要这么繁琐的开发步骤,显然是不合适的。那么接下来我们可以利用Mybatis的拦截器功能实现分页。在实现拦截器之前,我们要关注以下几点:

    • 要拦截什么对象
    • 拦截对象的什么行为
    • 什么时候拦截
      代码:
    package com.mybatis.interceptor;
    
    import com.mybatis.util.Page;
    import org.apache.ibatis.executor.parameter.ParameterHandler;
    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.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.Map;
    import java.util.Properties;
    
    /**
     * 分页拦截器
     */
    @Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class})})
    public class PageInterceptor implements Interceptor{
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
            //获得metaObject
            MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY);
            MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
            //配置SQL语句中的ID
            String id = mappedStatement.getId();
            if(id.matches(".+ByPage$")) {
                BoundSql boundSql = statementHandler.getBoundSql();
                //原始的sql语句
                String sql = boundSql.getSql();
                //查询的总条数
                String countSql = "select count(*) from (" + sql + ")a";
                Connection connection = (Connection) invocation.getArgs()[0];
                PreparedStatement countStatement = connection.prepareStatement(countSql);
                ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
                parameterHandler.setParameters(countStatement);
                ResultSet rs = countStatement.executeQuery();
    
                Map<?,?> parameter = (Map<?,?>)boundSql.getParameterObject();
                Page page = (Page)parameter.get("page");
                if(rs.next()) {
                    page.setTotalNumber(rs.getInt(1));
                }
                // 改造后带分页查询的SQL语句
                String pageSql = sql + " limit " + page.getStart() + "," + page.getNumber();
                metaObject.setValue("delegate.boundSql.sql", pageSql);
            }
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object target) {
            //获得被拦截的对象,然后调用intercept方法,判断拦截的行为
            return Plugin.wrap(target,this);
        }
    
        @Override
        public void setProperties(Properties properties) {
    
        }
    }
    
    

    原理可以参考文章
    参考文章:
    https://blog.csdn.net/u012089657/article/details/49763631
    我们来总结一下拦截器的使用逻辑:
    用买票的案例来总结
    1.成立一家代购公司----inplements Interceptor
    2.注册---- plugin(在配置文件中注册)
    3.申报资产---- property
    下面开始工作了
    4.使用资产--- setProperties()
    5.定位客户群体--- Plugin.wrap() /@Intercepts
    6.定位客户群体后开始代购(intercept:定义客户的行为,看是不是真的要买票)

    • 过滤客户 ----id.matches(".+ByPage$")
    • 获取购票信息---- Page
    • 购票--原始SQL----》pageSql
    • 送票--- return invocation.proceed();

    4.批量新增

    没插入前


    image.png

    XML

    <!--批量增加-->
        <insert id="insertBath" parameterType="java.util.List">
            insert into message(command,description) values
            <foreach collection="list" item="item" separator=",">
                (#{item.command},#{item.description})
            </foreach>
    
        </insert>
    

    DAO

    public void insertBath(List<Message> list) {
            SqlSession sqlSession = DBUtil.getSqlSession();
            IMessage iMessage = sqlSession.getMapper(IMessage.class);
            iMessage.insertBath(list);
            sqlSession.commit();
            sqlSession.close();
        }
    
    public interface IMessage {
         List<Message> queryMessageList (Map<String,Object> parameter);
         int count(Message message);
         List<Message> queryMessageListByPage (Map<String,Object> parameter);
         void insertBath(List<Message> list);
    }
    
    

    测试:

    public static void main(String[] args) {
            MessageDao messageDao = new MessageDao();
            Message message = new Message();
            message.setDescription("测试修改");
            message.setCommand("xixi");
            Message message1 = new Message();
            message1.setCommand("lalalal");
            message1.setDescription("lalalal");
            List<Message> list = new ArrayList<Message>();
            list.add(message);
            list.add(message1);
            messageDao.insertBath(list);
        }
    

    结果


    image.png

    相关文章

      网友评论

          本文标题:一起来学习Mybatis:第二篇

          本文链接:https://www.haomeiwen.com/subject/mlqujftx.html