Merge remote-tracking branch 'origin/main'

# Conflicts:
#	README.md
This commit is contained in:
lijiahang
2024-07-22 10:31:45 +08:00
252 changed files with 3365 additions and 2142 deletions

21
.github/workflows/e2e.yaml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: E2E
on:
pull_request:
branches:
- main
concurrency:
group: ${{github.workflow}} - ${{github.ref}}
cancel-in-progress: true
jobs:
testing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: E2E Testing
run: |
sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo chmod u+x /usr/local/bin/docker-compose
docker compose -f docker-compose-testing.yml up --build testing --exit-code-from testing --remove-orphans

7
NOTICE Normal file
View File

@@ -0,0 +1,7 @@
* 在使用本项目前,请您仔细阅读免责声明,确保您已充分理解其中的内容
* 本项目采用 APACHE LICENSE 2.0 开源协议,如您需要源码的开发方式,需要遵循以下几点
1. 禁止修改或删除 LICENSE 文件。
2. 不可二次开发或参与同类竞品的开发。
3. 本项目可免费商业使用,商业使用请保留项目源码、出处、描述文件和作者声明等。

View File

@@ -13,27 +13,27 @@
</a>
<a target="_blank"
style="text-decoration: none !important;"
href="https://github.com/lijiahangmax/orion-visor/releases">
href="https://github.com/dromara/orion-visor/releases">
<img src="https://img.shields.io/github/v/release/lijiahangmax/orion-visor" alt="release" />
</a>
<a target="_blank"
style="text-decoration: none !important;"
href="https://gitee.com/lijiahangmax/orion-visor/stargazers">
<img src="https://gitee.com/lijiahangmax/orion-visor/badge/star.svg?theme=dark" alt="star" />
href="https://gitee.com/dromara/orion-visor/stargazers">
<img src="https://gitee.com/dromara/orion-visor/badge/star.svg?theme=dark" alt="star" />
</a>
<a target="_blank"
style="text-decoration: none !important;"
href="https://gitee.com/lijiahangmax/orion-visor/members">
<img src="https://gitee.com/lijiahangmax/orion-visor/badge/fork.svg?theme=dark" alt="fork" />
href="https://gitee.com/dromara/orion-visor/members">
<img src="https://gitee.com/dromara/orion-visor/badge/fork.svg?theme=dark" alt="fork" />
</a>
<a target="_blank"
style="text-decoration: none !important;"
href="https://github.com/lijiahangmax/orion-visor">
href="https://github.com/dromara/orion-visor">
<img src="https://img.shields.io/github/stars/lijiahangmax/orion-visor" alt="star" />
</a>
<a target="_blank"
style="text-decoration: none !important;"
href="https://github.com/lijiahangmax/orion-visor">
href="https://github.com/dromara/orion-visor">
<img src="https://img.shields.io/github/forks/lijiahangmax/orion-visor" alt="star" />
</a>
</p>
@@ -53,7 +53,7 @@
* 🔗 演示地址: http://101.43.254.243:1081/
* 🔏 演示账号: admin/admin
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/lijiahangmax/orion-visor) [gitee](https://gitee.com/lijiahangmax/orion-visor) [gitcode](https://gitcode.com/qq_41011894/orion-visor/overview)
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/dromara/orion-visor) [gitee](https://gitee.com/dromara/orion-visor)
* 🌈 如果本项目对你有帮助请帮忙推广一下 让更多的人知道此项目!
* 🎭 演示环境部分功能不可用, 完整功能请本地部署!
* 📛 演示环境请不要随便删除数据!
@@ -63,7 +63,7 @@
```bash
# clone
git clone https://github.com/lijiahangmax/orion-visor
git clone https://github.com/dromara/orion-visor
cd orion-visor
# 启动
docker compose up -d
@@ -131,8 +131,8 @@ docker compose up -d
## 免责声明
在使用本项目之前, 请确保您已经了解并同意相关的使用协议和隐私政策。[免责声明](https://github.com/lijiahangmax/orion-visor/blob/main/DISCLAIMER.md)
在使用本项目之前, 请确保您已经了解并同意相关的使用协议和隐私政策。[免责声明](https://github.com/dromara/orion-visor/blob/main/DISCLAIMER.md)
## License
本项目遵循 [Apache-2.0](https://github.com/lijiahangmax/orion-visor/blob/main/LICENSE) 开源许可证。
本项目遵循 [Apache-2.0](https://github.com/dromara/orion-visor/blob/main/LICENSE) 开源许可证。

View File

@@ -0,0 +1,79 @@
version: '3.3'
services:
orion-visor-service:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.0.11
privileged: true
ports:
- 1081:80
environment:
- MYSQL_HOST=orion-visor-mysql
- MYSQL_PORT=3306
- MYSQL_DATABASE=orion_visor
- MYSQL_USER=root
- MYSQL_PASSWORD=Data@123456
- REDIS_HOST=orion-visor-redis
- REDIS_PASSWORD=Data@123456
- SECRET_KEY=uQeacXV8b3isvKLK
- DEMO_MODE=false
volumes:
- /data/orion-visor-space/docker-volumes/service/root-orion:/root/orion
healthcheck:
test: [ "CMD", "curl", "http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health" ]
interval: 3s
timeout: 300s
retries: 200
start_period: 3s
depends_on:
orion-visor-mysql:
condition: service_healthy
orion-visor-redis:
condition: service_healthy
links:
- orion-visor-mysql
- orion-visor-redis
orion-visor-mysql:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.0.11
privileged: true
ports:
- 3307:3306
environment:
- MYSQL_DATABASE=orion_visor
- MYSQL_USER=orion
- MYSQL_PASSWORD=Data@123456
- MYSQL_ROOT_PASSWORD=Data@123456
volumes:
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql:/var/lib/mysql
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql-files:/var/lib/mysql-files
- /data/orion-visor-space/docker-volumes/mysql/etc-mysql:/etc/mysql
healthcheck:
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
interval: 3s
timeout: 60s
retries: 10
start_period: 3s
orion-visor-redis:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.0.11
privileged: true
ports:
- 6380:6379
environment:
- REDIS_PASSWORD=Data@123456
volumes:
- /data/orion-visor-space/docker-volumes/redis/data:/data
command: sh -c "redis-server /usr/local/redis.conf --requirepass $${REDIS_PASSWORD}"
healthcheck:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
interval: 3s
timeout: 60s
retries: 10
start_period: 3s
testing:
build:
context: ./docker/e2e
environment:
SERVER: http://orion-visor-service:80
depends_on:
orion-visor-service:
condition: service_healthy
links:
- orion-visor-service

View File

@@ -1,7 +1,8 @@
version: '3.3'
services:
orion-visor-service:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.0.6
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.0.11
privileged: true
ports:
- 1081:80
environment:
@@ -15,12 +16,23 @@ services:
- SECRET_KEY=uQeacXV8b3isvKLK
- DEMO_MODE=false
volumes:
- /data/orion-visor-space/docker-volumes/orion-visor-service/root-orion:/root/orion
- /data/orion-visor-space/docker-volumes/service/root-orion:/root/orion
healthcheck:
test: [ "CMD", "curl", "http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health" ]
interval: 3s
timeout: 300s
retries: 200
start_period: 3s
depends_on:
orion-visor-mysql:
condition: service_healthy
orion-visor-redis:
condition: service_healthy
links:
- orion-visor-mysql
- orion-visor-redis
orion-visor-mysql:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.0.6
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.0.11
privileged: true
ports:
- 3307:3306
@@ -30,19 +42,31 @@ services:
- MYSQL_PASSWORD=Data@123456
- MYSQL_ROOT_PASSWORD=Data@123456
volumes:
- /data/orion-visor-space/docker-volumes/orion-visor-mysql/var-lib-mysql:/var/lib/mysql
- /data/orion-visor-space/docker-volumes/orion-visor-mysql/var-lib-mysql-files:/var/lib/mysql-files
- /data/orion-visor-space/docker-volumes/orion-visor-mysql/etc-mysql:/etc/mysql
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql:/var/lib/mysql
- /data/orion-visor-space/docker-volumes/mysql/var-lib-mysql-files:/var/lib/mysql-files
- /data/orion-visor-space/docker-volumes/mysql/etc-mysql:/etc/mysql
healthcheck:
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306" ]
interval: 3s
timeout: 60s
retries: 10
start_period: 3s
orion-visor-redis:
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.0.6
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.0.11
privileged: true
ports:
- 6380:6379
environment:
- REDIS_PASSWORD=Data@123456
volumes:
- /data/orion-visor-space/docker-volumes/orion-visor-redis/data:/data
- /data/orion-visor-space/docker-volumes/redis/data:/data
command: sh -c "redis-server /usr/local/redis.conf --requirepass $${REDIS_PASSWORD}"
healthcheck:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
interval: 3s
timeout: 60s
retries: 10
start_period: 3s
orion-visor-adminer:
image: adminer
ports:

View File

@@ -1,8 +1,7 @@
#/bin/bash
docker compose down
sh ./pull.sh
# demo 启动
if [ "$1" == "demo" ]; then
sed -i 's/DEMO_MODE=false/DEMO_MODE=true/g' docker-compose.yml
fi
docker compose up -d
docker compose up -d --remove-orphans

7
docker/e2e/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM ghcr.io/linuxsuren/api-testing:v0.0.17
WORKDIR /workspace
COPY . .
RUN chmod 777 *
CMD [ "/workspace/entrypoint.sh" ]

3
docker/e2e/entrypoint.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
set -e
atest run -p testsuite.yaml --report md

49
docker/e2e/testsuite.yaml Normal file
View File

@@ -0,0 +1,49 @@
#!api-testing
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
name: orion-visor
api: |
{{default "http://orion-visor-service:80" (env "SERVER")}}
items:
- name: login
request:
api: /orion-visor/api/infra/auth/login
method: POST
header:
Content-type: application/json
body: |
{"username":"admin","password":"21232f297a57a5a743894a0e4a801fc3"}
expect:
bodyFieldsExpect:
code: 200
- name: userPermission
request:
api: /orion-visor/api/infra/permission/user
header:
Authorization: Bearer {{.login.data.token}}
expect:
bodyFieldsExpect:
code: 200
msg: "success"
- name: menu
request:
api: /orion-visor/api/infra/permission/menu
header:
Authorization: Bearer {{.login.data.token}}
expect:
bodyFieldsExpect:
code: 200
msg: "success"
- name: haveUnRead
request:
api: /orion-visor/api/infra/system-message/has-unread
- name: queryOperatorLog
request:
api: /orion-visor/api/infra/mine/query-operator-log
method: POST
- name: hostList
request:
api: /orion-visor/api/infra/tag/list?type=HOST
- name: queryHost
request:
api: /orion-visor/api/asset/host/query
method: POST

View File

@@ -1,5 +1,5 @@
#/bin/bash
version=2.0.6
version=2.0.11
cp -r ../../sql ./sql
docker build -t orion-visor-mysql:${version} .
rm -rf ./sql

View File

@@ -1,5 +1,5 @@
#/bin/bash
version=2.0.6
version=2.0.11
docker build -t orion-visor-redis:${version} .
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}
docker push registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}

View File

@@ -8,6 +8,7 @@ RUN \
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
apk update && \
apk add tzdata && \
apk add dmidecode && \
apk add openjdk8
# 设置时区
RUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \

View File

@@ -1,5 +1,5 @@
#/bin/bash
version=2.0.6
version=2.0.11
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
mv ../../orion-visor-ui/dist ./dist
docker build -t orion-visor-service:${version} .

View File

@@ -11,10 +11,10 @@
<name>${project.artifactId}</name>
<description>项目所有依赖</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<properties>
<revision>2.0.6</revision>
<revision>2.0.11</revision>
<spring.boot.version>2.7.17</spring.boot.version>
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目公共基准包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,14 +14,17 @@ public interface AppConst extends OrionConst {
/**
* 同 ${orion.version} 迭代时候需要手动更改
*/
String VERSION = "2.0.6";
String VERSION = "2.0.11";
String ORION_VISOR = "orion-visor";
/**
* 同 ${spring.application.name}
*/
String APP_NAME = "orion-visor";
String GITHUB = "https://github.com/lijiahangmax/orion-visor";
String GITHUB = "https://github.com/dromara/orion-visor";
String GITEE = "https://gitee.com/lijiahangmax/orion-visor";
String GITEE = "https://gitee.com/dromara/orion-visor";
String ISSUES = "https://github.com/lijiahangmax/orion-visor/issues";
String ISSUES = "https://github.com/dromara/orion-visor/issues";
}

View File

@@ -13,4 +13,8 @@ public interface CnConst {
String CN_ROLE = "角色";
String CN_UNKNOWN = "未知";
String CN_INTRANET_IP = "内网IP";
}

View File

@@ -17,10 +17,6 @@ public interface Const extends com.orion.lang.constant.Const, FieldConst, CnCons
int MD5_LEN = 32;
String UNKNOWN = "未知";
String INTRANET_IP = "内网IP";
Long ROOT_PARENT_ID = 0L;
Integer DEFAULT_SORT = 10;

View File

@@ -83,8 +83,12 @@ public interface ErrorMessage {
String UNKNOWN_TYPE = "未知类型";
String ERROR_TYPE = "错误的类型";
String FILE_ABSENT = "文件不存在";
String FILE_ABSENT_CLEAR = "文件不存在 (可能已被清理)";
String LOG_ABSENT = "日志不存在";
String TASK_ABSENT = "任务不存在";
@@ -95,6 +99,8 @@ public interface ErrorMessage {
String FILE_READ_ERROR = "文件读取失败";
String FILE_READ_ERROR_CLEAR = "文件读取失败 (可能已被清理)";
String PLEASE_CHECK_HOST_SSH = "请检查主机 {} 是否存在/权限/SSH配置";
String CLIENT_ABORT = "手动中断";

View File

@@ -43,4 +43,6 @@ public interface ExtraFieldConst extends FieldConst {
String LOG_ID = "logId";
String DARK = "dark";
}

View File

@@ -31,6 +31,8 @@ public interface FieldConst {
String INFO = "info";
String EXTRA = "extra";
String REL_ID = "relId";
String BEFORE = "before";
@@ -59,10 +61,24 @@ public interface FieldConst {
String TIME = "time";
String ISSUE = "issue";
String EXPIRE = "expire";
String LOCATION = "location";
String USER_AGENT = "userAgent";
String ERROR_MESSAGE = "errorMessage";
String UUID = "uuid";
String REDIRECT = "redirect";
String SCHEMA = "schema";
String FILTER = "filter";
String LICENSE = "license";
}

View File

@@ -1,13 +1,13 @@
package com.orion.visor.framework.common.constant;
/**
* 路径常量
* 文件常量
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/4/17 10:35
*/
public interface PathConst {
public interface FileConst {
String ERROR_LOG = "error.log";

View File

@@ -0,0 +1,25 @@
package com.orion.visor.framework.common.entity;
import lombok.Data;
/**
* 自动清理配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/24 15:03
*/
@Data
public class AutoClearConfig {
/**
* 是否开启
*/
private Boolean enabled;
/**
* 保留周期 (天)
*/
private Integer keepPeriod;
}

View File

@@ -0,0 +1,45 @@
package com.orion.visor.framework.common.enums;
import com.orion.lang.utils.Strings;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 端点定义
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/21 19:15
*/
@Getter
@AllArgsConstructor
public enum EndpointDefine {
/**
* 上传临时分区
*/
UPLOAD_SWAP("/upload/swap/{}"),
/**
* 批量执行日志
*/
EXEC_LOG("/exec/{}/{}.log"),
;
/**
* 端点
*/
private final String endpoint;
/**
* 格式化
*
* @param params params
* @return path
*/
public String format(Object... params) {
return Strings.format(this.endpoint, params);
}
}

View File

@@ -1,9 +1,8 @@
package com.orion.visor.framework.common.handler.data;
import com.alibaba.fastjson.JSON;
import com.orion.spring.SpringHolder;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.framework.common.handler.data.strategy.GenericsDataStrategy;
/**
* 标准数据定义
@@ -12,45 +11,50 @@ import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
* @version 1.0.0
* @since 2023/12/21 0:07
*/
@SuppressWarnings("unchecked")
public interface GenericsDataDefinition {
/**
* 获取数据模型类型
*
* @return class
*/
Class<? extends GenericsDataModel> getModel();
/**
* 获取数据处理策略
*
* @return class
*/
Class<? extends MapDataStrategy<? extends GenericsDataModel>> getStrategy();
Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> getStrategyClass();
/**
* 获取数据模型策略处理器
*
* @param <Model> Model
* @param <Strategy> Strategy
* @return StrategyBean
* @param <M> Model
* @param <S> Strategy
* @return Strategy Bean
*/
@SuppressWarnings("unchecked")
default <Model extends GenericsDataModel, Strategy extends MapDataStrategy<Model>> Strategy getStrategyBean() {
return (Strategy) SpringHolder.getBean(this.getStrategy());
default <M extends GenericsDataModel, S extends GenericsDataStrategy<M>> S getStrategy() {
return (S) SpringHolder.getBean(this.getStrategyClass());
}
/**
* 反序列化对象
*
* @param json json
* @param <Model> Model
* @param serialModel serialModel
* @param <M> Model
* @return object
*/
@SuppressWarnings("unchecked")
default <Model extends GenericsDataModel> Model parse(String json) {
return (Model) JSON.parseObject(json, this.getModel());
default <M extends GenericsDataModel> M parse(String serialModel) {
return (M) this.getStrategy().parse(serialModel);
}
/**
* 转为视图对象
*
* @param serialModel serialModel
* @param <M> Model
* @return viewModel
*/
default <M extends GenericsDataModel> M toView(String serialModel) {
GenericsDataStrategy<GenericsDataModel> strategy = this.getStrategy();
GenericsDataModel model = strategy.parse(serialModel);
strategy.toView(model);
return (M) model;
}
}

View File

@@ -2,6 +2,8 @@ package com.orion.visor.framework.common.handler.data.model;
import com.alibaba.fastjson.JSON;
import java.util.Map;
/**
* 标准数据模型
*
@@ -20,4 +22,14 @@ public interface GenericsDataModel {
return JSON.toJSONString(this);
}
/**
* 转为 map
*
* @return map
*/
default Map<String, Object> toMap() {
return JSON.parseObject(this.serial());
}
}

View File

@@ -0,0 +1,65 @@
package com.orion.visor.framework.common.handler.data.strategy;
import com.alibaba.fastjson.JSON;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
/**
* 标准数据处理策略 基类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/11 21:44
*/
public abstract class AbstractGenericsDataStrategy<M extends GenericsDataModel> implements GenericsDataStrategy<M> {
protected final Class<M> modelClass;
public AbstractGenericsDataStrategy(Class<M> modelClass) {
this.modelClass = modelClass;
}
/**
* 更新填充
*
* @param beforeModel 修改前的配置
* @param afterModel 修改后的配置
*/
protected void updateFill(M beforeModel, M afterModel) {
}
/**
* 预校验参数
*
* @param model model
*/
protected void preValid(M model) {
}
/**
* 校验参数
*
* @param model model
*/
protected void valid(M model) {
}
@Override
public void doValid(M beforeModel, M afterModel) {
// 预校验参数
this.preValid(afterModel);
// 更新填充
this.updateFill(beforeModel, afterModel);
// 校验参数
this.valid(afterModel);
}
@Override
public M parse(String serialModel) {
return JSON.parseObject(serialModel, modelClass);
}
@Override
public void toView(M model) {
}
}

View File

@@ -9,60 +9,38 @@ import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
* @version 1.0.0
* @since 2023/12/20 22:09
*/
public interface GenericsDataStrategy<Model extends GenericsDataModel, View> {
public interface GenericsDataStrategy<M extends GenericsDataModel> {
/**
* 获取默认值
*
* @return 默认值
*/
Model getDefault();
/**
* 更新填充
*
* @param beforeModel 修改前的配置
* @param afterModel 修改后的配置
*/
void updateFill(Model beforeModel, Model afterModel);
/**
* 预校验参数
*
* @param model model
*/
void preValid(Model model);
/**
* 校验参数
*
* @param model model
*/
void valid(Model model);
M getDefault();
/**
* 执行完整验证链
* <p>
* preValid > updateFill > preValid
* preValid > updateFill > valid
*
* @param beforeModel beforeModel
* @param afterModel afterModel
*/
default void doValidChain(Model beforeModel, Model afterModel) {
// 预校验参数
this.preValid(afterModel);
// 更新填充
this.updateFill(beforeModel, afterModel);
// 校验参数
this.valid(afterModel);
}
void doValid(M beforeModel, M afterModel);
/**
* 解析数据
*
* @param serialModel serialModel
* @return model
*/
M parse(String serialModel);
/**
* 转为视图配置
*
* @param model model
* @return 视图配置
*/
View toView(String model);
void toView(M model);
}

View File

@@ -1,22 +0,0 @@
package com.orion.visor.framework.common.handler.data.strategy;
import com.alibaba.fastjson.JSONObject;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import java.util.Map;
/**
* map 数据处理策略
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/12/20 22:11
*/
public interface MapDataStrategy<Model extends GenericsDataModel> extends GenericsDataStrategy<Model, Map<String, Object>> {
@Override
default Map<String, Object> toView(String model) {
return JSONObject.parseObject(model);
}
}

View File

@@ -2,8 +2,12 @@ package com.orion.visor.framework.common.utils;
import com.orion.ext.location.Region;
import com.orion.ext.location.region.LocationRegions;
import com.orion.lang.constant.StandardHttpHeader;
import com.orion.lang.utils.Strings;
import com.orion.visor.framework.common.constant.Const;
import com.orion.web.servlet.web.Servlets;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@@ -21,6 +25,22 @@ public class IpUtils {
private IpUtils() {
}
/**
* 获取请求地址
*
* @param request request
* @return addr
*/
public static String getRemoteAddr(HttpServletRequest request) {
// 获取实际地址
String realIp = request.getHeader(StandardHttpHeader.X_REAL_IP);
if (!Strings.isBlank(realIp)) {
return realIp;
}
// 获取请求地址
return Servlets.getRemoteAddr(request);
}
/**
* 获取 ip 位置
*
@@ -29,7 +49,7 @@ public class IpUtils {
*/
public static String getLocation(String ip) {
if (ip == null) {
return Const.UNKNOWN;
return Const.CN_UNKNOWN;
}
// 查询缓存
return CACHE.computeIfAbsent(ip, IpUtils::queryLocation);
@@ -43,21 +63,21 @@ public class IpUtils {
*/
private static String queryLocation(String ip) {
if (ip == null) {
return Const.UNKNOWN;
return Const.CN_UNKNOWN;
}
Region region;
try {
region = LocationRegions.getRegion(ip, 3);
} catch (Exception e) {
return Const.UNKNOWN;
return Const.CN_UNKNOWN;
}
if (region != null) {
String net = region.getNet();
String province = region.getProvince();
if (net.equals(Const.INTRANET_IP)) {
if (net.equals(Const.CN_INTRANET_IP)) {
return net;
}
if (province.equals(Const.UNKNOWN)) {
if (province.equals(Const.CN_UNKNOWN)) {
return province;
}
StringBuilder location = new StringBuilder()
@@ -69,7 +89,7 @@ public class IpUtils {
location.append(" (").append(net).append(')');
return location.toString();
}
return Const.UNKNOWN;
return Const.CN_UNKNOWN;
}
}

View File

@@ -0,0 +1,38 @@
package com.orion.visor.framework.common.utils;
import com.orion.lang.utils.Arrays1;
import com.orion.lang.utils.crypto.Caesars;
/**
* 混淆工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/17 18:27
*/
public class Mixes {
private Mixes() {
}
/**
* 混淆
* <p>
* 此方法不可修改
*
* @param str str
* @return str
*/
public static String obfuscate(String str) {
char[] chars = str.toCharArray();
Arrays1.reverse(chars);
for (int i = 0; i < chars.length; i += 2) {
char temp = chars[i];
chars[i] = chars[i + 1];
chars[i + 1] = temp;
}
String res = new String(chars);
return new Caesars().encrypt(res);
}
}

View File

@@ -47,7 +47,7 @@ public class PathUtils {
public static String getAppPath(boolean isWindows, String username) {
return getHomePath(isWindows, username)
+ "/" + AppConst.ORION
+ "/" + AppConst.ORION_VISOR;
+ "/" + AppConst.APP_NAME;
}
/**

View File

@@ -41,7 +41,7 @@ public class Requests {
.map(s -> (ServletRequestAttributes) s)
.map(ServletRequestAttributes::getRequest)
.ifPresent(request -> {
String address = Servlets.getRemoteAddr(request);
String address = IpUtils.getRemoteAddr(request);
identity.setAddress(address);
identity.setLocation(IpUtils.getLocation(address));
identity.setUserAgent(Servlets.getUserAgent(request));

View File

@@ -10,7 +10,7 @@
{
"name": "orion.async.executor.core-pool-size",
"type": "java.lang.Integer",
"description": "核心线程数量",
"description": "核心线程数量.",
"defaultValue": "8"
},
{

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 banner 打印包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -51,7 +51,7 @@ public class BannerApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
AnsiAppender appender = AnsiAppender.create()
.append(AnsiForeground.BRIGHT_GREEN, ":: orion-visor-launch v" + version + " 服务已启动(" + env + ") ::\n");
.append(AnsiForeground.BRIGHT_GREEN, ":: orion-visor v" + version + " 服务已启动(" + env + ") ::\n");
// swagger 地址
if (apiDocsEnabled) {
appender.append(AnsiForeground.BRIGHT_GREEN, ":: swagger 文档 ")

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目操作日志包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目数据源配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目数据脱敏包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目定时任务配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目日志配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -1,6 +1,7 @@
package com.orion.visor.framework.log.configuration.config;
import com.orion.visor.framework.common.utils.ConfigUtils;
import com.orion.visor.framework.log.core.enums.LogPrinterMode;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -17,6 +18,11 @@ import java.util.List;
@ConfigurationProperties("orion.logging.printer")
public class LogPrinterConfig {
/**
* 类型
*/
private LogPrinterMode mode;
/**
* 字段配置
*/
@@ -32,12 +38,31 @@ public class LogPrinterConfig {
*/
private String expression;
public void setField(LogPrinterFieldConfig field) {
this.field = field;
}
public void setHeaders(List<String> headers) {
this.headers = ConfigUtils.parseStringList(headers, String::toLowerCase);
}
@Data
public static class LogPrinterFieldConfig {
/**
* 忽略的字段
*/
private List<String> ignore;
/**
* 脱敏的字段
*/
private List<String> desensitize;
public void setIgnore(List<String> ignore) {
this.ignore = ConfigUtils.parseStringList(ignore);
}
public void setDesensitize(List<String> desensitize) {
this.desensitize = ConfigUtils.parseStringList(desensitize);
}
}
}

View File

@@ -1,36 +0,0 @@
package com.orion.visor.framework.log.configuration.config;
import com.orion.visor.framework.common.utils.ConfigUtils;
import lombok.Data;
import java.util.List;
/**
* 日志打印字段配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/28 22:36
*/
@Data
public class LogPrinterFieldConfig {
/**
* 忽略的字段
*/
private List<String> ignore;
/**
* 脱敏的字段
*/
private List<String> desensitize;
public void setIgnore(List<String> ignore) {
this.ignore = ConfigUtils.parseStringList(ignore);
}
public void setDesensitize(List<String> desensitize) {
this.desensitize = ConfigUtils.parseStringList(desensitize);
}
}

View File

@@ -3,6 +3,7 @@ package com.orion.visor.framework.log.core.interceptor;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.time.Dates;
import com.orion.visor.framework.common.utils.IpUtils;
import com.orion.visor.framework.common.utils.SwaggerUtils;
import com.orion.visor.framework.log.configuration.config.LogPrinterConfig;
import com.orion.web.servlet.web.Servlets;
@@ -60,7 +61,7 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor {
// http
if (request != null) {
// remoteAddr
requestLog.append("\tremoteAddr: ").append(Servlets.getRemoteAddr(request)).append('\n');
requestLog.append("\tremoteAddr: ").append(IpUtils.getRemoteAddr(request)).append('\n');
// header
Servlets.getHeaderMap(request).forEach((hk, hv) -> {
if (headerFilter.test(hk.toLowerCase())) {

View File

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.time.Dates;
import com.orion.visor.framework.common.utils.IpUtils;
import com.orion.visor.framework.common.utils.SwaggerUtils;
import com.orion.visor.framework.log.configuration.config.LogPrinterConfig;
import com.orion.visor.framework.log.core.enums.LogFieldConst;
@@ -61,7 +62,7 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl
// http
if (request != null) {
// remoteAddr
fields.put(REMOTE_ADDR, Servlets.getRemoteAddr(request));
fields.put(REMOTE_ADDR, IpUtils.getRemoteAddr(request));
// header
Map<String, Object> headers = new LinkedHashMap<>();
Servlets.getHeaderMap(request).forEach((hk, hv) -> {

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目监控配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 mybatis 配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -38,13 +38,13 @@ public class CustomFileFilter {
public List<CustomFile> doFilter() {
// 生成文件副本
List<CustomFile> files = originCustomerFile.stream().map(s ->
new CustomFile.Builder()
.enableFileOverride()
.templatePath(s.getTemplatePath())
.filePath(s.getFilePath())
.fileName(s.getFileName())
.packageName(s.getPackageName())
.build())
new CustomFile.Builder()
.enableFileOverride()
.templatePath(s.getTemplatePath())
.filePath(s.getFilePath())
.fileName(s.getFileName())
.packageName(s.getPackageName())
.build())
.collect(Collectors.toList());
// 不生成对外 api 文件
if (!table.isEnableProviderApi()) {

View File

@@ -1,6 +1,6 @@
<template>
<a-modal v-model:visible="visible"
body-class="modal-form-large"
modal-class="modal-form-large"
title-align="start"
:title="title"
:top="80"

View File

@@ -6,7 +6,7 @@ const columns = [
title: 'id',
dataIndex: 'id',
slotName: 'id',
width: 100,
width: 80,
align: 'left',
fixed: 'left',
}, #foreach($field in ${table.fields})#if("$!field.propertyName" != "id"){
@@ -15,6 +15,7 @@ const columns = [
slotName: '${field.propertyName}',
align: 'left',
#if(${field.propertyType} == 'String')
minWidth: 238,
ellipsis: true,
tooltip: true,
#elseif(${field.propertyType} == 'Date')

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 redis 配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 security 配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -2,9 +2,9 @@ package com.orion.visor.framework.security.configuration;
import com.orion.visor.framework.common.constant.AutoConfigureOrderConst;
import com.orion.visor.framework.common.crypto.ValueCrypto;
import com.orion.visor.framework.security.configuration.config.CryptoConfig;
import com.orion.visor.framework.security.configuration.config.AesCryptoConfig;
import com.orion.visor.framework.security.core.crypto.PrimaryValueCrypto;
import com.orion.visor.framework.security.core.crypto.aes.AesCryptoProcessor;
import com.orion.visor.framework.security.core.crypto.processor.AesCryptoProcessor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -12,8 +12,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
/**
* 项目加密解密配置
*
@@ -22,13 +20,10 @@ import javax.annotation.Resource;
* @since 2023/7/7 23:59
*/
@AutoConfiguration
@EnableConfigurationProperties(CryptoConfig.class)
@EnableConfigurationProperties({AesCryptoConfig.class})
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_SECURITY_CRYPTO)
public class OrionCryptoAutoConfiguration {
@Resource
private CryptoConfig config;
/**
* @return 默认加密器
*/
@@ -43,8 +38,8 @@ public class OrionCryptoAutoConfiguration {
*/
@Bean(initMethod = "init")
@ConditionalOnProperty(value = "orion.crypto.aes.enabled", havingValue = "true")
public ValueCrypto aesValueCrypto() {
return new AesCryptoProcessor(config.getAes());
public ValueCrypto aesValueCrypto(AesCryptoConfig config) {
return new AesCryptoProcessor(config);
}
}

View File

@@ -1,4 +1,4 @@
package com.orion.visor.framework.security.core.crypto.aes;
package com.orion.visor.framework.security.configuration.config;
import com.orion.lang.utils.crypto.CryptoConst;
import com.orion.lang.utils.crypto.enums.PaddingMode;
@@ -6,6 +6,7 @@ import com.orion.lang.utils.crypto.enums.WorkingMode;
import com.orion.visor.framework.security.core.crypto.CryptoConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* aes 加密器配置
@@ -16,6 +17,7 @@ import lombok.EqualsAndHashCode;
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties("orion.crypto.aes")
public class AesCryptoConfig extends CryptoConfig {
/**

View File

@@ -1,23 +0,0 @@
package com.orion.visor.framework.security.configuration.config;
import com.orion.visor.framework.security.core.crypto.aes.AesCryptoConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 加密配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/8 0:01
*/
@Data
@ConfigurationProperties("orion.crypto")
public class CryptoConfig {
/**
* aes 加密器配置
*/
private AesCryptoConfig aes;
}

View File

@@ -1,4 +1,4 @@
package com.orion.visor.framework.security.core.crypto.aes;
package com.orion.visor.framework.security.core.crypto.processor;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.crypto.Keys;
@@ -6,6 +6,7 @@ import com.orion.lang.utils.crypto.enums.CipherAlgorithm;
import com.orion.lang.utils.crypto.enums.WorkingMode;
import com.orion.lang.utils.crypto.symmetric.SymmetricBuilder;
import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto;
import com.orion.visor.framework.security.configuration.config.AesCryptoConfig;
import com.orion.visor.framework.security.core.crypto.CryptoProcessor;
import javax.crypto.SecretKey;

View File

@@ -5,15 +5,10 @@
"type": "com.orion.visor.framework.security.configuration.config.SecurityConfig",
"sourceType": "com.orion.visor.framework.security.configuration.config.SecurityConfig"
},
{
"name": "orion.crypto",
"type": "com.orion.visor.framework.security.configuration.config.CryptoConfig",
"sourceType": "com.orion.visor.framework.security.configuration.config.CryptoConfig"
},
{
"name": "orion.crypto.aes",
"type": "com.orion.visor.framework.security.core.crypto.aes.AesCryptoConfig",
"sourceType": "com.orion.visor.framework.security.core.crypto.aes.AesCryptoConfig"
"type": "com.orion.visor.framework.security.configuration.config.AesCryptoConfig",
"sourceType": "com.orion.visor.framework.security.configuration.config.AesCryptoConfig"
}
],
"properties": [

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目存储层配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -2,7 +2,8 @@ package com.orion.visor.framework.storage.configuration;
import com.orion.visor.framework.common.constant.AutoConfigureOrderConst;
import com.orion.visor.framework.common.file.FileClient;
import com.orion.visor.framework.storage.configuration.config.StorageConfig;
import com.orion.visor.framework.storage.configuration.config.LocalStorageConfig;
import com.orion.visor.framework.storage.configuration.config.LogsStorageConfig;
import com.orion.visor.framework.storage.core.client.PrimaryFileClient;
import com.orion.visor.framework.storage.core.client.local.LocalFileClient;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -12,8 +13,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
/**
* 存储配置类
*
@@ -25,12 +24,9 @@ import javax.annotation.Resource;
*/
@AutoConfiguration
@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_STORAGE)
@EnableConfigurationProperties(StorageConfig.class)
@EnableConfigurationProperties({LocalStorageConfig.class, LogsStorageConfig.class})
public class OrionStorageAutoConfiguration {
@Resource
private StorageConfig config;
/**
* @return 默认文件客户端
*/
@@ -45,8 +41,8 @@ public class OrionStorageAutoConfiguration {
*/
@Bean
@ConditionalOnProperty(value = "orion.storage.local.enabled", havingValue = "true")
public FileClient localFileClient() {
return new LocalFileClient(config.getLocal());
public FileClient localFileClient(LocalStorageConfig config) {
return new LocalFileClient(config);
}
/**
@@ -54,8 +50,8 @@ public class OrionStorageAutoConfiguration {
*/
@Bean
@ConditionalOnProperty(value = "orion.storage.logs.enabled", havingValue = "true")
public FileClient logsFileClient() {
return new LocalFileClient(config.getLogs());
public FileClient logsFileClient(LogsStorageConfig config) {
return new LocalFileClient(config);
}
}

View File

@@ -2,27 +2,19 @@ package com.orion.visor.framework.storage.configuration.config;
import com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 存储配置
* 本地存储配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 18:40
*/
@Data
@ConfigurationProperties(prefix = "orion.storage")
public class StorageConfig {
/**
* 本地文件客户端 配置
*/
private LocalFileClientConfig local;
/**
* 日志文件客户端 配置
*/
private LocalFileClientConfig logs;
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "orion.storage.local")
public class LocalStorageConfig extends LocalFileClientConfig {
}

View File

@@ -0,0 +1,20 @@
package com.orion.visor.framework.storage.configuration.config;
import com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 日志存储配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/6/30 18:40
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "orion.storage.logs")
public class LogsStorageConfig extends LocalFileClientConfig {
}

View File

@@ -1,19 +1,14 @@
{
"groups": [
{
"name": "orion.storage",
"type": "com.orion.visor.framework.storage.configuration.config.StorageConfig",
"sourceType": "com.orion.visor.framework.storage.configuration.config.StorageConfig"
},
{
"name": "orion.storage.local",
"type": "com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig",
"sourceType": "com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig"
"type": "com.orion.visor.framework.storage.configuration.config.LocalStorageConfig",
"sourceType": "com.orion.visor.framework.storage.configuration.config.LocalStorageConfig"
},
{
"name": "orion.storage.logs",
"type": "com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig",
"sourceType": "com.orion.visor.framework.storage.core.client.local.LocalFileClientConfig"
"type": "com.orion.visor.framework.storage.configuration.config.LogsStorageConfig",
"sourceType": "com.orion.visor.framework.storage.configuration.config.LogsStorageConfig"
}
],
"properties": [

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 swagger 配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目单元测试包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 web 包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -14,7 +14,7 @@
<packaging>jar</packaging>
<description>项目 websocket 配置包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -10,7 +10,7 @@
{
"name": "orion.websocket.prefix",
"type": "java.lang.String",
"description": "公共 websocket 前缀"
"description": "公共 websocket 前缀."
},
{
"name": "orion.websocket.binary-buffer-size",

View File

@@ -13,7 +13,7 @@
<packaging>pom</packaging>
<description>项目组件包</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<modules>
<module>orion-visor-framework-common</module>

View File

@@ -13,7 +13,7 @@
<packaging>jar</packaging>
<description>后端服务主项目容器 按需引用 orion-visor-module-xxx 依赖</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<!-- spring boot 配置所需依赖 -->

View File

@@ -1,10 +1,17 @@
package com.orion.visor.launch;
import com.orion.lang.utils.Strings;
import com.orion.visor.framework.common.constant.Const;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Optional;
/**
* application 启动类
@@ -26,9 +33,25 @@ public class LaunchApplication {
* 自定义 bean 名称生成器
*/
public static class CustomBeanNameGenerator implements BeanNameGenerator {
private static final String BEAN_ANNOTATION_CLASS_NAME = "org.springframework.stereotype.Component";
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return definition.getBeanClassName();
// 兼容注解自定义名称
if (definition instanceof AnnotatedBeanDefinition) {
AnnotationMetadata metadata = ((AnnotatedBeanDefinition) definition).getMetadata();
// 处理自定义 bean 名称
return Optional.of(metadata)
.map(s -> s.getAnnotationAttributes(BEAN_ANNOTATION_CLASS_NAME))
.map(s -> s.get(Const.VALUE))
.map(Object::toString)
.filter(Strings::isNotBlank)
.orElseGet(definition::getBeanClassName);
} else {
// 非注解形式默认使用默认名称
return BeanDefinitionReaderUtils.generateBeanName(definition, registry);
}
}
}

View File

@@ -3,7 +3,7 @@ server:
spring:
application:
name: orion-visor-launch
name: orion-visor
profiles:
active: dev
main:
@@ -142,7 +142,7 @@ knife4j:
logging:
file:
path: ${user.home}/orion/logs/orion-visor
path: ${user.home}/orion/logs/${spring.application.name}
name: ${logging.file.path}/app.log
logback:
rollingpolicy:
@@ -189,10 +189,16 @@ app:
exec-log:
# 是否拼接 ansi 执行状态日志
append-ansi: true
# 自动清理执行文件
auto-clear: true
# 保留周期 (天)
keep-period: 30
# 自动清理配置
auto-clear:
# 批量执行日志
exec-log:
enabled: false
keep-period: 30
# 主机连接日志
host-connect-log:
enabled: false
keep-period: 30
# orion framework config
orion:
@@ -220,10 +226,10 @@ orion:
title: orion-visor 运维平台
description: 一站式运维服务平台
version: ${orion.version}
url: https://github.com/lijiahangmax/orion-visor
url: https://github.com/dromara/orion-visor
email: ljh1553488six@139.com
license: Apache-2.0
license-url: https://github.com/lijiahangmax/orion-visor/blob/main/LICENSE
license-url: https://github.com/dromara/orion-visor/blob/main/LICENSE
grouped-api:
infra:
group: "infra - 基建模块"
@@ -253,14 +259,14 @@ orion:
timestamp-prefix: false
date-directory: false
storage-path: ${user.home}
base-path: /orion/orion-visor/storage
base-path: /orion/${spring.application.name}/storage
# 日志文件存储
logs:
enabled: true
timestamp-prefix: false
date-directory: false
storage-path: ${user.home}
base-path: /orion/orion-visor/logs
base-path: /orion/${spring.application.name}/logs
security:
password-encoder-length: 4
# 匿名接口

View File

@@ -13,7 +13,7 @@
<packaging>jar</packaging>
<description>项目资产模块</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -13,7 +13,7 @@
<packaging>jar</packaging>
<description>项目资产模块</description>
<url>https://github.com/lijiahangmax/orion-visor</url>
<url>https://github.com/dromara/orion-visor</url>
<dependencies>
<dependency>

View File

@@ -1,9 +1,9 @@
package com.orion.visor.module.asset.controller;
import com.alibaba.fastjson.JSONArray;
import com.orion.visor.framework.log.core.annotation.IgnoreLog;
import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
import com.orion.visor.framework.web.core.annotation.RestWrapper;
import com.orion.visor.module.asset.entity.vo.HostTerminalThemeVO;
import com.orion.visor.module.asset.service.HostTerminalService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 主机终端 api
@@ -38,7 +39,7 @@ public class HostTerminalController {
@IgnoreLog(IgnoreLogMode.ALL)
@GetMapping("/themes")
@Operation(summary = "获取主机终端主题")
public JSONArray getTerminalThemes() {
public List<HostTerminalThemeVO> getTerminalThemes() {
return hostTerminalService.getTerminalThemes();
}

View File

@@ -0,0 +1,22 @@
package com.orion.visor.module.asset.define.config;
import com.orion.visor.framework.common.entity.AutoClearConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 批量执行日志自动清理配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/24 15:01
*/
@Data
@Component
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "app.auto-clear.exec-log")
public class AppExecLogAutoClearConfig extends AutoClearConfig {
}

View File

@@ -21,20 +21,8 @@ public class AppExecLogConfig {
*/
private Boolean appendAnsi;
/**
* 自动清理执行文件
*/
private Boolean autoClear;
/**
* 保留周期 (天)
*/
private Integer keepPeriod;
public AppExecLogConfig() {
this.appendAnsi = true;
this.autoClear = true;
this.keepPeriod = 30;
}
}

View File

@@ -0,0 +1,22 @@
package com.orion.visor.module.asset.define.config;
import com.orion.visor.framework.common.entity.AutoClearConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 主机连接日志自动清理配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/24 15:01
*/
@Data
@Component
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "app.auto-clear.host-connect-log")
public class AppHostConnectLogAutoClearConfig extends AutoClearConfig {
}

View File

@@ -20,16 +20,13 @@ import lombok.NoArgsConstructor;
@Schema(name = "ExecParameterSchemaDTO", description = "命令执行参数 schema 对象")
public class ExecParameterSchemaDTO {
@Schema(description = "参数名")
@Schema(description = "参数名")
private String name;
@Schema(description = "参数描述")
private String desc;
@Schema(description = "默认")
private Object defaultValue;
@Schema(description = "")
@Schema(description = "参数")
private Object value;
}

View File

@@ -7,6 +7,7 @@ import lombok.*;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 批量执行日志 查询请求对象
@@ -54,4 +55,11 @@ public class ExecLogQueryRequest extends PageRequest {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date[] startTimeRange;
@Schema(description = "创建时间 <=")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeLe;
@Schema(description = "状态")
private List<String> statusList;
}

View File

@@ -56,4 +56,11 @@ public class HostConnectLogQueryRequest extends PageRequest {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date[] startTimeRange;
@Schema(description = "创建时间 <=")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeLe;
@Schema(description = "状态")
private List<String> statusList;
}

View File

@@ -0,0 +1,33 @@
package com.orion.visor.module.asset.entity.vo;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 主机终端主题 视图响应对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/4 19:27
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostTerminalThemeVO", description = "主机终端主题 视图响应对象")
public class HostTerminalThemeVO {
@Schema(description = "主题名称")
private String name;
@Schema(description = "是否为暗色")
private Boolean dark;
@Schema(description = "主题 schema")
private JSONObject schema;
}

View File

@@ -1,8 +1,11 @@
package com.orion.visor.module.asset.enums;
import com.orion.lang.utils.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
/**
* 批量执行状态
*
@@ -36,6 +39,8 @@ public enum ExecStatusEnum {
;
public static final List<String> FINISH_STATUS_LIST = Lists.of(COMPLETED.name(), FAILED.name());
private final boolean closeable;
public static ExecStatusEnum of(String status) {

View File

@@ -3,8 +3,7 @@ package com.orion.visor.module.asset.enums;
import com.orion.visor.framework.common.enums.EnableStatus;
import com.orion.visor.framework.common.handler.data.GenericsDataDefinition;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.module.asset.handler.host.config.model.HostSshConfigModel;
import com.orion.visor.framework.common.handler.data.strategy.GenericsDataStrategy;
import com.orion.visor.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -24,7 +23,6 @@ public enum HostConfigTypeEnum implements GenericsDataDefinition {
* SSH 配置
*/
SSH("ssh",
HostSshConfigModel.class,
HostSshConfigStrategy.class,
EnableStatus.ENABLED.getValue()),
@@ -32,9 +30,7 @@ public enum HostConfigTypeEnum implements GenericsDataDefinition {
private final String type;
private final Class<? extends GenericsDataModel> model;
private final Class<? extends MapDataStrategy<? extends GenericsDataModel>> strategy;
private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass;
private final Integer defaultStatus;

View File

@@ -1,5 +1,9 @@
package com.orion.visor.module.asset.enums;
import com.orion.lang.utils.collect.Lists;
import java.util.List;
/**
* 主机连接状态
*
@@ -31,6 +35,8 @@ public enum HostConnectStatusEnum {
;
public static final List<String> FINISH_STATUS_LIST = Lists.of(COMPLETE.name(), FAILED.name(), FORCE_OFFLINE.name());
public static HostConnectStatusEnum of(String type) {
if (type == null) {
return null;

View File

@@ -2,9 +2,7 @@ package com.orion.visor.module.asset.enums;
import com.orion.visor.framework.common.handler.data.GenericsDataDefinition;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.module.asset.handler.host.extra.model.HostLabelExtraModel;
import com.orion.visor.module.asset.handler.host.extra.model.HostSshExtraModel;
import com.orion.visor.framework.common.handler.data.strategy.GenericsDataStrategy;
import com.orion.visor.module.asset.handler.host.extra.strategy.HostLabelExtraStrategy;
import com.orion.visor.module.asset.handler.host.extra.strategy.HostSshExtraStrategy;
import lombok.AllArgsConstructor;
@@ -24,20 +22,18 @@ public enum HostExtraItemEnum implements GenericsDataDefinition {
/**
* SSH 额外配置
*/
SSH("ssh", HostSshExtraModel.class, HostSshExtraStrategy.class),
SSH("ssh", HostSshExtraStrategy.class),
/**
* 标签额外配置
*/
LABEL("label", HostLabelExtraModel.class, HostLabelExtraStrategy.class),
LABEL("label", HostLabelExtraStrategy.class),
;
private final String item;
private final Class<? extends GenericsDataModel> model;
private final Class<? extends MapDataStrategy<? extends GenericsDataModel>> strategy;
private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass;
public static HostExtraItemEnum of(String type) {
if (type == null) {

View File

@@ -1,13 +1,12 @@
package com.orion.visor.module.asset.handler.host.config.strategy;
import com.alibaba.fastjson.JSON;
import com.orion.lang.utils.Booleans;
import com.orion.lang.utils.Charsets;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.framework.common.handler.data.strategy.AbstractGenericsDataStrategy;
import com.orion.visor.framework.common.security.PasswordModifier;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.module.asset.dao.HostIdentityDAO;
@@ -18,7 +17,6 @@ import com.orion.visor.module.asset.handler.host.config.model.HostSshConfigModel
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
/**
* 主机 SSH 配置策略
@@ -28,7 +26,7 @@ import java.util.Map;
* @since 2023/9/19 14:26
*/
@Component
public class HostSshConfigStrategy implements MapDataStrategy<HostSshConfigModel> {
public class HostSshConfigStrategy extends AbstractGenericsDataStrategy<HostSshConfigModel> {
@Resource
private HostKeyDAO hostKeyDAO;
@@ -40,6 +38,10 @@ public class HostSshConfigStrategy implements MapDataStrategy<HostSshConfigModel
private static final String USERNAME = "root";
public HostSshConfigStrategy() {
super(HostSshConfigModel.class);
}
@Override
public HostSshConfigModel getDefault() {
return HostSshConfigModel.builder()
@@ -55,7 +57,7 @@ public class HostSshConfigStrategy implements MapDataStrategy<HostSshConfigModel
}
@Override
public void preValid(HostSshConfigModel model) {
protected void preValid(HostSshConfigModel model) {
// 验证认证类型
Valid.valid(HostSshAuthTypeEnum::of, model.getAuthType());
// 验证系统版本
@@ -77,13 +79,13 @@ public class HostSshConfigStrategy implements MapDataStrategy<HostSshConfigModel
}
@Override
public void valid(HostSshConfigModel model) {
protected void valid(HostSshConfigModel model) {
// 验证填充后的参数
Valid.valid(model);
}
@Override
public void updateFill(HostSshConfigModel beforeModel, HostSshConfigModel afterModel) {
protected void updateFill(HostSshConfigModel beforeModel, HostSshConfigModel afterModel) {
// 加密密码
this.checkEncryptPassword(beforeModel, afterModel);
afterModel.setHasPassword(null);
@@ -91,14 +93,12 @@ public class HostSshConfigStrategy implements MapDataStrategy<HostSshConfigModel
}
@Override
public Map<String, Object> toView(String config) {
if (config == null) {
return null;
public void toView(HostSshConfigModel model) {
if (model == null) {
return;
}
HostSshConfigModel model = JSON.parseObject(config, HostSshConfigModel.class);
model.setHasPassword(Strings.isNotBlank(model.getPassword()));
model.setPassword(null);
return JSON.parseObject(JSON.toJSONString(model));
}
/**

View File

@@ -31,7 +31,7 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
// 拼接启动日志
AnsiAppender appender = AnsiAppender.create()
.append(AnsiForeground.BRIGHT_GREEN, "> 准备执行命令 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine()
.append(AnsiForeground.BRIGHT_BLUE, "执行记录: ")
.append(execCommand.getLogId())
@@ -81,7 +81,7 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
// 非脚本执行拼接开始执行日志
if (!Booleans.isTrue(execCommand.getScriptExec())) {
appender.append(AnsiForeground.BRIGHT_GREEN, "> 开始执行命令 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine();
}
this.appendLog(appender);
@@ -94,7 +94,7 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
AnsiAppender startAppender = AnsiAppender.create()
.newLine()
.append(AnsiForeground.BRIGHT_GREEN, "> 准备上传脚本 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine()
.append(AnsiForeground.BRIGHT_BLUE, "文件路径: ")
.append(execHostCommand.getScriptPath())
@@ -105,18 +105,18 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
// 拼接完成日志
AnsiAppender finishAppender = AnsiAppender.create()
.append(AnsiForeground.BRIGHT_GREEN, "< 脚本上传成功 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine()
.newLine()
.append(AnsiForeground.BRIGHT_GREEN, "> 开始执行脚本 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine();
this.appendLog(finishAppender);
} catch (Exception e) {
// 拼接失败日志
AnsiAppender errorAppender = AnsiAppender.create()
.append(AnsiForeground.BRIGHT_RED, "< 脚本上传失败 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine();
this.appendLog(errorAppender);
throw e;
@@ -133,12 +133,12 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
if (this.status == ExecHostStatusEnum.INTERRUPTED) {
// 中断执行
appender.append(AnsiForeground.BRIGHT_YELLOW, "< 命令执行中断 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine();
} else if (this.status == ExecHostStatusEnum.FAILED) {
// 执行失败
appender.append(AnsiForeground.BRIGHT_RED, "< 命令执行失败 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine()
.append(AnsiForeground.BRIGHT_RED, "错误原因: ")
.append(this.getErrorMessage(e))
@@ -146,14 +146,14 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
} else if (this.status == ExecHostStatusEnum.TIMEOUT) {
// 更新执行超时
appender.append(AnsiForeground.BRIGHT_YELLOW, "< 命令执行超时 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine();
} else {
long ms = updateRecord.getFinishTime().getTime() - updateRecord.getStartTime().getTime();
Integer exitCode = updateRecord.getExitCode();
// 执行完成
appender.append(AnsiForeground.BRIGHT_GREEN, "< 命令执行完成 ")
.append(Dates.current())
.append(this.getCurrentTime())
.newLine()
.append(AnsiForeground.BRIGHT_BLUE, "exit: ");
if (ExitCode.isSuccess(exitCode)) {
@@ -173,4 +173,13 @@ public class ExecCommandAnsiHandler extends BaseExecCommandHandler {
this.appendLog(appender);
}
/**
* 获取当前时间
*
* @return 当前时间
*/
private String getCurrentTime() {
return Const.SPACE + Dates.current();
}
}

View File

@@ -1,7 +1,7 @@
package com.orion.visor.module.asset.handler.host.extra.strategy;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.framework.common.handler.data.strategy.AbstractGenericsDataStrategy;
import com.orion.visor.module.asset.handler.host.extra.model.HostLabelExtraModel;
import org.springframework.stereotype.Component;
@@ -13,7 +13,11 @@ import org.springframework.stereotype.Component;
* @since 2024/2/29 23:16
*/
@Component
public class HostLabelExtraStrategy implements MapDataStrategy<HostLabelExtraModel> {
public class HostLabelExtraStrategy extends AbstractGenericsDataStrategy<HostLabelExtraModel> {
public HostLabelExtraStrategy() {
super(HostLabelExtraModel.class);
}
@Override
public HostLabelExtraModel getDefault() {
@@ -36,12 +40,4 @@ public class HostLabelExtraStrategy implements MapDataStrategy<HostLabelExtraMod
}
}
@Override
public void preValid(HostLabelExtraModel model) {
}
@Override
public void valid(HostLabelExtraModel model) {
}
}

View File

@@ -1,7 +1,7 @@
package com.orion.visor.module.asset.handler.host.extra.strategy;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.handler.data.strategy.MapDataStrategy;
import com.orion.visor.framework.common.handler.data.strategy.AbstractGenericsDataStrategy;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.security.core.utils.SecurityUtils;
import com.orion.visor.module.asset.dao.HostIdentityDAO;
@@ -22,7 +22,7 @@ import javax.annotation.Resource;
* @since 2023/12/20 22:17
*/
@Component
public class HostSshExtraStrategy implements MapDataStrategy<HostSshExtraModel> {
public class HostSshExtraStrategy extends AbstractGenericsDataStrategy<HostSshExtraModel> {
@Resource
private HostKeyDAO hostKeyDAO;
@@ -33,6 +33,10 @@ public class HostSshExtraStrategy implements MapDataStrategy<HostSshExtraModel>
@Resource
private DataPermissionApi dataPermissionApi;
public HostSshExtraStrategy() {
super(HostSshExtraModel.class);
}
@Override
public HostSshExtraModel getDefault() {
return HostSshExtraModel.builder()
@@ -40,10 +44,6 @@ public class HostSshExtraStrategy implements MapDataStrategy<HostSshExtraModel>
.build();
}
@Override
public void updateFill(HostSshExtraModel beforeModel, HostSshExtraModel afterModel) {
}
@Override
public void preValid(HostSshExtraModel model) {
HostExtraSshAuthTypeEnum authType = Valid.valid(HostExtraSshAuthTypeEnum::of, model.getAuthType());
@@ -79,8 +79,4 @@ public class HostSshExtraStrategy implements MapDataStrategy<HostSshExtraModel>
}
}
@Override
public void valid(HostSshExtraModel model) {
}
}

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