## 表格分页

本商城前端采用Element数据分页组件`Pagination`分页，后端采用`Mybatis`的`PageHelper`分页插件。

### 前端分页

前端采用`Pagination`分页，具体文档参考[Element UI][https://element.eleme.cn/#/zh-CN/component/pagination]

本商城中，组件定义位置为：`src/components/Pagination/index.vue`

```html
<el-pagination
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      v-bind="$attrs"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
/>
```

该组件中定义了两个事件，其中`@size-change`为组件页数改变时会触发，而` @current-change`事件中，当前页数改变时即会触发该事件。

其他页面需要用到分页时，通过import导入该组件，并通过设置相关参数来使用，以下代码参考`src/views/order/order/index.vue`

```html
<pagination
  v-show="pageVO.total > 0"
  :total="pageVO.total"
  :page.sync="pageQuery.pageNum"
  :limit.sync="pageQuery.pageSize"
  @pagination="getDataList()"
/>
```

组件在被引用时，页面可以调用他的同名参数 `@pagination`

```js
getPage() {
    this.pageLoading = true
    api.page({ ...this.pageQuery, ...this.searchParam }).then(pageVO => {
        this.pageVO = pageVO
        this.pageLoading = false
    })
}
```

### 后台分页

后端采用`Mybatis`的`PageHelper`分页插件，由`PageHelper-Spring-Boot-Starter`集成分页插件到Spring Boot来完成表格分页。

```
使用pagehelper进行分页，该分页只能一对一。
```

#### 导入依赖

```xml
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
```

#### 建立分页工具类

```java
public class PageUtil {

    /**
     * 使用pagehelper进行分页，该分页只能一对一
     */
    public static <T> PageVO<T> doPage(PageDTO pageDTO, ISelect select) {

        PageSerializable<T> simplePageInfo = PageHelper.startPage(pageDTO).doSelectPageSerializable(select);

        PageVO<T> pageVO = new PageVO<>();
        pageVO.setList(simplePageInfo.getList());
        pageVO.setTotal(simplePageInfo.getTotal());
        pageVO.setPages(getPages(simplePageInfo.getTotal(), pageDTO.getPageSize()));
        return pageVO;
    }

    public static Integer getPages(long total, Integer pageSize) {

        if (total == -1) {
            return 1;
        }
        if (pageSize > 0) {
            return  (int) (total / pageSize + ((total % pageSize == 0) ? 0 : 1));
        }
        return  0;
    }
}
```

#### 搜索

服务端`ShopUserController`

```java
@RequestMapping(value = "/m/shop_user")
@RestController("multishopShopUserController")
@Tag(name = "店铺用户信息")
public class ShopUserController {

	@Autowired
	private ShopUserService shopUserService;

	@GetMapping("/page")
	@Operation(summary = "店铺用户列表" , description = "获取店铺用户列表")
	public ServerResponseEntity<PageVO<ShopUserVO>> page(@Valid PageDTO pageDTO, String nickName) {
		UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
		PageVO<ShopUserVO> shopUserPage = shopUserService.pageByShopId(pageDTO, userInfoInTokenBO.getTenantId(), nickName);
		return ServerResponseEntity.success(shopUserPage);
	}
}
```

```java
@Service
public class ShopUserServiceImpl implements ShopUserService {

	@Resource
	private ShopUserMapper shopUserMapper;

	@Override
	public PageVO<ShopUserVO> pageByShopId(PageDTO pageDTO, Long shopId, String nickName) {
		return PageUtil.doPage(pageDTO, () -> shopUserMapper.listByShopId(shopId, nickName));
	}
}
```

可见，传入的参数为`pageDTO`，该对象是根据**POJO**，即“Plain Old Java Object”->“简单java对象”而得。

> POJO的意义就在于它的简单而灵活性，因为它的简单和灵活，使得POJO能够任意扩展，从而胜任多个场合，也就让一个模型贯穿多个层成为现实。

|           名称            |                    含义                    |                             说明                             |
| :-----------------------: | :----------------------------------------: | :----------------------------------------------------------: |
|   PO(Persistant Object)   | 代表持久层对象的意思，对应数据库中表的字段 |                 一个PO就是数据库中的一条记录                 |
|    BO(Business Object)    |          把业务逻辑封装成一个对象          | 教育经历是一个PO，技术能力是一个PO，工作经历是一个PO，建立一个HR对象，也即BO去处理简历，每个BO均包含这些PO |
|      VO(View Object)      |                 表现层对象                 |                     后台返回给前端的对象                     |
| DTO(Data Transfer Object) |                数据传输对象                |                      前端传给后台的对象                      |

`pageDTO`如下

```java
public class PageDTO implements IPage {
   /** ...省略*/
       
    /**
     * 最大分页大小，如果分页大小大于500，则用500作为分页的大小。防止有人直接传入一个较大的数，导致服务器内存溢出宕机
     */
    public static final Integer MAX_PAGE_SIZE = 500;

    /**
     * 当前页
     */
    @NotNull(message = "pageNum 不能为空")
    @Schema(description = "当前页" , requiredMode = Schema.RequiredMode.REQUIRED)
    private Integer pageNum;

    @NotNull(message = "pageSize 不能为空")
    @Schema(description = "每页大小" , requiredMode = Schema.RequiredMode.REQUIRED)
    private Integer pageSize;

    @Schema(description = "排序字段数组，用逗号分割" )
    private String[] columns;

    @Schema(description = "排序字段方式，用逗号分割，ASC正序，DESC倒序" )
    private String[] orders;

   /** ...省略*/
}
```

返回给前端的参数`PageVO`如下：

```java
public class PageVO<T> {

    @Schema(description = "总页数" )
    private Integer pages;

    @Schema(description = "总条目数" )
    private Long total;

    @Schema(description = "结果集" )
    private List<T> list;

   /** ...省略*/
}
```

调用`PageUtil.doPage(pageDTO, () -> shopUserMapper.listByShopId(shopId, nickName))`方法，对返回的列表进行分页。

