首页消息
This commit is contained in:
@@ -56,6 +56,13 @@
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 配置属性元数据支持 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.honeycombis</groupId>
|
||||
<artifactId>honeycom-flow-task-api</artifactId>
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.honeycombis.honeycom.spdm;
|
||||
import com.honeycombis.honeycom.common.feign.annotation.EnableHoneycomFeignClients;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@@ -18,6 +19,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
@EnableConfigurationProperties
|
||||
public class HoneycomSpdmApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HoneycomSpdmApplication.class, args);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.honeycombis.honeycom.spdm.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "proxy")
|
||||
@Component
|
||||
public class RouteConfig {
|
||||
|
||||
@Data
|
||||
public static class Route {
|
||||
private String baseUrl;
|
||||
private String prefix;
|
||||
private String targetPrefix = "";
|
||||
private int timeout;
|
||||
private boolean enabled;
|
||||
private List<String> allowedMethods = Arrays.asList("GET", "POST", "PUT", "DELETE");
|
||||
private boolean forwardHeaders = true;
|
||||
private List<String> excludeHeaders = Arrays.asList("host", "content-length");
|
||||
}
|
||||
|
||||
private Map<String, Route> routes = new HashMap<>();
|
||||
|
||||
public Optional<Route> findRouteByPath(String path) {
|
||||
return routes.entrySet().stream()
|
||||
.filter(entry -> path.startsWith(entry.getValue().getPrefix()))
|
||||
.map(Map.Entry::getValue)
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.honeycombis.honeycom.spdm.controller;
|
||||
|
||||
import com.honeycombis.honeycom.spdm.config.RouteConfig;
|
||||
import com.honeycombis.honeycom.spdm.service.ProxyService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class ProxyController {
|
||||
|
||||
@Autowired
|
||||
private ProxyService proxyService;
|
||||
|
||||
@Autowired
|
||||
private RouteConfig routeConfig;
|
||||
|
||||
/**
|
||||
* 统一的代理入口
|
||||
* 匹配所有以/api开头的请求
|
||||
*/
|
||||
@RequestMapping("/api/**")
|
||||
public ResponseEntity<byte[]> proxy(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
// 1. 查找匹配的路由配置
|
||||
String requestPath = request.getRequestURI();
|
||||
Optional<RouteConfig.Route> routeOpt = routeConfig.findRouteByPath(requestPath);
|
||||
|
||||
if (!routeOpt.isPresent()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
RouteConfig.Route route = routeOpt.get();
|
||||
|
||||
// 2. 检查路由是否启用
|
||||
if (!route.isEnabled()) {
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
|
||||
.body("该路由暂不可用".getBytes());
|
||||
}
|
||||
|
||||
// 3. 检查HTTP方法是否允许
|
||||
if (!route.getAllowedMethods().contains(request.getMethod())) {
|
||||
return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED)
|
||||
.body("不支持该HTTP方法".getBytes());
|
||||
}
|
||||
|
||||
// 4. 执行转发
|
||||
ResponseEntity<byte[]> proxyResponse = proxyService.forward(request, route);
|
||||
|
||||
// 5. 复制响应头到原始响应(可选)
|
||||
copyHeadersToResponse(proxyResponse, response);
|
||||
|
||||
return proxyResponse;
|
||||
}
|
||||
|
||||
private void copyHeadersToResponse(ResponseEntity<?> source,
|
||||
HttpServletResponse target) {
|
||||
source.getHeaders().forEach((key, values) -> {
|
||||
if (!key.toLowerCase().equals("transfer-encoding")) { // 排除分块传输编码
|
||||
values.forEach(value -> target.addHeader(key, value));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,18 +19,32 @@
|
||||
|
||||
package com.honeycombis.honeycom.spdm.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.honeycombis.honeycom.common.core.util.R;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageListItemUpdateDto;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageListUserQueryDto;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageOpenApiDTO;
|
||||
import com.honeycombis.honeycom.msg.api.entity.MessageListItemEntity;
|
||||
import com.honeycombis.honeycom.msg.api.vo.MessageListItemDetailVo;
|
||||
import com.honeycombis.honeycom.spdm.dto.*;
|
||||
import com.honeycombis.honeycom.spdm.feign.RemoteMsgServiceFeign;
|
||||
import com.honeycombis.honeycom.spdm.util.PageResult;
|
||||
import com.honeycombis.honeycom.spdm.util.ResponseR;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
@@ -43,6 +57,9 @@ public class SpdmMsgController {
|
||||
@Resource
|
||||
private RemoteMsgServiceFeign remoteMsgServiceFeign;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Operation(summary = "发送消息通知")
|
||||
@PostMapping(value = "/sendMessage")
|
||||
public ResponseR sendMessage(@RequestBody MessageDto messageDto) {
|
||||
@@ -55,4 +72,20 @@ public class SpdmMsgController {
|
||||
return ResponseR.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取消息记录")
|
||||
@GetMapping(value = "/getUserMsgPageList")
|
||||
public ResponseR getUserMsgPageList(@ParameterObject MessageListUserQueryDto query, @RequestHeader String userId, @RequestHeader String tenantId) {
|
||||
query.setUserId(Long.valueOf(userId));
|
||||
R<Page<MessageListItemDetailVo>> iPageR = remoteMsgServiceFeign.getUserMsgPageList(query, tenantId);
|
||||
Page<MessageListItemDetailVo> pageList = iPageR.getData();
|
||||
return ResponseR.ok(PageResult.of(pageList.getTotal(), pageList.getCurrent(), pageList.getSize(), pageList.getRecords()));
|
||||
}
|
||||
|
||||
@Operation(summary = "消息已读")
|
||||
@PostMapping(value = "/setMsgReadStatus")
|
||||
public ResponseR setItemReadStatus(@RequestBody MessageListItemUpdateDto dto, @RequestHeader String tenantId) {
|
||||
R<Object> objectR = remoteMsgServiceFeign.setItemReadStatus(dto, tenantId);
|
||||
return ResponseR.ok(objectR.getData());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.honeycombis.honeycom.spdm.feign;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.honeycombis.honeycom.common.core.constant.CommonConstants;
|
||||
import com.honeycombis.honeycom.common.core.constant.ServiceNameConstants;
|
||||
import com.honeycombis.honeycom.common.core.util.R;
|
||||
import com.honeycombis.honeycom.common.feign.config.FeignConfig;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageListItemUpdateDto;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageListUserQueryDto;
|
||||
import com.honeycombis.honeycom.msg.api.dto.MessageOpenApiDTO;
|
||||
import com.honeycombis.honeycom.msg.api.vo.MessageListItemDetailVo;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.SpringQueryMap;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
@@ -15,5 +21,9 @@ public interface RemoteMsgServiceFeign {
|
||||
@PostMapping(value = "/openapi/push")
|
||||
R<Object> pushMessage(@RequestBody MessageOpenApiDTO dto, @RequestHeader(CommonConstants.TENANT_ID) String tenantId);
|
||||
|
||||
@GetMapping("/message/list/user/page")
|
||||
R<Page<MessageListItemDetailVo>> getUserMsgPageList(@SpringQueryMap MessageListUserQueryDto query, @RequestHeader(CommonConstants.TENANT_ID) String tenantId);
|
||||
|
||||
@PostMapping("/message/list/item/isRead")
|
||||
R<Object> setItemReadStatus(@RequestBody MessageListItemUpdateDto dto, @RequestHeader(CommonConstants.TENANT_ID) String tenantId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.honeycombis.honeycom.spdm.service;
|
||||
|
||||
import com.honeycombis.honeycom.spdm.config.RouteConfig;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
public interface ProxyService {
|
||||
ResponseEntity<byte[]> forward(HttpServletRequest request, RouteConfig.Route route);
|
||||
|
||||
String buildTargetUrl(HttpServletRequest request, RouteConfig.Route route);
|
||||
|
||||
HttpHeaders extractHeaders(HttpServletRequest request, RouteConfig.Route route);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.honeycombis.honeycom.spdm.service.impl;
|
||||
|
||||
import com.alibaba.nacos.common.utils.StringUtils;
|
||||
import com.honeycombis.honeycom.spdm.config.RouteConfig;
|
||||
import com.honeycombis.honeycom.spdm.service.ProxyService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ProxyServiceImpl implements ProxyService {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Override
|
||||
public ResponseEntity<byte[]> forward(HttpServletRequest request, RouteConfig.Route route) {
|
||||
try {
|
||||
// 1. 构建目标URL
|
||||
String targetUrl = buildTargetUrl(request, route);
|
||||
|
||||
// 2. 提取请求头
|
||||
HttpHeaders headers = extractHeaders(request, route);
|
||||
|
||||
// 3. 提取请求体
|
||||
byte[] body = extractRequestBody(request);
|
||||
|
||||
// 4. 构建HttpEntity
|
||||
HttpEntity<byte[]> entity = new HttpEntity<>(body, headers);
|
||||
|
||||
// 5. 执行请求
|
||||
HttpMethod method = HttpMethod.valueOf(request.getMethod());
|
||||
|
||||
log.debug("Forwarding request: {} {} -> {}",
|
||||
method, request.getRequestURI(), targetUrl);
|
||||
|
||||
return restTemplate.exchange(
|
||||
targetUrl,
|
||||
method,
|
||||
entity,
|
||||
byte[].class
|
||||
);
|
||||
|
||||
} catch (ResourceAccessException e) {
|
||||
log.error("Connection failed to target system: {}", route.getBaseUrl(), e);
|
||||
throw new RuntimeException("无法连接到目标系统", e);
|
||||
} catch (Exception e) {
|
||||
log.error("Forward request failed", e);
|
||||
throw new RuntimeException("请求转发失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildTargetUrl(HttpServletRequest request, RouteConfig.Route route) {
|
||||
// 1. 获取请求路径
|
||||
String requestPath = request.getRequestURI();
|
||||
|
||||
// 2. 移除路由配置中的prefix
|
||||
String targetPath = requestPath.substring(route.getPrefix().length());
|
||||
|
||||
// 3. 确保targetPath以/开头
|
||||
if (!targetPath.startsWith("/")) {
|
||||
targetPath = "/" + targetPath;
|
||||
}
|
||||
|
||||
// 4. 构建目标URL
|
||||
StringBuilder urlBuilder = new StringBuilder();
|
||||
|
||||
// 添加baseUrl
|
||||
urlBuilder.append(route.getBaseUrl());
|
||||
|
||||
// 添加目标系统的前缀(如果配置了)
|
||||
if (StringUtils.hasText(route.getTargetPrefix())) {
|
||||
String targetPrefix = route.getTargetPrefix();
|
||||
// 确保targetPrefix以/开头且不以/结尾
|
||||
if (!targetPrefix.startsWith("/")) {
|
||||
targetPrefix = "/" + targetPrefix;
|
||||
}
|
||||
if (targetPrefix.endsWith("/")) {
|
||||
targetPrefix = targetPrefix.substring(0, targetPrefix.length() - 1);
|
||||
}
|
||||
urlBuilder.append(targetPrefix);
|
||||
}
|
||||
|
||||
// 添加请求路径
|
||||
urlBuilder.append(targetPath);
|
||||
|
||||
// 5. 添加查询参数
|
||||
String queryString = request.getQueryString();
|
||||
if (StringUtils.hasText(queryString)) {
|
||||
urlBuilder.append("?").append(queryString);
|
||||
}
|
||||
|
||||
String targetUrl = urlBuilder.toString();
|
||||
log.debug("构建目标URL: {} -> {}", requestPath, targetUrl);
|
||||
|
||||
return targetUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders extractHeaders(HttpServletRequest request,
|
||||
RouteConfig.Route route) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
if (!route.isForwardHeaders()) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
// 复制所有请求头
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
while (headerNames.hasMoreElements()) {
|
||||
String headerName = headerNames.nextElement().toLowerCase();
|
||||
|
||||
// 排除不需要转发的头
|
||||
if (route.getExcludeHeaders().contains(headerName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Enumeration<String> headerValues = request.getHeaders(headerName);
|
||||
while (headerValues.hasMoreElements()) {
|
||||
headers.add(headerName, headerValues.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
// 添加自定义头(可选)
|
||||
headers.add("X-Forwarded-For", request.getRemoteAddr());
|
||||
headers.add("X-Forwarded-Host", request.getServerName());
|
||||
headers.add("X-Forwarded-Proto", request.getScheme());
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
private byte[] extractRequestBody(HttpServletRequest request) throws IOException {
|
||||
if (request.getContentLength() <= 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
try (InputStream inputStream = request.getInputStream();
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,22 +5,22 @@ server:
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: @artifactId@
|
||||
name: honeycom-spdm
|
||||
cloud:
|
||||
nacos:
|
||||
username: @nacos.username@
|
||||
password: @nacos.password@
|
||||
username: nacos
|
||||
password: N@c0s_2025_Honey!
|
||||
discovery:
|
||||
server-addr: ${NACOS_HOST:honeycom-register}:${NACOS_PORT:8848}
|
||||
namespace: @nacos.namespace@
|
||||
namespace:
|
||||
config:
|
||||
server-addr: ${spring.cloud.nacos.discovery.server-addr}
|
||||
namespace: @nacos.namespace@
|
||||
namespace:
|
||||
config:
|
||||
import:
|
||||
- optional:classpath:/application-local.yml
|
||||
- optional:nacos:application-@profiles.active@.yml
|
||||
- optional:nacos:${spring.application.name}-@profiles.active@.yml
|
||||
- optional:nacos:application-dev.yml
|
||||
- optional:nacos:${spring.application.name}-dev.yml
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
@@ -33,4 +33,20 @@ springdoc:
|
||||
tags-sorter: alpha
|
||||
default-flat-param-object: false
|
||||
cache:
|
||||
disabled: true
|
||||
disabled: true
|
||||
|
||||
proxy:
|
||||
routes:
|
||||
spdm-system:
|
||||
base-url: http://192.168.65.161:7103
|
||||
prefix: /honeycom-spdm/api/simulation/system
|
||||
targetPrefix:
|
||||
timeout: 5000
|
||||
enabled: true
|
||||
|
||||
spdm-project:
|
||||
base-url: http://192.168.65.161:7101
|
||||
prefix: /honeycom-spdm/api/simulation/project
|
||||
targetPrefix:
|
||||
timeout: 5000
|
||||
enabled: true
|
||||
|
||||
Reference in New Issue
Block a user