分頁查詢:前後端展示

分頁查詢時怎麼操作的,面試問過


在這裏插入圖片描述

1.配置分頁功能實體類Page對象

分頁的三個基本屬性:這三個必須有,其餘屬性可以通過這3個值計算添加

  • 1、每頁幾條記錄limit,顯示上限值,可以有默認值
  • 2、當前第幾頁current,當前頁數,可以有默認值
  • 3、總數據數rows,不可以有默認值,必須從數據庫中查到

page類

/**
 * 封裝分頁相關的信息.
 */
public class Page {

    // 當前頁碼,默認1
    private int current = 1;
    // 顯示上限,本題默認10
    private int limit = 10;
    // 數據總數(用於計算總頁數)
    private int rows;
    // 查詢路徑(用於複用分頁鏈接)
    private String path;

    public int getCurrent() {
        return current;
    }

    public void setCurrent(int current) {
        if (current >= 1) {
            this.current = current;
        }
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        if (limit >= 1 && limit <= 100) {
            this.limit = limit;
        }
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        if (rows >= 0) {
            this.rows = rows;
        }
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    //獲取當前頁的起始行
    public int getOffset() {
        // current * limit - limit
        return (current - 1) * limit;
    }

    //獲取總頁數
    public int getTotal() {
        // rows / limit [+1]
        if (rows % limit == 0) {
            return rows / limit;
        } else {
            return rows / limit + 1;
        }
    }

    //獲取起始頁碼,就是上一頁和下一頁中間的頁數:每次當前頁前後隔2頁
    public int getFrom() {
        int from = current - 2;
        return from < 1 ? 1 : from;
    }

    //獲取結束頁碼,就是上一頁和下一頁中間的頁數:每次當前頁前後隔2頁
    public int getTo() {
        int to = current + 2;
        int total = getTotal();
        return to > total ? total : to;
    }
 }

2. javabean實體類和數據庫建表

實體類

@Data
public class DiscussPost {
   private int id;
   private int userId;
   private String title;
   private String content;
   private int type;
   private int status;
   private Date createTime;
   private int commentCount;
   private double score;
}

建表語句

CREATE TABLE `discuss_post` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(45) DEFAULT NULL,
  `title` varchar(100) DEFAULT NULL,
  `content` text,
  `type` int(11) DEFAULT NULL COMMENT '0-普通; 1-置頂;',
  `status` int(11) DEFAULT NULL COMMENT '0-正常; 1-精華; 2-拉黑;',
  `create_time` timestamp NULL DEFAULT NULL,
  `comment_count` int(11) DEFAULT NULL,
  `score` double DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3. Mapper接口類和映射文件

數據層接口

@Mapper
public interface DiscussPostsMapper {
    /**
     * 如果是社區首頁,那麼userId=0(不傳入userId),也就是說將全部討論帖顯示出來
     * 如果是個人首頁,那麼userId!=0(傳入UserId),也就是說僅顯示個人發佈的帖子
     * 因此需要使用動態SQL,將SQL語句拼接起來。
     *
     * @param userId
     * @param offset 每一頁的起始行號
     * @param limit 每一頁顯示的帖子數
     * @return 返回的是執行SQL語句查詢結果的DiscussPost對象的集合。
     */
    List<DiscussPost> selelctDiscussPost(int userId,int offset,int limit);

    /**
     * 查詢數據庫中所有的帖子數,使用動態SQL,社區首頁userId=0,個人首頁userId!=0
     * 用來分頁查詢時計算每頁顯示的帖子數:總數/頁數
     * @param userId
     * @return
     *
     * @Param 註解的使用場景:
     * 1、方法有多個參數時
     * 2、方法參數需要起別名時
     * 3、XML中的SQL使用了 $
     * 4、動態sql中參數是非自定義pojo類型
     * 
     * 這裏並不是爲了給userId起別名,而是如果方法只有一個參數,
     * 並且在<if></if>中使用,必須加這個註解
     */
    int selectDiscussPostRows(@Param("userId") int userId);
}

映射文件

<!--定義一個sql標籤,唯一id,用來封裝sql語句-->
    <sql id="selectFields">
        id, user_id, title, content, type, status, create_time, comment_count, score
    </sql>

    <select id="selectDiscussPosts" resultType="DiscussPost">
        <!--使用include標籤來引用封裝好的sql語句-->
        select <include refid="selectFields"></include>
        from discuss_post
        where status != 2
        <!--動態sql, test屬性常用條件判斷語句中判斷真假,如果傳入的查詢條件成立(userId!=0),就進行SQL組裝-->
        <if test="userId!=0">
            and user_id = #{userId}
        </if>
        order by type desc, create_time desc
        limit #{offset}, #{limit}
    </select>

    <select id="selectDiscussPostRows" resultType="int">
        select count(id)
        from discuss_post
        where status != 2
        <if test="userId!=0">
            and user_id = #{userId}
        </if>
    </select>

4. 業務層和表現層

service

/**
 * Service層用於編寫業務邏輯,調用dao層的方法
 */
@Service
public class DiscussPostService {
    
    @Autowired
    DiscussPostMapper discussPostMapper;
    
    public List<DiscussPost> findDiscussPosts(int userId,int offset,int limit){
        return discussPostMapper.selectDiscussPosts(userId,offset,limit);
    }
    
    public int findDiscussPostsRows(int userId){
        return discussPostMapper.selectDiscussPostRows(userId);
    }
}

controller前後端交互

@Controller
public class HomeController {

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private UserService userService;

    /**
     * 1、model對象用於傳遞控制方法處理數據到結果頁面,把結果頁面上需要的數據放到Model對象中
     * 2、在方法調用前,SpringMvc會自動實例化Model和Page,並將Page注入Model,因此可以在thymeleaf中直接訪問page中數據
     * 3、使用limit #{offset}, #{limit}實現分頁查詢,查詢數據庫時方法中需要傳入offset和limit
     * 4、封裝Page對象,用來封裝實現分頁查詢的屬性和方法:對象的三大特性之一
     *      當前頁碼:current
     *      每頁顯示的帖子數:limit
     *      帖子總數:rows
     *      查詢路徑:path
     *      前端點擊頁碼會在超鏈接中傳入一個請求參數current,通過current可計算出當前頁的起始行offset
     *      傳入的Page對象不但可獲取offset和limit,而且可將數據庫中查詢信息封裝在Page對象中,傳遞給頁面
     */
    @RequestMapping(path = "/index", method = RequestMethod.GET)
    public String getIndexPage(Model model, Page page) {

        page.setRows(discussPostService.findDiscussPostRows(0));
        page.setPath("/index");

        List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
        List<Map<String, Object>> discussPosts = new ArrayList<>();
        if (list != null) {
            for (DiscussPost post : list) {
                Map<String, Object> map = new HashMap<>();
                map.put("post", post);
                User user = userService.findUserById(post.getUserId());
                map.put("user", user);
                discussPosts.add(map);
            }
        }
        model.addAttribute("discussPosts", discussPosts);
//        model.addAttribute("page",page);
        return "/index";
    }
}

5. 前端頁面

<!-- 分頁 -->
<nav class="mt-5" th:if="${page.rows>0}">
    <ul class="pagination justify-content-center">
        <li class="page-item">
            <a class="page-link" th:href="@{${page.path}(current=1)}">首頁</a>
        </li>
        <li th:class="|page-item ${page.current==1?'disabled':''}|">
            <a class="page-link" th:href="@{${page.path}(current=${page.current-1})}">上一頁</a></li>
        <li th:class="|page-item ${i==page.current?'active':''}|" th:each="i:${#numbers.sequence(page.from,page.to)}">
            <a class="page-link" href="#" th:text="${i}">1</a>
        </li>
        <li th:class="|page-item ${page.current==page.total?'disabled':''}|">
            <a class="page-link" th:href="@{${page.path}(current=${page.current+1})}">下一頁</a>
        </li>
        <li class="page-item">
            <a class="page-link" th:href="@{${page.path}(current=${page.total})}">末頁</a>
        </li>
    </ul>
</nav>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章