提交 512a8795 authored 作者: Matrix's avatar Matrix

feat(SQL执行器): SQL执行器的初版

- SQL执行器的初版 - 修改了一些不正确的目录结构 - 代码执行器
上级 06b09d75
/*
Navicat Premium Data Transfer
Source Server : 我的阿里云
Source Server Type : MySQL
Source Server Version : 80022
Source Host : 47.106.142.73:3306
Source Schema : lstest
Target Server Type : MySQL
Target Server Version : 80022
File Encoding : 65001
Date: 14/01/2022 11:22:30
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for action
-- ----------------------------
DROP TABLE IF EXISTS `action`;
CREATE TABLE `action` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`move_id` int NULL DEFAULT NULL COMMENT '行为ID',
`project_id` int NULL DEFAULT NULL COMMENT '项目ID',
`remark` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注',
`type` int NULL DEFAULT NULL COMMENT '类型 1为SQL,2为HTTP,3为CASE,4为WAIT_TIME',
`detail` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '详细参数',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_active_move`(`move_id`) USING BTREE,
CONSTRAINT `fk_active_move` FOREIGN KEY (`move_id`) REFERENCES `move` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '动作' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for connect
-- ----------------------------
DROP TABLE IF EXISTS `connect`;
CREATE TABLE `connect` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'URL',
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '账号',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`driver` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所用驱动',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for dynamic_variable
-- ----------------------------
DROP TABLE IF EXISTS `dynamic_variable`;
CREATE TABLE `dynamic_variable` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`project_id` int NULL DEFAULT NULL COMMENT '所属项目',
`taken_field` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '取用字段',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`type` int NOT NULL COMMENT '动态变量类型 1为KV,2为SQL,3为CASE,4为HTTP',
`remark` varchar(510) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
`detail` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '详细内容',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_project_dynamicVariable`(`project_id`) USING BTREE,
CONSTRAINT `fk_project_dynamicVariable` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for example
-- ----------------------------
DROP TABLE IF EXISTS `example`;
CREATE TABLE `example` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '实例名称',
`parameter_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数名 (例如:env)',
`project_id` int NULL DEFAULT NULL COMMENT '项目ID',
`variable` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '静态变量,以JSON的形式存储,例如({\"name\":\"张三\"})',
`ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ip,例如(http:www.abc.com)',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_project_case`(`project_id`) USING BTREE,
CONSTRAINT `fk_project_case` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '实例表,项目对应的环境实例,例如:实验室环境,开发环境等' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for move
-- ----------------------------
DROP TABLE IF EXISTS `move`;
CREATE TABLE `move` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`project_id` int NULL DEFAULT NULL COMMENT '所属项目',
`remark` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_move_project`(`project_id`) USING BTREE,
CONSTRAINT `fk_move_project` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for project
-- ----------------------------
DROP TABLE IF EXISTS `project`;
CREATE TABLE `project` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for test_case
-- ----------------------------
DROP TABLE IF EXISTS `test_case`;
CREATE TABLE `test_case` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`project_id` int NULL DEFAULT NULL COMMENT '所属项目',
`type` int NOT NULL COMMENT '用例类型 1为http',
`move_before` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '前置行动ID组,例如:1,2,3',
`move_afer_case` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '后置行动ID组,例如:1,2,3',
`move_afer_test` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '测试执行后行动ID组,例如:1,2,3',
`abnormal_checkpoint` int NOT NULL DEFAULT 0 COMMENT '是否进行异常检验,0为否,1为是',
`no_empty_checkpoint` int NOT NULL DEFAULT 0 COMMENT '是否进行非空检验,0为否,1为是',
`contain_checkpoint` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '包含某字段检验(例如 张三,李四) 则对检查结果中是否包含张三或者李四',
`no_contain_checkpoint` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '不包含某字段检验(例如 张三,李四) 则对检查结果中是否不包含张三或者李四',
`database_checkpoint` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '数据库检验点,以JSON形式存放',
`jsonpath_checkpoint` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'jsonpath检验点,以json形式存放',
`detail` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '详细参数',
`create_time` timestamp NULL DEFAULT NULL,
`update_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `fk_case_project`(`project_id`) USING BTREE,
CONSTRAINT `fk_case_project` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
package org.matrix.actuators;
/**
* Actuator. 执行器接口
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/14 at 6:02 PM
* Suffering is the most powerful teacher of life.
*/
public interface Actuator {
}
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.Data; import lombok.Data;
......
package org.matrix.actuator; package org.matrix.actuators.checkpoint;
import cn.hutool.script.ScriptUtil; import cn.hutool.script.ScriptUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
...@@ -11,8 +11,8 @@ import com.jayway.jsonpath.JsonPath; ...@@ -11,8 +11,8 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException; import com.jayway.jsonpath.PathNotFoundException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.matrix.entity.checkPoint.*; import org.matrix.actuators.Actuator;
import org.matrix.entity.httpRequest.HttpResponseDetail; import org.matrix.actuators.httpclient.HttpResponseDetail;
import org.matrix.exception.CheckPointException; import org.matrix.exception.CheckPointException;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
...@@ -31,15 +31,15 @@ import java.util.regex.Pattern; ...@@ -31,15 +31,15 @@ import java.util.regex.Pattern;
* *
* @author huangxiahao * @author huangxiahao
*/ */
public class CheckPointActuator { public class CheckPointActuator implements Actuator {
private final String baseJs; private final String baseJs;
private int projectId; private Long projectId;
private String env; private Long envId;
CheckPointActuator(String baseJsPath, String env, int projectId) { public CheckPointActuator(String baseJsPath, Long env, Long projectId) {
ClassPathResource cpr = new ClassPathResource(baseJsPath); ClassPathResource cpr = new ClassPathResource(baseJsPath);
try { try {
this.baseJs = IOUtils.toString(cpr.getInputStream(), StandardCharsets.UTF_8); this.baseJs = IOUtils.toString(cpr.getInputStream(), StandardCharsets.UTF_8);
...@@ -47,7 +47,7 @@ public class CheckPointActuator { ...@@ -47,7 +47,7 @@ public class CheckPointActuator {
throw new CheckPointException("初始JS加载失败"); throw new CheckPointException("初始JS加载失败");
} }
this.projectId = projectId; this.projectId = projectId;
this.env = env; this.envId = env;
} }
public CheckPointResult httpCheck(HttpResponseDetail httpResponseDetail, CheckPoint checkPoint) { public CheckPointResult httpCheck(HttpResponseDetail httpResponseDetail, CheckPoint checkPoint) {
......
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.Data; import lombok.Data;
......
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
......
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.Data; import lombok.Data;
......
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
......
package org.matrix.entity.checkPoint; package org.matrix.actuators.checkpoint;
import lombok.Data; import lombok.Data;
......
package org.matrix.actuators.datasource;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DataSourceDTO.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2021/12/31 at 2:18 PM
* Suffering is the most powerful teacher of life.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DataSourceDTO {
/**
* 连接池名称
*/
private String poolName;
/**
* JDBC driver org.h2.Driver
*/
private String driverClassName;
/**
* JDBC url 地址
*/
private String url;
/**
* JDBC 用户名
*/
private String username;
/**
* JDBC 密码
*/
private String password;
}
package org.matrix.actuators.datasource;
import java.util.Set;
/**
* IDataSourceService.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 5:38 PM
* Suffering is the most powerful teacher of life.
*/
public interface IDataSourceService {
/**
* 将当前使用的数据替换为参数提供的数据源,如果还没有,则会添加,如果已经有了,则不会添加
*
* @param dto 数据源信息
* @return 当前已经存在的数据源集合
*/
@SuppressWarnings("UnusedReturnValue")
Set<String> switchDataSource(DataSourceDTO dto);
/**
* 添加数据源,如果已经存在同名的数据源了,则不会添加
*
* @param dto 数据源信息
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
Set<String> add(DataSourceDTO dto);
/**
* 添加数据源,如果已经存在同名的数据源了,则会覆盖
*
* @param dto 数据源信息
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
Set<String> addAndUpdate(DataSourceDTO dto);
/**
* 获取当前所有数据源
*
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
Set<String> now();
/**
* 删除数据源
*
* @param name 数据源名称
* @return 删除信息
*/
public String remove(String name);
}
package org.matrix.actuators.datasource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Set;
/**
* IDataSourceServiceImpl.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 5:47 PM
* Suffering is the most powerful teacher of life.
*/
@Service
@RequiredArgsConstructor(onConstructor = @__(@Lazy))
public class IDataSourceServiceImpl implements IDataSourceService {
private final DataSource dataSource;
private final DefaultDataSourceCreator dataSourceCreator;
/**
* 将当前使用的数据替换为参数提供的数据源,如果还没有,则会添加,如果已经有了,则不会添加
*
* @param dto 数据源信息
* @return 当前存在的数据源集合
*/
@Override
public Set<String> switchDataSource(DataSourceDTO dto) {
// todo 该方法需要添加线程安全保护
Set<String> currentDataSources = add(dto);
DynamicDataSourceContextHolder.push(dto.getPoolName());
return currentDataSources;
}
/**
* 添加数据源,如果已经存在同名的数据源了,则不会添加
*
* @param dto 数据源信息
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
@Override
public Set<String> add(DataSourceDTO dto) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
if (ds.getDataSources().containsKey(dto.getPoolName())) {
return ds.getDataSources().keySet();
} else {
return addDataSource(dto);
}
}
/**
* 添加数据源,如果已经存在同名的数据源了,则会覆盖
*
* @param dto 数据源信息
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
@Override
public Set<String> addAndUpdate(DataSourceDTO dto) {
return addDataSource(dto);
}
/**
* 获取当前所有数据源
*
* @return 数据源名称的集合, 用于 DynamicDataSourceContextHolder.push("数据源名称") 这样的代码中
*/
@Override
public Set<String> now() {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
return ds.getDataSources().keySet();
}
/**
* 删除数据源
*
* @param name 数据源名称
* @return 删除信息
*/
@Override
public String remove(String name) {
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
ds.removeDataSource(name);
return "删除成功";
}
private Set<String> addDataSource(DataSourceDTO dto) {
DataSourceProperty dataSourceProperty = new DataSourceProperty();
BeanUtils.copyProperties(dto, dataSourceProperty);
DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
ds.addDataSource(dto.getPoolName(), dataSource);
return ds.getDataSources().keySet();
}
}
package org.matrix.actuator; package org.matrix.actuators.httpclient;
import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaderValues;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.matrix.actuators.Actuator;
import org.matrix.config.HttpRequestConfig; import org.matrix.config.HttpRequestConfig;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
...@@ -18,7 +19,6 @@ import org.apache.http.entity.mime.MultipartEntityBuilder; ...@@ -18,7 +19,6 @@ import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.matrix.entity.httpRequest.*;
import org.matrix.exception.HttpRequestException; import org.matrix.exception.HttpRequestException;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
...@@ -40,7 +40,7 @@ import java.util.List; ...@@ -40,7 +40,7 @@ import java.util.List;
* todo 打印LOG * todo 打印LOG
* @author HuangXiahao * @author HuangXiahao
**/ **/
public class HttpClientActuator { public class HttpClientActuator implements Actuator {
HttpRequestConfig config; HttpRequestConfig config;
...@@ -48,15 +48,19 @@ public class HttpClientActuator { ...@@ -48,15 +48,19 @@ public class HttpClientActuator {
CloseableHttpClient client; CloseableHttpClient client;
private int projectId; private Long projectId;
private String env; private Long env;
public HttpClientActuator(HttpRequestConfig config, String env, int projectId) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { public HttpClientActuator(HttpRequestConfig config, Long env, Long projectId) {
this.config = config; this.config = config;
this.cookieStore = config.cookieStore(); this.cookieStore = config.cookieStore();
try {
this.client = config.client(); this.client = config.client();
} catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
this.projectId = projectId; this.projectId = projectId;
this.env = env; this.env = env;
} }
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.matrix.entity.testCase.BaseTestCaseResponseDetail; import org.matrix.actuators.usecase.BaseTestCaseResponseDetail;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
/** /**
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
......
package org.matrix.entity.httpRequest; package org.matrix.actuators.httpclient;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
......
package org.matrix.actuators.sql;
import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.matrix.actuators.usecase.CaseActuator;
import org.matrix.actuators.httpclient.HttpClientActuator;
import org.matrix.actuators.Actuator;
import org.matrix.actuators.datasource.DataSourceDTO;
import org.matrix.actuators.datasource.IDataSourceService;
import org.matrix.config.HttpRequestConfig;
import org.matrix.database.entity.DynamicVariable;
import org.matrix.database.entity.Example;
import org.matrix.database.entity.TestCase;
import org.matrix.database.service.IConnectService;
import org.matrix.database.service.IDynamicVariableService;
import org.matrix.database.service.IExampleService;
import org.matrix.database.service.ITestCaseService;
import org.matrix.actuators.httpclient.HttpRequestDetail;
import org.matrix.actuators.httpclient.HttpResponseDetail;
import org.matrix.enums.DynamicVarType;
import org.matrix.misc.GlobalException;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.matrix.enums.DynamicVarType.*;
import static org.springframework.util.CollectionUtils.isEmpty;
/**
* SqlExpParse.
* SQL表达式解析器
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/7 at 5:49 PM
* Suffering is the most powerful teacher of life.
*/
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Lazy))
public class SqlExpActuator implements Actuator {
/**
* 用于正则找出形如${id}这样的SQL变量
*/
public static final String DYNAMIC_VAR_EXP = "(\\$\\{.*})[\\[]?(.*)[]]?";
/**
* 用于正则找出形如#{id}这样的环境
*/
public static final String ENV_VAR_EXP = "(#\\{.*})";
private final JdbcTemplate jdbcTemplate;
private final IDynamicVariableService varService;
private final IExampleService envService;
private final IConnectService connectService;
private final IDataSourceService dataSourceService;
private final ITestCaseService caseService;
/**
* 解析给定的动态变量ByName
*
* @param varNameString 变量名,形如${id}这样的字符串
* @param projectId 该变量所在的项目ID
* @return 变量递归解析后的值
*/
public String parseVarByName(String varNameString, Long envId, Long projectId) {
List<SqlRegObject> varList = findDynamicVarList(varNameString);
if (varList.size() == 1) {
SqlRegObject sqlReg = varList.get(0);
DynamicVariable variable = varService.getByName(sqlReg.getVarName(), projectId)
.orElseThrow(() -> new GlobalException("没有找到name = " + sqlReg.getVarName() + " 的动态变量"));
return parseVar(envId, sqlReg.getIndex(), projectId, variable);
} else {
throw new GlobalException("varNameString 参数请一次只输入一个动态变量! 你的提供的参数为: " + varNameString);
}
}
/**
* 解析给定的动态变量ById,取的下标默认为0
*
* @param varId 动态变量ID
* @param envId 环境ID - 环境共享变量需要
* @param projectId 项目id,防止SQL表达式中带的嵌合动态变量名字重复
* @return 变量递归解析后的值
*/
public String parseVarById(Long varId, Long envId, Long projectId) {
DynamicVariable dynamicVar = Optional.of(varService.getById(varId))
.orElseThrow(() -> new GlobalException(String.format("没有找到ID = %d 的动态变量", varId)))
.parseSqlDetail();
return parseVar(envId, 0, projectId, dynamicVar);
}
private String parseVar(Long envId, Integer takenIndex, Long projectId, DynamicVariable dynamicVar) {
DynamicVarType varType = dynamicVar.getType();
log.info("[SQL解析器] 当前解析的动态变量是: {}", JSON.toJSONString(dynamicVar));
// 1.如果是常量则直接返回
if (varType == CONSTANT_VARIABLE) {
return dynamicVar.getDetail();
}
// 2.如果是SQL变量,则需要解析SQL
if (varType == SQL_VARIABLE) {
// 首先替换掉#{id}这类的共享变量(如果有的话)
String sqlExp = dynamicVar.getSqlExpDetail().getSqlExp();
sqlExp = replaceEnvVar(sqlExp, envId);
List<SqlRegObject> dynamicVarList = findDynamicVarList(dynamicVar.getDetail());
// 解析SQL表达式,判断是可以直接执行的SQL还是需要再递归解析动态变量
if (isEmpty(dynamicVarList)) {
// 如果查到的动态变量列表为空,则直接执行SQL
List<Map<String, Object>> resultList = runSql(dynamicVar, envId);
return takenResultString(resultList, dynamicVar.getTakenField(), Math.toIntExact(takenIndex));
} else {
// 如果还存在动态变量,则继续递归解析
for (SqlRegObject sqlReg : dynamicVarList) {
DynamicVariable recVar = varService.getByName(sqlReg.getVarName(), projectId)
.orElseThrow(() -> new GlobalException(
String.format("没有找到项目id = %d 下,name = %s的变量", projectId, sqlReg.getVarName())));
String calculatedValue = parseVar(envId, sqlReg.getIndex(), projectId, recVar);
sqlExp = sqlExp.replaceAll(sqlReg.getVarName(), calculatedValue);
}
// 将里面的动态变量全部计算完替换之后返回出去
return sqlExp;
}
}
// 3.如果是HTTP接口,则调用http接口
if (varType == HTTP_VARIABLE) {
HttpClientActuator httpClient = new HttpClientActuator(new HttpRequestConfig(), envId, projectId);
HttpRequestDetail httpRequestDetail = JSON.parseObject(dynamicVar.getDetail(), HttpRequestDetail.class);
return httpClient.sendHttpRequest(httpRequestDetail).getResponseBody();
}
// 4.如果是测试用例,则调用测试用例执行器
if (varType == CASE_VARIABLE) {
CaseActuator caseActuator = new CaseActuator(envId, projectId);
long caseId = Long.parseLong(dynamicVar.getDetail());
TestCase testCase = Optional.of(caseService.getById(caseId))
.orElseThrow(() -> new GlobalException(String.format("没有找到id = %d 的TestCase", caseId)));
HttpResponseDetail responseDetail = (HttpResponseDetail) caseActuator.executeTestCase(testCase).getBaseTestCaseRequestDetail();
return responseDetail.getResponseBody();
}
return "";
}
/**
* @param resultList 初始查询的结果集(表)
* @param takenField 要取用的字段(列)
* @param index 要取用的行数,从0开始算第一行
* @return 取到的字段的结果
* @throws GlobalException 如果找不到对应行列的数据(index与takenField),会抛出这个异常,建议把上层的SQL语句也返回到信息里
*/
private String takenResultString(List<Map<String, Object>> resultList, String takenField, int index) throws GlobalException {
Map<String, Object> resultMap = Optional.of(resultList.get(index))
.orElseThrow(() -> new GlobalException(String.format("没有在 %s 中找到第 %d 行 的数据",
JSON.toJSON(resultList), index + 1)));
return Optional.of(resultMap.get(takenField))
.orElseThrow(() -> new GlobalException(String.format("%s 数据集中不存在属性名为 %s 的字段",
JSON.toJSON(resultMap), takenField))).toString();
}
/**
* 替换掉SQL表达式中的形如#{id}这样的环境共享变量
*
* @param sqlExp sql表达式
* @param envId 环境共享变量
* @return 替换后的字符串
*/
private String replaceEnvVar(String sqlExp, Long envId) {
// SQL表达式首先尝试替换掉形如#{name}的共享环境变量
Example env = Optional.of(envService.getById(envId))
.orElseThrow(() -> new GlobalException("没有找到对应ID的example(env)对象,id = " + envId));
Map<String, String> envMap = env.getVariable();
List<String> envList = ReUtil.findAll(ENV_VAR_EXP, sqlExp, 0, new ArrayList<>());
// 到对应env的变量池里找到值替换掉
for (String key : envList) {
if (envMap.containsKey(key)) {
sqlExp = sqlExp.replaceAll(key, envMap.get(key));
} else {
throw new GlobalException(String.format("id = %d 的环境(用例)表里没有key = %s 的数值,当前环境的变量池 = %s",
envId, key, envMap));
}
}
return sqlExp;
}
/**
* 执行一段SQL,该SQL表达式必须要是可以直接执行的语句
*
* @param dynamicVar 动态变量对象(必须是可以直接执行SQL 例`select * from user where id = 5`)
* @param envId 环境ID
* @return 运行SQL后取完数值的结果, 是一张数据表, 以LIST<MAP>的形式呈现
*/
private List<Map<String, Object>> runSql(DynamicVariable dynamicVar, Long envId) {
String sqlExp = dynamicVar.getSqlExpDetail().getSqlExp();
Long connectId = dynamicVar.getSqlExpDetail().getPoolId();
DataSourceDTO dataSourceDTO = Optional.of(connectService.getById(connectId))
.orElseThrow(() -> new GlobalException(String.format("没有找到id = %d 的连接池connect对象", connectId)))
.toDataSourceDTO();
// 替换环境共享变量
sqlExp = replaceEnvVar(sqlExp, envId);
// 校验dynamicVar里的detail是否是可以直接执行的SQL
if (dynamicVar.getType() == SQL_VARIABLE && findDynamicVarList(sqlExp).size() == 0) {
// 切换数据源,执行SQL,获取数值
dataSourceService.switchDataSource(dataSourceDTO);
return jdbcTemplate.queryForList(sqlExp);
} else {
throw new GlobalException(String.format("动态变量的类型必须要是SQL类型且DETAIL内的SQL语句必须为元SQL语句,当前type : %s , 当前detail : %s",
dynamicVar.getType(), sqlExp));
}
}
/**
* 将含有动态变量的字符串语句中的形如{$id}动态变量语句给找到
* 如果使用者写了诸如{$id}[1]的下标,则会使用下标值,否则使用默认值0
*
* @param dynamicString SQL字符串或者动态变量
* @return SQL动态变量对象, 分别找出其中的变量名与对应的下标序列值(默认为0)
*/
private List<SqlRegObject> findDynamicVarList(String dynamicString) {
Pattern pattern = Pattern.compile(DYNAMIC_VAR_EXP);
Matcher matcher = pattern.matcher(dynamicString);
List<SqlRegObject> sqlRegObjects = new ArrayList<>();
// 如果使用者写了诸如{$id}[1]的下标,则会使用下标值,否则使用默认值0
while (matcher.find()) {
if (matcher.groupCount() == 1) {
sqlRegObjects.add(new SqlRegObject(matcher.group(0), 0));
} else if (matcher.groupCount() == 2) {
sqlRegObjects.add(new SqlRegObject(matcher.group(0), Integer.parseInt(matcher.group(1))));
} else {
throw new GlobalException("给定的动态变量/SQL表达式 不符合语法,给定的值是: " + dynamicString);
}
}
return sqlRegObjects;
}
}
package org.matrix.actuators.sql;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* SqlExpDetail.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 5:08 PM
* Suffering is the most powerful teacher of life.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SqlExpDetail {
/**
* 连接池ID {@link org.matrix.database.entity.Connect} 这张表的主键
*/
private Long poolId;
/**
* sql 表达式 形如 select * from table where id = #{id}
*/
private String sqlExp;
}
package org.matrix.actuators.sql;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* SqlRegObject.
* SQL语法的正则取值对象
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 2:30 PM
* Suffering is the most powerful teacher of life.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SqlRegObject {
/**
* 动态变量名
*/
private String varName;
/**
* 结果下标,默认为0
*/
private int index = 0;
}
package org.matrix.actuator; package org.matrix.actuators.usecase;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import org.matrix.actuators.Actuator;
import org.matrix.actuators.checkpoint.CheckPointActuator;
import org.matrix.actuators.httpclient.HttpClientActuator;
import org.matrix.config.HttpRequestConfig; import org.matrix.config.HttpRequestConfig;
import org.matrix.database.entity.TestCase; import org.matrix.database.entity.TestCase;
import org.matrix.entity.checkPoint.CheckPoint; import org.matrix.actuators.checkpoint.CheckPoint;
import org.matrix.entity.checkPoint.CheckPointResult; import org.matrix.actuators.checkpoint.CheckPointResult;
import org.matrix.entity.httpRequest.HttpRequestDetail; import org.matrix.actuators.httpclient.HttpRequestDetail;
import org.matrix.entity.httpRequest.HttpResponseDetail; import org.matrix.actuators.httpclient.HttpResponseDetail;
import org.matrix.entity.testCase.BaseTestCaseResponseDetail;
import org.matrix.entity.testCase.TestCaseExecuteResult;
import org.matrix.entity.testCase.TestCaseTypeEnum;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.function.Function;
/** /**
* 测试用例执行器 * 测试用例执行器
...@@ -22,11 +17,11 @@ import java.util.function.Function; ...@@ -22,11 +17,11 @@ import java.util.function.Function;
* *
* @author huangxiahao * @author huangxiahao
*/ */
public class TestCaseActuator { public class CaseActuator implements Actuator {
private int projectId; private Long projectId;
private String env; private Long envId;
private CheckPointActuator checkPointActuator; private CheckPointActuator checkPointActuator;
...@@ -34,11 +29,11 @@ public class TestCaseActuator { ...@@ -34,11 +29,11 @@ public class TestCaseActuator {
private final String baseJsPath = "baseJs.js"; private final String baseJsPath = "baseJs.js";
public TestCaseActuator(String env, int projectId) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException { public CaseActuator(Long envId, Long projectId) {
this.projectId = projectId; this.projectId = projectId;
this.env = env; this.envId = envId;
checkPointActuator = new CheckPointActuator(baseJsPath, env, projectId); checkPointActuator = new CheckPointActuator(baseJsPath, envId, projectId);
httpClientActuator = new HttpClientActuator(new HttpRequestConfig(), env, projectId); httpClientActuator = new HttpClientActuator(new HttpRequestConfig(), envId, projectId);
} }
/** /**
......
package org.matrix.entity.testCase; package org.matrix.actuators.usecase;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.matrix.entity.checkPoint.CheckPointResult; import org.matrix.actuators.checkpoint.CheckPointResult;
/** /**
* @author huangxiahao * @author huangxiahao
......
package org.matrix.entity.testCase; package org.matrix.actuators.usecase;
/** /**
* @author huangxiahao * @author huangxiahao
......
...@@ -24,10 +24,6 @@ import lombok.NoArgsConstructor; ...@@ -24,10 +24,6 @@ import lombok.NoArgsConstructor;
@ApiModel(value = "Action对象", description = "动作") @ApiModel(value = "Action对象", description = "动作")
public class Action extends BaseEntity { public class Action extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("名称") @ApiModelProperty("名称")
private String name; private String name;
......
...@@ -11,7 +11,6 @@ import lombok.AllArgsConstructor; ...@@ -11,7 +11,6 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
......
...@@ -2,10 +2,13 @@ package org.matrix.database.entity; ...@@ -2,10 +2,13 @@ package org.matrix.database.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import org.matrix.database.entity.BaseEntity;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.matrix.actuators.datasource.DataSourceDTO;
/** /**
* <p> * <p>
...@@ -22,10 +25,6 @@ import lombok.*; ...@@ -22,10 +25,6 @@ import lombok.*;
@ApiModel(value = "Connect对象", description = "") @ApiModel(value = "Connect对象", description = "")
public class Connect extends BaseEntity { public class Connect extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("名称") @ApiModelProperty("名称")
private String name; private String name;
...@@ -41,5 +40,14 @@ public class Connect extends BaseEntity { ...@@ -41,5 +40,14 @@ public class Connect extends BaseEntity {
@ApiModelProperty("所用驱动") @ApiModelProperty("所用驱动")
private String driver; private String driver;
/**
* 转化为数据源DTO对象
*
* @return {@link DataSourceDTO}
*/
public DataSourceDTO toDataSourceDTO() {
return new DataSourceDTO("name", driver, url, username, password);
}
} }
package org.matrix.database.entity; package org.matrix.database.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import org.matrix.database.entity.BaseEntity;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.matrix.actuators.sql.SqlExpDetail;
import org.matrix.enums.DynamicVarType; import org.matrix.enums.DynamicVarType;
import org.matrix.misc.GlobalException;
/** /**
* <p> * <p>
...@@ -25,10 +29,6 @@ import org.matrix.enums.DynamicVarType; ...@@ -25,10 +29,6 @@ import org.matrix.enums.DynamicVarType;
@ApiModel(value = "DynamicVariable对象", description = "") @ApiModel(value = "DynamicVariable对象", description = "")
public class DynamicVariable extends BaseEntity { public class DynamicVariable extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("所属项目") @ApiModelProperty("所属项目")
private Integer projectId; private Integer projectId;
...@@ -47,5 +47,19 @@ public class DynamicVariable extends BaseEntity { ...@@ -47,5 +47,19 @@ public class DynamicVariable extends BaseEntity {
@ApiModelProperty("详细内容") @ApiModelProperty("详细内容")
private String detail; private String detail;
@ApiModelProperty(hidden = true)
@TableField(exist = false)
private SqlExpDetail sqlExpDetail;
public DynamicVariable parseSqlDetail() {
if (type == DynamicVarType.SQL_VARIABLE) {
this.sqlExpDetail = JSON.parseObject(this.detail, SqlExpDetail.class);
return this;
} else {
throw new GlobalException("只有SQL类型的变量才能解析详细内容");
}
}
} }
package org.matrix.database.entity; package org.matrix.database.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import org.matrix.database.entity.BaseEntity; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.Map;
/** /**
* <p> * <p>
...@@ -20,12 +27,9 @@ import lombok.*; ...@@ -20,12 +27,9 @@ import lombok.*;
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ApiModel(value = "Example对象", description = "实例表,项目对应的环境实例,例如:实验室环境,开发环境等") @ApiModel(value = "Example对象", description = "实例表,项目对应的环境实例,例如:实验室环境,开发环境等")
@TableName(autoResultMap = true)
public class Example extends BaseEntity { public class Example extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("实例名称") @ApiModelProperty("实例名称")
private String name; private String name;
...@@ -36,7 +40,8 @@ public class Example extends BaseEntity { ...@@ -36,7 +40,8 @@ public class Example extends BaseEntity {
private Integer projectId; private Integer projectId;
@ApiModelProperty("静态变量,以JSON的形式存储,例如({\"name\":\"张三\"})") @ApiModelProperty("静态变量,以JSON的形式存储,例如({\"name\":\"张三\"})")
private String variable; @TableField(typeHandler = FastjsonTypeHandler.class)
private Map<String, String> variable;
@ApiModelProperty("ip,例如(http:www.abc.com)") @ApiModelProperty("ip,例如(http:www.abc.com)")
private String ip; private String ip;
......
...@@ -22,10 +22,6 @@ import lombok.*; ...@@ -22,10 +22,6 @@ import lombok.*;
@ApiModel(value = "Move对象", description = "") @ApiModel(value = "Move对象", description = "")
public class Move extends BaseEntity { public class Move extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("名称") @ApiModelProperty("名称")
private String name; private String name;
......
...@@ -22,10 +22,6 @@ import lombok.*; ...@@ -22,10 +22,6 @@ import lombok.*;
@ApiModel(value = "Project对象", description = "") @ApiModel(value = "Project对象", description = "")
public class Project extends BaseEntity { public class Project extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("名称") @ApiModelProperty("名称")
private String name; private String name;
......
...@@ -24,10 +24,6 @@ import lombok.*; ...@@ -24,10 +24,6 @@ import lombok.*;
@ApiModel(value = "TestCase对象", description = "") @ApiModel(value = "TestCase对象", description = "")
public class TestCase extends BaseEntity { public class TestCase extends BaseEntity {
@ApiModelProperty("ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty("名称") @ApiModelProperty("名称")
private String name; private String name;
......
...@@ -13,4 +13,6 @@ import com.baomidou.mybatisplus.extension.service.IService; ...@@ -13,4 +13,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface IConnectService extends IService<Connect> { public interface IConnectService extends IService<Connect> {
} }
package org.matrix.database.service; package org.matrix.database.service;
import org.matrix.database.entity.DynamicVariable;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import org.matrix.database.entity.DynamicVariable;
import java.util.Optional;
/** /**
* <p> * <p>
...@@ -13,4 +15,13 @@ import com.baomidou.mybatisplus.extension.service.IService; ...@@ -13,4 +15,13 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface IDynamicVariableService extends IService<DynamicVariable> { public interface IDynamicVariableService extends IService<DynamicVariable> {
/**
* 根据变量名称获取变量
*
* @param name 变量名
* @param projectId 项目id
* @return 变量
*/
Optional<DynamicVariable> getByName(String name, Long projectId);
} }
package org.matrix.database.service.impl; package org.matrix.database.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.matrix.database.entity.DynamicVariable; import org.matrix.database.entity.DynamicVariable;
import org.matrix.database.mapper.DynamicVariableMapper; import org.matrix.database.mapper.DynamicVariableMapper;
import org.matrix.database.service.IDynamicVariableService; import org.matrix.database.service.IDynamicVariableService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Optional;
/** /**
* <p> * <p>
* 服务实现类 * 服务实现类
...@@ -17,4 +20,23 @@ import org.springframework.stereotype.Service; ...@@ -17,4 +20,23 @@ import org.springframework.stereotype.Service;
@Service @Service
public class DynamicVariableServiceImpl extends ServiceImpl<DynamicVariableMapper, DynamicVariable> implements IDynamicVariableService { public class DynamicVariableServiceImpl extends ServiceImpl<DynamicVariableMapper, DynamicVariable> implements IDynamicVariableService {
private final DynamicVariableMapper mapper;
public DynamicVariableServiceImpl(DynamicVariableMapper dynamicVariableMapper) {
this.mapper = dynamicVariableMapper;
}
/**
* 根据变量名称获取变量
*
* @param name 变量名
* @param projectId 项目id
* @return 变量
*/
@Override
public Optional<DynamicVariable> getByName(String name, Long projectId) {
return Optional.ofNullable(mapper.selectOne(Wrappers.lambdaUpdate(DynamicVariable.class)
.eq(DynamicVariable::getName, name)
.eq(DynamicVariable::getProjectId, projectId)));
}
} }
package org.matrix.misc;
/**
* GlobalException.
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 12:53 PM
* Suffering is the most powerful teacher of life.
*/
public class GlobalException extends RuntimeException {
public GlobalException(String message) {
super(message);
}
public GlobalException(String message, Throwable cause) {
super(message, cause);
}
public GlobalException(Throwable cause) {
super(cause);
}
public GlobalException() {
super();
}
}
package org.matrix.misc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* GlobalExceptionHandler. 全局异常处理类
*
* @author Matrix <xhyrzldf@gmail.com>
* @since 2022/1/19 at 12:54 PM
* Suffering is the most powerful teacher of life.
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 报错信息都会通过这个方法处理并通过统一的返回方式进行返回
*
* @param e 报错信息
*/
@ResponseBody
@ExceptionHandler(Exception.class)
public ResponseEntity<String> errorMessage(Exception e) {
log.error("[其他异常] {}", e.getMessage());
return ResponseEntity.status(500).body("服务器异常" + e.getMessage());
}
/**
* 业务错误
*
* @param e 报错信息
*/
@ResponseBody
@ExceptionHandler(GlobalException.class)
public ResponseEntity<String> errorMessage(GlobalException e) {
log.warn("[自定义异常]" + e.getMessage());
return ResponseEntity.status(400).body(e.getMessage());
}
}
package org.matrix.entity; package org.matrix.testNg;
/** /**
* DataProvider. * DataProvider.
......
...@@ -45,7 +45,7 @@ public class CodeGenerator { ...@@ -45,7 +45,7 @@ public class CodeGenerator {
.enableLombok() .enableLombok()
.disableSerialVersionUID() // 禁用序列化 .disableSerialVersionUID() // 禁用序列化
.superClass("org.matrix.database.entity.BaseEntity") // 自定义实体父类 .superClass("org.matrix.database.entity.BaseEntity") // 自定义实体父类
.addIgnoreColumns("create_time", "update_time"); // 忽略生成的字段 .addIgnoreColumns("create_time", "update_time", "id"); // 忽略生成的字段
}) })
.templateConfig(builder -> { .templateConfig(builder -> {
builder.disable(TemplateType.CONTROLLER, TemplateType.ENTITY, TemplateType.MAPPER) // 禁用模板 builder.disable(TemplateType.CONTROLLER, TemplateType.ENTITY, TemplateType.MAPPER) // 禁用模板
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
</properties> </properties>
<!-- 子模块版本以及依赖的版本管理--> <!-- 子模块版本以及依赖的版本管理-->
...@@ -59,6 +59,18 @@ ...@@ -59,6 +59,18 @@
<!-- 全局依赖--> <!-- 全局依赖-->
<dependencies> <dependencies>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
...@@ -66,10 +78,11 @@ ...@@ -66,10 +78,11 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- fastjson -->
<dependency> <dependency>
<groupId>org.modelmapper</groupId> <groupId>com.alibaba</groupId>
<artifactId>modelmapper</artifactId> <artifactId>fastjson</artifactId>
<version>2.4.5</version> <version>1.2.79</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论