feat(系统设置): 服务集成插件化

This commit is contained in:
chenjianxing 2022-11-11 17:29:24 +08:00 committed by jianxing
parent 122d0fbc00
commit debc072829
33 changed files with 1216 additions and 820 deletions

View File

@ -1,9 +0,0 @@
package io.metersphere.api.dto.plugin;
import io.metersphere.plugin.core.ui.PluginResource;
import lombok.Data;
@Data
public class PluginResourceDTO extends PluginResource {
private String entry;
}

View File

@ -1,409 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.PluginMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.Plugin">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="plugin_id" jdbcType="VARCHAR" property="pluginId" />
<result column="script_id" jdbcType="VARCHAR" property="scriptId" />
<result column="jmeter_clazz" jdbcType="VARCHAR" property="jmeterClazz" />
<result column="clazz_name" jdbcType="VARCHAR" property="clazzName" />
<result column="source_path" jdbcType="VARCHAR" property="sourcePath" />
<result column="source_name" jdbcType="VARCHAR" property="sourceName" />
<result column="exec_entry" jdbcType="VARCHAR" property="execEntry" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user_id" jdbcType="VARCHAR" property="createUserId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.PluginWithBLOBs">
<result column="form_option" jdbcType="LONGVARCHAR" property="formOption" />
<result column="form_script" jdbcType="LONGVARCHAR" property="formScript" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, `name`, plugin_id, script_id, jmeter_clazz, clazz_name, source_path, source_name,
exec_entry, create_time, update_time, create_user_id
</sql>
<sql id="Blob_Column_List">
form_option, form_script
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.PluginExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.PluginExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from plugin
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from plugin
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.PluginExample">
delete from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin (id, `name`, plugin_id,
script_id, jmeter_clazz, clazz_name,
source_path, source_name, exec_entry,
create_time, update_time, create_user_id,
form_option, form_script)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR},
#{scriptId,jdbcType=VARCHAR}, #{jmeterClazz,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR},
#{sourcePath,jdbcType=VARCHAR}, #{sourceName,jdbcType=VARCHAR}, #{execEntry,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUserId,jdbcType=VARCHAR},
#{formOption,jdbcType=LONGVARCHAR}, #{formScript,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="name != null">
`name`,
</if>
<if test="pluginId != null">
plugin_id,
</if>
<if test="scriptId != null">
script_id,
</if>
<if test="jmeterClazz != null">
jmeter_clazz,
</if>
<if test="clazzName != null">
clazz_name,
</if>
<if test="sourcePath != null">
source_path,
</if>
<if test="sourceName != null">
source_name,
</if>
<if test="execEntry != null">
exec_entry,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="createUserId != null">
create_user_id,
</if>
<if test="formOption != null">
form_option,
</if>
<if test="formScript != null">
form_script,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="name != null">
#{name,jdbcType=VARCHAR},
</if>
<if test="pluginId != null">
#{pluginId,jdbcType=VARCHAR},
</if>
<if test="scriptId != null">
#{scriptId,jdbcType=VARCHAR},
</if>
<if test="jmeterClazz != null">
#{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
#{clazzName,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null">
#{sourcePath,jdbcType=VARCHAR},
</if>
<if test="sourceName != null">
#{sourceName,jdbcType=VARCHAR},
</if>
<if test="execEntry != null">
#{execEntry,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="createUserId != null">
#{createUserId,jdbcType=VARCHAR},
</if>
<if test="formOption != null">
#{formOption,jdbcType=LONGVARCHAR},
</if>
<if test="formScript != null">
#{formScript,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.PluginExample" resultType="java.lang.Long">
select count(*) from plugin
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update plugin
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.pluginId != null">
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
</if>
<if test="record.scriptId != null">
script_id = #{record.scriptId,jdbcType=VARCHAR},
</if>
<if test="record.jmeterClazz != null">
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="record.clazzName != null">
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
</if>
<if test="record.sourcePath != null">
source_path = #{record.sourcePath,jdbcType=VARCHAR},
</if>
<if test="record.sourceName != null">
source_name = #{record.sourceName,jdbcType=VARCHAR},
</if>
<if test="record.execEntry != null">
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.createUserId != null">
create_user_id = #{record.createUserId,jdbcType=VARCHAR},
</if>
<if test="record.formOption != null">
form_option = #{record.formOption,jdbcType=LONGVARCHAR},
</if>
<if test="record.formScript != null">
form_script = #{record.formScript,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update plugin
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR},
form_option = #{record.formOption,jdbcType=LONGVARCHAR},
form_script = #{record.formScript,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update plugin
set id = #{record.id,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
update plugin
<set>
<if test="name != null">
`name` = #{name,jdbcType=VARCHAR},
</if>
<if test="pluginId != null">
plugin_id = #{pluginId,jdbcType=VARCHAR},
</if>
<if test="scriptId != null">
script_id = #{scriptId,jdbcType=VARCHAR},
</if>
<if test="jmeterClazz != null">
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null">
clazz_name = #{clazzName,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null">
source_path = #{sourcePath,jdbcType=VARCHAR},
</if>
<if test="sourceName != null">
source_name = #{sourceName,jdbcType=VARCHAR},
</if>
<if test="execEntry != null">
exec_entry = #{execEntry,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="createUserId != null">
create_user_id = #{createUserId,jdbcType=VARCHAR},
</if>
<if test="formOption != null">
form_option = #{formOption,jdbcType=LONGVARCHAR},
</if>
<if test="formScript != null">
form_script = #{formScript,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
update plugin
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR},
form_option = #{formOption,jdbcType=LONGVARCHAR},
form_script = #{formScript,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.Plugin">
update plugin
set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -1,8 +1,7 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import lombok.Data;
@Data @Data
public class Plugin implements Serializable { public class Plugin implements Serializable {
@ -14,10 +13,10 @@ public class Plugin implements Serializable {
private String scriptId; private String scriptId;
private String jmeterClazz;
private String clazzName; private String clazzName;
private String jmeterClazz;
private String sourcePath; private String sourcePath;
private String sourceName; private String sourceName;
@ -30,5 +29,9 @@ public class Plugin implements Serializable {
private String createUserId; private String createUserId;
private Boolean xpack;
private String scenario;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -384,76 +384,6 @@ public class PluginExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andJmeterClazzIsNull() {
addCriterion("jmeter_clazz is null");
return (Criteria) this;
}
public Criteria andJmeterClazzIsNotNull() {
addCriterion("jmeter_clazz is not null");
return (Criteria) this;
}
public Criteria andJmeterClazzEqualTo(String value) {
addCriterion("jmeter_clazz =", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotEqualTo(String value) {
addCriterion("jmeter_clazz <>", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThan(String value) {
addCriterion("jmeter_clazz >", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThanOrEqualTo(String value) {
addCriterion("jmeter_clazz >=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThan(String value) {
addCriterion("jmeter_clazz <", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThanOrEqualTo(String value) {
addCriterion("jmeter_clazz <=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLike(String value) {
addCriterion("jmeter_clazz like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotLike(String value) {
addCriterion("jmeter_clazz not like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzIn(List<String> values) {
addCriterion("jmeter_clazz in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotIn(List<String> values) {
addCriterion("jmeter_clazz not in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzBetween(String value1, String value2) {
addCriterion("jmeter_clazz between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotBetween(String value1, String value2) {
addCriterion("jmeter_clazz not between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andClazzNameIsNull() { public Criteria andClazzNameIsNull() {
addCriterion("clazz_name is null"); addCriterion("clazz_name is null");
return (Criteria) this; return (Criteria) this;
@ -524,6 +454,76 @@ public class PluginExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andJmeterClazzIsNull() {
addCriterion("jmeter_clazz is null");
return (Criteria) this;
}
public Criteria andJmeterClazzIsNotNull() {
addCriterion("jmeter_clazz is not null");
return (Criteria) this;
}
public Criteria andJmeterClazzEqualTo(String value) {
addCriterion("jmeter_clazz =", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotEqualTo(String value) {
addCriterion("jmeter_clazz <>", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThan(String value) {
addCriterion("jmeter_clazz >", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzGreaterThanOrEqualTo(String value) {
addCriterion("jmeter_clazz >=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThan(String value) {
addCriterion("jmeter_clazz <", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLessThanOrEqualTo(String value) {
addCriterion("jmeter_clazz <=", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzLike(String value) {
addCriterion("jmeter_clazz like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotLike(String value) {
addCriterion("jmeter_clazz not like", value, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzIn(List<String> values) {
addCriterion("jmeter_clazz in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotIn(List<String> values) {
addCriterion("jmeter_clazz not in", values, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzBetween(String value1, String value2) {
addCriterion("jmeter_clazz between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andJmeterClazzNotBetween(String value1, String value2) {
addCriterion("jmeter_clazz not between", value1, value2, "jmeterClazz");
return (Criteria) this;
}
public Criteria andSourcePathIsNull() { public Criteria andSourcePathIsNull() {
addCriterion("source_path is null"); addCriterion("source_path is null");
return (Criteria) this; return (Criteria) this;
@ -923,6 +923,136 @@ public class PluginExample {
addCriterion("create_user_id not between", value1, value2, "createUserId"); addCriterion("create_user_id not between", value1, value2, "createUserId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andXpackIsNull() {
addCriterion("xpack is null");
return (Criteria) this;
}
public Criteria andXpackIsNotNull() {
addCriterion("xpack is not null");
return (Criteria) this;
}
public Criteria andXpackEqualTo(Boolean value) {
addCriterion("xpack =", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackNotEqualTo(Boolean value) {
addCriterion("xpack <>", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackGreaterThan(Boolean value) {
addCriterion("xpack >", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackGreaterThanOrEqualTo(Boolean value) {
addCriterion("xpack >=", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackLessThan(Boolean value) {
addCriterion("xpack <", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackLessThanOrEqualTo(Boolean value) {
addCriterion("xpack <=", value, "xpack");
return (Criteria) this;
}
public Criteria andXpackIn(List<Boolean> values) {
addCriterion("xpack in", values, "xpack");
return (Criteria) this;
}
public Criteria andXpackNotIn(List<Boolean> values) {
addCriterion("xpack not in", values, "xpack");
return (Criteria) this;
}
public Criteria andXpackBetween(Boolean value1, Boolean value2) {
addCriterion("xpack between", value1, value2, "xpack");
return (Criteria) this;
}
public Criteria andXpackNotBetween(Boolean value1, Boolean value2) {
addCriterion("xpack not between", value1, value2, "xpack");
return (Criteria) this;
}
public Criteria andScenarioIsNull() {
addCriterion("scenario is null");
return (Criteria) this;
}
public Criteria andScenarioIsNotNull() {
addCriterion("scenario is not null");
return (Criteria) this;
}
public Criteria andScenarioEqualTo(String value) {
addCriterion("scenario =", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioNotEqualTo(String value) {
addCriterion("scenario <>", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioGreaterThan(String value) {
addCriterion("scenario >", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioGreaterThanOrEqualTo(String value) {
addCriterion("scenario >=", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioLessThan(String value) {
addCriterion("scenario <", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioLessThanOrEqualTo(String value) {
addCriterion("scenario <=", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioLike(String value) {
addCriterion("scenario like", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioNotLike(String value) {
addCriterion("scenario not like", value, "scenario");
return (Criteria) this;
}
public Criteria andScenarioIn(List<String> values) {
addCriterion("scenario in", values, "scenario");
return (Criteria) this;
}
public Criteria andScenarioNotIn(List<String> values) {
addCriterion("scenario not in", values, "scenario");
return (Criteria) this;
}
public Criteria andScenarioBetween(String value1, String value2) {
addCriterion("scenario between", value1, value2, "scenario");
return (Criteria) this;
}
public Criteria andScenarioNotBetween(String value1, String value2) {
addCriterion("scenario not between", value1, value2, "scenario");
return (Criteria) this;
}
} }
public static class Criteria extends GeneratedCriteria { public static class Criteria extends GeneratedCriteria {

View File

@ -1,11 +1,10 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import java.io.Serializable;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)

View File

@ -105,10 +105,21 @@
:default-open="defaultOpen" :default-open="defaultOpen"
:data="data" :disabled="disabled"/> :data="data" :disabled="disabled"/>
<el-input class="custom-with" <el-input v-else-if="data.type === 'password'"
@input="handleChange" v-model="data[prop]"
class="custom-with"
auto-complete="new-password"
show-password
:disabled="disabled"
@input="handleChange"/>
<el-input v-else
v-model="data[prop]"
class="custom-with"
maxlength="450"
show-word-limit
:disabled="disabled" :disabled="disabled"
v-else v-model="data[prop]" maxlength="450" show-word-limit/> @input="handleChange"/>
</span> </span>

View File

@ -1256,6 +1256,7 @@ const message = {
jar_file: "Jar Package", jar_file: "Jar Package",
jar_manage: "JAR package management", jar_manage: "JAR package management",
delete_tip: "The deletion takes effect after the service is restarted", delete_tip: "The deletion takes effect after the service is restarted",
delete_confirm: "Confirm to delete the plugin",
file_exist: "The name already exists in the project", file_exist: "The name already exists in the project",
upload_limit_size: "Upload file size cannot exceed 30MB!", upload_limit_size: "Upload file size cannot exceed 30MB!",
upload_limit_size_warn: "Upload file size cannot exceed {0} MB!", upload_limit_size_warn: "Upload file size cannot exceed {0} MB!",

View File

@ -1266,6 +1266,7 @@ const message = {
jar_file: "jar包", jar_file: "jar包",
jar_manage: "JAR包管理", jar_manage: "JAR包管理",
delete_tip: "删除需重启服务后生效", delete_tip: "删除需重启服务后生效",
delete_confirm: "确认删除插件",
file_exist: "该项目下已存在该jar包", file_exist: "该项目下已存在该jar包",
upload_limit_size: "上传文件大小不能超过 30MB!", upload_limit_size: "上传文件大小不能超过 30MB!",
upload_limit_size_warn: "上传文件大小不能超过 {0} MB!", upload_limit_size_warn: "上传文件大小不能超过 {0} MB!",

View File

@ -1264,6 +1264,7 @@ const message = {
jar_manage: "JAR包管理", jar_manage: "JAR包管理",
delete_tip: "刪除需重啟服務後生效", delete_tip: "刪除需重啟服務後生效",
file_exist: "該項目下已存在該jar包", file_exist: "該項目下已存在該jar包",
delete_confirm: "確認刪除插件",
upload_limit_size: "上傳文件大小不能超過 30MB!", upload_limit_size: "上傳文件大小不能超過 30MB!",
upload_limit_size_warn: "上傳文件大小不能超過 {0} MB!", upload_limit_size_warn: "上傳文件大小不能超過 {0} MB!",
upload_limit: "上傳文件大小不能超過", upload_limit: "上傳文件大小不能超過",

View File

@ -3,9 +3,8 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.Plugin; import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample; import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs; import io.metersphere.base.domain.PluginWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface PluginMapper { public interface PluginMapper {
long countByExample(PluginExample example); long countByExample(PluginExample example);

View File

@ -6,14 +6,16 @@
<result column="name" jdbcType="VARCHAR" property="name" /> <result column="name" jdbcType="VARCHAR" property="name" />
<result column="plugin_id" jdbcType="VARCHAR" property="pluginId" /> <result column="plugin_id" jdbcType="VARCHAR" property="pluginId" />
<result column="script_id" jdbcType="VARCHAR" property="scriptId" /> <result column="script_id" jdbcType="VARCHAR" property="scriptId" />
<result column="jmeter_clazz" jdbcType="VARCHAR" property="jmeterClazz" />
<result column="clazz_name" jdbcType="VARCHAR" property="clazzName" /> <result column="clazz_name" jdbcType="VARCHAR" property="clazzName" />
<result column="jmeter_clazz" jdbcType="VARCHAR" property="jmeterClazz" />
<result column="source_path" jdbcType="VARCHAR" property="sourcePath" /> <result column="source_path" jdbcType="VARCHAR" property="sourcePath" />
<result column="source_name" jdbcType="VARCHAR" property="sourceName" /> <result column="source_name" jdbcType="VARCHAR" property="sourceName" />
<result column="exec_entry" jdbcType="VARCHAR" property="execEntry" /> <result column="exec_entry" jdbcType="VARCHAR" property="execEntry" />
<result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" /> <result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="create_user_id" jdbcType="VARCHAR" property="createUserId" /> <result column="create_user_id" jdbcType="VARCHAR" property="createUserId" />
<result column="xpack" jdbcType="BIT" property="xpack" />
<result column="scenario" jdbcType="VARCHAR" property="scenario" />
</resultMap> </resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.PluginWithBLOBs"> <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.PluginWithBLOBs">
<result column="form_option" jdbcType="LONGVARCHAR" property="formOption" /> <result column="form_option" jdbcType="LONGVARCHAR" property="formOption" />
@ -78,8 +80,8 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, `name`, plugin_id, script_id, jmeter_clazz, clazz_name, source_path, source_name, id, `name`, plugin_id, script_id, clazz_name, jmeter_clazz, source_path, source_name,
exec_entry, create_time, update_time, create_user_id exec_entry, create_time, update_time, create_user_id, xpack, scenario
</sql> </sql>
<sql id="Blob_Column_List"> <sql id="Blob_Column_List">
form_option, form_script form_option, form_script
@ -134,15 +136,17 @@
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.PluginWithBLOBs"> <insert id="insert" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin (id, `name`, plugin_id, insert into plugin (id, `name`, plugin_id,
script_id, jmeter_clazz, clazz_name, script_id, clazz_name, jmeter_clazz,
source_path, source_name, exec_entry, source_path, source_name, exec_entry,
create_time, update_time, create_user_id, create_time, update_time, create_user_id,
form_option, form_script) xpack, scenario, form_option,
form_script)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR}, values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{pluginId,jdbcType=VARCHAR},
#{scriptId,jdbcType=VARCHAR}, #{jmeterClazz,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR}, #{scriptId,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR}, #{jmeterClazz,jdbcType=VARCHAR},
#{sourcePath,jdbcType=VARCHAR}, #{sourceName,jdbcType=VARCHAR}, #{execEntry,jdbcType=VARCHAR}, #{sourcePath,jdbcType=VARCHAR}, #{sourceName,jdbcType=VARCHAR}, #{execEntry,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUserId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{createUserId,jdbcType=VARCHAR},
#{formOption,jdbcType=LONGVARCHAR}, #{formScript,jdbcType=LONGVARCHAR}) #{xpack,jdbcType=BIT}, #{scenario,jdbcType=VARCHAR}, #{formOption,jdbcType=LONGVARCHAR},
#{formScript,jdbcType=LONGVARCHAR})
</insert> </insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.PluginWithBLOBs">
insert into plugin insert into plugin
@ -159,12 +163,12 @@
<if test="scriptId != null"> <if test="scriptId != null">
script_id, script_id,
</if> </if>
<if test="jmeterClazz != null">
jmeter_clazz,
</if>
<if test="clazzName != null"> <if test="clazzName != null">
clazz_name, clazz_name,
</if> </if>
<if test="jmeterClazz != null">
jmeter_clazz,
</if>
<if test="sourcePath != null"> <if test="sourcePath != null">
source_path, source_path,
</if> </if>
@ -183,6 +187,12 @@
<if test="createUserId != null"> <if test="createUserId != null">
create_user_id, create_user_id,
</if> </if>
<if test="xpack != null">
xpack,
</if>
<if test="scenario != null">
scenario,
</if>
<if test="formOption != null"> <if test="formOption != null">
form_option, form_option,
</if> </if>
@ -203,12 +213,12 @@
<if test="scriptId != null"> <if test="scriptId != null">
#{scriptId,jdbcType=VARCHAR}, #{scriptId,jdbcType=VARCHAR},
</if> </if>
<if test="jmeterClazz != null">
#{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null"> <if test="clazzName != null">
#{clazzName,jdbcType=VARCHAR}, #{clazzName,jdbcType=VARCHAR},
</if> </if>
<if test="jmeterClazz != null">
#{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null"> <if test="sourcePath != null">
#{sourcePath,jdbcType=VARCHAR}, #{sourcePath,jdbcType=VARCHAR},
</if> </if>
@ -227,6 +237,12 @@
<if test="createUserId != null"> <if test="createUserId != null">
#{createUserId,jdbcType=VARCHAR}, #{createUserId,jdbcType=VARCHAR},
</if> </if>
<if test="xpack != null">
#{xpack,jdbcType=BIT},
</if>
<if test="scenario != null">
#{scenario,jdbcType=VARCHAR},
</if>
<if test="formOption != null"> <if test="formOption != null">
#{formOption,jdbcType=LONGVARCHAR}, #{formOption,jdbcType=LONGVARCHAR},
</if> </if>
@ -256,12 +272,12 @@
<if test="record.scriptId != null"> <if test="record.scriptId != null">
script_id = #{record.scriptId,jdbcType=VARCHAR}, script_id = #{record.scriptId,jdbcType=VARCHAR},
</if> </if>
<if test="record.jmeterClazz != null">
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="record.clazzName != null"> <if test="record.clazzName != null">
clazz_name = #{record.clazzName,jdbcType=VARCHAR}, clazz_name = #{record.clazzName,jdbcType=VARCHAR},
</if> </if>
<if test="record.jmeterClazz != null">
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="record.sourcePath != null"> <if test="record.sourcePath != null">
source_path = #{record.sourcePath,jdbcType=VARCHAR}, source_path = #{record.sourcePath,jdbcType=VARCHAR},
</if> </if>
@ -280,6 +296,12 @@
<if test="record.createUserId != null"> <if test="record.createUserId != null">
create_user_id = #{record.createUserId,jdbcType=VARCHAR}, create_user_id = #{record.createUserId,jdbcType=VARCHAR},
</if> </if>
<if test="record.xpack != null">
xpack = #{record.xpack,jdbcType=BIT},
</if>
<if test="record.scenario != null">
scenario = #{record.scenario,jdbcType=VARCHAR},
</if>
<if test="record.formOption != null"> <if test="record.formOption != null">
form_option = #{record.formOption,jdbcType=LONGVARCHAR}, form_option = #{record.formOption,jdbcType=LONGVARCHAR},
</if> </if>
@ -297,14 +319,16 @@
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR}, plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR}, script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR}, clazz_name = #{record.clazzName,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR}, source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR}, source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR}, exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR}, create_user_id = #{record.createUserId,jdbcType=VARCHAR},
xpack = #{record.xpack,jdbcType=BIT},
scenario = #{record.scenario,jdbcType=VARCHAR},
form_option = #{record.formOption,jdbcType=LONGVARCHAR}, form_option = #{record.formOption,jdbcType=LONGVARCHAR},
form_script = #{record.formScript,jdbcType=LONGVARCHAR} form_script = #{record.formScript,jdbcType=LONGVARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
@ -317,14 +341,16 @@
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
plugin_id = #{record.pluginId,jdbcType=VARCHAR}, plugin_id = #{record.pluginId,jdbcType=VARCHAR},
script_id = #{record.scriptId,jdbcType=VARCHAR}, script_id = #{record.scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{record.clazzName,jdbcType=VARCHAR}, clazz_name = #{record.clazzName,jdbcType=VARCHAR},
jmeter_clazz = #{record.jmeterClazz,jdbcType=VARCHAR},
source_path = #{record.sourcePath,jdbcType=VARCHAR}, source_path = #{record.sourcePath,jdbcType=VARCHAR},
source_name = #{record.sourceName,jdbcType=VARCHAR}, source_name = #{record.sourceName,jdbcType=VARCHAR},
exec_entry = #{record.execEntry,jdbcType=VARCHAR}, exec_entry = #{record.execEntry,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}, update_time = #{record.updateTime,jdbcType=BIGINT},
create_user_id = #{record.createUserId,jdbcType=VARCHAR} create_user_id = #{record.createUserId,jdbcType=VARCHAR},
xpack = #{record.xpack,jdbcType=BIT},
scenario = #{record.scenario,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -341,12 +367,12 @@
<if test="scriptId != null"> <if test="scriptId != null">
script_id = #{scriptId,jdbcType=VARCHAR}, script_id = #{scriptId,jdbcType=VARCHAR},
</if> </if>
<if test="jmeterClazz != null">
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="clazzName != null"> <if test="clazzName != null">
clazz_name = #{clazzName,jdbcType=VARCHAR}, clazz_name = #{clazzName,jdbcType=VARCHAR},
</if> </if>
<if test="jmeterClazz != null">
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
</if>
<if test="sourcePath != null"> <if test="sourcePath != null">
source_path = #{sourcePath,jdbcType=VARCHAR}, source_path = #{sourcePath,jdbcType=VARCHAR},
</if> </if>
@ -365,6 +391,12 @@
<if test="createUserId != null"> <if test="createUserId != null">
create_user_id = #{createUserId,jdbcType=VARCHAR}, create_user_id = #{createUserId,jdbcType=VARCHAR},
</if> </if>
<if test="xpack != null">
xpack = #{xpack,jdbcType=BIT},
</if>
<if test="scenario != null">
scenario = #{scenario,jdbcType=VARCHAR},
</if>
<if test="formOption != null"> <if test="formOption != null">
form_option = #{formOption,jdbcType=LONGVARCHAR}, form_option = #{formOption,jdbcType=LONGVARCHAR},
</if> </if>
@ -379,14 +411,16 @@
set `name` = #{name,jdbcType=VARCHAR}, set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR}, plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR}, script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR}, clazz_name = #{clazzName,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR}, source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR}, source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR}, exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR}, create_user_id = #{createUserId,jdbcType=VARCHAR},
xpack = #{xpack,jdbcType=BIT},
scenario = #{scenario,jdbcType=VARCHAR},
form_option = #{formOption,jdbcType=LONGVARCHAR}, form_option = #{formOption,jdbcType=LONGVARCHAR},
form_script = #{formScript,jdbcType=LONGVARCHAR} form_script = #{formScript,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
@ -396,14 +430,16 @@
set `name` = #{name,jdbcType=VARCHAR}, set `name` = #{name,jdbcType=VARCHAR},
plugin_id = #{pluginId,jdbcType=VARCHAR}, plugin_id = #{pluginId,jdbcType=VARCHAR},
script_id = #{scriptId,jdbcType=VARCHAR}, script_id = #{scriptId,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
clazz_name = #{clazzName,jdbcType=VARCHAR}, clazz_name = #{clazzName,jdbcType=VARCHAR},
jmeter_clazz = #{jmeterClazz,jdbcType=VARCHAR},
source_path = #{sourcePath,jdbcType=VARCHAR}, source_path = #{sourcePath,jdbcType=VARCHAR},
source_name = #{sourceName,jdbcType=VARCHAR}, source_name = #{sourceName,jdbcType=VARCHAR},
exec_entry = #{execEntry,jdbcType=VARCHAR}, exec_entry = #{execEntry,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}, update_time = #{updateTime,jdbcType=BIGINT},
create_user_id = #{createUserId,jdbcType=VARCHAR} create_user_id = #{createUserId,jdbcType=VARCHAR},
xpack = #{xpack,jdbcType=BIT},
scenario = #{scenario,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR} where id = #{id,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum PluginScenario {
api, platform
}

View File

@ -8,6 +8,7 @@ public class ShiroUtils {
filterChainDefinitionMap.put("/resource/md/get/**", "anon"); filterChainDefinitionMap.put("/resource/md/get/**", "anon");
filterChainDefinitionMap.put("/resource/ui/get/**", "anon"); filterChainDefinitionMap.put("/resource/ui/get/**", "anon");
filterChainDefinitionMap.put("/platform/plugin/resource/**", "anon");
filterChainDefinitionMap.put("/attachment/preview/**", "anon"); filterChainDefinitionMap.put("/attachment/preview/**", "anon");
filterChainDefinitionMap.put("/*.worker.js", "anon"); filterChainDefinitionMap.put("/*.worker.js", "anon");
filterChainDefinitionMap.put("/*.html", "anon"); filterChainDefinitionMap.put("/*.html", "anon");

View File

@ -5,7 +5,9 @@ import io.metersphere.config.MinioProperties;
import io.metersphere.dto.FileInfoDTO; import io.metersphere.dto.FileInfoDTO;
import io.metersphere.metadata.vo.FileRequest; import io.metersphere.metadata.vo.FileRequest;
import io.minio.*; import io.minio.*;
import io.minio.messages.Item;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -56,12 +58,55 @@ public class MinIOFileRepository implements FileRepository {
@Override @Override
public void delete(FileRequest request) throws Exception { public void delete(FileRequest request) throws Exception {
String bucket = minioProperties.getBucket(); String bucket = minioProperties.getBucket();
String fileName = request.getProjectId() + "/" + request.getFileName(); String fileName = request.getProjectId();
if (StringUtils.isNotBlank(request.getFileName())) {
fileName += "/" + request.getFileName();
}
if (fileName.endsWith("/")) {
// 删除文件夹
removeObjects(bucket, fileName);
} else {
// 删除单个文件
removeObject(bucket, fileName);
}
}
private boolean removeObject(String bucketName, String objectName) throws Exception {
minioClient.removeObject(RemoveObjectArgs.builder() minioClient.removeObject(RemoveObjectArgs.builder()
.bucket(bucket) // 存储桶 .bucket(bucketName) // 存储桶
.object(fileName) // 文件名 .object(objectName) // 文件名
.build()); .build());
return true;
}
public void removeObjects(String bucketName, String objectName) throws Exception {
List<String> objects = listObjects(bucketName, objectName);
for (String object : objects) {
removeObject(bucketName, object);
}
}
/**
* 递归获取某路径下的所有文件
*/
public List<String> listObjects(String bucketName, String objectName) throws Exception {
List<String> list = new ArrayList<>(12);
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder()
.bucket(bucketName)
.prefix(objectName)
.build());
for (Result<Item> result : results) {
Item item = result.get();
if (item.isDir()) {
List<String> files = listObjects(bucketName, item.objectName());
list.addAll(files);
} else {
list.add(item.objectName());
}
}
return list;
} }
@Override @Override

View File

@ -0,0 +1,23 @@
package io.metersphere.service;
import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.base.mapper.PluginMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class BasePluginService {
@Resource
private PluginMapper pluginMapper;
public List<PluginWithBLOBs> getPlugins(String scenario) {
PluginExample example = new PluginExample();
example.createCriteria().andScenarioEqualTo(scenario);
return pluginMapper.selectByExampleWithBLOBs(example);
}
}

View File

@ -23,6 +23,7 @@
<spring-cloud.version>2021.0.5</spring-cloud.version> <spring-cloud.version>2021.0.5</spring-cloud.version>
<spring-security.version>5.7.5</spring-security.version> <spring-security.version>5.7.5</spring-security.version>
<dubbo.version>2.7.15</dubbo.version> <dubbo.version>2.7.15</dubbo.version>
<platform-plugin-sdk.version>main</platform-plugin-sdk.version>
<flyway.version>7.15.0</flyway.version> <flyway.version>7.15.0</flyway.version>
<shiro.version>1.10.0</shiro.version> <shiro.version>1.10.0</shiro.version>
<mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version> <mssql-jdbc.version>7.4.1.jre8</mssql-jdbc.version>

View File

@ -22,6 +22,11 @@
<artifactId>xpack-interface</artifactId> <artifactId>xpack-interface</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<artifactId>metersphere-platform-plugin-sdk</artifactId>
<groupId>io.metersphere</groupId>
<version>${platform-plugin-sdk.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,38 +0,0 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface PluginMapper {
long countByExample(PluginExample example);
int deleteByExample(PluginExample example);
int deleteByPrimaryKey(String id);
int insert(PluginWithBLOBs record);
int insertSelective(PluginWithBLOBs record);
List<PluginWithBLOBs> selectByExampleWithBLOBs(PluginExample example);
List<Plugin> selectByExample(PluginExample example);
PluginWithBLOBs selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") PluginWithBLOBs record, @Param("example") PluginExample example);
int updateByExampleWithBLOBs(@Param("record") PluginWithBLOBs record, @Param("example") PluginExample example);
int updateByExample(@Param("record") Plugin record, @Param("example") PluginExample example);
int updateByPrimaryKeySelective(PluginWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(PluginWithBLOBs record);
int updateByPrimaryKey(Plugin record);
}

View File

@ -0,0 +1,28 @@
package io.metersphere.controller;
import io.metersphere.service.PlatformPluginService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
@RestController
@RequestMapping(value = "/platform/plugin")
public class PlatformPluginController {
@Resource
private PlatformPluginService platformPluginService;
@GetMapping("/integration/info")
public Object getIntegrationInfo() {
return platformPluginService.getIntegrationInfo();
}
@GetMapping("/resource/{pluginId}")
public void getPluginResource(@PathVariable("pluginId") String pluginId, @RequestParam("fileName") String fileName, HttpServletResponse response) {
platformPluginService.getPluginResource(pluginId, fileName, response);
}
}

View File

@ -19,12 +19,12 @@ public class PluginController {
@Resource @Resource
private PluginService pluginService; private PluginService pluginService;
@PostMapping("/add") @PostMapping("/add/{scenario}")
public String create(@RequestPart(value = "file", required = false) MultipartFile file) { public void create(@RequestPart(value = "file", required = false) MultipartFile file, @PathVariable String scenario) {
if (file == null) { if (file == null) {
MSException.throwException("上传文件/执行入口为空"); MSException.throwException("上传文件/执行入口为空");
} }
return pluginService.editPlugin(file); pluginService.addPlugin(file, scenario);
} }
@GetMapping("/list") @GetMapping("/list")
@ -37,14 +37,13 @@ public class PluginController {
return pluginService.get(id); return pluginService.get(id);
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{scenario}/{id}")
public String delete(@PathVariable String id) { public void delete(@PathVariable String scenario, @PathVariable String id) {
return pluginService.delete(id); pluginService.delete(scenario, id);
} }
@PostMapping("/custom/method") @PostMapping("/custom/method")
public Object customMethod(@RequestBody PluginRequest request) { public Object customMethod(@RequestBody PluginRequest request) {
return pluginService.customMethod(request); return pluginService.customMethod(request);
} }
} }

View File

@ -0,0 +1,20 @@
package io.metersphere.listener;
import io.metersphere.service.PlatformPluginService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class InitListener implements ApplicationRunner {
@Resource
private PlatformPluginService platformPluginService;
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
platformPluginService.loadPlatFormPlugins();
}
}

View File

@ -0,0 +1,157 @@
package io.metersphere.service;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.base.mapper.PluginMapper;
import io.metersphere.commons.constants.PluginScenario;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.PluginResourceDTO;
import io.metersphere.plugin.core.ui.PluginResource;
import io.metersphere.utils.CommonUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiPluginService {
@Resource
private PluginMapper pluginMapper;
public List<PluginWithBLOBs> addApiPlugin(MultipartFile file) {
String id = UUID.randomUUID().toString();
String path = FileUtils.create(id, file);
List<PluginWithBLOBs> addPlugins = new ArrayList<>();
if (StringUtils.isNotEmpty(path)) {
List<PluginResourceDTO> resources = this.getMethod(path, file.getOriginalFilename());
if (CollectionUtils.isNotEmpty(resources)) {
for (PluginResourceDTO resource : resources) {
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(resource.getPluginId());
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
String delPath = plugins.get(0).getSourcePath();
FileUtils.deleteFile(delPath);
pluginMapper.deleteByExample(example);
}
this.create(resource, path, file.getOriginalFilename(), addPlugins);
}
}
}
return addPlugins;
}
private boolean loadJar(String jarPath) {
try {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
File file = new File(jarPath);
if (!file.exists()) {
return false;
}
Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, file.toURI().toURL());
} catch (NoSuchMethodException e) {
Method method = classLoader.getClass()
.getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
method.setAccessible(true);
method.invoke(classLoader, jarPath);
}
return true;
} catch (Exception e) {
LogUtil.error(e);
}
return false;
}
private List<PluginResourceDTO> getMethod(String path, String fileName) {
List<PluginResourceDTO> resources = new LinkedList<>();
this.loadJar(path);
List<Class<?>> classes = CommonUtil.getSubClass(fileName);
try {
for (Class<?> aClass : classes) {
Object instance = aClass.newInstance();
Object pluginObj = aClass.getDeclaredMethod("init").invoke(instance);
if (pluginObj != null) {
PluginResourceDTO pluginResourceDTO = new PluginResourceDTO();
BeanUtils.copyBean(pluginResourceDTO, (PluginResource) pluginObj);
pluginResourceDTO.setEntry(aClass.getName());
resources.add(pluginResourceDTO);
}
}
} catch (Exception e) {
LogUtil.error("初始化脚本异常:" + e.getMessage());
MSException.throwException("调用插件初始化脚本失败");
}
return resources;
}
private void create(PluginResourceDTO resource, String path, String name, List<PluginWithBLOBs> addPlugins) {
resource.getUiScripts().forEach(item -> {
PluginWithBLOBs plugin = new PluginWithBLOBs();
plugin.setName(item.getName());
plugin.setPluginId(resource.getPluginId());
plugin.setScriptId(item.getId());
plugin.setSourcePath(path);
plugin.setFormOption(item.getFormOption());
plugin.setFormScript(item.getFormScript());
plugin.setClazzName(item.getClazzName());
plugin.setSourceName(name);
plugin.setJmeterClazz(item.getJmeterClazz());
plugin.setExecEntry(resource.getEntry());
plugin.setCreateUserId(SessionUtils.getUserId());
plugin.setScenario(PluginScenario.api.name());
addPlugins.add(plugin);
});
}
public boolean isXpack(Plugin item) {
try {
Class<?> clazz = Class.forName(item.getExecEntry());
Object instance = clazz.newInstance();
return isXpack(Class.forName(item.getExecEntry()), instance);
} catch (Exception e) {
LogUtil.error(e.getMessage());
}
return false;
}
private boolean isXpack(Class<?> aClass, Object instance) {
try {
Object verify = aClass.getDeclaredMethod("xpack").invoke(instance);
return (Boolean) verify;
} catch (Exception e) {
return false;
}
}
public void delete(String id) {
//通过pluginId判断是否还有其他脚本无则清理加载的jar包
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(id);
List<Plugin> list = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(list)) {
FileUtils.deleteFile(list.get(0).getSourcePath());
pluginMapper.deleteByExample(example);
}
}
}

View File

@ -0,0 +1,121 @@
package io.metersphere.service;
import im.metersphere.loader.PluginManager;
import io.metersphere.api.PluginMetaInfo;
import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.base.mapper.PluginMapper;
import io.metersphere.commons.constants.PluginScenario;
import io.metersphere.commons.utils.JSON;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.utils.PluginManagerUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class PlatformPluginService {
@Resource
private BasePluginService basePluginService;
@Resource
private PluginMapper pluginMapper;
private PluginManager pluginManager;
public PluginWithBLOBs addPlatformPlugin(MultipartFile file) {
if (pluginManager != null) {
pluginManager = new PluginManager();
}
String id = UUID.randomUUID().toString();
PluginManagerUtil.loadPlugin(id, pluginManager, file);
PluginMetaInfo pluginMetaInfo = pluginManager.getImplInstance(id, PluginMetaInfo.class);
Map map = JSON.parseMap(pluginMetaInfo.getFrontendMetaData());
map.put("id", id);
map.put("key", pluginMetaInfo.getKey());
PluginWithBLOBs plugin = new PluginWithBLOBs();
plugin.setId(id);
plugin.setName(file.getOriginalFilename());
plugin.setPluginId(pluginMetaInfo.getKey() + "-" + pluginMetaInfo.getVersion());
plugin.setScriptId(plugin.getPluginId());
plugin.setSourcePath("");
// plugin.setFormOption(item.getFormOption());
plugin.setFormScript(JSON.toJSONString(map));
plugin.setClazzName("");
plugin.setSourceName(file.getOriginalFilename());
plugin.setJmeterClazz("");
plugin.setExecEntry("");
plugin.setCreateUserId(SessionUtils.getUserId());
plugin.setXpack(pluginMetaInfo.isXpack());
plugin.setScenario(PluginScenario.platform.name());
return plugin;
}
/**
* 查询所有平台插件并加载
*/
public void loadPlatFormPlugins() {
pluginManager = new PluginManager();
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
PluginManagerUtil.loadPlugins(pluginManager, plugins);
}
public void getPluginResource(String pluginId, String name, HttpServletResponse response) {
InputStream inputStream = pluginManager.getClassLoader(pluginId)
.getResourceAsStream(name);
getImage(inputStream, response);
}
public Object getIntegrationInfo() {
List<PluginWithBLOBs> plugins = basePluginService.getPlugins(PluginScenario.platform.name());
List<Map> configs = new ArrayList<>();
plugins.forEach(item ->{
Map metaData = JSON.parseMap(item.getFormScript());
Map serviceIntegration = (Map) metaData.get("serviceIntegration");
serviceIntegration.put("id", metaData.get("id"));
serviceIntegration.put("key", metaData.get("key"));
configs.add(serviceIntegration);
});
return configs;
}
public void getImage(InputStream in, HttpServletResponse response) {
response.setContentType("image/png");
try(OutputStream out = response.getOutputStream()) {
out.write(in.readAllBytes());
out.flush();
} catch (Exception e) {
LogUtil.error(e);
} finally {
try {
in.close();
} catch (IOException e) {
LogUtil.error(e);
}
}
}
public void delete(String id) {
pluginMapper.deleteByPrimaryKey(id);
try {
pluginManager.getClassLoader(id).getStorageStrategy().delete();
pluginManager.deletePlugin(id);
} catch (IOException e) {
LogUtil.error(e);
}
}
}

View File

@ -4,16 +4,12 @@ import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.PluginExample; import io.metersphere.base.domain.PluginExample;
import io.metersphere.base.domain.PluginWithBLOBs; import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.base.mapper.PluginMapper; import io.metersphere.base.mapper.PluginMapper;
import io.metersphere.commons.constants.PluginScenario;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.PluginResourceDTO;
import io.metersphere.plugin.core.ui.PluginResource;
import io.metersphere.request.PluginDTO; import io.metersphere.request.PluginDTO;
import io.metersphere.request.PluginRequest; import io.metersphere.request.PluginRequest;
import io.metersphere.utils.CommonUtil;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -21,175 +17,57 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class PluginService { public class PluginService {
@Resource @Resource
private PluginMapper pluginMapper; private PluginMapper pluginMapper;
@Resource
private PlatformPluginService platformPluginService;
@Resource
private ApiPluginService apiPluginService;
public String editPlugin(MultipartFile file) { public void addPlugin(PluginWithBLOBs plugin) {
String id = UUID.randomUUID().toString(); if (StringUtils.isBlank(plugin.getId())) {
String path = FileUtils.create(id, file);
if (StringUtils.isNotEmpty(path)) {
List<PluginResourceDTO> resources = this.getMethod(path, file.getOriginalFilename());
if (CollectionUtils.isNotEmpty(resources)) {
for (PluginResourceDTO resource : resources) {
PluginExample example = new PluginExample();
example.createCriteria().andPluginIdEqualTo(resource.getPluginId());
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
String delPath = plugins.get(0).getSourcePath();
// this.closeJar(delPath);
FileUtils.deleteFile(delPath);
pluginMapper.deleteByExample(example);
}
this.create(resource, path, file.getOriginalFilename());
}
}
}
return null;
}
private void create(PluginResourceDTO resource, String path, String name) {
resource.getUiScripts().forEach(item -> {
PluginWithBLOBs plugin = new PluginWithBLOBs();
plugin.setId(UUID.randomUUID().toString()); plugin.setId(UUID.randomUUID().toString());
plugin.setCreateTime(System.currentTimeMillis());
plugin.setUpdateTime(System.currentTimeMillis());
plugin.setName(item.getName());
plugin.setPluginId(resource.getPluginId());
plugin.setScriptId(item.getId());
plugin.setSourcePath(path);
plugin.setFormOption(item.getFormOption());
plugin.setFormScript(item.getFormScript());
plugin.setClazzName(item.getClazzName());
plugin.setSourceName(name);
plugin.setJmeterClazz(item.getJmeterClazz());
plugin.setExecEntry(resource.getEntry());
plugin.setCreateUserId(SessionUtils.getUserId());
pluginMapper.insert(plugin);
});
}
private boolean isXpack(Class<?> aClass, Object instance) {
try {
Object verify = aClass.getDeclaredMethod("xpack").invoke(instance);
return (Boolean) verify;
} catch (Exception e) {
return false;
}
}
private List<PluginResourceDTO> getMethod(String path, String fileName) {
List<PluginResourceDTO> resources = new LinkedList<>();
this.loadJar(path);
List<Class<?>> classes = CommonUtil.getSubClass(fileName);
try {
for (Class<?> aClass : classes) {
Object instance = aClass.newInstance();
Object pluginObj = aClass.getDeclaredMethod("init").invoke(instance);
if (pluginObj != null) {
PluginResourceDTO pluginResourceDTO = new PluginResourceDTO();
BeanUtils.copyBean(pluginResourceDTO, (PluginResource) pluginObj);
pluginResourceDTO.setEntry(aClass.getName());
resources.add(pluginResourceDTO);
}
}
} catch (Exception e) {
LogUtil.error("初始化脚本异常:" + e.getMessage());
MSException.throwException("调用插件初始化脚本失败");
}
return resources;
}
private boolean loadJar(String jarPath) {
try {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try {
File file = new File(jarPath);
if (!file.exists()) {
return false;
}
Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, file.toURI().toURL());
} catch (NoSuchMethodException e) {
Method method = classLoader.getClass()
.getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
method.setAccessible(true);
method.invoke(classLoader, jarPath);
}
return true;
} catch (Exception e) {
LogUtil.error(e);
}
return false;
}
public void loadPlugins() {
try {
PluginExample example = new PluginExample();
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
plugins = plugins.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
-> new TreeSet<>(Comparator.comparing(Plugin::getPluginId))), ArrayList::new));
if (CollectionUtils.isNotEmpty(plugins)) {
plugins.forEach(item -> {
boolean isLoad = this.loadJar(item.getSourcePath());
if (!isLoad) {
PluginExample pluginExample = new PluginExample();
pluginExample.createCriteria().andPluginIdEqualTo(item.getPluginId());
pluginMapper.deleteByExample(pluginExample);
}
});
}
}
} catch (Exception e) {
LogUtil.error(e);
} }
plugin.setCreateTime(System.currentTimeMillis());
plugin.setUpdateTime(System.currentTimeMillis());
pluginMapper.insert(plugin);
} }
public List<PluginDTO> list(String name) { public List<PluginDTO> list(String name) {
try { PluginExample example = new PluginExample();
PluginExample example = new PluginExample(); if (StringUtils.isNotBlank(name)) {
if (StringUtils.isNotBlank(name)) { name = "%" + name + "%";
name = "%" + name + "%"; example.createCriteria().andNameLike(name);
example.createCriteria().andNameLike(name); }
} List<Plugin> plugins = pluginMapper.selectByExample(example);
List<Plugin> plugins = pluginMapper.selectByExample(example); Map<String, Boolean> pluginMap = new HashMap<>();
Map<String, Boolean> pluginMap = new HashMap<>(); List<PluginDTO> lists = new LinkedList<>();
List<PluginDTO> lists = new LinkedList<>(); if (CollectionUtils.isNotEmpty(plugins)) {
if (CollectionUtils.isNotEmpty(plugins)) { // 校验插件是否是企业版
// 校验插件是否是企业版 plugins.forEach(item -> {
plugins.forEach(item -> { PluginDTO dto = new PluginDTO();
PluginDTO dto = new PluginDTO(); BeanUtils.copyBean(dto, item);
BeanUtils.copyBean(dto, item); if (StringUtils.equals(PluginScenario.api.name(), item.getScenario())) {
// api 插件调用
if (!pluginMap.containsKey(item.getPluginId())) { if (!pluginMap.containsKey(item.getPluginId())) {
try { dto.setLicense(apiPluginService.isXpack(item));
Class<?> clazz = Class.forName(item.getExecEntry());
Object instance = clazz.newInstance();
dto.setLicense(this.isXpack(Class.forName(item.getExecEntry()), instance));
} catch (Exception e) {
LogUtil.error(e.getMessage());
}
} else { } else {
dto.setLicense(pluginMap.get(item.getPluginId())); dto.setLicense(pluginMap.get(item.getPluginId()));
} }
lists.add(dto);
pluginMap.put(item.getPluginId(), dto.getLicense()); pluginMap.put(item.getPluginId(), dto.getLicense());
}); } else {
return lists; // 平台插件加载时已经保存
} dto.setLicense(item.getXpack());
} catch (Exception e) { }
LogUtil.error(e); lists.add(dto);
});
} }
return null; return lists;
} }
public Plugin get(String scriptId) { public Plugin get(String scriptId) {
@ -202,16 +80,14 @@ public class PluginService {
return null; return null;
} }
public String delete(String id) { public void delete(String scenario, String id) {
//通过pluginId判断是否还有其他脚本无则清理加载的jar包 if (StringUtils.equalsIgnoreCase(scenario, PluginScenario.platform.name())) {
PluginExample example = new PluginExample(); // 平台插件传的是 id
example.createCriteria().andPluginIdEqualTo(id); platformPluginService.delete(id);
List<Plugin> list = pluginMapper.selectByExample(example); } else {
if (CollectionUtils.isNotEmpty(list)) { // 接口传的是 pluginId
FileUtils.deleteFile(list.get(0).getSourcePath()); apiPluginService.delete(id);
pluginMapper.deleteByExample(example);
} }
return "success";
} }
public Object customMethod(PluginRequest request) { public Object customMethod(PluginRequest request) {
@ -229,4 +105,25 @@ public class PluginService {
PluginExample example = new PluginExample(); PluginExample example = new PluginExample();
return pluginMapper.selectByExample(example); return pluginMapper.selectByExample(example);
} }
public void addPlugin(MultipartFile file, String scenario) {
checkPluginExist(file);
if (StringUtils.equalsIgnoreCase(scenario, PluginScenario.platform.name())) {
PluginWithBLOBs plugin = platformPluginService.addPlatformPlugin(file);
addPlugin(plugin);
} else {
List<PluginWithBLOBs> plugins = apiPluginService.addApiPlugin(file);
plugins.forEach(this::addPlugin);
}
}
public void checkPluginExist(MultipartFile file) {
String filename = file.getOriginalFilename();
PluginExample example = new PluginExample();
example.createCriteria().andSourceNameEqualTo(filename);
List<Plugin> plugins = pluginMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(plugins)) {
MSException.throwException("Plugin exist!");
}
}
} }

View File

@ -0,0 +1,54 @@
package io.metersphere.service.plugin;
import im.metersphere.storage.StorageStrategy;
import io.metersphere.commons.constants.StorageConstants;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.metadata.service.FileManagerService;
import io.metersphere.metadata.vo.FileRequest;
import java.io.IOException;
import java.io.InputStream;
/**
* jar包静态资源存储策略存储在 Minio
*/
public class MinioStorageStrategy implements StorageStrategy {
private FileManagerService fileManagerService;
private String pluginId;
public static final String DIR_PATH = "system/plugin";
public MinioStorageStrategy(String pluginId) {
this.pluginId = pluginId;
fileManagerService = CommonBeanFactory.getBean(FileManagerService.class);
}
@Override
public String store(String name, InputStream in) throws IOException {
FileRequest request = getFileRequest(name);
return fileManagerService.upload(in.readAllBytes(), request);
}
@Override
public InputStream get(String name) {
FileRequest request = getFileRequest(name);
return fileManagerService.downloadFileAsStream(request);
}
@Override
public void delete() throws IOException {
FileRequest request = new FileRequest();
request.setProjectId(DIR_PATH + "/" + this.pluginId + "/");
request.setStorage(StorageConstants.MINIO.name());
fileManagerService.delete(request);
}
private FileRequest getFileRequest(String name) {
FileRequest request = new FileRequest();
request.setProjectId(DIR_PATH + "/" + this.pluginId);
request.setFileName(name);
request.setStorage(StorageConstants.MINIO.name());
return request;
}
}

View File

@ -0,0 +1,55 @@
package io.metersphere.utils;
import im.metersphere.loader.PluginManager;
import io.metersphere.base.domain.PluginWithBLOBs;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.plugin.MinioStorageStrategy;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class PluginManagerUtil {
public static void loadPlugin(String id, PluginManager pluginManager, MultipartFile file) {
if (pluginManager == null) {
pluginManager = new PluginManager();
}
MinioStorageStrategy minioStorageStrategy = new MinioStorageStrategy(id);
try {
// 上传到 sso
minioStorageStrategy.store(file.getOriginalFilename(), file.getInputStream());
} catch (IOException e) {
LogUtil.error("上传 jar 包失败: ", e);
MSException.throwException("上传 jar 包失败: " + e.getMessage());
}
// 加载 jar
try {
pluginManager.loadJar(id, file.getInputStream(), minioStorageStrategy);
} catch (IOException e) {
LogUtil.error("加载jar包失败: ", e);
MSException.throwException("加载jar包失败: " + e.getMessage());
}
}
/**
* 加载插件
*/
public static void loadPlugins(PluginManager pluginManager, List<PluginWithBLOBs> plugins) {
plugins.forEach(plugin -> {
String id = plugin.getId();
MinioStorageStrategy minioStorageStrategy = new MinioStorageStrategy(id);
InputStream inputStream = minioStorageStrategy.get(plugin.getSourceName());
try {
pluginManager.loadJar(id, inputStream, minioStorageStrategy);
} catch (IOException e) {
LogUtil.error("初始化插件失败:", e);
}
});
}
}

View File

@ -0,0 +1,6 @@
import {post, get} from "metersphere-frontend/src/plugins/request";
const BASE_URL = "/platform/plugin/";
export function getIntegrationInfo() {
return get(BASE_URL + 'integration/info');
}

View File

@ -8,22 +8,23 @@ export function getPluginPageByName(name) {
return get(`/plugin/list?name=${name}`); return get(`/plugin/list?name=${name}`);
} }
export function delPluginById(pluginId) { export function delPluginById(scenario, pluginId) {
return get(`/plugin/delete/${pluginId}`); return get(`/plugin/delete/${scenario}/${pluginId}`);
} }
export function getPluginById(pluginId) { export function getPluginById(pluginId) {
return get(`/plugin/get/${pluginId}`); return get(`/plugin/get/${pluginId}`);
} }
export function addPlugin(file) { export function addPlugin(scenario, file) {
let formData = new FormData(); let formData = new FormData();
if (file) { if (file) {
formData.append("file", file); formData.append("file", file);
} }
let url = '/plugin/add/' + scenario;
let config = { let config = {
method: 'POST', method: 'POST',
url: '/plugin/add', url: url,
data: formData, data: formData,
headers: { headers: {
'Content-Type': undefined 'Content-Type': undefined

View File

@ -1,28 +1,45 @@
<template> <template>
<el-form :model="currentConfig" :rules="rules" label-width="105px" v-loading="loading" ref="form"> <el-form
v-loading="loading"
label-width="105px"
:model="currentConfig"
:rules="rules"
ref="form">
<el-row> <el-row>
<el-upload <el-col :span="11">
class="jar-upload" <el-form-item label="使用场景">
drag <el-select size="small" v-model="currentConfig.scenario" clearable>
action="#" <el-option v-for="item in scenarioOptions" :key="item.id" :label="item.text" :value="item.value"/>
:http-request="upload" </el-select>
:limit="1" </el-form-item>
:beforeUpload="uploadValidate"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:file-list="fileList"
ref="fileUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
<div class="el-upload__tip" slot="tip">{{ $t('api_test.jar_config.upload_tip') }}</div>
</el-upload>
<el-col>
<div class="buttons">
<el-button type="primary" size="small" @click="save()">{{ $t('commons.confirm') }}</el-button>
</div>
</el-col> </el-col>
<el-col :span="1">
<el-divider direction="vertical"/>
</el-col>
<el-col :span="12">
<el-upload
class="jar-upload"
drag
action="#"
:http-request="upload"
:limit="1"
:beforeUpload="uploadValidate"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:file-list="fileList"
ref="fileUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text" v-html="$t('load_test.upload_tips')"></div>
<div class="el-upload__tip" slot="tip">{{ $t('api_test.jar_config.upload_tip') }}</div>
</el-upload>
</el-col>
<div class="buttons">
<el-button type="primary" size="small" @click="save()">{{ $t('commons.confirm') }}</el-button>
</div>
</el-row> </el-row>
</el-form> </el-form>
</template> </template>
@ -40,7 +57,12 @@ export default {
name: '', name: '',
description: '', description: '',
fileName: '', fileName: '',
scenario: 'api'
}, },
scenarioOptions: [
{text: '接口测试', value: 'api'},
{text: '平台对接', value: "platform"},
],
rules: { rules: {
name: [ name: [
{required: true, message: this.$t('commons.input_name'), trigger: 'blur'}, {required: true, message: this.$t('commons.input_name'), trigger: 'blur'},
@ -115,7 +137,7 @@ export default {
this.$warning(this.$t('commons.please_upload')); this.$warning(this.$t('commons.please_upload'));
return; return;
} }
this.loading = addPlugin(this.fileList[0]).then(() => { this.loading = addPlugin(this.currentConfig.scenario, this.fileList[0]).then(() => {
this.$success(this.$t('organization.integration.successful_operation')); this.$success(this.$t('organization.integration.successful_operation'));
this.$emit("close"); this.$emit("close");
this.fileList = []; this.fileList = [];

View File

@ -44,7 +44,7 @@
:tip="$t('commons.delete')" :tip="$t('commons.delete')"
icon="el-icon-delete" icon="el-icon-delete"
type="danger" type="danger"
@exec="handleDelete(scope.row.id)" v-permission="['SYSTEM_PLUGIN:DEL']"/> @exec="handleDelete(scope.row)" v-permission="['SYSTEM_PLUGIN:DEL']"/>
</div> </div>
<div v-else> <div v-else>
<ms-table-operator-button <ms-table-operator-button
@ -57,7 +57,7 @@
</el-table> </el-table>
</el-card> </el-card>
<el-dialog :title="$t('commons.import')" :visible.sync="dialogVisible" @close="close" destroy-on-close> <el-dialog :title="$t('commons.import')" width="900px" :visible.sync="dialogVisible" @close="close" destroy-on-close>
<ms-jar-config @close="close"/> <ms-jar-config @close="close"/>
</el-dialog> </el-dialog>
<ms-script-view ref="scriptView"/> <ms-script-view ref="scriptView"/>
@ -106,10 +106,19 @@ export default {
if (res.data) { if (res.data) {
this.format(res.data); this.format(res.data);
this.dataMap.forEach((values, key) => { this.dataMap.forEach((values, key) => {
let obj = {id: key, license: values[0].license, name: values[0].sourceName, sourceName: values[0].sourceName, pluginId: key, createUserId: values[0].createUserId, updateTime: values[0].updateTime}; let item = values[0];
obj.children = values; if (item.scenario === 'api') {
this.tableData.push(obj); let obj = {};
}) Object.assign(obj, item);
obj.id = key;
obj.pluginId = key;
obj.name = item.sourceName;
obj.children = values;
this.tableData.push(obj);
} else {
this.tableData.push(item);
}
});
} }
}) })
}, },
@ -131,9 +140,10 @@ export default {
handleView(row) { handleView(row) {
this.$refs.scriptView.open(row.scriptId); this.$refs.scriptView.open(row.scriptId);
}, },
handleDelete(id) { handleDelete(row) {
operationConfirm(this, this.$t('api_test.jar_config.delete_tip'), () => { let tip = row.scenario === 'api' ? this.$t('api_test.jar_config.delete_tip') : this.$t('api_test.jar_config.delete_confirm');
this.loading = delPluginById(id).then(() => { operationConfirm(this, tip, () => {
this.loading = delPluginById(row.scenario, row.id).then(() => {
this.$success(this.$t('commons.delete_success')); this.$success(this.$t('commons.delete_success'));
this.initPlugins(); this.initPlugins();
}); });

View File

@ -2,13 +2,16 @@
<div class="header-title" v-loading="loading"> <div class="header-title" v-loading="loading">
<div> <div>
<div>{{ $t('organization.integration.select_defect_platform') }}</div> <div>{{ $t('organization.integration.select_defect_platform') }}</div>
<el-radio-group v-model="platform" style="margin-top: 10px" @change="change"> <el-radio-group v-model="platform" style="margin-top: 10px">
<span v-for="config in platformConfigs" :key="config.key">
<el-radio :label="config.label">
<img class="platform" :src="'/platform/plugin/resource/' + config.id + '?fileName=' + config.image"
alt="Jira"/>
</el-radio>
</span>
<el-radio label="Tapd"> <el-radio label="Tapd">
<img class="platform" src="/assets/tapd.png" alt="Tapd"/> <img class="platform" src="/assets/tapd.png" alt="Tapd"/>
</el-radio> </el-radio>
<el-radio label="Jira">
<img class="platform" src="/assets/jira.png" alt="Jira"/>
</el-radio>
<el-radio label="Zentao"> <el-radio label="Zentao">
<img class="zentao_platform" src="/assets/zentao.jpg" alt="Zentao"/> <img class="zentao_platform" src="/assets/zentao.jpg" alt="Zentao"/>
</el-radio> </el-radio>
@ -19,9 +22,15 @@
</div> </div>
<tapd-setting v-if="tapdEnable" ref="tapdSetting"/> <tapd-setting v-if="tapdEnable" ref="tapdSetting"/>
<jira-setting v-if="jiraEnable" ref="jiraSetting"/>
<zentao-setting v-if="zentaoEnable" ref="zentaoSetting"/> <zentao-setting v-if="zentaoEnable" ref="zentaoSetting"/>
<azuredevops-setting v-if="azuredevopsEnable" ref="azureDevopsSetting"/> <azuredevops-setting v-if="azuredevopsEnable" ref="azureDevopsSetting"/>
<div v-for="config in platformConfigs" :key="config.key">
<platform-config
:config="config"
v-if="config.key === platform"
/>
</div>
</div> </div>
</template> </template>
@ -30,46 +39,43 @@ import TapdSetting from '@/business/workspace/integration/TapdSetting';
import JiraSetting from '@/business/workspace/integration/JiraSetting'; import JiraSetting from '@/business/workspace/integration/JiraSetting';
import ZentaoSetting from '@/business/workspace/integration/ZentaoSetting'; import ZentaoSetting from '@/business/workspace/integration/ZentaoSetting';
import AzuredevopsSetting from '@/business/workspace/integration/AzureDevopsSetting'; import AzuredevopsSetting from '@/business/workspace/integration/AzureDevopsSetting';
import {AZURE_DEVOPS, JIRA, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants"; import {AZURE_DEVOPS, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
import PlatformConfig from "@/business/workspace/integration/PlatformConfig";
import {getIntegrationInfo} from "@/api/platform-plugin";
export default { export default {
name: "BugManagement", name: "BugManagement",
components: {TapdSetting, JiraSetting, ZentaoSetting, AzuredevopsSetting}, components: {PlatformConfig, TapdSetting, JiraSetting, ZentaoSetting, AzuredevopsSetting},
data() { data() {
return { return {
tapdEnable: true,
jiraEnable: false,
zentaoEnable: false,
azuredevopsEnable: false,
loading: false, loading: false,
platform: TAPD platformConfigs: [],
platform: TAPD,
} }
}, },
methods: { created() {
change(platform) { this.platformConfigs = [];
if (platform === TAPD) {
this.tapdEnable = true; getIntegrationInfo()
this.jiraEnable = false; .then((r) => {
this.zentaoEnable = false; this.platformConfigs = r.data;
this.azuredevopsEnable = false; });
} else if (platform === JIRA) {
this.tapdEnable = false; this.platform = TAPD;
this.jiraEnable = true; this.platformConfigs[0].key;
this.zentaoEnable = false; },
this.azuredevopsEnable = false; computed: {
} else if (platform === ZEN_TAO) { tapdEnable() {
this.tapdEnable = false; return this.platform === TAPD;
this.jiraEnable = false; },
this.zentaoEnable = true; zentaoEnable() {
this.azuredevopsEnable = false; return this.platform === ZEN_TAO;
} else if (platform === AZURE_DEVOPS) { },
this.tapdEnable = false; azuredevopsEnable() {
this.jiraEnable = false; return this.platform === AZURE_DEVOPS;
this.zentaoEnable = false; },
this.azuredevopsEnable = true; },
} methods: {}
}
}
} }
</script> </script>

View File

@ -0,0 +1,215 @@
<template>
<div>
<div style="width: 500px">
<div style="margin-top: 20px;margin-bottom: 10px">{{ $t('organization.integration.basic_auth_info') }}</div>
<el-form :model="form" ref="form" label-width="100px" size="small" :disabled="show" :rules="rules">
<el-form-item
v-for="item in config.formItems"
:key="item.name"
:label="item.i18n ? $t(item.label) : item.label"
:prop="item.name">
<custom-filed-component :form="form"
:data="item"
prop="defaultValue"/>
</el-form-item>
</el-form>
</div>
<bug-manage-btn @save="save"
@init="init"
:edit-permission="['WORKSPACE_SERVICE:READ+EDIT']"
@testConnection="testConnection"
@cancelIntegration="cancelIntegration"
@reloadPassInput="reloadPassInput"
:form="form"
:show.sync="show"
ref="bugBtn"/>
<div class="defect-tip" v-html="config.tips">
<!-- todo 处理跳转逻辑 -->
<!-- {{config.tips}}-->
<!-- <div>{{ $t('organization.integration.use_tip') }}</div>-->
<!-- <div>-->
<!-- 1. {{ $t('organization.integration.use_tip_jira') }}-->
<!-- </div>-->
<!-- <div>-->
<!-- 2. {{ $t('organization.integration.use_tip_two') }}-->
<!-- <router-link to="/setting/project/all"-->
<!-- style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer">-->
<!-- {{ $t('organization.integration.link_the_project_now') }}-->
<!-- </router-link>-->
<!-- </div>-->
<!-- <div>-->
<!-- 3. {{ $t('organization.integration.use_tip_three') }}-->
<!-- <span style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer"-->
<!-- @click="resVisible = true">-->
<!-- {{ $t('organization.integration.link_the_info_now') }}-->
<!-- </span>-->
<!-- <el-dialog :close-on-click-modal="false" width="80%"-->
<!-- :visible.sync="resVisible" destroy-on-close @close="closeDialog">-->
<!-- <ms-person-router @closeDialog="closeDialog"/>-->
<!-- </el-dialog>-->
<!-- </div>-->
</div>
</div>
</template>
<script>
import BugManageBtn from "./BugManageBtn";
import {getCurrentUser, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
import {JIRA} from "metersphere-frontend/src/utils/constants";
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
import MsPersonRouter from "metersphere-frontend/src/components/personal/PersonRouter";
import CustomFiledComponent from "metersphere-frontend/src/components/template/CustomFiledComponent";
import {
authServiceIntegration,
delServiceIntegration,
getServiceIntegration,
saveServiceIntegration
} from "../../../api/workspace";
export default {
name: "PlatformConfig",
components: {MsInstructionsIcon, BugManageBtn, MsPersonRouter, CustomFiledComponent},
created() {
this.init();
},
props: {
config: {
type: Object,
default() {
return {}
},
}
},
data() {
return {
show: true,
showInput: true,
resVisible: false,
form: {},
rules: {},
};
},
methods: {
init() {
let rules = {};
this.config.formItems.forEach(item => {
rules[item.name] = {
required: item.required,
message: item.i18n ? this.$t(item.message) : item.message,
trigger: ['change', 'blur']
}
});
this.rules = rules;
const {lastWorkspaceId} = getCurrentUser();
let param = {};
param.platform = JIRA;
param.workspaceId = lastWorkspaceId;
this.$parent.loading = getServiceIntegration(param).then(res => {
let data = res.data;
if (data.configuration) {
let config = JSON.parse(data.configuration);
let form = {};
Object.assign(form, config);
this.form = form;
//
this.config.formItems.forEach(item => {
item.defaultValue = this.form[item.name];
});
} else {
this.clear();
}
});
},
save() {
this.$refs['form'].validate(valid => {
if (valid) {
let config = {};
Object.assign(config, this.form);
const {lastWorkspaceId} = getCurrentUser();
let param = {};
param.workspaceId = lastWorkspaceId;
param.platform = this.config.key;
param.configuration = JSON.stringify(config);
this.$parent.loading = saveServiceIntegration(param).then(() => {
this.show = true;
this.$refs.bugBtn.showEdit = true;
this.$refs.bugBtn.showSave = false;
this.$refs.bugBtn.showCancel = false;
this.reloadPassInput();
this.init();
this.$success(this.$t('commons.save_success'));
});
} else {
return false;
}
});
},
clear() {
this.form = {};
this.$nextTick(() => {
if (this.$refs.form) {
this.$refs.form.clearValidate();
}
});
},
testConnection() {
if (this.form.account && this.form.password) {
// todo
this.$parent.loading = authServiceIntegration(getCurrentWorkspaceId(), JIRA).then(() => {
this.$success(this.$t('organization.integration.verified'));
});
} else {
this.$warning(this.$t('organization.integration.not_integrated'));
return false;
}
},
cancelIntegration() {
if (this.form.account && this.form.password) {
this.$alert(this.$t('organization.integration.cancel_confirm') + JIRA + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
const {lastWorkspaceId} = getCurrentUser();
let param = {};
param.workspaceId = lastWorkspaceId;
param.platform = this.config.key;
this.$parent.loading = delServiceIntegration(param).then(() => {
this.$success(this.$t('organization.integration.successful_operation'));
this.init('');
});
}
}
});
} else {
this.$warning(this.$t('organization.integration.not_integrated'));
}
},
reloadPassInput() {
this.showInput = false;
this.$nextTick(function () {
this.showInput = true;
});
},
closeDialog() {
this.resVisible = false;
}
}
};
</script>
<style scoped>
.defect-tip {
background: #EDEDED;
border: solid #E1E1E1 1px;
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
.el-input {
width: 80%;
}
</style>