Commit d7a480a1 by yuwei

项目初始化

parent c45748a3
package cn.datax.common.utils; package cn.datax.common.utils;
import cn.datax.common.core.DataUser; import cn.datax.common.core.DataUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Optional;
public class SecurityUtil { public class SecurityUtil {
/** /**
...@@ -13,11 +12,14 @@ public class SecurityUtil { ...@@ -13,11 +12,14 @@ public class SecurityUtil {
* @return user * @return user
*/ */
public static DataUser getDataUser() { public static DataUser getDataUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
if (principal instanceof DataUser) { if (principal instanceof DataUser) {
DataUser user = (DataUser) principal; DataUser user = (DataUser) principal;
return user; return user;
} }
}
return null; return null;
} }
...@@ -27,9 +29,8 @@ public class SecurityUtil { ...@@ -27,9 +29,8 @@ public class SecurityUtil {
* @return id * @return id
*/ */
public static String getUserId() { public static String getUserId() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); DataUser user = getDataUser();
if (principal instanceof DataUser) { if (user != null){
DataUser user = (DataUser) principal;
return user.getId(); return user.getId();
} }
return null; return null;
...@@ -41,9 +42,8 @@ public class SecurityUtil { ...@@ -41,9 +42,8 @@ public class SecurityUtil {
* @return id * @return id
*/ */
public static String getUserDeptId() { public static String getUserDeptId() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); DataUser user = getDataUser();
if (principal instanceof DataUser) { if (user != null){
DataUser user = (DataUser) principal;
return user.getDept(); return user.getDept();
} }
return null; return null;
...@@ -55,9 +55,8 @@ public class SecurityUtil { ...@@ -55,9 +55,8 @@ public class SecurityUtil {
* @return username * @return username
*/ */
public static String getUserName() { public static String getUserName() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); DataUser user = getDataUser();
if (principal instanceof DataUser) { if (user != null){
DataUser user = (DataUser) principal;
return user.getUsername(); return user.getUsername();
} }
return null; return null;
......
...@@ -24,10 +24,5 @@ ...@@ -24,10 +24,5 @@
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
package cn.datax.common.redis.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisCacheAop {
// 缓存名
String cacheName() default "";
// 过期时间(秒) time要大于0 如果time小于等于0 将设置无限期
long expire() default -1;
// 缓存反序列化获取的对象
Class clazz() default Object.class;
// 序列化后的对象是否是数组 比如 List<Object>
boolean isArray() default false;
}
package cn.datax.common.redis.aspectj;
import cn.datax.common.redis.annotation.RedisCacheAop;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Aspect
@Slf4j
public class RedisCacheAspect {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private ObjectMapper objectMapper;
/**
* 分隔符 生成key 格式为 类全类名|方法名|参数所属类全类名
*/
private static final String DELIMITER = ":";
/**
* Service层切点 使用到了我们定义的 RedisCacheAspect 作为切点表达式。
* 而且我们可以看出此表达式基于 annotation。
* 并且用于内建属性为查询的方法之上
*/
@Pointcut("@annotation(cn.datax.common.redis.annotation.RedisCacheAop)")
public void redisCacheAspect() {
}
/**
* Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
* <p>
* 注意:当核心业务抛异常后,立即退出,转向AfterAdvice 执行完AfterAdvice,再转到ThrowingAdvice
*/
@Around(value = "redisCacheAspect()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// 得到类名、方法名和参数
String clazzName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
// 根据类名、方法名和参数生成Key
log.info("key参数: " + clazzName + "." + methodName);
String key = getKey(clazzName, methodName, args);
log.info("生成key: " + key);
// 得到被代理的方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String cacheName = method.getAnnotation(RedisCacheAop.class).cacheName();
long expire = method.getAnnotation(RedisCacheAop.class).expire();
Class objectType = method.getAnnotation(RedisCacheAop.class).clazz();
boolean isArray = method.getAnnotation(RedisCacheAop.class).isArray();
// 检查Redis中是否有缓存
String value = (String) redisTemplate.opsForValue().get(key + DELIMITER + cacheName);
// result是方法的最终返回结果
Object result = null;
try {
if (null == value) {
log.info("缓存未命中");
// 调用数据库查询方法
result = joinPoint.proceed(args);
// 结果放入缓存
if (expire > 0) {
redisTemplate.opsForValue().set(key + DELIMITER + cacheName, objectMapper.writeValueAsString(result), expire, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().set(key + DELIMITER + cacheName, objectMapper.writeValueAsString(result));
}
} else {
/**
* 可以直接针对mapper进行缓存,如果mapper查询返回的List<Objec> 需要isArray 为true 否则转换异常
*/
if (isArray){
JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, objectType);
return objectMapper.readValue(value, javaType);
}else {
return objectMapper.readValue(value, objectType);
}
}
} catch (Throwable e) {
log.error("程序异常", e.getMessage());
throw e;
}
return result;
}
/**
* 根据类名、方法名和参数生成Key
* @param clazzName
* @param methodName
* @param args
* @return key格式:全类名:方法名:参数类型
*/
private String getKey(String clazzName, String methodName, Object[] args) {
StringBuilder key = new StringBuilder(clazzName);
key.append(DELIMITER);
key.append(methodName);
key.append(DELIMITER);
key.append(Arrays.stream(args).map(x -> x.toString()).collect(Collectors.joining(DELIMITER)));
return key.toString();
}
}
package cn.datax.common.redis.config;
import cn.datax.common.redis.service.impl.RedissonLocker;
import cn.datax.common.redis.utils.LockUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties({RedisProperties.class})
@AllArgsConstructor
public class RedissonConfig {
private RedisProperties redisProperties;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
if(redisProperties.getCluster() != null){
// 集群模式配置
config.useClusterServers()
.addNodeAddress(redisProperties.getCluster().getNodes().stream().toArray(String[]::new))
.setPassword(StringUtils.isBlank(redisProperties.getPassword()) ? null : redisProperties.getPassword());
}else if(redisProperties.getSentinel() != null){
//添加哨兵配置
config.useMasterSlaveServers().setMasterAddress(redisProperties.getSentinel().getMaster())
.addSlaveAddress(redisProperties.getSentinel().getNodes().stream().toArray(String[]::new))
.setPassword(StringUtils.isBlank(redisProperties.getPassword()) ? null : redisProperties.getPassword());
}else {
//单节点
config.useSingleServer().setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort())
.setPassword(StringUtils.isBlank(redisProperties.getPassword()) ? null : redisProperties.getPassword());
}
return Redisson.create(config);
}
@Bean
public RedissonLocker redissonLocker(RedissonClient redissonClient) {
RedissonLocker locker = new RedissonLocker(redissonClient);
// 设置LockUtil的锁处理对象
LockUtil.setLocker(locker);
return locker;
}
}
package cn.datax.common.redis.service;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;
/**
* 锁接口
*/
public interface Locker {
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。
*
* @param lockKey
*/
RLock lock(String lockKey);
/**
* 释放锁
*
* @param lockKey
*/
RLock unlock(String lockKey);
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。如果获取到锁后,执行结束后解锁或达到超时时间后会自动释放锁
*
* @param lockKey
* @param timeout
*/
RLock lock(String lockKey, int timeout);
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。如果获取到锁后,执行结束后解锁或达到超时时间后会自动释放锁
*
* @param lockKey
* @param unit
* @param timeout
*/
RLock lock(String lockKey, TimeUnit unit, int timeout);
/**
* 尝试获取锁,获取到立即返回true,未获取到立即返回false
*
* @param lockKey
* @return
*/
boolean tryLock(String lockKey);
/**
* 尝试获取锁,在等待时间内获取到锁则返回true,否则返回false,如果获取到锁,则要么执行完后程序释放锁,
* 要么在给定的超时时间leaseTime后释放锁
*
* @param lockKey
* @param waitTime
* @param leaseTime
* @param unit
* @return
*/
boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit);
/**
* 锁是否被任意一个线程锁持有
*
* @param lockKey
* @return
*/
boolean isLocked(String lockKey);
}
package cn.datax.common.redis.service.impl;
import cn.datax.common.redis.service.Locker;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
/**
* 基于Redisson的分布式锁
*/
public class RedissonLocker implements Locker {
private RedissonClient redissonClient;
public RedissonLocker(RedissonClient redissonClient) {
super();
this.redissonClient = redissonClient;
}
public void setRedissonClient(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public RLock lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
@Override
public RLock unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
return lock;
}
@Override
public RLock lock(String lockKey, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
@Override
public RLock lock(String lockKey, TimeUnit unit, int timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
@Override
public boolean tryLock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
return lock.tryLock();
}
@Override
public boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
}
@Override
public boolean isLocked(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
return lock.isLocked();
}
}
package cn.datax.common.redis.utils;
import cn.datax.common.redis.service.Locker;
import java.util.concurrent.TimeUnit;
/**
* redis分布式锁工具类
*/
public final class LockUtil {
private static Locker locker;
/**
* 设置工具类使用的locker
*
* @param locker
*/
public static void setLocker(Locker locker) {
LockUtil.locker = locker;
}
/**
* 获取锁
*
* @param lockKey
*/
public static void lock(String lockKey) {
locker.lock(lockKey);
}
/**
* 释放锁
*
* @param lockKey
*/
public static void unlock(String lockKey) {
locker.unlock(lockKey);
}
/**
* 获取锁,超时释放
*
* @param lockKey
* @param timeout
*/
public static void lock(String lockKey, int timeout) {
locker.lock(lockKey, timeout);
}
/**
* 获取锁,超时释放,指定时间单位
*
* @param lockKey
* @param unit
* @param timeout
*/
public static void lock(String lockKey, TimeUnit unit, int timeout) {
locker.lock(lockKey, unit, timeout);
}
/**
* 尝试获取锁,获取到立即返回true,获取失败立即返回false
*
* @param lockKey
* @return
*/
public static boolean tryLock(String lockKey) {
return locker.tryLock(lockKey);
}
/**
* 尝试获取锁,在给定的waitTime时间内尝试,获取到返回true,获取失败返回false,获取到后再给定的leaseTime时间超时释放
*
* @param lockKey
* @param waitTime
* @param leaseTime
* @param unit
* @return
* @throws InterruptedException
*/
public static boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit) {
return locker.tryLock(lockKey, waitTime, leaseTime, unit);
}
/**
* 锁释放被任意一个线程持有
*
* @param lockKey
* @return
*/
public static boolean isLocked(String lockKey) {
return locker.isLocked(lockKey);
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.redis.config.RedisConfig,\ cn.datax.common.redis.config.RedisConfig
cn.datax.common.redis.aspectj.RedisCacheAspect,\
cn.datax.common.redis.config.RedissonConfig
...@@ -30,4 +30,7 @@ public class ResParam implements Serializable { ...@@ -30,4 +30,7 @@ public class ResParam implements Serializable {
@ApiModelProperty(value = "示例值") @ApiModelProperty(value = "示例值")
@NotBlank(message = "示例值不能为空", groups = {ValidationGroups.Insert.class, ValidationGroups.Update.class}) @NotBlank(message = "示例值不能为空", groups = {ValidationGroups.Insert.class, ValidationGroups.Update.class})
private String exampleValue; private String exampleValue;
@ApiModelProperty(value = "字段别名")
private String fieldAliasName;
} }
package cn.datax.service.data.market.mapping.config; package cn.datax.service.data.market.mapping.config;
import cn.datax.common.core.DataConstant; import cn.datax.common.core.DataConstant;
import cn.datax.common.core.R;
import cn.datax.common.database.core.PageResult;
import cn.datax.common.utils.IPUtil; import cn.datax.common.utils.IPUtil;
import cn.datax.common.utils.MD5Util; import cn.datax.common.utils.MD5Util;
import cn.datax.common.utils.RequestHolder; import cn.datax.common.utils.RequestHolder;
import cn.datax.service.data.market.api.dto.ApiLogDto; import cn.datax.service.data.market.api.dto.ApiLogDto;
import cn.datax.service.data.market.mapping.async.AsyncTask; import cn.datax.service.data.market.mapping.async.AsyncTask;
import cn.hutool.core.map.MapUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
...@@ -18,6 +23,8 @@ import org.springframework.stereotype.Component; ...@@ -18,6 +23,8 @@ import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@Slf4j @Slf4j
@Aspect @Aspect
...@@ -40,10 +47,14 @@ public class ApiLogAspect { ...@@ -40,10 +47,14 @@ public class ApiLogAspect {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
System.out.println("endTime:" + endTime); ApiLogDto log = getLog();
// ApiLogDto log = getLog(); log.setTime(endTime - startTime);
// log.setTime(endTime - startTime); if (result instanceof R) {
// handleLog(joinPoint, log); if (((R) result).getData() instanceof PageResult) {
log.setCallerSize(((PageResult) ((R) result).getData()).getData().size());
}
}
handleLog(joinPoint, log);
return result; return result;
} }
...@@ -56,10 +67,10 @@ public class ApiLogAspect { ...@@ -56,10 +67,10 @@ public class ApiLogAspect {
@AfterThrowing(value = "logPointCut()", throwing = "e") @AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) { public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
log.error("出错{}", e.getMessage()); log.error("出错{}", e.getMessage());
// ApiLogDto log = getLog(); ApiLogDto log = getLog();
// log.setStatus(DataConstant.EnableState.DISABLE.getKey()); log.setStatus(DataConstant.EnableState.DISABLE.getKey());
// log.setMsg(e.getMessage()); log.setMsg(e.getMessage());
// handleLog(joinPoint, log); handleLog(joinPoint, log);
} }
private ApiLogDto getLog() { private ApiLogDto getLog() {
...@@ -67,9 +78,8 @@ public class ApiLogAspect { ...@@ -67,9 +78,8 @@ public class ApiLogAspect {
HttpServletRequest request = RequestHolder.getHttpServletRequest(); HttpServletRequest request = RequestHolder.getHttpServletRequest();
String apiKey = request.getHeader("api_key"); String apiKey = request.getHeader("api_key");
String secretKey = request.getHeader("secret_key"); String secretKey = request.getHeader("secret_key");
MD5Util mt = null;
try { try {
mt = MD5Util.getInstance(); MD5Util mt = MD5Util.getInstance();
String apiId = mt.decode(apiKey); String apiId = mt.decode(apiKey);
String userId = mt.decode(secretKey); String userId = mt.decode(secretKey);
log.setCallerId(userId); log.setCallerId(userId);
...@@ -85,6 +95,22 @@ public class ApiLogAspect { ...@@ -85,6 +95,22 @@ public class ApiLogAspect {
} }
protected void handleLog(final JoinPoint joinPoint, ApiLogDto log) { protected void handleLog(final JoinPoint joinPoint, ApiLogDto log) {
// asyncTask.doTask(log); Map<String, Object> pathVariables = (Map<String, Object>) joinPoint.getArgs()[2];
Map<String, Object> requestParams = (Map<String, Object>) joinPoint.getArgs()[3];
Map<String, Object> requestBodys = (Map<String, Object>) joinPoint.getArgs()[4];
Map<String, Object> params = new HashMap<>();
if (MapUtil.isNotEmpty(pathVariables)) {
params.putAll(pathVariables);
}
if (MapUtil.isNotEmpty(requestParams)) {
params.putAll(requestParams);
}
if (MapUtil.isNotEmpty(requestBodys)) {
params.putAll(requestBodys);
}
try {
log.setCallerParams(new ObjectMapper().writeValueAsString(params));
} catch (JsonProcessingException e) {}
asyncTask.doTask(log);
} }
} }
package cn.datax.service.data.market.mapping.config; package cn.datax.service.data.market.mapping.config;
import cn.datax.service.data.market.mapping.async.AsyncTask;
import cn.datax.service.data.market.mapping.handler.MappingHandlerMapping; import cn.datax.service.data.market.mapping.handler.MappingHandlerMapping;
import cn.datax.service.data.market.mapping.handler.RequestHandler; import cn.datax.service.data.market.mapping.handler.RequestHandler;
import cn.datax.service.data.market.mapping.handler.RequestInterceptor; import cn.datax.service.data.market.mapping.handler.RequestInterceptor;
...@@ -18,19 +17,17 @@ public class ApiMappingConfig { ...@@ -18,19 +17,17 @@ public class ApiMappingConfig {
public MappingHandlerMapping mappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping, public MappingHandlerMapping mappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping,
ApiMappingEngine apiMappingEngine, ApiMappingEngine apiMappingEngine,
RedisTemplate redisTemplate, RedisTemplate redisTemplate,
ObjectMapper objectMapper, ObjectMapper objectMapper) {
AsyncTask asyncTask) {
MappingHandlerMapping mappingHandlerMapping = new MappingHandlerMapping(); MappingHandlerMapping mappingHandlerMapping = new MappingHandlerMapping();
mappingHandlerMapping.setHandler(requestHandler(apiMappingEngine, redisTemplate, objectMapper, asyncTask)); mappingHandlerMapping.setHandler(requestHandler(apiMappingEngine, redisTemplate, objectMapper));
mappingHandlerMapping.setRequestMappingHandlerMapping(requestMappingHandlerMapping); mappingHandlerMapping.setRequestMappingHandlerMapping(requestMappingHandlerMapping);
return mappingHandlerMapping; return mappingHandlerMapping;
} }
@Bean @Bean
public RequestHandler requestHandler(ApiMappingEngine apiMappingEngine, RedisTemplate redisTemplate, ObjectMapper objectMapper, AsyncTask asyncTask) { public RequestHandler requestHandler(ApiMappingEngine apiMappingEngine, RedisTemplate redisTemplate, ObjectMapper objectMapper) {
RequestHandler handler = new RequestHandler(); RequestHandler handler = new RequestHandler();
handler.setApiMappingEngine(apiMappingEngine); handler.setApiMappingEngine(apiMappingEngine);
handler.setAsyncTask(asyncTask);
handler.setObjectMapper(objectMapper); handler.setObjectMapper(objectMapper);
handler.setRequestInterceptor(new RequestInterceptor(redisTemplate)); handler.setRequestInterceptor(new RequestInterceptor(redisTemplate));
return handler; return handler;
......
package cn.datax.service.data.market.mapping.handler; package cn.datax.service.data.market.mapping.handler;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.R; import cn.datax.common.core.R;
import cn.datax.common.database.core.PageResult; import cn.datax.common.database.core.PageResult;
import cn.datax.common.utils.ThrowableUtil;
import cn.datax.service.data.market.api.dto.ApiLogDto;
import cn.datax.service.data.market.api.entity.DataApiEntity; import cn.datax.service.data.market.api.entity.DataApiEntity;
import cn.datax.service.data.market.mapping.async.AsyncTask;
import cn.datax.service.data.market.mapping.service.impl.ApiMappingEngine; import cn.datax.service.data.market.mapping.service.impl.ApiMappingEngine;
import cn.datax.service.data.market.mapping.utils.ThreadUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
...@@ -31,8 +27,6 @@ public class RequestHandler { ...@@ -31,8 +27,6 @@ public class RequestHandler {
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
private AsyncTask asyncTask;
public void setRequestInterceptor(RequestInterceptor requestInterceptor) { public void setRequestInterceptor(RequestInterceptor requestInterceptor) {
this.requestInterceptor = requestInterceptor; this.requestInterceptor = requestInterceptor;
} }
...@@ -45,17 +39,12 @@ public class RequestHandler { ...@@ -45,17 +39,12 @@ public class RequestHandler {
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
} }
public void setAsyncTask(AsyncTask asyncTask) { @SneakyThrows
this.asyncTask = asyncTask;
}
@ResponseBody @ResponseBody
public Object invoke(HttpServletRequest request, HttpServletResponse response, public Object invoke(HttpServletRequest request, HttpServletResponse response,
@PathVariable(required = false) Map<String, Object> pathVariables, @PathVariable(required = false) Map<String, Object> pathVariables,
@RequestParam(required = false) Map<String, Object> requestParams, @RequestParam(required = false) Map<String, Object> requestParams,
@RequestBody(required = false) Map<String, Object> requestBodys) { @RequestBody(required = false) Map<String, Object> requestBodys) {
try {
long start = System.currentTimeMillis();
DataApiEntity api; DataApiEntity api;
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
if (MapUtil.isNotEmpty(pathVariables)) { if (MapUtil.isNotEmpty(pathVariables)) {
...@@ -71,31 +60,13 @@ public class RequestHandler { ...@@ -71,31 +60,13 @@ public class RequestHandler {
params.putAll(requestBodys); params.putAll(requestBodys);
} }
api = MappingHandlerMapping.getMappingApiInfo(request); api = MappingHandlerMapping.getMappingApiInfo(request);
// 序列化出错 // 序列化
api = objectMapper.readValue(objectMapper.writeValueAsString(api), DataApiEntity.class); api = objectMapper.readValue(objectMapper.writeValueAsString(api), DataApiEntity.class);
// 执行前置拦截器 // 执行前置拦截器
Object obj = requestInterceptor.preHandle(request, response, api, params); requestInterceptor.preHandle(request, response, api, params);
if (obj != null) {
return obj;
}
PageResult<Map<String, Object>> value = apiMappingEngine.execute(api, params); PageResult<Map<String, Object>> value = apiMappingEngine.execute(api, params);
// 执行后置拦截器 // 执行后置拦截器
requestInterceptor.postHandle(request, response, api, params, value); requestInterceptor.postHandle(request, response, api, params, value);
ThreadUtil.getInstance().get().setCallerSize(value.getData().size());
ThreadUtil.getInstance().get().setTime(System.currentTimeMillis() - start);
return R.ok().setData(value); return R.ok().setData(value);
} catch (Exception e) {
log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
ThreadUtil.getInstance().get().setMsg(e.getMessage());
return R.error(e.getMessage());
} finally {
ApiLogDto apiLogDto = ThreadUtil.getInstance().get();
log.info("ApiLogDto信息={}", apiLogDto);
if (apiLogDto != null) {
asyncTask.doTask(apiLogDto);
}
ThreadUtil.getInstance().remove();
}
} }
} }
package cn.datax.service.data.market.mapping.handler; package cn.datax.service.data.market.mapping.handler;
import cn.datax.common.core.DataConstant; import cn.datax.common.core.DataConstant;
import cn.datax.common.core.R; import cn.datax.common.exception.DataException;
import cn.datax.common.utils.IPUtil; import cn.datax.common.utils.IPUtil;
import cn.datax.common.utils.MD5Util; import cn.datax.common.utils.MD5Util;
import cn.datax.service.data.market.api.dto.ApiLogDto; import cn.datax.service.data.market.api.dto.ApiLogDto;
...@@ -39,37 +39,23 @@ public class RequestInterceptor { ...@@ -39,37 +39,23 @@ public class RequestInterceptor {
* @return 当返回对象时,直接将此对象返回到页面,返回null时,继续执行后续操作 * @return 当返回对象时,直接将此对象返回到页面,返回null时,继续执行后续操作
* @throws Exception * @throws Exception
*/ */
public Object preHandle(HttpServletRequest request, HttpServletResponse response, DataApiEntity api, Map<String, Object> params) throws Exception { public void preHandle(HttpServletRequest request, HttpServletResponse response, DataApiEntity api, Map<String, Object> params) throws Exception {
System.out.println("************ApiInterceptor preHandle executed**********"); System.out.println("************ApiInterceptor preHandle executed**********");
String uri = request.getRequestURI(); String uri = request.getRequestURI();
log.info("getRequestURI的值:" + uri); log.info("getRequestURI的值:" + uri);
String ipAddr = IPUtil.getIpAddr(request); String ipAddr = IPUtil.getIpAddr(request);
log.info("ipAddr的值:" + ipAddr); log.info("ipAddr的值:" + ipAddr);
// 记录日志
ApiLogDto log = new ApiLogDto();
log.setCallerIp(ipAddr);
log.setCallerUrl(uri);
log.setCallerParams(new ObjectMapper().writeValueAsString(params));
log.setCallerDate(LocalDateTime.now());
log.setStatus(DataConstant.EnableState.ENABLE.getKey());
ThreadUtil.getInstance().set(log);
// 密钥校验 // 密钥校验
String apiKey = request.getHeader("api_key"); String apiKey = request.getHeader("api_key");
String secretKey = request.getHeader("secret_key"); String secretKey = request.getHeader("secret_key");
if (StrUtil.isBlank(apiKey) || StrUtil.isBlank(secretKey)) { if (StrUtil.isBlank(apiKey) || StrUtil.isBlank(secretKey)) {
ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey()); throw new DataException("api_key或secret_key空");
ThreadUtil.getInstance().get().setMsg("api_key或secret_key空");
return R.error("api_key或secret_key空");
} }
MD5Util mt = MD5Util.getInstance(); MD5Util mt = MD5Util.getInstance();
String apiId = mt.decode(apiKey); String apiId = mt.decode(apiKey);
String userId = mt.decode(secretKey); String userId = mt.decode(secretKey);
ThreadUtil.getInstance().get().setApiId(apiId);
ThreadUtil.getInstance().get().setCallerId(userId);
// 黑名单校验 // 黑名单校验
String deny = api.getDeny(); String deny = api.getDeny();
if (StrUtil.isNotBlank(deny)) { if (StrUtil.isNotBlank(deny)) {
...@@ -77,33 +63,23 @@ public class RequestInterceptor { ...@@ -77,33 +63,23 @@ public class RequestInterceptor {
if (CollUtil.isNotEmpty(denyList)) { if (CollUtil.isNotEmpty(denyList)) {
for (String ip : denyList) { for (String ip : denyList) {
if(ip.equals(ipAddr)){ if(ip.equals(ipAddr)){
ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey()); throw new DataException(ip + "已被加入IP黑名单");
ThreadUtil.getInstance().get().setMsg("此IP已被加入API调用黑名单");
return R.error("此IP已被加入API调用黑名单");
} }
} }
} }
} }
// 参数校验 // 参数校验
if (MapUtil.isNotEmpty(params)) { if (MapUtil.isNotEmpty(params)) {
try {
api.getReqParams().stream().forEach(param -> { api.getReqParams().stream().forEach(param -> {
if (params.containsKey(param.getParamName())) { if (params.containsKey(param.getParamName())) {
// 参数类型是否正确 // 参数类型是否正确
ParamType.parse(ParamType.getParamType(param.getParamType()), params.get(param.getParamName())); ParamType.parse(ParamType.getParamType(param.getParamType()), params.get(param.getParamName()));
} }
}); });
} catch (Exception e) {
ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
ThreadUtil.getInstance().get().setMsg(e.getMessage());
return R.error(e.getMessage());
}
} }
// 限流校验
String apiName = api.getApiName();
ThreadUtil.getInstance().get().setApiName(apiName);
// 限流校验
String rateLimit = api.getRateLimit(); String rateLimit = api.getRateLimit();
rateLimit = Optional.ofNullable(rateLimit).orElse(DataConstant.TrueOrFalse.TRUE.getKey()); rateLimit = Optional.ofNullable(rateLimit).orElse(DataConstant.TrueOrFalse.TRUE.getKey());
if (DataConstant.TrueOrFalse.TRUE.getKey().equals(rateLimit)) { if (DataConstant.TrueOrFalse.TRUE.getKey().equals(rateLimit)) {
...@@ -123,13 +99,9 @@ public class RequestInterceptor { ...@@ -123,13 +99,9 @@ public class RequestInterceptor {
} else if (maxTimes < times) { } else if (maxTimes < times) {
redisTemplate.opsForValue().set(key, maxTimes + 1, seconds, TimeUnit.SECONDS); redisTemplate.opsForValue().set(key, maxTimes + 1, seconds, TimeUnit.SECONDS);
} else { } else {
// 请求过于频繁 throw new DataException("API调用过于频繁");
ThreadUtil.getInstance().get().setStatus(DataConstant.EnableState.DISABLE.getKey());
ThreadUtil.getInstance().get().setMsg("API调用过于频繁");
return R.error("API调用过于频繁");
} }
} }
return null;
} }
/** /**
......
...@@ -49,8 +49,8 @@ public class ApiMappingEngine { ...@@ -49,8 +49,8 @@ public class ApiMappingEngine {
dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid()); dbSchema.getUsername(), dbSchema.getPassword(), dbSchema.getPort(), dbSchema.getDbName(), dbSchema.getSid());
DbQuery dbQuery = dataSourceFactory.createDbQuery(dbQueryProperty); DbQuery dbQuery = dataSourceFactory.createDbQuery(dbQueryProperty);
// 参数 // 参数
Integer pageNum = (Integer) params.getOrDefault("pageNum", 1); Integer pageNum = Integer.parseInt((String) params.getOrDefault("pageNum", 1));
Integer pageSize = (Integer) params.getOrDefault("pageSize", 20); Integer pageSize = Integer.parseInt((String) params.getOrDefault("pageSize", 20));
PageUtil pageUtil = new PageUtil(pageNum, pageSize); PageUtil pageUtil = new PageUtil(pageNum, pageSize);
Integer offset = pageUtil.getOffset(); Integer offset = pageUtil.getOffset();
SqlBuilderUtil.SqlFilterResult sqlFilterResult; SqlBuilderUtil.SqlFilterResult sqlFilterResult;
...@@ -62,11 +62,9 @@ public class ApiMappingEngine { ...@@ -62,11 +62,9 @@ public class ApiMappingEngine {
} }
Map<String, Object> acceptedFilters = sqlFilterResult.getAcceptedFilters(); Map<String, Object> acceptedFilters = sqlFilterResult.getAcceptedFilters();
// 数据脱敏 // 数据脱敏
List<FieldRule> rules; List<FieldRule> rules = null;
ApiMaskEntity apiMaskEntity = apiMaskServiceFeign.getApiMaskByApiId(dataApi.getId()); ApiMaskEntity apiMaskEntity = apiMaskServiceFeign.getApiMaskByApiId(dataApi.getId());
if (apiMaskEntity == null) { if (apiMaskEntity != null) {
throw new DataException("API调用查询数据脱敏出错");
} else {
rules = apiMaskEntity.getRules(); rules = apiMaskEntity.getRules();
} }
PageResult<Map<String, Object>> pageResult; PageResult<Map<String, Object>> pageResult;
......
...@@ -37,6 +37,7 @@ import net.sf.jsqlparser.statement.Statement; ...@@ -37,6 +37,7 @@ import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitorAdapter; import net.sf.jsqlparser.statement.StatementVisitorAdapter;
import net.sf.jsqlparser.statement.select.*; import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.util.SelectUtils; import net.sf.jsqlparser.util.SelectUtils;
import net.sf.jsqlparser.util.TablesNamesFinder;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import net.sf.jsqlparser.util.deparser.SelectDeParser; import net.sf.jsqlparser.util.deparser.SelectDeParser;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
...@@ -46,12 +47,9 @@ import org.springframework.stereotype.Service; ...@@ -46,12 +47,9 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -137,8 +135,47 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit ...@@ -137,8 +135,47 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit
log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e)); log.error("全局异常信息ex={}, StackTrace={}", e.getMessage(), ThrowableUtil.getStackTrace(e));
throw new DataException("SQL语法有问题,解析出错"); throw new DataException("SQL语法有问题,解析出错");
} }
final List<String> variables = new ArrayList<>(); // 维护元数据缓存数据
final List<String> cols = new ArrayList<>(); TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tables = tablesNamesFinder.getTableList(stmt);
// 查询字段
final List<Map<String,String>> cols = new ArrayList<>();
// 查询参数
final List<String> vars = new ArrayList<>();
if (tables.size() == 1) {
// 单表解析
singleSqlParse(stmt, cols, vars, tables.get(0));
} else if (tables.size() > 1) {
// 多表解析
multipleSqlParse(stmt, cols, vars);
}
SqlParseVo sqlParseVo = new SqlParseVo();
List<ReqParam> reqParams = vars.stream().map(s -> {
ReqParam reqParam = new ReqParam();
reqParam.setParamName(s);
reqParam.setNullable(DataConstant.TrueOrFalse.FALSE.getKey());
return reqParam;
}).collect(Collectors.toList());
sqlParseVo.setReqParams(reqParams);
Map<String, List<Map<String, String>>> map = cols.stream().collect(Collectors.groupingBy(e -> e.get("tableName").toString()));
for (Map.Entry<String, List<Map<String, String>>> entry : map.entrySet()) {
String entryKey = entry.getKey().toLowerCase();
// 根据entryKey找到数据库表
List<Map<String, String>> entryValue = entry.getValue();
entryValue.stream().map(m -> m.get("columnName"));
}
// List<ResParam> resParams = cols.stream().map(s -> {
// ResParam resParam = new ResParam();
// resParam.setFieldName(s);
// return resParam;
// }).collect(Collectors.toList());
// sqlParseVo.setResParams(resParams);
return sqlParseVo;
}
private void singleSqlParse(Statement stmt, List<Map<String, String>> cols, List<String> vars, String tableName) {
stmt.accept(new StatementVisitorAdapter() { stmt.accept(new StatementVisitorAdapter() {
@Override @Override
public void visit(Select select) { public void visit(Select select) {
...@@ -149,12 +186,16 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit ...@@ -149,12 +186,16 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit
selectItem.accept(new SelectItemVisitorAdapter() { selectItem.accept(new SelectItemVisitorAdapter() {
@Override @Override
public void visit(SelectExpressionItem item) { public void visit(SelectExpressionItem item) {
Map<String,String> map = new HashMap<>();
String columnName; String columnName;
if (item.getAlias() == null) {
SimpleNode node = item.getExpression().getASTNode(); SimpleNode node = item.getExpression().getASTNode();
Object value = node.jjtGetValue(); Object value = node.jjtGetValue();
if (value instanceof Column) { if (value instanceof Column) {
columnName = ((Column) value).getColumnName(); Column column = (Column) value;
columnName = column.getColumnName();
if (item.getAlias() != null) {
map.put("columnAliasName", item.getAlias().getName());
}
} else if (value instanceof Function) { } else if (value instanceof Function) {
columnName = value.toString(); columnName = value.toString();
} else { } else {
...@@ -164,41 +205,97 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit ...@@ -164,41 +205,97 @@ public class DataApiServiceImpl extends BaseServiceImpl<DataApiDao, DataApiEntit
columnName = columnName.replace("\"", ""); columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", ""); columnName = columnName.replace("`", "");
} }
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
map.put("tableName", tableName);
map.put("columnName", columnName);
cols.add(map);
}
});
});
plainSelect.getWhere().accept(new ExpressionVisitorAdapter() {
@Override
public void visit(JdbcNamedParameter jdbcNamedParameter) {
vars.add(jdbcNamedParameter.getName());
}
});
}
});
}
});
}
private void multipleSqlParse(Statement stmt, List<Map<String, String>> cols, List<String> vars) {
stmt.accept(new StatementVisitorAdapter() {
@Override
public void visit(Select select) {
select.getSelectBody().accept(new SelectVisitorAdapter() {
@Override
public void visit(PlainSelect plainSelect) {
// 存储表名
Map<String,String> map = new HashMap<>();
Table table = (Table)plainSelect.getFromItem();
if (table.getAlias() != null) {
map.put(table.getName(), table.getAlias().getName());
}
for (Join join : plainSelect.getJoins()) {
Table table1 = (Table)join.getRightItem();
if (table1.getAlias() != null) {
map.put(table1.getName(), table1.getAlias().getName());
}
}
plainSelect.getSelectItems().stream().forEach(selectItem -> {
selectItem.accept(new SelectItemVisitorAdapter() {
@Override
public void visit(SelectExpressionItem item) {
Map<String,String> m = new HashMap<>();
String tableName = "", columnName;
SimpleNode node = item.getExpression().getASTNode();
Object value = node.jjtGetValue();
if (value instanceof Column) {
Column column = (Column) value;
Table table = column.getTable();
if (table != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
if(table.getName().equals(entry.getValue())){
tableName = entry.getKey();
break;
}
}
}
columnName = column.getColumnName();
if (item.getAlias() != null) {
m.put("columnAliasName", item.getAlias().getName());
}
} else if (value instanceof Function) {
columnName = value.toString();
} else { } else {
columnName = item.getAlias().getName(); // 增加对select 'aaa' from table; 的支持
columnName = String.valueOf(value);
columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", "");
} }
columnName = columnName.replace("'", ""); columnName = columnName.replace("'", "");
columnName = columnName.replace("\"", ""); columnName = columnName.replace("\"", "");
columnName = columnName.replace("`", ""); columnName = columnName.replace("`", "");
cols.add(columnName); m.put("tableName", tableName);
m.put("columnName", columnName);
cols.add(m);
} }
}); });
}); });
plainSelect.getWhere().accept(new ExpressionVisitorAdapter() { plainSelect.getWhere().accept(new ExpressionVisitorAdapter() {
@Override @Override
public void visit(JdbcNamedParameter jdbcNamedParameter) { public void visit(JdbcNamedParameter jdbcNamedParameter) {
variables.add(jdbcNamedParameter.getName()); vars.add(jdbcNamedParameter.getName());
} }
}); });
} }
}); });
} }
}); });
SqlParseVo sqlParseVo = new SqlParseVo();
List<ReqParam> reqParams = variables.stream().map(s -> {
ReqParam reqParam = new ReqParam();
reqParam.setParamName(s);
reqParam.setNullable(DataConstant.TrueOrFalse.FALSE.getKey());
return reqParam;
}).collect(Collectors.toList());
sqlParseVo.setReqParams(reqParams);
List<ResParam> resParams = cols.stream().map(s -> {
ResParam resParam = new ResParam();
resParam.setFieldName(s);
return resParam;
}).collect(Collectors.toList());
sqlParseVo.setResParams(resParams);
return sqlParseVo;
} }
private String sqlJdbcNamedParameterBuild(DataApiEntity dataApi) throws JSQLParserException { private String sqlJdbcNamedParameterBuild(DataApiEntity dataApi) throws JSQLParserException {
......
...@@ -69,6 +69,7 @@ export default { ...@@ -69,6 +69,7 @@ export default {
.main-container{ .main-container{
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; width: 6px;
height: 6px;
} }
::-webkit-scrollbar-track-piece { ::-webkit-scrollbar-track-piece {
background: #d3dce6; background: #d3dce6;
......
...@@ -4,17 +4,17 @@ ...@@ -4,17 +4,17 @@
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span>{{ title }}</span> <span>{{ title }}</span>
<el-button-group style="float: right;"> <el-button-group style="float: right;">
<el-button size="mini" icon="el-icon-plus" round @click="submitForm" :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled">{{loadingOptions.loadingText}}</el-button> <el-button size="mini" icon="el-icon-plus" round :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled" @click="submitForm">{{ loadingOptions.loadingText }}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button> <el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group> </el-button-group>
</div> </div>
<div :style="classCardbody"> <div :style="classCardbody">
<el-steps :active="active" finish-status="success" align-center> <el-steps :active="active" finish-status="success" align-center>
<el-step title="属性配置"></el-step> <el-step title="属性配置" />
<el-step title="执行配置"></el-step> <el-step title="执行配置" />
<el-step title="参数配置"></el-step> <el-step title="参数配置" />
</el-steps> </el-steps>
<el-form ref="form1" :model="form1" :rules="rules1" label-width="80px" v-if="active == 1"> <el-form v-if="active == 1" ref="form1" :model="form1" :rules="rules1" label-width="80px">
<el-form-item label="API名称" prop="apiName"> <el-form-item label="API名称" prop="apiName">
<el-input v-model="form1.apiName" placeholder="请输入API名称" /> <el-input v-model="form1.apiName" placeholder="请输入API名称" />
</el-form-item> </el-form-item>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
:key="dict.id" :key="dict.id"
:label="dict.itemValue" :label="dict.itemValue"
:value="dict.itemText" :value="dict.itemText"
></el-option> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="返回格式" prop="resType"> <el-form-item label="返回格式" prop="resType">
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
:key="dict.id" :key="dict.id"
:label="dict.itemValue" :label="dict.itemValue"
:value="dict.itemText" :value="dict.itemText"
></el-option> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="IP黑名单" prop="deny"> <el-form-item label="IP黑名单" prop="deny">
...@@ -53,14 +53,14 @@ ...@@ -53,14 +53,14 @@
v-for="dict in whetherOptions" v-for="dict in whetherOptions"
:key="dict.id" :key="dict.id"
:label="dict.itemText" :label="dict.itemText"
>{{dict.itemValue}}</el-radio> >{{ dict.itemValue }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="请求次数" prop="times" v-if="form1.rateLimit === '1'"> <el-form-item v-if="form1.rateLimit === '1'" label="请求次数" prop="times">
<el-input-number v-model="form1.times" controls-position="right" :min="1" /> <el-input-number v-model="form1.times" controls-position="right" :min="1" />
</el-form-item> </el-form-item>
<el-form-item label="请求时间范围" prop="seconds" v-if="form1.rateLimit === '1'"> <el-form-item v-if="form1.rateLimit === '1'" label="请求时间范围" prop="seconds">
<el-input-number v-model="form1.seconds" controls-position="right" :min="1"/> <el-input-number v-model="form1.seconds" controls-position="right" :min="1" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="form1.status" disabled> <el-radio-group v-model="form1.status" disabled>
...@@ -68,14 +68,14 @@ ...@@ -68,14 +68,14 @@
v-for="dict in statusOptions" v-for="dict in statusOptions"
:key="dict.id" :key="dict.id"
:label="dict.itemText" :label="dict.itemText"
>{{dict.itemValue}}</el-radio> >{{ dict.itemValue }}</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">
<el-input v-model="form1.remark" type="textarea" placeholder="请输入内容" /> <el-input v-model="form1.remark" type="textarea" placeholder="请输入内容" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-form ref="form2" :model="form2" :rules="rules2" label-width="80px" v-if="active == 2"> <el-form v-if="active == 2" ref="form2" :model="form2" :rules="rules2" label-width="80px">
<el-form-item label="配置方式" prop="configType"> <el-form-item label="配置方式" prop="configType">
<el-select v-model="form2.configType" placeholder="请选择配置方式" @change="configTypeSelectChanged"> <el-select v-model="form2.configType" placeholder="请选择配置方式" @change="configTypeSelectChanged">
<el-option <el-option
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
:key="dict.id" :key="dict.id"
:label="dict.itemValue" :label="dict.itemValue"
:value="dict.itemText" :value="dict.itemText"
></el-option> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="数据源" prop="sourceId"> <el-form-item label="数据源" prop="sourceId">
...@@ -94,59 +94,55 @@ ...@@ -94,59 +94,55 @@
:label="source.sourceName" :label="source.sourceName"
:value="source.id" :value="source.id"
:disabled="source.status === '0'" :disabled="source.status === '0'"
></el-option> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="数据库表" prop="tableName" v-if="form2.configType === '1'"> <el-form-item v-if="form2.configType === '1'" label="数据库表" prop="tableName">
<el-select v-model="form2.table" value-key="id" placeholder="请选择数据库表" @change="tableSelectChanged"> <el-select v-model="form2.table" value-key="id" placeholder="请选择数据库表" @change="tableSelectChanged">
<el-option <el-option
v-for="item in tableOptions" v-for="item in tableOptions"
:key="item.id" :key="item.id"
:label="item.tableComment ? item.tableComment : item.tableName" :label="item.tableComment ? item.tableComment : item.tableName"
:value="item"> :value="item"
</el-option> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="字段列表" v-if="form2.configType === '1'"> <el-form-item v-if="form2.configType === '1'" label="字段列表">
<el-table :data="form2.fieldParams" stripe border <el-table
:data="form2.fieldParams"
stripe
border
:max-height="300" :max-height="300"
style="width: 100%; margin: 15px 0;"> style="width: 100%; margin: 15px 0;"
<el-table-column prop="columnPosition" label="序号" width="55" align="center" > >
</el-table-column> <el-table-column prop="columnPosition" label="序号" width="55" align="center" />
<el-table-column prop="columnName" label="列名" align="center" show-overflow-tooltip > <el-table-column prop="columnName" label="列名" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="dataType" label="数据类型" align="center" show-overflow-tooltip />
<el-table-column prop="dataType" label="数据类型" align="center" show-overflow-tooltip > <el-table-column prop="dataLength" label="数据长度" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="dataPrecision" label="数据精度" align="center" show-overflow-tooltip />
<el-table-column prop="dataLength" label="数据长度" align="center" show-overflow-tooltip > <el-table-column prop="dataScale" label="数据小数位" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="columnKey" label="是否主键" align="center" show-overflow-tooltip>
<el-table-column prop="dataPrecision" label="数据精度" align="center" show-overflow-tooltip >
</el-table-column>
<el-table-column prop="dataScale" label="数据小数位" align="center" show-overflow-tooltip >
</el-table-column>
<el-table-column prop="columnKey" label="是否主键" align="center" show-overflow-tooltip >
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.columnKey === '1'">Y</span> <span v-if="scope.row.columnKey === '1'">Y</span>
<span v-if="scope.row.columnKey === '0'">N</span> <span v-if="scope.row.columnKey === '0'">N</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="columnNullable" label="是否允许为空" align="center" show-overflow-tooltip > <el-table-column prop="columnNullable" label="是否允许为空" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.columnNullable === '1'">Y</span> <span v-if="scope.row.columnNullable === '1'">Y</span>
<span v-if="scope.row.columnNullable === '0'">N</span> <span v-if="scope.row.columnNullable === '0'">N</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="dataDefault" label="列默认值" align="center" show-overflow-tooltip > <el-table-column prop="dataDefault" label="列默认值" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="columnComment" label="列注释" align="center" show-overflow-tooltip />
<el-table-column prop="columnComment" label="列注释" align="center" show-overflow-tooltip > <el-table-column prop="reqable" label="是否作为请求参数" align="center" width="50">
</el-table-column>
<el-table-column prop="reqable" label="是否作为请求参数" align="center" width="50" >
<template slot-scope="scope"> <template slot-scope="scope">
<el-checkbox v-model="scope.row.reqable" true-label="1" false-label="0" @change="checked=>reqCheckChange(scope.row, checked)"></el-checkbox> <el-checkbox v-model="scope.row.reqable" true-label="1" false-label="0" @change="checked=>reqCheckChange(scope.row, checked)" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="resable" label="是否作为返回参数" align="center" width="50" > <el-table-column prop="resable" label="是否作为返回参数" align="center" width="50">
<template slot-scope="scope"> <template slot-scope="scope">
<el-checkbox v-model="scope.row.resable" true-label="1" false-label="0" @change="checked=>resCheckChange(scope.row, checked)"></el-checkbox> <el-checkbox v-model="scope.row.resable" true-label="1" false-label="0" @change="checked=>resCheckChange(scope.row, checked)" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -156,35 +152,41 @@ ...@@ -156,35 +152,41 @@
<sql-editor <sql-editor
ref="sqleditor" ref="sqleditor"
:value="form2.sqlText" :value="form2.sqlText"
@changeTextarea="changeTextarea($event)"
style="height: 300px;margin: 10px 10px;" style="height: 300px;margin: 10px 10px;"
></sql-editor> @changeTextarea="changeTextarea($event)"
/>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item v-if="form2.configType === '2'"> <el-form-item v-if="form2.configType === '2'">
<el-button size="mini" type="primary" @click="sqlParse">SQL解析</el-button> <el-button size="mini" type="primary" @click="sqlParse">SQL解析</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-form ref="form3" :model="form3" label-width="80px" v-if="active == 3"> <el-form v-if="active == 3" ref="form3" :model="form3" label-width="80px">
<el-divider content-position="left">请求参数</el-divider> <el-divider content-position="left">请求参数</el-divider>
<el-table :data="form3.reqParams" stripe border <el-table
:data="form3.reqParams"
stripe
border
:max-height="300" :max-height="300"
style="width: 100%; margin: 15px 0;"> style="width: 100%; margin: 15px 0;"
>
<el-table-column label="序号" width="55" align="center"> <el-table-column label="序号" width="55" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.$index +1 }}</span> <span>{{ scope.$index +1 }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="paramName" label="参数名称" align="center" show-overflow-tooltip > <el-table-column prop="paramName" label="参数名称" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="nullable" label="是否允许为空" align="center" show-overflow-tooltip>
<el-table-column prop="nullable" label="是否允许为空" align="center" show-overflow-tooltip >
<template slot-scope="scope"> <template slot-scope="scope">
<el-checkbox v-model="scope.row.nullable" true-label="1" false-label="0"></el-checkbox> <el-checkbox v-model="scope.row.nullable" true-label="1" false-label="0" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="paramComment" label="描述" align="center" show-overflow-tooltip > <el-table-column prop="paramComment" label="描述" align="center" show-overflow-tooltip>
<template slot-scope="scope">
<el-input v-model="scope.row.paramComment" placeholder="请输入描述" />
</template>
</el-table-column> </el-table-column>
<el-table-column prop="paramType" label="参数类型" align="center" show-overflow-tooltip > <el-table-column prop="paramType" label="参数类型" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.paramType" placeholder="请选择参数类型"> <el-select v-model="scope.row.paramType" placeholder="请选择参数类型">
<el-option <el-option
...@@ -192,11 +194,11 @@ ...@@ -192,11 +194,11 @@
:key="dict.id" :key="dict.id"
:label="dict.itemValue" :label="dict.itemValue"
:value="dict.itemText" :value="dict.itemText"
></el-option> />
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="whereType" label="操作符" align="center" show-overflow-tooltip > <el-table-column prop="whereType" label="操作符" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.whereType" placeholder="请选择操作符"> <el-select v-model="scope.row.whereType" placeholder="请选择操作符">
<el-option <el-option
...@@ -204,45 +206,54 @@ ...@@ -204,45 +206,54 @@
:key="dict.id" :key="dict.id"
:label="dict.itemValue" :label="dict.itemValue"
:value="dict.itemText" :value="dict.itemText"
></el-option> />
</el-select> </el-select>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="exampleValue" label="示例值" align="center" show-overflow-tooltip > <el-table-column prop="exampleValue" label="示例值" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.exampleValue" placeholder="请输入示例值" /> <el-input v-model="scope.row.exampleValue" placeholder="请输入示例值" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="defaultValue" label="默认值" align="center" show-overflow-tooltip > <el-table-column prop="defaultValue" label="默认值" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.defaultValue" placeholder="请输入默认值" /> <el-input v-model="scope.row.defaultValue" placeholder="请输入默认值" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-divider content-position="left">返回字段</el-divider> <el-divider content-position="left">返回字段</el-divider>
<el-table :data="form3.resParams" stripe border <el-table
:data="form3.resParams"
stripe
border
:max-height="300" :max-height="300"
style="width: 100%; margin: 15px 0;"> style="width: 100%; margin: 15px 0;"
>
<el-table-column label="序号" width="55" align="center"> <el-table-column label="序号" width="55" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.$index +1 }}</span> <span>{{ scope.$index +1 }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="fieldName" label="字段名称" align="center" show-overflow-tooltip > <el-table-column prop="fieldName" label="字段名称" align="center" show-overflow-tooltip />
</el-table-column> <el-table-column prop="fieldComment" label="描述" align="center" show-overflow-tooltip>
<el-table-column prop="fieldComment" label="描述" align="center" show-overflow-tooltip > <template slot-scope="scope">
<el-input v-model="scope.row.fieldComment" placeholder="请输入描述" />
</template>
</el-table-column> </el-table-column>
<el-table-column prop="dataType" label="数据类型" align="center" show-overflow-tooltip > <el-table-column prop="dataType" label="数据类型" align="center" show-overflow-tooltip>
<template slot-scope="scope">
<el-input v-model="scope.row.dataType" placeholder="请输入数据类型" />
</template>
</el-table-column> </el-table-column>
<el-table-column prop="exampleValue" label="示例值" align="center" show-overflow-tooltip > <el-table-column prop="exampleValue" label="示例值" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.exampleValue" placeholder="请输入示例值" /> <el-input v-model="scope.row.exampleValue" placeholder="请输入示例值" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-form> </el-form>
<el-button style="margin-top: 12px;" @click="handleNextStep" v-if="active < 3">下一步</el-button> <el-button v-if="active < 3" style="margin-top: 12px;" @click="handleNextStep">下一步</el-button>
<el-button style="margin-top: 12px;" @click="handleLastStep" v-if="active > 1">上一步</el-button> <el-button v-if="active > 1" style="margin-top: 12px;" @click="handleLastStep">上一步</el-button>
</div> </div>
</el-card> </el-card>
</div> </div>
...@@ -263,12 +274,12 @@ export default { ...@@ -263,12 +274,12 @@ export default {
props: { props: {
data: { data: {
type: Object, type: Object,
default: function () { default: function() {
return {} return {}
} }
} }
}, },
data () { data() {
return { return {
classCardbody: { classCardbody: {
overflow: 'auto', overflow: 'auto',
...@@ -367,7 +378,7 @@ export default { ...@@ -367,7 +378,7 @@ export default {
paramTypeOptions: [] paramTypeOptions: []
} }
}, },
created () { created() {
this.getDicts('data_req_method').then(response => { this.getDicts('data_req_method').then(response => {
if (response.success) { if (response.success) {
this.reqMethodOptions = response.data this.reqMethodOptions = response.data
...@@ -406,10 +417,10 @@ export default { ...@@ -406,10 +417,10 @@ export default {
}) })
}, },
methods: { methods: {
showCard () { showCard() {
this.$emit('showCard', this.showOptions) this.$emit('showCard', this.showOptions)
}, },
getDataSourceList () { getDataSourceList() {
listDataSource().then(response => { listDataSource().then(response => {
if (response.success) { if (response.success) {
this.sourceOptions = response.data this.sourceOptions = response.data
...@@ -417,7 +428,7 @@ export default { ...@@ -417,7 +428,7 @@ export default {
}) })
}, },
/** 步骤条下一步 */ /** 步骤条下一步 */
handleNextStep () { handleNextStep() {
if (this.active === 1) { if (this.active === 1) {
this.$refs['form1'].validate(valid => { this.$refs['form1'].validate(valid => {
if (valid) { if (valid) {
...@@ -433,15 +444,15 @@ export default { ...@@ -433,15 +444,15 @@ export default {
} }
}, },
/** 步骤条上一步 */ /** 步骤条上一步 */
handleLastStep () { handleLastStep() {
this.active-- this.active--
}, },
changeTextarea (val) { changeTextarea(val) {
this.form2.sqlText = val this.form2.sqlText = val
}, },
configTypeSelectChanged (val) { configTypeSelectChanged(val) {
if (this.form2.configType === '1' && this.form2.sourceId && this.tableOptions.length <= 0) { if (this.form2.configType === '1' && this.form2.sourceId && this.tableOptions.length <= 0) {
let data = {} const data = {}
data.sourceId = this.form2.sourceId data.sourceId = this.form2.sourceId
listDataTable(data).then(response => { listDataTable(data).then(response => {
if (response.success) { if (response.success) {
...@@ -451,9 +462,9 @@ export default { ...@@ -451,9 +462,9 @@ export default {
}) })
} }
}, },
sourceSelectChanged (val) { sourceSelectChanged(val) {
if (this.form2.configType && this.form2.configType === '1') { if (this.form2.configType && this.form2.configType === '1') {
let data = {} const data = {}
data.sourceId = val data.sourceId = val
listDataTable(data).then(response => { listDataTable(data).then(response => {
if (response.success) { if (response.success) {
...@@ -463,8 +474,8 @@ export default { ...@@ -463,8 +474,8 @@ export default {
}) })
} }
}, },
tableSelectChanged (item) { tableSelectChanged(item) {
let data = {} const data = {}
data.sourceId = item.sourceId data.sourceId = item.sourceId
data.tableId = item.id data.tableId = item.id
this.form2.tableId = item.id this.form2.tableId = item.id
...@@ -477,7 +488,7 @@ export default { ...@@ -477,7 +488,7 @@ export default {
} }
}) })
}, },
sqlParse () { sqlParse() {
if (!this.form2.sourceId) { if (!this.form2.sourceId) {
this.$message.error('数据源不能为空') this.$message.error('数据源不能为空')
return return
...@@ -486,21 +497,21 @@ export default { ...@@ -486,21 +497,21 @@ export default {
this.$message.error('解析SQL不能为空') this.$message.error('解析SQL不能为空')
return return
} }
let data = {} const data = {}
data.sqlText = this.form2.sqlText data.sqlText = this.form2.sqlText
sqlParse(data).then(response => { sqlParse(data).then(response => {
if (response.success) { if (response.success) {
const { data } = response const { data } = response
let reqParams = data.reqParams const reqParams = data.reqParams
let resParams = data.resParams const resParams = data.resParams
this.form3.reqParams = reqParams.map(function (item) { this.form3.reqParams = reqParams.map(function(item) {
let json = {} const json = {}
json.paramName = item.paramName json.paramName = item.paramName
json.nullable = '0' json.nullable = '0'
return json return json
}) })
this.form3.resParams = resParams.map(function (item) { this.form3.resParams = resParams.map(function(item) {
let json = {} const json = {}
json.fieldName = item.fieldName json.fieldName = item.fieldName
return json return json
}) })
...@@ -508,9 +519,9 @@ export default { ...@@ -508,9 +519,9 @@ export default {
} }
}) })
}, },
reqCheckChange (row, checked) { reqCheckChange(row, checked) {
if (checked === '1') { if (checked === '1') {
let json = {} const json = {}
json.paramName = row.columnName json.paramName = row.columnName
json.paramComment = row.columnComment || undefined json.paramComment = row.columnComment || undefined
json.nullable = '0' json.nullable = '0'
...@@ -519,9 +530,9 @@ export default { ...@@ -519,9 +530,9 @@ export default {
this.form3.reqParams.splice(this.form3.reqParams.findIndex(item => item.paramName === row.columnName), 1) this.form3.reqParams.splice(this.form3.reqParams.findIndex(item => item.paramName === row.columnName), 1)
} }
}, },
resCheckChange (row, checked) { resCheckChange(row, checked) {
if (checked === '1') { if (checked === '1') {
let json = {} const json = {}
json.fieldName = row.columnName json.fieldName = row.columnName
json.fieldComment = row.columnComment || undefined json.fieldComment = row.columnComment || undefined
json.dataType = row.dataType || undefined json.dataType = row.dataType || undefined
...@@ -531,7 +542,7 @@ export default { ...@@ -531,7 +542,7 @@ export default {
} }
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm: function () { submitForm: function() {
this.$refs['form3'].validate(valid => { this.$refs['form3'].validate(valid => {
if (valid) { if (valid) {
if (this.form3.reqParams.length <= 0) { if (this.form3.reqParams.length <= 0) {
......
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
<el-checkbox v-model="scope.row.nullable" true-label="1" false-label="0" disabled /> <el-checkbox v-model="scope.row.nullable" true-label="1" false-label="0" disabled />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="remark" label="描述" align="center" show-overflow-tooltip /> <el-table-column prop="paramComment" label="描述" align="center" show-overflow-tooltip />
<el-table-column prop="paramType" label="参数类型" align="center" show-overflow-tooltip> <el-table-column prop="paramType" label="参数类型" align="center" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-select v-model="scope.row.paramType" placeholder="请选择参数类型" disabled> <el-select v-model="scope.row.paramType" placeholder="请选择参数类型" disabled>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment