初始化
This commit is contained in:
77
easyflow-commons/easyflow-common-web/pom.xml
Normal file
77
easyflow-commons/easyflow-common-web/pom.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?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>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-commons</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-common-web</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-common-satoken</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-common-base</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-common-ai</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,6 @@
|
||||
package tech.easyflow.common.web.controller;
|
||||
|
||||
public class BaseController {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
package tech.easyflow.common.web.controller;
|
||||
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.query.SqlOperators;
|
||||
import com.mybatisflex.core.service.IService;
|
||||
import com.mybatisflex.core.table.TableInfo;
|
||||
import com.mybatisflex.core.table.TableInfoFactory;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
import tech.easyflow.common.util.SqlOperatorsUtil;
|
||||
import tech.easyflow.common.util.SqlUtil;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.exceptions.ProgramException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
public class BaseCurdController<S extends IService<M>, M> extends BaseController {
|
||||
|
||||
|
||||
protected final S service;
|
||||
|
||||
public BaseCurdController(S service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加(保存)数据
|
||||
*
|
||||
* @param entity 表生成内容配置
|
||||
* @return {@code Result.errorCode == 0} 添加成功,否则添加失败
|
||||
*/
|
||||
@PostMapping("save")
|
||||
public Result<?> save(@JsonBody M entity) {
|
||||
Result<?> result = onSaveOrUpdateBefore(entity, true);
|
||||
if (result != null) return result;
|
||||
|
||||
if (entity == null) {
|
||||
throw new NullPointerException("entity is null");
|
||||
}
|
||||
LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
|
||||
commonFiled(entity, loginAccount.getId(), loginAccount.getTenantId(), loginAccount.getDeptId());
|
||||
service.save(entity);
|
||||
onSaveOrUpdateAfter(entity, true);
|
||||
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entity.getClass());
|
||||
Object[] pkArgs = tableInfo.buildPkSqlArgs(entity);
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("id", pkArgs);
|
||||
return Result.ok(resultMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键删除数据,id 需通过 json 传入,例如:
|
||||
* <pre>
|
||||
* {
|
||||
* "id":123
|
||||
* }
|
||||
* <pre/>
|
||||
*
|
||||
*
|
||||
* @param id 主键
|
||||
* @return {@code Result.errorCode == 0} 删除成功,否则删除失败
|
||||
*/
|
||||
@PostMapping("remove")
|
||||
@Transactional
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
List<Serializable> ids = Collections.singletonList(id);
|
||||
Result<?> result = onRemoveBefore(ids);
|
||||
if (result != null) return result;
|
||||
boolean success = service.removeById(id);
|
||||
onRemoveAfter(ids);
|
||||
return Result.ok(success);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据多个主键删数据内容,id 需通过 json 传入,例如:
|
||||
* <pre>
|
||||
* {
|
||||
* "ids":[123, 234, 222]
|
||||
* }
|
||||
* <pre/>
|
||||
*
|
||||
* @param ids 主键
|
||||
* @return {@code Result.errorCode == 0} 删除成功,否则删除失败
|
||||
*/
|
||||
@PostMapping("removeBatch")
|
||||
@Transactional
|
||||
public Result<?> removeBatch(@JsonBody(value = "ids", required = true) Collection<Serializable> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return Result.fail("id不能为空");
|
||||
}
|
||||
Result<?> result = onRemoveBefore(ids);
|
||||
if (result != null) return result;
|
||||
boolean success = service.removeByIds(ids);
|
||||
onRemoveAfter(ids);
|
||||
return Result.ok(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键更新内容
|
||||
*
|
||||
* @param entity 实体类数据
|
||||
* @return {@code Result.errorCode == 0} 更新成功,否则更新失败
|
||||
*/
|
||||
@PostMapping("update")
|
||||
public Result<?> update(@JsonBody M entity) {
|
||||
Result<?> result = onSaveOrUpdateBefore(entity, false);
|
||||
if (result != null) return result;
|
||||
service.updateById(entity);
|
||||
onSaveOrUpdateAfter(entity, false);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有所有数据
|
||||
*
|
||||
* @return 所有数据
|
||||
*/
|
||||
@GetMapping("list")
|
||||
public Result<List<M>> list(M entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<M> list = Tree.tryToTree(service.list(queryWrapper), asTree);
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据表主键查询数据详情。
|
||||
*
|
||||
* @param id 主键值
|
||||
* @return 内容详情
|
||||
*/
|
||||
@GetMapping("detail")
|
||||
public Result<M> detail(String id) {
|
||||
if (tech.easyflow.common.util.StringUtil.noText(id)) {
|
||||
throw new BusinessException("id must not be null");
|
||||
}
|
||||
return Result.ok(service.getById(id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询数据列表
|
||||
*
|
||||
* @param request 查询数据
|
||||
* @param sortKey 排序字段
|
||||
* @param sortType 排序方式 asc | desc
|
||||
* @param pageNumber 当前页码
|
||||
* @param pageSize 每页的数据量
|
||||
* @return 查询的结果集
|
||||
*/
|
||||
@GetMapping("page")
|
||||
public Result<Page<M>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
|
||||
}
|
||||
|
||||
|
||||
protected QueryWrapper buildQueryWrapper(HttpServletRequest request) {
|
||||
|
||||
QueryWrapper queryWrapper = new QueryWrapper();
|
||||
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
if (parameterMap == null || parameterMap.isEmpty()) {
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
String[] isQueryOrs = parameterMap.get("isQueryOr");
|
||||
boolean isQueryOrBool = false;
|
||||
|
||||
if (isQueryOrs != null && isQueryOrs.length > 0) {
|
||||
String isQueryOr = isQueryOrs[0];
|
||||
isQueryOrBool = "true".equals(isQueryOr);
|
||||
}
|
||||
|
||||
Map<String, String> propertyColumnMapping = TableInfoFactory.ofEntityClass(getEntityClass())
|
||||
.getPropertyColumnMapping();
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
String paramKey = entry.getKey();
|
||||
if (StringUtil.hasText(paramKey) && !paramKey.endsWith(OperatorBuilder.operatorSuffix) && propertyColumnMapping.containsKey(paramKey)) {
|
||||
String columnName = propertyColumnMapping.get(paramKey);
|
||||
String[] values = entry.getValue();
|
||||
if (values != null && values.length > 0 && StringUtil.hasText(values[0])) {
|
||||
String op = request.getParameter(paramKey + OperatorBuilder.operatorSuffix);
|
||||
if (StringUtil.hasText(op)) {
|
||||
OperatorBuilder.buildOperator(queryWrapper, columnName, op.trim(), values);
|
||||
} else {
|
||||
if (values.length == 2) {
|
||||
queryWrapper.between(columnName, values[0], values[1]);
|
||||
} else {
|
||||
String value = values[0];
|
||||
if (StringUtil.isNumeric(value)) {
|
||||
queryWrapper.eq(columnName, value);
|
||||
} else {
|
||||
if (isQueryOrBool) {
|
||||
queryWrapper.or(columnName + " like " + "'%" + value + "%' ");
|
||||
} else {
|
||||
queryWrapper.like(columnName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
protected Class<?> getEntityClass() {
|
||||
Type type = getClass().getGenericSuperclass();
|
||||
if (type instanceof ParameterizedType) {
|
||||
return (Class<M>) ((ParameterizedType) type).getActualTypeArguments()[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 方便子类复写,构建自己的 SqlOperators
|
||||
*
|
||||
* @param entity 实体类
|
||||
* @return SqlOperators
|
||||
*/
|
||||
protected SqlOperators buildOperators(M entity) {
|
||||
return entity == null ? SqlOperators.empty() : SqlOperatorsUtil.build(entity.getClass());
|
||||
}
|
||||
|
||||
protected String getDefaultOrderBy() {
|
||||
return "id desc";
|
||||
}
|
||||
|
||||
/**
|
||||
* 方便子类复写,构建自己的 orderBy
|
||||
*
|
||||
* @param sortKey 排序字段
|
||||
* @param sortType 排序类型
|
||||
* @param defaultOrderBy 默认方式内容
|
||||
* @return orderBy 的内容,返回 null 或者 空字符串,表示不参与排序
|
||||
*/
|
||||
protected String buildOrderBy(String sortKey, String sortType, String defaultOrderBy) {
|
||||
sortKey = StringUtil.camelToUnderline(sortKey);
|
||||
return SqlUtil.buildOrderBy(sortKey, sortType, defaultOrderBy);
|
||||
}
|
||||
|
||||
protected Page<M> queryPage(Page<M> page, QueryWrapper queryWrapper) {
|
||||
return service.page(page, queryWrapper);
|
||||
}
|
||||
|
||||
protected Result<?> onSaveOrUpdateBefore(M entity, boolean isSave) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onSaveOrUpdateAfter(M entity, boolean isSave) {
|
||||
//void
|
||||
}
|
||||
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onRemoveAfter(Collection<Serializable> ids) {
|
||||
//void
|
||||
}
|
||||
|
||||
protected void commonFiled(Object t, BigInteger userId, BigInteger tenantId, BigInteger deptId) {
|
||||
Method[] methods = t.getClass().getMethods();
|
||||
try {
|
||||
for (Method m : methods) {
|
||||
String name = m.getName();
|
||||
if ("setDeptId".equals(name)) {
|
||||
m.invoke(t, deptId);
|
||||
}
|
||||
if ("setTenantId".equals(name)) {
|
||||
m.invoke(t, tenantId);
|
||||
}
|
||||
if ("setCreatedBy".equals(name)) {
|
||||
m.invoke(t, userId);
|
||||
}
|
||||
if ("setModifiedBy".equals(name)) {
|
||||
m.invoke(t, userId);
|
||||
}
|
||||
if ("setCreated".equals(name)) {
|
||||
m.invoke(t, new Date());
|
||||
}
|
||||
if ("setModified".equals(name)) {
|
||||
m.invoke(t, new Date());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ProgramException("commonFiled反射出错:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package tech.easyflow.common.web.controller;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class OperatorBuilder {
|
||||
|
||||
public static final String operatorSuffix = "__op";
|
||||
public static final Set<String> supportedOperators = new HashSet<>(Arrays.asList(
|
||||
"eq", "ne", "gt", "ge", "lt", "le",
|
||||
"like", "likeLeft", "likeRight", "notLike", "notLikeLeft", "notLikeRight",
|
||||
"between", "notBetween", "in", "notIn"
|
||||
, "isNull", "isNotNull"));
|
||||
|
||||
|
||||
public static void buildOperator(QueryWrapper queryWrapper, String columnName, String op, String[] values) {
|
||||
if (!supportedOperators.contains(op)) {
|
||||
return;
|
||||
}
|
||||
switch (op) {
|
||||
case "eq":
|
||||
queryWrapper.eq(columnName, values[0]);
|
||||
break;
|
||||
case "ne":
|
||||
queryWrapper.ne(columnName, values[0]);
|
||||
break;
|
||||
case "gt":
|
||||
queryWrapper.gt(columnName, values[0]);
|
||||
break;
|
||||
case "ge":
|
||||
queryWrapper.ge(columnName, values[0]);
|
||||
break;
|
||||
case "lt":
|
||||
queryWrapper.lt(columnName, values[0]);
|
||||
break;
|
||||
case "le":
|
||||
queryWrapper.le(columnName, values[0]);
|
||||
break;
|
||||
case "like":
|
||||
queryWrapper.like(columnName, values[0]);
|
||||
break;
|
||||
case "likeLeft":
|
||||
queryWrapper.likeLeft(columnName, values[0]);
|
||||
break;
|
||||
case "likeRight":
|
||||
queryWrapper.likeRight(columnName, values[0]);
|
||||
case "notLike":
|
||||
queryWrapper.notLike(columnName, values[0]);
|
||||
break;
|
||||
case "notLikeLeft":
|
||||
queryWrapper.notLikeLeft(columnName, values[0]);
|
||||
break;
|
||||
case "notLikeRight":
|
||||
queryWrapper.notLikeRight(columnName, values[0]);
|
||||
break;
|
||||
case "between":
|
||||
queryWrapper.between(columnName, values[0], values[1]);
|
||||
break;
|
||||
case "notBetween":
|
||||
queryWrapper.notBetween(columnName, values[0], values[1]);
|
||||
break;
|
||||
case "in":
|
||||
queryWrapper.in(columnName, values);
|
||||
break;
|
||||
case "notIn":
|
||||
queryWrapper.notIn(columnName, values);
|
||||
break;
|
||||
case "isNull":
|
||||
queryWrapper.isNull(columnName);
|
||||
break;
|
||||
case "isNotNull":
|
||||
queryWrapper.isNotNull(columnName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package tech.easyflow.common.web.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class WhiteLabelPageController implements ErrorController {
|
||||
|
||||
/**
|
||||
* 解决 Whitelabel Error Page
|
||||
*/
|
||||
@RequestMapping("/error")
|
||||
public Result<Void> error(HttpServletRequest request) {
|
||||
Integer statusCode = (Integer) request.getAttribute("jakarta.servlet.error.status_code");
|
||||
HttpStatus httpStatus = HttpStatus.valueOf(statusCode);
|
||||
return Result.fail(httpStatus.value(), httpStatus.getReasonPhrase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
//package tech.easyflow.common.web.devlog;
|
||||
//
|
||||
//
|
||||
//import com.alibaba.fastjson2.JSON;
|
||||
//import com.alibaba.fastjson2.JSONWriter;
|
||||
//import com.alibaba.fastjson2.filter.PropertyFilter;
|
||||
//import com.mybatisflex.core.util.ClassUtil;
|
||||
//import com.mybatisflex.core.util.StringUtil;
|
||||
//import jakarta.servlet.http.HttpServletRequest;
|
||||
//import org.apache.ibatis.javassist.*;
|
||||
//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 org.springframework.context.annotation.Profile;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.context.request.RequestContextHolder;
|
||||
//import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
//import org.springframework.web.servlet.ModelAndView;
|
||||
//
|
||||
//import java.lang.reflect.Method;
|
||||
//import java.util.Enumeration;
|
||||
//import java.util.StringJoiner;
|
||||
//
|
||||
//@Aspect
|
||||
//@Component
|
||||
//@Profile({"dev", "test"})
|
||||
//public class DevLogAspect {
|
||||
//
|
||||
// private static final int maxOutputLengthOfParaValue = 512;
|
||||
// private static ClassPool classPool = ClassPool.getDefault();
|
||||
//
|
||||
// static {
|
||||
// classPool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) || execution(* tech.easyflow.common.web.controller.BaseCurdController.*(..))")
|
||||
// public void webLog() {
|
||||
// }
|
||||
//
|
||||
// @Around("webLog()")
|
||||
// public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
// HttpServletRequest request = attributes.getRequest();
|
||||
//
|
||||
// MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
|
||||
// Class<?> controllerClass = signature.getDeclaringType();
|
||||
// Method method = signature.getMethod();
|
||||
//
|
||||
// String url = request.getRequestURL().toString();
|
||||
// String param = getRequestParamsString(request);
|
||||
//
|
||||
// int lineNumber = getLineNumber(controllerClass, method);
|
||||
//
|
||||
//
|
||||
// long startTime = System.currentTimeMillis();
|
||||
// Object result = null;
|
||||
// try {
|
||||
// result = proceedingJoinPoint.proceed();
|
||||
// } finally {
|
||||
// String logInfo = "\n" +
|
||||
// "+========================================= Start ==========================================\n" +
|
||||
// "| Request : " + request.getMethod() + " " + url + "\n" +
|
||||
// "| Request Params : " + param + "\n" +
|
||||
// "| Request IP : " + request.getRemoteAddr() + "\n" +
|
||||
// "| Controller : " + signature.getDeclaringTypeName() + "." + "(" + controllerClass.getSimpleName() + ".java:" + lineNumber + ")" + "\n" +
|
||||
// "| Method : " + method.getName() + buildParamsString(method) + "\n" +
|
||||
// "| Response : " + getResponseText(result) + "\n" +
|
||||
// "| Elapsed Time : " + (System.currentTimeMillis() - startTime) + " ms" + "\n" +
|
||||
// "+========================================== End ===========================================\n";
|
||||
// System.out.println(logInfo);
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// private static String getResponseText(Object result) {
|
||||
// if (result instanceof ModelAndView && ((ModelAndView) result).isReference()) {
|
||||
// return ((ModelAndView) result).getViewName();
|
||||
// }
|
||||
//
|
||||
// String originalText;
|
||||
// if (result instanceof String) {
|
||||
// originalText = (String) result;
|
||||
// } else {
|
||||
// originalText = JSON.toJSONString(result);
|
||||
// }
|
||||
//
|
||||
// if (StringUtil.noText(originalText)) {
|
||||
// return "";
|
||||
// }
|
||||
//
|
||||
// originalText = originalText.replace("\n", "");
|
||||
//
|
||||
// if (originalText.length() > 100) {
|
||||
// return originalText.substring(0, 100) + "...";
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// // 使用PropertyFilter过滤掉timeout字段
|
||||
// PropertyFilter filter = (object, name, value) -> !"timeout".equals(name);
|
||||
//
|
||||
// String resultStr = JSON.toJSONString(result,
|
||||
// filter,
|
||||
// JSONWriter.Feature.WriteMapNullValue,
|
||||
// JSONWriter.Feature.IgnoreNonFieldGetter);
|
||||
// return resultStr;
|
||||
// } catch (Exception e) {
|
||||
// return "[Serialization Error: " + e.getMessage() + "]";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private String buildParamsString(Method method) {
|
||||
// StringJoiner joiner = new StringJoiner(", ", "(", ")");
|
||||
// for (Class<?> parameterType : method.getParameterTypes()) {
|
||||
// joiner.add(parameterType.getSimpleName());
|
||||
// }
|
||||
// return joiner.toString();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private int getLineNumber(Class<?> controllerClass, Method method) throws NotFoundException {
|
||||
// CtClass ctClass = classPool.get(ClassUtil.getUsefulClass(controllerClass).getName());
|
||||
// classPool.get(ClassUtil.getUsefulClass(controllerClass).getName());
|
||||
// String desc = DevLogUtil.getMethodDescWithoutName(method);
|
||||
// CtMethod ctMethod = ctClass.getMethod(method.getName(), desc);
|
||||
// return ctMethod.getMethodInfo().getLineNumber(0);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private String getRequestParamsString(HttpServletRequest request) {
|
||||
// StringBuilder sb = new StringBuilder();
|
||||
// Enumeration<String> e = request.getParameterNames();
|
||||
// if (e.hasMoreElements()) {
|
||||
// while (e.hasMoreElements()) {
|
||||
// String name = e.nextElement();
|
||||
// String[] values = request.getParameterValues(name);
|
||||
// if (values.length == 1) {
|
||||
// sb.append(name).append("=");
|
||||
// if (values[0] != null && values[0].length() > maxOutputLengthOfParaValue) {
|
||||
// sb.append(values[0], 0, maxOutputLengthOfParaValue).append("...");
|
||||
// } else {
|
||||
// sb.append(values[0]);
|
||||
// }
|
||||
// } else {
|
||||
// sb.append(name).append("[]={");
|
||||
// for (int i = 0; i < values.length; i++) {
|
||||
// if (i > 0) {
|
||||
// sb.append(",");
|
||||
// }
|
||||
// sb.append(values[i]);
|
||||
// }
|
||||
// sb.append("}");
|
||||
// }
|
||||
// sb.append(" ");
|
||||
// }
|
||||
// }
|
||||
// return sb.toString();
|
||||
// }
|
||||
//
|
||||
//}
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package tech.easyflow.common.web.devlog;
|
||||
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* 参考 https://github.com/apache/dubbo/blob/master/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectUtils.java
|
||||
*/
|
||||
public final class DevLogUtil {
|
||||
|
||||
/**
|
||||
* void(V).
|
||||
*/
|
||||
public static final char JVM_VOID = 'V';
|
||||
|
||||
/**
|
||||
* boolean(Z).
|
||||
*/
|
||||
public static final char JVM_BOOLEAN = 'Z';
|
||||
|
||||
/**
|
||||
* byte(B).
|
||||
*/
|
||||
public static final char JVM_BYTE = 'B';
|
||||
|
||||
/**
|
||||
* char(C).
|
||||
*/
|
||||
public static final char JVM_CHAR = 'C';
|
||||
|
||||
/**
|
||||
* double(D).
|
||||
*/
|
||||
public static final char JVM_DOUBLE = 'D';
|
||||
|
||||
/**
|
||||
* float(F).
|
||||
*/
|
||||
public static final char JVM_FLOAT = 'F';
|
||||
|
||||
/**
|
||||
* int(I).
|
||||
*/
|
||||
public static final char JVM_INT = 'I';
|
||||
|
||||
/**
|
||||
* long(J).
|
||||
*/
|
||||
public static final char JVM_LONG = 'J';
|
||||
|
||||
/**
|
||||
* short(S).
|
||||
*/
|
||||
public static final char JVM_SHORT = 'S';
|
||||
|
||||
|
||||
/**
|
||||
* get class desc.
|
||||
* boolean[].class => "[Z"
|
||||
* Object.class => "Ljava/lang/Object;"
|
||||
*
|
||||
* @param c class.
|
||||
* @return desc.
|
||||
*/
|
||||
public static String getDesc(Class<?> c) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
|
||||
while (c.isArray()) {
|
||||
ret.append('[');
|
||||
c = c.getComponentType();
|
||||
}
|
||||
|
||||
if (c.isPrimitive()) {
|
||||
String t = c.getName();
|
||||
if ("void".equals(t)) {
|
||||
ret.append(JVM_VOID);
|
||||
} else if ("boolean".equals(t)) {
|
||||
ret.append(JVM_BOOLEAN);
|
||||
} else if ("byte".equals(t)) {
|
||||
ret.append(JVM_BYTE);
|
||||
} else if ("char".equals(t)) {
|
||||
ret.append(JVM_CHAR);
|
||||
} else if ("double".equals(t)) {
|
||||
ret.append(JVM_DOUBLE);
|
||||
} else if ("float".equals(t)) {
|
||||
ret.append(JVM_FLOAT);
|
||||
} else if ("int".equals(t)) {
|
||||
ret.append(JVM_INT);
|
||||
} else if ("long".equals(t)) {
|
||||
ret.append(JVM_LONG);
|
||||
} else if ("short".equals(t)) {
|
||||
ret.append(JVM_SHORT);
|
||||
}
|
||||
} else {
|
||||
ret.append('L');
|
||||
ret.append(c.getName().replace('.', '/'));
|
||||
ret.append(';');
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get method desc.
|
||||
* "(I)I", "()V", "(Ljava/lang/String;Z)V"
|
||||
*
|
||||
* @param m method.
|
||||
* @return desc.
|
||||
*/
|
||||
public static String getMethodDescWithoutName(Method m) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.append('(');
|
||||
Class<?>[] parameterTypes = m.getParameterTypes();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
ret.append(getDesc(parameterTypes[i]));
|
||||
}
|
||||
ret.append(')').append(getDesc(m.getReturnType()));
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package tech.easyflow.common.web.error;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
public class GlobalErrorResolver implements HandlerExceptionResolver {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GlobalErrorResolver.class);
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Result<?> error;
|
||||
if (ex instanceof MissingServletRequestParameterException) {
|
||||
error = Result.fail(1, ((MissingServletRequestParameterException) ex).getParameterName() + " 不能为空.");
|
||||
} else if (ex instanceof NotLoginException) {
|
||||
response.setStatus(401);
|
||||
error = Result.fail(401, "请登录");
|
||||
} else if (ex instanceof NotPermissionException || ex instanceof NotRoleException) {
|
||||
error = Result.fail(4010, "无权操作");
|
||||
} else if (ex instanceof ConstraintViolationException) {
|
||||
error = Result.fail(400, ex.getMessage());
|
||||
} else if (ex instanceof BusinessException) {
|
||||
error = Result.fail(1, ex.getMessage());
|
||||
} else {
|
||||
LOG.error(ex.toString(), ex);
|
||||
error = Result.fail(1, "错误信息:" + ex.getMessage());
|
||||
}
|
||||
JSONObject object = JSON.parseObject(JSON.toJSONString(error));
|
||||
return new ModelAndView(new JakartaJsonView())
|
||||
.addAllObjects(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package tech.easyflow.common.web.error;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
public class JakartaJsonView implements View {
|
||||
@Override
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
if (model != null) {
|
||||
String jsonString = JSON.toJSONString(model);
|
||||
try (ServletOutputStream out = response.getOutputStream()) {
|
||||
out.write(jsonString.getBytes(StandardCharsets.UTF_8));
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package tech.easyflow.common.web.exceptions;
|
||||
|
||||
/**
|
||||
* 业务报错
|
||||
*/
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
public BusinessException() {
|
||||
}
|
||||
|
||||
public BusinessException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package tech.easyflow.common.web.exceptions;
|
||||
|
||||
/**
|
||||
* 参数报错
|
||||
*/
|
||||
public class ParamException extends RuntimeException {
|
||||
|
||||
public ParamException() {
|
||||
}
|
||||
|
||||
public ParamException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package tech.easyflow.common.web.exceptions;
|
||||
|
||||
/**
|
||||
* 程序报错
|
||||
*/
|
||||
public class ProgramException extends RuntimeException {
|
||||
|
||||
public ProgramException() {
|
||||
}
|
||||
|
||||
public ProgramException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package tech.easyflow.common.web.jsonbody;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.PARAMETER})
|
||||
public @interface JsonBody {
|
||||
|
||||
/**
|
||||
* 自定义前缀
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 是否跳过转换异常
|
||||
*/
|
||||
boolean skipConvertError() default true;
|
||||
|
||||
|
||||
boolean required() default false;
|
||||
|
||||
|
||||
String defaultValue() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package tech.easyflow.common.web.jsonbody;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import tech.easyflow.common.util.RequestUtil;
|
||||
import com.mybatisflex.core.util.ConvertUtil;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
public class JsonBodyArgumentResolver implements HandlerMethodArgumentResolver, SmartInitializingSingleton {
|
||||
|
||||
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
|
||||
|
||||
|
||||
public JsonBodyArgumentResolver(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
|
||||
this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
List<HandlerMethodArgumentResolver> argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
|
||||
ArrayList<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(Objects.requireNonNull(argumentResolvers));
|
||||
resolvers.add(0, this);
|
||||
requestMappingHandlerAdapter.setArgumentResolvers(resolvers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.hasParameterAnnotation(JsonBody.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer
|
||||
, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
|
||||
|
||||
JsonBody jsonBody = parameter.getParameterAnnotation(JsonBody.class);
|
||||
Class<?> paraClass = parameter.getParameterType();
|
||||
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object jsonObjectOrArray = RequestUtil.readJsonObjectOrArray(request);
|
||||
|
||||
Object result = null;
|
||||
Type paraType = parameter.getGenericParameterType();
|
||||
if (paraType instanceof TypeVariable) {
|
||||
Type variableRawType = JsonBodyParser.getTypeVariableRawType(
|
||||
parameter.getContainingClass(), ((TypeVariable<?>) paraType));
|
||||
if (variableRawType != null) {
|
||||
paraClass = (Class<?>) variableRawType;
|
||||
paraType = variableRawType;
|
||||
}
|
||||
}
|
||||
try {
|
||||
result = JsonBodyParser.parseJsonBody(jsonObjectOrArray, paraClass, paraType, jsonBody.value());
|
||||
} catch (Exception e) {
|
||||
if (jsonBody.skipConvertError()) {
|
||||
//ignore
|
||||
} else {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null && StringUtil.hasText(jsonBody.defaultValue())) {
|
||||
result = ConvertUtil.convert(jsonBody.defaultValue(), paraClass);
|
||||
}
|
||||
|
||||
if ((result == null) && jsonBody.required()) {
|
||||
throw new IllegalArgumentException(jsonBody.value() + " must not be null or blank");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package tech.easyflow.common.web.jsonbody;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.util.ConvertUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class JsonBodyParser {
|
||||
|
||||
private static final String startOfArray = "[";
|
||||
private static final String endOfArray = "]";
|
||||
|
||||
|
||||
/**
|
||||
* 获取方法里的泛型参数 T 对于的真实的 Class 类
|
||||
*
|
||||
* @param defClass
|
||||
* @param typeVariable
|
||||
* @return
|
||||
*/
|
||||
public static Type getTypeVariableRawType(Class<?> defClass, TypeVariable<?> typeVariable) {
|
||||
Type type = defClass.getGenericSuperclass();
|
||||
if (type instanceof ParameterizedType) {
|
||||
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
|
||||
if (typeArguments.length == 1) {
|
||||
return typeArguments[0];
|
||||
} else if (typeArguments.length > 1) {
|
||||
TypeVariable<?>[] typeVariables = typeVariable.getGenericDeclaration().getTypeParameters();
|
||||
for (int i = 0; i < typeVariables.length; i++) {
|
||||
if (typeVariable.getName().equals(typeVariables[i].getName())) {
|
||||
return typeArguments[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Object parseJsonBody(Object jsonObjectOrArray, Class<?> paraClass, Type paraType, String jsonKey) throws InstantiationException, IllegalAccessException {
|
||||
if (jsonObjectOrArray == null) {
|
||||
return paraClass.isPrimitive() ? getPrimitiveDefaultValue(paraClass) : null;
|
||||
}
|
||||
if (Collection.class.isAssignableFrom(paraClass) || paraClass.isArray()) {
|
||||
return parseArray(jsonObjectOrArray, paraClass, paraType, jsonKey);
|
||||
} else {
|
||||
return parseObject((JSONObject) jsonObjectOrArray, paraClass, paraType, jsonKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Object getPrimitiveDefaultValue(Class<?> paraClass) {
|
||||
if (paraClass == int.class || paraClass == long.class || paraClass == float.class || paraClass == double.class) {
|
||||
return 0;
|
||||
} else if (paraClass == boolean.class) {
|
||||
return Boolean.FALSE;
|
||||
} else if (paraClass == short.class) {
|
||||
return (short) 0;
|
||||
} else if (paraClass == byte.class) {
|
||||
return (byte) 0;
|
||||
} else if (paraClass == char.class) {
|
||||
return '\u0000';
|
||||
} else {
|
||||
//不存在这种类型
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Object parseObject(JSONObject rawObject, Class<?> paraClass, Type paraType, String jsonKey) throws IllegalAccessException, InstantiationException {
|
||||
if (!StringUtils.hasText(jsonKey)) {
|
||||
return toJavaObject(rawObject, paraClass, paraType);
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
String[] keys = jsonKey.split("\\.");
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (rawObject != null && !rawObject.isEmpty()) {
|
||||
String key = keys[i].trim();
|
||||
if (StringUtils.hasText(key)) {
|
||||
//the last
|
||||
if (i == keys.length - 1) {
|
||||
if (key.endsWith(endOfArray) && key.contains(startOfArray)) {
|
||||
String realKey = key.substring(0, key.indexOf(startOfArray));
|
||||
JSONArray jarray = rawObject.getJSONArray(realKey.trim());
|
||||
if (jarray != null && jarray.size() > 0) {
|
||||
String arrayString = key.substring(key.indexOf(startOfArray) + 1, key.length() - 1);
|
||||
int arrayIndex = StringUtils.hasText(arrayString) ? Integer.parseInt(arrayString.trim()) : 0;
|
||||
result = arrayIndex >= jarray.size() ? null : jarray.get(arrayIndex);
|
||||
}
|
||||
} else {
|
||||
result = rawObject.get(key);
|
||||
}
|
||||
}
|
||||
//not last
|
||||
else {
|
||||
rawObject = getJSONObjectByKey(rawObject, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null || "".equals(result)) {
|
||||
return paraClass.isPrimitive() ? getPrimitiveDefaultValue(paraClass) : null;
|
||||
}
|
||||
|
||||
if (paraClass == String.class && paraClass == paraType) {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
// JSONObject 类型
|
||||
if (result instanceof JSONObject) {
|
||||
return toJavaObject((JSONObject) result, paraClass, paraType);
|
||||
}
|
||||
|
||||
return ConvertUtil.convert(result, paraClass);
|
||||
}
|
||||
|
||||
|
||||
private static Object parseArray(Object rawJsonObjectOrArray, Class<?> typeClass, Type type, String jsonKey) {
|
||||
JSONArray jsonArray = null;
|
||||
if (!StringUtils.hasText(jsonKey)) {
|
||||
if (rawJsonObjectOrArray instanceof JSONArray) {
|
||||
jsonArray = (JSONArray) rawJsonObjectOrArray;
|
||||
}
|
||||
} else {
|
||||
if (rawJsonObjectOrArray instanceof JSONObject) {
|
||||
JSONObject rawObject = (JSONObject) rawJsonObjectOrArray;
|
||||
String[] keys = jsonKey.split("\\.");
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (rawObject == null || rawObject.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
String key = keys[i].trim();
|
||||
if (StringUtils.hasText(key)) {
|
||||
//the last
|
||||
if (i == keys.length - 1) {
|
||||
if (key.endsWith(endOfArray) && key.contains(startOfArray)) {
|
||||
String realKey = key.substring(0, key.indexOf(startOfArray));
|
||||
JSONArray jarray = rawObject.getJSONArray(realKey.trim());
|
||||
if (jarray == null || jarray.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String subKey = key.substring(key.indexOf(startOfArray) + 1, key.length() - 1).trim();
|
||||
if (!StringUtils.hasText(subKey)) {
|
||||
throw new IllegalStateException("Sub key can not empty: " + jsonKey);
|
||||
}
|
||||
|
||||
JSONArray newJsonArray = new JSONArray();
|
||||
for (int j = 0; j < jarray.size(); j++) {
|
||||
Object value = jarray.getJSONObject(j).get(subKey);
|
||||
if (value != null) {
|
||||
newJsonArray.add(value);
|
||||
}
|
||||
}
|
||||
jsonArray = newJsonArray;
|
||||
} else {
|
||||
jsonArray = rawObject.getJSONArray(key);
|
||||
}
|
||||
}
|
||||
//not last
|
||||
else {
|
||||
rawObject = getJSONObjectByKey(rawObject, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonArray == null || jsonArray.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//非泛型 set
|
||||
if ((typeClass == Set.class || typeClass == HashSet.class) && typeClass == type) {
|
||||
return new HashSet<>(jsonArray);
|
||||
}
|
||||
|
||||
//直接获取 JsonArray
|
||||
if (typeClass == type && typeClass == JSONArray.class) {
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
return jsonArray.toJavaObject(type);
|
||||
}
|
||||
|
||||
|
||||
private static JSONObject getJSONObjectByKey(JSONObject jsonObject, String key) {
|
||||
if (key.endsWith(endOfArray) && key.contains(startOfArray)) {
|
||||
String realKey = key.substring(0, key.indexOf(startOfArray));
|
||||
JSONArray jarray = jsonObject.getJSONArray(realKey.trim());
|
||||
if (jarray == null || jarray.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String arrayString = key.substring(key.indexOf(startOfArray) + 1, key.length() - 1);
|
||||
int arrayIndex = StringUtils.hasText(arrayString) ? Integer.parseInt(arrayString.trim()) : 0;
|
||||
return arrayIndex >= jarray.size() ? null : jarray.getJSONObject(arrayIndex);
|
||||
} else {
|
||||
return jsonObject.getJSONObject(key);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object toJavaObject(JSONObject rawObject, Class<?> paraClass, Type paraType) throws IllegalAccessException, InstantiationException {
|
||||
if (rawObject.isEmpty()) {
|
||||
return paraClass.isPrimitive() ? getPrimitiveDefaultValue(paraClass) : null;
|
||||
}
|
||||
|
||||
//非泛型 的 map
|
||||
if ((paraClass == Map.class || paraClass == JSONObject.class) && paraClass == paraType) {
|
||||
return rawObject;
|
||||
}
|
||||
|
||||
//非泛型 的 map
|
||||
if (Map.class.isAssignableFrom(paraClass) && paraClass == paraType && canNewInstance(paraClass)) {
|
||||
Map map = (Map) paraClass.newInstance();
|
||||
map.putAll(rawObject);
|
||||
return map;
|
||||
}
|
||||
|
||||
return rawObject.toJavaObject(paraType);
|
||||
}
|
||||
|
||||
|
||||
private static boolean canNewInstance(Class<?> clazz) {
|
||||
int modifiers = clazz.getModifiers();
|
||||
return !Modifier.isAbstract(modifiers) && !Modifier.isInterface(modifiers);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user