基于Spring+SpringMVC+MyBatis开发书评网图书分页查询模块采用Ajax动态加载图书信息和实现图书多条件动态查询
Posted 被雨遗忘的夏天
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Spring+SpringMVC+MyBatis开发书评网图书分页查询模块采用Ajax动态加载图书信息和实现图书多条件动态查询相关的知识,希望对你有一定的参考价值。
一、 图书分页查询
概述:
1、 采用Ajax动态加载图书信息
2、 实现图书多条件动态查询
作用:
不用一次加载全部图书信息,防止更新的时候数据丢失,相对于采用Freemaker加载,后者复杂些,需要加入javascript 来控制请求的提交和返回数据的处理
二、 开发流程
1、 创建图书实体类
package com.imooc.reader.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @ClassName Book
* @Description 图书实体类
* @date 2021/5/9 19:18
* @Param
* @return
*/
// 映射相应的数据库表
@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;
}
}
2、 创建Mapper接口类
package com.imooc.reader.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.imooc.reader.entity.Book;
/**
* @ClassName BookMapper
* @Description 图书接口类
* @date 2021/5/9 19:25
* @Param
* @return
*/
public interface BookMapper extends BaseMapper<Book> {
/**
* 更新图书评分/评价数量
*/
public void updateEvaluation();
}
3、 创建mapper.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.imooc.reader.mapper.BookMapper">
<update id="updateEvaluation">
update book b SET evaluation_score = (
select ifnull(avg(score),0) from evaluation where book_id = b.book_id and state='enable'
),evaluation_quantity = (
select ifnull(count(*),0) from evaluation where book_id = b.book_id and state='enable'
)
</update>
</mapper>
4、 创建Service层的服务接口BookService
package com.imooc.reader.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.imooc.reader.entity.Book;
/**
* @ClassName BookService
* @Description TODO
* @date 2021/5/9 19:28
* @Param
* @return
*/
public interface BookService {
/**
* 分页查询图书
* @param categoryId 分类编号
* @param order 排序方式
* @param page 页号
* @param rows 每页记录数
* @return 分页对象
*/
public IPage<Book> paging(Long categoryId , String order , Integer page,Integer rows);
}
5、 实现服务接口BookService
package com.imooc.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.imooc.reader.entity.Book;
import com.imooc.reader.mapper.BookMapper;
import com.imooc.reader.service.BookService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @ClassName BookServiceImp
* @Description TODO
* @date 2021/5/9 19:32
* @Param
* @return
*/
@Service("bookService")
// 声明式事务注解
@Transactional(propagation = Propagation.NOT_SUPPORTED,readOnly = true)
public class BookServiceImpl implements BookService {
@Resource
private BookMapper bookMapper;
/**
* 分页查询图书
* @param categoryId 分类编号
* @param order 排序方式
* @param page 页号
* @param rows 每页记录数
* @return 分页对象
*/
public IPage<Book> paging(Long categoryId , String order ,Integer page, Integer rows) {
// p: 查询的页数
Page<Book> p = new Page<Book>(page, rows);
// queryWrapper: 条件构造器
QueryWrapper<Book> queryWrapper = new QueryWrapper<Book>();
// 表示从前台传入了有效的编号
if (categoryId != null && categoryId != -1) {
queryWrapper.eq("category_id", categoryId);
}
// 排序方式
if (order != null) {
// quantity: 按评价人数进行排序
if (order.equals("quantity")) {
queryWrapper.orderByDesc("evaluation_quantity");
} else if (order.equals("score")) {
// score: 按评分进行排序
queryWrapper.orderByDesc("evaluation_score");
}
}
// 核心方法 selectPage:实现分页查询
// 两个参数:p queryWrapper
IPage<Book> pageObject = bookMapper.selectPage(p, queryWrapper);
return pageObject;
}
}
6、 创建测试用例
package com.imooc.reader.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.imooc.reader.entity.Book;
import com.imooc.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;
// IOC容器初始化
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class BookServiceImplTest {
@Resource
private BookService bookService;
@Test
public void paging() {
IPage<Book> pageObject = bookService.paging(2l,"quantity" ,2, 10);
// getRecords: 分页对象记录列表
List<Book> records = pageObject.getRecords();
// 增强for循环
for(Book b:records){
System.out.println(b.getBookId() + ":" + b.getBookName());
}
System.out.println("总页数:" + pageObject.getPages());
System.out.println("总记录数:" + pageObject.getTotal());
}
}
7、 controller 层配置
package com.imooc.reader.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.imooc.reader.entity.Book;
import com.imooc.reader.entity.Category;
import com.imooc.reader.service.BookService;
import com.imooc.reader.service.CategoryService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import java.util.List;
/**
* @ClassName BookController
* @Description 图书控制类,接收前端请求
* @date 2021/5/8 21:54
* @Param
* @return
*/
@Controller
public class BookController {
@Resource
private CategoryService categoryService;
@Resource
private BookService bookService;
/**
* 显示首页
* @return
*/
@GetMapping("/")
public ModelAndView showIndex() {
ModelAndView mav = new ModelAndView("/index");
List<Category> categoryList = categoryService.selectAll();
mav.addObject("categoryList", categoryList);
return mav;
}
/**
* 分页查询图书列表
* @param categoryId 分类编号
* @param order 排序方式
* @param p 页号
* @return 分页对象
*/
// 绑定URL
@GetMapping("/books")
// 使用springMVC对这个IPage对象进行JSON序列化输出
@ResponseBody
public IPage<Book> selectBook(Long categoryId , String order ,Integer p) {
// 容错处理: 若前台没有传入页号,默认第一页
if (p == null) {
p = 1;
}
// p: 前台传过来的页号
IPage<Book> pageObject = bookService.paging(categoryId , order , p, 10);
return pageObject;
}
}
8、 JavaScript + Ajax 结合开发前端
<!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">
<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="/">
<img src="https://m.imooc.com/static/wap/static/common/img/logo2.png" class="mt-1" style="width: 100px">
</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>
三、 效果图
以上是关于基于Spring+SpringMVC+MyBatis开发书评网图书分页查询模块采用Ajax动态加载图书信息和实现图书多条件动态查询的主要内容,如果未能解决你的问题,请参考以下文章
抽奖活动啦!5本SpringMVC+MyBatis相关3本Android Studio相关6本Kafka相关