PageHelper的高级使用,一个注解即可实现分页 一个注

一个注解就能搞定分页,为何你的却那么复杂

一个java程序员都避免不了增删改查,最近这几天又开始去写增删改查的接口了。这个时候就避免不了做数据的分页。

所以这几天写下来发现,即使使用了 pagehelper 分页插件,去对数据物理分页。虽然 pagehelper 插件使用起来很简单了。

但是我是个非常懒的程序员,多一行非业务相关的代码,我都不想写。 一个函数下来,被来业务程序就四五行,一顿操作下来非业务代码都占用了3份1。我是非常不能接受这些无相关业务太多的代码嵌入到函数中的。

其中一点就是:代码阅读起来不清晰,代码结构冗余,我特别喜欢看即简洁,条理又清晰的的。

所以自己就封装了一个 基于 pagehelper 上分页工具使用,即简洁,使用又方便。

1、思路

使用Spring拦截器和aspectj的作用,MethodInterceptor.java 去做Mapper接口的拦截,然后对要分页的方法加上 自定义分页注解 @StartPage ,在拦截到该方法的时候就,方法执行前,利用 **pagehelper.startPage()**进行分页,然后继续执行该方法,将查询结果封装到Page里面。即可实现分页拦截,在不修改 pagehelper 的操作上。这样子就避免了,在也service层的业务中去写这个一个多余的代码。

还避免了,在业务的service函数中,出现误操作,提前执行了 PageHelper.start()方法。导致真正的分页方法不生效了。

比如:

1
2
3
4
5
6
java复制代码PageHelper.start(1,10);
........
cityMapper.selectById(id);
........
userMaper.selectList();
........

如上这种情况 userMaper.selectList(); 是需要分页的数据,但是在此之前执行了 cityMapper.selectById(id); 所以这个时候 cityMapper.selectById(id); 生效了。userMaper.selectList();分页 不生效。

使用这种注解方式,就不需要管这种情况,因为分页处理直接是在 当前mapper函数上处理了。

1、新建一个SpringBoot项目,将其做成一个starter。

2、相关文件介绍

封装一个 分页对象:

  • 1、Page.java
1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码public class Page<T> implements IPage<T>
{
private int pageNum = 1;
private int pageSize = 15;
private int pages;
private long total;
private int[] navigatepageNums = new int[]{0};
private List<T> rows = Collections.emptyList();
private boolean START_PAGE_ED = false;
private OrderBy[] orderBys = new OrderBy[0];

// 省略 set get
}
  • OrderBy: 排序查询对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
java复制代码/**
* <br>
*
* @author 永健
* @since 2020-06-16 15:02
*/
public class OrderBy
{
private String[] columns;
private Direction direction;

public OrderBy(OrderBy.Direction direction, String... properties) {
this.columns = properties;
this.direction = direction;
}

// set get

public enum Direction {
ASC,
DESC;

Direction()
{
}

public boolean isAscending()
{
return this.equals(ASC);
}

public boolean isDescending()
{
return this.equals(DESC);
}
}
}
  • PageHelperAutoConfiguration.java SpringBoot自动配置类,starter的关键操纵
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
java复制代码@Configuration
// 加载SqlSessionFactory
@ConditionalOnBean({SqlSessionFactory.class})
//允许自动读取配置文件
@EnableConfigurationProperties({PageHelperProperties.class})
// 在加载配置的类
@AutoConfigureAfter({MybatisAutoConfiguration.class})
// 加载自定义Config配置类
@Import(PageHelperConfig.class)
public class PageHelperAutoConfiguration
{

@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;

/**
* SpringBoot的参数自动配置类
*/
@Autowired
private PageHelperProperties properties;

public PageHelperAutoConfiguration()
{
}

/**
* 注册Pagehelper拦截器
*/
@PostConstruct
public void addPageInterceptor()
{
PageInterceptor interceptor = new PageInterceptor();
Properties properties = new Properties();
properties.putAll(this.properties.getProperties());
interceptor.setProperties(properties);
Iterator var3 = this.sqlSessionFactoryList.iterator();

while (var3.hasNext())
{
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3.next();
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
}
  • PageHelperProperties.java 就是读取 PageHelper 插件的配置类的。属性如下:
  • PageHelperConfig.java 自定义配置类,主要是配置 Spring的增强类 DefaultPointcutAdvisor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
java复制代码/**
* <br>
*
* @author 永健
* @since 2020-11-11 11:19
*/
@Configuration
public class PageHelperConfig
{
/**
* 表达式
* 拦截哪个包下的所有方法
*/
private static final String EXECUTION = "execution(* %s..*.*(..))";

@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor2(PageHelperProperties pageHelperProperties) {

// 拦截器
PageMethodInterceptor interceptor = new PageMethodInterceptor();

// 切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
String mapperPackage = pageHelperProperties.getMapperPackage();
pointcut.setExpression(String.format(EXECUTION,mapperPackage));

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,interceptor);
return advisor;
}
}
  • PageMethodInterceptor.java 重点:拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
JAVA复制代码 /**
* 核心方法
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
Method method = methodInvocation.getMethod();
StartPage annotation = method.getAnnotation(StartPage.class);
if (annotation != null)
{
LOGGER.info("start page mapper");
}
Page<?> page = getPage(methodInvocation);

if (page != null)
{
if (!page.isStartPageEd())
{

PageHelper.startPage(page.getPageNum(), page.getPageSize(),PageUtils.filterSql(page.getOrderBy()));
Object proceed = methodInvocation.proceed();
page.setRows(proceed);
return proceed;
}
}
return methodInvocation.proceed();
}
  • @StartPage.java 分页注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码/**
* <p>
*
* </p>
*
* @author 永健
* @since 2020-11-11 11:52
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StartPage
{
}

……

项目搭建完毕! 将项目达成一个 jar文件引入到另外一个SpringBoot项目中。

3、使用

在另外一个项目中使用。

1
2
3
4
5
java复制代码        <dependency>
<groupId>cn.yj.pagehelper</groupId>
<artifactId>annotation-pagehelper</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

1、pagehelper配置文件

1
2
3
4
5
6
yaml复制代码# 如下的配置文件都除了多增加一个 mapper-package 属性外,其他的一切 pagehelper 的配置都保持原有的功能。
pagehelper:
helper-dialect: mysql
mapper-package: com.ex.das.mapper # mapper接口下的包
reasonable: false # true:当默认值为pageNum<=0时,自动配置为1,pageSize>pages时候,默认为最后一页
supportMethodsArguments: false # 不支持参数接口分页

2、在CityMapper.java中的方法加上 注解@StartPage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
java复制代码/**
* <br>
*
* @author 永健
* @since 2020-11-11 15:02
*/
public interface CityMapper
{
/**
*
* @param page 分页参数
* @return
*/
@StartPage
@Select("select * from city")
List<City> selectPage(IPage<City> page);

/**
*
* @param page 分页参数
* @param city 查询对象
* @return
*/
@StartPage
List<City> selectList(IPage<City> page,@Param("params") City city);
}

3、Service、Controller中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码public interface ICityService
{
// 可有返回值
Page<City> getCityPage(Page<City> page);

// 可没有返回值
void getCitysPage(Page<City> page);

// 带查询参数
Page<City> getCitysPage3(Page<City> page,City city);

Page<City> getCitysPage4(Page<City> page,City city);
}

CityServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
java复制代码@Service
public class CityServiceImpl implements ICityService
{

private final CityMapper cityMapper;

@Autowired
public CityServiceImpl(CityMapper cityMapper)
{
this.cityMapper = cityMapper;
}

/**
* 注解分页
* @param page 分页参数
* @return
*/
@Override
public Page<City> getCityPage(Page<City> page)
{
return page.setRows(cityMapper.selectPage(page));
}

/**
* 使用注解分页可不带返回值,已经将结果封装到page 中
* @param page
*/
@Override
public void getCitysPage(Page<City> page)
{
cityMapper.selectPage(page);
}

/**
* 不使用中注解分页
* @param page 分页参数
* @param city 查询参数
* @return
*/
@Override
public Page<City> getCitysPage3(Page<City> page, City city)
{
return page.startPage().setRows(cityMapper.selectList(page, city));
}

/**
* 使用注解分页
* @param page 分页参数
* @param city 查询参数
* @return
*/
@Override
public Page<City> getCitysPage4(Page<City> page, City city)
{
cityMapper.selectList(page, city);
return page;
}
}

SpringController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
java复制代码/**
* <br>
*
* @author 永健
* @since 2020-04-22 09:30
*/
@RestController
public class SpringController extends BaseController<City>
{

@Autowired
ICityService cityService;


@GetMapping("/list")
public R page1()
{
return success(cityService.getCityPage(page()));
}

@GetMapping("/list2")
public R page2()
{
Page<City> page = page(new OrderBy(OrderBy.Direction.ASC, "id"));
cityService.getCitysPage(page);
return success(page);
}

@GetMapping("/list3")
public R page3(City city)
{
return success(cityService.getCitysPage3(page(new OrderBy(OrderBy.Direction.ASC, "id")), city));
}

@GetMapping("/list4")
public R page4(City city)
{
return success(cityService.getCitysPage4(page(new OrderBy(OrderBy.Direction.ASC, "id")), city));
}
}

controller 中的使用,为了更加将分页参数与查询参数分离开。抽取一个共用的BaseController 也可以将封装好统一的返回对象给客户端,这样子即规范统一又好管理,简洁又方便。还可以放一些当前用户的信息啥的….

所以 BaseController.java 负责获取分页参数和封装好分页对象。包括统一响应客户端的对象,不用特意去 new一个对象了直接重父类拿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
java复制代码public class BaseController<T>
{
// 。。。。。。
protected Page<T> page()
{
int pageNumber = getParamsInt("pageNum");
int pageSize = getParamsInt("pageSize");
return new Page<>(pageNumber, pageSize);
}

/**
*
* @param orderBy 排序对象
* @return
*/
protected Page<T> page(OrderBy... orderBy)
{
int pageNumber = getParamsInt("pageNum");
int pageSize = getParamsInt("pageSize");
return new Page<>(pageNumber==0?1:pageNumber, pageSize==0?15:pageSize, orderBy);
}

private HttpServletRequest getRequest()
{
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return ((ServletRequestAttributes) attributes).getRequest();
}

private int getParamsInt(String name)
{
String parameter = getRequest().getParameter(name);
if (parameter == null || "".equals(parameter.trim()))
{
return 0;
}
return Integer.valueOf(parameter);
}
}

4、验证分页结果

项目启动访问获取数据。

  • list 接口

拦截器已经生效。

  • list3带参数的分页注解分页

使用结束了,一个注解就能简单的搞定分页操作,mysql的分页操作。你还在写多那几行非业务相关的代码吗????

当然,如果不使用该注解分页方式也可使用 PageHelper 的方式进行分页。两不冲突。引入到你的项目中根据自己需要定制自己的一套规则。没有固定死的,合适你的项目的就是好的。

因为我懒,所以我就爱动脑爱动手,减轻开发中的痛苦,去写一个更加适合我个人开发的组建,抽离开来,方便以后个人使用便捷,不需要重复去写。直接引用这一套代码即可,更能提升个人开发的效率。

如上代 码可完善地方很多,感兴趣的,可以将其继续扩展使用学习使用…

如果公司让你封装一个分页插件的使用,你会怎么去封装一个???

更多PageHelper的使用方式,请移步官网

github.com/pagehelper/…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%