【wrapper】增加wrapper功能

pull/3/head
fengshuonan 2021-01-19 22:59:14 +08:00
parent f32847a931
commit 0a6ab12db6
17 changed files with 531 additions and 0 deletions

View File

@ -0,0 +1,10 @@
# wrapper模块一种开发思路或者开发工具
将控制器层的返回结果进行进一层包装从而灵活的进行响应参数装配
例如:
select menu_id,menu_name,create_user from sys_menu
利用Wrapper可以将返回结果的关联字段响应中文名称例如create_user这种字段就不用去left join连表查询
另外wrapper时可以用缓存加快wrapper速度

35
kernel-d-wrapper/pom.xml Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>roses-kernel</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>kernel-d-wrapper</artifactId>
<packaging>pom</packaging>
<modules>
<module>wrapper-api</module>
<module>wrapper-sdk</module>
<module>wrapper-spring-boot-starter</module>
</modules>
<dependencies>
<!-- 开发规则 -->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-a-rule</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
wrapper的api模块

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-d-wrapper</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>wrapper-api</artifactId>
<packaging>jar</packaging>
<dependencies>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
package cn.stylefeng.roses.kernel.wrapper.api;
import java.util.Map;
/**
*
*
* @author fengshuonan
* @date 2020/7/24 17:18
*/
public interface BaseWrapper<T> {
/**
*
*
* @param beWrappedModel objlistpagePageResult
* @return
* @author fengshuonan
* @date 2020/7/24 17:22
*/
Map<String, Object> doWrap(T beWrappedModel);
}

View File

@ -0,0 +1,23 @@
package cn.stylefeng.roses.kernel.wrapper.api.annotation;
import cn.stylefeng.roses.kernel.wrapper.api.BaseWrapper;
import java.lang.annotation.*;
/**
* Controller
*
* @author fengshuonan
* @date 2020/7/24 17:10
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Wrapper {
/**
*
*/
Class<? extends BaseWrapper<?>>[] value();
}

View File

@ -0,0 +1,21 @@
package cn.stylefeng.roses.kernel.wrapper.api.constants;
/**
* Wrapper
*
* @author fengshuonan
* @date 2021/1/19 22:23
*/
public interface WrapperConstants {
/**
* Wrapper
*/
String WRAPPER_MODULE_NAME = "kernel-d-wrapper";
/**
*
*/
String WRAPPER_EXCEPTION_STEP_CODE = "24";
}

View File

@ -0,0 +1,24 @@
package cn.stylefeng.roses.kernel.wrapper.api.exception;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.rule.abstracts.AbstractExceptionEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.wrapper.api.constants.WrapperConstants;
/**
* Wrapper
*
* @author fengshuonan
* @date 2021/1/19 22:24
*/
public class WrapperException extends ServiceException {
public WrapperException(AbstractExceptionEnum exception, Object... params) {
super(WrapperConstants.WRAPPER_MODULE_NAME, exception.getErrorCode(), StrUtil.format(exception.getUserTip(), params));
}
public WrapperException(AbstractExceptionEnum exception) {
super(WrapperConstants.WRAPPER_MODULE_NAME, exception);
}
}

View File

@ -0,0 +1,42 @@
package cn.stylefeng.roses.kernel.wrapper.api.exception.enums;
import cn.stylefeng.roses.kernel.rule.abstracts.AbstractExceptionEnum;
import cn.stylefeng.roses.kernel.rule.constants.RuleConstants;
import cn.stylefeng.roses.kernel.wrapper.api.constants.WrapperConstants;
import lombok.Getter;
/**
* Wrapper
*
* @author fengshuonan
* @date 2021/1/19 22:24
*/
@Getter
public enum WrapperExceptionEnum implements AbstractExceptionEnum {
/**
*
*/
BASIC_TYPE_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + WrapperConstants.WRAPPER_EXCEPTION_STEP_CODE + "01", "被包装的值不能是基本类型"),
/**
*
*/
TRANSFER_ERROR(RuleConstants.BUSINESS_ERROR_TYPE_CODE + WrapperConstants.WRAPPER_EXCEPTION_STEP_CODE + "02", "字段包装转化异常");
/**
*
*/
private final String errorCode;
/**
*
*/
private final String userTip;
WrapperExceptionEnum(String errorCode, String userTip) {
this.errorCode = errorCode;
this.userTip = userTip;
}
}

View File

@ -0,0 +1 @@
wrapper模块的sdk

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-d-wrapper</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>wrapper-sdk</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--wrapper模块的api-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>wrapper-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--db模块的api-->
<!--包装的时候可能包装PageResult对象-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>db-api</artifactId>
<version>1.0.0</version>
</dependency>
<!-- aop -->
<!-- 包装过程是在aop中进行 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- mybatis-plus dao框架 -->
<!-- 包装分页的参数可能 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,213 @@
package cn.stylefeng.roses.kernel.wrapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.rule.pojo.response.ResponseData;
import cn.stylefeng.roses.kernel.wrapper.api.BaseWrapper;
import cn.stylefeng.roses.kernel.wrapper.api.annotation.Wrapper;
import cn.stylefeng.roses.kernel.wrapper.api.exception.WrapperException;
import cn.stylefeng.roses.kernel.wrapper.api.exception.enums.WrapperExceptionEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
* controlleraop
*
* @author fengshuonan
* @date 2020/7/24 17:42
*/
@Aspect
@Slf4j
public class WrapperAop {
/**
*
*
* @author fengshuonan
* @date 2020/7/24 17:42
*/
@Pointcut("@annotation(cn.stylefeng.roses.kernel.wrapper.api.annotation.Wrapper)")
private void wrapperPointcut() {
}
/**
*
*
* @author fengshuonan
* @date 2020/7/24 17:44
*/
@Around("wrapperPointcut()")
public Object doWrapper(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 直接执行原有业务逻辑
Object proceedResult = proceedingJoinPoint.proceed();
return processWrapping(proceedingJoinPoint, proceedResult);
}
/**
*
*
* @author fengshuonan
* @date 2020/7/24 17:53
*/
@SuppressWarnings("all")
private Object processWrapping(ProceedingJoinPoint proceedingJoinPoint, Object originResult) throws IllegalAccessException, InstantiationException {
// 获取@Wrapper注解
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = methodSignature.getMethod();
Wrapper wrapperAnnotation = method.getAnnotation(Wrapper.class);
// 获取注解上的处理类
Class<? extends BaseWrapper<?>>[] baseWrapperClasses = wrapperAnnotation.value();
// 如果注解上的为空直接返回
if (ObjectUtil.isEmpty(baseWrapperClasses)) {
return originResult;
}
// 获取原有返回结果如果不是ResponseData则不进行处理(需要遵守这个约定)
if (!(originResult instanceof ResponseData)) {
log.warn("当前请求的返回结果不是ResponseData类型直接返回原值");
return originResult;
}
// 获取ResponseData中的值
ResponseData responseData = (ResponseData) originResult;
Object beWrapped = responseData.getData();
// 如果是基本类型,不进行加工处理
if (ObjectUtil.isBasicType(beWrapped)) {
throw new WrapperException(WrapperExceptionEnum.BASIC_TYPE_ERROR);
}
// 如果是Page类型
if (beWrapped instanceof Page) {
// 获取Page原有对象
Page page = (Page) beWrapped;
// 将page中所有records都包装一遍
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : page.getRecords()) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
page.setRecords(maps);
responseData.setData(page);
}
// 如果是PageResult类型
else if (beWrapped instanceof PageResult) {
// 获取PageResult原有对象
PageResult pageResult = (PageResult) beWrapped;
// 将PageResult中所有rows都包装一遍
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : pageResult.getRows()) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
pageResult.setRows(maps);
responseData.setData(pageResult);
}
// 如果是List类型
else if (beWrapped instanceof Collection) {
// 获取原有的List
Collection collection = (Collection) beWrapped;
// 将page中所有records都包装一遍
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : collection) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
responseData.setData(maps);
}
// 如果是Array类型
else if (ArrayUtil.isArray(beWrapped)) {
// 获取原有的Array
Object[] objects = this.objToArray(beWrapped);
// 将array中所有records都包装一遍
ArrayList<Map<String, Object>> maps = new ArrayList<>();
for (Object wrappedItem : objects) {
maps.add(this.wrapPureObject(wrappedItem, baseWrapperClasses));
}
responseData.setData(maps);
}
// 如果是Object类型
else {
responseData.setData(this.wrapPureObject(beWrapped, baseWrapperClasses));
}
return responseData;
}
/**
* map
* <p>
* BaseWrapper
*
* @author fengshuonan
* @date 2020/7/24 21:40
*/
@SuppressWarnings("all")
private Map<String, Object> wrapPureObject(Object originModel, Class<? extends BaseWrapper<?>>[] baseWrapperClasses) {
// 首先将原始的对象转化为map
Map<String, Object> originMap = BeanUtil.beanToMap(originModel);
// 经过多个包装类填充属性
try {
for (Class<? extends BaseWrapper<?>> baseWrapperClass : baseWrapperClasses) {
BaseWrapper baseWrapper = baseWrapperClass.newInstance();
Map<String, Object> incrementFieldsMap = baseWrapper.doWrap(originModel);
originMap.putAll(incrementFieldsMap);
}
} catch (Exception e) {
log.error("原始对象包装过程,字段转化异常:{}", e.getMessage());
throw new WrapperException(WrapperExceptionEnum.TRANSFER_ERROR);
}
return originMap;
}
/**
* Objectarrayobject
*
* @author fengshuonan
* @date 2020/7/24 22:06
*/
private Object[] objToArray(Object object) {
int length = Array.getLength(object);
Object[] result = new Object[length];
for (int i = 0; i < result.length; i++) {
result[i] = Array.get(object, i);
}
return result;
}
}

View File

@ -0,0 +1 @@
wrapper功能的spring boot自动加载模块

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>kernel-d-wrapper</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>wrapper-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--wrapper的sdk-->
<dependency>
<groupId>cn.stylefeng.roses</groupId>
<artifactId>wrapper-sdk</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,29 @@
package cn.stylefeng.roses.kernel.wrapper.starter;
import cn.stylefeng.roses.kernel.wrapper.WrapperAop;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Wrapper
*
* @author fengshuonan
* @date 2021/1/19 22:42
*/
@Configuration
public class GunsWrapperAutoConfiguration {
/**
* Wrapper
*
* @author fengshuonan
* @date 2021/1/19 22:42
*/
@Bean
@ConditionalOnMissingBean(WrapperAop.class)
public WrapperAop wrapperAop() {
return new WrapperAop();
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.stylefeng.roses.kernel.wrapper.starter.GunsWrapperAutoConfiguration

View File

@ -34,6 +34,9 @@
<!--参数校验模块-->
<module>kernel-d-validator</module>
<!--wrapper包装模块-->
<module>kernel-d-wrapper</module>
<!--jwt模块用于token校验-->
<module>kernel-d-jwt</module>