提交 2703e881 authored 作者: fit2cloud-chenyw's avatar fit2cloud-chenyw

feat: 插件管理v0.01

上级 ba678266
......@@ -13,6 +13,9 @@ import io.dataease.auth.util.RsaUtil;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.commons.utils.CodingUtil;
import io.dataease.commons.utils.ServletUtils;
/*import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.xpack.dto.response.SysSettingDto;
import io.dataease.plugins.xpack.service.DePluginXpackService;*/
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
......@@ -105,6 +108,14 @@ public class AuthServer implements AuthApi {
SysUserEntity userById = authUserService.getUserById(4L);
String nickName = userById.getNickName();
System.out.println(nickName);
/* Map<String, DePluginXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType(DePluginXpackService.class);
for (Map.Entry entry : beansOfType.entrySet()) {
Object key = entry.getKey();
DePluginXpackService value = (DePluginXpackService)entry.getValue();
List<SysSettingDto> sysSettingDtos = value.systemSettings();
String name = entry.getValue().getClass().getName();
System.out.println("key: "+ key + ", value: "+ name);
}*/
return "apple";
}
}
package io.dataease.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class MyPlugin implements Serializable {
private Long pluginId;
private String name;
private Boolean free;
private Integer cost;
private String descript;
private String version;
private Integer installType;
private String creator;
private Long releaseTime;
private Long installTime;
private String moduleName;
private String beanName;
private String icon;
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
package io.dataease.base.mapper;
import io.dataease.base.domain.MyPlugin;
import io.dataease.base.domain.MyPluginExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface MyPluginMapper {
long countByExample(MyPluginExample example);
int deleteByExample(MyPluginExample example);
int deleteByPrimaryKey(Long pluginId);
int insert(MyPlugin record);
int insertSelective(MyPlugin record);
List<MyPlugin> selectByExample(MyPluginExample example);
MyPlugin selectByPrimaryKey(Long pluginId);
int updateByExampleSelective(@Param("record") MyPlugin record, @Param("example") MyPluginExample example);
int updateByExample(@Param("record") MyPlugin record, @Param("example") MyPluginExample example);
int updateByPrimaryKeySelective(MyPlugin record);
int updateByPrimaryKey(MyPlugin record);
}
\ No newline at end of file
package io.dataease.base.mapper.ext;
import io.dataease.base.domain.MyPlugin;
import io.dataease.base.mapper.ext.query.GridExample;
import java.util.List;
public interface ExtSysPluginMapper {
List<MyPlugin> query(GridExample example);
}
<?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.dataease.base.mapper.ext.ExtSysPluginMapper">
<select id="query" parameterType="io.dataease.base.mapper.ext.query.GridExample" resultMap="io.dataease.base.mapper.MyPluginMapper.BaseResultMap">
select *
from my_plugin
<if test="_parameter != null">
<include refid="io.dataease.base.mapper.ext.query.GridSql.gridCondition" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
<if test="orderByClause == null">
order by install_time desc
</if>
</select>
</mapper>
package io.dataease.commons.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.channels.FileChannel;
public class DeFileUtils {
/**
* Java文件操作 获取不带扩展名的文件名
*/
public static String getFileNameNoEx(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length()))) {
return filename.substring(0, dot);
}
}
return filename;
}
/**
* 获取文件扩展名,不带 .
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload(MultipartFile file, String filePath) {
String name = getFileNameNoEx(file.getOriginalFilename());
String suffix = getExtensionName(file.getOriginalFilename());
try {
String fileName = name + "." + suffix;
String path = filePath + fileName;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
// file.transferTo(dest);
FileOutputStream fileOutputStream = new FileOutputStream(dest);
fileOutputStream.write(file.getBytes());
fileOutputStream.flush();
fileOutputStream.close();
return dest;
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
}
return null;
}
public static String copy(File source, String targetDir) throws IOException{
String name = source.getName();
String destPath = null;
if (targetDir.endsWith("/") || targetDir.endsWith("\\")){
destPath = targetDir + name;
}else{
destPath = targetDir + "/" + name;
}
File DestFile = new File(destPath);
if (!DestFile.getParentFile().exists()) {
DestFile.getParentFile().mkdirs();
}
copyFileUsingFileChannels(source, DestFile);
return destPath;
}
private static void copyFileUsingFileChannels(File source, File dest) throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
}
}
public static String readJson(File file) {
String str = null;
try {
FileReader fileReader = new FileReader(file);
Reader reader = new InputStreamReader(new FileInputStream(file), "utf-8");
int ch=0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
fileReader.close();
reader.close();
str = sb.toString();
return str;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package io.dataease.commons.utils;
import java.io.*;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class ZipUtils {
/**
* 解压文件
*
* @param zipFilePath 解压文件路径
* @param outputFolder 输出解压文件路径
*/
public static void unZipIt(String zipFilePath, String outputFolder) {
byte[] buffer = new byte[1024];
File folder = new File(outputFolder);
if (!folder.exists()) {
folder.mkdir();
}
try {
//get the zip file content
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath));
ZipEntry ze = zis.getNextEntry();
while (ze != null) {
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);
System.out.println("file unzip : " + newFile.getAbsoluteFile());
//大部分网络上的源码,这里没有判断子目录
if (ze.isDirectory()) {
if (!newFile.mkdirs()) {
System.out.println("was not successful.");
}
} else {
if (!new File(newFile.getParent()).mkdirs()) {
System.out.println("was not successful.");
}
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
}
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void unzip(File source, String out) throws IOException {
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(source))) {
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
File file = new File(out, entry.getName());
if (entry.isDirectory()) {
if (!file.mkdirs()) {
System.out.println("was not successful.");
}
} else {
File parent = file.getParentFile();
if (!parent.exists()) {
if (!parent.mkdirs()) {
System.out.println("was not successful.");
}
}
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
byte[] buffer = new byte[Math.toIntExact(entry.getSize())];
int location;
while ((location = zis.read(buffer)) != -1) {
bos.write(buffer, 0, location);
}
}
}
entry = zis.getNextEntry();
}
}
}
/**
* 把所有文件都直接解压到指定目录(忽略子文件夹)
*
* @param zipFile
* @param folderPath
* @throws ZipException
* @throws IOException
*/
public static void upZipFile(File zipFile, String folderPath) throws ZipException, IOException {
File desDir = new File(folderPath);
if (!desDir.exists()) {
if (!desDir.mkdirs()) {
System.out.println("was not successful.");
}
}
ZipFile zf = new ZipFile(zipFile);
for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements(); ) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
InputStream in = zf.getInputStream(entry);
File desFile = new File(folderPath, java.net.URLEncoder.encode(entry.getName(), "UTF-8"));
if (!desFile.exists()) {
File fileParentDir = desFile.getParentFile();
if (!fileParentDir.exists()) {
if (!fileParentDir.mkdirs()) {
System.out.println("was not successful.");
}
}
}
OutputStream out = new FileOutputStream(desFile);
byte[] buffer = new byte[1024 * 1024];
int realLength = in.read(buffer);
while (realLength != -1) {
out.write(buffer, 0, realLength);
realLength = in.read(buffer);
}
out.close();
in.close();
}
}
}
package io.dataease.controller.sys;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.dataease.base.domain.MyPlugin;
import io.dataease.commons.utils.PageUtils;
import io.dataease.commons.utils.Pager;
import io.dataease.controller.sys.base.BaseGridRequest;
import io.dataease.service.sys.PluginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@RestController
@Api(tags = "系统:插件管理")
@RequestMapping("/api/plugin")
public class SysPluginController {
@Autowired
private PluginService pluginService;
@ApiOperation("查询已安装插件")
@PostMapping("/pluginGrid/{goPage}/{pageSize}")
public Pager<List<MyPlugin>> pluginGrid(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody BaseGridRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, pluginService.query(request));
}
@PostMapping("upload")
public Map<String, Object> localUpload(@RequestParam("file") MultipartFile file) throws Exception {
return pluginService.localInstall(file);
}
}
package io.dataease.plugins.config;
import io.dataease.plugins.loader.ClassloaderResponsity;
import io.dataease.plugins.loader.ModuleClassLoader;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.Map;
@Component
public class LoadjarUtil {
public List<?> loadJar(String jarPath){
File jar = new File(jarPath);
URI uri = jar.toURI();
String moduleName = jarPath.substring(jarPath.lastIndexOf("/")+1,jarPath.lastIndexOf("."));
try {
if(ClassloaderResponsity.getInstance().containsClassLoader(moduleName)){
ClassloaderResponsity.getInstance().removeClassLoader(moduleName);
}
ModuleClassLoader classLoader = new ModuleClassLoader(new URL[]{uri.toURL()}, Thread.currentThread().getContextClassLoader());
SpringContextUtil.getBeanFactory().setBeanClassLoader(classLoader);
Thread.currentThread().setContextClassLoader(classLoader);
classLoader.initBean();
ClassloaderResponsity.getInstance().addClassLoader(moduleName,classLoader);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return SpringContextUtil.getAllBean();
}
public List<Map<String, Object>> deleteModule(String moduleName){
if(ClassloaderResponsity.getInstance().containsClassLoader(moduleName)){
ClassloaderResponsity.getInstance().removeClassLoader(moduleName);
}
return beans();
}
public List<Map<String, Object>> beans(){
return SpringContextUtil.getAllBean();
}
}
package io.dataease.plugins.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class SpringContextUtil implements ApplicationContextAware {
//获取bean工厂,用来实现动态注入bean
//不能使用其他类加载器加载bean
//否则会出现异常:类未找到,类未定义
public static DefaultListableBeanFactory getBeanFactory(){
return (DefaultListableBeanFactory) getApplicationContext().getAutowireCapableBeanFactory();
}
public static List<Map<String, Object>> getAllBean() {
List<Map<String, Object>> list = new ArrayList<>();
String[] beans = getApplicationContext()
.getBeanDefinitionNames();
for (String beanName : beans) {
Class<?> beanType = getApplicationContext()
.getType(beanName);
Map<String, Object> map = new HashMap<>();
map.put("BeanName", beanName);
map.put("beanType", beanType);
map.put("package", beanType.getPackage());
list.add(map);
}
return list;
}
/**
* 上下文对象实例
*/
private static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 获取applicationContext
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
package io.dataease.plugins.loader;
import io.dataease.plugins.config.SpringContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ClassloaderResponsity {
private static Logger logger = LoggerFactory.getLogger(ClassloaderResponsity.class);
private ClassloaderResponsity(){}
private Map<String,ModuleClassLoader> responsityMap = new ConcurrentHashMap<>();
public void addClassLoader(String moduleName,ModuleClassLoader moduleClassLoader){
responsityMap.put(moduleName,moduleClassLoader);
}
public boolean containsClassLoader(String key){
return responsityMap.containsKey(key);
}
public ModuleClassLoader getClassLoader(String key){
return responsityMap.get(key);
}
public void removeClassLoader(String moduleName){
ModuleClassLoader moduleClassLoader = responsityMap.get(moduleName);
try {
List<String> registeredBean = moduleClassLoader.getRegisteredBean();
for (String beanName : registeredBean) {
logger.info("删除bean:"+beanName);
SpringContextUtil.getBeanFactory().removeBeanDefinition(beanName);
}
moduleClassLoader.close();
responsityMap.remove(moduleName);
} catch (IOException e) {
logger.error("删除"+moduleName+"模块发生错误");
}
}
private static class ClassloaderResponsityHodler{
private static ClassloaderResponsity instamce = new ClassloaderResponsity();
}
public static ClassloaderResponsity getInstance(){
return ClassloaderResponsityHodler.instamce;
}
}
package io.dataease.plugins.loader;
import io.dataease.plugins.config.SpringContextUtil;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ModuleClassLoader extends URLClassLoader {
//属于本类加载器加载的jar包
private JarFile jarFile;
//保存已经加载过的Class对象
private Map<String,Class> cacheClassMap = new HashMap<>();
//保存本类加载器加载的class字节码
private Map<String,byte[]> classBytesMap = new HashMap<>();
//需要注册的spring bean的name集合
private List<String> registeredBean = new ArrayList<>();
//构造
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
URL url = urls[0];
String path = url.getPath();
try {
jarFile = new JarFile(path);
} catch (IOException e) {
e.printStackTrace();
}
//初始化类加载器执行类加载
init();
}
//重写loadClass方法
//改写loadClass方式
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if(findLoadedClass(name)==null){
return super.loadClass(name);
}else{
return cacheClassMap.get(name);
}
}
/**
* 方法描述 初始化类加载器,保存字节码
* @method init
*/
private void init() {
//解析jar包每一项
Enumeration<JarEntry> en = jarFile.entries();
InputStream input = null;
try{
while (en.hasMoreElements()) {
JarEntry je = en.nextElement();
String name = je.getName();
//这里添加了路径扫描限制
if (name.endsWith(".class")) {
String className = name.replace(".class", "").replaceAll("/", ".");
input = jarFile.getInputStream(je);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = input.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
byte[] classBytes = baos.toByteArray();
classBytesMap.put(className,classBytes);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(input!=null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//将jar中的每一个class字节码进行Class载入
for (Map.Entry<String, byte[]> entry : classBytesMap.entrySet()) {
String key = entry.getKey();
Class<?> aClass = null;
try {
aClass = loadClass(key);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
cacheClassMap.put(key,aClass);
}
}
/**
* 方法描述 初始化spring bean
* @method initBean
*/
public void initBean(){
for (Map.Entry<String, Class> entry : cacheClassMap.entrySet()) {
String className = entry.getKey();
Class<?> cla = entry.getValue();
if(isSpringBeanClass(cla)){
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(cla);
BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
//设置当前bean定义对象是单利的
beanDefinition.setScope("singleton");
//将变量首字母置小写
String beanName = StringUtils.uncapitalize(className);
beanName = beanName.substring(beanName.lastIndexOf(".")+1);
beanName = StringUtils.uncapitalize(beanName);
SpringContextUtil.getBeanFactory().registerBeanDefinition(beanName,beanDefinition);
registeredBean.add(beanName);
System.out.println("注册bean:"+beanName);
}
}
}
//获取当前类加载器注册的bean
//在移除当前类加载器的时候需要手动删除这些注册的bean
public List<String> getRegisteredBean() {
return registeredBean;
}
/**
* 方法描述 判断class对象是否带有spring的注解
* @method isSpringBeanClass
* @param cla jar中的每一个class
* @return true 是spring bean false 不是spring bean
*/
public boolean isSpringBeanClass(Class<?> cla){
if(cla==null){
return false;
}
//是否是接口
if(cla.isInterface()){
return false;
}
//是否是抽象类
if( Modifier.isAbstract(cla.getModifiers())){
return false;
}
if(cla.getAnnotation(Component.class)!=null){
return true;
}
if(cla.getAnnotation(Repository.class)!=null){
return true;
}
if(cla.getAnnotation(Service.class)!=null){
return true;
}
return false;
}
}
package io.dataease.service.sys;
import com.google.gson.Gson;
import io.dataease.base.domain.MyPlugin;
import io.dataease.base.mapper.MyPluginMapper;
import io.dataease.base.mapper.ext.ExtSysPluginMapper;
import io.dataease.base.mapper.ext.query.GridExample;
import io.dataease.commons.utils.BeanUtils;
import io.dataease.commons.utils.DeFileUtils;
import io.dataease.commons.utils.ZipUtils;
import io.dataease.controller.sys.base.BaseGridRequest;
import io.dataease.plugins.config.LoadjarUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
@Service
public class PluginService {
@Value("${dataease.plugin.dir:/opt/dataease/plugins/}")
private String pluginDir;
private final static String pluginJsonName = "plugin.json";
@Resource
private ExtSysPluginMapper extSysPluginMapper;
@Resource
private MyPluginMapper myPluginMapper;
@Resource
private LoadjarUtil loadjarUtil;
public List<MyPlugin> query(BaseGridRequest request) {
GridExample gridExample = request.convertExample();
List<MyPlugin> results = extSysPluginMapper.query(gridExample);
return results;
}
/**
* 从本地安装处插件
* @param file
* @return
*/
public Map<String, Object> localInstall(MultipartFile file) {
//1.上传文件到服务器pluginDir目录下
File dest = DeFileUtils.upload(file, pluginDir+"temp/");
//2.解压目标文件dest 得到plugin.json和jar
String folder = pluginDir+"folder/";
try {
ZipUtils.upZipFile(dest, folder);
} catch (IOException e) {
// 需要删除文件
e.printStackTrace();
}
//3.解析plugin.json 失败则 直接返回错误 删除文件
File folderFile = new File(folder);
File[] jsonFiles = folderFile.listFiles(this::isPluginJson);
if (ArrayUtils.isEmpty(jsonFiles)) {
throw new RuntimeException("缺少插件描述文件");
}
MyPlugin myPlugin = formatJsonFile(jsonFiles[0]);
//4.加载jar包 失败则 直接返回错误 删除文件
File[] jarFiles = folderFile.listFiles(this::isPluginJar);
if (ArrayUtils.isEmpty(jarFiles)) {
throw new RuntimeException("缺少插件jar文件");
}
File jarFile = jarFiles[0];
String jarRoot = pluginDir+"jar/";
String jarPath = null;
try {
jarPath = DeFileUtils.copy(jarFile, jarRoot);
} catch (IOException e) {
e.printStackTrace();
}
loadjarUtil.loadJar(jarPath);
//5.写表到my_plugin
myPlugin.setPluginId(0L);
myPluginMapper.insert(myPlugin);
return null;
}
//判断当前文件是否实插件描述文件
//文件名称必须plugin.json
private boolean isPluginJson(File file) {
return StringUtils.equals(file.getName(), pluginJsonName);
}
private boolean isPluginJar(File file) {
String name = file.getName();
return StringUtils.equals(DeFileUtils.getExtensionName(name), "jar");
}
/**
* 从plugin.json文件反序列化为MyPlugin实例对象
* @return
*/
private MyPlugin formatJsonFile(File file) {
String str = DeFileUtils.readJson(file);
Gson gson = new Gson();
Map<String, Object> myPlugin = gson.fromJson(str, Map.class);
myPlugin.put("free", (Double)myPlugin.get("free") > 0.0);
MyPlugin result = new MyPlugin();
try {
org.apache.commons.beanutils.BeanUtils.populate(result, myPlugin);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//BeanUtils.copyBean(result, myPlugin);
return result;
}
/**
* 从插件商城远程安装插件
* 2.0版本实现
* @param params
* @return
*/
public Map<String, Object> remoteInstall(Map<String, Object> params) {
return null;
}
}
......@@ -239,3 +239,35 @@ INSERT INTO `sys_users_roles` VALUES (19, 4);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for my_plugin
-- ----------------------------
DROP TABLE IF EXISTS `my_plugin`;
CREATE TABLE `my_plugin` (
`plugin_id` bigint(20) NOT NULL COMMENT '主键',
`name` varchar(255) DEFAULT NULL COMMENT '插件名称',
`free` tinyint(1) DEFAULT NULL COMMENT '是否免费',
`cost` int(10) DEFAULT NULL COMMENT '费用',
`descript` varchar(255) DEFAULT NULL COMMENT '描述',
`version` varchar(255) DEFAULT NULL COMMENT '版本号',
`install_type` int(4) DEFAULT NULL COMMENT '安装类型',
`creator` varchar(255) DEFAULT NULL COMMENT '开发者',
`release_time` bigint(13) DEFAULT NULL COMMENT '发布时间',
`install_time` bigint(13) DEFAULT NULL COMMENT '安装时间',
`module_name` varchar(255) DEFAULT NULL COMMENT 'jar包名称',
`bean_name` varchar(40) DEFAULT NULL COMMENT 'bean名称',
`icon` varchar(255) DEFAULT NULL COMMENT '图标',
PRIMARY KEY (`plugin_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of my_plugin
-- ----------------------------
BEGIN;
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
......@@ -67,7 +67,7 @@
<!-- <table tableName="datasource"/>-->
<!-- <table tableName="sys_dict"/>-->
<!-- <table tableName="sys_dict_item"/>-->
<table tableName="dataset_table_field"/>
<table tableName="my_plugin"/>
<!-- <table tableName="panel_design"/>-->
......
......@@ -887,5 +887,20 @@ export default {
back: '返回',
view: '视图',
edit: '编辑'
},
plugin: {
local_install: '本地安装',
remote_install: '远程安装',
name: '插件名称',
free: '是否免费',
cost: '费用',
descript: '描述',
version: '版本',
creator: '作者',
install_time: '安装时间',
release_time: '时间',
un_install: '卸载',
uninstall_confirm: '确定卸载该插件',
uninstall_cancel: '取消卸载插件'
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论