Bootstrap

vue3+element-plus+mybatisplus实现分页

目录

写在前面

简单使用

mybatis-plus分页

elementplus的分页器

踩坑

配合搜索条件使用

效果



今天在使用这个Pagination分页的时候,有一个小坑,坑了我不少时间,记录一下

写在前面

前端使用vue3+elementplus,后端使用springboot+mybatisplus

对于elementplus的安装,这里就不多说了,直接开始使用。

简单使用

mybatis-plus分页

我们查看mybatis-plus的官方文档,直接使用他的分页插件

假设我需要分页查询sku(一个商城系统的术语,你可以粗略的理解为商品信息)的数据,假设我们已经有了一个实体类和service接口以及实现类,并且这个接口继承了mybatis-plus的IService接口,实现类继承mybatis-plus的ServiceImpl类,否则我们就不能使用它的CRUD接口。

//实体类
@Data
@TableName("my_sku_info")
public class SkuInfo implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @TableField("spu_id")
    private Long spuId;

    @TableField("sku_name")
    private String skuName;

    /**
     * 描述
     */
    @TableField("sku_desc")
    private String skuDesc;

    @TableField("category_id")
    private Long categoryId;

    @TableField("brand_id")
    private Long brandId;

    @TableField("sku_default_img")
    private Long skuDefaultImg;

    /**
     * 标题
     */
    @TableField("sku_title")
    private String skuTitle;

    @TableField("price")
    private BigDecimal price;

    /**
     * 副标题
     */
    @TableField("sku_subtitle")
    private String skuSubtitle;

    /**
     *售卖量
     */
    @TableField("sale_count")
    private String saleCount;

    @TableField(exist = false)
    private FileInfoVo fileInfoVo;
}


//service接口
public interface ISkuInfoService extends IService<SkuInfo> {
}
//service实现类
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements ISkuInfoService {

}

我们需要调用它的page方法,通过文档我们知道需要传入一个 IPage类型的对象,假设我们有一个GoodsServiceImpl 类来处理所有的逻辑

@Service
@Slf4j
public class GoodsServiceImpl implements IGoodsService {
    @Autowired
    private ISkuInfoService skuInfoService;

  @Override
    public Page getSkuList(Integer pageNum, Integer pageSize) {
  Page<SkuInfo> page = skuInfoService.page(new Page<SkuInfo>(pageNum, pageSize));
 return page;
 }
}

controller接受前端传入的分页数据

@RestController
@RequestMapping("/goods/")
@Slf4j
public class GoodsController {
 @Autowired
    IGoodsService goodsService;

 @GetMapping("get/sku/list/{pageNum}/{pageSize}")
    public R getSkuList(@PathVariable Integer pageNum, @PathVariable Integer pageSize, ) {
        Page list = goodsService.getSkuList(pageNum, pageSize);
        return RUtils.successData(list);
    }

}

到这,我们后端已经简单完成了。

elementplus的分页器

我们先来写一个axios请求

export function getSkuList(pageNum, pageSize) {
    return request({
        method: 'get',
        url: goodsBase + `get/sku/list/${pageNum}/${pageSize}`,
      
    })
}

在这里我们需要再次查看mybatis-plus的文档,我们需要知道这个返回的page有哪些属性,因为在前端中我们需要获取这些数据并处理

<template>
                        <--  其他代码,此处忽略 -->

   <el-pagination
        hide-on-single-page
        v-model:current-page="pageInfo.pageNum"
        v-model:page-size="pageInfo.pageSize"
        :total="pageInfo.totals"
    />
</template>

<script setup>
import {onMounted, reactive, ref} from "vue";
import {getSkuList, modifySku, getSpuAtlas} from '@/api/home/goods/goods'

/*数据封装区域*/
let pageInfo = reactive({
  pageNum: 1,
  pageSize: 5,
  totals: Number
})
/*初始化区域*/
onMounted(() => {
   getSkuListData(pageInfo.pageNum, pageInfo.pageSize)
})

/*方法事件区域*/

async function getSkuListData(pageNum, pageSize) {
  let res = await getSkuList(pageNum, pageSize)
  /*封装分页信息*/
    pageInfo.totals = res.data.data.total - 0
    pageInfo.pageNum = res.data.data.current - 0
    skuList.value = res.data.data.records
}
//监听
watch(()=>pageInfo.pageNum, (newValue) => {
  
  getSkuListData(pageInfo.pageNum, pageInfo.pageSize)
})

</script>

在官网中说不推荐使用事件

所以在上面的代码中,我使用事件监听来监听:current-page 和 page-size 的改变,他们的值只要改变了,就要发送请求获取对应的页码的table数据

踩坑

注意后端传入的分页数据很可能是字符串类型的,我们不能直接对分页器赋值,需要转换为数字类型,也就是-0就行了,否则可能会出现分页器消失的情况 

大工告成!

配合搜索条件使用

在实际情况中,我们一般不会简单分页查询就完事了,时常会伴有条件查询。

在上面的代码上,我需要添加一些条件。由于搜索条件一般只会在这一个地方使用,我就不用dto实体类封装了,直接使用map封装

后端:

@Service
@Slf4j
public class GoodsServiceImpl implements IGoodsService {  
 @Autowired
    private ISkuInfoService skuInfoService;

   @Override
    public Page getSkuList(Integer pageNum, Integer pageSize, Map<String, Object> skuSearchDto) {
        /*管管理员可以查看所有Sku信息
         * 非管理员只能查看自己的sku信息
         * 由于sku表并没有商家的字段,而spu表有,需要查出商家的所有spu,然后查出所有spu下的sku*/
        long adminId = StpUtil.getLoginIdAsLong();//使用satoken框架获取登录人的id
        List<SpuInfo> spuInfoList = null;
        boolean isAdmin = adminUserService.isAdmin(adminId);
        QueryWrapper<SkuInfo> wrapper = new QueryWrapper<>();
        if (!isAdmin) {
            QueryWrapper<SpuInfo> spuWraper = new QueryWrapper<>();
            spuWraper.eq("business_id", adminId);
            spuInfoList = spuInfoService.list(spuWraper);
            if (spuInfoList == null || spuInfoList.size() == 0) {
                return null;//如果不是管理员,并且没有SPU,不需要查询sku了,直接返回,
            } else {
                List<Long> spuIds = spuInfoList.stream().map(SpuInfo::getId).collect(Collectors.toList());
                wrapper.in("spu_id", spuIds);
            }
        }
        String brandId = (String) skuSearchDto.get("brandId");
        if (!StringUtils.isEmptyString(brandId)) {
            wrapper.eq("brand_id", skuSearchDto.get("brandId"));
        }
        String categoryId = (String) skuSearchDto.get("categoryId");
        if (!StringUtils.isEmptyString(categoryId)) {
            wrapper.eq("category_id", skuSearchDto.get("categoryId"));
        }
        String state = (String) skuSearchDto.get("state");
        if (!StringUtils.isEmptyString(state)) {
            wrapper.eq("state", skuSearchDto.get("state"));
        }
        String serachValue = (String) skuSearchDto.get("serachValue");
        if (!StringUtils.isEmptyString(serachValue)) {
            wrapper.like("sku_name", skuSearchDto.get("serachValue"))
                    .or().like("sku_subtitle", skuSearchDto.get("serachValue"))
                    .or().like("sku_title",serachValue);
        }
        Integer minPrice = Integer.valueOf(skuSearchDto.get("minPrice").toString());
        if (minPrice != 0) {
            wrapper.ge("price", minPrice);
        }
        Integer maxPrice = Integer.valueOf(skuSearchDto.get("maxPrice").toString());
        if (maxPrice != 0) {
            wrapper.le("price", maxPrice);
        }
        Page<SkuInfo> page = skuInfoService.page(new Page<SkuInfo>(pageNum, pageSize), wrapper);
        page.getRecords().forEach(item -> {
            if (item.getSkuDefaultImg() != null) {
                FileInfoVo infoVoFromFIles = fileService.getInfoVoFromFIles(item.getSkuDefaultImg());
                item.setFileInfoVo(infoVoFromFIles);
            }
        });
        return page;
    }
}

 controller类

@RestController
@RequestMapping("/goods/")
@Slf4j
public class GoodsController {
    @Autowired
    IGoodsService goodsService;

   @GetMapping("get/sku/list/{pageNum}/{pageSize}")
    public R getSkuList(@PathVariable Integer pageNum, @PathVariable Integer pageSize, @RequestParam Map<String, Object> skuSearchDto) {
        Page list = goodsService.getSkuList(pageNum, pageSize, skuSearchDto);
        return RUtils.successData(list);
    }
}

前端,我们需要修改一下axios请求,添加一个封装条件的变量

export function getSkuList(pageNum, pageSize, skuSearchDto) {
    return request({
        method: 'get',
        url: goodsBase + `get/sku/list/${pageNum}/${pageSize}`,
        params: skuSearchDto
    })
}
<template>
  <div>
    <!--    检索条件-->
    <el-form :inline="true" :model="skuSearchDto" ref="searchRef">
      <el-form-item label="分类" prop="categoryId">
        <el-cascader v-model="skuSearchDto.categoryId" :options="allCategoryList" @visible-change="getCategoryList"
                     :props="cascaderProps"/>
      </el-form-item>
      <el-form-item label="品牌" prop="brandId">
        <el-select v-model="skuSearchDto.brandId" class="m-2" placeholder="Select" size="large"
                   @visible-change="getBrandList" :disabled="skuSearchDto.categoryId.length==0">
          <el-option
              v-for="item in brandList"
              :key="item.id"
              :label="item.brandName"
              :value="item.brandId"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="状态" prop="state">
        <el-select v-model="skuSearchDto.state" class="m-2" placeholder="Select" size="large">
          <el-option
              label="上架"
              value="0"
          />
          <el-option
              label="下架"
              value="1"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="价格" prop="Price">
        <el-input-number v-model="skuSearchDto.minPrice" :min="1" @change="handleChange"/>
        -
        <el-input-number v-model="skuSearchDto.maxPrice" :min="skuSearchDto.minPrice" @change="handleChange"/>
      </el-form-item>
      <el-form-item label="检索" prop="serachValue">
        <el-input v-model="skuSearchDto.serachValue"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="skuSearch">搜索</el-button>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="searchRef.resetFields()">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
<-- 其他代码-->
 <el-pagination
        hide-on-single-page
        v-model:current-page="pageInfo.pageNum"
        v-model:page-size="pageInfo.pageSize"
        :page-sizes="[3, 5, 8]"
        :small="small"
        :background="background"
        layout="total, sizes, prev, pager, next, jumper"
        :total="pageInfo.totals"
        
    />
</template>
<script setup>
import {getSkuList, modifySku, getSpuAtlas} from '@/api/home/goods/goods'

let skuSearchDto = reactive({
  categoryId: '',
  brandId: '',
  state: '',
  serachValue: '',
  minPrice: 0,
  maxPrice: 0
})
let pageInfo = reactive({
  pageNum: 1,
  pageSize: 5,
  totals: Number
})

async function getSkuListData(pageNum, pageSize, skuSearchDto) {
  let res = await getSkuList(pageNum, pageSize, skuSearchDto)
  /*封装分页信息*/
     try {
    pageInfo.totals = res.data.data.total - 0
    pageInfo.pageNum = res.data.data.current - 0
    skuList.value = res.data.data.records
    for (let i = 0; i < skuList.value.length; i++) {
      if (skuList.value[i].skuDefaultImg != null) {
        skuList.value[i].imgBase64Str = await getImageToBase64FromFileId(skuList.value[i].skuDefaultImg)
      }
    }
  } catch (e) {
    console.log("这里捕获了一个异常,多半是后端查出的数据是空的,返回了一个null,或者是默认图片转换失败", e)
  }
}
function skuSearch() {
  getSkuListData(pageInfo.pageNum, pageInfo.pageSize, skuSearchDto)
}


onMounted(() => {
  skuSearch()
})
watch([()=>pageInfo.pageNum,()=>pageInfo.pageSize], (newValue) => {
  //这里使用了skuSearchDto,不能使用watchEffect,否则在skuSearchDto变化的时候也会触发
  skuSearch()
})

完成!

效果

;