1.提取出分页的逻辑放在工具类中
分页逻辑中需要的属性
- 1.totalRows:声明数据库中一共有多少条记录,读取数据库时可以获得
- 2.totalPages:一共能分多少页,通过数据库中有多少条记录和每页显示多少条记录计算出来
①如果
总页数%每页显示的条数==0
一共能分多少页=总页数/每页显示的条数
即:totalPages=totalRows/pageSize
②如果
总页数%每页显示的条数!=0
一共能分多少页=总页数/每页显示的条数+1
即:totalPages=totalRows/pageSize+1 - 3.pageSize:每页显示多少条记录,通过前端获取到
- 4.currentpage:当前是第几页,通过前端获取到。前端是第几页,后端就是第几页
- 5.start:每页开始的位置。通过当前页和每页显示几条数据计算出来
start? currentPage(当前页) pageSize(每页显示几条数据)
0 1 5
5 2 5
10 3 5
start = (currentPage-1)*pageSize
- 6.end:每页结束的位置,start+pageSize
分页逻辑中需要的方法
-
1.构造方法(计算一共能分出多少页)
//构造方法 public PageInfo(int totalRows,int pageSize){ this.totalRows=totalRows; this.pageSize=pageSize; //一共能分出多少页 if (this.totalRows%this.pageSize==0){ this.totalPages=this.totalRows/this.pageSize; }else { this.totalPages=this.totalRows/this.pageSize+1; } }
-
2.分页方法
//分页逻辑 public void doPaging(int reqPage){ this.currentPage=reqPage; //计算开始和结束的位置 this.start= (this.currentPage-1)*this.pageSize; }
完整的分页逻辑代码
package com.neusoft.util;
/*
* 分页信息类
* @Author
* @Date 2021-8-16
* */
import com.neusoft.pojo.Food;
import java.util.List;
public class PageInfo<T> {
private int totalRows;//声明数据库中一共有多少条记录
private int totalPages;//一共能分多少页
private int pageSize;//每页显示多少条记录
private int currentPage = 1;//当前页,前端是第几页,后端就是第几页。需要接收前端数据
private int start;//每页开始的位置
private int end;//每页结束的位置
private List<T> list; //每页展示所需展示的数据
//构造方法
public PageInfo(int totalRows,int pageSize){
this.totalRows=totalRows;
this.pageSize=pageSize;
//一共能分出多少页
if (this.totalRows%this.pageSize==0){
this.totalPages=this.totalRows/this.pageSize;
}else {
this.totalPages=this.totalRows/this.pageSize+1;
}
}
//分页逻辑
public void doPaging(int reqPage){
this.currentPage=reqPage;
//计算开始的位置
this.start= (this.currentPage-1)*this.pageSize;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
2.将分页的逻辑在业务逻辑层实现(即在service层实现)
package com.neusoft.service;
import com.neusoft.mapper.FoodMapper;
import com.neusoft.pojo.Food;
import com.neusoft.util.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class FoodService implements IFoodService {
@Autowired
FoodMapper foodMapper;
/*
* currPage:当前是第几页
* pageSize:每页显示多少条记录
* 通过list.size获取数据库中总的数据条数
* */
@Override
public PageInfo<Food> foodListBiz(int currPage,int pageSize) {
//1.调用数据库的全表查询,存储在缓存中
List<Food> list = foodMapper.foodlist();
//2.调用分页
PageInfo<Food> pageInfo = new PageInfo<Food>(list.size(),pageSize);
//3.开始分页
pageInfo.doPaging(currPage);
//设置每一页的最后一条数据
//如果当前页为最后一页
if (currPage==pageInfo.getTotalPages()){
//最后一条数据==总数据的长度
pageInfo.setEnd(list.size());
}
//
else {
pageInfo.setEnd(pageInfo.getStart() + pageSize);
}
// sublist为分页结果[start,end)
List<Food> sublist = list.subList(pageInfo.getStart(),pageInfo.getEnd());
//5.将分页结果存到pageInfo中的list
pageInfo.setList(sublist);
return pageInfo;
}
}
3.controller层实现分页
package com.neusoft.controller;
import com.neusoft.pojo.Food;
import com.neusoft.service.IFoodService;
import com.neusoft.util.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/food")
public class FoodController {
// 通过@Autowired让spring实现bean的自动装配工作
@Autowired
IFoodService foodService;
@ResponseBody
@RequestMapping("/list")
/*
* currPage:为前端传过来的当前页
* PageSize:为前端传过来的每页显示的数据条数
* */
public PageInfo<Food> listfoods(int currPage, int pageSize)
{
return foodService.foodListBiz(currPage,pageSize);
}
}
4.通过拦截器,实现将数据从数据库中加载到缓存
目的:是为了让分页逻辑更高效。我们要把数据库中的所有数据加载到缓存中,这样可以大幅缩短请求耗时(因为只有第一个用户是从数据库中拿数据,同时数据被加载到缓存中,请求耗时稍微长一点。其余用户直接从缓存中拿数据,请求耗时很短)
实现方式:
拦截器代码:
package com.neusoft.util;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInter implements HandlerInterceptor {
@Override
// 请求发生前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("startTime",System.currentTimeMillis());
System.out.println("请求开始了");
return true;
}
@Override
// 请求完成后
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("请求结束了");
long startTime=(Long)request.getAttribute("startTime");
long endTime=System.currentTimeMillis();
System.out.println("本次请求耗时:"+(endTime-startTime));
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
mybatis.xml代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--二级缓存总开关-->
<setting name="cacheEnabled" value="true" />
</settings>
</configuration>
在application.xml的sqlSessionFactory中配置mybatis.xml对象的别名
<property name="configLocation" value="classpath:mybatis.xml"/>
-
application.xml的完整代码:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 引入db配置文件 --> <!-- 配置dataSource数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/business?serverTimezone=UTC&characterEncoding=utf8"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!-- 创建SqlSessionFactory,并配置实体对象别名 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="typeAliasesPackage" value="com.neusoft.pojo" /> <property name="mapperLocations" value="classpath:mapper/FoodMapper.xml"/> <property name="configLocation" value="classpath:mybatis.xml"/> </bean> <!-- 配置Mapper。自动扫描Mapper接口,并为其注入SqlSessionFactory --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> <property name="basePackage" value="com.neusoft.mapper"></property> </bean> <!-- 配置Spring提供的事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
springMVC.xml的配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.neusoft.util.MyInter"></bean>
</mvc:interceptor>
</mvc:interceptors>
-
springMVC.xml的完整代码
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <mvc:annotation-driven /> <context:component-scan base-package="com.neusoft.controller" /> <context:component-scan base-package="com.neusoft.service"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.neusoft.util.MyInter"></bean> </mvc:interceptor> </mvc:interceptors> </beans>
5.vue实现前端分页逻辑
使用element-ui的
<template>
<div>
<el-table
:data="food"
style="width: 100%">
<el-table-column
prop="foodId"
label="食品id"
>
</el-table-column>
<el-table-column
prop="foodName"
label="食品名称"
>
</el-table-column>
<el-table-column
prop="foodExplain"
label="食品介绍">
</el-table-column>
<el-table-column
prop="foodImg"
label="食品图片"
>
</el-table-column>
<el-table-column
prop="foodPrice"
label="食品价格"
>
</el-table-column>
<el-table-column
prop="businessId"
label="商家id"
>
</el-table-column>
<el-table-column
prop="remarks"
label="备注"
>
</el-table-column>
</el-table>
<div class="block">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[2, 3, 4]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
export default{
data(){
return{
// 一共有多少条数据
total:0,
//每页显示条数
pageSize:2,
//当前页
currentPage:1,
food:[]
}
},
methods:{
xmlRequestFun(currPage,pageSize){
let that = this
this.$axios({
method:'get',
url:'http://localhost:8888/proSSM/food/list?currPage='+currPage+'&pageSize='+that.pageSize
}).then(function(response){
console.log(response.data)
console.log(typeof response.data)
that.total=response.data.totalRows
that.currentPage=response.data.currentPage
that.food=response.data.list
// console.log(typeof that.food)
console.log(that.total)
})
},
// 每页条数改变时触发
handleSizeChange(pageSize) {
console.log(pageSize+"条每页");
this.pageSize=pageSize
this.handleCurrentChange(this.currentPage)
},
handleCurrentChange(currentPage) {
console.log("当前为:"+currentPage+"页");
this.currentPage=currentPage
this.pageFun(this.currentPage)
},
pageFun(pageIndex){
this.xmlRequestFun(pageIndex,this.pageSize)
console.log(pageIndex)
}
},
created() {
this.xmlRequestFun(1,this.pageSize)
}
}
</script>
<style>
</style>
自己定义的
<template>
<div>
<el-table
:data="food"
style="width: 100%">
<el-table-column
prop="foodId"
label="食品id"
>
</el-table-column>
<el-table-column
prop="foodName"
label="食品名称"
>
</el-table-column>
<el-table-column
prop="foodExplain"
label="食品介绍">
</el-table-column>
<el-table-column
prop="foodImg"
label="食品图片"
>
</el-table-column>
<el-table-column
prop="foodPrice"
label="食品价格"
>
</el-table-column>
<el-table-column
prop="businessId"
label="商家id"
>
</el-table-column>
<el-table-column
prop="remarks"
label="备注"
>
</el-table-column>
</el-table>
<p align="right">
<el-button @click="pageFun(currentPage-1<=0?1:currentPage-1)"><</el-button>
<el-button @click="pageFun(i)" v-for="i in totalPages">
{{i}}
</el-button >
<el-button @click="pageFun(currentPage+1>totalPages?totalPages:currentPage+1)">></el-button>
</p>
</div>
</template>
<script>
export default{
data(){
return{
// 一共有多少页
totalPages:0,
sizes:0,
pageSize:3,
currentPage:1,
food:[]
}
},
methods:{
xmlRequestFun(currPage,pageSize){
let that = this
this.$axios({
method:'get',
url:'http://localhost:8888/proSSM/food/list?currPage='+currPage+'&pageSize='+that.pageSize
}).then(function(response){
console.log(response.data.list)
console.log(typeof response.data)
that.totalPages=response.data.totalPages
that.currentPage=response.data.currentPage
that.food=response.data.list
// console.log(typeof that.food)
})
},
pageFun(pageIndex){
this.xmlRequestFun(pageIndex,this.pageSize)
console.log(pageIndex)
}
},
created() {
this.xmlRequestFun(1,this.pageSize)
}
}
</script>
<style>
</style>