Pre Merge pull request !123 from Sor1e/master

pull/123/MERGE
Sor1e 4 years ago committed by Gitee
commit 510da15fae

@ -40,12 +40,24 @@
<common-pool.version>2.10.0</common-pool.version> <common-pool.version>2.10.0</common-pool.version>
<commons-collections.version>3.2.2</commons-collections.version> <commons-collections.version>3.2.2</commons-collections.version>
<transmittable-thread-local.version>2.12.2</transmittable-thread-local.version> <transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
<mockito.version>4.1.0</mockito.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<!-- SpringCloud 微服务 --> <!-- SpringCloud 微服务 -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>

@ -1,130 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.2.0</version> <version>3.2.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
<description> <description>
ruoyi-common-core核心模块 ruoyi-common-core核心模块
</description> </description>
<dependencies> <dependencies>
<!-- SpringCloud Openfeign --> <!-- SpringCloud Openfeign -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency> </dependency>
<!-- SpringCloud Loadbalancer --> <!-- SpringCloud Loadbalancer -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency> </dependency>
<!-- Spring Context Support --> <!-- Spring Context Support -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId> <artifactId>spring-context-support</artifactId>
</dependency> </dependency>
<!-- Spring Web --> <!-- Spring Web -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId> <artifactId>spring-web</artifactId>
</dependency> </dependency>
<!-- Transmittable ThreadLocal --> <!-- Transmittable ThreadLocal -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId> <artifactId>transmittable-thread-local</artifactId>
</dependency> </dependency>
<!-- Apache Commons Pool2 --> <!-- Apache Commons Pool2 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
</dependency> </dependency>
<!-- Pagehelper --> <!-- Pagehelper -->
<dependency> <dependency>
<groupId>com.github.pagehelper</groupId> <groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId> <artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency> </dependency>
<!-- Hibernate Validator --> <!-- Hibernate Validator -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency> </dependency>
<!-- Jackson --> <!-- Jackson -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
</dependency> </dependency>
<!-- Alibaba Fastjson --> <!-- Alibaba Fastjson -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
</dependency> </dependency>
<!-- Jwt --> <!-- Jwt -->
<dependency> <dependency>
<groupId>io.jsonwebtoken</groupId> <groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId> <artifactId>jjwt</artifactId>
</dependency> </dependency>
<!-- Jaxb --> <!-- Jaxb -->
<dependency> <dependency>
<groupId>javax.xml.bind</groupId> <groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId> <artifactId>jaxb-api</artifactId>
</dependency> </dependency>
<!-- Apache Lang3 --> <!-- Apache Lang3 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<!-- Commons Io --> <!-- Commons Io -->
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
</dependency> </dependency>
<!-- Commons Fileupload --> <!-- Commons Fileupload -->
<dependency> <dependency>
<groupId>commons-fileupload</groupId> <groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId> <artifactId>commons-fileupload</artifactId>
</dependency> </dependency>
<!-- excel工具 --> <!-- excel工具 -->
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId> <artifactId>poi-ooxml</artifactId>
</dependency> </dependency>
<!-- Java Servlet --> <!-- Java Servlet -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
</dependency> </dependency>
<!-- Swagger --> <!-- Swagger -->
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId> <artifactId>swagger-annotations</artifactId>
</dependency> </dependency>
<dependency>
</dependencies> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</project> <scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,28 @@
package com.ruoyi.common.core.annotation.order;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 使:
* @DefaultOrder(column="createTime", orderType="desc", tableName="user")
* class UserVO {
* ...
* }
* startPage(UserVO.class)
* @author ruoyi
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(CustomOrders.class)
public @interface CustomOrder {
// 列名 驼峰最终会转换为下划线命名法作为最终排序列名。
String column() default "";
// 列对应的表名
String tableName() default "";
}

@ -0,0 +1,19 @@
package com.ruoyi.common.core.annotation.order;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author ruoyi
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CustomOrders {
CustomOrder[] value();
}

@ -0,0 +1,27 @@
package com.ruoyi.common.core.annotation.order;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 使:
* @DefaultOrder(column="createTime", orderType="desc", tableName="user")
* class UserVO {
* ...
* }
* startPage(UserVO.class)
* @author ruoyi
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultOrder {
// 默认排序列 驼峰最终会转换为下划线命名法作为最终排序列名。
String column() default "";
// 排序类型, desc/asc
String orderType() default "asc";
// 表名, 可不指定
String tableName() default "";
}

@ -0,0 +1,25 @@
package com.ruoyi.common.core.annotation.order;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* 使:
* class UserVO {
* ...
* @TableAlias("dept")
* private String deptName;
* ...
* }
* startPage(UserVO.class)
* , ,
* @author ruoyi
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableAlias {
String value() default "";
}

@ -1,8 +1,14 @@
package com.ruoyi.common.core.web.controller; package com.ruoyi.common.core.web.controller;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.lang.reflect.Field;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
import com.ruoyi.common.core.annotation.order.CustomOrder;
import com.ruoyi.common.core.annotation.order.DefaultOrder;
import com.ruoyi.common.core.annotation.order.TableAlias;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
@ -20,7 +26,7 @@ import com.ruoyi.common.core.web.page.TableSupport;
/** /**
* web * web
* *
* @author ruoyi * @author ruoyi
*/ */
public class BaseController public class BaseController
@ -60,12 +66,162 @@ public class BaseController
} }
} }
/**
*
* class
*
* TableAlias > CustomOrder > DefaultOrder
* @param clazz
*/
protected void startPage(Class<?> clazz) {
// 正常分页的情况
if (clazz == null) {
startPage();
return;
}
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (pageNum != null && pageSize != null) {
PageHelper.startPage(pageNum, pageSize);
}
// 处理orderBy的情况。
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
String column = SqlUtil.escapeOrderBySql(pageDomain.getOrderByColumn());
// 获取默认排序
if (StringUtils.isEmpty(orderBy)) {
orderBy = getDefaultOrderByAnnotation(clazz);
}
if (StringUtils.isEmpty(orderBy)) {
return;
}
// 根据列获取表名
String tableName = getTableNameByColumn(clazz, column);
if (StringUtils.isNotEmpty(tableName)) {
orderBy = tableName + "." + orderBy;
}
PageHelper.orderBy(orderBy);
}
/**
* fieldTableAlias
* @param clazz
* @param column
* @return
*/
private static String getFieldTableName(Class<?> clazz, String column) {
// 获取对象中所有的成员变量
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
String fieldName = field.getName();
if (Objects.equals(column, fieldName)) {
if (field.isAnnotationPresent(TableAlias.class)) {
TableAlias orderTableAlias = field.getAnnotation(TableAlias.class);
return orderTableAlias.value();
}
}
}
return null;
}
/**
* CustomOrder
* @param clazz
* @param column
* @return
*/
private static String getCustomOrderTableName(Class<?> clazz, String column) {
// 获取对象中所有的成员变量
if (clazz.isAnnotationPresent(CustomOrder.class)) {
CustomOrder[] customOrders = clazz.getAnnotationsByType(CustomOrder.class);
for (CustomOrder customOrder : customOrders) {
String realColumn = column;
if (column.contains("_")) {
realColumn = StringUtils.toCamelCase(customOrder.column());
}
if (Objects.equals(column, realColumn)) {
return customOrder.tableName();
}
}
}
return null;
}
/**
*
* @param clazz
* @return
*/
private static String getDefaultTableName(Class<?> clazz) {
// 最后查找类上的tableName
if (clazz.isAnnotationPresent(DefaultOrder.class)) {
DefaultOrder defaultOrder = clazz.getAnnotation(DefaultOrder.class);
if (StringUtils.isNotEmpty(defaultOrder.tableName())) {
return defaultOrder.tableName();
}
}
return null;
}
/**
* table
* @param clazz
* @param column
* @return
*/
private static String getTableNameByColumn(Class<?> clazz, String column) {
if (clazz == null) {
return null;
}
String tableName = null;
// 未指定排序 则尝试设置默认排序的Table
if (StringUtils.isEmpty(column)) {
tableName = getDefaultTableName(clazz);
return tableName;
}
// 优先获取字段的tableName
tableName = getFieldTableName(clazz, column);
if (StringUtils.isNotEmpty(tableName)) {
return tableName;
}
// 其次查找CustomOrder定义的column对应的TableName
tableName = getCustomOrderTableName(clazz, column);
if (StringUtils.isNotEmpty(tableName)) {
return tableName;
}
// 获取默认排序
tableName = getDefaultTableName(clazz);
return tableName;
}
/**
*
* @param clazz
* @return
*/
private String getDefaultOrderByAnnotation(Class<?> clazz) {
if (!clazz.isAnnotationPresent(DefaultOrder.class)) {
return null;
}
DefaultOrder defaultOrder = clazz.getAnnotation(DefaultOrder.class);
String orderBy = null;
if (StringUtils.isNotEmpty(defaultOrder.column())) {
orderBy = StringUtils.toUnderScoreCase(defaultOrder.column()) + " " + defaultOrder.orderType();
}
return orderBy;
}
/** /**
* *
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list) protected TableDataInfo getDataTable(List<?> list) {
{
TableDataInfo rspData = new TableDataInfo(); TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS); rspData.setCode(HttpStatus.SUCCESS);
rspData.setRows(list); rspData.setRows(list);
@ -76,7 +232,7 @@ public class BaseController
/** /**
* *
* *
* @param rows * @param rows
* @return * @return
*/ */
@ -87,7 +243,7 @@ public class BaseController
/** /**
* *
* *
* @param result * @param result
* @return * @return
*/ */

@ -0,0 +1,125 @@
package com.ruoyi.common.core.web.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.annotation.order.CustomOrder;
import com.ruoyi.common.core.annotation.order.DefaultOrder;
import com.ruoyi.common.core.annotation.order.TableAlias;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.core.web.page.TableSupport;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.*;
class BaseControllerTest {
@Test
void testStartPageByDefaultOrder()
{
@DefaultOrder(tableName = "user", column = "userName")
class UserVO {
private String userName;
}
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(10);
pageDomain.setPageSize(20);
MockedStatic<TableSupport> mocked = Mockito.mockStatic(TableSupport.class);
mocked.when(TableSupport::buildPageRequest).thenReturn(
pageDomain
);
new BaseController().startPage(UserVO.class);
Page<Object> localPage = PageHelper.getLocalPage();
String orderBy = localPage.getOrderBy();
assertEquals("user.user_name asc", orderBy);
}
@Test
void testStartPageByDefaultOrder2()
{
@DefaultOrder(tableName = "user", column = "user_name")
class UserVO {
private String userName;
}
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(10);
pageDomain.setPageSize(20);
MockedStatic<TableSupport> mocked = Mockito.mockStatic(TableSupport.class);
mocked.when(TableSupport::buildPageRequest).thenReturn(
pageDomain
);
new BaseController().startPage(UserVO.class);
Page<Object> localPage = PageHelper.getLocalPage();
String orderBy = localPage.getOrderBy();
assertEquals("user.user_name asc", orderBy);
}
@Test
void testStartPageByTableAlias()
{
class UserVO {
@TableAlias("user")
private String userName;
}
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(10);
pageDomain.setPageSize(20);
pageDomain.setOrderByColumn("userName");
MockedStatic<TableSupport> mocked = Mockito.mockStatic(TableSupport.class);
mocked.when(TableSupport::buildPageRequest).thenReturn(
pageDomain
);
new BaseController().startPage(UserVO.class);
Page<Object> localPage = PageHelper.getLocalPage();
String orderBy = localPage.getOrderBy();
assertEquals("user.user_name asc", orderBy);
}
@Test
void testStartPageByCustomOrder()
{
@CustomOrder(tableName = "user", column = "createTime")
class UserVO extends BaseEntity {
private String userName;
}
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(10);
pageDomain.setPageSize(20);
pageDomain.setOrderByColumn("createTime");
pageDomain.setIsAsc("desc");
MockedStatic<TableSupport> mocked = Mockito.mockStatic(TableSupport.class);
mocked.when(TableSupport::buildPageRequest).thenReturn(
pageDomain
);
new BaseController().startPage(UserVO.class);
Page<Object> localPage = PageHelper.getLocalPage();
String orderBy = localPage.getOrderBy();
assertEquals("user.create_time desc", orderBy);
}
@Test
void testStartPageByCustomOrder2()
{
@CustomOrder(tableName = "user", column = "create_time")
class UserVO extends BaseEntity {
private String userName;
}
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(10);
pageDomain.setPageSize(20);
pageDomain.setOrderByColumn("createTime");
pageDomain.setIsAsc("desc");
MockedStatic<TableSupport> mocked = Mockito.mockStatic(TableSupport.class);
mocked.when(TableSupport::buildPageRequest).thenReturn(
pageDomain
);
new BaseController().startPage(UserVO.class);
Page<Object> localPage = PageHelper.getLocalPage();
String orderBy = localPage.getOrderBy();
assertEquals("user.create_time desc", orderBy);
}
}
Loading…
Cancel
Save