基於Mysql數據庫的SSM分頁查詢


前言: Hello,本Y又來了,"分頁"在我們使用軟件的過程中是一個很常見的場景,比如博客園對於每個博主的博客都進行了分頁展示。可以簡單清晰的展示數據,防止一下子將過多的數據展現給用戶,畢竟用戶的閱讀能力和短期接受力都有限,使用分頁可以避免帶給用戶瀏覽上的不舒服感,利用它可以帶給用戶良好的體驗,便於瀏覽和查詢數據。那么本期我們的博客就來探討關於分頁,使用的Java的框架是Spring+Springmvc+mybatis,這也是目前企業非常流行的搭配方式,使用的數據庫是Mysql,我們將采用項目驅動的方式,模擬一個論壇帖子瀏覽的功能,做一個對論壇中的帖子進行分頁查詢的Demo

目錄:

一:SSM框架的搭建

二:Mysql的分頁機制

三:代碼的分層結構

四:功能演示

五:原理總結

一:SSM框架的搭建

1.1:基本的文件配置

1.1.1:web.xml

任何一個web項目的起點都是web.xml,通過它我們可以知道這個項目所使用的技術,本次我們使用的是MVC框架是springmvc,所以我們必須在web.xml中配置SpringMvc,我們來看看web.xml的代碼(這里我只寫關鍵的部分):

    <!-- 編碼過濾器 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

   <!--  Springmvc的配置 -->
    <servlet>
        <servlet-name>Springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-config.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <!-- 上下文監聽器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:mybatis-config.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

其中編碼過濾器主要是對web的請求進行過濾,防止其編碼不統一而產生亂碼,這里統一設定為utf-8,接下來就是Springmvc的配置,主要配置了DispatcherServlet,注意這里的適配url是以.do方式結尾的,所以我們后面 的請求方式都要是.do結尾的,這樣Springmvc才能識別,其中又引用了springmvc-config.xml這個文件,這個文件的作用就是Spring的具體配置了,我們來看看:

1.1.2:springmvc-config.xml配置文件

    <!-- 注解掃描 -->
    <context:annotation-config></context:annotation-config>

    <!-- 掃描的包 -->
    <context:component-scan base-package="com.wyq"></context:component-scan>

    <!--視圖解析器 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/" />
        <property name="suffix" value=".jsp" />
    </bean>

可以看出其中主要配置了注解掃描器,以包級為單位用來掃描我們代碼中的注解,這里的注解包括@Controller @Service等,有了這個配置我們的注解才能生效。接下來就是視圖解析器,它主要就是給我們的控制器返回的值加路徑和.jsp,我們就不用在java代碼中寫.jsp了,很方便的一個東西

。1.1.3:mybatis-config.xml

順着web.xml往下看,可以看到mybatis-config.xml,顧名思義,這個主要作用就是用來配置mybatis的:

     <!-- 數據源 -->
    <bean name="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/pageparation?characterEncoding=utf8" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="username" value="root" />
        <property name="password" value="123" />
    </bean>
     <!--  事務管理器 -->
    <bean name="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
     <!--   注解驅動 -->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    <!--  會話工廠 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath:com/wyq/Dao/*.xml"/>
    </bean>
    <!-- mapper文件配置器 -->
    <bean name="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.wyq.*" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>

可以看出,我們其中主要是配置了數據源、事務等相關的東西,數據源也就是連接mysql的屬性,事務管理器就是用來管理事務的,比如增刪改都需要用到事務管理器(查詢一般不需要事務)。下面的兩個都是mybatis特有的,我們寫的Mapper的路徑等等

二:Mysql的分頁機制

2.1:數據庫構造數據

我們這次模擬的是一個分頁查詢論壇中帖子的demo,所以首先建一張表,用來存放數據:(下面的數據都來自天涯論壇),我們要做的就是對這些數據進行顯示,然后分頁

 2.2:Mysql的分頁機制

Mysql的分頁查詢語句是:select * from table limit param1,param2 ,其中param1是查詢的開始,param2是查詢的條數,其實也就是我們的頁大小,然后利句這些sql,我們就可以在每次點擊“上一條”,下一條“的時候在服務器端完成數據的分頁,具體的原理請看下面的代碼

如圖所示,其中limit第一個數字表示的是開始查詢的編號(注意:它是從0開始的,而Id是從1開始的),所以查出來的第一條是4,然后第二個數字是4,也就是最終查出來是4條數據。這樣4就充當了分頁中的PageSize的角色

三:代碼分層結構

按照 我們以往的代碼習慣,我們的代碼分為Controller層、Service層,Dao層,我們來依次看一下按照這三個層次划分的代碼結構,首先我們先看看DB層,也就是Dao層:

3.1:Dao層

public interface InvactionMapper { //Mapper接口
    
    public List<Invitation>  searchInvList(Page page);//查詢帖子列表
    
    public List<Invitation> getInvBycondtion(Page page);//根據條件查詢帖子
    
    public Integer searchTotalCount(Page page);//搜索總數量
    
    public Integer deleteInvition(Integer id);//根據id刪除帖子
    
}

這里定義了一系列的接口方法,主要是用來操作數據庫的,而對於其具體的實現,這里我們不需要寫實現類,根據mybatis的特性,我們需要有一個對應的Mapper的文件,然后把其方法和mapper中的xml文件對應,就可以完成對數據庫的操作了,需要注意的是:(mapper和xml最好在一個包下,否則會有很蛋疼的異常,樓主在這上面花費了一個晚會才解決 - -)具體的代碼如下:

<mapper namespace="com.wyq.Dao.InvactionMapper">
    
     <!--注意: nameSpace要和接口的名字和路徑對應 -->

    <resultMap id="invatition" type="com.wyq.Entities.Invitation">
        <id column="id" property="id"></id>
        <result column="content" property="content"></result>
        <result column="title" property="title"></result>
        <result column="createDate" property="createDate"></result>
        <result column="summay" property="summay"></result>
        <result column="author" property="author"></result>
    </resultMap>

    <select id="searchInvList" parameterType="com.wyq.Entities.Page" resultMap="invatition">

        select * from invitation limit #{startRow},#{pageSize}

    </select>

    <select id="searchTotalCount" parameterType="com.wyq.Entities.Page"
        resultType="java.lang.Integer">
        select count(id) from invitation <where>
            <if test="queryCondition!=null">
                and title like CONCAT('%',#{queryCondition},'%')
            </if>
        </where>
    </select>


    <select id="getInvBycondtion" parameterType="com.wyq.Entities.Page" resultMap="invatition">
    
        select * from invitation
         <where>
            <if test="queryCondition!=null">
                 title like  CONCAT('%',#{queryCondition},'%')
            </if>
        </where>
      </select>

    <delete id="deleteInvition" parameterType="java.lang.Integer">
        delete from INVITATION
        where
        id=#{id}
    </delete>

</mapper>

其中可以看出我們在mapper文件中寫了sql,而sql的寫法其中用#{}這種方式攜帶參數,這里就是方法中的參數了,我們需要用的時候,只需要把值傳入進去,mybaits,就會自動進行解析

3.2:Service層:

首先我們還是先來定義一個服務層的接口:

public interface InvitationService {

    
    List<Invitation> searchInvList(Page page);

    
    Integer searchTotalCount(Page page);

    
    Integer deleteInvition(Integer id);
    
    List<Invitation> getInvBycondtion(Page page);

}

然后是其具體的實現,需要注入mapper層:

 

@Service
@Transactional
public class InvitationServiceImpl implements InvitationService {
    
    @Autowired
    private InvactionMapper invactionMapper;
    
    
    @Override
    public List<Invitation> searchInvList(Page page) {
        return invactionMapper.searchInvList(page);
    }


    public Integer deleteInvition(Integer id){
         return invactionMapper.deleteInvition(id);
    }


    public Integer searchTotalCount(Page page) {
        return invactionMapper.searchTotalCount(page);
    }
    
    public List<Invitation> getInvBycondtion(Page page){
        return invactionMapper.getInvBycondtion(page);
    }

}

注意這里我們加入了@Service注解,主要用來表示這就是一個Service層,然后注意這里有delete方法,所以這里也必須有一個@Transaction注解用來表示事務的操作

3.3:controller層

 

@Controller
@Scope("prototype")
public class InvacationController {

    @Autowired
    private InvitationServiceImpl invitationServiceImpl;

    @RequestMapping("init.do")
    public String searchInvList(Page page,HttpServletRequest request) throws UnsupportedEncodingException {

        //組裝page對象,傳入方法中查詢列表 回顯數據
        Page p =page;
        int pageSize=4; //設置每頁大小
        p.setPageSize(pageSize);
        int curPage=p.getCurrentPage();
        
        if (curPage==0) {
            curPage=1;
            p.setCurrentPage(curPage);
        }
        int startRow =page.getStartRow();
        
        if (!(p.getCurrentPage()==0)) {
             startRow = getStartRowBycurrentPage(curPage, pageSize);
        }
        
        p.setStartRow(startRow);
        
        String queryCondition=null;
        if (page.getQueryCondition()!=null) {
             queryCondition = page.getQueryCondition();//查詢條件
        }


        List<Invitation> Invlist = getInvListByCondition(page);

        Integer totalCounts = invitationServiceImpl.searchTotalCount(page);//總條數

        int totalPages=(totalCounts%pageSize==0)?(totalCounts/pageSize):(totalCounts/pageSize+1);//總頁數=總條數/頁大小+1

        p.setTotalPage(totalPages);//總頁數

        page.setTotalRows(totalCounts);//總行數

        request.setAttribute("invList", Invlist);

        request.setAttribute("page", page);

        return "index";
    }

    private List<Invitation> getInvListByCondition(Page page) {
        
        List<Invitation> InvList =null;
        
        if (page.getQueryCondition()==null) {
            
            InvList = invitationServiceImpl.searchInvList(page);
            
            return InvList;
            
        }
        
         InvList = invitationServiceImpl.getInvBycondtion(page);
        
        
        return InvList;
        
    }

    /**
     * 刪除帖子的方法
     * @param id
     * @return
     */
    @RequestMapping("isdelete.do")
    public String deleteInvition(Integer id) {

         invitationServiceImpl.deleteInvition(id);
         
         return "index";
    }

    /**
     * 根據當前頁獲取開始行
     * @param currentPage
     * @param pageSize
     * @return
     */
    
    public int getStartRowBycurrentPage(int currentPage,int pageSize){
        
        int startRow=0;
        
        if (currentPage==1) {
            
            return startRow=0;
        }
        
        startRow=(currentPage-1)*pageSize;
        
        return startRow;
        
    }


}

Controller就是我們的具體的控制器,這里實現對象的封裝,調用Service層,Service層去操作數據庫,數據庫把數據返回來,我們再把數據放在服務端,在經過jsp進行渲染,其中這里一定要注意分頁數據的操作,controller中主要實現的對所有的數據查詢分頁,然后還有我們對具體的條件查詢出來的結果進行分頁展示

3.4:jsp視圖層頁面

        <body>
        <center>
        <table border="1" style="text-align:center">
        <tr>
        <td colspan="6"><h1>帖子列表</h1></td>
        </tr>
       <tr>
       <td colspan="6">帖子標題:
       <form action="init.do" method="get">
       <input type="text" name="queryCondition"
       value="${page.queryCondition}" id="condition"> <input
       type="submit" value="查詢" />
        </form>
        </td>
        </tr>

      <th>編號</th> 
      <th>標題</th> 
      <th>內容摘要</th> 
      <th>作者</th> 
      <th>發布時間</th> 
      <th>操作</th> 
     </tr> 
     <tr <c:if="" test="${status.count%2!=0}">
       style=&quot;background-color:#dbce8f&quot;  &gt; 
      <td>${item.id}</td> 
      <td>${item.title}&quot;</td> 
      <td>${item.summay}</td> 
      <td>${item.author}</td> &lt;%-- 
      <td>${item.content}</td> --%&gt; 
      <td>
       <fmt:formatdate value="${item.createDate}" pattern="yyyy-MM-dd" /></td> 
      <td><a href="isdelete.do?id=${item.id}">刪除</a></td> 
     </tr>  
    </tbody>
   </table> 
   <br /> 
   <br /> 
   <label>第${page.currentPage}/${page.totalPage}頁 共${page.totalRows}條</label> 
   <a href="init.do?currentPage=0">首頁</a> 
   <a href="init.do?currentPage=${page.currentPage-1}" onclick="return checkFirst()">上一頁</a> 
   <a href="init.do?currentPage=${page.currentPage+1}" onclick="return checkNext()">下一頁</a> 
   <a href="init.do?currentPage=${page.totalPage}">尾頁</a> 跳轉到:
   <input type="text" style="width:30px" id="turnPage" /><input type="button" onclick="startTurn()" value="跳轉" /> 
  </center> 
  <script type="text/javascript">
    
    function checkFirst(){
         if(${page.currentPage>1}){
         
           return true;
         
         }
         alert("已到頁首,無法加載更多");
        
       return false;
    }
    
    function checkNext(){
    
    if(${page.currentPage<page.totalPage}){
    
      return true;
    
    }
    alert("已到頁尾,無法加載更多頁");
    return false;
    
    }
    
    
    function startTurn(){
    
    var turnPage=document.getElementById("turnPage").value;
    
    if(turnPage>${page.totalPage}){
    
      alert("對不起已超過最大頁數");
     
      return false;
    
    }
    
    var shref="init.do?currentPage="+turnPage;
    
    window.location.href=shref;
}
</script>   
 </body>
</html>

其中主要是對數據的展示,用到了jstl表達式和javascript,js的目的在於防止其越界,超出頁數的最大或最小值

四:功能演示

4.1:分頁功能,

其中第1/4頁表示的當前是第一頁,一共4頁,數據庫中查詢出來的條數一共是13條,每頁顯示4條數據。然后點擊下一頁可以返回下一頁的數據,這些都是動態獲取的,只要數據庫中的條數或者頁數發生變化,這里也會發生變化。

4.2:跳轉功能

其中可以在小框中輸入你想跳轉的頁數(這里會做校驗,如果你超過總頁數,那么會提示你已經超過總頁數,這些都是js來完成的),然后點擊跳轉按鈕,會跳轉到具體的頁數

4.3:刪除帖子功能

假如你想刪除指定帖子,只需要點擊刪除,然后就會刪除這條記錄,同時數據庫中的值也會發生變化,就會顯示一共12條

4.4:根據標題查詢文章的功能

這里做的是一個模糊搜索,利用具體的查詢條件,然后去數據庫里查詢,輸入關鍵字進行查詢,就可以查到具體的帖子,並且會顯示條數

 

 5:總結

本篇博文主要是探討了數據庫分頁技術,對數據庫中的數據進行查詢與顯示,采用的技術框架是javaWeb中的SSM,數據庫是mysql。這里簡單說一下原理:我們點擊上一條下一條的時候其實是利用超鏈接攜帶參數值,然后把值傳入Controller中,Controller對值進行解析,然后封裝去數據庫查詢,最后再返回給視圖層,這就是原理:

 

本篇博文就講到這里:Demo下載鏈接:http://pan.baidu.com/s/1hsBsye4     密碼:knot

注:采用的java jdk:1.7  Tomcat:8.0  IDE:Myeclipse 2016 stable 1.0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM