Java项目(三)-- SSM开发社交网站(4)--实现图书类别和图书分页查询

实现图书列表

首先,在src/main/webapp目录下创建images、resources、upload三个目录,且在resources目录下引入bootstrap、layui、jquery等前端插件
在这里插入图片描述
Bootstrap
Bootstrap是全球最受欢迎的前端组件库,由推特(TWitter)开源。
Bootstrap用于开发响应式布局、移动设备优先的WEB项目。
Bootstrap提供完整的HTML、CSS和JS开发工具集。
Bootstrap中文网

在src/main/webapp/WEB-INF/ftl目录下创建index.ftl文件,然后可以删除src/main/webapp目录下的index.html文件。

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <title>书评网</title>
    <meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0,user-scalable=no">
    <meta name="referrer" content="no-referrer">
    <link rel="stylesheet" href="./resources/bootstrap/bootstrap.css">
    <link rel="stylesheet" href="./resources/raty/lib/jquery.raty.css">
    <script src="./resources/jquery.3.3.1.min.js"></script>
    <script src="./resources/bootstrap/bootstrap.min.js"></script>
    <script src="./resources/art-template.js"></script>
    <script src="./resources/raty/lib/jquery.raty.js"></script>
    <style>
        .highlight {
            color: red !important;
        }
        a:active{
            text-decoration: none!important;
        }
    </style>


    <style>
        .container {
            padding: 0px;
            margin: 0px;
        }

        .row {
            padding: 0px;
            margin: 0px;
        }

        .col- * {
            padding: 0px;
        }
    </style>
    <#--定义模板-->
    <script type="text/html" id="tpl">
        <a href="/book/{{bookId}}" style="color: inherit">
            <div class="row mt-2 book">
                <div class="col-4 mb-2 pr-2">
                    <img class="img-fluid" src="{{cover}}">
                </div>
                <div class="col-8  mb-2 pl-0">
                    <h5 class="text-truncate">{{bookName}}</h5>

                    <div class="mb-2 bg-light small  p-2 w-100 text-truncate">{{author}}</div>


                    <div class="mb-2 w-100">{{subTitle}}</div>

                    <p>
                        <span class="stars" data-score="{{evaluationScore}}" title="gorgeous"></span>
                        <span class="mt-2 ml-2">{{evaluationScore}}</span>
                        <span class="mt-2 ml-2">{{evaluationQuantity}}人已评</span>
                    </p>
                </div>
            </div>
        </a>

        <hr>
    </script>

    <script>
        $.fn.raty.defaults.path ="./resources/raty/lib/images";
        // loadMore()加载更多数据
        // isReset参数设置为true,代表从第一页开始查询,否则按nextPage查询后续页
        function loadMore(isReset){
            if(isReset == true){
                $("#bookList").html("");
                $("#nextPage").val(1);
            }
            var nextPage = $("#nextPage").val();
            var categoryId= $("#categoryId").val();
            var order = $("#order").val();

            $.ajax({
                url : "/books" ,
                data : {p:nextPage,"categoryId":categoryId , "order":order},
                type : "get" ,
                dataType : "json" ,
                success : function(json){
                    console.info(json);
                    var list = json.records;
                    for(var i = 0 ; i < list.length ; i++){
                        var book = json.records[i];
                        // var html = "<li>" + book.bookName + "</li>";
                        // 将数据结合tpl模板,生成html
                        var html = template("tpl" , book);
                        console.info(html);
                        $("#bookList").append(html);
                    }
                    // 显示星型评价组件
                    $(".stars").raty({readOnly:true});

                    // 判断是否到最后一页
                    if(json.current < json.pages){
                        $("#nextPage").val(parseInt(json.current) + 1);
                        $("#btnMore").show();
                        $("#divNoMore").hide();
                    }else{
                        $("#btnMore").hide();
                        $("#divNoMore").show();
                    }
                }
            })
        }
        $(function(){
            /*$.ajax({
                url : "/books" ,
                data : {p:1},
                type : "get" ,
                dataType : "json" ,
                success : function(json){
                    console.info(json);
                    var list = json.records;
                    for(var i = 0 ; i < list.length ; i++){
                        var book = json.records[i];
                        // var html = "<li>" + book.bookName + "</li>";
                        // 将数据结合tpl模板,生成html
                        var html = template("tpl" , book);
                        console.info(html);
                        $("#bookList").append(html);
                    }
                    // 显示星型评价组件
                    $(".stars").raty({readOnly:true});
                }
            })*/
            loadMore(true);
        })

        // 绑定加载更多按钮单击事件
        $(function(){
            $("#btnMore").click(function(){
                loadMore();
            })

            $(".category").click(function () {
                $(".category").removeClass("highlight");
                $(".category").addClass("text-black-50");
                $(this).addClass("highlight");
                var categoryId = $(this).data("category");
                $("#categoryId").val(categoryId);
                loadMore(true);
            })

            $(".order").click(function(){
                $(".order").removeClass("highlight");
                $(".order").addClass("text-black-50");
                $(this).addClass("highlight");
                var order = $(this).data("order");
                $("#order").val(order);
                loadMore(true);
            })
        })
    </script>
</head>
<body>
<div class="container">
    <nav class="navbar navbar-light bg-white shadow mr-auto">
        <ul class="nav">
            <li class="nav-item">
                <a href="/" style="color: #aaa;font-weight: bold">
                   书评网
                </a>
            </li>

        </ul>
        <#if loginMember??>
            <h6 class="mt-1">
                <img style="width: 2rem;margin-top: -5px" class="mr-1" src="./images/user_icon.png">${loginMember.nickname}
            </h6>
        <#else>
            <a href="/login.html" class="btn btn-light btn-sm">
                <img style="width: 2rem;margin-top: -5px" class="mr-1" src="./images/user_icon.png">登录
            </a>
        </#if>

    </nav>
    <div class="row mt-2">


        <div class="col-8 mt-2">
            <h4>热评好书推荐</h4>
        </div>

        <div class="col-8 mt-2">
            <span data-category="-1" style="cursor: pointer" class="highlight  font-weight-bold category">全部</span>
            |
            <#list categoryList as category>
                <a style="cursor: pointer" data-category="${category.categoryId}" class="text-black-50 font-weight-bold category">${category.categoryName}</a>
                <#if category_has_next>|</#if>
            </#list>


        </div>

        <div class="col-8 mt-2">
            <span data-order="quantity" style="cursor: pointer" class="order highlight  font-weight-bold mr-3">按热度</span>

            <span data-order="score" style="cursor: pointer" class="order text-black-50 mr-3 font-weight-bold">按评分</span>
        </div>
    </div>
    <div class="d-none">
        <input type="hidden" id="nextPage" value="2">
        <input type="hidden" id="categoryId" value="-1">
        <input type="hidden" id="order" value="quantity">
    </div>

    <div id="bookList">



    </div>
    <button type="button" id="btnMore" data-next-page="1" class="mb-5 btn btn-outline-primary btn-lg btn-block">
        点击加载更多...
    </button>
    <div id="divNoMore" class="text-center text-black-50 mb-5" style="display: none;">没有其他数据了</div>
</div>

</body></html>
显式图书类别

在com.ql.reader.entity包下创建实体类

package com.ql.reader.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

/**
 * 图书分类实体
 */
@TableName("category")
public class Category {
    @TableId(type = IdType.AUTO)
    private Long categoryId;
    private String categoryName;

    public Long getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Long categoryId) {
        this.categoryId = categoryId;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    @Override
    public String toString() {
        return "Category{" +
                "categoryId=" + categoryId +
                ", categoryName='" + categoryName + '\'' +
                '}';
    }
}

然后在com.ql.reader.mapper包下创建CategoryMapper接口

package com.ql.reader.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ql.reader.entity.Category;

/**
 * 图书分类Mapper接口
 */
public interface CategoryMapper extends BaseMapper<Category> {
}

在src/main/resources/mappers目录下创建category.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ql.reader.mapper.CategoryMapper">

</mapper>

然后在com.ql.reader.service包下创建接口CategoryService接口,且在com.ql.reader.service.impl包下创建它的实现类

package com.ql.reader.service;

import com.ql.reader.entity.Category;

import java.util.List;

public interface CategoryService {
    public List<Category> selectAll();
}

package com.ql.reader.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ql.reader.entity.Category;
import com.ql.reader.mapper.CategoryMapper;
import com.ql.reader.service.CategoryService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
@Service("categoryService")
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class CategoryServiceImpl implements CategoryService {
    @Resource
    private CategoryMapper categoryMapper;

    /**
     * 查询所有图书分类
     * @return 图书分类List
     */
    public List<Category> selectAll() {
        List<Category> list = categoryMapper.selectList(new QueryWrapper<Category>());
        return list;
    }
}

然后在src/test/java/com/ql/reader/service/impl目录下编写测试用例,并运行

package com.ql.reader.service.impl;

import com.ql.reader.entity.Category;
import com.ql.reader.service.CategoryService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

import java.util.List;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class CategoryServiceImplTest {
    @Resource
    private CategoryService categoryService;

    @Test
    public void selectAll() {
        List<Category> list = categoryService.selectAll();
        System.out.println(list);

    }
}

在这里插入图片描述
测试没问题,在com.ql.reader.controller包下创建BookController.java

package com.ql.reader.controller;

import com.ql.reader.entity.Category;
import com.ql.reader.service.CategoryService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import java.util.List;

@Controller
public class BookController {
    @Resource
    private CategoryService categoryService;

    /**
     * 显式首页
     * @return
     */
    @GetMapping("/")
    public ModelAndView showIndex(){
        ModelAndView mav = new ModelAndView("/index");
        List<Category> list = categoryService.selectAll();
        mav.addObject("categoryList", list);
        return mav;
    }
}

然后运行项目,在浏览器中访问http://localhost:8080/分类信息显式成功。
在这里插入图片描述

实现图书分页查询

在com.ql.reader.entity包下创建实体类

package com.ql.reader.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

@TableName("book")
public class Book {
    // 图书编号
    // 映射相应主键,并设置为自增
    @TableId(type = IdType.AUTO)
    private Long bookId;
    // 书名
    private String bookName;
    // 子标题
    private String subTitle;
    // 作者
    private String author;
    // 封面图片URL
    private String cover;
    // 图书详情
    private String description;
    // 分类编号
    private Long categoryId;
    // 图书评分
    private float evaluationScore;
    // 评价数量
    private Integer evaluationQuantity;

    public Long getBookId() {
        return bookId;
    }

    public void setBookId(Long bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getSubTitle() {
        return subTitle;
    }

    public void setSubTitle(String subTitle) {
        this.subTitle = subTitle;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getCover() {
        return cover;
    }

    public void setCover(String cover) {
        this.cover = cover;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Long getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Long categoryId) {
        this.categoryId = categoryId;
    }

    public float getEvaluationScore() {
        return evaluationScore;
    }

    public void setEvaluationScore(float evaluationScore) {
        this.evaluationScore = evaluationScore;
    }

    public Integer getEvaluationQuantity() {
        return evaluationQuantity;
    }

    public void setEvaluationQuantity(Integer evaluationQuantity) {
        this.evaluationQuantity = evaluationQuantity;
    }
}

然后在com.ql.reader.mapper包下创建BookMapper 接口

package com.ql.reader.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ql.reader.entity.Book;

public interface BookMapper extends BaseMapper<Book> {
}

然后在src/main/resources/mappers目录下创建book.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ql.reader.mapper.BookMapper">

</mapper>

在com.ql.reader.service包下创建接口BookService,且在com.ql.reader.service.impl创建它的实现类

package com.ql.reader.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ql.reader.entity.Book;

/**
 * 图书服务
 */
public interface BookService {
    /**
     * 分页查询图书
     * @param page 页号
     * @param rows 每页记录数
     * @return 分页对象
     */
    public IPage<Book> paging(Integer page, Integer rows);
}

package com.ql.reader.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ql.reader.entity.Book;
import com.ql.reader.mapper.BookMapper;
import com.ql.reader.service.BookService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

@Service("bookService")
@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
public class BookServiceImpl implements BookService {
    @Resource
    private BookMapper bookMapper;

    /**
     * 分页查询图书
     * @param page 页号
     * @param rows 每页记录数
     * @return 分页对象
     */
    public IPage<Book> paging(Integer page, Integer rows) {
        Page<Book> p = new Page<Book>(page, rows);
        QueryWrapper<Book> queryWrapper = new QueryWrapper<Book>();
        IPage<Book> pageObject = bookMapper.selectPage(p, queryWrapper);
        return pageObject;
    }
}

然后在src/test/java/com/ql/reader/service/impl目录下编写测试用例,并运行

package com.ql.reader.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ql.reader.entity.Book;
import com.ql.reader.service.BookService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

import java.util.List;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class BookServiceImplTest {
    @Resource
    private BookService bookService;

    @Test
    public void paging() {
        IPage<Book> pageObject = bookService.paging(2, 10);
        List<Book> records = pageObject.getRecords();
        for (Book book: records){
            System.out.println(book.getBookId()+":"+book.getBookName());
        }
        System.out.println("总页数:"+pageObject.getPages());
        System.out.println("总记录数"+pageObject.getTotal());
    }
}

在这里插入图片描述
然后打开com.ql.reader.controller.BookController.java添加分页查询方法

    /**
     * 分页查询图书列表
     * @param p 页号
     * @return 分页对象
     */
    @GetMapping("/books")
    @ResponseBody
    public IPage<Book> selectBook(Integer p){
        if(p==null){
            p=1;
        }
        IPage<Book> pageObject = bookService.paging(p, 10);
        return pageObject;
    }

实现图书分页前端部分需要用到JS模板引擎及星星评分组件。
Art-Template 腾讯JS模板引擎
Art-Template是一款开源的JS模板引擎,其主要用途为高效的基于模板来生成HTML片段。

具体前端代码为

<#--引入jquery组件-->
<script src="./resources/jquery.3.3.1.min.js"></script>
<#--引入JS模板引擎-->
<script src="./resources/art-template.js">
</script>
<#--引入星星评分组件-->
<script src="./resources/raty/lib/jquery.raty.js"></script>
<#--定义模板-->
<script type="text/html" id="tpl">
    <a href="/book/{{bookId}}" style="color: inherit">
        <div class="row mt-2 book">
            <div class="col-4 mb-2 pr-2">
                <img class="img-fluid" src="{{cover}}"/>
            </div>
            <div class="col-8  mb-2 pl-0">
                <h5 class="text-truncate">{{bookName}}</h5>

                <div class="mb-2 bg-light small  p-2 w-100 text-truncate">{{author}}</div>


                <div class="mb-2 w-100">{{subTitle}}</div>

                <p>
                    <span class="stars" data-score="{{evaluationScore}}" title="gorgeous"></span>
                    <span class="mt-2 ml-2">{{evaluationScore}}</span>
                    <span class="mt-2 ml-2">{{evaluationQuantity}}人已评</span>
                </p>
            </div>
        </div>
    </a>

    <hr>
</script>

<script>
    $.fn.raty.defaults.path ="./resources/raty/lib/images";
    // loadMore()加载更多数据
    // isReset参数设置为true,代表从第一页开始查询,否则按nextPage查询后续页
    function loadMore(isReset){
        if(isReset == true){
            $("#bookList").html("");
            $("#nextPage").val(1);
        }
        var nextPage = $("#nextPage").val();
        var categoryId= $("#categoryId").val();
        var order = $("#order").val();

        $.ajax({
            url : "/books" ,
            data : {p:nextPage,"categoryId":categoryId , "order":order},
            type : "get" ,
            dataType : "json" ,
            success : function(json){
                console.info(json);
                var list = json.records;
                for(var i = 0 ; i < list.length ; i++){
                    var book = json.records[i];
                    // var html = "<li>" + book.bookName + "</li>";
                    // 将数据结合tpl模板,生成html
                    var html = template("tpl" , book);
                    console.info(html);
                    $("#bookList").append(html);
                }
                // 显示星型评价组件
                $(".stars").raty({readOnly:true});

                // 判断是否到最后一页
                if(json.current < json.pages){
                    $("#nextPage").val(parseInt(json.current) + 1);
                    $("#btnMore").show();
                    $("#divNoMore").hide();
                }else{
                    $("#btnMore").hide();
                    $("#divNoMore").show();
                }
            }
        })
    }
    $(function(){
        /*$.ajax({
            url : "/books" ,
            data : {p:1},
            type : "get" ,
            dataType : "json" ,
            success : function(json){
                console.info(json);
                var list = json.records;
                for(var i = 0 ; i < list.length ; i++){
                    var book = json.records[i];
                    // var html = "<li>" + book.bookName + "</li>";
                    // 将数据结合tpl模板,生成html
                    var html = template("tpl" , book);
                    console.info(html);
                    $("#bookList").append(html);
                }
                // 显示星型评价组件
                $(".stars").raty({readOnly:true});
            }
        })*/
        loadMore(true);
    })
            
        $(function(){
        	// 绑定加载更多按钮单击事件
            $("#btnMore").click(function(){
                loadMore();
            })
        })
</script>

然后运行项目,在浏览器中访问http://localhost:8080/并按F12把浏览器调成手机模式
在这里插入图片描述
鼠标滚轮往下滑到页面底部,点击“点击加载更多”按钮
在这里插入图片描述
加载5次后查出了所有数据,页底也没有加载按钮了。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值