feat: ASW-109 pcap页面增加跳转到opensearch dashboard按钮
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -186,6 +186,11 @@
|
||||
<version>7.0.0.202409031743-r</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.geedge.asw.common.config;
|
||||
|
||||
import net.geedge.asw.common.util.T;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
public class FreeMarkerConfig {
|
||||
|
||||
@Value("${asw.template.path:static}")
|
||||
private String templatePath;
|
||||
|
||||
@Bean
|
||||
public FreeMarkerConfigurationFactoryBean factoryBean() {
|
||||
FreeMarkerConfigurationFactoryBean freeMarkerConfigurationFactoryBean = new FreeMarkerConfigurationFactoryBean();
|
||||
// 设置 FreeMarker 模板位置
|
||||
boolean exist = T.FileUtil.exist(templatePath);
|
||||
templatePath = exist ? templatePath : "classpath:" + templatePath;
|
||||
freeMarkerConfigurationFactoryBean.setTemplateLoaderPath(templatePath);
|
||||
|
||||
// 其他配置
|
||||
Properties settings = new Properties();
|
||||
settings.setProperty("default_encoding", "utf-8");
|
||||
settings.setProperty("number_format", "0.##");
|
||||
|
||||
freeMarkerConfigurationFactoryBean.setFreemarkerSettings(settings);
|
||||
return freeMarkerConfigurationFactoryBean;
|
||||
}
|
||||
}
|
||||
28
src/main/java/net/geedge/asw/common/util/TemplateUtil.java
Normal file
28
src/main/java/net/geedge/asw/common/util/TemplateUtil.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package net.geedge.asw.common.util;
|
||||
|
||||
import freemarker.cache.StringTemplateLoader;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TemplateUtil {
|
||||
|
||||
public static Template stringToTemplate(String templateStr,String templateKey) throws IOException {
|
||||
|
||||
// 创建配置类
|
||||
Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
|
||||
//创建模板加载器
|
||||
StringTemplateLoader templateLoader = new StringTemplateLoader();
|
||||
// 存入模板
|
||||
templateLoader.putTemplate(templateKey, templateStr); //template = 虚拟名称, 用来当作获取静态文件的key
|
||||
//加载模板加载器
|
||||
configuration.setTemplateLoader(templateLoader);
|
||||
//得到模板
|
||||
Template template = configuration.getTemplate(templateKey, "utf-8");
|
||||
|
||||
return template;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,4 +85,15 @@ public class FeignClientConfiguration {
|
||||
.target(PcapCommentClient.class, url);
|
||||
}
|
||||
|
||||
@Bean("dashboardClient")
|
||||
public DashboardClient dashboardClient() {
|
||||
String url = UrlBuilder.ofHttp(kibanaUrl).toString();
|
||||
log.info("[kibanaClient] [url: {}]", url);
|
||||
return Feign.builder()
|
||||
.encoder(new FormEncoder())
|
||||
.decoder(new Fastjson2Decoder())
|
||||
.client(new Http2Client())
|
||||
.target(DashboardClient.class, url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.geedge.asw.module.feign.client;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import feign.Headers;
|
||||
import feign.Param;
|
||||
import feign.RequestLine;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@FeignClient(name = "dashboardClient")
|
||||
@Headers("Authorization: Bearer {token}")
|
||||
public interface DashboardClient {
|
||||
|
||||
@Headers({
|
||||
"Content-Type: multipart/form-data",
|
||||
"osd-xsrf: true",
|
||||
"kbn-xsrf: true"
|
||||
})
|
||||
@RequestLine("POST /api/saved_objects/_import?createNewCopies={createNewCopies}")
|
||||
JSONObject importDashboard(@Param("token") String token, @Param("file") File file, @Param("createNewCopies") boolean createNewCopies);
|
||||
}
|
||||
@@ -10,8 +10,8 @@ import org.springframework.cloud.openfeign.FeignClient;
|
||||
@Headers("Authorization: Bearer {token}")
|
||||
public interface KibanaClient {
|
||||
|
||||
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type=index-pattern&search_fields=title&search={name}")
|
||||
JSONObject findIndexPattern(@Param("token") String token, @Param("name") String name);
|
||||
@RequestLine("GET /api/saved_objects/_find?fields=title&per_page=10000&type={type}&search_fields=title&search={name}")
|
||||
JSONObject findIndexPattern(@Param("token") String token, @Param("type") String type , @Param("name") String name);
|
||||
|
||||
@Headers({
|
||||
"Content-Type: application/json",
|
||||
@@ -20,4 +20,11 @@ public interface KibanaClient {
|
||||
@RequestLine("POST /api/saved_objects/index-pattern/{id}")
|
||||
JSONObject saveIndexPattern(@Param("token") String token, @Param("id") String id, JSONObject body);
|
||||
|
||||
@Headers({
|
||||
"Content-Type: application/json",
|
||||
"osd-xsrf: true"
|
||||
})
|
||||
@RequestLine("DELETE /api/saved_objects/index-pattern/{id}?force={force}")
|
||||
JSONObject deleteIndexPattern(@Param("token") String token, @Param("id") String id , @Param("force") boolean force);
|
||||
|
||||
}
|
||||
@@ -193,4 +193,10 @@ public class PcapController {
|
||||
String discoverUrl = pcapService.generateKibanaDiscoverUrl(workspaceId, pcapIds, protocol, streamId);
|
||||
return R.ok().putData("url", discoverUrl);
|
||||
}
|
||||
|
||||
@GetMapping("/dashboard")
|
||||
public R dashboard(@RequestParam String workspaceId, @RequestParam String pcapIds) {
|
||||
String dashboardUrl = pcapService.generateKibanaDashboardUrl(workspaceId, pcapIds);
|
||||
return R.ok().putData("url", dashboardUrl);
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,6 @@ public interface IPcapService extends IService<PcapEntity>{
|
||||
void unparse2session(String[] ids);
|
||||
|
||||
String generateKibanaDiscoverUrl(String workspaceId, String pcapIds, String protocol, String streamId);
|
||||
|
||||
String generateKibanaDashboardUrl(String workspaceId, String pcapIds);
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||
String token = tokenInfo.getTokenValue();
|
||||
|
||||
JSONObject index = kibanaClient.findIndexPattern(token, indexName);
|
||||
JSONObject index = kibanaClient.findIndexPattern(token, "index-pattern" ,indexName);
|
||||
JSONArray savedObjects = index.getJSONArray("saved_objects");
|
||||
|
||||
// check if index exists
|
||||
@@ -371,6 +371,48 @@ public class PcapServiceImpl extends ServiceImpl<PcapDao, PcapEntity> implements
|
||||
return kibanaDiscoverUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateKibanaDashboardUrl(String workspaceId, String pcapIds) {
|
||||
|
||||
WorkspaceEntity workspace = workspaceService.getById(workspaceId);
|
||||
T.VerifyUtil.is(workspace).notNull(RCode.SYS_RECORD_NOT_FOUND);
|
||||
|
||||
List<String> pcapIdList = T.StrUtil.split(pcapIds, ",").stream().filter(s -> T.StrUtil.isNotEmpty(s)).collect(Collectors.toList());
|
||||
List<PcapEntity> pcapList = this.list(new LambdaQueryWrapper<PcapEntity>().in(PcapEntity::getId, pcapIdList));
|
||||
T.VerifyUtil.is(pcapList).notEmpty(RCode.SYS_RECORD_NOT_FOUND);
|
||||
|
||||
SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
|
||||
String token = tokenInfo.getTokenValue();
|
||||
|
||||
String dashboardId = T.JSONUtil.parseObj(workspace.getProperties()).getStr("dashboardId");
|
||||
String dashboardName = String.format("workspace-%s", workspace.getName());
|
||||
|
||||
// build url
|
||||
String baseUrl = UrlBuilder.ofHttp(kibanaUrl)
|
||||
.addPath(T.StrUtil.concat(true, "/app/dashboards"))
|
||||
.addQuery("jwt", token)
|
||||
.toString();
|
||||
|
||||
String param1 = "_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-15m,to:now))";
|
||||
String filter = pcapList.stream()
|
||||
.map(PcapEntity::getName)
|
||||
.map(pcapName -> "\"" + pcapName + "\"")
|
||||
.collect(Collectors.joining(" or ", "pcap.name:(", ")"));
|
||||
String param2 = String.format("_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),query:(language:kuery,query:'%s'),timeRestore:!f,title:%s,viewMode:view)", filter, dashboardName);
|
||||
String param3 = T.StrUtil.concat(true, "#/view/", dashboardId);
|
||||
|
||||
// 处理 空格 &
|
||||
param2 = URLEncodeUtil.encode(param2);
|
||||
param2 = param2.replaceAll("&", "%26");
|
||||
|
||||
String query = String.format("%s?%s&%s", param3, param1, param2);
|
||||
String kibanaDashboardUrl = baseUrl + query;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("[generateKibanaDashboardUrl] [url: {}]", kibanaDashboardUrl);
|
||||
}
|
||||
return kibanaDashboardUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate Parse Thread Timeout
|
||||
*
|
||||
|
||||
@@ -20,6 +20,7 @@ public class WorkspaceEntity {
|
||||
private String tags;
|
||||
private String visibility;
|
||||
private String description;
|
||||
private String properties;
|
||||
|
||||
private Long createTimestamp;
|
||||
private Long updateTimestamp;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package net.geedge.asw.module.workspace.service.impl;
|
||||
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.extra.template.Template;
|
||||
import cn.hutool.log.Log;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@@ -8,6 +13,9 @@ import net.geedge.asw.common.util.ASWException;
|
||||
import net.geedge.asw.common.util.Constants;
|
||||
import net.geedge.asw.common.util.RCode;
|
||||
import net.geedge.asw.common.util.T;
|
||||
import net.geedge.asw.module.feign.client.DashboardClient;
|
||||
import net.geedge.asw.module.feign.client.KibanaClient;
|
||||
import net.geedge.asw.module.sys.service.ISysConfigService;
|
||||
import net.geedge.asw.module.workspace.dao.WorkspaceDao;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceEntity;
|
||||
import net.geedge.asw.module.workspace.entity.WorkspaceMemberEntity;
|
||||
@@ -17,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -24,12 +33,23 @@ import java.util.Map;
|
||||
@Service
|
||||
public class WorkspaceServiceImpl extends ServiceImpl<WorkspaceDao, WorkspaceEntity> implements IWorkspaceService {
|
||||
|
||||
private static final Log log = Log.get();
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceService workspaceService;
|
||||
|
||||
@Autowired
|
||||
private IWorkspaceMemberService workspaceMemberService;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private DashboardClient dashboardClient;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private KibanaClient kibanaClient;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService sysConfigService;
|
||||
|
||||
@Override
|
||||
public Page queryList(Map<String, Object> params) {
|
||||
Page page = T.PageUtil.getPage(params);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<result property="name" column="name"/>
|
||||
<result property="tags" column="tags"/>
|
||||
<result property="visibility" column="visibility"/>
|
||||
<result property="properties" column="properties"/>
|
||||
<result property="description" column="description"/>
|
||||
<result property="createTimestamp" column="create_timestamp"/>
|
||||
<result property="updateTimestamp" column="update_timestamp"/>
|
||||
|
||||
7
src/main/resources/db/migration/R__AZ_sys_config.sql
Normal file
7
src/main/resources/db/migration/R__AZ_sys_config.sql
Normal file
File diff suppressed because one or more lines are too long
@@ -448,6 +448,7 @@ CREATE TABLE `workspace` (
|
||||
`name` varchar(256) NOT NULL DEFAULT '' COMMENT '名称',
|
||||
`tags` varchar(256) NOT NULL DEFAULT '' COMMENT '标签,多个逗号分隔',
|
||||
`visibility` varchar(16) NOT NULL DEFAULT 'private' COMMENT '可见程度,可选值:private,public 默认:private',
|
||||
`properties` varchar(256) NOT NULL DEFAULT '' COMMENT '属性',
|
||||
`description` text NOT NULL DEFAULT '' COMMENT '描述信息',
|
||||
`create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳',
|
||||
`update_timestamp` bigint(20) NOT NULL COMMENT '更新时间戳',
|
||||
|
||||
Reference in New Issue
Block a user