Merge pull request !99 from Arno/dev
This commit is contained in:
不忘初心 2019-04-23 16:36:21 +08:00 committed by Arno
commit 33f5ee3103
287 changed files with 11897 additions and 3167 deletions

View File

@ -1,15 +1,22 @@
# 版本日志
## 2.3.3
## 2.4.0
### 新增功能
1. 首页进程列表显示属于Jpom项目名称(〓下页)
1. 首页进程列表显示属于Jpom项目名称(感谢@〓下页)
2. 多节点统一管理(插件模式)
3. 证书解析支持cer 证书(感谢@JAVA jesion)
4. 新增记录用户操作日志[采用H2数据库](感谢@〓下页)
5. 节点分发功能、合并管理项目
### 解决BUG、优化功能
1. 解析端口信息兼容`:::8084`(感谢@Agoni 、)
2. 进程id解析端口、解析项目名称带缓存
3. 项目分组变更,项目列表及时刷新(感谢@〓下页)
4. 批量上传文件数量进度显示(感谢@群友)
5. linux udp端口信息解析失败(感谢@Ruby)
-----------------------------------------------------------

24
FQA.md
View File

@ -8,7 +8,7 @@
修改管理程序命令文件中 --jpom.log=/jpom/log/
### 如何修改话超时时长
### 如何修改话超时时长
在管理程序命令文件中 ARGS 变量添加 --tomcat.sessionTimeOut=1800
@ -71,4 +71,24 @@
![jpom](/doc/error/can't-open-socket-file.jpg)
针对以上两个问题Jpom目前采用略过这些进程的解决办法请更新到2.3.1以上。
针对以上两个问题Jpom目前采用略过这些进程的解决办法请更新到2.3.1以上。
### SpringBoot 读取jar包同路径配置文件失败
由于目前Jpom 启动下面的方式限制SpringBoot未能读取到对应配置文件目前解决方案是在配置项目的args参数解决
> --spring.config.location=D:\config\config.properties
### windows 环境 com.sun.tools.attach.AttachNotSupportedException: no providers installed 之类异常
> 问题原因${JAVA_HOME}/jre/bin/attach.dll 文件没有找到检查当前Jdk环境是否安装完整
### 常见问题未知问题
https://github.com/alibaba/arthas/issues/347
### windows 环境项目在运行中不能删除文件
> 由于系统原因,暂时还没有找到解决办法

View File

@ -1,6 +1,10 @@
### 开发计划
1. 主要管理页面兼容移动端
2. ssl 到期提醒、快捷续签
3. 多机统一管理
4. 程序宕机处理
1. 程序宕机处理
2. 主要管理页面兼容移动端
3. ssl 到期提醒、快捷续签
### 待优化解决
1. 支持更多压缩包
2. 项目监控完善

View File

@ -31,7 +31,7 @@
> 当多个项目运行在同一台服务器时运维人员通常也不只一个如果每个人都登录服务器管理项目难免会造成一些不必要的麻烦甚至给服务器的安全性带来问题服务器密码知道的人越多越容易泄露因为不需要登录服务器管理项目维护人员不需要知道服务器的登录密码只需要有Jpom的账号就行Jpom本身可以通过权限管理给不同用户不同的权限这样也使得项目的稳定性得到提升。
> Jpom可以在Linux和Windows服务器上运行
> Jpom可以在Linux和Windows服务器上运行并且Jpom采用多节点模式随时开启关闭节点服务器节点分发减少运维人员上传、修改操作
### Jpom 目标
@ -42,47 +42,76 @@
1. 创建、修改、删除项目、Jar包管理
2. 实时查看控制台日志、备份日志、删除日志、导出日志
3. cpu、ram 监控、导出堆栈信息、查看项目进程端口、服务器状态监控
4. 多用户管理,用户项目权限独立(上传、删除权限可控制)
5. 系统路径白名单模式,杜绝用户误操作系统文件
6. 在线管理Nginx配置、ssl证书文件
7. Jpom完全不依赖数据库随装随用
4. 多节点管理、多节点自动分发
5. 多用户管理,用户项目权限独立(上传、删除权限可控制),完善的操作日志
6. 系统路径白名单模式,杜绝用户误操作系统文件
7. 在线管理Nginx配置、ssl证书文件
8. [阿里云 CodePipeline + Oss在线管理](/doc/CodePipeline-Oss.md)
#### 基本操作演示
<img src="http://s.keepbx.cn/jpom-demo-gif.gif" ></img>
![jpom-server](http://s.keepbx.cn/jpom-server.gif)
![jpom-node-agent](http://s.keepbx.cn/jpom-node-agent.gif)
### 下载安装
1. 下载安装包 [https://gitee.com/keepbx/Jpom/attach_files](https://gitee.com/keepbx/Jpom/attach_files)
2. 上传到服务解压对应路径
3. 命令运行Jpom.sh、Jpom.bat
2. 解压文件
3. 安装插件端
1. agent-x.x.x-release 目录为插件端的全部安装文件
2. 上传到对应服务器
3. 命令运行Agent.sh、Agent.bat
4. 安装服务端
1. server-x.x.x-release 目录为服务端的全部安装文件
2. 上传到对应服务器
3. 命令运行Server.sh、Server.bat
### 编译安装
1. 访问[Jpom](https://gitee.com/keepbx/Jpom)的码云主页,拉取最新完整代码(建议使用master分支)
2. 进入项目目录执行:`mvn clean package`
3. 然后在目录中查看 target/jpom-x.x.x-release
4. 打包上传服务器运行
5. 命令运行Jpom.sh、Jpom.bat
3. 安装插件端
1. 查看插件端安装包 modules/agent/target/agent-x.x.x-release
2. 打包上传服务器运行
3. 命令运行Agent.sh、Agent.bat
4. 安装服务端
1. 查看插件端安装包 modules/server/target/server-x.x.x-release
2. 打包上传服务器运行
3. 命令运行Server.sh、Server.bat
### 编译运行
1. 访问[Jpom](https://gitee.com/keepbx/Jpom)的码云主页,拉取最新完整代码(建议使用master分支)
2. 运行`cn.keepbx.jpom.JpomApplication`
3. 浏览器访问http://127.0.0.1:2122
2. 运行插件端
1. 运行`cn.keepbx.jpom.JpomAgentApplication`
2. 注意控制台打印的默认账号密码信息
3. 运行服务端
1. 运行`cn.keepbx.jpom.JpomServerApplication`
2. 浏览器访问http://127.0.0.1:2122
### 管理命令
1. windows中Jpom.bat
1. windows中Agent.bat 、Server.bat
```
Jpom.bat 启动管理面板(按照面板提示输入操作)
# 服务端
Server.bat 启动管理面板(按照面板提示输入操作)
# 插件端
Agent.bat 启动管理面板(按照面板提示输入操作)
```
2. linux中Jpom.sh
2. linux中Agent.sh 、Server.sh
```
Jpom.sh start 启动Jpom
Jpom.sh stop 停止Jpom
Jpom.sh restart 重启Jpom
Jpom.sh status 查看Jpom运行状态
# 服务端
Server.sh start 启动Jpom服务端
Server.sh stop 停止Jpom服务端
Server.sh restart 重启Jpom服务端
Server.sh status 查看Jpom服务端运行状态
# 插件端
Agent.sh start 启动Jpom插件端
Agent.sh stop 停止Jpom插件端
Agent.sh restart 重启Jpom插件端
Agent.sh status 查看Jpom插件端运行状态
```
### 视频教程

View File

@ -1,21 +1,28 @@
### 用户权限具体差异对比
| 功能 | 系统管理员 | 普通管理员 | 非管理员 |
| -- | -- | -- | -- |
| 查看项目 | √ | √ | √ |
| 创建项目 | √ | √ | × |
| 修改项目 | √ | √ | 授权项目 |
| 删除项目 | √ | √ | × |
| 修改自身昵称、密码 | √ | √ | √ |
| 查看用户列表 | √ | √ | × |
| 重置用户密码 | √ | × | × |
| 创建用户、修改用户 | √ | √ | × |
| 修改系统白名单 | √ | × | × |
| 查看、修改阿里云OSS配置 | √ | × | × |
| nginx管理 | √ | √ | × |
| nginx静态资源配置 | √ | x | × |
| 证书管理 | √ | √ | × |
| 删除证书 | √ | x | × |
| 功能 | 系统管理员 | 节点管理员 | 非管理员 | 服务管理员 |
| -- | -- | -- | -- | -- |
| 创建、修改、删除节点 | √ | × | × | × |
| 创建、修改、删除节点分发 | √ | × | × | √ |
| 查看操作日志 | √ | √ | √ | √ |
| 分发白名单 | √ | × | × | × |
| 分发文件 | √ | × | × | √ |
| 查看项目 | √ | √ | √ | × |
| 创建项目 | √ | √ | × | × |
| 修改项目 | √ | √ | 授权项目 | × |
| 删除项目 | √ | √ | × | × |
| 上传、删除项目jar | √ | 单独授权 | 单独授权 | × |
| 修改自身昵称、密码 | √ | √ | √ | √ |
| 查看用户列表 | √ | x | × | √ |
| 重置用户密码 | √ | × | × | × |
| 创建用户、修改用户 | √ | × | × | √ |
| 修改系统白名单 | √ | × | × | × |
| 查看、修改阿里云OSS配置 | √ | × | × | × |
| nginx管理 | √ | √ | × | × |
| nginx静态资源配置 | √ | x | × | × |
| 证书管理 | √ | √ | × | × |
| 删除证书 | √ | × | × | × |
### 防暴力登录账号机制

101
modules/agent/pom.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jpom</artifactId>
<groupId>cn.keepbx</groupId>
<version>2.4.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>cn.keepbx.jpom</groupId>
<artifactId>agent</artifactId>
<version>2.4.0</version>
<dependencies>
<dependency>
<groupId>cn.keepbx.jpom</groupId>
<artifactId>common</artifactId>
<version>${pom.version}</version>
</dependency>
<!-- 文件编码识别-->
<dependency>
<groupId>net.sourceforge.jchardet</groupId>
<artifactId>jchardet</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
<!--nginx-->
<dependency>
<groupId>com.github.odiszapc</groupId>
<artifactId>nginxparser</artifactId>
<version>0.9.6</version>
</dependency>
<!-- 证书解密-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.61</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.18</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<mainClass>cn.keepbx.jpom.JpomAgentApplication</mainClass>
<!-- 是否指定项目classpath下的依赖 -->
<addClasspath>true</addClasspath>
<!-- 指定依赖的时候声明前缀 -->
<classpathPrefix>./</classpathPrefix>
</manifest>
<manifestEntries>
<!-- 项目版本号 -->
<Jpom-Project-Version>${project.version}</Jpom-Project-Version>
<!-- 打包时间 -->
<Jpom-Timestamp>${maven.build.timestamp}</Jpom-Timestamp>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<descriptors>
<descriptor>script/release.xml</descriptor>
</descriptors>
<outputDirectory>target</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,119 @@
@REM The MIT License (MIT)
@REM
@REM Copyright (c) 2019 码之科技工作室
@REM
@REM Permission is hereby granted, free of charge, to any person obtaining a copy of
@REM this software and associated documentation files (the "Software"), to deal in
@REM the Software without restriction, including without limitation the rights to
@REM use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
@REM the Software, and to permit persons to whom the Software is furnished to do so,
@REM subject to the following conditions:
@REM
@REM The above copyright notice and this permission notice shall be included in all
@REM copies or substantial portions of the Software.
@REM
@REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
@REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
@REM FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
@REM COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
@REM IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
@REM CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@REM
@echo off
setlocal enabledelayedexpansion
set Tag=KeepBx-Agent-System-JpomAgentApplication
set MainClass=cn.keepbx.jpom.JpomAgentApplication
set CloseMainClass=cn.keepbx.jpom.JpomClose
set basePath=%~dp0
set Lib=%basePath%lib\
set Log=%basePath%agent.log
set LogBack=%basePath%log\
set JVM=-server
set ARGS= --jpom.applicationTag=%Tag% --jpom.log=%basePath%log --server.port=2123
color 0a
TITLE Jpom管理系统BAT控制台
echo. ***** Jpom管理系统BAT控制台 *****
::*************************************************************************************************************
echo.
echo. [1] 启动 start
echo. [2] 关闭 stop
echo. [3] 查看运行状态 status
echo. [4] 重启 restart
echo. [5] 帮助 use
echo. [0] 退 出 0
echo.
echo.请输入选择的序号:
set /p ID=
IF "%id%"=="1" goto start
IF "%id%"=="2" goto stop
IF "%id%"=="3" goto status
IF "%id%"=="4" goto restart
IF "%id%"=="5" goto use
IF "%id%"=="0" EXIT
PAUSE
echo 即将关闭窗口
timeout 3
EXIT 1
@REM 启动
:start
if "%JAVA_HOME%"=="" (
echo 请配置【JAVA_HOME】环境变量
PAUSE
EXIT 2
)
rem 备份日志
if exist %Log% (
if not exist %LogBack% (
echo %LogBack%
md %LogBack%
)
move %Log% %LogBack%%date:~0,4%%date:~5,2%%date:~8,2%0%time:~1,1%%time:~3,2%%time:~6,2%.log
del %Log%
)
set TEMPCLASSPATH=
for /f "delims=" %%I in ('dir /B %Lib%') do (set TEMPCLASSPATH=!TEMPCLASSPATH!%Lib%%%I;)
REM echo 启动成功,关闭窗口不影响运行
echo 启动中.....关闭窗口不影响运行
javaw %JVM% -classpath %TEMPCLASSPATH%"%JAVA_HOME%"\lib\tools.jar -Dapplication=%Tag% -Dbasedir=%basePath% %MainClass% %ARGS% >> %Log%
timeout 3
goto:eof
@REM 关闭Jpom
:stop
set TEMPCLASSPATH=
for /f "delims=" %%I in ('dir /B %Lib%') do (set TEMPCLASSPATH=!TEMPCLASSPATH!%Lib%%%I;)
java -classpath %TEMPCLASSPATH%"%JAVA_HOME%"\lib\tools.jar %CloseMainClass% %ARGS% --jpom.applicationTag=%Tag% --event=stop
goto:eof
@REM 查看Jpom运行状态
:status
set TEMPCLASSPATH=
for /f "delims=" %%I in ('dir /B %Lib%') do (set TEMPCLASSPATH=!TEMPCLASSPATH!%Lib%%%I;)
java -classpath %TEMPCLASSPATH%"%JAVA_HOME%"\lib\tools.jar %CloseMainClass% %ARGS% --jpom.applicationTag=%Tag% --event=status
goto:eof
@REM 重启Jpom
:restart
echo 停止中....
call:stop
timeout 3
echo 启动中....
call:start
goto:eof
@REM 重新加载Nginx
:reloadNginx
nginx -s reload
goto:eof
@REM 提示用法
:use
echo please use (start|stop|restart|status)
goto:eof

View File

@ -0,0 +1,152 @@
# The MIT License (MIT)
#
# Copyright (c) 2019 码之科技工作室
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#!/bin/bash
Tag="KeepBx-Agent-System-JpomAgentApplication"
MainClass="cn.keepbx.jpom.JpomAgentApplication"
# 自动获取当前路径
Path=$(cd `dirname $0`; pwd)"/"
Lib="${Path}lib/"
Log="${Path}agent.log"
LogBack="${Path}log/"
JVM="-server "
# 修改项目端口号 日志路径
ARGS="--jpom.applicationTag=${Tag} --server.port=2123 --jpom.log=${Path}log"
echo ${Tag}
echo ${Path}
RETVAL="0"
# 启动程序
function start() {
if [[ -z "${JAVA_HOME}" ]] ; then
echo "请配置【JAVA_HOME】环境变量"
exit 2
fi
echo ${Log}
# 备份日志
if [[ -f ${Log} ]]; then
if [[ ! -d ${LogBack} ]];then
mkdir ${LogBack}
fi
cur_dateTime="`date +%Y-%m-%d_%H:%M:%S`.log"
mv ${Log} ${LogBack}${cur_dateTime}
echo "mv to $LogBack$cur_dateTime"
touch ${Log}
fi
# classPath
CLASSPATH=`listDir ${Lib}`
nohup java ${JVM} -classpath ${CLASSPATH}${JAVA_HOME}/lib/tools.jar -Dapplication=${Tag} -Dbasedir=${Path} ${MainClass} ${ARGS} >> ${Log} 2>&1 &
if [[ -f ${Log} ]]; then
tail -f ${Log}
else
sleep 3
if [[ -f ${Log} ]]; then
tail -f ${Log}
else
echo "还没有生成日志文件:${Log}"
fi
fi
}
# 拼接所有文件
function listDir()
{
ALL=""
for file in `ls $1`
do
#得到文件的完整的目录
ALL="${ALL}${1}/${file}:"
done
echo ${ALL}
}
# 停止程序
function stop() {
pid=$(ps -ef | grep -v 'grep' | egrep ${Tag}| awk '{printf $2 " "}')
if [[ "$pid" != "" ]]; then
echo -n "boot ( pid $pid) is running"
echo
echo -n $"Shutting down boot: wait"
kill $(pgrep -f ${Tag}) 2>/dev/null
sleep 3
pid=$(ps -ef | grep -v 'grep' | egrep ${Tag}| awk '{printf $2 " "}')
if [[ "$pid" != "" ]]; then
echo "kill boot process"
kill -9 "$pid"
fi
else
echo "boot is stopped"
fi
status
}
# 获取程序状态
function status()
{
pid=$(ps -ef | grep -v 'grep' | egrep ${Tag}| awk '{printf $2 " "}')
#echo "$pid"
if [[ "$pid" != "" ]]; then
echo "boot is running,pid is $pid"
else
echo "boot is stopped"
fi
}
# 重新加载nginx
function reloadNginx(){
nginx -t
nginx -s reload
}
# 提示使用语法
function usage()
{
echo "Usage: $0 {start|stop|restart|status|reloadNginx}"
RETVAL="2"
}
# See how we were called.
RETVAL="0"
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
reloadNginx)
reloadNginx
;;
status)
status
;;
*)
usage
;;
esac
exit $RETVAL

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly>
<id>release</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
@ -11,16 +10,16 @@
<fileSets>
<!-- 打包Jpom 管理命令文件-->
<fileSet>
<directory>${basedir}/script/</directory>
<directory>script/</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>Jpom.sh</include>
<include>Jpom.bat</include>
<include>Agent.sh</include>
<include>Agent.bat</include>
</includes>
</fileSet>
<!--复制外部配置文件-->
<fileSet>
<directory>${basedir}/src/main/resources/bin/</directory>
<directory>src/main/resources/bin/</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>extConfig.yml</include>

View File

@ -0,0 +1,44 @@
package cn.keepbx.jpom;
import cn.hutool.core.util.CharsetUtil;
import cn.jiangzeyin.common.ApplicationBuilder;
import cn.jiangzeyin.common.EnableCommonBoot;
import cn.keepbx.jpom.common.JpomApplicationEvent;
import cn.keepbx.jpom.common.Type;
import cn.keepbx.jpom.common.interceptor.AuthorizeInterceptor;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.http.converter.StringHttpMessageConverter;
/**
* jpom 启动类
* Created by jiangzeyin on 2017/9/14.
*
* @author jiangzeyin
*/
@SpringBootApplication
@ServletComponentScan
@EnableCommonBoot
public class JpomAgentApplication extends BaseJpomApplication {
public JpomAgentApplication() {
super(Type.Agent, JpomAgentApplication.class);
}
/**
* 启动执行
*
* @param args 参数
*/
public static void main(String[] args) throws Exception {
JpomAgentApplication.args = args;
ApplicationBuilder.createBuilder(JpomAgentApplication.class)
.addHttpMessageConverter(new StringHttpMessageConverter(CharsetUtil.CHARSET_UTF_8))
// 拦截器
.addInterceptor(AuthorizeInterceptor.class)
//
.addApplicationEventClient(new JpomApplicationEvent())
.run(args);
}
}

View File

@ -0,0 +1,79 @@
package cn.keepbx.jpom.common;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.keepbx.jpom.model.Role;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.system.ConfigBean;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* agent
*
* @author jiangzeyin
* @date 2019/4/17
*/
public abstract class BaseAgentController extends BaseJpomController {
@Resource
protected ProjectInfoService projectInfoService;
protected String getUserName() {
return getUserName(getRequest());
}
/**
* 获取server 端操作人
*
* @param request req
* @return name
*/
public static String getUserName(HttpServletRequest request) {
String name = ServletUtil.getHeaderIgnoreCase(request, ConfigBean.JPOM_SERVER_USER_NAME);
name = CharsetUtil.convert(name, CharsetUtil.CHARSET_ISO_8859_1, CharsetUtil.CHARSET_UTF_8);
return StrUtil.emptyToDefault(name, StrUtil.DASHED);
}
/**
* 操作的人员是否为系统管理员
*
* @return true
*/
protected Role getUserRole() {
String val = ServletUtil.getHeaderIgnoreCase(getRequest(), ConfigBean.JPOM_SERVER_SYSTEM_USER_ROLE);
try {
return Role.valueOf(val);
} catch (Exception e) {
return Role.User;
}
}
protected boolean isSystemUser() {
return getUserRole() == Role.System;
}
/**
* 获取拦截器中缓存的项目信息
*
* @return this
*/
protected ProjectInfoModel getProjectInfoModel() {
ProjectInfoModel projectInfoModel = tryGetProjectInfoModel();
Objects.requireNonNull(projectInfoModel, "获取项目信息失败");
return projectInfoModel;
}
protected ProjectInfoModel tryGetProjectInfoModel() {
ProjectInfoModel projectInfoModel = null;
String id = getParameter("id");
if (StrUtil.isNotEmpty(id)) {
projectInfoModel = projectInfoService.getItem(id);
}
return projectInfoModel;
}
}

View File

@ -7,18 +7,16 @@ import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.JarClassLoader;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.commander.impl.LinuxProjectCommander;
import cn.keepbx.jpom.common.commander.impl.WindowsProjectCommander;
import cn.keepbx.jpom.model.RunMode;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.system.NetstatModel;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.system.JpomRuntimeException;
import cn.keepbx.jpom.util.CommandUtil;
@ -28,7 +26,6 @@ import com.sun.tools.attach.VirtualMachine;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
@ -44,9 +41,12 @@ import java.util.jar.Manifest;
*/
public abstract class AbstractProjectCommander {
public static final String RUNING_TAG = "running";
public static final String STOP_TAG = "stopped";
private static AbstractProjectCommander abstractProjectCommander = null;
protected Charset charset;
public static final OsInfo OS_INFO = SystemUtil.getOsInfo();
/**
* 进程id 对应Jpom 名称
*/
@ -56,14 +56,6 @@ public abstract class AbstractProjectCommander {
*/
private static final LRUCache<Integer, Integer> PID_PORT = new LRUCache<>(100, TimeUnit.MINUTES.toMillis(10));
protected AbstractProjectCommander(Charset charset) {
this.charset = charset;
}
public Charset getCharset() {
return charset;
}
/**
* 实例化Commander
*
@ -73,14 +65,14 @@ public abstract class AbstractProjectCommander {
if (abstractProjectCommander != null) {
return abstractProjectCommander;
}
if (OS_INFO.isLinux()) {
if (BaseJpomApplication.OS_INFO.isLinux()) {
// Linux系统
abstractProjectCommander = new LinuxProjectCommander(CharsetUtil.CHARSET_UTF_8);
} else if (OS_INFO.isWindows()) {
abstractProjectCommander = new LinuxProjectCommander();
} else if (BaseJpomApplication.OS_INFO.isWindows()) {
// Windows系统
abstractProjectCommander = new WindowsProjectCommander(CharsetUtil.CHARSET_GBK);
abstractProjectCommander = new WindowsProjectCommander();
} else {
throw new JpomRuntimeException("不支持的:" + OS_INFO.getName());
throw new JpomRuntimeException("不支持的:" + BaseJpomApplication.OS_INFO.getName());
}
return abstractProjectCommander;
}
@ -168,7 +160,7 @@ public abstract class AbstractProjectCommander {
return "没有jar包,请先到文件管理中上传程序的jar";
}
//
if (projectInfoModel.getRunMode() == ProjectInfoModel.RunMode.ClassPath) {
if (projectInfoModel.getRunMode() == RunMode.ClassPath) {
JarClassLoader jarClassLoader = JarClassLoader.load(FileUtil.file(projectInfoModel.getLib()));
// 判断主类
try {
@ -227,9 +219,9 @@ public abstract class AbstractProjectCommander {
File backPath = projectInfoModel.getLogBack();
backPath = new File(backPath, DateTime.now().toString(DatePattern.PURE_DATETIME_FORMAT) + ".log");
FileUtil.copy(file, backPath, true);
if (OS_INFO.isLinux()) {
if (BaseJpomApplication.OS_INFO.isLinux()) {
CommandUtil.execCommand("cp /dev/null " + projectInfoModel.getLog());
} else if (OS_INFO.isWindows()) {
} else if (BaseJpomApplication.OS_INFO.isWindows()) {
// 清空日志
String r = CommandUtil.execSystemCommand("echo \"\" > " + file.getAbsolutePath());
if (StrUtil.isEmpty(r)) {
@ -247,9 +239,9 @@ public abstract class AbstractProjectCommander {
public String status(String tag) throws Exception {
VirtualMachine virtualMachine = JvmUtil.getVirtualMachine(tag);
if (virtualMachine == null) {
return ConsoleService.STOP_TAG;
return AbstractProjectCommander.STOP_TAG;
}
return StrUtil.format("{}:{}", ConsoleService.RUNING_TAG, virtualMachine.id());
return StrUtil.format("{}:{}", AbstractProjectCommander.RUNING_TAG, virtualMachine.id());
}
//---------------------------------------------------- 基本操作----end
@ -378,7 +370,7 @@ public abstract class AbstractProjectCommander {
* @return int
*/
protected static int parsePid(String result) {
if (result.startsWith(ConsoleService.RUNING_TAG)) {
if (result.startsWith(AbstractProjectCommander.RUNING_TAG)) {
return Convert.toInt(result.split(":")[1]);
}
return 0;
@ -393,7 +385,7 @@ public abstract class AbstractProjectCommander {
*/
public boolean isRun(String tag) throws Exception {
String result = status(tag);
return result.contains(ConsoleService.RUNING_TAG);
return result.contains(AbstractProjectCommander.RUNING_TAG);
}
/***

View File

@ -1,5 +1,6 @@
package cn.keepbx.jpom.common.commander;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.commander.impl.LinuxSystemCommander;
import cn.keepbx.jpom.common.commander.impl.WindowsSystemCommander;
import cn.keepbx.jpom.model.system.ProcessModel;
@ -11,30 +12,38 @@ import java.io.File;
import java.util.List;
/**
* 系统监控基类
* 系统监控命令
*
* @author jiangzeyin
* @date 2019/4/15
* @date 2019/4/16
*/
public abstract class AbstractSystemCommander {
private static AbstractSystemCommander abstractSystemCommander = null;
public static AbstractSystemCommander getInstance() {
if (abstractSystemCommander != null) {
return abstractSystemCommander;
}
if (AbstractProjectCommander.OS_INFO.isLinux()) {
if (BaseJpomApplication.OS_INFO.isLinux()) {
// Linux系统
abstractSystemCommander = new LinuxSystemCommander();
} else if (AbstractProjectCommander.OS_INFO.isWindows()) {
} else if (BaseJpomApplication.OS_INFO.isWindows()) {
// Windows系统
abstractSystemCommander = new WindowsSystemCommander();
} else {
throw new JpomRuntimeException("不支持的:" + AbstractProjectCommander.OS_INFO.getName());
throw new JpomRuntimeException("不支持的:" + BaseJpomApplication.OS_INFO.getName());
}
return abstractSystemCommander;
}
/**
* 获取整个服务器监控信息
*
* @return data
*/
public abstract JSONObject getAllMonitor();
/**
* 获取当前服务器的所有进程列表
*
@ -50,12 +59,13 @@ public abstract class AbstractSystemCommander {
*/
public abstract ProcessModel getPidInfo(int pid);
/**
* 获取整个服务器监控信息
*
* @return data
*/
public abstract JSONObject getAllMonitor();
protected static JSONObject putObject(String name, Object value, String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("value", value);
jsonObject.put("type", type);
return jsonObject;
}
/**
* 磁盘占用
@ -77,12 +87,4 @@ public abstract class AbstractSystemCommander {
array.add(putObject("空闲磁盘", freeSpace / 1024f, "disk"));
return array;
}
protected static JSONObject putObject(String name, Object value, String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("value", value);
jsonObject.put("type", type);
return jsonObject;
}
}

View File

@ -2,12 +2,12 @@ package cn.keepbx.jpom.common.commander.impl;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.thread.GlobalThreadPool;
import cn.hutool.core.util.StrUtil;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.system.NetstatModel;
import cn.keepbx.jpom.util.CommandUtil;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@ -18,10 +18,6 @@ import java.util.List;
*/
public class LinuxProjectCommander extends AbstractProjectCommander {
public LinuxProjectCommander(Charset charset) {
super(charset);
}
@Override
public String start(ProjectInfoModel projectInfoModel) throws Exception {
String msg = checkStart(projectInfoModel);
@ -79,8 +75,13 @@ public class LinuxProjectCommander extends AbstractProjectCommander {
netstatModel.setSend(list.get(2));
netstatModel.setLocal(list.get(3));
netstatModel.setForeign(list.get(4));
netstatModel.setStatus(list.get(5));
netstatModel.setName(list.get(6));
if ("tcp".equalsIgnoreCase(netstatModel.getProtocol())) {
netstatModel.setStatus(list.get(5));
netstatModel.setName(list.get(6));
} else {
netstatModel.setStatus(StrUtil.DASHED);
netstatModel.setName(list.get(5));
}
array.add(netstatModel);
}
return array;

View File

@ -14,28 +14,10 @@ import java.util.List;
/**
* @author jiangzeyin
* @date 2019/4/15
* @date 2019/4/16
*/
public class LinuxSystemCommander extends AbstractSystemCommander {
@Override
public List<ProcessModel> getProcessList() {
String s = CommandUtil.execSystemCommand("top -b -n 1 | grep java");
return formatLinuxTop(s, false);
}
@Override
public ProcessModel getPidInfo(int pid) {
String command = "top -b -n 1 -p " + pid;
String internal = CommandUtil.execCommand(command);
List<ProcessModel> processModels = formatLinuxTop(internal, true);
if (processModels == null || processModels.isEmpty()) {
return null;
}
return processModels.get(0);
}
@Override
public JSONObject getAllMonitor() {
String result = CommandUtil.execCommand("top -b -n 1");
@ -62,6 +44,25 @@ public class LinuxSystemCommander extends AbstractSystemCommander {
return jsonObject;
}
@Override
public List<ProcessModel> getProcessList() {
String s = CommandUtil.execSystemCommand("top -b -n 1 | grep java");
return formatLinuxTop(s, false);
}
@Override
public ProcessModel getPidInfo(int pid) {
String command = "top -b -n 1 -p " + pid;
String internal = CommandUtil.execCommand(command);
List<ProcessModel> processModels = formatLinuxTop(internal, true);
if (processModels == null || processModels.isEmpty()) {
return null;
}
return processModels.get(0);
}
/**
* 将linux的top信息转为集合
*
@ -119,14 +120,17 @@ public class LinuxSystemCommander extends AbstractSystemCommander {
}
private static String formSize(String val) {
if (val.endsWith("g")) {
return String.format("%.2f MB", Convert.toDouble(val.replace("g", "")) * 1024);
} else {
return Convert.toLong(val) / 1024 + " MB";
if (StrUtil.endWithIgnoreCase(val, "g")) {
String newVal = val.substring(0, val.length() - 1);
return String.format("%.2f MB", Convert.toDouble(newVal, 0D) * 1024);
}
if (StrUtil.endWithIgnoreCase(val, "m")) {
String newVal = val.substring(0, val.length() - 1);
return Convert.toLong(newVal, 0L) / 1024 + " MB";
}
return Convert.toLong(val, 0L) / 1024 + " MB";
}
/**
* 获取内存信息
*

View File

@ -8,7 +8,6 @@ import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.system.NetstatModel;
import cn.keepbx.jpom.util.CommandUtil;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@ -19,10 +18,6 @@ import java.util.List;
*/
public class WindowsProjectCommander extends AbstractProjectCommander {
public WindowsProjectCommander(Charset charset) {
super(charset);
}
@Override
public String start(ProjectInfoModel projectInfoModel) throws Exception {
String msg = checkStart(projectInfoModel);

View File

@ -19,8 +19,10 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* windows 系统查询命令
*
* @author jiangzeyin
* @date 2019/4/15
* @date 2019/4/16
*/
public class WindowsSystemCommander extends AbstractSystemCommander {
@ -28,31 +30,7 @@ public class WindowsSystemCommander extends AbstractSystemCommander {
* 锁定查看进程信息
*/
private static final AtomicBoolean ATOMIC_BOOLEAN = new AtomicBoolean(false);
@Override
public List<ProcessModel> getProcessList() {
if (ATOMIC_BOOLEAN.get()) {
return null;
}
try {
ATOMIC_BOOLEAN.set(true);
String s = CommandUtil.execSystemCommand("tasklist /V | findstr java");
return formatWindowsProcess(s, false);
} finally {
ATOMIC_BOOLEAN.set(false);
}
}
@Override
public ProcessModel getPidInfo(int pid) {
String command = "tasklist /V /FI \"pid eq " + pid + "\"";
String result = CommandUtil.execCommand(command);
List<ProcessModel> array = formatWindowsProcess(result, true);
if (array == null || array.isEmpty()) {
return null;
}
return array.get(0);
}
private static List<ProcessModel> lastResult;
/**
* 获取windows 监控
@ -89,6 +67,34 @@ public class WindowsSystemCommander extends AbstractSystemCommander {
return jsonObject;
}
@Override
public List<ProcessModel> getProcessList() {
if (ATOMIC_BOOLEAN.get()) {
// 返回上一次结果
return lastResult;
}
try {
ATOMIC_BOOLEAN.set(true);
String s = CommandUtil.execSystemCommand("tasklist /V | findstr java");
lastResult = formatWindowsProcess(s, false);
return lastResult;
} finally {
ATOMIC_BOOLEAN.set(false);
}
}
@Override
public ProcessModel getPidInfo(int pid) {
String command = "tasklist /V /FI \"pid eq " + pid + "\"";
String result = CommandUtil.execCommand(command);
List<ProcessModel> array = formatWindowsProcess(result, true);
if (array == null || array.isEmpty()) {
return null;
}
return array.get(0);
}
/**
* 将windows的tasklist转为集合
*
@ -160,5 +166,4 @@ public class WindowsSystemCommander extends AbstractSystemCommander {
}
return "未知";
}
}

View File

@ -1,5 +1,5 @@
/**
* 系统实体信息
* Jpom 管理项目实现管理的工具包
* <p>
* The MIT License(MIT)
* <p>
@ -25,4 +25,4 @@
*
* @author jiangzeyin
*/
package cn.keepbx.jpom.model.system;
package cn.keepbx.jpom.common.commander;

View File

@ -0,0 +1,49 @@
package cn.keepbx.jpom.common.interceptor;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.interceptor.BaseInterceptor;
import cn.jiangzeyin.common.interceptor.InterceptorPattens;
import cn.keepbx.jpom.system.AgentAuthorize;
import cn.keepbx.jpom.system.ConfigBean;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 授权拦截
*
* @author jiangzeyin
* @date 2019/4/17
*/
@InterceptorPattens()
public class AuthorizeInterceptor extends BaseInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.preHandle(request, response, handler);
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
NotAuthorize notAuthorize = handlerMethod.getMethodAnnotation(NotAuthorize.class);
if (notAuthorize == null) {
String authorize = ServletUtil.getHeaderIgnoreCase(request, ConfigBean.JPOM_AGENT_AUTHORIZE);
if (StrUtil.isEmpty(authorize)) {
this.error(response);
return false;
}
if (!AgentAuthorize.getInstance().checkAuthorize(authorize)) {
this.error(response);
return false;
}
}
}
return true;
}
private void error(HttpServletResponse response) {
ServletUtil.write(response, JsonMessage.getString(ConfigBean.AUTHORIZE_ERROR, "授权信息错误"), MediaType.APPLICATION_JSON_UTF8_VALUE);
}
}

View File

@ -0,0 +1,15 @@
package cn.keepbx.jpom.common.interceptor;
import java.lang.annotation.*;
/**
* 不需要授权
* Created by jiangzeyin on 2019/4/17.
*/
@Documented
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface NotAuthorize {
}

View File

@ -0,0 +1,86 @@
package cn.keepbx.jpom.controller;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.common.interceptor.NotAuthorize;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.system.JpomManifest;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.util.JvmUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 首页
*
* @author jiangzeyin
* @date 2019/4/17
*/
@RestController
public class IndexController extends BaseAgentController {
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
@Resource
private ProjectInfoService projectInfoService;
@RequestMapping(value = {"index", "", "index.html", "/"}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@NotAuthorize
public String index() {
return "Jpom-Agent";
}
@RequestMapping(value = "info", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String info() {
int code;
if (whitelistDirectoryService.isInstalled()) {
code = 200;
} else {
code = 201;
}
return JsonMessage.getString(code, "", JpomManifest.getInstance());
}
/**
* 返回节点项目状态信息
*
* @return array
*/
@RequestMapping(value = "status", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String status() {
List<ProjectInfoModel> projectInfoModels = projectInfoService.list();
JSONObject jsonObject = new JSONObject();
jsonObject.put("javaVirtualCount", JvmUtil.getJavaVirtualCount());
jsonObject.put("osName", BaseJpomApplication.OS_INFO.getName());
jsonObject.put("jpomVersion", JpomManifest.getInstance().getVersion());
if (projectInfoModels == null) {
jsonObject.put("count", 0);
jsonObject.put("runCount", 0);
jsonObject.put("stopCount", 0);
return JsonMessage.getString(200, "", jsonObject);
}
int count = 0, runCount = 0, stopCount = 0;
for (ProjectInfoModel projectInfoModel : projectInfoModels) {
count++;
if (projectInfoModel.isStatus(true)) {
runCount++;
} else {
stopCount++;
}
}
jsonObject.put("count", count);
jsonObject.put("runCount", runCount);
jsonObject.put("stopCount", stopCount);
JSONArray jsonArray = new JSONArray();
jsonArray.add(jsonObject);
return JsonMessage.getString(200, "", jsonArray);
}
}

View File

@ -1,34 +1,26 @@
package cn.keepbx.jpom.controller;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.jiangzeyin.controller.base.AbstractController;
import cn.keepbx.jpom.common.commander.AbstractSystemCommander;
import cn.keepbx.jpom.model.system.ProcessModel;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 欢迎页
*
* @author Administrator
* @author jiangzeyin
* @date 2019/4/16
*/
@Controller
@RequestMapping(value = "/")
public class WelcomeController extends BaseController {
@RequestMapping(value = "welcome", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String welcome() {
return "welcome";
}
@RestController
public class WelcomeController extends AbstractController {
@RequestMapping(value = "getTop", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String getTop() {
JSONObject topInfo = AbstractSystemCommander.getInstance().getAllMonitor();
return JsonMessage.getString(200, "", topInfo);
@ -38,6 +30,9 @@ public class WelcomeController extends BaseController {
@ResponseBody
public String getProcessList() {
List<ProcessModel> array = AbstractSystemCommander.getInstance().getProcessList();
return JsonMessage.getString(200, "", array);
if (array != null && !array.isEmpty()) {
return JsonMessage.getString(200, "", array);
}
return JsonMessage.getString(402, "没有获取到进程信息");
}
}

View File

@ -5,18 +5,16 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.interceptor.ProjectPermission;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.service.oss.OssManagerService;
import cn.keepbx.jpom.socket.CommandOp;
import com.alibaba.fastjson.JSONArray;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
@ -27,48 +25,43 @@ import java.io.File;
* @author jiangzeyin
* @date 2018/9/29
*/
@Controller
@RestController
@RequestMapping(value = "/manage/")
public class BuildController extends BaseController {
public class BuildController extends BaseAgentController {
@Resource
private OssManagerService ossManagerService;
@Resource
private ProjectInfoService projectInfoService;
@Resource
private ConsoleService consoleService;
@RequestMapping(value = "build", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
@RequestMapping(value = "build_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String build(String id) {
ProjectInfoModel projectInfoModel = projectInfoService.getItem(id);
JSONArray jsonArray = null;
if (projectInfoModel != null && StrUtil.isNotEmpty(projectInfoModel.getBuildTag())) {
JSONArray jsonArray = ossManagerService.list(projectInfoModel.getBuildTag());
setAttribute("array", jsonArray);
setAttribute("id", id);
jsonArray = ossManagerService.list(projectInfoModel.getBuildTag());
}
return "manage/build";
return JsonMessage.getString(200, "", jsonArray);
}
@RequestMapping(value = "build_download", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
@RequestMapping(value = "build_download", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String buildDownload(String id, String key) {
if (!getUser().isProject(id)) {
return "redirect:error";
if (StrUtil.isEmpty(key)) {
return JsonMessage.getString(401, "key 错误");
}
String url = null;
try {
ProjectInfoModel projectInfoModel = projectInfoService.getItem(id);
if (projectInfoModel == null) {
return "redirect:error";
if (projectInfoModel != null) {
url = ossManagerService.getUrl(key).toString();
}
return "redirect:" + ossManagerService.getUrl(key);
} catch (Exception e) {
DefaultSystemLog.ERROR().error("获取下载地址失败", e);
return "redirect:error";
}
return JsonMessage.getString(200, "", url);
}
@RequestMapping(value = "build_install", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission
public String buildInstall(String key) throws Exception {
ProjectInfoModel projectInfoModel = getProjectInfoModel();
if (StrUtil.isEmpty(projectInfoModel.getBuildTag())) {
@ -86,7 +79,7 @@ public class BuildController extends BaseController {
// 修改使用状态
projectInfoModel.setUseLibDesc("build");
projectInfoService.updateItem(projectInfoModel);
String result = consoleService.execCommand(ConsoleService.CommandOp.restart, projectInfoModel);
String result = consoleService.execCommand(CommandOp.restart, projectInfoModel);
return JsonMessage.getString(200, "安装成功,已自动重启,当前状态是:" + result);
}
}

View File

@ -1,5 +1,6 @@
package cn.keepbx.jpom.controller.manage;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.PatternPool;
@ -8,100 +9,54 @@ import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.Role;
import cn.keepbx.jpom.model.RunMode;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.service.system.WhitelistDirectoryService;
import cn.keepbx.jpom.socket.LogWebSocketHandle;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import cn.keepbx.jpom.socket.CommonSocketConfig;
import cn.keepbx.jpom.system.ConfigBean;
import com.alibaba.fastjson.JSONArray;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
/**
* 项目管理
* 编辑项目
*
* @author jiangzeyin
* @date 2018/9/29
* @date 2019/4/16
*/
@Controller
@RestController
@RequestMapping(value = "/manage/")
public class EditProjectController extends BaseController {
@Resource
private ProjectInfoService projectInfoService;
public class EditProjectController extends BaseAgentController {
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
/**
* 修改项目页面
*
* @param id 项目Id
* @return json
* @throws IOException IO
*/
@RequestMapping(value = "editProject", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String editProject(String id) throws IOException {
ProjectInfoModel projectInfo = projectInfoService.getItem(id);
// 白名单
JSONArray jsonArray = whitelistDirectoryService.getProjectDirectory();
setAttribute("whitelistDirectory", jsonArray);
if (projectInfo != null && jsonArray != null) {
for (Object obj : jsonArray) {
String path = obj.toString();
String lib = projectInfo.getLib();
if (lib.startsWith(path)) {
String itemWhitelistDirectory = lib.substring(0, path.length());
lib = lib.substring(path.length());
setAttribute("itemWhitelistDirectory", itemWhitelistDirectory);
projectInfo.setLib(lib);
break;
}
}
}
setAttribute("item", projectInfo);
// 运行模式
ProjectInfoModel.RunMode[] runModes = ProjectInfoModel.RunMode.values();
setAttribute("runModes", runModes);
//
HashSet<String> hashSet = projectInfoService.getAllGroup();
if (hashSet.isEmpty()) {
hashSet.add("默认");
}
setAttribute("groups", hashSet);
return "manage/editProject";
}
/**
* 基础检查
*
* @param projectInfo 项目实体
* @param whitelistDirectory 白名单
* @param previewData 预检查数据
* @return null 检查正常
*/
private String checkParameter(ProjectInfoModel projectInfo, String whitelistDirectory) {
private String checkParameter(ProjectInfoModel projectInfo, String whitelistDirectory, boolean previewData) {
String id = projectInfo.getId();
if (StrUtil.isEmptyOrUndefined(id)) {
return JsonMessage.getString(400, "项目id不能为空");
}
if (Validator.isChinese(id)) {
return JsonMessage.getString(401, "项目id不能包含中文");
if (!Validator.isGeneral(id, 2, 20)) {
return JsonMessage.getString(401, "项目id 长度范围2-20英文字母 、数字和下划线)");
}
if (LogWebSocketHandle.SYSTEM_ID.equals(id)) {
return JsonMessage.getString(401, "项目id " + LogWebSocketHandle.SYSTEM_ID + " 关键词被系统占用");
if (CommonSocketConfig.SYSTEM_ID.equals(id)) {
return JsonMessage.getString(401, "项目id " + CommonSocketConfig.SYSTEM_ID + " 关键词被系统占用");
}
// 防止和Jpom冲突
if (StrUtil.isNotEmpty(ConfigBean.getInstance().applicationTag) && ConfigBean.getInstance().applicationTag.equalsIgnoreCase(id)) {
@ -109,33 +64,49 @@ public class EditProjectController extends BaseController {
}
// 运行模式
String runMode = getParameter("runMode");
ProjectInfoModel.RunMode runMode1 = ProjectInfoModel.RunMode.ClassPath;
RunMode runMode1 = RunMode.ClassPath;
try {
runMode1 = ProjectInfoModel.RunMode.valueOf(runMode);
runMode1 = RunMode.valueOf(runMode);
} catch (Exception ignored) {
}
projectInfo.setRunMode(runMode1);
// 监测
if (runMode1 == ProjectInfoModel.RunMode.ClassPath) {
if (runMode1 == RunMode.ClassPath) {
if (StrUtil.isEmpty(projectInfo.getMainClass())) {
return JsonMessage.getString(401, "ClassPath 模式 MainClass必填");
}
} else if (runMode1 == ProjectInfoModel.RunMode.Jar) {
} else if (runMode1 == RunMode.Jar) {
projectInfo.setMainClass("");
}
//
if (!whitelistDirectoryService.checkProjectDirectory(whitelistDirectory)) {
return JsonMessage.getString(401, "请选择正确的项目路径,或者还没有配置白名单");
// 判断是否为分发添加
String strOutGivingProject = getParameter("outGivingProject");
boolean outGivingProject = Boolean.valueOf(strOutGivingProject);
// 检查权限
Role role = getUserRole();
if (outGivingProject) {
if (role != Role.System && role != Role.NodeManage) {
return JsonMessage.getString(405, "没有权限操作分发项目管理");
}
}
projectInfo.setOutGivingProject(outGivingProject);
if (!previewData) {
// 不是预检查数据才效验白名单
if (!whitelistDirectoryService.checkProjectDirectory(whitelistDirectory)) {
if (outGivingProject) {
if (role == Role.System) {
whitelistDirectoryService.addProjectWhiteList(whitelistDirectory);
} else {
return JsonMessage.getString(405, "对应白名单还没有添加,请联系管理员添加");
}
} else {
return JsonMessage.getString(401, "请选择正确的项目路径,或者还没有配置白名单");
}
}
}
String lib = projectInfo.getLib();
if (StrUtil.isEmpty(lib)) {
return JsonMessage.getString(401, "项目Jar路径不能为空");
}
if (StrUtil.SLASH.equals(lib)) {
return JsonMessage.getString(401, "项目Jar路径不能为顶级目录");
}
if (Validator.isChinese(lib)) {
return JsonMessage.getString(401, "项目Jar路径中不能包含中文");
if (StrUtil.isEmpty(lib) || StrUtil.SLASH.equals(lib) || Validator.isChinese(lib)) {
return JsonMessage.getString(401, "项目Jar路径不能为空,不能为顶级目录,不能包含中文");
}
if (!checkPathSafe(lib)) {
return JsonMessage.getString(401, "项目Jar路径存在提升目录问题");
@ -143,21 +114,20 @@ public class EditProjectController extends BaseController {
return null;
}
/**
* 保存项目
*
* @param projectInfo 项目实体
* @return json
*/
@RequestMapping(value = "saveProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String saveProject(ProjectInfoModel projectInfo, String whitelistDirectory) {
String error = checkParameter(projectInfo, whitelistDirectory);
// 预检查数据
String strPreviewData = getParameter("previewData");
boolean previewData = Convert.toBool(strPreviewData, false);
//
String error = checkParameter(projectInfo, whitelistDirectory, previewData);
if (error != null) {
return error;
}
String lib = projectInfo.getLib();
String id = projectInfo.getId();
//
String lib = projectInfo.getLib();
lib = String.format("%s/%s", whitelistDirectory, lib);
lib = FileUtil.normalize(lib);
// 重复lib
@ -191,53 +161,63 @@ public class EditProjectController extends BaseController {
if (id.contains(StrUtil.SPACE) || lib.contains(StrUtil.SPACE)) {
return JsonMessage.getString(401, "项目Id、项目Jar不能包含空格");
}
return save(projectInfo);
return save(projectInfo, previewData);
}
private String save(ProjectInfoModel projectInfo) {
/**
* 保存项目
*
* @param projectInfo 项目
* @param previewData 是否是预检查
* @return 错误信息
*/
private String save(ProjectInfoModel projectInfo, boolean previewData) {
String edit = getParameter("edit");
ProjectInfoModel exits = projectInfoService.getItem(projectInfo.getId());
try {
UserModel userName = getUser();
JsonMessage jsonMessage = checkPath(projectInfo);
if (jsonMessage != null) {
return jsonMessage.toString();
}
if (exits == null) {
if (!userName.isManage()) {
return JsonMessage.getString(400, "管理员才能创建项目!");
}
// 检查运行中的tag 是否被占用
if (AbstractProjectCommander.getInstance().isRun(projectInfo.getId())) {
return JsonMessage.getString(400, "当前项目id已经被正在运行的程序占用");
}
projectInfo.setCreateTime(DateUtil.now());
this.modify(projectInfo);
projectInfoService.addItem(projectInfo);
return JsonMessage.getString(200, "新增成功!");
if (previewData) {
// 预检查数据
return JsonMessage.getString(200, "");
} else {
projectInfo.setCreateTime(DateUtil.now());
this.modify(projectInfo);
projectInfoService.addItem(projectInfo);
return JsonMessage.getString(200, "新增成功!");
}
}
//
// 新增但是下面id 已经存在
if (!"on".equalsIgnoreCase(edit)) {
return JsonMessage.getString(400, "项目id已经存在啦");
}
if (!userName.isProject(projectInfo.getId())) {
return JsonMessage.getString(400, "你没有对应操作权限操作!");
if (previewData) {
// 预检查数据
return JsonMessage.getString(200, "");
} else {
this.modify(exits);
exits.setLog(projectInfo.getLog());
exits.setName(projectInfo.getName());
exits.setGroup(projectInfo.getGroup());
exits.setMainClass(projectInfo.getMainClass());
exits.setLib(projectInfo.getLib());
exits.setJvm(projectInfo.getJvm());
exits.setArgs(projectInfo.getArgs());
exits.setBuildTag(projectInfo.getBuildTag());
exits.setRunMode(projectInfo.getRunMode());
exits.setToken(projectInfo.getToken());
//
moveTo(exits, projectInfo);
projectInfoService.updateItem(exits);
return JsonMessage.getString(200, "修改成功");
}
this.modify(exits);
exits.setLog(projectInfo.getLog());
exits.setName(projectInfo.getName());
exits.setGroup(projectInfo.getGroup());
exits.setMainClass(projectInfo.getMainClass());
exits.setLib(projectInfo.getLib());
exits.setJvm(projectInfo.getJvm());
exits.setArgs(projectInfo.getArgs());
exits.setBuildTag(projectInfo.getBuildTag());
exits.setRunMode(projectInfo.getRunMode());
exits.setToken(projectInfo.getToken());
//
moveTo(exits, projectInfo);
projectInfoService.updateItem(exits);
return JsonMessage.getString(200, "修改成功");
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, e.getMessage());
@ -250,52 +230,7 @@ public class EditProjectController extends BaseController {
* @param exits 项目
*/
private void modify(ProjectInfoModel exits) {
UserModel userName = getUser();
exits.logModifyUser(userName);
}
/**
* 验证lib 暂时用情况
*
* @param id 项目Id
* @param newLib 新lib
* @return json
*/
@RequestMapping(value = "judge_lib.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String saveProject(String id, String newLib) {
File file = new File(newLib);
// 填写的jar路径是一个存在的文件
if (file.exists() && file.isFile()) {
return JsonMessage.getString(400, "填写jar目录当前是一个已经存在的文件,请修改");
}
ProjectInfoModel exits = projectInfoService.getItem(id);
if (exits == null) {
// 创建项目 填写的jar路径是已经存在的文件夹
if (file.exists()) {
return JsonMessage.getString(401, "填写jar目录当前已经在,创建成功后会自动同步文件");
}
} else {
// 已经存在的项目
File oldLib = new File(exits.getLib());
Path newPath = file.toPath();
Path oldPath = oldLib.toPath();
if (newPath.equals(oldPath)) {
// 旧没有变更
return JsonMessage.getString(200, "");
}
if (file.exists()) {
if (oldLib.exists()) {
// 新旧jar路径都存在会自动覆盖新的jar路径中的文件
return JsonMessage.getString(401, "原jar目录已经存在并且新的jar目录已经存在,保存将覆盖新文件夹并会自动同步原jar目录");
}
return JsonMessage.getString(401, "填写jar目录当前已经在,创建成功后会自动同步文件");
}
}
if (Validator.isChinese(newLib)) {
return JsonMessage.getString(401, "不建议使用中文目录");
}
return JsonMessage.getString(200, "");
exits.setModifyUser(getUserName());
}
private void moveTo(ProjectInfoModel old, ProjectInfoModel news) {
@ -352,4 +287,61 @@ public class EditProjectController extends BaseController {
}
return null;
}
@RequestMapping(value = "deleteProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String deleteProject() {
ProjectInfoModel projectInfoModel = tryGetProjectInfoModel();
if (projectInfoModel == null) {
return JsonMessage.getString(200, "项目不存在");
}
try {
// 运行判断
if (projectInfoModel.isStatus(true)) {
return JsonMessage.getString(401, "不能删除正在运行的项目");
}
String userId = getUserName();
projectInfoService.deleteProject(projectInfoModel, userId);
return JsonMessage.getString(200, "删除成功!");
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, e.getMessage());
}
}
@RequestMapping(value = "judge_lib.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String saveProject(String id, String newLib) {
File file = new File(newLib);
// 填写的jar路径是一个存在的文件
if (file.exists() && file.isFile()) {
return JsonMessage.getString(400, "填写jar目录当前是一个已经存在的文件,请修改");
}
ProjectInfoModel exits = projectInfoService.getItem(id);
if (exits == null) {
// 创建项目 填写的jar路径是已经存在的文件夹
if (file.exists()) {
return JsonMessage.getString(401, "填写jar目录当前已经在,创建成功后会自动同步文件");
}
} else {
// 已经存在的项目
File oldLib = new File(exits.getLib());
Path newPath = file.toPath();
Path oldPath = oldLib.toPath();
if (newPath.equals(oldPath)) {
// 旧没有变更
return JsonMessage.getString(200, "");
}
if (file.exists()) {
if (oldLib.exists()) {
// 新旧jar路径都存在会自动覆盖新的jar路径中的文件
return JsonMessage.getString(401, "原jar目录已经存在并且新的jar目录已经存在,保存将覆盖新文件夹并会自动同步原jar目录");
}
return JsonMessage.getString(401, "填写jar目录当前已经在,创建成功后会自动同步文件");
}
}
if (Validator.isChinese(newLib)) {
return JsonMessage.getString(401, "不建议使用中文目录");
}
return JsonMessage.getString(200, "");
}
}

View File

@ -1,4 +1,4 @@
package cn.keepbx.jpom.controller.manage.file;
package cn.keepbx.jpom.controller.manage;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
@ -8,53 +8,34 @@ import cn.hutool.extra.servlet.ServletUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.interceptor.ProjectPermission;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.socket.CommandOp;
import cn.keepbx.jpom.system.AgentConfigBean;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
/**
* 文件管理
* 项目文件管理
*
* @author Administrator
* @author jiangzeyin
* @date 2019/4/17
*/
@Controller
@RestController
@RequestMapping(value = "/manage/file/")
public class ProjectFileControl extends BaseController {
public class ProjectFileControl extends BaseAgentController {
@Resource
private ProjectInfoService projectInfoService;
private ConsoleService consoleService;
/**
* 文件管理页面
*
* @param id 项目id
*/
@RequestMapping(value = "list.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String fileManage(String id) {
setAttribute("id", id);
return "manage/filemanage";
}
/**
* 列出目录下的文件
*
* @param id 项目id
*/
@RequestMapping(value = "getFileList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission
public String getFileList(String id) {
// 查询项目路径
ProjectInfoModel pim = projectInfoService.getItem(id);
@ -107,21 +88,15 @@ public class ProjectFileControl extends BaseController {
return arrayFile;
}
/**
* 上传文件
*
* @return json
*/
@RequestMapping(value = "upload", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission(checkUpload = true)
public String upload() throws Exception {
ProjectInfoModel pim = getProjectInfoModel();
MultipartFileBuilder multipartFileBuilder = createMultipart()
.addFieldName("file");
String type = getParameter("type");
if ("unzip".equals(type)) {
multipartFileBuilder.setSavePath(ConfigBean.getInstance().getTempPathName());
multipartFileBuilder.setInputStreamType("zip");
multipartFileBuilder.setSavePath(AgentConfigBean.getInstance().getTempPathName());
String path = multipartFileBuilder.save();
//
File lib = new File(pim.getLib());
@ -142,17 +117,49 @@ public class ProjectFileControl extends BaseController {
// 修改使用状态
pim.setUseLibDesc("upload");
projectInfoService.updateItem(pim);
//
String after = getParameter("after");
if ("restart".equalsIgnoreCase(after)) {
String result = consoleService.execCommand(CommandOp.restart, pim);
return JsonMessage.getString(200, "上传成功并重启:" + result);
}
return JsonMessage.getString(200, "上传成功");
}
/**
* 下载文件
*
* @param id 项目id
* @return File
*/
@RequestMapping(value = "deleteFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String deleteFile(String filename, String type) {
ProjectInfoModel pim = getProjectInfoModel();
if ("clear".equalsIgnoreCase(type)) {
// 清空文件
File file = new File(pim.getLib());
if (FileUtil.clean(file)) {
return JsonMessage.getString(200, "清除成功");
}
if (pim.isStatus(true)) {
return JsonMessage.getString(501, "文件被占用,请先停止项目");
}
return JsonMessage.getString(500, "删除失败:" + file.getAbsolutePath());
} else {
// 删除文件
String fileName = pathSafe(filename);
if (StrUtil.isEmpty(fileName)) {
return JsonMessage.getString(405, "非法操作");
}
File file = FileUtil.file(pim.getLib(), fileName);
if (file.exists()) {
if (FileUtil.del(file)) {
return JsonMessage.getString(200, "删除成功");
}
} else {
return JsonMessage.getString(404, "文件不存在");
}
return JsonMessage.getString(500, "删除失败");
}
}
@RequestMapping(value = "download", method = RequestMethod.GET)
@ResponseBody
public String download(String id, String filename) {
filename = pathSafe(filename);
if (StrUtil.isEmpty(filename)) {
@ -171,51 +178,4 @@ public class ProjectFileControl extends BaseController {
}
return "下载失败。请刷新页面后重试";
}
/**
* 清除文件
*
* @return json
*/
@RequestMapping(value = "clear", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission(checkDelete = true)
public String clear() {
ProjectInfoModel pim = getProjectInfoModel();
File file = new File(pim.getLib());
if (FileUtil.clean(file)) {
return JsonMessage.getString(200, "清除成功");
}
if (pim.isStatus(true)) {
return JsonMessage.getString(501, "文件被占用,请先停止项目");
}
return JsonMessage.getString(500, "删除失败:" + file.getAbsolutePath());
}
/**
* 删除文件
*
* @param filename 文件名称
* @return json
*/
@RequestMapping(value = "deleteFile", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission(checkDelete = true)
public String deleteFile(String filename) {
String fileName = pathSafe(filename);
if (StrUtil.isEmpty(fileName)) {
return JsonMessage.getString(405, "非法操作");
}
ProjectInfoModel pim = getProjectInfoModel();
File file = FileUtil.file(pim.getLib(), fileName);
if (file.exists()) {
if (FileUtil.del(file)) {
return JsonMessage.getString(200, "删除成功");
}
} else {
return JsonMessage.getString(404, "文件不存在");
}
return JsonMessage.getString(500, "删除失败");
}
}

View File

@ -3,59 +3,124 @@ package cn.keepbx.jpom.controller.manage;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.Role;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.common.interceptor.ProjectPermission;
import cn.keepbx.jpom.common.interceptor.UrlPermission;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
/**
* 项目管理
* 管理的信息获取接口
*
* @author Administrator
* @author jiangzeyin
* @date 2019/4/16
*/
@Controller
@RestController
@RequestMapping(value = "/manage/")
public class ProjectManageControl extends BaseController {
@Resource
private ProjectInfoService projectInfoService;
public class ProjectListController extends BaseAgentController {
/**
* 展示项目页面
* 获取项目的信息
*
* @return page
* @param id id
* @return item
* @see ProjectInfoModel
*/
@RequestMapping(value = "projectInfo", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String projectInfo() {
HashSet hashSet = projectInfoService.getAllGroup();
setAttribute("groups", hashSet);
return "manage/projectInfo";
@RequestMapping(value = "getProjectItem", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getProjectItem(String id) {
return JsonMessage.getString(200, "", projectInfoService.getItem(id));
}
/**
* 获取正在运行的项目的端口和进程id
* 获取所有的分组
*
* @param ids ids
* @return array
*/
@RequestMapping(value = "getProjectGroup", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getProjectGroup() {
HashSet<String> strings = projectInfoService.getAllGroup();
return JsonMessage.getString(200, "", strings);
}
/**
* 获取项目的进程id
*
* @param id 项目id
* @return json
*/
@RequestMapping(value = "getProjectStatus", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getProjectStatus(String id) {
if (StrUtil.isEmpty(id)) {
return JsonMessage.getString(405, "项目id 不正确");
}
int pid = 0;
try {
pid = AbstractProjectCommander.getInstance().getPid(id);
} catch (Exception e) {
DefaultSystemLog.ERROR().error("获取项目pid 失败", e);
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("pId", pid);
return JsonMessage.getString(200, "", jsonObject);
}
/**
* 程序项目信息
*
* @param group 分组
* @return json
*/
@RequestMapping(value = "getProjectInfo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getProjectInfo(String group, String notStatus) {
try {
boolean status = StrUtil.isEmpty(notStatus);
// 查询数据
List<ProjectInfoModel> projectInfoModels = projectInfoService.list();
// 转换为数据
JSONArray array = new JSONArray();
for (ProjectInfoModel projectInfoModel : projectInfoModels) {
if (StrUtil.isNotEmpty(group) && !group.equals(projectInfoModel.getGroup())) {
continue;
}
JSONObject object = projectInfoModel.toJson();
if (status) {
object.put("status", projectInfoModel.isStatus(true));
}
array.add(object);
}
array.sort((oo1, oo2) -> {
JSONObject o1 = (JSONObject) oo1;
JSONObject o2 = (JSONObject) oo2;
String group1 = o1.getString("group");
String group2 = o2.getString("group");
if (group1 == null || group2 == null) {
return -1;
}
return group1.compareTo(group2);
});
return JsonMessage.getString(200, "查询成功!", array);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, e.getMessage());
}
}
/**
* 获取项目的运行端口
*
* @param ids ids
* @return obj
*/
@RequestMapping(value = "getProjectPort", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String getProjectPort(String ids) {
public String getProjectGroup(String ids) {
if (StrUtil.isEmpty(ids)) {
return JsonMessage.getString(400, "");
}
@ -83,76 +148,14 @@ public class ProjectManageControl extends BaseController {
return JsonMessage.getString(200, "", jsonObject);
}
/**
* 查询所有项目
*
* @return json
*/
@RequestMapping(value = "getProjectInfo", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public String getProjectInfo(String group) {
try {
UserModel userName = getUser();
// 查询数据
List<ProjectInfoModel> projectInfoModels = projectInfoService.list();
// 转换为数据
JSONArray array = new JSONArray();
for (ProjectInfoModel projectInfoModel : projectInfoModels) {
if (StrUtil.isNotEmpty(group) && !group.equals(projectInfoModel.getGroup())) {
continue;
}
String id = projectInfoModel.getId();
JSONObject object = projectInfoModel.toJson();
object.put("manager", userName.isProject(id));
object.put("status", projectInfoModel.isStatus(true));
array.add(object);
}
array.sort((oo1, oo2) -> {
JSONObject o1 = (JSONObject) oo1;
JSONObject o2 = (JSONObject) oo2;
String group1 = o1.getString("group");
String group2 = o2.getString("group");
if (group1 == null || group2 == null) {
return -1;
}
return group1.compareTo(group2);
});
return JsonMessage.getString(200, "查询成功!", array);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, e.getMessage());
}
}
/**
* 删除项目
*
* @return json
*/
@RequestMapping(value = "deleteProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission
@UrlPermission(Role.Manage)
public String deleteProject() {
ProjectInfoModel projectInfoModel = getProjectInfoModel();
UserModel userModel = getUser();
try {
// 运行判断
if (projectInfoModel.isStatus(true)) {
return JsonMessage.getString(401, "不能删除正在运行的项目");
}
String userId;
if (userModel.isSystemUser()) {
userId = UserModel.SYSTEM_OCCUPY_NAME;
} else {
userId = userModel.getId();
}
projectInfoService.deleteProject(projectInfoModel, userId);
return JsonMessage.getString(200, "删除成功!");
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, e.getMessage());
}
}
// /**
// * 获取运行方式
// *
// * @return array
// */
// @RequestMapping(value = "getRunModes", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
// public String getRunModes() {
// ProjectInfoModel.RunMode[] runModes = ProjectInfoModel.RunMode.values();
// return JsonMessage.getString(200, "", runModes);
// }
}

View File

@ -1,50 +1,38 @@
package cn.keepbx.jpom.controller.manage.recover;
package cn.keepbx.jpom.controller.manage;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.BaseJpomController;
import cn.keepbx.jpom.model.data.ProjectRecoverModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.manage.ProjectRecoverService;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
/**
* 项目管理
* 回收站管理
*
* @author Administrator
* @author jiangzeyin
* @date 2019/4/16
*/
@Controller
@RestController
@RequestMapping(value = "/manage/recover")
public class ProjectRecoverControl extends BaseController {
public class ProjectRecoverControl extends BaseJpomController {
@Resource
private ProjectRecoverService projectRecoverService;
/**
* 展示项目页面
*
* @return page
*/
@RequestMapping(value = "list.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
@RequestMapping(value = "list_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String projectInfo() {
UserModel userModel = getUser();
if (userModel.isManage()) {
List<ProjectRecoverModel> projectInfoModels = projectRecoverService.list();
setAttribute("array", projectInfoModels);
}
return "manage/project_recover";
List<ProjectRecoverModel> projectInfoModels = projectRecoverService.list();
return JsonMessage.getString(200, "", projectInfoModels);
}
@RequestMapping(value = "data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@RequestMapping(value = "item_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String project(String id) throws IOException {
if (StrUtil.isEmpty(id)) {
return JsonMessage.getString(400, "项目id错误");
@ -52,5 +40,4 @@ public class ProjectRecoverControl extends BaseController {
ProjectRecoverModel item = projectRecoverService.getItem(id);
return JsonMessage.getString(200, "", item);
}
}

View File

@ -5,72 +5,78 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.common.interceptor.ProjectPermission;
import cn.keepbx.jpom.controller.manage.file.ProjectFileControl;
import cn.keepbx.jpom.controller.manage.ProjectFileControl;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
/**
* 控制台日志备份管理
*
* @author jiangzeyin
* @date 2019/3/7
* @date 2019/4/17
*/
@Controller
@RequestMapping(value = "/manage/log")
public class LogBackController extends BaseController {
@Resource
private ProjectInfoService projectInfoService;
@RestController
@RequestMapping(value = "manage/log")
public class LogBackController extends BaseAgentController {
@RequestMapping(value = "export.html", method = RequestMethod.GET)
@ResponseBody
@ProjectPermission
public String export() {
ProjectInfoModel pim = getProjectInfoModel();
File file = new File(pim.getLog());
if (!file.exists()) {
return JsonMessage.getString(400, "没有日志文件:" + file.getPath());
}
HttpServletResponse response = getResponse();
ServletUtil.write(response, file);
return JsonMessage.getString(200, "");
@RequestMapping(value = "logSize", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String logSize(String id) {
ProjectInfoModel projectInfoModel = getProjectInfoModel();
//获取日志备份路径
File logBack = projectInfoModel.getLogBack();
JSONObject jsonObject = new JSONObject();
boolean logBackBool = logBack.exists() && logBack.isDirectory();
jsonObject.put("logBack", logBackBool);
String info = projectInfoService.getLogSize(id);
jsonObject.put("logSize", info);
return JsonMessage.getString(200, "", jsonObject);
}
@RequestMapping(value = "logBack", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String console(String id) {
// 查询项目路径
ProjectInfoModel pim = projectInfoService.getItem(id);
if (pim != null) {
File logBack = pim.getLogBack();
if (logBack.exists() && logBack.isDirectory()) {
File[] filesAll = logBack.listFiles();
if (filesAll != null) {
JSONArray jsonArray = ProjectFileControl.parseInfo(filesAll, true);
setAttribute("array", jsonArray);
}
@RequestMapping(value = "resetLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String resetLog() {
ProjectInfoModel pim = getProjectInfoModel();
try {
String msg = AbstractProjectCommander.getInstance().backLog(pim);
if (msg.contains("ok")) {
return JsonMessage.getString(200, "重置成功");
}
setAttribute("id", pim.getId());
setAttribute("logPath", pim.getLog());
setAttribute("logBackPath", logBack.getAbsolutePath());
return JsonMessage.getString(201, "重置失败:" + msg);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, "重置日志失败");
}
}
@RequestMapping(value = "logBack_delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String clear(String name) {
name = pathSafe(name);
if (StrUtil.isEmpty(name)) {
return JsonMessage.getString(405, "非法操作:" + name);
}
ProjectInfoModel pim = getProjectInfoModel();
File logBack = pim.getLogBack();
if (logBack.exists() && logBack.isDirectory()) {
logBack = FileUtil.file(logBack, name);
if (logBack.exists()) {
FileUtil.del(logBack);
return JsonMessage.getString(200, "删除成功");
}
return JsonMessage.getString(500, "没有对应文件");
} else {
return JsonMessage.getString(500, "没有对应文件夹");
}
return "manage/logBack";
}
@RequestMapping(value = "logBack_download", method = RequestMethod.GET)
@ResponseBody
@ProjectPermission
public String download(String key) {
key = pathSafe(key);
if (StrUtil.isEmpty(key)) {
@ -91,58 +97,36 @@ public class LogBackController extends BaseController {
return "下载失败。请刷新页面后重试";
}
@RequestMapping(value = "logBack_delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission(checkDelete = true)
public String clear(String name) {
name = pathSafe(name);
if (StrUtil.isEmpty(name)) {
return JsonMessage.getString(405, "非法操作:" + name);
}
@RequestMapping(value = "logBack", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String console() {
// 查询项目路径
ProjectInfoModel pim = getProjectInfoModel();
JSONObject jsonObject = new JSONObject();
File logBack = pim.getLogBack();
if (logBack.exists() && logBack.isDirectory()) {
logBack = FileUtil.file(logBack, name);
if (logBack.exists()) {
FileUtil.del(logBack);
return JsonMessage.getString(200, "删除成功");
File[] filesAll = logBack.listFiles();
if (filesAll != null) {
JSONArray jsonArray = ProjectFileControl.parseInfo(filesAll, true);
jsonObject.put("array", jsonArray);
}
return JsonMessage.getString(500, "没有对应文件");
} else {
return JsonMessage.getString(500, "没有对应文件夹");
}
jsonObject.put("id", pim.getId());
jsonObject.put("logPath", pim.getLog());
jsonObject.put("logBackPath", logBack.getAbsolutePath());
return JsonMessage.getString(200, "", jsonObject);
}
@RequestMapping(value = "logSize", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RequestMapping(value = "export.html", method = RequestMethod.GET)
@ResponseBody
public String logSize(String id) {
String info = projectInfoService.getLogSize(id);
if (info != null) {
return JsonMessage.getString(200, "ok", info);
}
return JsonMessage.getString(500, "获取日志大小失败");
}
/**
* 重置日志
*
* @return json
*/
@RequestMapping(value = "resetLog", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@ProjectPermission
public String resetLog() {
public String export() {
ProjectInfoModel pim = getProjectInfoModel();
try {
String msg = AbstractProjectCommander.getInstance().backLog(pim);
if (msg.contains("ok")) {
return JsonMessage.getString(200, "重置成功");
}
return JsonMessage.getString(201, "重置失败:" + msg);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return JsonMessage.getString(500, "重置日志失败");
File file = new File(pim.getLog());
if (!file.exists()) {
return JsonMessage.getString(400, "没有日志文件:" + file.getPath());
}
HttpServletResponse response = getResponse();
ServletUtil.write(response, file);
return JsonMessage.getString(200, "");
}
}

View File

@ -4,21 +4,21 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.common.commander.AbstractSystemCommander;
import cn.keepbx.jpom.model.system.NetstatModel;
import cn.keepbx.jpom.model.system.ProcessModel;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.system.AgentConfigBean;
import cn.keepbx.jpom.util.CommandUtil;
import cn.keepbx.jpom.util.JvmUtil;
import com.alibaba.fastjson.JSONObject;
import com.sun.tools.attach.VirtualMachine;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
@ -32,27 +32,28 @@ import java.util.List;
*
* @author Administrator
*/
@Controller
@RestController
@RequestMapping(value = "/manage/")
public class InternalController extends BaseController {
public class InternalController extends BaseAgentController {
/**
* 获取内存信息
*/
@RequestMapping(value = "internal", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
@RequestMapping(value = "internal_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getInternal(String tag) throws Exception {
setAttribute("tag", tag);
int pid = AbstractProjectCommander.getInstance().getPid(tag);
if (pid > 0) {
ProcessModel item = AbstractSystemCommander.getInstance().getPidInfo(pid);
setAttribute("item", item);
JSONObject beanMem = getBeanMem(tag);
setAttribute("beanMem", beanMem);
//获取端口信息
List<NetstatModel> port = AbstractProjectCommander.getInstance().listNetstat(pid);
setAttribute("port", port);
if (pid <= 0) {
return JsonMessage.getString(400, "");
}
return "manage/internal";
JSONObject jsonObject = new JSONObject();
ProcessModel item = AbstractSystemCommander.getInstance().getPidInfo(pid);
jsonObject.put("process", item);
JSONObject beanMem = getBeanMem(tag);
jsonObject.put("beanMem", beanMem);
//获取端口信息
List<NetstatModel> netstatModels = AbstractProjectCommander.getInstance().listNetstat(pid);
jsonObject.put("netstat", netstatModels);
return JsonMessage.getString(200, "", jsonObject);
}
/**
@ -106,10 +107,10 @@ public class InternalController extends BaseController {
/**
* 导出堆栈信息
*/
@RequestMapping(value = "stack", method = RequestMethod.GET)
@RequestMapping(value = "internal_stack", method = RequestMethod.GET)
@ResponseBody
public String stack(String tag) throws Exception {
String fileName = ConfigBean.getInstance().getTempPathName() + "/" + tag + "_java_cpu.txt";
String fileName = AgentConfigBean.getInstance().getTempPathName() + "/" + tag + "_java_cpu.txt";
fileName = FileUtil.normalize(fileName);
try {
int pid = AbstractProjectCommander.getInstance().getPid(tag);
@ -121,7 +122,7 @@ public class InternalController extends BaseController {
downLoad(getResponse(), fileName);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
getResponse().sendRedirect("internal?tag=" + tag);
// getResponse().sendRedirect("internal?tag=" + tag);
}
return JsonMessage.getString(200, "");
}
@ -129,10 +130,10 @@ public class InternalController extends BaseController {
/**
* 导出内存信息
*/
@RequestMapping(value = "ram", method = RequestMethod.GET)
@RequestMapping(value = "internal_ram", method = RequestMethod.GET)
@ResponseBody
public String ram(String tag) throws Exception {
String fileName = ConfigBean.getInstance().getTempPathName() + "/" + tag + "_java_ram.txt";
String fileName = AgentConfigBean.getInstance().getTempPathName() + "/" + tag + "_java_ram.txt";
fileName = FileUtil.normalize(fileName);
try {
int pid = AbstractProjectCommander.getInstance().getPid(tag);
@ -144,7 +145,7 @@ public class InternalController extends BaseController {
downLoad(getResponse(), fileName);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
getResponse().sendRedirect("internal?tag=" + tag);
// getResponse().sendRedirect("internal?tag=" + tag);
}
return JsonMessage.getString(200, "");
}

View File

@ -2,39 +2,30 @@ package cn.keepbx.jpom.controller.system;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.Role;
import cn.keepbx.jpom.common.interceptor.UrlPermission;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.service.oss.OssManagerService;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 阿里云oss 配置
*
* @author jiangzeyin
* @date 2019/3/5
* @date 2019/4/17
*/
@Controller
@RestController
@RequestMapping(value = "/system")
public class AliOssController extends BaseController {
public class AliOssController extends BaseAgentController {
@Resource
private OssManagerService ossManagerService;
/**
* 页面
*/
@RequestMapping(value = "alioss", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
@RequestMapping(value = "alioss_config", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String whitelistDirectory() {
setAttribute("item", ossManagerService.getConfig());
return "system/alioss";
return JsonMessage.getString(200, "", ossManagerService.getConfig());
}
/**
@ -48,8 +39,6 @@ public class AliOssController extends BaseController {
* @return json
*/
@RequestMapping(value = "alioss_submit", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.System)
public String aliOssSubmit(String endpoint, String accessKeyId, String accessKeySecret, String bucketName, String keyPrefix) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("endpoint", endpoint);

View File

@ -1,4 +1,4 @@
package cn.keepbx.jpom.controller.system.ssl;
package cn.keepbx.jpom.controller.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Validator;
@ -8,22 +8,17 @@ import cn.hutool.extra.servlet.ServletUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.controller.multipart.MultipartFileBuilder;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.Role;
import cn.keepbx.jpom.common.interceptor.UrlPermission;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.model.data.CertModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import cn.keepbx.jpom.service.system.CertService;
import cn.keepbx.jpom.service.system.WhitelistDirectoryService;
import cn.keepbx.jpom.system.ConfigBean;
import com.alibaba.fastjson.JSONArray;
import cn.keepbx.jpom.system.AgentConfigBean;
import com.alibaba.fastjson.JSONObject;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
@ -39,22 +34,15 @@ import java.util.zip.ZipFile;
*
* @author Arno
*/
@Controller
@RestController
@RequestMapping(value = "/system/certificate")
public class CertificateController extends BaseController {
public class CertificateController extends BaseAgentController {
@Resource
private CertService certService;
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
@RequestMapping(value = "/list.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String certificate() {
JSONArray jsonArray = whitelistDirectoryService.getCertificateDirectory();
setAttribute("certificate", jsonArray);
return "system/certificate";
}
/**
* 保存证书
@ -62,8 +50,6 @@ public class CertificateController extends BaseController {
* @return json
*/
@RequestMapping(value = "/saveCertificate", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String saveCertificate() {
String data = getParameter("data");
JSONObject jsonObject = JSONObject.parseObject(data);
@ -110,7 +96,7 @@ public class CertificateController extends BaseController {
}
} catch (Exception e) {
DefaultSystemLog.ERROR().error("证书文件", e);
return JsonMessage.getString(400, e.getMessage());
return JsonMessage.getString(400, "解析证书文件失败:" + e.getMessage());
}
return JsonMessage.getString(200, "提交成功");
}
@ -148,7 +134,7 @@ public class CertificateController extends BaseController {
String certPath = null;
String pemPath = null, keyPath = null;
try {
String path = ConfigBean.getInstance().getTempPathName();
String path = AgentConfigBean.getInstance().getTempPathName();
MultipartFileBuilder cert = createMultipart().addFieldName("file").setSavePath(path);
certPath = cert.save();
ZipFile zipFile = new ZipFile(certPath);
@ -165,6 +151,13 @@ public class CertificateController extends BaseController {
FileUtil.writeFromStream(inputStream, filePathItem);
pemPath = filePathItem;
}
// cer 文件
if (pemPath == null && StrUtil.endWith(keyName, ".cer", true)) {
String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName);
InputStream inputStream = zipFile.getInputStream(zipEntry);
FileUtil.writeFromStream(inputStream, filePathItem);
pemPath = filePathItem;
}
//
if (keyPath == null && StrUtil.endWith(keyName, ".key", true)) {
String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName);
@ -231,8 +224,6 @@ public class CertificateController extends BaseController {
* 证书列表
*/
@RequestMapping(value = "/getCertList", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String getCertList() {
List<CertModel> array = certService.list();
return JsonMessage.getString(200, "", array);
@ -245,14 +236,11 @@ public class CertificateController extends BaseController {
* @return json
*/
@RequestMapping(value = "/delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.System)
public String delete(String id) {
if (StrUtil.isEmpty(id)) {
return JsonMessage.getString(400, "删除失败");
}
UserModel userModel = getUser();
if (!userModel.isSystemUser()) {
if (!isSystemUser()) {
return JsonMessage.getString(400, "你没有操作权限");
}
boolean b = certService.delete(id);
@ -267,8 +255,6 @@ public class CertificateController extends BaseController {
* 导出证书
*/
@RequestMapping(value = "/export", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String export(String id) {
CertModel item = certService.getItem(id);
if (null == item) {

View File

@ -1,18 +1,13 @@
package cn.keepbx.jpom.controller.system.nginx;
package cn.keepbx.jpom.controller.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.Role;
import cn.keepbx.jpom.common.interceptor.UrlPermission;
import cn.keepbx.jpom.model.data.CertModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.system.CertService;
import cn.keepbx.jpom.common.BaseAgentController;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import cn.keepbx.jpom.service.system.NginxService;
import cn.keepbx.jpom.service.system.WhitelistDirectoryService;
import cn.keepbx.jpom.util.CommandUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@ -21,10 +16,10 @@ import com.github.odiszapc.nginxparser.NgxConfig;
import com.github.odiszapc.nginxparser.NgxEntry;
import com.github.odiszapc.nginxparser.NgxParam;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
@ -34,64 +29,53 @@ import java.io.InputStream;
import java.util.List;
/**
* nginx 管理
* nginx 列表
*
* @author Arno
* @author jiangzeyin
* @date 2019/4/17
*/
@Controller
@RestController
@RequestMapping("/system/nginx")
public class NginxController extends BaseController {
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
@Resource
private CertService certService;
public class NginxController extends BaseAgentController {
@Resource
private NginxService nginxService;
@RequestMapping(value = "list.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String ngx() {
JSONArray ngxDirectory = whitelistDirectoryService.getNgxDirectory();
setAttribute("nginx", ngxDirectory);
List<CertModel> certList = certService.list();
setAttribute("cert", certList);
return "system/nginx";
}
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
/**
* 配置列表
*/
@RequestMapping(value = "list_data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String list() {
JSONArray array = nginxService.list();
return JsonMessage.getString(200, "", array);
}
@RequestMapping(value = "item.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String setting(String path, String name, String type) {
JSONArray ngxDirectory = whitelistDirectoryService.getNgxDirectory();
setAttribute("nginx", ngxDirectory);
List<CertModel> certList = certService.list();
setAttribute("cert", certList);
setAttribute("type", type);
name = pathSafe(name);
if (StrUtil.isNotEmpty(path) && whitelistDirectoryService.checkNgxDirectory(path)) {
File file = FileUtil.file(path, name);
/**
* 获取配置文件信息页面
*
* @param path 白名单路径
* @param name 名称
* @return 页面
*/
@RequestMapping(value = "item_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String itemData(String path, String name) {
String newName = pathSafe(name);
if (whitelistDirectoryService.checkNgxDirectory(path)) {
File file = FileUtil.file(path, newName);
JSONObject jsonObject = new JSONObject();
String string = FileUtil.readUtf8String(file);
jsonObject.put("context", string);
jsonObject.put("name", nginxService.paresName(path, file.getAbsolutePath()));
jsonObject.put("whitePath", path);
setAttribute("data", jsonObject);
return JsonMessage.getString(200, "", jsonObject);
// setAttribute("data", jsonObject);
}
return "system/nginxSetting";
return JsonMessage.getString(400, "错误");
}
/**
* 新增或修改配置
*
@ -100,7 +84,6 @@ public class NginxController extends BaseController {
*/
@RequestMapping(value = "updateNgx", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String updateNgx(String name, String whitePath, String context, String genre) {
if (StrUtil.isEmpty(name)) {
return JsonMessage.getString(400, "请填写文件名");
@ -186,7 +169,7 @@ public class NginxController extends BaseController {
* @return false 不正确
*/
private boolean checkRootRole(NgxBlock ngxBlock) {
UserModel userModel = getUser();
// UserModel userModel = getUser();
List<NgxEntry> locationAll = ngxBlock.findAll(NgxBlock.class, "location");
if (locationAll != null) {
for (NgxEntry ngxEntry1 : locationAll) {
@ -195,7 +178,7 @@ public class NginxController extends BaseController {
if (locationMain == null) {
locationMain = ngxBlock1.findParam("alias");
}
if (locationMain != null && !userModel.isSystemUser()) {
if (locationMain != null && !isSystemUser()) {
return false;
}
}
@ -210,7 +193,6 @@ public class NginxController extends BaseController {
*/
@RequestMapping(value = "delete", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.Manage)
public String delete(String path, String name) {
if (!whitelistDirectoryService.checkNgxDirectory(path)) {
return JsonMessage.getString(400, "非法操作");
@ -230,5 +212,4 @@ public class NginxController extends BaseController {
String msg = this.reloadNginx();
return JsonMessage.getString(200, "删除成功" + msg);
}
}

View File

@ -3,59 +3,36 @@ package cn.keepbx.jpom.controller.system;
import cn.hutool.core.text.StrSpliter;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.JsonMessage;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.Role;
import cn.keepbx.jpom.common.interceptor.UrlPermission;
import cn.keepbx.jpom.service.system.WhitelistDirectoryService;
import cn.keepbx.jpom.system.ExtConfigBean;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.keepbx.jpom.common.BaseJpomController;
import cn.keepbx.jpom.model.data.AgentWhitelist;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import cn.keepbx.jpom.system.AgentExtConfigBean;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 白名单目录
*
* @author jiangzeyin
* @date 2019/2/28
* @date 2019/4/16
*/
@Controller
@RestController
@RequestMapping(value = "/system")
public class WhitelistDirectoryController extends BaseController {
public class WhitelistDirectoryController extends BaseJpomController {
@Resource
private WhitelistDirectoryService whitelistDirectoryService;
/**
* 页面
*/
@RequestMapping(value = "whitelistDirectory", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
public String whitelistDirectory() {
JSONArray jsonArray = whitelistDirectoryService.getProjectDirectory();
setAttribute("project", whitelistDirectoryService.convertToLine(jsonArray));
//
jsonArray = whitelistDirectoryService.getCertificateDirectory();
setAttribute("certificate", whitelistDirectoryService.convertToLine(jsonArray));
jsonArray = whitelistDirectoryService.getNgxDirectory();
setAttribute("nginx", whitelistDirectoryService.convertToLine(jsonArray));
return "system/whitelistDirectory";
@RequestMapping(value = "whitelistDirectory_data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String whiteListDirectoryData() {
AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
return JsonMessage.getString(200, "", agentWhitelist);
}
/**
* 保存接口
*
* @param project 项目
* @param certificate 证书
* @return json
*/
@RequestMapping(value = "whitelistDirectory_submit", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@UrlPermission(Role.System)
public String whitelistDirectorySubmit(String project, String certificate, String nginx) {
//
List<String> certificateList = null;
@ -72,11 +49,10 @@ public class WhitelistDirectoryController extends BaseController {
return JsonMessage.getString(401, "nginx路径白名单不能为空");
}
}
JsonMessage jsonMessage = save(project, certificateList, nList);
return jsonMessage.toString();
return save(project, certificateList, nList).toString();
}
public JsonMessage save(String project, List<String> certificate, List<String> nginx) {
private JsonMessage save(String project, List<String> certificate, List<String> nginx) {
if (StrUtil.isEmpty(project)) {
return new JsonMessage(401, "项目路径白名单不能为空");
}
@ -87,10 +63,11 @@ public class WhitelistDirectoryController extends BaseController {
return save(list, certificate, nginx);
}
private JsonMessage save(List<String> projects, List<String> certificate, List<String> nginx) {
JSONArray projectArray;
List<String> projectArray;
{
projectArray = covertToArray(projects);
projectArray = AgentWhitelist.covertToArray(projects);
if (projectArray == null) {
return new JsonMessage(401, "项目路径白名单不能位于Jpom目录下");
}
@ -102,9 +79,9 @@ public class WhitelistDirectoryController extends BaseController {
return new JsonMessage(401, "白名单目录中不能存在包含关系:" + error);
}
}
JSONArray certificateArray = null;
List<String> certificateArray = null;
if (certificate != null && !certificate.isEmpty()) {
certificateArray = covertToArray(certificate);
certificateArray = AgentWhitelist.covertToArray(certificate);
if (certificateArray == null) {
return new JsonMessage(401, "证书路径白名单不能位于Jpom目录下");
}
@ -116,9 +93,9 @@ public class WhitelistDirectoryController extends BaseController {
return new JsonMessage(401, "证书目录中不能存在包含关系:" + error);
}
}
JSONArray nginxArray = null;
List<String> nginxArray = null;
if (nginx != null && !nginx.isEmpty()) {
nginxArray = covertToArray(nginx);
nginxArray = AgentWhitelist.covertToArray(nginx);
if (nginxArray == null) {
return new JsonMessage(401, "nginx路径白名单不能位于Jpom目录下");
}
@ -130,37 +107,17 @@ public class WhitelistDirectoryController extends BaseController {
return new JsonMessage(401, "nginx目录中不能存在包含关系" + error);
}
}
JSONObject jsonObject = whitelistDirectoryService.getWhitelist();
if (jsonObject == null) {
jsonObject = new JSONObject();
AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
if (agentWhitelist == null) {
agentWhitelist = new AgentWhitelist();
}
jsonObject.put("project", projectArray);
jsonObject.put("certificate", certificateArray);
jsonObject.put("nginx", nginxArray);
whitelistDirectoryService.saveWhitelistDirectory(jsonObject);
agentWhitelist.setProject(projectArray);
agentWhitelist.setCertificate(certificateArray);
agentWhitelist.setNginx(nginxArray);
whitelistDirectoryService.saveWhitelistDirectory(agentWhitelist);
return new JsonMessage(200, "保存成功");
}
private JSONArray covertToArray(List<String> list) {
JSONArray array = new JSONArray();
for (String s : list) {
String val = String.format("/%s/", s);
val = pathSafe(val);
if (StrUtil.SLASH.equals(val)) {
continue;
}
if (array.contains(val)) {
continue;
}
// 判断是否保护jpom 路径
if (val.startsWith(ExtConfigBean.getInstance().getPath())) {
return null;
}
array.add(val);
}
return array;
}
/**
* 检查白名单包含关系
*
@ -168,17 +125,17 @@ public class WhitelistDirectoryController extends BaseController {
* @param start 检查的坐标
* @return null 正常
*/
private String findStartsWith(JSONArray jsonArray, int start) {
if (!ExtConfigBean.getInstance().whitelistDirectoryCheckStartsWith) {
private String findStartsWith(List<String> jsonArray, int start) {
if (!AgentExtConfigBean.getInstance().whitelistDirectoryCheckStartsWith) {
return null;
}
String str = jsonArray.getString(start);
String str = jsonArray.get(start);
int len = jsonArray.size();
for (int i = 0; i < len; i++) {
if (i == start) {
continue;
}
String findStr = jsonArray.getString(i);
String findStr = jsonArray.get(i);
if (findStr.startsWith(str)) {
return str;
}

View File

@ -1,9 +1,11 @@
package cn.keepbx.jpom.model.data;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.jiangzeyin.common.DefaultSystemLog;
@ -13,10 +15,9 @@ import cn.keepbx.jpom.service.system.CertService;
import cn.keepbx.jpom.system.JpomRuntimeException;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
@ -26,7 +27,8 @@ import java.util.Date;
* @author Arno
*/
public class CertModel extends BaseModel {
private String name;
private static final String KEY = "Jpom 管理系统";
/**
* 证书文件
*/
@ -52,13 +54,6 @@ public class CertModel extends BaseModel {
*/
private String whitePath;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWhitePath() {
return whitePath;
@ -143,22 +138,27 @@ public class CertModel extends BaseModel {
if (!FileUtil.exist(file)) {
return null;
}
PrivateKey privateKey = BCUtil.readPrivateKey(ResourceUtil.getStream(key));
PublicKey publicKey = BCUtil.readPublicKey(ResourceUtil.getStream(file));
RSA rsa = new RSA(privateKey, publicKey);
String str = UserModel.SYSTEM_OCCUPY_NAME;
String encryptStr = rsa.encryptBase64(str, KeyType.PublicKey);
String decryptStr = rsa.decryptStr(encryptStr, KeyType.PrivateKey);
if (!str.equals(decryptStr)) {
throw new JpomRuntimeException("证书和私钥证书不匹配");
InputStream inputStream = null;
try {
inputStream = ResourceUtil.getStream(key);
PrivateKey privateKey = BCUtil.readPrivateKey(inputStream);
IoUtil.close(inputStream);
inputStream = ResourceUtil.getStream(file);
PublicKey publicKey = BCUtil.readPublicKey(inputStream);
IoUtil.close(inputStream);
RSA rsa = new RSA(privateKey, publicKey);
String encryptStr = rsa.encryptBase64(KEY, KeyType.PublicKey);
String decryptStr = rsa.decryptStr(encryptStr, KeyType.PrivateKey);
if (!KEY.equals(decryptStr)) {
throw new JpomRuntimeException("证书和私钥证书不匹配");
}
} finally {
IoUtil.close(inputStream);
}
try {
BufferedInputStream inStream = FileUtil.getInputStream(file);
// 创建X509工厂类
CertificateFactory cf = CertificateFactory.getInstance("X.509");
inputStream = ResourceUtil.getStream(file);
// 创建证书对象
X509Certificate oCert = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
X509Certificate oCert = (X509Certificate) KeyUtil.readX509Certificate(inputStream);
//到期时间
Date expirationTime = oCert.getNotAfter();
//生效日期
@ -174,6 +174,8 @@ public class CertModel extends BaseModel {
return jsonObject;
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
} finally {
IoUtil.close(inputStream);
}
return null;
}

View File

@ -1,12 +1,14 @@
package cn.keepbx.jpom.model.data;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.BaseModel;
import cn.keepbx.jpom.model.RunMode;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
@ -15,7 +17,6 @@ import java.util.List;
* @author jiangzeyin
*/
public class ProjectInfoModel extends BaseModel {
private String name;
/**
* 分组
*/
@ -50,6 +51,18 @@ public class ProjectInfoModel extends BaseModel {
private String modifyUser;
private RunMode runMode;
/**
* 节点分发项目不允许在项目管理中编辑
*/
private boolean outGivingProject;
public boolean isOutGivingProject() {
return outGivingProject;
}
public void setOutGivingProject(boolean outGivingProject) {
this.outGivingProject = outGivingProject;
}
public RunMode getRunMode() {
if (runMode == null) {
@ -64,7 +77,7 @@ public class ProjectInfoModel extends BaseModel {
public String getModifyUser() {
if (StrUtil.isEmpty(modifyUser)) {
return UserModel.SYSTEM_OCCUPY_NAME;
return StrUtil.DASHED;
}
return modifyUser;
}
@ -73,15 +86,6 @@ public class ProjectInfoModel extends BaseModel {
this.modifyUser = modifyUser;
}
public void logModifyUser(UserModel userModel) {
// 隐藏系统管理员登录名
if (userModel.isSystemUser()) {
this.setModifyUser(UserModel.SYSTEM_OCCUPY_NAME);
} else {
this.setModifyUser(userModel.getId());
}
}
/**
* 项目是否正在运行
*
@ -150,14 +154,6 @@ public class ProjectInfoModel extends BaseModel {
this.jvm = jvm;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroup() {
if (StrUtil.isEmpty(group)) {
return "默认";
@ -197,12 +193,20 @@ public class ProjectInfoModel extends BaseModel {
*/
public static List<File> listJars(ProjectInfoModel projectInfoModel) {
File fileLib = new File(projectInfoModel.getLib());
return FileUtil.loopFiles(fileLib, pathname -> {
if (!pathname.isFile()) {
return false;
File[] files = fileLib.listFiles();
List<File> files1 = new ArrayList<>();
if (files != null) {
for (File file : files) {
if (!file.isFile()) {
continue;
}
if (!StrUtil.endWith(file.getName(), ".jar", true)) {
continue;
}
files1.add(file);
}
return StrUtil.endWith(pathname.getName(), ".jar", true);
});
}
return files1;
}
/**
@ -231,7 +235,7 @@ public class ProjectInfoModel extends BaseModel {
File file = files.get(i);
classPath.append(file.getAbsolutePath());
if (i != len - 1) {
classPath.append(AbstractProjectCommander.OS_INFO.isWindows() ? ";" : ":");
classPath.append(BaseJpomApplication.OS_INFO.isWindows() ? ";" : ":");
}
}
return classPath.toString();
@ -290,18 +294,4 @@ public class ProjectInfoModel extends BaseModel {
public void setArgs(String args) {
this.args = args;
}
/**
* 运行方式
*/
public enum RunMode {
/**
* java -classpath
*/
ClassPath,
/**
* java -jar
*/
Jar,
}
}

View File

@ -1,5 +1,6 @@
package cn.keepbx.jpom.model.system;
import cn.hutool.core.util.StrUtil;
import cn.keepbx.jpom.model.BaseJsonModel;
/**
@ -10,8 +11,8 @@ import cn.keepbx.jpom.model.BaseJsonModel;
*/
public class NetstatModel extends BaseJsonModel {
private String protocol;
private String receive = "-";
private String send = "-";
private String receive = StrUtil.DASHED;
private String send = StrUtil.DASHED;
private String local;
private String foreign;
private String status;

View File

@ -104,7 +104,6 @@ public class ProcessModel extends BaseJsonModel {
DefaultSystemLog.ERROR().error("解析进程失败", e);
}
}
}
public String getCommand() {

View File

@ -0,0 +1,110 @@
package cn.keepbx.jpom.service;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.common.BaseDataService;
import cn.keepbx.jpom.model.data.AgentWhitelist;
import cn.keepbx.jpom.system.AgentConfigBean;
import cn.keepbx.jpom.util.JsonFileUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 白名单服务
*
* @author jiangzeyin
* @date 2019/2/28
*/
@Service
public class WhitelistDirectoryService extends BaseDataService {
public AgentWhitelist getWhitelist() {
try {
JSONObject jsonObject = getJSONObject(AgentConfigBean.WHITELIST_DIRECTORY);
if (jsonObject == null) {
return null;
}
return jsonObject.toJavaObject(AgentWhitelist.class);
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
}
return null;
}
/**
* 单项添加白名单
*
* @param item 白名单
*/
public void addProjectWhiteList(String item) {
AgentWhitelist agentWhitelist = getWhitelist();
if (agentWhitelist == null) {
agentWhitelist = new AgentWhitelist();
}
List<String> project = agentWhitelist.getProject();
if (project == null) {
project = new ArrayList<>();
}
project.add(item);
saveWhitelistDirectory(agentWhitelist);
}
public boolean isInstalled() {
AgentWhitelist agentWhitelist = getWhitelist();
if (agentWhitelist == null) {
return false;
}
List<String> project = agentWhitelist.getProject();
return project != null && !project.isEmpty();
}
private List<String> getNgxDirectory() {
AgentWhitelist agentWhitelist = getWhitelist();
if (agentWhitelist == null) {
return null;
}
return agentWhitelist.getNginx();
}
public boolean checkProjectDirectory(String path) {
AgentWhitelist agentWhitelist = getWhitelist();
if (agentWhitelist == null) {
return false;
}
List<String> list = agentWhitelist.getProject();
return AgentWhitelist.checkPath(list, path);
}
public boolean checkNgxDirectory(String path) {
List<String> list = getNgxDirectory();
return AgentWhitelist.checkPath(list, path);
}
private List<String> getCertificateDirectory() {
AgentWhitelist agentWhitelist = getWhitelist();
if (agentWhitelist == null) {
return null;
}
return agentWhitelist.getCertificate();
}
public boolean checkCertificateDirectory(String path) {
List<String> list = getCertificateDirectory();
if (list == null) {
return false;
}
return AgentWhitelist.checkPath(list, path);
}
/**
* 保存白名单
*
* @param jsonObject 实体
*/
public void saveWhitelistDirectory(AgentWhitelist jsonObject) {
String path = getDataFilePath(AgentConfigBean.WHITELIST_DIRECTORY);
JsonFileUtil.saveJson(path, jsonObject.toJson());
}
}

View File

@ -2,6 +2,7 @@ package cn.keepbx.jpom.service.manage;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.socket.CommandOp;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -14,32 +15,12 @@ import javax.annotation.Resource;
*/
@Service
public class ConsoleService {
public static final String RUNING_TAG = "running";
public static final String STOP_TAG = "stopped";
@Resource
private ProjectInfoService projectInfoService;
public enum CommandOp {
/**
* 启动
*/
start,
stop,
restart,
status,
/**
* 运行日志
*/
showlog,
/**
* 查看内存信息
*/
top
}
/**
* 执行shell命令
*

View File

@ -5,7 +5,7 @@ import cn.hutool.core.io.FileUtil;
import cn.keepbx.jpom.common.BaseOperService;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.data.ProjectRecoverModel;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.system.AgentConfigBean;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
@ -32,7 +32,7 @@ public class ProjectInfoService extends BaseOperService<ProjectInfoModel> {
*/
@Override
public List<ProjectInfoModel> list() {
JSONObject jsonObject = getJSONObject(ConfigBean.PROJECT);
JSONObject jsonObject = getJSONObject(AgentConfigBean.PROJECT);
JSONArray jsonArray = formatToArray(jsonObject);
return jsonArray.toJavaList(ProjectInfoModel.class);
}
@ -56,7 +56,7 @@ public class ProjectInfoService extends BaseOperService<ProjectInfoModel> {
@Override
public void addItem(ProjectInfoModel projectInfo) {
// 保存
saveJson(ConfigBean.PROJECT, projectInfo.toJson());
saveJson(AgentConfigBean.PROJECT, projectInfo.toJson());
}
/**
@ -65,7 +65,7 @@ public class ProjectInfoService extends BaseOperService<ProjectInfoModel> {
* @param projectInfo 项目
*/
public void deleteProject(ProjectInfoModel projectInfo, String userId) throws Exception {
deleteJson(ConfigBean.PROJECT, projectInfo.getId());
deleteJson(AgentConfigBean.PROJECT, projectInfo.getId());
// 添加回收记录
ProjectRecoverModel projectRecoverModel = new ProjectRecoverModel(projectInfo);
projectRecoverModel.setDelUser(userId);
@ -80,7 +80,7 @@ public class ProjectInfoService extends BaseOperService<ProjectInfoModel> {
@Override
public boolean updateItem(ProjectInfoModel projectInfo) throws Exception {
projectInfo.setModifyTime(DateUtil.now());
updateJson(ConfigBean.PROJECT, projectInfo.toJson());
updateJson(AgentConfigBean.PROJECT, projectInfo.toJson());
return true;
}
@ -93,7 +93,7 @@ public class ProjectInfoService extends BaseOperService<ProjectInfoModel> {
*/
@Override
public ProjectInfoModel getItem(String id) {
return getJsonObjectById(ConfigBean.PROJECT, id, ProjectInfoModel.class);
return getJsonObjectById(AgentConfigBean.PROJECT, id, ProjectInfoModel.class);
}
public String getLogSize(String id) {

View File

@ -3,7 +3,7 @@ package cn.keepbx.jpom.service.manage;
import cn.hutool.core.date.DateUtil;
import cn.keepbx.jpom.common.BaseOperService;
import cn.keepbx.jpom.model.data.ProjectRecoverModel;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.system.AgentConfigBean;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
@ -26,7 +26,7 @@ public class ProjectRecoverService extends BaseOperService<ProjectRecoverModel>
*/
@Override
public List<ProjectRecoverModel> list() {
JSONObject jsonObject = getJSONObject(ConfigBean.PROJECT_RECOVER);
JSONObject jsonObject = getJSONObject(AgentConfigBean.PROJECT_RECOVER);
JSONArray jsonArray = formatToArray(jsonObject);
return jsonArray.toJavaList(ProjectRecoverModel.class);
}
@ -41,7 +41,7 @@ public class ProjectRecoverService extends BaseOperService<ProjectRecoverModel>
public void addItem(ProjectRecoverModel projectInfo) {
projectInfo.setDelTime(DateUtil.now());
// 保存
saveJson(ConfigBean.PROJECT_RECOVER, projectInfo.toJson());
saveJson(AgentConfigBean.PROJECT_RECOVER, projectInfo.toJson());
}
/**
@ -52,7 +52,7 @@ public class ProjectRecoverService extends BaseOperService<ProjectRecoverModel>
*/
@Override
public ProjectRecoverModel getItem(String id) throws IOException {
return getJsonObjectById(ConfigBean.PROJECT_RECOVER, id, ProjectRecoverModel.class);
return getJsonObjectById(AgentConfigBean.PROJECT_RECOVER, id, ProjectRecoverModel.class);
}
@Override

View File

@ -3,7 +3,7 @@ package cn.keepbx.jpom.service.oss;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.keepbx.jpom.common.BaseDataService;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.system.AgentConfigBean;
import cn.keepbx.jpom.util.JsonFileUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit;
public class OssManagerService extends BaseDataService {
public File download(String key) {
File file = ConfigBean.getInstance().getTempPath();
File file = AgentConfigBean.getInstance().getTempPath();
//getTempPath();
file = FileUtil.file(file, key);
OSSClient ossClient = getOSSClient(getConfig());
@ -98,7 +98,7 @@ public class OssManagerService extends BaseDataService {
}
public JSONObject getConfig() {
return getJSONObject(ConfigBean.ALI_OSS);
return getJSONObject(AgentConfigBean.ALI_OSS);
}
private String getBucketName() {
@ -112,7 +112,7 @@ public class OssManagerService extends BaseDataService {
}
public void save(JSONObject jsonObject) {
String path = getDataFilePath(ConfigBean.ALI_OSS);
String path = getDataFilePath(AgentConfigBean.ALI_OSS);
JsonFileUtil.saveJson(path, jsonObject);
}
}

View File

@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.common.BaseOperService;
import cn.keepbx.jpom.model.data.CertModel;
import cn.keepbx.jpom.system.ConfigBean;
import cn.keepbx.jpom.system.AgentConfigBean;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
@ -27,7 +27,7 @@ public class CertService extends BaseOperService<CertModel> {
*/
@Override
public void addItem(CertModel certModel) {
saveJson(ConfigBean.CERT, certModel.toJson());
saveJson(AgentConfigBean.CERT, certModel.toJson());
}
/**
@ -37,7 +37,7 @@ public class CertService extends BaseOperService<CertModel> {
*/
@Override
public List<CertModel> list() {
JSONObject jsonObject = getJSONObject(ConfigBean.CERT);
JSONObject jsonObject = getJSONObject(AgentConfigBean.CERT);
if (jsonObject == null) {
return null;
}
@ -47,7 +47,7 @@ public class CertService extends BaseOperService<CertModel> {
@Override
public CertModel getItem(String id) {
return getJsonObjectById(ConfigBean.CERT, id, CertModel.class);
return getJsonObjectById(AgentConfigBean.CERT, id, CertModel.class);
}
@ -63,7 +63,7 @@ public class CertService extends BaseOperService<CertModel> {
return true;
}
String keyPath = certModel.getCert();
deleteJson(ConfigBean.CERT, id);
deleteJson(AgentConfigBean.CERT, id);
if (StrUtil.isNotEmpty(keyPath)) {
// 删除证书文件
File parentFile = FileUtil.file(keyPath).getParentFile();
@ -84,7 +84,7 @@ public class CertService extends BaseOperService<CertModel> {
@Override
public boolean updateItem(CertModel certModel) {
try {
updateJson(ConfigBean.CERT, certModel.toJson());
updateJson(AgentConfigBean.CERT, certModel.toJson());
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
return false;

View File

@ -6,6 +6,8 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.common.BaseOperService;
import cn.keepbx.jpom.model.data.AgentWhitelist;
import cn.keepbx.jpom.service.WhitelistDirectoryService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.odiszapc.nginxparser.NgxBlock;
@ -31,7 +33,11 @@ public class NginxService extends BaseOperService {
@Override
public JSONArray list() {
JSONArray ngxDirectory = whitelistDirectoryService.getNgxDirectory();
AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist();
if (agentWhitelist == null) {
return null;
}
List<String> ngxDirectory = agentWhitelist.getNginx();
if (ngxDirectory == null) {
return null;
}

View File

@ -5,12 +5,11 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* socket 配置
*
* @author jiangzeyin
* @date 2019/4/19
*/
@Configuration
public class WebSocketConfig {
public class AgentWebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();

View File

@ -2,15 +2,16 @@ package cn.keepbx.jpom.socket;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.JsonMessage;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.model.data.UserModel;
import cn.keepbx.jpom.service.manage.ConsoleService;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.service.user.UserService;
import cn.keepbx.jpom.system.TopManager;
import cn.keepbx.jpom.util.SocketSessionUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
@ -19,61 +20,37 @@ import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* socket 消息控制器
* 插件端socket
*
* @author jiangzeyin
* @date 2017/9/8
* @date 2019/4/16
*/
@ServerEndpoint(value = "/console/{userInfo}/{projectId}")
@ServerEndpoint(value = "/console/{projectId}/{optUser}")
@Component
public class LogWebSocketHandle {
public class AgentWebSocketHandle {
public static final String SYSTEM_ID = "system";
private ConsoleService consoleService;
private static volatile AtomicInteger onlineCount = new AtomicInteger();
private static final ConcurrentHashMap<String, UserModel> USER = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, String> USER = new ConcurrentHashMap<>();
private static ProjectInfoService projectInfoService;
/**
* 新的WebSocket请求开启
*
* @param userInfo 用户授权信息
* @param projectId 项目id
* @param session 回话
*/
@OnOpen
public void onOpen(@PathParam("userInfo") String userInfo, @PathParam("projectId") String projectId, Session session) {
if (consoleService == null) {
consoleService = SpringUtil.getBean(ConsoleService.class);
}
// 通过用户名和密码的Md5值判断是否是登录的
public void onOpen(@PathParam("projectId") String projectId, @PathParam("optUser") String urlOptUser, Session session) {
try {
ProjectInfoService projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
UserService userService = SpringUtil.getBean(UserService.class);
UserModel userModel = userService.checkUser(userInfo);
if (userModel == null) {
SocketSessionUtil.send(session, "用户名或密码错误!");
session.close();
return;
}
// 判断项目
if (!SYSTEM_ID.equals(projectId)) {
if (!CommonSocketConfig.SYSTEM_ID.equals(projectId)) {
if (projectInfoService == null) {
projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
}
ProjectInfoModel projectInfoModel = projectInfoService.getItem(projectId);
if (projectInfoModel == null) {
SocketSessionUtil.send(session, "获取项目信息错误");
session.close();
return;
}
if (!userModel.isProject(projectInfoModel.getId())) {
SocketSessionUtil.send(session, "没有项目权限");
session.close();
return;
}
}
SocketSessionUtil.send(session, StrUtil.format("欢迎加入:{} 回话id:{} 当前会话总数:{}", userModel.getName(), session.getId(), onlineCount.incrementAndGet()));
USER.put(session.getId(), userModel);
String optUser = URLUtil.decode(urlOptUser);
USER.put(session.getId(), optUser);
} catch (Exception e) {
DefaultSystemLog.ERROR().error("socket 错误", e);
try {
@ -85,26 +62,42 @@ public class LogWebSocketHandle {
}
}
private String getOptUserName(Session session) {
String name = USER.get(session.getId());
return StrUtil.emptyToDefault(name, StrUtil.DASHED);
}
private boolean silentMsg(CommandOp commandOp, Session session) {
if (commandOp == CommandOp.heart) {
return true;
}
if (commandOp == CommandOp.top) {
TopManager.addMonitor(session);
return true;
}
return false;
}
@OnMessage
public void onMessage(String message, Session session) throws Exception {
JSONObject json = JSONObject.parseObject(message);
String op = json.getString("op");
if ("heart".equals(op)) {
return;
}
UserModel userModel = USER.get(session.getId());
if (userModel == null) {
SocketSessionUtil.send(session, "回话信息失效,刷新网页再试");
CommandOp commandOp = CommandOp.valueOf(op);
if (silentMsg(commandOp, session)) {
return;
}
String projectId = json.getString("projectId");
ProjectInfoService projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
ProjectInfoModel projectInfoModel = projectInfoService.getItem(projectId);
ConsoleService.CommandOp commandOp = ConsoleService.CommandOp.valueOf(op);
if (projectInfoModel == null && commandOp != ConsoleService.CommandOp.top) {
if (projectInfoModel == null) {
SocketSessionUtil.send(session, "没有对应项目");
return;
}
runMsg(commandOp, session, projectInfoModel, json);
}
private void runMsg(CommandOp commandOp, Session session, ProjectInfoModel projectInfoModel, JSONObject reqJson) throws Exception {
ConsoleService consoleService = SpringUtil.getBean(ConsoleService.class);
JSONObject resultData = null;
String strResult;
boolean logUser = false;
@ -115,7 +108,7 @@ public class LogWebSocketHandle {
case restart:
logUser = true;
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.RUNING_TAG)) {
if (strResult.contains(AbstractProjectCommander.RUNING_TAG)) {
resultData = JsonMessage.toJson(200, "操作成功:" + strResult);
} else {
resultData = JsonMessage.toJson(400, strResult);
@ -125,7 +118,7 @@ public class LogWebSocketHandle {
logUser = true;
// 停止项目
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.STOP_TAG)) {
if (strResult.contains(AbstractProjectCommander.STOP_TAG)) {
resultData = JsonMessage.toJson(200, "操作成功");
} else {
resultData = JsonMessage.toJson(500, strResult);
@ -134,7 +127,7 @@ public class LogWebSocketHandle {
case status:
// 获取项目状态
strResult = consoleService.execCommand(commandOp, projectInfoModel);
if (strResult.contains(ConsoleService.RUNING_TAG)) {
if (strResult.contains(AbstractProjectCommander.RUNING_TAG)) {
resultData = JsonMessage.toJson(200, "运行中", strResult);
} else {
resultData = JsonMessage.toJson(404, "未运行", strResult);
@ -146,15 +139,13 @@ public class LogWebSocketHandle {
try {
FileTailWatcher.addWatcher(log, session);
} catch (IOException io) {
DefaultSystemLog.ERROR().error(io.getMessage(), io);
SocketSessionUtil.send(session, io.getMessage());
}
break;
}
case top:
TopManager.addMonitor(session);
break;
default:
resultData = JsonMessage.toJson(404, "不支持的方式:" + op);
resultData = JsonMessage.toJson(404, "不支持的方式:" + commandOp.name());
break;
}
} catch (Exception e) {
@ -165,19 +156,28 @@ public class LogWebSocketHandle {
} finally {
if (logUser) {
// 记录操作人
projectInfoModel = projectInfoService.getItem(projectId);
projectInfoModel.logModifyUser(userModel);
projectInfoModel = projectInfoService.getItem(projectInfoModel.getId());
String name = getOptUserName(session);
projectInfoModel.setModifyUser(name);
projectInfoService.updateItem(projectInfoModel);
}
}
//
if (resultData != null) {
resultData.put("op", op);
DefaultSystemLog.LOG().info(resultData.toString());
SocketSessionUtil.send(session, resultData.toString());
// resultData.put("op", commandOp.name());
reqJson.putAll(resultData);
DefaultSystemLog.LOG().info(reqJson.toString());
SocketSessionUtil.send(session, reqJson.toString());
}
}
@OnClose
public void onClose(Session session) {
destroy(session);
// top
TopManager.removeMonitor(session);
}
private void destroy(Session session) {
// 清理日志监听
try {
@ -185,26 +185,9 @@ public class LogWebSocketHandle {
} catch (Exception e) {
DefaultSystemLog.ERROR().error("关闭异常", e);
}
onlineCount.getAndDecrement();
}
/**
* WebSocket请求关闭
*/
@OnClose
public void onClose(Session session) {
try {
destroy(session);
} catch (Exception e) {
DefaultSystemLog.ERROR().error("关闭异常", e);
}
// top
TopManager.removeMonitor(session);
USER.remove(session.getId());
DefaultSystemLog.LOG().info(session.getId() + " socket 关闭");
}
@OnError
public void onError(Session session, Throwable thr) {
// java.io.IOException: Broken pipe
@ -212,7 +195,6 @@ public class LogWebSocketHandle {
SocketSessionUtil.send(session, "服务端发生异常" + ExceptionUtil.stacktraceToString(thr));
} catch (IOException ignored) {
}
USER.remove(session.getId());
DefaultSystemLog.ERROR().error(session.getId() + "socket 异常", thr);
}
}
}

View File

@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.util.CharsetDetector;
import cn.keepbx.jpom.util.LimitQueue;
import cn.keepbx.jpom.util.SocketSessionUtil;
import javax.websocket.Session;
import java.io.File;
@ -34,7 +35,7 @@ public class FileTailWatcher implements Runnable {
private LimitQueue limitQueue = new LimitQueue(10);
private final RandomAccessFile randomFile;
/**
* 所有
* 所有
*/
private Set<Session> socketSessions = new HashSet<>();
private final String log;
@ -48,7 +49,7 @@ public class FileTailWatcher implements Runnable {
* 添加文件监听
*
* @param log 日志文件路径
* @param session
* @param session
* @throws IOException 异常
*/
public static void addWatcher(String log, Session session) throws IOException {
@ -75,7 +76,7 @@ public class FileTailWatcher implements Runnable {
/**
* 有客户端离线
*
* @param session
* @param session
*/
public static void offline(Session session) {
Collection<FileTailWatcher> collection = CONCURRENT_HASH_MAP.values();
@ -95,9 +96,9 @@ public class FileTailWatcher implements Runnable {
}
/**
* 添加监听
* 添加监听
*
* @param session
* @param session
*/
private void add(Session session) {
if (this.socketSessions.add(session)) {

View File

@ -0,0 +1,102 @@
package cn.keepbx.jpom.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.model.system.AgentAutoUser;
import cn.keepbx.jpom.util.JsonFileUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* agent 端授权账号信息
*
* @author jiangzeyin
* @date 2019/4/17
*/
@Configuration
public class AgentAuthorize {
private static AgentAuthorize agentAuthorize;
/**
* 账号
*/
@Value("${jpom.authorize.agentName}")
private String agentName;
/**
* 密码
*/
@Value("${jpom.authorize.agentPwd:}")
private String agentPwd;
/**
* 授权加密字符串
*/
private String authorize;
/**
* 单例
*
* @return this
*/
public static AgentAuthorize getInstance() {
if (agentAuthorize == null) {
agentAuthorize = SpringUtil.getBean(AgentAuthorize.class);
// 登录名不能为空
if (StrUtil.isEmpty(agentAuthorize.agentName)) {
throw new JpomRuntimeException("agent 端登录名不能为空");
}
agentAuthorize.checkPwd();
// 生成密码授权字符串
agentAuthorize.authorize = SecureUtil.sha1(agentAuthorize.agentName + "@" + agentAuthorize.agentPwd);
}
return agentAuthorize;
}
public boolean checkAuthorize(String authorize) {
return StrUtil.equals(authorize, this.authorize);
}
/**
* 检查是否配置密码
*/
private void checkPwd() {
String path = ConfigBean.getInstance().getAgentAutoAuthorizeFile(ConfigBean.getInstance().getDataPath());
if (StrUtil.isNotEmpty(agentPwd)) {
// 有指定密码 清除旧密码信息
FileUtil.del(path);
return;
}
if (FileUtil.exist(path)) {
// 读取旧密码
try {
String json = FileUtil.readString(path, CharsetUtil.CHARSET_UTF_8);
AgentAutoUser autoUser = JSONObject.parseObject(json, AgentAutoUser.class);
String oldAgentPwd = autoUser.getAgentPwd();
if (!StrUtil.equals(autoUser.getAgentName(), this.agentName)) {
throw new JpomRuntimeException("已经存在的登录名和配置的登录名不一致");
}
if (StrUtil.isNotEmpty(oldAgentPwd)) {
this.agentPwd = oldAgentPwd;
DefaultSystemLog.LOG().info("已有授权账号:{} 密码:{},授权信息保存位置:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
return;
}
} catch (JpomRuntimeException e) {
throw e;
} catch (Exception ignored) {
}
}
this.agentPwd = RandomUtil.randomString(10);
AgentAutoUser autoUser = new AgentAutoUser();
autoUser.setAgentName(this.agentName);
autoUser.setAgentPwd(this.agentPwd);
// 写入文件中
JsonFileUtil.saveJson(path, autoUser.toJson());
DefaultSystemLog.LOG().info("已经自动生成授权账号:{} 密码:{},授权信息保存位置:{}", this.agentName, this.agentPwd, FileUtil.getAbsolutePath(path));
}
}

View File

@ -3,92 +3,58 @@ package cn.keepbx.jpom.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.common.BaseController;
import cn.keepbx.jpom.common.JpomApplicationEvent;
import org.springframework.beans.factory.annotation.Value;
import cn.jiangzeyin.controller.base.AbstractController;
import cn.keepbx.jpom.common.BaseAgentController;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
* 配置信息静态变量类
* 插件端配置
*
* @author jiangzeyin
* @date 2019/1/16
* @date 2019/4/16
*/
@Configuration
public class ConfigBean {
private static final String DATA = "data";
private static ConfigBean configBean;
/**
* 用户数据文件
*/
public static final String USER = "user.json";
/**
* 项目数据文件
*/
public static final String PROJECT = "project.json";
public class AgentConfigBean {
/**
* 白名单文件
*/
public static final String WHITELIST_DIRECTORY = "whitelistDirectory.json";
/**
* 阿里oss 文件
* 项目数据文件
*/
public static final String ALI_OSS = "aliOss.json";
/**
* 证书文件
*/
public static final String CERT = "cert.json";
public static final String PROJECT = "project.json";
/**
* 项目回收文件
*/
public static final String PROJECT_RECOVER = "project_recover.json";
/**
* Jpom 程序运行的 application 标识
* 阿里oss 文件
*/
@Value("${jpom.applicationTag:}")
public String applicationTag;
public static final String ALI_OSS = "aliOss.json";
/**
* 证书文件
*/
public static final String CERT = "cert.json";
private static AgentConfigBean agentConfigBean;
/**
* 单利模式
*
* @return config
*/
public static ConfigBean getInstance() {
if (configBean == null) {
configBean = SpringUtil.getBean(ConfigBean.class);
public static AgentConfigBean getInstance() {
if (agentConfigBean == null) {
agentConfigBean = SpringUtil.getBean(AgentConfigBean.class);
}
return configBean;
}
/**
* 获取项目运行数据存储文件夹路径
*
* @return 文件夹路径
*/
public String getDataPath() {
String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + "/" + DATA);
FileUtil.mkdir(dataPath);
return dataPath;
}
/**
* 获取pid文件
*
* @return file
*/
public File getPidFile() {
return new File(getDataPath(), "pid." + JpomApplicationEvent.getPid());
}
/**
* 获取当前Jpom 运行信息文件
*
* @return file
*/
public File getJpomInfo() {
return new File(getDataPath(), "jpom.info");
return agentConfigBean;
}
/**
@ -107,8 +73,9 @@ public class ConfigBean {
* @return file
*/
public File getTempPath() {
File file = new File(getDataPath());
String userName = BaseController.getUserName();
File file = new File(ConfigBean.getInstance().getDataPath());
HttpServletRequest request = AbstractController.getRequestAttributes().getRequest();
String userName = BaseAgentController.getUserName(request);
if (StrUtil.isEmpty(userName)) {
throw new JpomRuntimeException("没有登录");
}

View File

@ -0,0 +1,60 @@
package cn.keepbx.jpom.system;
import cn.jiangzeyin.common.spring.SpringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* agent 端外部配置
*
* @author jiangzeyin
* @date 2019/4/16
*/
@Configuration
public class AgentExtConfigBean {
/**
* 白名单路径是否判断包含关系
*/
@Value("${whitelistDirectory.checkStartsWith:true}")
public boolean whitelistDirectoryCheckStartsWith;
/**
* 自动备份控制台日志防止日志文件过大目前暂只支持linux 不停服备份 如果配置none 则不自动备份 默认10分钟扫描一次
*/
@Value("${log.autoBackConsoleCron:0 0/10 * * * ?}")
public String autoBackConsoleCron;
/**
* 当文件多大时自动备份
*
* @see ch.qos.logback.core.util.FileSize
*/
@Value("${log.autoBackSize:50MB}")
public String autoBackSize;
/**
* 控制台日志保存时长单位天
*/
@Value("${log.saveDays:7}")
private int logSaveDays;
/**
* 配置错误或者没有默认是7天
*
* @return int
*/
public int getLogSaveDays() {
if (logSaveDays <= 0) {
return 7;
}
return logSaveDays;
}
/**
* 单例
*
* @return this
*/
public static AgentExtConfigBean getInstance() {
return SpringUtil.getBean(AgentExtConfigBean.class);
}
}

View File

@ -6,7 +6,7 @@ import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.pool.ThreadPoolService;
import cn.keepbx.jpom.common.commander.AbstractSystemCommander;
import cn.keepbx.jpom.model.system.ProcessModel;
import cn.keepbx.jpom.socket.SocketSessionUtil;
import cn.keepbx.jpom.util.SocketSessionUtil;
import com.alibaba.fastjson.JSONObject;
import javax.websocket.Session;
@ -37,7 +37,7 @@ public class TopManager {
/**
* 添加top 命令监听
*
* @param session
* @param session
*/
public static void addMonitor(Session session) {
SESSIONS.add(session);
@ -47,7 +47,7 @@ public class TopManager {
/**
* 移除top 命令监控
*
* @param session
* @param session
*/
public static void removeMonitor(Session session) {
SESSIONS.remove(session);
@ -62,7 +62,7 @@ public class TopManager {
return;
}
CronUtil.remove(CRON_ID);
CronUtil.schedule(CRON_ID, "0/10 * * * * ?", () -> {
CronUtil.schedule(CRON_ID, "0/5 * * * * ?", () -> {
//发送监控信息
try {
JSONObject topInfo = AbstractSystemCommander.getInstance().getAllMonitor();
@ -105,13 +105,13 @@ public class TopManager {
*/
private static void send(String content) {
synchronized (TopManager.class) {
String htmlContent = content.replaceAll("\n", "<br/>");
htmlContent = htmlContent.replaceAll(" ", "&nbsp;&nbsp;");
Iterator<Session> iterator = SESSIONS.iterator();
while (iterator.hasNext()) {
Session session = iterator.next();
content = content.replaceAll("\n", "<br/>");
content = content.replaceAll(" ", "&nbsp;&nbsp;");
try {
SocketSessionUtil.send(session, content);
SocketSessionUtil.send(session, htmlContent);
} catch (IOException e) {
DefaultSystemLog.ERROR().error("消息失败", e);
try {

View File

@ -14,7 +14,7 @@ import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.model.data.ProjectInfoModel;
import cn.keepbx.jpom.service.manage.ProjectInfoService;
import cn.keepbx.jpom.system.ExtConfigBean;
import cn.keepbx.jpom.system.AgentExtConfigBean;
import java.io.File;
import java.util.List;
@ -35,17 +35,18 @@ public class AutoBackLog {
@PreLoadMethod
private static void startAutoBackLog() {
// 开启秒级表达式
CronUtil.setMatchSecond(true);
if (projectInfoService == null) {
projectInfoService = SpringUtil.getBean(ProjectInfoService.class);
}
// 获取cron 表达式
String cron = StrUtil.emptyToDefault(ExtConfigBean.getInstance().autoBackConsoleCron, "none");
String cron = StrUtil.emptyToDefault(AgentExtConfigBean.getInstance().autoBackConsoleCron, "none");
if ("none".equalsIgnoreCase(cron.trim())) {
DefaultSystemLog.LOG().info("没有配置自动备份控制台日志表达式");
return;
}
String size = StrUtil.emptyToDefault(ExtConfigBean.getInstance().autoBackSize, "50MB");
String size = StrUtil.emptyToDefault(AgentExtConfigBean.getInstance().autoBackSize, "50MB");
MAX_SIZE = FileSize.valueOf(size.trim());
//
CronUtil.schedule(ID, cron, () -> {
@ -73,7 +74,7 @@ public class AutoBackLog {
List<File> files = FileUtil.loopFiles(logFile, pathname -> {
DateTime dateTime = DateUtil.date(pathname.lastModified());
long days = DateUtil.betweenDay(dateTime, nowTime, false);
long saveDays = ExtConfigBean.getInstance().getLogSaveDays();
long saveDays = AgentExtConfigBean.getInstance().getLogSaveDays();
return days > saveDays;
});
files.forEach(FileUtil::del);

View File

@ -0,0 +1,19 @@
package cn.keepbx.jpom.system.init;
import cn.jiangzeyin.common.PreLoadClass;
import cn.jiangzeyin.common.PreLoadMethod;
import cn.keepbx.jpom.system.AgentAuthorize;
/**
* 检查授权信息
*
* @author jiangzeyin
* @date 2019/4/17
*/
@PreLoadClass
public class CheckAuthorize {
@PreLoadMethod
private static void startAutoBackLog() {
AgentAuthorize.getInstance();
}
}

View File

@ -0,0 +1,20 @@
#运行端口号
server:
port: 2123
spring:
application:
name: jpomAgent
profiles:
active: dev
banner:
msg: Jpom-Agent管理系统启动中
# session 超时时间
tomcat:
sessionTimeOut: 3600
sessionCookieName: JPOMID-AGENT
# 启动完成自动初始化指定包
preload:
packageName: cn.keepbx.jpom.system.init
# 强制去掉空格
request:
trimAll: true

View File

@ -1,16 +1,14 @@
jpom:
# jpom 数据存储路径, 如果调试模式运行默认路径为【/jpom/】,安装运行默认为jar包文件的父级
path:
authorize:
# agent 端管理账号,必填。
agentName: jpomAgent
# agent 端管理密码非必填如果为空Jpom 会自动生成一串随机字符串当密码
agentPwd:
whitelistDirectory:
# 白名单目录是否验证包含关系
checkStartsWith: true
user:
# 最多能创建多少个用户
maxCount: 10
# 用户连续登录失败次数,超过此数将被限制登录
alwaysLoginError: 5
# 当ip连续登录失败锁定对应IP时长单位毫秒
ipErrorLockTime: 60*60*5*1000
log:
# 自动备份控制台日志防止日志文件过大目前暂只支持linux 不停服备份
autoBackConsoleCron: 0 0/10 * * * ?

View File

@ -0,0 +1,103 @@
//import cn.hutool.core.io.FileUtil;
//import org.apache.commons.codec.binary.Base64;
//import sun.misc.BASE64Decoder;
//import sun.misc.BASE64Encoder;
//
//import java.io.BufferedInputStream;
//import java.io.BufferedReader;
//import java.io.File;
//import java.io.FileReader;
//import java.security.KeyFactory;
//import java.security.PrivateKey;
//import java.security.Signature;
//import java.security.cert.Certificate;
//import java.security.cert.CertificateFactory;
//import java.security.cert.X509Certificate;
//import java.security.spec.PKCS8EncodedKeySpec;
//
//public class DTest {
//
//
// public static void main(String[] args) throws Exception {
//
// }
//
// private static void printTrack() {
// StackTraceElement[] st = Thread.currentThread().getStackTrace();
// StringBuilder sbf = new StringBuilder();
// for (StackTraceElement e : st) {
// if (sbf.length() > 0) {
// sbf.append(" <- ");
// sbf.append(System.getProperty("line.separator"));
// }
// sbf.append(java.text.MessageFormat.format("{0}.{1}() {2}"
// , e.getClassName()
// , e.getMethodName()
// , e.getLineNumber()));
// }
// System.out.println(sbf.toString());
// }
//
//
// private static void cert() throws Exception {
// String plain = "aaaa";
// File certFile = FileUtil.file("G:/soft/nginx/cert/full_chain.pem");
// CertificateFactory cf = CertificateFactory.getInstance("X.509");
// BufferedInputStream inStream = FileUtil.getInputStream(certFile);
// // 创建证书对象
// Certificate certificate = cf.generateCertificate(inStream);
// inStream.close();
//
// String sigAlgName = ((X509Certificate) certificate).getSigAlgName();
//
// Signature instance = Signature.getInstance(sigAlgName);
// PrivateKey privateKey = getPrivateKey(new File("G:/soft/nginx/cert/private.key"));
// instance.initSign(privateKey);
// instance.update(plain.getBytes());
// byte[] signed = instance.sign();
// BASE64Encoder encoder = new BASE64Encoder();
// //签名
// String encode = encoder.encode(signed);
//
// Signature signature = Signature.getInstance(sigAlgName);
// signature.initVerify(certificate.getPublicKey());
// signature.update(plain.getBytes());
// BASE64Decoder decoder = new BASE64Decoder();
// boolean verify = signature.verify(decoder.decodeBuffer(encode));
// System.out.println(verify);
// }
//
// /**
// * 利用java自带的方法读取openssl私钥,openssl私钥文件格式为pem需要去除页眉页脚后再进行base64位解码才能被java读取
// * 注意该方法有缺陷,只是简单的根据注释将页眉页脚去掉了,不是很完善,如果页眉页脚前面有空格和注释的情况的会有问题,保留此方法是为方便弄清楚openssl私钥解析原理
// */
// private static PrivateKey getPrivateKey(File file) {
// if (file == null) {
// return null;
// }
// PrivateKey privKey;
// try {
// BufferedReader privateKey = new BufferedReader(new FileReader(
// file));
// String line;
// StringBuilder strPrivateKey = new StringBuilder();
// while ((line = privateKey.readLine()) != null) {
// if (line.contains("--")) {//过滤掉首尾页眉页脚
// continue;
// }
// strPrivateKey.append(line);
// }
// privateKey.close();
// //使用base64位解码
// byte[] privKeyByte = Base64.decodeBase64(strPrivateKey.toString());
// //私钥需要使用pkcs8格式编码
// PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privKeyByte);
// KeyFactory kf = KeyFactory.getInstance("RSA");
// privKey = kf.generatePrivate(privKeySpec);
// return privKey;
// } catch (Exception e) {
// e.printStackTrace();
// }
// return null;
// }
//}

View File

@ -0,0 +1,232 @@
import cn.hutool.core.util.StrUtil;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class FileUtil {
public static int BUFFER_SIZE = 2048;
private static List<String> unTar(InputStream inputStream, String destDir) throws Exception {
List<String> fileNames = new ArrayList<String>();
TarArchiveInputStream tarIn = new TarArchiveInputStream(inputStream, BUFFER_SIZE);
TarArchiveEntry entry = null;
try {
while ((entry = tarIn.getNextTarEntry()) != null) {
fileNames.add(entry.getName());
if (entry.isDirectory()) {
//是目录
createDirectory(destDir, entry.getName());
//创建空目录
} else {
System.out.println(entry.getName());
//是文件
File tmpFile = new File(destDir + File.separator + entry.getName());
//创建输出目录
createDirectory(tmpFile.getParent() + File.separator, null);
OutputStream out = null;
try {
out = new FileOutputStream(tmpFile);
int length = 0;
byte[] b = new byte[2048];
while ((length = tarIn.read(b)) != -1) {
out.write(b, 0, length);
}
} finally {
IOUtils.closeQuietly(out);
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
IOUtils.closeQuietly(tarIn);
}
return fileNames;
}
public static List<String> unTar(String tarFile, String destDir) throws Exception {
File file = new File(tarFile);
return unTar(file, destDir);
}
public static List<String> unTar(File tarFile, String destDir) throws Exception {
if (StrUtil.isBlank(destDir)) {
destDir = tarFile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
return unTar(new FileInputStream(tarFile), destDir);
}
public static List<String> unTarBZip2(File tarFile, String destDir) throws Exception {
if (StrUtil.isBlank(destDir)) {
destDir = tarFile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
return unTar(new BZip2CompressorInputStream(new FileInputStream(tarFile)), destDir);
}
public static List<String> unTarBZip2(String file, String destDir) throws Exception {
File tarFile = new File(file);
return unTarBZip2(tarFile, destDir);
}
public static List<String> unBZip2(String bzip2File, String destDir) throws IOException {
File file = new File(bzip2File);
return unBZip2(file, destDir);
}
public static List<String> unBZip2(File srcFile, String destDir) throws IOException {
if (StrUtil.isBlank(destDir)) {
destDir = srcFile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
List<String> fileNames = new ArrayList<>();
InputStream is = null;
OutputStream os = null;
try {
File destFile = new File(destDir, srcFile.getName());
fileNames.add(srcFile.getName());
is = new BZip2CompressorInputStream(new BufferedInputStream(new FileInputStream(srcFile), BUFFER_SIZE));
os = new BufferedOutputStream(new FileOutputStream(destFile), BUFFER_SIZE);
IOUtils.copy(is, os);
} finally {
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(is);
}
return fileNames;
}
public static List<String> unGZ(String gzFile, String destDir) throws IOException {
File file = new File(gzFile);
return unGZ(file, destDir);
}
public static List<String> unGZ(File srcFile, String destDir) throws IOException {
if (StrUtil.isBlank(destDir)) {
destDir = srcFile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
List<String> fileNames = new ArrayList<String>();
InputStream is = null;
OutputStream os = null;
try {
File destFile = new File(destDir, srcFile.getName());
fileNames.add(srcFile.getName());
is = new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(srcFile), BUFFER_SIZE));
os = new BufferedOutputStream(new FileOutputStream(destFile), BUFFER_SIZE);
IOUtils.copy(is, os);
} finally {
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(is);
}
return fileNames;
}
public static List<String> unTarGZ(File tarFile, String destDir) throws Exception {
if (StrUtil.isBlank(destDir)) {
destDir = tarFile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
return unTar(new GzipCompressorInputStream(new FileInputStream(tarFile)), destDir);
}
public static List<String> unTarGZ(String file, String destDir) throws Exception {
File tarFile = new File(file);
return unTarGZ(tarFile, destDir);
}
public static void createDirectory(String outputDir, String subDir) {
File file = new File(outputDir);
if (!(subDir == null || "".equals(subDir.trim()))) {
//子目录不为空
file = new File(outputDir + File.separator + subDir);
}
if (!file.exists()) {
file.mkdirs();
}
}
public static List<String> unZip(File zipfile, String destDir) throws Exception {
if (StrUtil.isBlank(destDir)) {
destDir = zipfile.getParent();
}
destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
ZipArchiveInputStream is = null;
List<String> fileNames = new ArrayList<String>();
try {
is = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipfile), BUFFER_SIZE));
ZipArchiveEntry entry = null;
while ((entry = is.getNextZipEntry()) != null) {
fileNames.add(entry.getName());
if (entry.isDirectory()) {
File directory = new File(destDir, entry.getName());
directory.mkdirs();
} else {
OutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(new File(destDir, entry.getName())), BUFFER_SIZE);
IOUtils.copy(is, os);
} finally {
IOUtils.closeQuietly(os);
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
IOUtils.closeQuietly(is);
}
return fileNames;
}
public static List<String> unZip(String zipfile, String destDir) throws Exception {
File zipFile = new File(zipfile);
return unZip(zipFile, destDir);
}
public static List<String> unCompress(String compressFile, String destDir) throws Exception {
String upperName = compressFile.toUpperCase();
List<String> ret = null;
if (upperName.endsWith(".ZIP")) {
ret = unZip(compressFile, destDir);
} else if (upperName.endsWith(".TAR")) {
ret = unTar(compressFile, destDir);
} else if (upperName.endsWith(".TAR.BZ2")) {
ret = unTarBZip2(compressFile, destDir);
} else if (upperName.endsWith(".BZ2")) {
ret = unBZip2(compressFile, destDir);
} else if (upperName.endsWith(".TAR.GZ")) {
ret = unTarGZ(compressFile, destDir);
} else if (upperName.endsWith(".GZ")) {
ret = unGZ(compressFile, destDir);
}
return ret;
}
public static void main(String[] args) throws Exception {
unCompress("D:\\SystemDocument\\Desktop\\Desktop.tar.gz", "D:\\SystemDocument\\Desktop\\Desktop-test");
//System.out.println(unZip("F:\\fileupload\\dna-sample.zip", "F:\\fileupload\\"));
// System.out.println(unTar("F:\\fileupload\\中文test.tar", "F:\\fileupload\\"));
//System.out.println(unBZip2("F:\\fileupload\\中文test.xml.bz2", "F:\\fileupload\\"));
//System.out.println(unTarBZip2("F:\\fileupload\\中文test.tar.bz2", "F:\\fileupload\\"));
//System.out.println(unGZ("F:\\fileupload\\test.xml.gz", "F:\\fileupload\\"));
//System.out.println(unTarGZ("F:\\fileupload\\all.tar.gz", "F:\\fileupload\\"));
}
}

View File

@ -0,0 +1,33 @@
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ZipUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by jiangzeyin on 2019/4/22.
*/
public class TestFile {
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("D:\\SystemDocument\\Desktop\\Desktop.zip");
String code = IoUtil.readHex28Upper(inputStream);
System.out.println(code);
System.out.println(FileUtil.getMimeType("D:\\SystemDocument\\Desktop\\Desktop.zip"));
System.out.println(FileUtil.getMimeType("D:\\SystemDocument\\Desktop\\Desktop.tar.gz"));
System.out.println(FileUtil.getMimeType("D:\\SystemDocument\\Desktop\\Desktop.7z"));
ZipUtil.unzip(new File("D:\\SystemDocument\\Desktop\\Desktop.tar.gz"), new File("D:\\SystemDocument\\Desktop\\Desktop.7z\""));
ZipUtil.unzip(new File("D:\\SystemDocument\\Desktop\\Desktop.7z"), new File("D:\\SystemDocument\\Desktop\\Desktop.7z\""));
System.out.println(FileUtil.extName("test.zip"));
}
}

View File

@ -0,0 +1,60 @@
package com.jinhill.pki;
import cn.hutool.core.io.resource.ResourceUtil;
import java.io.InputStream;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class CertUtil {
static {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
public static String getSubjectDN(InputStream bIn) {
String dn = "";
try {
// BouncyCastleProvider provider = new BouncyCastleProvider();
// CertificateFactory cf = CertificateFactory.getInstance("X509",
// provider);
CertificateFactory cf = CertificateFactory.getInstance("X.509",
"SUN");
//android 需采用bcprov
// CertificateFactory cf = CertificateFactory.getInstance("X.509",
// "BC");
X509Certificate cert = (X509Certificate) cf
.generateCertificate(bIn);
dn = cert.getSubjectDN().getName();
bIn.close();
} catch (CertificateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return dn;
}
public static String parseCertDN(String dn, String type) {
type = type + "=";
String[] split = dn.split(",");
for (String x : split) {
if (x.contains(type)) {
x = x.trim();
return x.substring(type.length());
}
}
return null;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
InputStream inputStream = ResourceUtil.getStream("D:\\jpom\\agent\\data\\temp\\系统管理员\\sdfasdf\\example.com.csr");
getSubjectDN(inputStream);
}
}

20
modules/common/pom.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jpom</artifactId>
<groupId>cn.keepbx</groupId>
<version>2.4.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>cn.keepbx.jpom</groupId>
<artifactId>common</artifactId>
<version>2.4.0</version>
<dependencies>
</dependencies>
</project>

View File

@ -0,0 +1,69 @@
package cn.keepbx.jpom;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import cn.keepbx.jpom.common.Type;
import java.nio.charset.Charset;
/**
* Jpom
*
* @author jiangzeyin
* @date 2019/4/16
*/
public abstract class BaseJpomApplication {
public static final OsInfo OS_INFO = SystemUtil.getOsInfo();
protected static String[] args;
/**
* 应用类型
*/
private static Type appType;
private static Charset charset;
private static Class appClass;
/**
* 获取程序命令行参数
*
* @return 数组
*/
public static String[] getArgs() {
return args;
}
public BaseJpomApplication(Type appType, Class appClass) {
BaseJpomApplication.appType = appType;
BaseJpomApplication.appClass = appClass;
}
/**
* 获取当前系统编码
*
* @return charset
*/
public static Charset getCharset() {
if (charset == null) {
if (OS_INFO.isLinux()) {
charset = CharsetUtil.CHARSET_UTF_8;
} else {
charset = CharsetUtil.CHARSET_GBK;
}
}
return charset;
}
public static Type getAppType() {
return appType;
}
public static Class getAppClass() {
if (appClass == null) {
return BaseJpomApplication.class;
}
return appClass;
}
}

View File

@ -0,0 +1,109 @@
package cn.keepbx.jpom;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import cn.keepbx.jpom.util.ArgsUtil;
import cn.keepbx.jpom.util.CommandUtil;
import cn.keepbx.jpom.util.JvmUtil;
import com.sun.tools.attach.VirtualMachine;
import java.io.IOException;
/**
* 命令行关闭Jpom
*
* @author jiangzeyin
* @date 2019/4/7
*/
public class JpomClose {
private static JpomClose jpomManager;
public static void main(String[] args) throws Exception {
if (args == null || args.length <= 0) {
Console.error("请传入正确的参数");
return;
}
String tag = ArgsUtil.getArgsValue(args, "jpom.applicationTag");
if (StrUtil.isEmpty(tag)) {
Console.error("请传入对应jpom.applicationTag");
return;
}
// 事件
String event = ArgsUtil.getArgsValue(args, "event");
if ("stop".equalsIgnoreCase(event)) {
String status = JpomClose.getInstance().status(tag);
if (!status.contains(StrUtil.COLON)) {
Console.error("Jpom并没有运行");
return;
}
String msg = JpomClose.getInstance().stop(tag);
Console.log(msg);
} else if ("status".equalsIgnoreCase(event)) {
String status = JpomClose.getInstance().status(tag);
Console.log(status);
} else {
Console.error("event error:" + event);
}
}
/**
* 单利模式
*
* @return JpomClose
*/
public static JpomClose getInstance() {
if (jpomManager != null) {
return jpomManager;
}
if (BaseJpomApplication.OS_INFO.isLinux()) {
jpomManager = new Linux();
} else {
jpomManager = new Windows();
}
return jpomManager;
}
public String stop(String tag) throws IOException {
VirtualMachine virtualMachine = JvmUtil.getVirtualMachine(tag);
if (virtualMachine == null) {
return null;
}
return virtualMachine.id();
}
public String status(String tag) throws IOException {
VirtualMachine virtualMachine = JvmUtil.getVirtualMachine(tag);
if (virtualMachine == null) {
return "Jpom并没有运行";
}
return "Jpom运行中:" + virtualMachine.id();
}
private static class Windows extends JpomClose {
@Override
public String stop(String tag) throws IOException {
String pid = super.stop(tag);
if (pid == null) {
return "stop";
}
String cmd = String.format("taskkill /F /PID %s", pid);
return CommandUtil.execCommand(cmd);
}
}
private static class Linux extends JpomClose {
@Override
public String stop(String tag) throws IOException {
String pid = super.stop(tag);
if (pid == null) {
return "stop";
}
String cmd = String.format("kill %s", pid);
return CommandUtil.execCommand(cmd);
}
}
}

View File

@ -60,7 +60,7 @@ public abstract class BaseDataService {
* @param filename 文件名
* @param json json数据
*/
protected void updateJson(String filename, JSONObject json) throws Exception {
protected void updateJson(String filename, JSONObject json) {
String key = json.getString("id");
// 读取文件如果不存在记录则抛出异常
JSONObject allData = getJSONObject(filename);
@ -68,7 +68,7 @@ public abstract class BaseDataService {
// 判断是否存在数据
if (null == data || 0 == data.keySet().size()) {
throw new Exception("数据不存在:" + key);
throw new JpomRuntimeException("数据不存在:" + key);
} else {
allData.put(key, json);
JsonFileUtil.saveJson(getDataFilePath(filename), allData);
@ -80,15 +80,14 @@ public abstract class BaseDataService {
*
* @param filename 文件
* @param key key
* @throws Exception 异常
*/
protected void deleteJson(String filename, String key) throws Exception {
protected void deleteJson(String filename, String key) {
// 读取文件如果存在记录则抛出异常
JSONObject allData = getJSONObject(filename);
JSONObject data = allData.getJSONObject(key);
// 判断是否存在数据
if (CollUtil.isEmpty(data)) {
throw new Exception("项目名称存不在!");
throw new JpomRuntimeException("项目名称存不在!");
} else {
allData.remove(key);
JsonFileUtil.saveJson(getDataFilePath(filename), allData);

View File

@ -0,0 +1,39 @@
package cn.keepbx.jpom.common;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.controller.base.AbstractController;
/**
* controller
*
* @author jiangzeyin
* @date 2019/4/16
*/
public abstract class BaseJpomController extends AbstractController {
/**
* 路径安全格式化
*
* @param path 路径
* @return 去掉 提权字符串
*/
public static String pathSafe(String path) {
if (path == null) {
return null;
}
String newPath = path.replace("../", StrUtil.EMPTY);
newPath = newPath.replace("..\\", StrUtil.EMPTY);
newPath = newPath.replace("+", StrUtil.EMPTY);
return FileUtil.normalize(newPath);
}
protected boolean checkPathSafe(String path) {
if (path == null) {
return false;
}
String newPath = path.replace("../", StrUtil.EMPTY);
newPath = newPath.replace("..\\", StrUtil.EMPTY);
newPath = newPath.replace("+", StrUtil.EMPTY);
return newPath.equals(path);
}
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.event.ApplicationEventClient;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.model.system.JpomManifest;
import cn.keepbx.jpom.system.ConfigBean;
import org.springframework.boot.context.event.ApplicationReadyEvent;
@ -14,8 +15,6 @@ import org.springframework.context.event.ContextClosedEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
@ -31,10 +30,7 @@ public class JpomApplicationEvent implements ApplicationEventClient {
private FileLock lock;
private FileOutputStream fileOutputStream;
private FileChannel fileChannel;
/**
* 记录当前程序进程
*/
private static int PID = 0;
@Override
public void onApplicationEvent(ApplicationEvent event) {
@ -50,15 +46,23 @@ public class JpomApplicationEvent implements ApplicationEventClient {
}
// 写入Jpom 信息
JpomManifest jpomManifest = JpomManifest.getInstance();
File jpomInfo = ConfigBean.getInstance().getJpomInfo();
FileUtil.writeString(jpomManifest.toString(), jpomInfo, CharsetUtil.CHARSET_UTF_8);
// 写入全局信息
File appJpomFile = ConfigBean.getInstance().getApplicationJpomInfo(BaseJpomApplication.getAppType());
FileUtil.writeString(jpomManifest.toString(), appJpomFile, CharsetUtil.CHARSET_UTF_8);
} else if (event instanceof ContextClosedEvent) {
// 应用关闭
this.unLockFile();
//
FileUtil.del(ConfigBean.getInstance().getPidFile());
//
File appJpomFile = ConfigBean.getInstance().getApplicationJpomInfo(BaseJpomApplication.getAppType());
FileUtil.del(appJpomFile);
}
}
/**
* 解锁进程文件
*/
private void unLockFile() {
if (lock != null) {
try {
@ -93,23 +97,4 @@ public class JpomApplicationEvent implements ApplicationEventClient {
}
}
}
/**
* 获取当前程序进程id
*
* @return pid
*/
public static int getPid() {
if (PID == 0) {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
// format: "pid@hostname"
String name = runtime.getName();
try {
PID = Integer.parseInt(name.substring(0, name.indexOf('@')));
} catch (Exception e) {
PID = -1;
}
}
return PID;
}
}

View File

@ -0,0 +1,18 @@
package cn.keepbx.jpom.common;
/**
* Jpom 程序类型
*
* @author jiangzeyin
* @date 2019/4/17
*/
public enum Type {
/**
* 插件端
*/
Agent,
/**
* 中心服务端
*/
Server
}

View File

@ -8,6 +8,15 @@ package cn.keepbx.jpom.model;
*/
public abstract class BaseModel extends BaseJsonModel {
private String id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;

View File

@ -1,4 +1,4 @@
package cn.keepbx.jpom.common;
package cn.keepbx.jpom.model;
/**
* 用户角色
@ -12,9 +12,13 @@ public enum Role {
*/
System,
/**
* 普通管理员
* 服务端管理员
*/
Manage,
ServerManager,
/**
* 节点管理员
*/
NodeManage,
/**
* 用户
*/

View File

@ -0,0 +1,18 @@
package cn.keepbx.jpom.model;
/**
* 项目的运行方式
*
* @author jiangzeyin
* @date 2019/4/22
*/
public enum RunMode {
/**
* java -classpath
*/
ClassPath,
/**
* java -jar
*/
Jar,
}

View File

@ -0,0 +1,109 @@
package cn.keepbx.jpom.model.data;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.common.BaseJpomController;
import cn.keepbx.jpom.model.BaseJsonModel;
import cn.keepbx.jpom.system.ExtConfigBean;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* 白名单
*
* @author jiangzeyin
* @date 2019/4/16
*/
public class AgentWhitelist extends BaseJsonModel {
private List<String> project;
private List<String> certificate;
private List<String> nginx;
public List<String> getProject() {
return project;
}
public void setProject(List<String> project) {
this.project = project;
}
public List<String> getCertificate() {
return certificate;
}
public void setCertificate(List<String> certificate) {
this.certificate = certificate;
}
public List<String> getNginx() {
return nginx;
}
public void setNginx(List<String> nginx) {
this.nginx = nginx;
}
public static List<String> covertToArray(List<String> list) {
List<String> array = new ArrayList<>();
for (String s : list) {
String val = String.format("/%s/", s);
val = BaseJpomController.pathSafe(val);
if (StrUtil.SLASH.equals(val)) {
continue;
}
if (array.contains(val)) {
continue;
}
// 判断是否保护jpom 路径
if (val == null || val.startsWith(ExtConfigBean.getInstance().getPath())) {
return null;
}
array.add(val);
}
return array;
}
/**
* 转换为字符串
*
* @param jsonArray jsonArray
* @return str
*/
public static String convertToLine(List<String> jsonArray) {
try {
return CollUtil.join(jsonArray, "\r\n");
} catch (Exception e) {
DefaultSystemLog.ERROR().error(e.getMessage(), e);
}
return "";
}
/**
* 判断是否在白名单列表中
*
* @param list list
* @param path 对应项
* @return false 不在列表中
*/
public static boolean checkPath(List<String> list, String path) {
if (list == null) {
return false;
}
if (StrUtil.isEmpty(path)) {
return false;
}
File file1, file2 = FileUtil.file(path);
for (String item : list) {
file1 = FileUtil.file(item);
if (FileUtil.pathEquals(file1, file2)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,31 @@
package cn.keepbx.jpom.model.system;
import cn.keepbx.jpom.model.BaseJsonModel;
/**
* agent 端自动生成的密码实体
*
* @author jiangzeyin
* @date 2019/4/18
*/
public class AgentAutoUser extends BaseJsonModel {
private String agentName;
private String agentPwd;
public String getAgentName() {
return agentName;
}
public void setAgentName(String agentName) {
this.agentName = agentName;
}
public String getAgentPwd() {
return agentPwd;
}
public void setAgentPwd(String agentPwd) {
this.agentPwd = agentPwd;
}
}

View File

@ -2,10 +2,14 @@ package cn.keepbx.jpom.model.system;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.keepbx.jpom.JpomApplication;
import cn.keepbx.jpom.common.JpomApplicationEvent;
import cn.hutool.system.SystemUtil;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.Type;
import cn.keepbx.jpom.system.ConfigBean;
import com.alibaba.fastjson.JSON;
import org.springframework.boot.ApplicationHome;
import java.io.File;
import java.io.IOException;
@ -20,11 +24,38 @@ import java.util.jar.Manifest;
* @date 2019/4/7
*/
public class JpomManifest {
private static final JpomManifest JPOM_MANIFEST;
private static JpomManifest JPOM_MANIFEST;
/**
* 当前版本
*/
private String version = "dev";
/**
* 打包时间
*/
private String timeStamp;
/**
* 进程id
*/
private long pid = SystemUtil.getCurrentPID();
/**
* 当前运行类型
*/
private Type type = BaseJpomApplication.getAppType();
/**
* 端口号
*/
private int port;
/**
* Jpom 的数据目录
*/
private String dataPath;
static {
private static synchronized void init() {
if (JPOM_MANIFEST != null) {
return;
}
JPOM_MANIFEST = new JpomManifest();
File jarFile = JpomApplication.getRunPath();
File jarFile = getRunPath();
if (jarFile.isFile()) {
JarFile jarFile1;
try {
@ -52,26 +83,15 @@ public class JpomManifest {
* @return this
*/
public static JpomManifest getInstance() {
init();
return JPOM_MANIFEST;
}
/**
* 当前版本
*/
private String version = "dev";
/**
* 打包时间
*/
private String timeStamp;
/**
* 进程id
*/
private int pid;
public Type getType() {
return type;
}
public int getPid() {
if (pid == 0) {
this.pid = JpomApplicationEvent.getPid();
}
public long getPid() {
return pid;
}
@ -109,15 +129,57 @@ public class JpomManifest {
*/
public void setTimeStamp(String timeStamp) {
if (StrUtil.isNotEmpty(timeStamp)) {
DateTime dateTime = DateUtil.parseUTC(timeStamp);
this.timeStamp = dateTime.toStringDefaultTimeZone();
try {
DateTime dateTime = DateUtil.parseUTC(timeStamp);
this.timeStamp = dateTime.toStringDefaultTimeZone();
} catch (Exception e) {
this.timeStamp = timeStamp;
}
} else {
this.timeStamp = timeStamp;
this.timeStamp = "dev";
}
}
public void setPort(int port) {
this.port = port;
}
/**
* 程序运行的端口
*
* @return 端口
*/
public int getPort() {
if (port == 0) {
port = ConfigBean.getInstance().getPort();
}
return port;
}
public String getDataPath() {
if (StrUtil.isEmpty(dataPath)) {
dataPath = ConfigBean.getInstance().getDataPath();
}
return dataPath;
}
public void setDataPath(String dataPath) {
this.dataPath = dataPath;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
/**
* 获取当前运行的路径
*
* @return jar 或者classPath
*/
public static File getRunPath() {
ApplicationHome home = new ApplicationHome(BaseJpomApplication.getAppClass());
String path = (home.getSource() == null ? "" : home.getSource().getAbsolutePath());
return FileUtil.file(path);
}
}

View File

@ -0,0 +1,29 @@
package cn.keepbx.jpom.socket;
/**
* socket 操作枚举
*
* @author jiangzeyin
* @date 2019/4/16
*/
public enum CommandOp {
/**
* 启动
*/
start,
stop,
restart,
status,
/**
* 运行日志
*/
showlog,
/**
* 查看内存信息
*/
top,
/**
* 心跳
*/
heart
}

View File

@ -0,0 +1,11 @@
package cn.keepbx.jpom.socket;
/**
* @author jiangzeyin
* @date 2019/4/19
*/
public class CommonSocketConfig {
public static final String SYSTEM_ID = "system";
}

View File

@ -0,0 +1,25 @@
package cn.keepbx.jpom.system;
import org.aspectj.lang.JoinPoint;
/**
* 日志接口
*
* @author jiangzeyin
* @date 2019/4/19
*/
public interface AopLogInterface {
/**
* 进入前
*
* @param joinPoint point
*/
void before(JoinPoint joinPoint);
/**
* 执行后
*
* @param value 结果
*/
void afterReturning(Object value);
}

View File

@ -0,0 +1,112 @@
package cn.keepbx.jpom.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.common.Type;
import cn.keepbx.jpom.model.system.JpomManifest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.io.File;
/**
* 配置项
*
* @author jiangzeyin
* @date 2019/4/16
*/
@Configuration
public class ConfigBean {
/**
* 用户角色header
*/
public static final String JPOM_SERVER_SYSTEM_USER_ROLE = "Jpom-Server-SystemUserRole";
/**
* 用户名header
*/
public static final String JPOM_SERVER_USER_NAME = "Jpom-Server-UserName";
public static final String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize";
private static final String DATA = "data";
public static final int AUTHORIZE_ERROR = 900;
/**
* 授权信息
*/
private static final String AUTHORIZE = "agent_authorize.json";
/**
* Jpom 程序运行的 application 标识
*/
@Value("${jpom.applicationTag:}")
public String applicationTag;
/**
* 程序端口
*/
@Value("${server.port}")
private int port;
private static ConfigBean configBean;
/**
* 单利模式
*
* @return config
*/
public static ConfigBean getInstance() {
if (configBean == null) {
configBean = SpringUtil.getBean(ConfigBean.class);
}
return configBean;
}
public int getPort() {
return port;
}
/**
* 获取项目运行数据存储文件夹路径
*
* @return 文件夹路径
*/
public String getDataPath() {
String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + "/" + DATA);
FileUtil.mkdir(dataPath);
return dataPath;
}
/**
* 获取pid文件
*
* @return file
*/
public File getPidFile() {
return new File(getDataPath(), StrUtil.format("pid.{}.{}",
BaseJpomApplication.getAppType().name(), JpomManifest.getInstance().getPid()));
}
/**
* 获取当前项目全局 运行信息文件路径
*
* @param type 程序类型
* @return file
*/
public File getApplicationJpomInfo(Type type) {
return FileUtil.file(SystemUtil.getUserInfo().getTempDir(), "jpom", type.name());
}
/**
* 获取 agent 端自动生成的授权文件路径
*
* @param dataPath 指定数据路径
* @return file
*/
public String getAgentAutoAuthorizeFile(String dataPath) {
return FileUtil.normalize(dataPath + "/" + ConfigBean.AUTHORIZE);
}
}

View File

@ -0,0 +1,87 @@
package cn.keepbx.jpom.system;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.spring.SpringUtil;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.model.system.JpomManifest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import java.io.File;
/**
* 外部资源配置
*
* @author jiangzeyin
* @date 2019/4/16
*/
@Configuration
public class ExtConfigBean {
static final String FILE_NAME = "extConfig.yml";
private static Resource resource;
/**
* 动态获取外部配置文件的 resource
*
* @return File
*/
public static Resource getResource() {
if (resource != null) {
return resource;
}
File file = JpomManifest.getRunPath();
if (file.isFile()) {
file = file.getParentFile().getParentFile();
file = new File(file, FILE_NAME);
if (file.exists() && file.isFile()) {
resource = new FileSystemResource(file);
return ExtConfigBean.resource;
}
}
resource = new ClassPathResource("/bin/" + FILE_NAME);
return ExtConfigBean.resource;
}
/**
* 单例
*
* @return this
*/
public static ExtConfigBean getInstance() {
return SpringUtil.getBean(ExtConfigBean.class);
}
/**
* 项目运行存储路径
*/
@Value("${jpom.path}")
private String path;
public String getPath() {
if (StrUtil.isEmpty(path)) {
if (JpomManifest.getInstance().isDebug()) {
// 调试模式 为根路径的 jpom文件
path = ("/jpom/" + BaseJpomApplication.getAppType().name() + "/").toLowerCase();
} else {
// 获取当前项目运行路径的父级
File file = JpomManifest.getRunPath();
if (!file.exists() && !file.isFile()) {
throw new JpomRuntimeException("请配置运行路径属性【jpom.path】");
}
path = file.getParentFile().getParentFile().getAbsolutePath();
}
DefaultSystemLog.LOG().info("当前数据路径:{}", path);
}
return path;
}
public String getAbsolutePath() {
return FileUtil.getAbsolutePath(FileUtil.file(getPath()));
}
}

View File

@ -3,7 +3,8 @@ package cn.keepbx.jpom.system;
import ch.qos.logback.core.PropertyDefinerBase;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.JpomApplication;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.model.system.JpomManifest;
import cn.keepbx.jpom.util.ArgsUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
@ -29,6 +30,12 @@ import java.io.File;
public class WebAopLog extends PropertyDefinerBase {
private static final ThreadLocal<Boolean> IS_LOG = new ThreadLocal<>();
private static volatile AopLogInterface aopLogInterface;
synchronized public static void setAopLogInterface(AopLogInterface aopLogInterface) {
WebAopLog.aopLogInterface = aopLogInterface;
}
@Pointcut("execution(public * cn.keepbx.jpom.controller..*.*(..))")
public void webLog() {
//
@ -36,6 +43,9 @@ public class WebAopLog extends PropertyDefinerBase {
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
if (aopLogInterface != null) {
aopLogInterface.before(joinPoint);
}
// 接收到请求记录请求内容
IS_LOG.set(true);
Signature signature = joinPoint.getSignature();
@ -53,6 +63,9 @@ public class WebAopLog extends PropertyDefinerBase {
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) {
if (aopLogInterface != null) {
aopLogInterface.afterReturning(ret);
}
if (ret == null) {
return;
}
@ -67,16 +80,17 @@ public class WebAopLog extends PropertyDefinerBase {
@Override
public String getPropertyValue() {
String path = ArgsUtil.getArgsValue(JpomApplication.getArgs(), "jpom.log");
String path = ArgsUtil.getArgsValue(BaseJpomApplication.getArgs(), "jpom.log");
if (StrUtil.isEmpty(path)) {
//
File file = JpomApplication.getRunPath();
File file = JpomManifest.getRunPath();
if (file.isFile()) {
file = file.getParentFile().getParentFile();
}
file = new File(file, "log");
path = file.getPath();
}
// System.out.println(path);
// 配置默认日志路径
DefaultSystemLog.configPath(path, false);
return path;

View File

@ -3,14 +3,21 @@ package cn.keepbx.jpom.system.init;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.jiangzeyin.common.PreLoadClass;
import cn.jiangzeyin.common.PreLoadMethod;
import cn.keepbx.jpom.BaseJpomApplication;
import cn.keepbx.jpom.model.system.JpomManifest;
import cn.keepbx.jpom.system.ExtConfigBean;
import cn.keepbx.jpom.util.JvmUtil;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.VmIdentifier;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
/**
* 数据目录权限检查
@ -45,7 +52,7 @@ public class CheckPath {
try {
ClassUtil.loadClass(CLASS_NAME, false);
} catch (Exception e) {
File file = getToolsJar();
File file = JvmUtil.getToolsJar();
if (file.exists() && file.isFile()) {
DefaultSystemLog.ERROR().error("Jpom未能正常加载tools.jar,请检查当前系统环境变量是否配置JAVA_HOME或者检查Jpom管理命令是否正确", e);
} else {
@ -55,8 +62,23 @@ public class CheckPath {
}
}
private static File getToolsJar() {
File file = new File(SystemUtil.getJavaRuntimeInfo().getHomeDir());
return new File(file.getParentFile(), "lib/tools.jar");
@PreLoadMethod(2)
private static void checkDuplicateRun() {
Class appClass = BaseJpomApplication.getAppClass();
List<MonitoredVm> monitoredVms;
try {
String pid = String.valueOf(JpomManifest.getInstance().getPid());
monitoredVms = JvmUtil.listMainClass(appClass.getName());
monitoredVms.forEach(monitoredVm -> {
VmIdentifier vmIdentifier = monitoredVm.getVmIdentifier();
if (pid.equals(vmIdentifier.getUserInfo())) {
return;
}
DefaultSystemLog.LOG().info("Jpom 程序建议一个机器上只运行一个对应的程序:" + BaseJpomApplication.getAppType());
});
} catch (MonitorException | URISyntaxException ignored) {
}
}
}

View File

@ -3,7 +3,7 @@ package cn.keepbx.jpom.util;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.common.commander.AbstractProjectCommander;
import cn.keepbx.jpom.BaseJpomApplication;
import java.io.IOException;
import java.io.InputStream;
@ -32,7 +32,7 @@ public class CommandUtil {
String result = "error";
try {
String[] cmd;
if (AbstractProjectCommander.OS_INFO.isLinux()) {
if (BaseJpomApplication.OS_INFO.isLinux()) {
//执行linux系统命令
cmd = new String[]{"/bin/sh", "-c", command};
} else {
@ -70,7 +70,7 @@ public class CommandUtil {
} else {
is = process.getErrorStream();
}
result = IoUtil.read(is, AbstractProjectCommander.getInstance().getCharset());
result = IoUtil.read(is, BaseJpomApplication.getCharset());
is.close();
process.destroy();
if (StrUtil.isEmpty(result) && wait != 0) {

View File

@ -4,6 +4,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.io.File;
@ -53,4 +54,13 @@ public class JsonFileUtil {
FileUtil.writeString(newsJson, path, CharsetUtil.UTF_8);
}
}
public static <T> JSONObject arrayToObjById(JSONArray array) {
JSONObject jsonObject = new JSONObject();
array.forEach(o -> {
JSONObject jsonObject1 = (JSONObject) o;
jsonObject.put(jsonObject1.getString("id"), jsonObject1);
});
return jsonObject;
}
}

View File

@ -8,6 +8,7 @@ import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.system.JpomRuntimeException;
import com.sun.management.OperatingSystemMXBean;
import com.sun.tools.attach.*;
import sun.jvmstat.monitor.*;
import sun.management.ConnectorAddressLink;
import javax.management.MBeanServerConnection;
@ -18,8 +19,8 @@ import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.List;
import java.util.Properties;
import java.net.URISyntaxException;
import java.util.*;
/**
* jvm jmx 工具
@ -94,6 +95,19 @@ public class JvmUtil {
return null;
}
/**
* 获取当前系统运行的java 程序个数
*
* @return 如果发生异常则返回0
*/
public static int getJavaVirtualCount() {
try {
List<VirtualMachineDescriptor> descriptorList = VirtualMachine.list();
return descriptorList.size();
} catch (Exception e) {
return 0;
}
}
/**
* 工具Jpom运行项目的id 获取virtualMachine
@ -142,4 +156,40 @@ public class JvmUtil {
}
throw new JpomRuntimeException("JDK中" + file.getAbsolutePath() + " 文件不存在");
}
/**
* 获取jdk 中的tools jar文件路径
*
* @return file
*/
public static File getToolsJar() {
File file = new File(SystemUtil.getJavaRuntimeInfo().getHomeDir());
return new File(file.getParentFile(), "lib/tools.jar");
}
/**
* 工具指定的 mainClass 获取对应所有的的 MonitoredVm对象
*
* @param mainClass 程序运行主类
* @return list
* @throws MonitorException e
* @throws URISyntaxException e
*/
public static List<MonitoredVm> listMainClass(String mainClass) throws MonitorException, URISyntaxException {
List<MonitoredVm> monitoredVms = new ArrayList<>();
MonitoredHost local = MonitoredHost.getMonitoredHost("localhost");
// 取得所有在活动的虚拟机集合
Set<?> vmList = new HashSet<Object>(local.activeVms());
// 遍历集合输出PID和进程名
for (Object process : vmList) {
MonitoredVm vm = local.getMonitoredVm(new VmIdentifier("//" + process));
// 获取类名
String processName = MonitoredVmUtil.mainClass(vm, true);
if (!mainClass.equals(processName)) {
continue;
}
monitoredVms.add(vm);
}
return monitoredVms;
}
}

View File

@ -1,14 +1,13 @@
package cn.keepbx.jpom.socket;
package cn.keepbx.jpom.util;
import cn.hutool.core.util.StrUtil;
import cn.jiangzeyin.common.DefaultSystemLog;
import cn.keepbx.jpom.util.KeyLock;
import javax.websocket.Session;
import java.io.IOException;
/**
* socket 话对象
* socket 话对象
*
* @author jiangzeyin
* @date 2018/9/29
@ -26,7 +25,7 @@ public class SocketSessionUtil {
/**
* 发送消息
*
* @param session 话对象
* @param session 话对象
* @param msg 消息
* @throws IOException 异常
*/
@ -53,6 +52,7 @@ public class SocketSessionUtil {
try {
session.getBasicRemote().sendText(msg);
exception = null;
break;
} catch (IOException e) {
DefaultSystemLog.ERROR().error("发送消息失败:" + tryCount, e);
exception = e;

Some files were not shown because too many files have changed in this diff Show More