mirror of
https://gitee.com/dromara/RuoYi-Cloud-Plus.git
synced 2026-03-22 10:47:17 +08:00
[重大更新] 使用 spring 新特性 HttpServiceClient 替代 Dubbo 降低框架使用难度(半成本 数据权限不好使)
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -74,7 +74,7 @@
|
|||||||
<id>dev</id>
|
<id>dev</id>
|
||||||
<properties>
|
<properties>
|
||||||
<!-- 环境标识,需要与配置文件的名称相对应 -->
|
<!-- 环境标识,需要与配置文件的名称相对应 -->
|
||||||
<profiles.active>dev</profiles.active>
|
<profiles.active>public</profiles.active>
|
||||||
<nacos.server>127.0.0.1:8848</nacos.server>
|
<nacos.server>127.0.0.1:8848</nacos.server>
|
||||||
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
|
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
|
||||||
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
|
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package org.dromara.resource.api;
|
package org.dromara.resource.api;
|
||||||
|
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.resource.api.domain.RemoteFile;
|
import org.dromara.resource.api.domain.RemoteFile;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -10,6 +16,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService(value = "ruoyi-resource", fallback = RemoteFileServiceFallback.class)
|
||||||
|
@HttpExchange("/remote/file")
|
||||||
public interface RemoteFileService {
|
public interface RemoteFileService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +26,9 @@ public interface RemoteFileService {
|
|||||||
* @param file 文件信息
|
* @param file 文件信息
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
RemoteFile upload(String name, String originalFilename, String contentType, byte[] file) throws ServiceException;
|
@PostExchange("/upload")
|
||||||
|
RemoteFile upload(@RequestParam String name, @RequestParam String originalFilename,
|
||||||
|
@RequestParam String contentType, @RequestBody byte[] file) throws ServiceException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过ossId查询对应的url
|
* 通过ossId查询对应的url
|
||||||
@@ -26,7 +36,8 @@ public interface RemoteFileService {
|
|||||||
* @param ossIds ossId串逗号分隔
|
* @param ossIds ossId串逗号分隔
|
||||||
* @return url串逗号分隔
|
* @return url串逗号分隔
|
||||||
*/
|
*/
|
||||||
String selectUrlByIds(String ossIds);
|
@GetExchange("/select-url-by-ids")
|
||||||
|
String selectUrlByIds(@RequestParam String ossIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过ossId查询列表
|
* 通过ossId查询列表
|
||||||
@@ -34,5 +45,6 @@ public interface RemoteFileService {
|
|||||||
* @param ossIds ossId串逗号分隔
|
* @param ossIds ossId串逗号分隔
|
||||||
* @return 列表
|
* @return 列表
|
||||||
*/
|
*/
|
||||||
List<RemoteFile> selectByIds(String ossIds);
|
@GetExchange("/select-by-ids")
|
||||||
|
List<RemoteFile> selectByIds(@RequestParam String ossIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import org.dromara.resource.api.domain.RemoteFile;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件服务(降级处理)
|
* 文件服务熔断降级.
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class RemoteFileServiceMock implements RemoteFileService {
|
public class RemoteFileServiceFallback implements RemoteFileService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件
|
* 上传文件
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
package org.dromara.resource.api;
|
package org.dromara.resource.api;
|
||||||
|
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮件服务
|
* 邮件服务
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-resource")
|
||||||
|
@HttpExchange("/remote/mail")
|
||||||
public interface RemoteMailService {
|
public interface RemoteMailService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,6 +22,7 @@ public interface RemoteMailService {
|
|||||||
* @param subject 标题
|
* @param subject 标题
|
||||||
* @param text 内容
|
* @param text 内容
|
||||||
*/
|
*/
|
||||||
void send(String to, String subject, String text) throws ServiceException;
|
@PostExchange("/send")
|
||||||
|
void send(@RequestParam String to, @RequestParam String subject, @RequestParam String text) throws ServiceException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
package org.dromara.resource.api;
|
package org.dromara.resource.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,6 +13,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService(value = "ruoyi-resource", fallback = RemoteMessageServiceFallback.class)
|
||||||
|
@HttpExchange("/remote/message")
|
||||||
public interface RemoteMessageService {
|
public interface RemoteMessageService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,12 +23,14 @@ public interface RemoteMessageService {
|
|||||||
* @param sessionKey session主键 一般为用户id
|
* @param sessionKey session主键 一般为用户id
|
||||||
* @param message 消息文本
|
* @param message 消息文本
|
||||||
*/
|
*/
|
||||||
void publishMessage(List<Long> sessionKey, String message);
|
@PostExchange("/publish-message")
|
||||||
|
void publishMessage(@RequestBody List<Long> sessionKey, @RequestParam String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发布订阅的消息(群发)
|
* 发布订阅的消息(群发)
|
||||||
*
|
*
|
||||||
* @param message 消息内容
|
* @param message 消息内容
|
||||||
*/
|
*/
|
||||||
void publishAll(String message);
|
@PostExchange("/publish-all")
|
||||||
|
void publishAll(@RequestParam String message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.dromara.resource.api;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息服务熔断降级.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RemoteMessageServiceFallback implements RemoteMessageService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*
|
||||||
|
* @param sessionKey session主键 一般为用户id
|
||||||
|
* @param message 消息文本
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void publishMessage(List<Long> sessionKey, String message) {
|
||||||
|
log.warn("消息服务调用失败, 已触发熔断降级");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布订阅的消息(群发)
|
||||||
|
*
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void publishAll(String message) {
|
||||||
|
log.warn("消息服务调用失败, 已触发熔断降级");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package org.dromara.resource.api;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息服务
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RemoteMessageServiceStub implements RemoteMessageService {
|
|
||||||
|
|
||||||
private final RemoteMessageService remoteMessageService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送消息
|
|
||||||
*
|
|
||||||
* @param sessionKey session主键 一般为用户id
|
|
||||||
* @param message 消息文本
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void publishMessage(List<Long> sessionKey, String message) {
|
|
||||||
try {
|
|
||||||
remoteMessageService.publishMessage(sessionKey, message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("推送功能未开启或服务未找到");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布订阅的消息(群发)
|
|
||||||
*
|
|
||||||
* @param message 消息内容
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void publishAll(String message) {
|
|
||||||
try {
|
|
||||||
remoteMessageService.publishAll(message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("推送功能未开启或服务未找到");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
package org.dromara.resource.api;
|
package org.dromara.resource.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.resource.api.domain.RemoteSms;
|
import org.dromara.resource.api.domain.RemoteSms;
|
||||||
|
import org.dromara.resource.api.domain.RemoteSmsBatch;
|
||||||
|
import org.dromara.resource.api.domain.RemoteSmsDelayBatch;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -10,6 +17,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Feng
|
* @author Feng
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-resource")
|
||||||
|
@HttpExchange("/inner/remote/resource/sms")
|
||||||
public interface RemoteSmsService {
|
public interface RemoteSmsService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,7 +28,8 @@ public interface RemoteSmsService {
|
|||||||
* @param message 短信内容
|
* @param message 短信内容
|
||||||
* @return 封装了短信发送结果的 RemoteSms 对象
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
*/
|
*/
|
||||||
RemoteSms sendMessage(String phone, String message);
|
@PostExchange("/send-text")
|
||||||
|
RemoteSms sendMessage(@RequestParam String phone, @RequestParam String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步方法:发送固定消息模板多模板参数短信
|
* 同步方法:发送固定消息模板多模板参数短信
|
||||||
@@ -28,7 +38,8 @@ public interface RemoteSmsService {
|
|||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
* @return 封装了短信发送结果的 RemoteSms 对象
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
*/
|
*/
|
||||||
RemoteSms sendMessage(String phone, LinkedHashMap<String, String> messages);
|
@PostExchange("/send-vars")
|
||||||
|
RemoteSms sendMessage(@RequestParam String phone, @RequestBody LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步方法:使用自定义模板发送短信
|
* 同步方法:使用自定义模板发送短信
|
||||||
@@ -38,7 +49,9 @@ public interface RemoteSmsService {
|
|||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
* @return 封装了短信发送结果的 RemoteSms 对象
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
*/
|
*/
|
||||||
RemoteSms sendMessage(String phone, String templateId, LinkedHashMap<String, String> messages);
|
@PostExchange("/send-template")
|
||||||
|
RemoteSms sendMessage(@RequestParam String phone, @RequestParam String templateId,
|
||||||
|
@RequestBody LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步方法:群发固定模板短信
|
* 同步方法:群发固定模板短信
|
||||||
@@ -47,7 +60,8 @@ public interface RemoteSmsService {
|
|||||||
* @param message 短信内容
|
* @param message 短信内容
|
||||||
* @return 封装了短信发送结果的 RemoteSms 对象
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
*/
|
*/
|
||||||
RemoteSms messageTexting(List<String> phones, String message);
|
@PostExchange("/message-texting")
|
||||||
|
RemoteSms messageTexting(@RequestBody List<String> phones, @RequestParam String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步方法:使用自定义模板群发短信
|
* 同步方法:使用自定义模板群发短信
|
||||||
@@ -57,7 +71,19 @@ public interface RemoteSmsService {
|
|||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
* @return 封装了短信发送结果的 RemoteSms 对象
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
*/
|
*/
|
||||||
RemoteSms messageTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages);
|
@PostExchange("/message-texting-template")
|
||||||
|
default RemoteSms messageTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages) {
|
||||||
|
return messageTextingTemplate(new RemoteSmsBatch(phones, templateId, messages));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义模板群发短信.
|
||||||
|
*
|
||||||
|
* @param request 群发模板短信请求
|
||||||
|
* @return 封装了短信发送结果的 RemoteSms 对象
|
||||||
|
*/
|
||||||
|
@PostExchange("/message-texting-template")
|
||||||
|
RemoteSms messageTextingTemplate(@RequestBody RemoteSmsBatch request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步方法:发送固定消息模板短信
|
* 异步方法:发送固定消息模板短信
|
||||||
@@ -65,7 +91,8 @@ public interface RemoteSmsService {
|
|||||||
* @param phone 目标手机号
|
* @param phone 目标手机号
|
||||||
* @param message 短信内容
|
* @param message 短信内容
|
||||||
*/
|
*/
|
||||||
void sendMessageAsync(String phone, String message);
|
@PostExchange("/send-async-text")
|
||||||
|
void sendMessageAsync(@RequestParam String phone, @RequestParam String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步方法:使用自定义模板发送短信
|
* 异步方法:使用自定义模板发送短信
|
||||||
@@ -74,7 +101,9 @@ public interface RemoteSmsService {
|
|||||||
* @param templateId 短信模板ID
|
* @param templateId 短信模板ID
|
||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
*/
|
*/
|
||||||
void sendMessageAsync(String phone, String templateId, LinkedHashMap<String, String> messages);
|
@PostExchange("/send-async-template")
|
||||||
|
void sendMessageAsync(@RequestParam String phone, @RequestParam String templateId,
|
||||||
|
@RequestBody LinkedHashMap<String, String> messages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟发送:发送固定消息模板短信
|
* 延迟发送:发送固定消息模板短信
|
||||||
@@ -83,7 +112,8 @@ public interface RemoteSmsService {
|
|||||||
* @param message 短信内容
|
* @param message 短信内容
|
||||||
* @param delayedTime 延迟发送时间(毫秒)
|
* @param delayedTime 延迟发送时间(毫秒)
|
||||||
*/
|
*/
|
||||||
void delayMessage(String phone, String message, Long delayedTime);
|
@PostExchange("/delay-text")
|
||||||
|
void delayMessage(@RequestParam String phone, @RequestParam String message, @RequestParam Long delayedTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟发送:使用自定义模板发送定时短信
|
* 延迟发送:使用自定义模板发送定时短信
|
||||||
@@ -93,7 +123,9 @@ public interface RemoteSmsService {
|
|||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
* @param delayedTime 延迟发送时间(毫秒)
|
* @param delayedTime 延迟发送时间(毫秒)
|
||||||
*/
|
*/
|
||||||
void delayMessage(String phone, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
@PostExchange("/delay-template")
|
||||||
|
void delayMessage(@RequestParam String phone, @RequestParam String templateId,
|
||||||
|
@RequestBody LinkedHashMap<String, String> messages, @RequestParam Long delayedTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟群发:群发延迟短信
|
* 延迟群发:群发延迟短信
|
||||||
@@ -102,7 +134,8 @@ public interface RemoteSmsService {
|
|||||||
* @param message 短信内容
|
* @param message 短信内容
|
||||||
* @param delayedTime 延迟发送时间(毫秒)
|
* @param delayedTime 延迟发送时间(毫秒)
|
||||||
*/
|
*/
|
||||||
void delayMessageTexting(List<String> phones, String message, Long delayedTime);
|
@PostExchange("/delay-message-texting")
|
||||||
|
void delayMessageTexting(@RequestBody List<String> phones, @RequestParam String message, @RequestParam Long delayedTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 延迟群发:使用自定义模板发送群体延迟短信
|
* 延迟群发:使用自定义模板发送群体延迟短信
|
||||||
@@ -112,34 +145,50 @@ public interface RemoteSmsService {
|
|||||||
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
* @param messages 短信模板参数,使用 LinkedHashMap 以保持参数顺序
|
||||||
* @param delayedTime 延迟发送时间(毫秒)
|
* @param delayedTime 延迟发送时间(毫秒)
|
||||||
*/
|
*/
|
||||||
void delayMessageTexting(List<String> phones, String templateId, LinkedHashMap<String, String> messages, Long delayedTime);
|
@PostExchange("/delay-message-texting-template")
|
||||||
|
default void delayMessageTexting(List<String> phones, String templateId,
|
||||||
|
LinkedHashMap<String, String> messages, Long delayedTime) {
|
||||||
|
delayMessageTextingTemplate(new RemoteSmsDelayBatch(phones, templateId, messages, delayedTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延迟群发模板短信.
|
||||||
|
*
|
||||||
|
* @param request 延迟群发模板短信请求
|
||||||
|
*/
|
||||||
|
@PostExchange("/delay-message-texting-template")
|
||||||
|
void delayMessageTextingTemplate(@RequestBody RemoteSmsDelayBatch request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加入黑名单
|
* 加入黑名单
|
||||||
*
|
*
|
||||||
* @param phone 手机号
|
* @param phone 手机号
|
||||||
*/
|
*/
|
||||||
void addBlacklist(String phone);
|
@PostExchange("/add-blacklist-one")
|
||||||
|
void addBlacklist(@RequestParam String phone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加入黑名单
|
* 加入黑名单
|
||||||
*
|
*
|
||||||
* @param phones 手机号列表
|
* @param phones 手机号列表
|
||||||
*/
|
*/
|
||||||
void addBlacklist(List<String> phones);
|
@PostExchange("/add-blacklist-list")
|
||||||
|
void addBlacklist(@RequestBody List<String> phones);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除黑名单
|
* 移除黑名单
|
||||||
*
|
*
|
||||||
* @param phone 手机号
|
* @param phone 手机号
|
||||||
*/
|
*/
|
||||||
void removeBlacklist(String phone);
|
@PostExchange("/remove-blacklist-one")
|
||||||
|
void removeBlacklist(@RequestParam String phone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除黑名单
|
* 移除黑名单
|
||||||
*
|
*
|
||||||
* @param phones 手机号
|
* @param phones 手机号
|
||||||
*/
|
*/
|
||||||
void removeBlacklist(List<String> phones);
|
@PostExchange("/remove-blacklist-list")
|
||||||
|
void removeBlacklist(@RequestBody List<String> phones);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.dromara.resource.api.domain;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群发模板短信请求.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public record RemoteSmsBatch(
|
||||||
|
List<String> phones,
|
||||||
|
String templateId,
|
||||||
|
LinkedHashMap<String, String> messages
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.dromara.resource.api.domain;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延迟群发模板短信请求.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public record RemoteSmsDelayBatch(
|
||||||
|
List<String> phones,
|
||||||
|
String templateId,
|
||||||
|
LinkedHashMap<String, String> messages,
|
||||||
|
Long delayedTime
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.vo.RemoteClientVo;
|
import org.dromara.system.api.domain.vo.RemoteClientVo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端服务
|
* 客户端服务
|
||||||
*
|
*
|
||||||
* @author Michelle.Chung
|
* @author Michelle.Chung
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/client")
|
||||||
public interface RemoteClientService {
|
public interface RemoteClientService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,6 +21,7 @@ public interface RemoteClientService {
|
|||||||
* @param clientId 客户端id
|
* @param clientId 客户端id
|
||||||
* @return 客户端对象
|
* @return 客户端对象
|
||||||
*/
|
*/
|
||||||
RemoteClientVo queryByClientId(String clientId);
|
@GetExchange("/query-by-client-id")
|
||||||
|
RemoteClientVo queryByClientId(@RequestParam String clientId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ package org.dromara.system.api;
|
|||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.lang.Dict;
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -11,12 +16,15 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Michelle.Chung
|
* @author Michelle.Chung
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/config")
|
||||||
public interface RemoteConfigService {
|
public interface RemoteConfigService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取注册开关
|
* 获取注册开关
|
||||||
* @return true开启,false关闭
|
* @return true开启,false关闭
|
||||||
*/
|
*/
|
||||||
|
@GetExchange("/select-register-enabled")
|
||||||
boolean selectRegisterEnabled();
|
boolean selectRegisterEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +33,8 @@ public interface RemoteConfigService {
|
|||||||
* @param configKey 参数 key
|
* @param configKey 参数 key
|
||||||
* @return 参数值
|
* @return 参数值
|
||||||
*/
|
*/
|
||||||
String getConfigValue(String configKey);
|
@GetExchange("/get-config-value")
|
||||||
|
String getConfigValue(@RequestParam String configKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参数 key 获取布尔值
|
* 根据参数 key 获取布尔值
|
||||||
@@ -73,7 +82,9 @@ public interface RemoteConfigService {
|
|||||||
* @param configKey 参数 key
|
* @param configKey 参数 key
|
||||||
* @return Dict 对象,如果配置为空或无法解析,返回空 Dict
|
* @return Dict 对象,如果配置为空或无法解析,返回空 Dict
|
||||||
*/
|
*/
|
||||||
Dict getConfigMap(String configKey);
|
default Dict getConfigMap(String configKey) {
|
||||||
|
return JsonUtils.parseMap(getConfigValue(configKey));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参数 key 获取 Map 类型的配置列表
|
* 根据参数 key 获取 Map 类型的配置列表
|
||||||
@@ -81,7 +92,9 @@ public interface RemoteConfigService {
|
|||||||
* @param configKey 参数 key
|
* @param configKey 参数 key
|
||||||
* @return Dict 列表,如果配置为空或无法解析,返回空列表
|
* @return Dict 列表,如果配置为空或无法解析,返回空列表
|
||||||
*/
|
*/
|
||||||
List<Dict> getConfigArrayMap(String configKey);
|
default List<Dict> getConfigArrayMap(String configKey) {
|
||||||
|
return JsonUtils.parseArrayMap(getConfigValue(configKey));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参数 key 获取指定类型的配置对象
|
* 根据参数 key 获取指定类型的配置对象
|
||||||
@@ -91,7 +104,9 @@ public interface RemoteConfigService {
|
|||||||
* @param <T> 目标对象泛型
|
* @param <T> 目标对象泛型
|
||||||
* @return 对象实例,如果配置为空或无法解析,返回 null
|
* @return 对象实例,如果配置为空或无法解析,返回 null
|
||||||
*/
|
*/
|
||||||
<T> T getConfigObject(String configKey, Class<T> clazz);
|
default <T> T getConfigObject(String configKey, Class<T> clazz) {
|
||||||
|
return JsonUtils.parseObject(getConfigValue(configKey), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据参数 key 获取指定类型的配置列表
|
* 根据参数 key 获取指定类型的配置列表
|
||||||
@@ -101,6 +116,8 @@ public interface RemoteConfigService {
|
|||||||
* @param <T> 元素类型泛型
|
* @param <T> 元素类型泛型
|
||||||
* @return 指定类型列表,如果配置为空或无法解析,返回空列表
|
* @return 指定类型列表,如果配置为空或无法解析,返回空列表
|
||||||
*/
|
*/
|
||||||
<T> List<T> getConfigArray(String configKey, Class<T> clazz);
|
default <T> List<T> getConfigArray(String configKey, Class<T> clazz) {
|
||||||
|
return JsonUtils.parseArray(getConfigValue(configKey), clazz);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据权限服务
|
* 数据权限服务
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/data-scope")
|
||||||
public interface RemoteDataScopeService {
|
public interface RemoteDataScopeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,7 +20,8 @@ public interface RemoteDataScopeService {
|
|||||||
* @param roleId 角色ID
|
* @param roleId 角色ID
|
||||||
* @return 返回角色的自定义权限语句,如果没有找到则返回 null
|
* @return 返回角色的自定义权限语句,如果没有找到则返回 null
|
||||||
*/
|
*/
|
||||||
String getRoleCustom(Long roleId);
|
@GetExchange("/role-custom")
|
||||||
|
String getRoleCustom(@RequestParam Long roleId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取部门和下级权限语句
|
* 获取部门和下级权限语句
|
||||||
@@ -21,6 +29,7 @@ public interface RemoteDataScopeService {
|
|||||||
* @param deptId 部门ID
|
* @param deptId 部门ID
|
||||||
* @return 返回部门及其下级的权限语句,如果没有找到则返回 null
|
* @return 返回部门及其下级的权限语句,如果没有找到则返回 null
|
||||||
*/
|
*/
|
||||||
String getDeptAndChild(Long deptId);
|
@GetExchange("/dept-and-child")
|
||||||
|
String getDeptAndChild(@RequestParam Long deptId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.vo.RemoteDeptVo;
|
import org.dromara.system.api.domain.vo.RemoteDeptVo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -11,6 +17,8 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/dept")
|
||||||
public interface RemoteDeptService {
|
public interface RemoteDeptService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,7 +27,8 @@ public interface RemoteDeptService {
|
|||||||
* @param deptIds 部门ID串逗号分隔
|
* @param deptIds 部门ID串逗号分隔
|
||||||
* @return 部门名称串逗号分隔
|
* @return 部门名称串逗号分隔
|
||||||
*/
|
*/
|
||||||
String selectDeptNameByIds(String deptIds);
|
@GetExchange("/select-dept-name-by-ids")
|
||||||
|
String selectDeptNameByIds(@RequestParam String deptIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据部门ID查询部门负责人
|
* 根据部门ID查询部门负责人
|
||||||
@@ -27,13 +36,15 @@ public interface RemoteDeptService {
|
|||||||
* @param deptId 部门ID,用于指定需要查询的部门
|
* @param deptId 部门ID,用于指定需要查询的部门
|
||||||
* @return 返回该部门的负责人ID
|
* @return 返回该部门的负责人ID
|
||||||
*/
|
*/
|
||||||
Long selectDeptLeaderById(Long deptId);
|
@GetExchange("/select-dept-leader-by-id")
|
||||||
|
Long selectDeptLeaderById(@RequestParam Long deptId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询部门
|
* 查询部门
|
||||||
*
|
*
|
||||||
* @return 部门列表
|
* @return 部门列表
|
||||||
*/
|
*/
|
||||||
|
@GetExchange("/select-depts-by-list")
|
||||||
List<RemoteDeptVo> selectDeptsByList();
|
List<RemoteDeptVo> selectDeptsByList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,6 +53,7 @@ public interface RemoteDeptService {
|
|||||||
* @param deptIds 部门 ID 列表
|
* @param deptIds 部门 ID 列表
|
||||||
* @return Map,其中 key 为部门 ID,value 为对应的部门名称
|
* @return Map,其中 key 为部门 ID,value 为对应的部门名称
|
||||||
*/
|
*/
|
||||||
Map<Long, String> selectDeptNamesByIds(Collection<Long> deptIds);
|
@PostExchange("/select-dept-names-by-ids")
|
||||||
|
Map<Long, String> selectDeptNamesByIds(@RequestBody Collection<Long> deptIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.vo.RemoteDictDataVo;
|
import org.dromara.system.api.domain.vo.RemoteDictDataVo;
|
||||||
import org.dromara.system.api.domain.vo.RemoteDictTypeVo;
|
import org.dromara.system.api.domain.vo.RemoteDictTypeVo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -10,6 +14,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/dict")
|
||||||
public interface RemoteDictService {
|
public interface RemoteDictService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,7 +24,8 @@ public interface RemoteDictService {
|
|||||||
* @param dictType 字典类型
|
* @param dictType 字典类型
|
||||||
* @return 字典类型
|
* @return 字典类型
|
||||||
*/
|
*/
|
||||||
RemoteDictTypeVo selectDictTypeByType(String dictType);
|
@GetExchange("/select-dict-type-by-type")
|
||||||
|
RemoteDictTypeVo selectDictTypeByType(@RequestParam String dictType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据字典类型查询字典数据
|
* 根据字典类型查询字典数据
|
||||||
@@ -26,6 +33,7 @@ public interface RemoteDictService {
|
|||||||
* @param dictType 字典类型
|
* @param dictType 字典类型
|
||||||
* @return 字典数据集合信息
|
* @return 字典数据集合信息
|
||||||
*/
|
*/
|
||||||
List<RemoteDictDataVo> selectDictDataByType(String dictType);
|
@GetExchange("/select-dict-data-by-type")
|
||||||
|
List<RemoteDictDataVo> selectDictDataByType(@RequestParam String dictType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.bo.RemoteLoginInfoBo;
|
import org.dromara.system.api.domain.bo.RemoteLoginInfoBo;
|
||||||
import org.dromara.system.api.domain.bo.RemoteOperLogBo;
|
import org.dromara.system.api.domain.bo.RemoteOperLogBo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日志服务
|
* 日志服务
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/log")
|
||||||
public interface RemoteLogService {
|
public interface RemoteLogService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,13 +21,15 @@ public interface RemoteLogService {
|
|||||||
*
|
*
|
||||||
* @param sysOperLog 日志实体
|
* @param sysOperLog 日志实体
|
||||||
*/
|
*/
|
||||||
void saveLog(RemoteOperLogBo sysOperLog);
|
@PostExchange("/save-log")
|
||||||
|
void saveLog(@RequestBody RemoteOperLogBo sysOperLog);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存访问记录
|
* 保存访问记录
|
||||||
*
|
*
|
||||||
* @param sysLoginInfo 访问实体
|
* @param sysLoginInfo 访问实体
|
||||||
*/
|
*/
|
||||||
void saveLoginInfo(RemoteLoginInfoBo sysLoginInfo);
|
@PostExchange("/save-login-info")
|
||||||
|
void saveLoginInfo(@RequestBody RemoteLoginInfoBo sysLoginInfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,6 +12,8 @@ import java.util.Set;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/permission")
|
||||||
public interface RemotePermissionService {
|
public interface RemotePermissionService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,7 +22,8 @@ public interface RemotePermissionService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 角色权限信息
|
* @return 角色权限信息
|
||||||
*/
|
*/
|
||||||
Set<String> getRolePermission(Long userId);
|
@GetExchange("/role-permission")
|
||||||
|
Set<String> getRolePermission(@RequestParam Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取菜单数据权限
|
* 获取菜单数据权限
|
||||||
@@ -23,6 +31,7 @@ public interface RemotePermissionService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 菜单权限信息
|
* @return 菜单权限信息
|
||||||
*/
|
*/
|
||||||
Set<String> getMenuPermission(Long userId);
|
@GetExchange("/menu-permission")
|
||||||
|
Set<String> getMenuPermission(@RequestParam Long userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,6 +13,8 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/post")
|
||||||
public interface RemotePostService {
|
public interface RemotePostService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,6 +23,7 @@ public interface RemotePostService {
|
|||||||
* @param postIds 岗位 ID 列表
|
* @param postIds 岗位 ID 列表
|
||||||
* @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
|
* @return Map,其中 key 为岗位 ID,value 为对应的岗位名称
|
||||||
*/
|
*/
|
||||||
Map<Long, String> selectPostNamesByIds(Collection<Long> postIds);
|
@PostExchange("/select-post-names-by-ids")
|
||||||
|
Map<Long, String> selectPostNamesByIds(@RequestBody Collection<Long> postIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,6 +13,8 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/role")
|
||||||
public interface RemoteRoleService {
|
public interface RemoteRoleService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,6 +23,7 @@ public interface RemoteRoleService {
|
|||||||
* @param roleIds 角色 ID 列表
|
* @param roleIds 角色 ID 列表
|
||||||
* @return Map,其中 key 为角色 ID,value 为对应的角色名称
|
* @return Map,其中 key 为角色 ID,value 为对应的角色名称
|
||||||
*/
|
*/
|
||||||
Map<Long, String> selectRoleNamesByIds(Collection<Long> roleIds);
|
@PostExchange("/select-role-names-by-ids")
|
||||||
|
Map<Long, String> selectRoleNamesByIds(@RequestBody Collection<Long> roleIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.bo.RemoteSocialBo;
|
import org.dromara.system.api.domain.bo.RemoteSocialBo;
|
||||||
import org.dromara.system.api.domain.vo.RemoteSocialVo;
|
import org.dromara.system.api.domain.vo.RemoteSocialVo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -10,6 +16,8 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Michelle.Chung
|
* @author Michelle.Chung
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/social")
|
||||||
public interface RemoteSocialService {
|
public interface RemoteSocialService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,28 +26,32 @@ public interface RemoteSocialService {
|
|||||||
* @param authId 认证id
|
* @param authId 认证id
|
||||||
* @return 授权信息
|
* @return 授权信息
|
||||||
*/
|
*/
|
||||||
List<RemoteSocialVo> selectByAuthId(String authId);
|
@GetExchange("/select-by-auth-id")
|
||||||
|
List<RemoteSocialVo> selectByAuthId(@RequestParam String authId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询列表
|
* 查询列表
|
||||||
*
|
*
|
||||||
* @param bo 社会化关系业务对象
|
* @param bo 社会化关系业务对象
|
||||||
*/
|
*/
|
||||||
List<RemoteSocialVo> queryList(RemoteSocialBo bo);
|
@PostExchange("/query-list")
|
||||||
|
List<RemoteSocialVo> queryList(@RequestBody RemoteSocialBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存社会化关系
|
* 保存社会化关系
|
||||||
*
|
*
|
||||||
* @param bo 社会化关系业务对象
|
* @param bo 社会化关系业务对象
|
||||||
*/
|
*/
|
||||||
void insertByBo(RemoteSocialBo bo);
|
@PostExchange("/insert-by-bo")
|
||||||
|
void insertByBo(@RequestBody RemoteSocialBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新社会化关系
|
* 更新社会化关系
|
||||||
*
|
*
|
||||||
* @param bo 社会化关系业务对象
|
* @param bo 社会化关系业务对象
|
||||||
*/
|
*/
|
||||||
void updateByBo(RemoteSocialBo bo);
|
@PostExchange("/update-by-bo")
|
||||||
|
void updateByBo(@RequestBody RemoteSocialBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除社会化关系
|
* 删除社会化关系
|
||||||
@@ -47,6 +59,7 @@ public interface RemoteSocialService {
|
|||||||
* @param socialId 社会化关系ID
|
* @param socialId 社会化关系ID
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
Boolean deleteWithValidById(Long socialId);
|
@PostExchange("/delete-with-valid-by-id")
|
||||||
|
Boolean deleteWithValidById(@RequestParam Long socialId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
package org.dromara.system.api;
|
package org.dromara.system.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.bo.RemoteTaskAssigneeBo;
|
import org.dromara.system.api.domain.bo.RemoteTaskAssigneeBo;
|
||||||
import org.dromara.system.api.domain.vo.RemoteTaskAssigneeVo;
|
import org.dromara.system.api.domain.vo.RemoteTaskAssigneeVo;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流设计器获取任务执行人
|
* 工作流设计器获取任务执行人
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/task-assignee")
|
||||||
public interface RemoteTaskAssigneeService {
|
public interface RemoteTaskAssigneeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +22,8 @@ public interface RemoteTaskAssigneeService {
|
|||||||
* @param taskQuery 查询条件
|
* @param taskQuery 查询条件
|
||||||
* @return 办理人
|
* @return 办理人
|
||||||
*/
|
*/
|
||||||
RemoteTaskAssigneeVo selectRolesByTaskAssigneeList(RemoteTaskAssigneeBo taskQuery);
|
@PostExchange("/select-roles")
|
||||||
|
RemoteTaskAssigneeVo selectRolesByTaskAssigneeList(@RequestBody RemoteTaskAssigneeBo taskQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询岗位并返回任务指派的列表,支持分页
|
* 查询岗位并返回任务指派的列表,支持分页
|
||||||
@@ -24,7 +31,8 @@ public interface RemoteTaskAssigneeService {
|
|||||||
* @param taskQuery 查询条件
|
* @param taskQuery 查询条件
|
||||||
* @return 办理人
|
* @return 办理人
|
||||||
*/
|
*/
|
||||||
RemoteTaskAssigneeVo selectPostsByTaskAssigneeList(RemoteTaskAssigneeBo taskQuery);
|
@PostExchange("/select-posts")
|
||||||
|
RemoteTaskAssigneeVo selectPostsByTaskAssigneeList(@RequestBody RemoteTaskAssigneeBo taskQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询部门并返回任务指派的列表,支持分页
|
* 查询部门并返回任务指派的列表,支持分页
|
||||||
@@ -32,7 +40,8 @@ public interface RemoteTaskAssigneeService {
|
|||||||
* @param taskQuery 查询条件
|
* @param taskQuery 查询条件
|
||||||
* @return 办理人
|
* @return 办理人
|
||||||
*/
|
*/
|
||||||
RemoteTaskAssigneeVo selectDeptsByTaskAssigneeList(RemoteTaskAssigneeBo taskQuery);
|
@PostExchange("/select-depts")
|
||||||
|
RemoteTaskAssigneeVo selectDeptsByTaskAssigneeList(@RequestBody RemoteTaskAssigneeBo taskQuery);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户并返回任务指派的列表,支持分页
|
* 查询用户并返回任务指派的列表,支持分页
|
||||||
@@ -40,6 +49,7 @@ public interface RemoteTaskAssigneeService {
|
|||||||
* @param taskQuery 查询条件
|
* @param taskQuery 查询条件
|
||||||
* @return 办理人
|
* @return 办理人
|
||||||
*/
|
*/
|
||||||
RemoteTaskAssigneeVo selectUsersByTaskAssigneeList(RemoteTaskAssigneeBo taskQuery);
|
@PostExchange("/select-users")
|
||||||
|
RemoteTaskAssigneeVo selectUsersByTaskAssigneeList(@RequestBody RemoteTaskAssigneeBo taskQuery);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ package org.dromara.system.api;
|
|||||||
|
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.exception.user.UserException;
|
import org.dromara.common.core.exception.user.UserException;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.system.api.domain.bo.RemoteUserBo;
|
import org.dromara.system.api.domain.bo.RemoteUserBo;
|
||||||
import org.dromara.system.api.domain.vo.RemoteUserVo;
|
import org.dromara.system.api.domain.vo.RemoteUserVo;
|
||||||
import org.dromara.system.api.model.LoginUser;
|
import org.dromara.system.api.model.LoginUser;
|
||||||
import org.dromara.system.api.model.XcxLoginUser;
|
import org.dromara.system.api.model.XcxLoginUser;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,6 +22,8 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService("ruoyi-system")
|
||||||
|
@HttpExchange("/remote/user")
|
||||||
public interface RemoteUserService {
|
public interface RemoteUserService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,7 +32,8 @@ public interface RemoteUserService {
|
|||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
LoginUser getUserInfo(String username) throws UserException;
|
@GetExchange("/get-by-username")
|
||||||
|
LoginUser getUserInfo(@RequestParam String username) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户id查询用户信息
|
* 通过用户id查询用户信息
|
||||||
@@ -32,7 +41,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
LoginUser getUserInfo(Long userId) throws UserException;
|
@GetExchange("/get-by-id")
|
||||||
|
LoginUser getUserInfo(@RequestParam Long userId) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过手机号查询用户信息
|
* 通过手机号查询用户信息
|
||||||
@@ -40,7 +50,8 @@ public interface RemoteUserService {
|
|||||||
* @param phonenumber 手机号
|
* @param phonenumber 手机号
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
LoginUser getUserInfoByPhonenumber(String phonenumber) throws UserException;
|
@GetExchange("/get-by-phonenumber")
|
||||||
|
LoginUser getUserInfoByPhonenumber(@RequestParam String phonenumber) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过邮箱查询用户信息
|
* 通过邮箱查询用户信息
|
||||||
@@ -48,7 +59,8 @@ public interface RemoteUserService {
|
|||||||
* @param email 邮箱
|
* @param email 邮箱
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
LoginUser getUserInfoByEmail(String email) throws UserException;
|
@GetExchange("/get-by-email")
|
||||||
|
LoginUser getUserInfoByEmail(@RequestParam String email) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过openid查询用户信息
|
* 通过openid查询用户信息
|
||||||
@@ -56,7 +68,8 @@ public interface RemoteUserService {
|
|||||||
* @param openid openid
|
* @param openid openid
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
XcxLoginUser getUserInfoByOpenid(String openid) throws UserException;
|
@GetExchange("/get-by-openid")
|
||||||
|
XcxLoginUser getUserInfoByOpenid(@RequestParam String openid) throws UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册用户信息
|
* 注册用户信息
|
||||||
@@ -64,7 +77,8 @@ public interface RemoteUserService {
|
|||||||
* @param remoteUserBo 用户信息
|
* @param remoteUserBo 用户信息
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
Boolean registerUserInfo(RemoteUserBo remoteUserBo) throws UserException, ServiceException;
|
@PostExchange("/register-user-info")
|
||||||
|
Boolean registerUserInfo(@RequestBody RemoteUserBo remoteUserBo) throws UserException, ServiceException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过userId查询用户账户
|
* 通过userId查询用户账户
|
||||||
@@ -72,7 +86,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
String selectUserNameById(Long userId);
|
@GetExchange("/select-username-by-id")
|
||||||
|
String selectUserNameById(@RequestParam Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户ID查询用户昵称
|
* 通过用户ID查询用户昵称
|
||||||
@@ -80,7 +95,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
* @return 用户昵称
|
* @return 用户昵称
|
||||||
*/
|
*/
|
||||||
String selectNicknameById(Long userId);
|
@GetExchange("/select-nickname-by-id")
|
||||||
|
String selectNicknameById(@RequestParam Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户ID查询用户昵称
|
* 通过用户ID查询用户昵称
|
||||||
@@ -88,7 +104,8 @@ public interface RemoteUserService {
|
|||||||
* @param userIds 用户ID 多个用逗号隔开
|
* @param userIds 用户ID 多个用逗号隔开
|
||||||
* @return 用户昵称
|
* @return 用户昵称
|
||||||
*/
|
*/
|
||||||
String selectNicknameByIds(String userIds);
|
@GetExchange("/select-nickname-by-ids")
|
||||||
|
String selectNicknameByIds(@RequestParam String userIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户ID查询用户手机号
|
* 通过用户ID查询用户手机号
|
||||||
@@ -96,7 +113,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 用户手机号
|
* @return 用户手机号
|
||||||
*/
|
*/
|
||||||
String selectPhonenumberById(Long userId);
|
@GetExchange("/select-phonenumber-by-id")
|
||||||
|
String selectPhonenumberById(@RequestParam Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户ID查询用户邮箱
|
* 通过用户ID查询用户邮箱
|
||||||
@@ -104,7 +122,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @return 用户邮箱
|
* @return 用户邮箱
|
||||||
*/
|
*/
|
||||||
String selectEmailById(Long userId);
|
@GetExchange("/select-email-by-id")
|
||||||
|
String selectEmailById(@RequestParam Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新用户信息
|
* 更新用户信息
|
||||||
@@ -112,7 +131,8 @@ public interface RemoteUserService {
|
|||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
* @param ip IP地址
|
* @param ip IP地址
|
||||||
*/
|
*/
|
||||||
void recordLoginInfo(Long userId, String ip);
|
@PostExchange("/record-login-info")
|
||||||
|
void recordLoginInfo(@RequestParam Long userId, @RequestParam String ip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过用户ID查询用户列表
|
* 通过用户ID查询用户列表
|
||||||
@@ -120,7 +140,8 @@ public interface RemoteUserService {
|
|||||||
* @param userIds 用户ids
|
* @param userIds 用户ids
|
||||||
* @return 用户列表
|
* @return 用户列表
|
||||||
*/
|
*/
|
||||||
List<RemoteUserVo> selectListByIds(Collection<Long> userIds);
|
@PostExchange("/select-list-by-ids")
|
||||||
|
List<RemoteUserVo> selectListByIds(@RequestBody Collection<Long> userIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过角色ID查询用户ID
|
* 通过角色ID查询用户ID
|
||||||
@@ -128,7 +149,8 @@ public interface RemoteUserService {
|
|||||||
* @param roleIds 角色ids
|
* @param roleIds 角色ids
|
||||||
* @return 用户ids
|
* @return 用户ids
|
||||||
*/
|
*/
|
||||||
List<Long> selectUserIdsByRoleIds(Collection<Long> roleIds);
|
@PostExchange("/select-user-ids-by-role-ids")
|
||||||
|
List<Long> selectUserIdsByRoleIds(@RequestBody Collection<Long> roleIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过角色ID查询用户
|
* 通过角色ID查询用户
|
||||||
@@ -136,7 +158,8 @@ public interface RemoteUserService {
|
|||||||
* @param roleIds 角色ids
|
* @param roleIds 角色ids
|
||||||
* @return 用户
|
* @return 用户
|
||||||
*/
|
*/
|
||||||
List<RemoteUserVo> selectUsersByRoleIds(Collection<Long> roleIds);
|
@PostExchange("/select-users-by-role-ids")
|
||||||
|
List<RemoteUserVo> selectUsersByRoleIds(@RequestBody Collection<Long> roleIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过部门ID查询用户
|
* 通过部门ID查询用户
|
||||||
@@ -144,7 +167,8 @@ public interface RemoteUserService {
|
|||||||
* @param deptIds 部门ids
|
* @param deptIds 部门ids
|
||||||
* @return 用户
|
* @return 用户
|
||||||
*/
|
*/
|
||||||
List<RemoteUserVo> selectUsersByDeptIds(Collection<Long> deptIds);
|
@PostExchange("/select-users-by-dept-ids")
|
||||||
|
List<RemoteUserVo> selectUsersByDeptIds(@RequestBody Collection<Long> deptIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过岗位ID查询用户
|
* 通过岗位ID查询用户
|
||||||
@@ -152,7 +176,8 @@ public interface RemoteUserService {
|
|||||||
* @param postIds 岗位ids
|
* @param postIds 岗位ids
|
||||||
* @return 用户
|
* @return 用户
|
||||||
*/
|
*/
|
||||||
List<RemoteUserVo> selectUsersByPostIds(Collection<Long> postIds);
|
@PostExchange("/select-users-by-post-ids")
|
||||||
|
List<RemoteUserVo> selectUsersByPostIds(@RequestBody Collection<Long> postIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户 ID 列表查询用户昵称映射关系
|
* 根据用户 ID 列表查询用户昵称映射关系
|
||||||
@@ -160,6 +185,7 @@ public interface RemoteUserService {
|
|||||||
* @param userIds 用户 ID 列表
|
* @param userIds 用户 ID 列表
|
||||||
* @return Map,其中 key 为用户 ID,value 为对应的用户昵称
|
* @return Map,其中 key 为用户 ID,value 为对应的用户昵称
|
||||||
*/
|
*/
|
||||||
Map<Long, String> selectUserNicksByIds(Collection<Long> userIds);
|
@PostExchange("/select-user-nicks-by-ids")
|
||||||
|
Map<Long, String> selectUserNicksByIds(@RequestBody Collection<Long> userIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
package org.dromara.workflow.api;
|
package org.dromara.workflow.api;
|
||||||
|
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
import org.dromara.workflow.api.domain.RemoteCompleteTask;
|
import org.dromara.workflow.api.domain.RemoteCompleteTask;
|
||||||
import org.dromara.workflow.api.domain.RemoteStartProcess;
|
import org.dromara.workflow.api.domain.RemoteStartProcess;
|
||||||
import org.dromara.workflow.api.domain.RemoteStartProcessReturn;
|
import org.dromara.workflow.api.domain.RemoteStartProcessReturn;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.annotation.PostExchange;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -13,6 +19,8 @@ import java.util.Map;
|
|||||||
* @Author ZETA
|
* @Author ZETA
|
||||||
* @Date 2024/6/3
|
* @Date 2024/6/3
|
||||||
*/
|
*/
|
||||||
|
@RemoteHttpService(value = "ruoyi-workflow", fallback = RemoteWorkflowServiceFallback.class)
|
||||||
|
@HttpExchange("/remote/workflow")
|
||||||
public interface RemoteWorkflowService {
|
public interface RemoteWorkflowService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +29,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param businessIds 业务id
|
* @param businessIds 业务id
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean deleteInstance(List<String> businessIds);
|
@PostExchange("/delete-instance")
|
||||||
|
boolean deleteInstance(@RequestBody List<String> businessIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前流程状态
|
* 获取当前流程状态
|
||||||
@@ -29,7 +38,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param taskId 任务id
|
* @param taskId 任务id
|
||||||
* @return 状态
|
* @return 状态
|
||||||
*/
|
*/
|
||||||
String getBusinessStatusByTaskId(Long taskId);
|
@GetExchange("/business-status-by-task-id")
|
||||||
|
String getBusinessStatusByTaskId(@RequestParam Long taskId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前流程状态
|
* 获取当前流程状态
|
||||||
@@ -37,7 +47,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param businessId 业务id
|
* @param businessId 业务id
|
||||||
* @return 状态
|
* @return 状态
|
||||||
*/
|
*/
|
||||||
String getBusinessStatus(String businessId);
|
@GetExchange("/business-status")
|
||||||
|
String getBusinessStatus(@RequestParam String businessId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置流程变量
|
* 设置流程变量
|
||||||
@@ -45,14 +56,16 @@ public interface RemoteWorkflowService {
|
|||||||
* @param instanceId 流程实例id
|
* @param instanceId 流程实例id
|
||||||
* @param variable 流程变量
|
* @param variable 流程变量
|
||||||
*/
|
*/
|
||||||
void setVariable(Long instanceId, Map<String, Object> variable);
|
@PostExchange("/set-variable")
|
||||||
|
void setVariable(@RequestParam Long instanceId, @RequestBody Map<String, Object> variable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取流程变量
|
* 获取流程变量
|
||||||
*
|
*
|
||||||
* @param instanceId 流程实例id
|
* @param instanceId 流程实例id
|
||||||
*/
|
*/
|
||||||
Map<String, Object> instanceVariable(Long instanceId);
|
@GetExchange("/instance-variable")
|
||||||
|
Map<String, Object> instanceVariable(@RequestParam Long instanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照业务id查询流程实例id
|
* 按照业务id查询流程实例id
|
||||||
@@ -60,7 +73,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param businessId 业务id
|
* @param businessId 业务id
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
Long getInstanceIdByBusinessId(String businessId);
|
@GetExchange("/instance-id-by-business-id")
|
||||||
|
Long getInstanceIdByBusinessId(@RequestParam String businessId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动流程
|
* 启动流程
|
||||||
@@ -68,7 +82,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param startProcess 参数
|
* @param startProcess 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
RemoteStartProcessReturn startWorkFlow(RemoteStartProcess startProcess);
|
@PostExchange("/start-workflow")
|
||||||
|
RemoteStartProcessReturn startWorkFlow(@RequestBody RemoteStartProcess startProcess);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 办理任务
|
* 办理任务
|
||||||
@@ -76,7 +91,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param completeTask 参数
|
* @param completeTask 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean completeTask(RemoteCompleteTask completeTask);
|
@PostExchange("/complete-task")
|
||||||
|
boolean completeTask(@RequestBody RemoteCompleteTask completeTask);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,7 +102,8 @@ public interface RemoteWorkflowService {
|
|||||||
* @param message 办理意见
|
* @param message 办理意见
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean completeTask(Long taskId, String message);
|
@PostExchange("/complete-task-simple")
|
||||||
|
boolean completeTask(@RequestParam Long taskId, @RequestParam String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动流程并办理第一个任务
|
* 启动流程并办理第一个任务
|
||||||
@@ -94,6 +111,7 @@ public interface RemoteWorkflowService {
|
|||||||
* @param startProcess 参数
|
* @param startProcess 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean startCompleteTask(RemoteStartProcess startProcess);
|
@PostExchange("/start-complete-task")
|
||||||
|
boolean startCompleteTask(@RequestBody RemoteStartProcess startProcess);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 工作流服务(降级处理)
|
* 工作流服务熔断降级.
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class RemoteWorkflowServiceMock implements RemoteWorkflowService {
|
public class RemoteWorkflowServiceFallback implements RemoteWorkflowService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteInstance(List<String> businessIds) {
|
public boolean deleteInstance(List<String> businessIds) {
|
||||||
@@ -53,6 +53,11 @@
|
|||||||
<artifactId>ruoyi-common-web</artifactId>
|
<artifactId>ruoyi-common-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-redis</artifactId>
|
<artifactId>ruoyi-common-redis</artifactId>
|
||||||
@@ -63,11 +68,6 @@
|
|||||||
<artifactId>ruoyi-common-encrypt</artifactId>
|
<artifactId>ruoyi-common-encrypt</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-seata</artifactId>
|
<artifactId>ruoyi-common-seata</artifactId>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.dromara.auth;
|
package org.dromara.auth;
|
||||||
|
|
||||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||||
@@ -10,7 +9,6 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@EnableDubbo
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class RuoYiAuthApplication {
|
public class RuoYiAuthApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import me.zhyd.oauth.model.AuthResponse;
|
|||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.request.AuthRequest;
|
import me.zhyd.oauth.request.AuthRequest;
|
||||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.RegisterBody;
|
import org.dromara.auth.form.RegisterBody;
|
||||||
import org.dromara.auth.form.SocialLoginBody;
|
import org.dromara.auth.form.SocialLoginBody;
|
||||||
@@ -53,13 +52,9 @@ public class TokenController {
|
|||||||
private final SysLoginService sysLoginService;
|
private final SysLoginService sysLoginService;
|
||||||
private final ScheduledExecutorService scheduledExecutorService;
|
private final ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
@DubboReference
|
|
||||||
private final RemoteConfigService remoteConfigService;
|
private final RemoteConfigService remoteConfigService;
|
||||||
@DubboReference
|
|
||||||
private final RemoteClientService remoteClientService;
|
private final RemoteClientService remoteClientService;
|
||||||
@DubboReference
|
|
||||||
private final RemoteSocialService remoteSocialService;
|
private final RemoteSocialService remoteSocialService;
|
||||||
@DubboReference(stub = "true")
|
|
||||||
private final RemoteMessageService remoteMessageService;
|
private final RemoteMessageService remoteMessageService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import cn.hutool.http.useragent.UserAgent;
|
|||||||
import cn.hutool.http.useragent.UserAgentUtil;
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.common.core.constant.CacheNames;
|
import org.dromara.common.core.constant.CacheNames;
|
||||||
import org.dromara.common.core.constant.Constants;
|
import org.dromara.common.core.constant.Constants;
|
||||||
import org.dromara.common.core.utils.MessageUtils;
|
import org.dromara.common.core.utils.MessageUtils;
|
||||||
@@ -35,10 +34,8 @@ import java.time.Duration;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class UserActionListener implements SaTokenListener {
|
public class UserActionListener implements SaTokenListener {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
private final RemoteMessageService remoteMessageService;
|
||||||
@DubboReference
|
|
||||||
private RemoteMessageService remoteMessageService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每次登录时触发
|
* 每次登录时触发
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import com.baomidou.lock.annotation.Lock4j;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.form.RegisterBody;
|
import org.dromara.auth.form.RegisterBody;
|
||||||
import org.dromara.auth.properties.CaptchaProperties;
|
import org.dromara.auth.properties.CaptchaProperties;
|
||||||
import org.dromara.auth.properties.UserPasswordProperties;
|
import org.dromara.auth.properties.UserPasswordProperties;
|
||||||
@@ -50,10 +49,8 @@ import java.util.function.Supplier;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SysLoginService {
|
public class SysLoginService {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
private final RemoteSocialService remoteSocialService;
|
||||||
@DubboReference
|
|
||||||
private RemoteSocialService remoteSocialService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserPasswordProperties userPasswordProperties;
|
private UserPasswordProperties userPasswordProperties;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import cn.dev33.satoken.stp.StpUtil;
|
|||||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.EmailLoginBody;
|
import org.dromara.auth.form.EmailLoginBody;
|
||||||
import org.dromara.auth.service.IAuthStrategy;
|
import org.dromara.auth.service.IAuthStrategy;
|
||||||
@@ -36,8 +35,7 @@ public class EmailAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, RemoteClientVo client) {
|
public LoginVo login(String body, RemoteClientVo client) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import cn.dev33.satoken.stp.StpUtil;
|
|||||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.PasswordLoginBody;
|
import org.dromara.auth.form.PasswordLoginBody;
|
||||||
import org.dromara.auth.properties.CaptchaProperties;
|
import org.dromara.auth.properties.CaptchaProperties;
|
||||||
@@ -41,8 +40,7 @@ public class PasswordAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, RemoteClientVo client) {
|
public LoginVo login(String body, RemoteClientVo client) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import cn.dev33.satoken.stp.StpUtil;
|
|||||||
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.SmsLoginBody;
|
import org.dromara.auth.form.SmsLoginBody;
|
||||||
import org.dromara.auth.service.IAuthStrategy;
|
import org.dromara.auth.service.IAuthStrategy;
|
||||||
@@ -36,8 +35,7 @@ public class SmsAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, RemoteClientVo client) {
|
public LoginVo login(String body, RemoteClientVo client) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.SocialLoginBody;
|
import org.dromara.auth.form.SocialLoginBody;
|
||||||
import org.dromara.auth.service.IAuthStrategy;
|
import org.dromara.auth.service.IAuthStrategy;
|
||||||
@@ -37,10 +36,8 @@ public class SocialAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SocialProperties socialProperties;
|
private final SocialProperties socialProperties;
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteSocialService remoteSocialService;
|
||||||
private RemoteSocialService remoteSocialService;
|
private final RemoteUserService remoteUserService;
|
||||||
@DubboReference
|
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录-第三方授权登录
|
* 登录-第三方授权登录
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import me.zhyd.oauth.model.AuthToken;
|
|||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.request.AuthRequest;
|
import me.zhyd.oauth.request.AuthRequest;
|
||||||
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
|
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.auth.domain.vo.LoginVo;
|
import org.dromara.auth.domain.vo.LoginVo;
|
||||||
import org.dromara.auth.form.XcxLoginBody;
|
import org.dromara.auth.form.XcxLoginBody;
|
||||||
import org.dromara.auth.service.IAuthStrategy;
|
import org.dromara.auth.service.IAuthStrategy;
|
||||||
@@ -37,8 +36,7 @@ public class XcxAuthStrategy implements IAuthStrategy {
|
|||||||
|
|
||||||
private final SysLoginService loginService;
|
private final SysLoginService loginService;
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginVo login(String body, RemoteClientVo client) {
|
public LoginVo login(String body, RemoteClientVo client) {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
<module>ruoyi-common-security</module>
|
<module>ruoyi-common-security</module>
|
||||||
<module>ruoyi-common-satoken</module>
|
<module>ruoyi-common-satoken</module>
|
||||||
<module>ruoyi-common-web</module>
|
<module>ruoyi-common-web</module>
|
||||||
|
<module>ruoyi-common-http</module>
|
||||||
<module>ruoyi-common-mybatis</module>
|
<module>ruoyi-common-mybatis</module>
|
||||||
<module>ruoyi-common-job</module>
|
<module>ruoyi-common-job</module>
|
||||||
<module>ruoyi-common-dubbo</module>
|
|
||||||
<module>ruoyi-common-seata</module>
|
<module>ruoyi-common-seata</module>
|
||||||
<module>ruoyi-common-loadbalancer</module>
|
<module>ruoyi-common-loadbalancer</module>
|
||||||
<module>ruoyi-common-oss</module>
|
<module>ruoyi-common-oss</module>
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
<spring-cloud-alibaba.version>2025.1.0.0</spring-cloud-alibaba.version>
|
<spring-cloud-alibaba.version>2025.1.0.0</spring-cloud-alibaba.version>
|
||||||
<seata.version>2.5.0</seata.version>
|
<seata.version>2.5.0</seata.version>
|
||||||
<nacos.client.version>3.1.1</nacos.client.version>
|
<nacos.client.version>3.1.1</nacos.client.version>
|
||||||
<dubbo.version>3.3.6</dubbo.version>
|
|
||||||
<dubbo-extensions.version>3.3.1</dubbo-extensions.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -60,30 +58,6 @@
|
|||||||
<version>${seata.version}</version>
|
<version>${seata.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Apache Dubbo 配置 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
<version>${dubbo.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-actuator</artifactId>
|
|
||||||
<version>${dubbo.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo</artifactId>
|
|
||||||
<version>${dubbo.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo.extensions</groupId>
|
|
||||||
<artifactId>dubbo-metadata-report-redis</artifactId>
|
|
||||||
<version>${dubbo-extensions.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -82,6 +82,13 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 内部HTTP远程调用 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 数据库服务 -->
|
<!-- 数据库服务 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
@@ -96,13 +103,6 @@
|
|||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- RPC服务 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 分布式事务 -->
|
<!-- 分布式事务 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package org.dromara.common.core.annotation;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 声明远程 HTTP Service 所属服务.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface RemoteHttpService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务名.
|
||||||
|
*/
|
||||||
|
@AliasFor("serviceId")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务名.
|
||||||
|
*/
|
||||||
|
@AliasFor("value")
|
||||||
|
String serviceId() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 远程调用失败时的 fallback 实现.
|
||||||
|
*/
|
||||||
|
Class<?> fallback() default void.class;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common</artifactId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
|
|
||||||
<description>
|
|
||||||
ruoyi-common-dubbo RPC服务
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-json</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-context</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-actuator</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo.extensions</groupId>
|
|
||||||
<artifactId>dubbo-metadata-report-redis</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>redis.clients</groupId>
|
|
||||||
<artifactId>jedis</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>redis.clients</groupId>
|
|
||||||
<artifactId>jedis</artifactId>
|
|
||||||
<version>5.2.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Sa-Token 整合 Dubbo -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.dev33</groupId>
|
|
||||||
<artifactId>sa-token-dubbo3</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-commons</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
@@ -1,538 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.dubbo.metadata.store.redis;
|
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
|
||||||
import org.apache.dubbo.common.URL;
|
|
||||||
import org.apache.dubbo.common.config.configcenter.ConfigItem;
|
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
|
||||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
|
||||||
import org.apache.dubbo.common.utils.*;
|
|
||||||
import org.apache.dubbo.metadata.MappingChangedEvent;
|
|
||||||
import org.apache.dubbo.metadata.MappingListener;
|
|
||||||
import org.apache.dubbo.metadata.MetadataInfo;
|
|
||||||
import org.apache.dubbo.metadata.ServiceNameMapping;
|
|
||||||
import org.apache.dubbo.metadata.report.identifier.*;
|
|
||||||
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
|
|
||||||
import org.apache.dubbo.rpc.RpcException;
|
|
||||||
import redis.clients.jedis.*;
|
|
||||||
import redis.clients.jedis.params.SetParams;
|
|
||||||
import redis.clients.jedis.util.JedisClusterCRC16;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.*;
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;
|
|
||||||
import static org.apache.dubbo.metadata.MetadataConstants.META_DATA_STORE_TAG;
|
|
||||||
import static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP;
|
|
||||||
import static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames;
|
|
||||||
import static org.apache.dubbo.metadata.report.support.Constants.DEFAULT_METADATA_REPORT_CYCLE_REPORT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RedisMetadataReport
|
|
||||||
*/
|
|
||||||
public class RedisMetadataReport extends AbstractMetadataReport {
|
|
||||||
|
|
||||||
private static final String REDIS_DATABASE_KEY = "database";
|
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RedisMetadataReport.class);
|
|
||||||
|
|
||||||
// protected , for test
|
|
||||||
protected JedisPool pool;
|
|
||||||
private Set<HostAndPort> jedisClusterNodes;
|
|
||||||
private int timeout;
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private final String root;
|
|
||||||
private final ConcurrentHashMap<String, MappingDataListener> mappingDataListenerMap = new ConcurrentHashMap<>();
|
|
||||||
private SetParams jedisParams = SetParams.setParams();
|
|
||||||
|
|
||||||
public RedisMetadataReport(URL url) {
|
|
||||||
super(url);
|
|
||||||
timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
|
|
||||||
username = url.getUsername();
|
|
||||||
password = url.getPassword();
|
|
||||||
this.root = url.getGroup(DEFAULT_ROOT);
|
|
||||||
if (url.getParameter(CYCLE_REPORT_KEY, DEFAULT_METADATA_REPORT_CYCLE_REPORT)) {
|
|
||||||
// ttl default is twice the cycle-report time
|
|
||||||
jedisParams.px(ONE_DAY_IN_MILLISECONDS * 2);
|
|
||||||
}
|
|
||||||
if (url.getParameter(CLUSTER_KEY, false)) {
|
|
||||||
jedisClusterNodes = new HashSet<>();
|
|
||||||
List<URL> urls = url.getBackupUrls();
|
|
||||||
for (URL tmpUrl : urls) {
|
|
||||||
jedisClusterNodes.add(new HostAndPort(tmpUrl.getHost(), tmpUrl.getPort()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int database = url.getParameter(REDIS_DATABASE_KEY, 0);
|
|
||||||
pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort(), timeout, username, password, database);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) {
|
|
||||||
this.storeMetadata(providerMetadataIdentifier, serviceDefinitions, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) {
|
|
||||||
this.storeMetadata(consumerMetadataIdentifier, value, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) {
|
|
||||||
this.storeMetadata(serviceMetadataIdentifier, URL.encode(url.toFullString()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) {
|
|
||||||
this.deleteMetadata(serviceMetadataIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) {
|
|
||||||
String content = getMetadata(metadataIdentifier);
|
|
||||||
if (StringUtils.isEmpty(content)) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return new ArrayList<>(Arrays.asList(URL.decode(content)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) {
|
|
||||||
this.storeMetadata(subscriberMetadataIdentifier, urlListStr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) {
|
|
||||||
return this.getMetadata(subscriberMetadataIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getServiceDefinition(MetadataIdentifier metadataIdentifier) {
|
|
||||||
return this.getMetadata(metadataIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMetadata(BaseMetadataIdentifier metadataIdentifier, String v, boolean ephemeral) {
|
|
||||||
if (pool != null) {
|
|
||||||
storeMetadataStandalone(metadataIdentifier, v, ephemeral);
|
|
||||||
} else {
|
|
||||||
storeMetadataInCluster(metadataIdentifier, v, ephemeral);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMetadataInCluster(BaseMetadataIdentifier metadataIdentifier, String v, boolean ephemeral) {
|
|
||||||
try (JedisCluster jedisCluster =
|
|
||||||
new JedisCluster(jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
if (ephemeral) {
|
|
||||||
jedisCluster.set(metadataIdentifier.getIdentifierKey() + META_DATA_STORE_TAG, v, jedisParams);
|
|
||||||
} else {
|
|
||||||
jedisCluster.set(metadataIdentifier.getIdentifierKey() + META_DATA_STORE_TAG, v);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg =
|
|
||||||
"Failed to put " + metadataIdentifier + " to redis cluster " + v + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMetadataStandalone(BaseMetadataIdentifier metadataIdentifier, String v, boolean ephemeral) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
if (ephemeral) {
|
|
||||||
jedis.set(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), v, jedisParams);
|
|
||||||
} else {
|
|
||||||
jedis.set(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), v);
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to put " + metadataIdentifier + " to redis " + v + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteMetadata(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
if (pool != null) {
|
|
||||||
deleteMetadataStandalone(metadataIdentifier);
|
|
||||||
} else {
|
|
||||||
deleteMetadataInCluster(metadataIdentifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteMetadataInCluster(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
try (JedisCluster jedisCluster =
|
|
||||||
new JedisCluster(jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
jedisCluster.del(metadataIdentifier.getIdentifierKey() + META_DATA_STORE_TAG);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to delete " + metadataIdentifier + " from redis cluster , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteMetadataStandalone(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
jedis.del(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to delete " + metadataIdentifier + " from redis , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMetadata(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
if (pool != null) {
|
|
||||||
return getMetadataStandalone(metadataIdentifier);
|
|
||||||
} else {
|
|
||||||
return getMetadataInCluster(metadataIdentifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMetadataInCluster(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
try (JedisCluster jedisCluster =
|
|
||||||
new JedisCluster(jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
return jedisCluster.get(metadataIdentifier.getIdentifierKey() + META_DATA_STORE_TAG);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to get " + metadataIdentifier + " from redis cluster , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMetadataStandalone(BaseMetadataIdentifier metadataIdentifier) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
return jedis.get(metadataIdentifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to get " + metadataIdentifier + " from redis , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store class and application names using Redis hashes
|
|
||||||
* key: default 'dubbo:mapping'
|
|
||||||
* field: class (serviceInterface)
|
|
||||||
* value: application_names
|
|
||||||
* @param serviceInterface field(class)
|
|
||||||
* @param defaultMappingGroup {@link ServiceNameMapping#DEFAULT_MAPPING_GROUP}
|
|
||||||
* @param newConfigContent new application_names
|
|
||||||
* @param ticket previous application_names
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean registerServiceAppMapping(
|
|
||||||
String serviceInterface, String defaultMappingGroup, String newConfigContent, Object ticket) {
|
|
||||||
try {
|
|
||||||
if (null != ticket && !(ticket instanceof String)) {
|
|
||||||
throw new IllegalArgumentException("redis publishConfigCas requires stat type ticket");
|
|
||||||
}
|
|
||||||
String pathKey = buildMappingKey(defaultMappingGroup);
|
|
||||||
|
|
||||||
return storeMapping(pathKey, serviceInterface, newConfigContent, (String) ticket);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.warn(TRANSPORT_FAILED_RESPONSE, "", "", "redis publishConfigCas failed.", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean storeMapping(String key, String field, String value, String ticket) {
|
|
||||||
if (pool != null) {
|
|
||||||
return storeMappingStandalone(key, field, value, ticket);
|
|
||||||
} else {
|
|
||||||
return storeMappingInCluster(key, field, value, ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* use 'watch' to implement cas.
|
|
||||||
* Find information about slot distribution by key.
|
|
||||||
*/
|
|
||||||
private boolean storeMappingInCluster(String key, String field, String value, String ticket) {
|
|
||||||
try (JedisCluster jedisCluster =
|
|
||||||
new JedisCluster(jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
Jedis jedis = new Jedis(jedisCluster.getConnectionFromSlot(JedisClusterCRC16.getSlot(key)));
|
|
||||||
jedis.watch(key);
|
|
||||||
String oldValue = jedis.hget(key, field);
|
|
||||||
if (null == oldValue || null == ticket || oldValue.equals(ticket)) {
|
|
||||||
Transaction transaction = jedis.multi();
|
|
||||||
transaction.hset(key, field, value);
|
|
||||||
List<Object> result = transaction.exec();
|
|
||||||
if (null != result) {
|
|
||||||
jedisCluster.publish(buildPubSubKey(), field);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
jedis.unwatch();
|
|
||||||
}
|
|
||||||
jedis.close();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to put " + key + ":" + field + " to redis " + value + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* use 'watch' to implement cas.
|
|
||||||
* Find information about slot distribution by key.
|
|
||||||
*/
|
|
||||||
private boolean storeMappingStandalone(String key, String field, String value, String ticket) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
jedis.watch(key);
|
|
||||||
String oldValue = jedis.hget(key, field);
|
|
||||||
if (null == oldValue || null == ticket || oldValue.equals(ticket)) {
|
|
||||||
Transaction transaction = jedis.multi();
|
|
||||||
transaction.hset(key, field, value);
|
|
||||||
List<Object> result = transaction.exec();
|
|
||||||
if (null != result) {
|
|
||||||
jedis.publish(buildPubSubKey(), field);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jedis.unwatch();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to put " + key + ":" + field + " to redis " + value + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build mapping key
|
|
||||||
* @param defaultMappingGroup {@link ServiceNameMapping#DEFAULT_MAPPING_GROUP}
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String buildMappingKey(String defaultMappingGroup) {
|
|
||||||
return this.root + GROUP_CHAR_SEPARATOR + defaultMappingGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* build pub/sub key
|
|
||||||
*/
|
|
||||||
private String buildPubSubKey() {
|
|
||||||
return buildMappingKey(DEFAULT_MAPPING_GROUP) + GROUP_CHAR_SEPARATOR + QUEUES_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get content and use content to complete cas
|
|
||||||
* @param serviceKey class
|
|
||||||
* @param group {@link ServiceNameMapping#DEFAULT_MAPPING_GROUP}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ConfigItem getConfigItem(String serviceKey, String group) {
|
|
||||||
String key = buildMappingKey(group);
|
|
||||||
String content = getMappingData(key, serviceKey);
|
|
||||||
|
|
||||||
return new ConfigItem(content, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get current application_names
|
|
||||||
*/
|
|
||||||
private String getMappingData(String key, String field) {
|
|
||||||
if (pool != null) {
|
|
||||||
return getMappingDataStandalone(key, field);
|
|
||||||
} else {
|
|
||||||
return getMappingDataInCluster(key, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMappingDataInCluster(String key, String field) {
|
|
||||||
try (JedisCluster jedisCluster =
|
|
||||||
new JedisCluster(jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
return jedisCluster.hget(key, field);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to get " + key + ":" + field + " from redis cluster , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMappingDataStandalone(String key, String field) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
return jedis.hget(key, field);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to get " + key + ":" + field + " from redis , cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove listener. If have no listener,thread will dead
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void removeServiceAppMappingListener(String serviceKey, MappingListener listener) {
|
|
||||||
MappingDataListener mappingDataListener = mappingDataListenerMap.get(buildPubSubKey());
|
|
||||||
if (null != mappingDataListener) {
|
|
||||||
NotifySub notifySub = mappingDataListener.getNotifySub();
|
|
||||||
notifySub.removeListener(serviceKey, listener);
|
|
||||||
if (notifySub.isEmpty()) {
|
|
||||||
mappingDataListener.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a thread and subscribe to {@link this#buildPubSubKey()}.
|
|
||||||
* Notify {@link MappingListener} if there is a change in the 'application_names' message.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Set<String> getServiceAppMapping(String serviceKey, MappingListener listener, URL url) {
|
|
||||||
MappingDataListener mappingDataListener =
|
|
||||||
ConcurrentHashMapUtils.computeIfAbsent(mappingDataListenerMap, buildPubSubKey(), k -> {
|
|
||||||
MappingDataListener dataListener = new MappingDataListener(buildPubSubKey());
|
|
||||||
dataListener.start();
|
|
||||||
return dataListener;
|
|
||||||
});
|
|
||||||
mappingDataListener.getNotifySub().addListener(serviceKey, listener);
|
|
||||||
return this.getServiceAppMapping(serviceKey, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<String> getServiceAppMapping(String serviceKey, URL url) {
|
|
||||||
String key = buildMappingKey(DEFAULT_MAPPING_GROUP);
|
|
||||||
return getAppNames(getMappingData(key, serviceKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map<String, String> instanceMetadata) {
|
|
||||||
String content = this.getMetadata(identifier);
|
|
||||||
return JsonUtils.toJavaObject(content, MetadataInfo.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {
|
|
||||||
this.storeMetadata(identifier, metadataInfo.getContent(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unPublishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) {
|
|
||||||
this.deleteMetadata(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for test
|
|
||||||
public MappingDataListener getMappingDataListener() {
|
|
||||||
return mappingDataListenerMap.get(buildPubSubKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen for changes in the 'application_names' message and notify the listener.
|
|
||||||
*/
|
|
||||||
class NotifySub extends JedisPubSub {
|
|
||||||
|
|
||||||
private final Map<String, Set<MappingListener>> listeners = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public void addListener(String key, MappingListener listener) {
|
|
||||||
Set<MappingListener> listenerSet = listeners.computeIfAbsent(key, k -> new ConcurrentHashSet<>());
|
|
||||||
listenerSet.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeListener(String serviceKey, MappingListener listener) {
|
|
||||||
Set<MappingListener> listenerSet = this.listeners.get(serviceKey);
|
|
||||||
if (listenerSet != null) {
|
|
||||||
listenerSet.remove(listener);
|
|
||||||
if (listenerSet.isEmpty()) {
|
|
||||||
this.listeners.remove(serviceKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isEmpty() {
|
|
||||||
return this.listeners.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(String key, String msg) {
|
|
||||||
logger.info("sub from redis:" + key + " message:" + msg);
|
|
||||||
String applicationNames = getMappingData(buildMappingKey(DEFAULT_MAPPING_GROUP), msg);
|
|
||||||
MappingChangedEvent mappingChangedEvent = new MappingChangedEvent(msg, getAppNames(applicationNames));
|
|
||||||
if (!CollectionUtils.isEmpty(listeners.get(msg))) {
|
|
||||||
for (MappingListener mappingListener : listeners.get(msg)) {
|
|
||||||
mappingListener.onEvent(mappingChangedEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPMessage(String pattern, String key, String msg) {
|
|
||||||
onMessage(key, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPSubscribe(String pattern, int subscribedChannels) {
|
|
||||||
super.onPSubscribe(pattern, subscribedChannels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribe application names change message.
|
|
||||||
*/
|
|
||||||
class MappingDataListener extends Thread {
|
|
||||||
|
|
||||||
private String path;
|
|
||||||
|
|
||||||
private final NotifySub notifySub = new NotifySub();
|
|
||||||
// for test
|
|
||||||
protected volatile boolean running = true;
|
|
||||||
|
|
||||||
public MappingDataListener(String path) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NotifySub getNotifySub() {
|
|
||||||
return notifySub;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (running) {
|
|
||||||
if (pool != null) {
|
|
||||||
try (Jedis jedis = pool.getResource()) {
|
|
||||||
jedis.subscribe(notifySub, path);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to subscribe " + path + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try (JedisCluster jedisCluster = new JedisCluster(
|
|
||||||
jedisClusterNodes, timeout, timeout, 2, password, new GenericObjectPoolConfig<>())) {
|
|
||||||
jedisCluster.subscribe(notifySub, path);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to subscribe " + path + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
throw new RpcException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
|
||||||
try {
|
|
||||||
running = false;
|
|
||||||
notifySub.unsubscribe(path);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
String msg = "Failed to unsubscribe " + path + ", cause: " + e.getMessage();
|
|
||||||
logger.error(TRANSPORT_FAILED_RESPONSE, "", "", msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package org.dromara.common.dubbo.config;
|
|
||||||
|
|
||||||
import org.apache.dubbo.common.constants.CommonConstants;
|
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.boot.context.properties.bind.Binder;
|
|
||||||
import org.springframework.cloud.commons.util.InetUtils;
|
|
||||||
import org.springframework.cloud.commons.util.InetUtilsProperties;
|
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dubbo自定义IP注入(避免IP不正确问题)
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered, EnvironmentAware {
|
|
||||||
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置此组件运行的应用环境。
|
|
||||||
* 由 Spring 容器回调注入。
|
|
||||||
*
|
|
||||||
* @param environment 当前应用环境对象
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(Environment environment) {
|
|
||||||
this.environment = environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取该 BeanFactoryPostProcessor 的顺序,确保它在容器初始化过程中具有最高优先级
|
|
||||||
*
|
|
||||||
* @return 优先级顺序值,越小优先级越高
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return Ordered.HIGHEST_PRECEDENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在 Spring 容器初始化过程中对 Bean 工厂进行后置处理
|
|
||||||
*
|
|
||||||
* @param beanFactory 可配置的 Bean 工厂
|
|
||||||
* @throws BeansException 如果在处理过程中发生错误
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
|
||||||
String property = System.getProperty(CommonConstants.DubboProperty.DUBBO_IP_TO_REGISTRY);
|
|
||||||
if (StringUtils.isNotBlank(property)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 手动绑定 InetUtilsProperties,避免早期初始化导致配置未注入
|
|
||||||
InetUtilsProperties properties = Binder.get(environment)
|
|
||||||
.bind(InetUtilsProperties.PREFIX, InetUtilsProperties.class)
|
|
||||||
.orElseGet(InetUtilsProperties::new);
|
|
||||||
|
|
||||||
// 创建临时的 InetUtils 实例
|
|
||||||
try (InetUtils inetUtils = new InetUtils(properties)) {
|
|
||||||
String ip = "127.0.0.1";
|
|
||||||
// 获取第一个非回环地址
|
|
||||||
InetAddress address = inetUtils.findFirstNonLoopbackAddress();
|
|
||||||
if (address != null) {
|
|
||||||
if (address instanceof Inet6Address) {
|
|
||||||
// 处理 IPv6 地址
|
|
||||||
String ipv6AddressString = address.getHostAddress();
|
|
||||||
if (ipv6AddressString.contains("%")) {
|
|
||||||
// 去掉可能存在的范围 ID
|
|
||||||
ipv6AddressString = ipv6AddressString.substring(0, ipv6AddressString.indexOf("%"));
|
|
||||||
}
|
|
||||||
ip = ipv6AddressString;
|
|
||||||
} else {
|
|
||||||
// 处理 IPv4 地址
|
|
||||||
ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 设置系统属性 DUBBO_IP_TO_REGISTRY 为获取到的 IP 地址
|
|
||||||
System.setProperty(CommonConstants.DubboProperty.DUBBO_IP_TO_REGISTRY, ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package org.dromara.common.dubbo.config;
|
|
||||||
|
|
||||||
import org.dromara.common.core.factory.YmlPropertySourceFactory;
|
|
||||||
import org.dromara.common.dubbo.handler.DubboExceptionHandler;
|
|
||||||
import org.dromara.common.dubbo.properties.DubboCustomProperties;
|
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.PropertySource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dubbo 配置类
|
|
||||||
*/
|
|
||||||
@AutoConfiguration
|
|
||||||
@EnableConfigurationProperties(DubboCustomProperties.class)
|
|
||||||
@PropertySource(value = "classpath:common-dubbo.yml", factory = YmlPropertySourceFactory.class)
|
|
||||||
public class DubboConfiguration {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dubbo自定义IP注入(避免IP不正确问题)
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public BeanFactoryPostProcessor customBeanFactoryPostProcessor() {
|
|
||||||
return new CustomBeanFactoryPostProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异常处理器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public DubboExceptionHandler dubboExceptionHandler() {
|
|
||||||
return new DubboExceptionHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package org.dromara.common.dubbo.filter;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.dubbo.common.constants.CommonConstants;
|
|
||||||
import org.apache.dubbo.common.extension.Activate;
|
|
||||||
import org.apache.dubbo.rpc.*;
|
|
||||||
import org.apache.dubbo.rpc.service.GenericService;
|
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
|
||||||
import org.dromara.common.dubbo.enumd.RequestLogEnum;
|
|
||||||
import org.dromara.common.dubbo.properties.DubboCustomProperties;
|
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dubbo 日志过滤器
|
|
||||||
* <p>
|
|
||||||
* 该过滤器通过实现 Dubbo 的 Filter 接口,在服务调用前后记录日志信息
|
|
||||||
* 可根据配置开关和日志级别输出不同详细程度的日志信息
|
|
||||||
* <p>
|
|
||||||
* 激活条件:
|
|
||||||
* - 在 Provider 和 Consumer 端都生效
|
|
||||||
* - 执行顺序设置为最大值,确保在所有其他过滤器之后执行
|
|
||||||
* <p>
|
|
||||||
* 使用 SpringUtils 获取配置信息,根据配置决定是否记录日志及日志详细程度
|
|
||||||
* <p>
|
|
||||||
* 使用 Lombok 的 @Slf4j 注解简化日志记录
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = Integer.MAX_VALUE)
|
|
||||||
public class DubboRequestFilter implements Filter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dubbo Filter 接口实现方法,处理服务调用逻辑并记录日志
|
|
||||||
*
|
|
||||||
* @param invoker Dubbo 服务调用者实例
|
|
||||||
* @param invocation 调用的具体方法信息
|
|
||||||
* @return 调用结果
|
|
||||||
* @throws RpcException 如果调用过程中发生异常
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
|
||||||
DubboCustomProperties properties = SpringUtils.getBean(DubboCustomProperties.class);
|
|
||||||
// 如果未开启请求日志记录,则直接执行服务调用并返回结果
|
|
||||||
if (!properties.getRequestLog()) {
|
|
||||||
return invoker.invoke(invocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是 Provider 还是 Consumer
|
|
||||||
String client = CommonConstants.PROVIDER;
|
|
||||||
if (RpcContext.getServiceContext().isConsumerSide()) {
|
|
||||||
client = CommonConstants.CONSUMER;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建基础日志信息
|
|
||||||
String baselog = "Client[" + client + "],InterfaceName=[" + invocation.getInvoker().getInterface().getSimpleName() + "],MethodName=[" + invocation.getMethodName() + "]";
|
|
||||||
// 根据日志级别输出不同详细程度的日志信息
|
|
||||||
if (properties.getLogLevel() == RequestLogEnum.INFO) {
|
|
||||||
log.info("DUBBO - 服务调用: {}", baselog);
|
|
||||||
} else {
|
|
||||||
log.info("DUBBO - 服务调用: {},Parameter={}", baselog, invocation.getArguments());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录调用开始时间
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
// 执行接口调用逻辑
|
|
||||||
Result result = invoker.invoke(invocation);
|
|
||||||
// 计算调用耗时
|
|
||||||
long elapsed = System.currentTimeMillis() - startTime;
|
|
||||||
// 如果发生异常且调用的不是泛化服务,则记录异常日志
|
|
||||||
if (result.hasException() && !invoker.getInterface().equals(GenericService.class)) {
|
|
||||||
log.error("DUBBO - 服务异常: {},Exception={}", baselog, result.getException());
|
|
||||||
} else {
|
|
||||||
// 根据日志级别输出服务响应信息
|
|
||||||
if (properties.getLogLevel() == RequestLogEnum.INFO) {
|
|
||||||
log.info("DUBBO - 服务响应: {},SpendTime=[{}ms]", baselog, elapsed);
|
|
||||||
} else if (properties.getLogLevel() == RequestLogEnum.FULL) {
|
|
||||||
log.info("DUBBO - 服务响应: {},SpendTime=[{}ms],Response={}", baselog, elapsed, JsonUtils.toJsonString(new Object[]{result.getValue()}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package org.dromara.common.dubbo.handler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.dubbo.rpc.RpcException;
|
|
||||||
import org.dromara.common.core.domain.R;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dubbo异常处理器
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@RestControllerAdvice
|
|
||||||
public class DubboExceptionHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主键或UNIQUE索引,数据重复异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(RpcException.class)
|
|
||||||
public R<Void> handleDubboException(RpcException e) {
|
|
||||||
log.error("RPC异常: {}", e.getMessage());
|
|
||||||
return R.fail("RPC异常,请联系管理员确认");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.dromara.common.dubbo.properties;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.dromara.common.dubbo.enumd.RequestLogEnum;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义配置
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@RefreshScope
|
|
||||||
@ConfigurationProperties(prefix = "dubbo.custom")
|
|
||||||
public class DubboCustomProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否开启请求日志记录
|
|
||||||
*/
|
|
||||||
private Boolean requestLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志级别
|
|
||||||
*/
|
|
||||||
private RequestLogEnum logLevel;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
dubboRequestFilter=org.dromara.common.dubbo.filter.DubboRequestFilter
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
org.dromara.common.dubbo.config.DubboConfiguration
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
|
|
||||||
dubbo:
|
|
||||||
application:
|
|
||||||
logger: slf4j
|
|
||||||
# 元数据中心 local 本地 remote 远程 这里使用远程便于其他服务获取
|
|
||||||
metadataType: remote
|
|
||||||
# 可选值 interface、instance、all,默认是 all,即接口级地址、应用级地址都注册
|
|
||||||
register-mode: instance
|
|
||||||
service-discovery:
|
|
||||||
# FORCE_INTERFACE,只消费接口级地址,如无地址则报错,单订阅 2.x 地址
|
|
||||||
# APPLICATION_FIRST,智能决策接口级/应用级地址,双订阅
|
|
||||||
# FORCE_APPLICATION,只消费应用级地址,如无地址则报错,单订阅 3.x 地址
|
|
||||||
migration: FORCE_APPLICATION
|
|
||||||
# 注册中心配置
|
|
||||||
registry:
|
|
||||||
address: nacos://${spring.cloud.nacos.server-addr}
|
|
||||||
group: DUBBO_GROUP
|
|
||||||
username: ${spring.cloud.nacos.username}
|
|
||||||
password: ${spring.cloud.nacos.password}
|
|
||||||
parameters:
|
|
||||||
namespace: ${spring.profiles.active}
|
|
||||||
metadata-report:
|
|
||||||
address: redis://${spring.data.redis.host:localhost}:${spring.data.redis.port:6379}
|
|
||||||
group: DUBBO_GROUP
|
|
||||||
username: ${spring.data.redis.username:default}
|
|
||||||
password: ${spring.data.redis.password}
|
|
||||||
parameters:
|
|
||||||
namespace: ${spring.profiles.active}
|
|
||||||
database: ${spring.data.redis.database}
|
|
||||||
timeout: ${spring.data.redis.timeout}
|
|
||||||
# 消费者相关配置
|
|
||||||
consumer:
|
|
||||||
# 结果缓存(LRU算法)
|
|
||||||
# 会有数据不一致问题 建议在注解局部开启
|
|
||||||
cache: false
|
|
||||||
# 支持校验注解
|
|
||||||
validation: jvalidationNew
|
|
||||||
# 调用重试 不包括第一次 0为不需要重试
|
|
||||||
retries: 0
|
|
||||||
# 初始化检查
|
|
||||||
check: false
|
|
||||||
45
ruoyi-common/ruoyi-common-http/pom.xml
Normal file
45
ruoyi-common/ruoyi-common-http/pom.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
ruoyi-common-http 内部 HTTP 远程调用
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-json</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.dromara</groupId>
|
||||||
|
<artifactId>ruoyi-common-satoken</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.dromara.common.http.annotation;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP 服务控制器.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@RestController
|
||||||
|
public @interface RemoteServiceController {
|
||||||
|
|
||||||
|
@AliasFor(annotation = RestController.class, attribute = "value")
|
||||||
|
String value() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
package org.dromara.common.http.config;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.same.SaSameUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.utils.ServletUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
|
import org.dromara.common.http.log.aspect.RemoteHttpProviderLogAspect;
|
||||||
|
import org.dromara.common.http.handler.RemoteHttpExceptionHandler;
|
||||||
|
import org.dromara.common.http.properties.RemoteHttpProperties;
|
||||||
|
import org.dromara.common.http.registrar.RemoteHttpServiceRegistrar;
|
||||||
|
import org.dromara.common.http.support.RemoteHttpFallbackProxyPostProcessor;
|
||||||
|
import org.dromara.common.http.log.support.LoggingHttpExchangeAdapter;
|
||||||
|
import org.dromara.common.http.log.support.RemoteHttpLogSupport;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatusCode;
|
||||||
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP 远程调用配置.
|
||||||
|
*
|
||||||
|
* 这里把运行时几条链路接起来:
|
||||||
|
* 1. Consumer 发请求前透传认证头和 Seata XID
|
||||||
|
* 2. 远程非 2xx 响应统一转成 ServiceException
|
||||||
|
* 3. 打开请求日志时,为 consumer/provider 两侧挂日志能力
|
||||||
|
* 4. 远程代理失败时按接口声明触发 fallback
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@AutoConfiguration
|
||||||
|
@Import(RemoteHttpServiceRegistrar.class)
|
||||||
|
@EnableConfigurationProperties(RemoteHttpProperties.class)
|
||||||
|
public class RemoteHttpAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static BeanFactoryPostProcessor remoteHttpControllerProxyCompatibilityPostProcessor() {
|
||||||
|
return new RemoteHttpInfrastructurePostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("remoteHttpHeaderInterceptor")
|
||||||
|
public ClientHttpRequestInterceptor remoteHttpHeaderInterceptor() {
|
||||||
|
return (request, body, execution) -> {
|
||||||
|
HttpHeaders headers = request.getHeaders();
|
||||||
|
HttpServletRequest currentRequest = ServletUtils.getRequest();
|
||||||
|
if (currentRequest != null) {
|
||||||
|
String authorization = currentRequest.getHeader(HttpHeaders.AUTHORIZATION);
|
||||||
|
if (StringUtils.isNotBlank(authorization)) {
|
||||||
|
headers.set(HttpHeaders.AUTHORIZATION, authorization);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 透传 same-token,保证服务间调用仍然走内网鉴权。
|
||||||
|
headers.set(SaSameUtil.SAME_TOKEN, SaSameUtil.getToken());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
relaySeataXid(headers);
|
||||||
|
return execution.execute(request, body);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestClientHttpServiceGroupConfigurer remoteHttpServiceGroupConfigurer(
|
||||||
|
ClientHttpRequestInterceptor remoteHttpHeaderInterceptor,
|
||||||
|
RemoteHttpLogSupport remoteHttpLogSupport) {
|
||||||
|
return groups -> groups.forEachGroup((group, clientBuilder, proxyFactoryBuilder) -> {
|
||||||
|
clientBuilder.requestInterceptor(remoteHttpHeaderInterceptor)
|
||||||
|
// provider 侧远程接口异常会直接映射成非 2xx,这里只按 HTTP 状态处理即可。
|
||||||
|
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> {
|
||||||
|
throwServiceException(response.getStatusCode().value(), response.getStatusText(), readResponseBody(response));
|
||||||
|
});
|
||||||
|
if (remoteHttpLogSupport.isEnabled()) {
|
||||||
|
// consumer 侧日志挂在 HttpExchangeAdapter 上,避免碰底层 body 重复读取问题。
|
||||||
|
proxyFactoryBuilder.exchangeAdapterDecorator(adapter -> new LoggingHttpExchangeAdapter(adapter, remoteHttpLogSupport));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RemoteHttpFallbackProxyPostProcessor remoteHttpFallbackProxyPostProcessor() {
|
||||||
|
return new RemoteHttpFallbackProxyPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RemoteHttpLogSupport remoteHttpLogSupport(RemoteHttpProperties properties) {
|
||||||
|
return new RemoteHttpLogSupport(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RemoteHttpProviderLogAspect remoteHttpProviderLogAspect(RemoteHttpLogSupport remoteHttpLogSupport) {
|
||||||
|
return new RemoteHttpProviderLogAspect(remoteHttpLogSupport);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RemoteHttpExceptionHandler remoteHttpExceptionHandler() {
|
||||||
|
return new RemoteHttpExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void relaySeataXid(HttpHeaders headers) {
|
||||||
|
try {
|
||||||
|
// 通过反射做可选适配,未引入 Seata 时不强依赖该类。
|
||||||
|
Class<?> rootContextClass = Class.forName("org.apache.seata.core.context.RootContext");
|
||||||
|
String xid = (String) rootContextClass.getMethod("getXID").invoke(null);
|
||||||
|
if (StringUtils.isBlank(xid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String headerName = (String) rootContextClass.getField("KEY_XID").get(null);
|
||||||
|
headers.set(headerName, xid);
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("relay seata xid failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readResponseBody(org.springframework.http.client.ClientHttpResponse response) {
|
||||||
|
try {
|
||||||
|
return StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.debug("read remote response body failed", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwServiceException(int statusCode, String statusText, String responseBody) {
|
||||||
|
if (StringUtils.isNotBlank(responseBody) && JsonUtils.isJsonObject(responseBody)) {
|
||||||
|
try {
|
||||||
|
// 远程服务如果按 R 返回错误信息,优先还原成更友好的业务异常消息。
|
||||||
|
R<?> result = JsonUtils.parseObject(responseBody, R.class);
|
||||||
|
if (result != null && (result.getCode() == 0 || R.isSuccess(result))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result != null && StringUtils.isNotBlank(result.getMsg())) {
|
||||||
|
throw new ServiceException(result.getMsg(), result.getCode());
|
||||||
|
}
|
||||||
|
} catch (ServiceException se) {
|
||||||
|
throw se;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log.debug("parse remote error body failed: {}", responseBody, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String message = StringUtils.firstNonBlank(responseBody, statusText, "远程服务调用失败");
|
||||||
|
throw new ServiceException(message, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RemoteHttpInfrastructurePostProcessor implements BeanFactoryPostProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||||
|
BeanDefinitionRegistry registry = beanFactory instanceof BeanDefinitionRegistry beanDefinitionRegistry
|
||||||
|
? beanDefinitionRegistry : null;
|
||||||
|
ClassLoader beanClassLoader = beanFactory.getBeanClassLoader();
|
||||||
|
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||||
|
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||||
|
preserveRemoteControllerTargetClass(beanDefinition);
|
||||||
|
registerFallbackBeanDefinition(registry, beanFactory, beanDefinition, beanClassLoader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void preserveRemoteControllerTargetClass(BeanDefinition beanDefinition) {
|
||||||
|
if (!(beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!annotatedBeanDefinition.getMetadata().hasAnnotation(RemoteServiceController.class.getName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
beanDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerFallbackBeanDefinition(BeanDefinitionRegistry registry,
|
||||||
|
ConfigurableListableBeanFactory beanFactory, BeanDefinition beanDefinition, ClassLoader beanClassLoader) {
|
||||||
|
if (registry == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Class<?> serviceInterface = resolveRemoteServiceInterface(beanDefinition, beanClassLoader);
|
||||||
|
if (serviceInterface == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RemoteHttpService remoteHttpService = serviceInterface.getAnnotation(RemoteHttpService.class);
|
||||||
|
if (remoteHttpService == null || remoteHttpService.fallback() == void.class) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Class<?> fallbackClass = remoteHttpService.fallback();
|
||||||
|
if (!serviceInterface.isAssignableFrom(fallbackClass)) {
|
||||||
|
throw new IllegalStateException("Fallback class must implement remote service interface: "
|
||||||
|
+ fallbackClass.getName() + " -> " + serviceInterface.getName());
|
||||||
|
}
|
||||||
|
if (beanFactory.getBeanNamesForType(fallbackClass, false, false).length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BeanDefinition fallbackBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(fallbackClass)
|
||||||
|
.setLazyInit(true)
|
||||||
|
.getBeanDefinition();
|
||||||
|
// fallback 只给框架内部按具体类型获取使用,不参与业务侧按接口类型自动注入,
|
||||||
|
// 否则会和真正的远程代理一起成为 RemoteXxxService 的候选 Bean。
|
||||||
|
fallbackBeanDefinition.setAutowireCandidate(false);
|
||||||
|
fallbackBeanDefinition.setPrimary(false);
|
||||||
|
registry.registerBeanDefinition(fallbackClass.getName(), fallbackBeanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> resolveRemoteServiceInterface(BeanDefinition beanDefinition, ClassLoader beanClassLoader) {
|
||||||
|
String beanClassName = beanDefinition.getBeanClassName();
|
||||||
|
if (beanClassName == null || beanClassLoader == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Class<?> beanClass = org.springframework.util.ClassUtils.resolveClassName(beanClassName, beanClassLoader);
|
||||||
|
if (!beanClass.isInterface() || !beanClass.isAnnotationPresent(RemoteHttpService.class)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return beanClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package org.dromara.common.http.handler;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.validation.ConstraintViolation;
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.constant.HttpStatus;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.dromara.common.core.exception.base.BaseException;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
|
import org.springframework.context.MessageSourceResolvable;
|
||||||
|
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.HttpStatusCode;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
|
import org.springframework.validation.BindException;
|
||||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.MissingPathVariableException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.method.annotation.HandlerMethodValidationException;
|
||||||
|
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||||
|
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅作用于内部远程 HTTP 接口的异常处理器.
|
||||||
|
*
|
||||||
|
* 远程接口与普通对外 API 分开处理:
|
||||||
|
* 1. provider 直接返回非 2xx HTTP 状态,consumer 只按状态码判错
|
||||||
|
* 2. 响应体仍保留 R.code / R.msg,方便把业务码继续透传回消费方
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Order(org.springframework.core.Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@RestControllerAdvice(annotations = RemoteServiceController.class)
|
||||||
|
public class RemoteHttpExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}',不支持'{}'请求", request.getRequestURI(), e.getMethod());
|
||||||
|
return buildResponse(HttpStatus.BAD_METHOD, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(ServiceException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleServiceException(ServiceException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
int code = resolveBusinessCode(e.getCode(), HttpStatus.ERROR);
|
||||||
|
return buildResponse(code, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(ServletException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleServletException(ServletException e, HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}',发生未知异常.", request.getRequestURI(), e);
|
||||||
|
return buildResponse(HttpStatus.ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(BaseException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleBaseException(BaseException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
return buildResponse(HttpStatus.ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MissingPathVariableException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
|
||||||
|
log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", request.getRequestURI());
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
log.error("请求参数类型不匹配'{}',发生系统异常.", request.getRequestURI());
|
||||||
|
String message = String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'",
|
||||||
|
e.getName(), e.getRequiredType().getName(), e.getValue());
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(NoHandlerFoundException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}'不存在.", request.getRequestURI());
|
||||||
|
return buildResponse(HttpStatus.NOT_FOUND, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleBindException(BindException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(ConstraintViolationException.class)
|
||||||
|
public ResponseEntity<R<Void>> constraintViolationException(ConstraintViolationException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
String message = StreamUtils.join(e.getBindingResult().getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(HandlerMethodValidationException.class)
|
||||||
|
public ResponseEntity<R<Void>> handlerMethodValidationException(HandlerMethodValidationException e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
String message = StreamUtils.join(e.getAllErrors(), MessageSourceResolvable::getDefaultMessage, ", ");
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleHttpMessageNotReadableException(HttpMessageNotReadableException e,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}', 参数解析失败: {}", request.getRequestURI(), e.getMessage());
|
||||||
|
return buildResponse(HttpStatus.BAD_REQUEST, "请求参数格式错误:" + e.getMostSpecificCause().getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(RuntimeException.class)
|
||||||
|
public ResponseEntity<R<Void>> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}',发生未知异常.", request.getRequestURI(), e);
|
||||||
|
return buildResponse(HttpStatus.ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public ResponseEntity<R<Void>> handleException(Exception e, HttpServletRequest request) {
|
||||||
|
log.error("请求地址'{}',发生系统异常.", request.getRequestURI(), e);
|
||||||
|
return buildResponse(HttpStatus.ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseEntity<R<Void>> buildResponse(int code, String message) {
|
||||||
|
return ResponseEntity.status(resolveHttpStatus(code))
|
||||||
|
.body(R.fail(code, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpStatusCode resolveHttpStatus(int code) {
|
||||||
|
if (code >= 100 && code <= 599) {
|
||||||
|
return HttpStatusCode.valueOf(code);
|
||||||
|
}
|
||||||
|
return HttpStatusCode.valueOf(HttpStatus.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int resolveBusinessCode(Integer code, int defaultCode) {
|
||||||
|
return code == null ? defaultCode : code;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package org.dromara.common.http.log.aspect;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.dromara.common.core.utils.ServletUtils;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.dromara.common.http.log.support.RemoteHttpLogSupport;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP Provider 日志切面.
|
||||||
|
*
|
||||||
|
* Provider 侧日志不直接读原始请求 body,而是等 Spring 完成参数绑定后
|
||||||
|
* 直接记录方法入参/返回值,这样可以避免 servlet body 重复读取。
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RemoteHttpProviderLogAspect {
|
||||||
|
|
||||||
|
private final RemoteHttpLogSupport logSupport;
|
||||||
|
|
||||||
|
@Around("@within(org.dromara.common.http.annotation.RemoteServiceController) && execution(public * *(..))")
|
||||||
|
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
Class<?> targetClass = AopUtils.getTargetClass(joinPoint.getTarget());
|
||||||
|
Object[] arguments = joinPoint.getArgs();
|
||||||
|
HttpServletRequest request = ServletUtils.getRequest();
|
||||||
|
Class<?> remoteInterface = resolveRemoteInterface(targetClass, method);
|
||||||
|
// 真实 HTTP 调用时优先从 servlet 请求拿 method/path;
|
||||||
|
// 本地短路调用时再回退到接口上的 @HttpExchange 注解。
|
||||||
|
HttpMethod httpMethod = resolveHttpMethod(request, remoteInterface, method);
|
||||||
|
String path = resolvePath(request, remoteInterface, method);
|
||||||
|
this.logSupport.logRequest(RemoteHttpLogSupport.PROVIDER, httpMethod, path, arguments);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
Object result = joinPoint.proceed();
|
||||||
|
this.logSupport.logResponse(RemoteHttpLogSupport.PROVIDER, httpMethod, path, System.currentTimeMillis() - startTime, result);
|
||||||
|
return result;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.logSupport.logException(RemoteHttpLogSupport.PROVIDER, httpMethod, path, System.currentTimeMillis() - startTime, ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpMethod resolveHttpMethod(HttpServletRequest request, Class<?> remoteInterface, Method method) {
|
||||||
|
if (request != null && StringUtils.hasText(request.getMethod())) {
|
||||||
|
return HttpMethod.valueOf(request.getMethod());
|
||||||
|
}
|
||||||
|
HttpExchange methodExchange = resolveMethodExchange(remoteInterface, method);
|
||||||
|
if (methodExchange != null && StringUtils.hasText(methodExchange.method())) {
|
||||||
|
return HttpMethod.valueOf(methodExchange.method());
|
||||||
|
}
|
||||||
|
HttpExchange typeExchange = resolveTypeExchange(remoteInterface);
|
||||||
|
if (typeExchange != null && StringUtils.hasText(typeExchange.method())) {
|
||||||
|
return HttpMethod.valueOf(typeExchange.method());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolvePath(HttpServletRequest request, Class<?> remoteInterface, Method method) {
|
||||||
|
if (request != null) {
|
||||||
|
String requestUri = request.getRequestURI();
|
||||||
|
if (StringUtils.hasText(requestUri)) {
|
||||||
|
String queryString = request.getQueryString();
|
||||||
|
if (!StringUtils.hasText(queryString)) {
|
||||||
|
return requestUri;
|
||||||
|
}
|
||||||
|
return requestUri + '?' + queryString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String typePath = extractPath(resolveTypeExchange(remoteInterface));
|
||||||
|
String methodPath = extractPath(resolveMethodExchange(remoteInterface, method));
|
||||||
|
if (!StringUtils.hasText(typePath)) {
|
||||||
|
return methodPath;
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(methodPath)) {
|
||||||
|
return typePath;
|
||||||
|
}
|
||||||
|
// 拼出接口级 + 方法级路径,作为本地短路场景下的日志定位信息。
|
||||||
|
return combinePath(typePath, methodPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> resolveRemoteInterface(Class<?> targetClass, Method method) {
|
||||||
|
for (Class<?> interfaceType : targetClass.getInterfaces()) {
|
||||||
|
if (interfaceType.isAnnotationPresent(RemoteHttpService.class)
|
||||||
|
&& org.springframework.util.ReflectionUtils.findMethod(interfaceType, method.getName(), method.getParameterTypes()) != null) {
|
||||||
|
return interfaceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpExchange resolveTypeExchange(Class<?> remoteInterface) {
|
||||||
|
if (remoteInterface == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AnnotatedElementUtils.findMergedAnnotation(remoteInterface, HttpExchange.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpExchange resolveMethodExchange(Class<?> remoteInterface, Method method) {
|
||||||
|
if (remoteInterface == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Method interfaceMethod = org.springframework.util.ReflectionUtils.findMethod(remoteInterface, method.getName(), method.getParameterTypes());
|
||||||
|
if (interfaceMethod == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AnnotatedElementUtils.findMergedAnnotation(interfaceMethod, HttpExchange.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractPath(HttpExchange exchange) {
|
||||||
|
if (exchange == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(exchange.url())) {
|
||||||
|
return exchange.url();
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(exchange.value())) {
|
||||||
|
return exchange.value();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String combinePath(String typePath, String methodPath) {
|
||||||
|
String normalizedTypePath = trimTrailingSlash(typePath);
|
||||||
|
String normalizedMethodPath = trimLeadingSlash(methodPath);
|
||||||
|
if (!StringUtils.hasText(normalizedTypePath)) {
|
||||||
|
return '/' + normalizedMethodPath;
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(normalizedMethodPath)) {
|
||||||
|
return normalizedTypePath;
|
||||||
|
}
|
||||||
|
return normalizedTypePath + '/' + normalizedMethodPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trimTrailingSlash(String path) {
|
||||||
|
if (!StringUtils.hasText(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return path.endsWith("/") ? path.substring(0, path.length() - 1) : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trimLeadingSlash(String path) {
|
||||||
|
if (!StringUtils.hasText(path)) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return path.startsWith("/") ? path.substring(1) : path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.dromara.common.dubbo.enumd;
|
package org.dromara.common.http.log.enums;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求日志泛型
|
* 请求日志级别.
|
||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@@ -11,18 +11,18 @@ import lombok.AllArgsConstructor;
|
|||||||
public enum RequestLogEnum {
|
public enum RequestLogEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* info 基础信息
|
* 基础信息.
|
||||||
*/
|
*/
|
||||||
INFO,
|
INFO,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* param 参数信息
|
* 参数信息.
|
||||||
*/
|
*/
|
||||||
PARAM,
|
PARAM,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* full 全部
|
* 全量信息.
|
||||||
*/
|
*/
|
||||||
FULL;
|
FULL
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package org.dromara.common.http.log.support;
|
||||||
|
|
||||||
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.service.invoker.HttpExchangeAdapter;
|
||||||
|
import org.springframework.web.service.invoker.HttpExchangeAdapterDecorator;
|
||||||
|
import org.springframework.web.service.invoker.HttpRequestValues;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP Consumer 日志装饰器.
|
||||||
|
*
|
||||||
|
* Consumer 侧日志挂在 HttpServiceProxyFactory 的 exchange adapter 上,
|
||||||
|
* 这样可以直接拿到最终请求 method/path 和解码后的返回值,
|
||||||
|
* 比直接拦截底层流更稳定,也更容易规避 body 重复读问题。
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public class LoggingHttpExchangeAdapter extends HttpExchangeAdapterDecorator {
|
||||||
|
|
||||||
|
private final RemoteHttpLogSupport logSupport;
|
||||||
|
|
||||||
|
public LoggingHttpExchangeAdapter(HttpExchangeAdapter delegate, RemoteHttpLogSupport logSupport) {
|
||||||
|
super(delegate);
|
||||||
|
this.logSupport = logSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exchange(HttpRequestValues requestValues) {
|
||||||
|
invoke(requestValues, () -> {
|
||||||
|
super.exchange(requestValues);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHeaders exchangeForHeaders(HttpRequestValues requestValues) {
|
||||||
|
return invoke(requestValues, () -> super.exchangeForHeaders(requestValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
|
return invoke(requestValues, () -> super.exchangeForBody(requestValues, bodyType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestValues) {
|
||||||
|
return invoke(requestValues, () -> super.exchangeForBodilessEntity(requestValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
|
||||||
|
return invoke(requestValues, () -> super.exchangeForEntity(requestValues, bodyType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T invoke(HttpRequestValues requestValues, ThrowingSupplier<T> supplier) {
|
||||||
|
HttpMethod httpMethod = requestValues.getHttpMethod();
|
||||||
|
String path = resolvePath(requestValues);
|
||||||
|
Object bodyValue = requestValues.getBodyValue();
|
||||||
|
Object[] arguments = bodyValue == null ? new Object[0] : bodyValue instanceof Object[] array ? array : new Object[] {bodyValue};
|
||||||
|
this.logSupport.logRequest(RemoteHttpLogSupport.CONSUMER, httpMethod, path, arguments);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
T result = supplier.get();
|
||||||
|
this.logSupport.logResponse(RemoteHttpLogSupport.CONSUMER, httpMethod, path,
|
||||||
|
System.currentTimeMillis() - startTime, result);
|
||||||
|
return result;
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
this.logSupport.logException(RemoteHttpLogSupport.CONSUMER, httpMethod, path,
|
||||||
|
System.currentTimeMillis() - startTime, ex);
|
||||||
|
switch (ex) {
|
||||||
|
case ServiceException serviceException -> throw serviceException;
|
||||||
|
case RuntimeException runtimeException -> throw runtimeException;
|
||||||
|
case Error error -> throw error;
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolvePath(HttpRequestValues requestValues) {
|
||||||
|
URI uri = requestValues.getUri();
|
||||||
|
if (uri != null) {
|
||||||
|
// 能拿到最终 URI 时优先打印最终请求地址,便于线上排查。
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
String uriTemplate = requestValues.getUriTemplate();
|
||||||
|
if (!StringUtils.hasText(uriTemplate)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map<String, String> uriVariables = requestValues.getUriVariables();
|
||||||
|
String path = uriTemplate;
|
||||||
|
if (uriVariables != null) {
|
||||||
|
for (Map.Entry<String, String> entry : uriVariables.entrySet()) {
|
||||||
|
path = path.replace("{" + entry.getKey() + "}", String.valueOf(entry.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface ThrowingSupplier<T> {
|
||||||
|
|
||||||
|
T get() throws Throwable;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package org.dromara.common.http.log.support;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.http.log.enums.RequestLogEnum;
|
||||||
|
import org.dromara.common.http.properties.RemoteHttpProperties;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP 日志支持.
|
||||||
|
*
|
||||||
|
* 这里只做两件事:
|
||||||
|
* 1. 统一 consumer/provider 的日志格式
|
||||||
|
* 2. 对 byte[] 等内容做简单脱敏,避免日志直接刷大块二进制
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RemoteHttpLogSupport {
|
||||||
|
|
||||||
|
public static final String CONSUMER = "CONSUMER";
|
||||||
|
public static final String PROVIDER = "PROVIDER";
|
||||||
|
|
||||||
|
private final RemoteHttpProperties properties;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return Boolean.TRUE.equals(properties.getRequestLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFullLogEnabled() {
|
||||||
|
return properties.getLogLevel() == RequestLogEnum.FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logRequest(String client, HttpMethod httpMethod, String path, Object[] arguments) {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String baseLog = buildBaseLog(client, httpMethod, path);
|
||||||
|
if (properties.getLogLevel() == RequestLogEnum.INFO) {
|
||||||
|
log.info("HTTP - 服务调用: {}", baseLog);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("HTTP - 服务调用: {},Parameter={}", baseLog, formatArguments(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logResponse(String client, HttpMethod httpMethod, String path, long elapsed, Object response) {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String baseLog = buildBaseLog(client, httpMethod, path);
|
||||||
|
if (properties.getLogLevel() == RequestLogEnum.FULL) {
|
||||||
|
log.info("HTTP - 服务响应: {},SpendTime=[{}ms],Response={}", baseLog, elapsed, formatValue(unwrapResponse(response)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("HTTP - 服务响应: {},SpendTime=[{}ms]", baseLog, elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logException(String client, HttpMethod httpMethod, String path, long elapsed, Throwable throwable) {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String baseLog = buildBaseLog(client, httpMethod, path);
|
||||||
|
log.error("HTTP - 服务异常: {},SpendTime=[{}ms],Exception={}", baseLog, elapsed, throwable.getMessage(), throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildBaseLog(String client, HttpMethod httpMethod, String path) {
|
||||||
|
return "Client[" + client + ']' +
|
||||||
|
",HttpMethod[" +
|
||||||
|
(httpMethod != null ? httpMethod : "UNKNOWN") +
|
||||||
|
']' +
|
||||||
|
",Path[" +
|
||||||
|
(StringUtils.hasText(path) ? path : "UNKNOWN") +
|
||||||
|
']';
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatArguments(Object[] arguments) {
|
||||||
|
return formatValue(arguments == null ? new Object[0] : arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object unwrapResponse(Object response) {
|
||||||
|
if (response instanceof ResponseEntity<?> responseEntity) {
|
||||||
|
return responseEntity.getBody();
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatValue(Object value) {
|
||||||
|
try {
|
||||||
|
return JsonUtils.toJsonString(sanitizeValue(value));
|
||||||
|
} catch (RuntimeException ignored) {
|
||||||
|
return String.valueOf(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object sanitizeValue(Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof byte[] bytes) {
|
||||||
|
// 文件上传这类场景只记录长度,避免二进制内容直接进日志。
|
||||||
|
return "byte[" + bytes.length + "]";
|
||||||
|
}
|
||||||
|
if (value instanceof Object[] array) {
|
||||||
|
Object[] sanitized = new Object[array.length];
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
sanitized[i] = sanitizeValue(array[i]);
|
||||||
|
}
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
if (value instanceof Collection<?> collection) {
|
||||||
|
return collection.stream().map(this::sanitizeValue).toList();
|
||||||
|
}
|
||||||
|
if (value instanceof Map<?, ?> map) {
|
||||||
|
Map<Object, Object> sanitized = new LinkedHashMap<>(map.size());
|
||||||
|
map.forEach((key, item) -> sanitized.put(key, sanitizeValue(item)));
|
||||||
|
return sanitized;
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isArray(value)) {
|
||||||
|
return ObjectUtils.nullSafeToString(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.dromara.common.http.properties;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.common.http.log.enums.RequestLogEnum;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部 HTTP 调用配置.
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "remote.http")
|
||||||
|
public class RemoteHttpProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启请求日志.
|
||||||
|
*/
|
||||||
|
private Boolean requestLog = Boolean.FALSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志级别.
|
||||||
|
*/
|
||||||
|
private RequestLogEnum logLevel = RequestLogEnum.INFO;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package org.dromara.common.http.registrar;
|
||||||
|
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||||
|
import org.springframework.context.EnvironmentAware;
|
||||||
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.boot.context.properties.bind.Binder;
|
||||||
|
import org.springframework.web.service.annotation.HttpExchange;
|
||||||
|
import org.springframework.web.service.registry.AbstractHttpServiceRegistrar;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按接口声明自动注册远程 HTTP Service.
|
||||||
|
*
|
||||||
|
* 这个注册器负责把“接口声明”转成 Spring HTTP Service Client 代理,
|
||||||
|
* 同时保留一个和 Dubbo 类似的优化:
|
||||||
|
* 当前服务自己就提供了该接口实现时,不再注册远程代理,直接走本地 Bean。
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public class RemoteHttpServiceRegistrar extends AbstractHttpServiceRegistrar
|
||||||
|
implements EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware {
|
||||||
|
|
||||||
|
private Environment environment;
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
private ClassLoader beanClassLoader;
|
||||||
|
private static final String SCAN_PACKAGES_PROPERTY = "remote.http.scan-packages";
|
||||||
|
private static final AntPathMatcher PACKAGE_MATCHER = new AntPathMatcher(".");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment environment) {
|
||||||
|
super.setEnvironment(environment);
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||||
|
super.setResourceLoader(resourceLoader);
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||||
|
super.setBeanClassLoader(beanClassLoader);
|
||||||
|
this.beanClassLoader = beanClassLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata importingClassMetadata) {
|
||||||
|
Set<String> scanPackagePatterns = new LinkedHashSet<>(resolveConfiguredScanPackages());
|
||||||
|
if (scanPackagePatterns.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> scanBasePackages = resolveScanBasePackages(scanPackagePatterns);
|
||||||
|
if (scanBasePackages.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 先找出当前服务自己已经提供的远程接口,后面这些接口不再注册 HTTP client。
|
||||||
|
Set<String> localServiceTypes = resolveLocalServiceTypes(scanBasePackages, scanPackagePatterns);
|
||||||
|
MultiValueMap<String, String> groupedServices = resolveRemoteHttpServices(scanBasePackages, scanPackagePatterns, localServiceTypes);
|
||||||
|
groupedServices.forEach((serviceId, classNames) ->
|
||||||
|
registry.forGroup(serviceId).registerTypeNames(classNames.toArray(String[]::new)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultiValueMap<String, String> resolveRemoteHttpServices(Set<String> basePackages, Set<String> scanPackagePatterns,
|
||||||
|
Set<String> localServiceTypes) {
|
||||||
|
MultiValueMap<String, String> groupedServices = new LinkedMultiValueMap<>();
|
||||||
|
for (AnnotatedBeanDefinition beanDefinition : scanCandidateComponents(basePackages, RemoteHttpService.class)) {
|
||||||
|
AnnotationMetadata metadata = beanDefinition.getMetadata();
|
||||||
|
if (!metadata.isInterface() || !hasHttpExchange(metadata)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String serviceTypeName = metadata.getClassName();
|
||||||
|
if (!matchesConfiguredPackage(serviceTypeName, scanPackagePatterns)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 同服务场景直接依赖本地 provider,不再生成 HTTP 代理。
|
||||||
|
if (localServiceTypes.contains(serviceTypeName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
groupedServices.add(resolveServiceId(metadata), serviceTypeName);
|
||||||
|
}
|
||||||
|
return groupedServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> resolveLocalServiceTypes(Set<String> basePackages, Set<String> scanPackagePatterns) {
|
||||||
|
MultiValueMap<String, String> localServiceTypes = new LinkedMultiValueMap<>();
|
||||||
|
for (AnnotatedBeanDefinition beanDefinition : scanCandidateComponents(basePackages, RemoteServiceController.class)) {
|
||||||
|
String className = beanDefinition.getMetadata().getClassName();
|
||||||
|
Class<?> beanClass = ClassUtils.resolveClassName(className, this.beanClassLoader);
|
||||||
|
for (Class<?> interfaceType : ClassUtils.getAllInterfacesForClass(beanClass, this.beanClassLoader)) {
|
||||||
|
if (interfaceType.isAnnotationPresent(RemoteHttpService.class)
|
||||||
|
&& matchesConfiguredPackage(interfaceType.getName(), scanPackagePatterns)) {
|
||||||
|
localServiceTypes.add(interfaceType.getName(), className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 同一个远程接口只允许一个本地 provider,否则本地短路目标不明确。
|
||||||
|
localServiceTypes.forEach((serviceTypeName, providerClassNames) -> {
|
||||||
|
if (providerClassNames.size() > 1) {
|
||||||
|
throw new IllegalStateException("Multiple local RemoteServiceController beans found for "
|
||||||
|
+ serviceTypeName + ": " + providerClassNames);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new LinkedHashSet<>(localServiceTypes.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AnnotatedBeanDefinition> scanCandidateComponents(Set<String> basePackages,
|
||||||
|
Class<? extends Annotation> annotationType) {
|
||||||
|
ClassPathScanningCandidateComponentProvider scanner = createScanner(annotationType);
|
||||||
|
List<AnnotatedBeanDefinition> beanDefinitions = new ArrayList<>();
|
||||||
|
for (String basePackage : basePackages) {
|
||||||
|
for (BeanDefinition beanDefinition : scanner.findCandidateComponents(basePackage)) {
|
||||||
|
if (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {
|
||||||
|
beanDefinitions.add(annotatedBeanDefinition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return beanDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassPathScanningCandidateComponentProvider createScanner(Class<? extends Annotation> annotationType) {
|
||||||
|
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
|
||||||
|
@Override
|
||||||
|
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
|
||||||
|
return beanDefinition.getMetadata().isIndependent();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
|
||||||
|
if (this.environment != null) {
|
||||||
|
scanner.setEnvironment(this.environment);
|
||||||
|
}
|
||||||
|
if (this.resourceLoader != null) {
|
||||||
|
scanner.setResourceLoader(this.resourceLoader);
|
||||||
|
}
|
||||||
|
return scanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveServiceId(AnnotationMetadata metadata) {
|
||||||
|
Map<String, Object> attributes = metadata.getAnnotationAttributes(RemoteHttpService.class.getName());
|
||||||
|
String serviceId = attributes != null ? String.valueOf(attributes.get("serviceId")) : StringUtils.EMPTY;
|
||||||
|
if (StringUtils.isBlank(serviceId)) {
|
||||||
|
throw new IllegalStateException("RemoteHttpService serviceId must not be blank: " + metadata.getClassName());
|
||||||
|
}
|
||||||
|
return serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasHttpExchange(AnnotationMetadata metadata) {
|
||||||
|
return metadata.isAnnotated(HttpExchange.class.getName()) || metadata.hasAnnotatedMethods(HttpExchange.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> resolveConfiguredScanPackages() {
|
||||||
|
if (this.environment == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return Binder.get(this.environment).bind(SCAN_PACKAGES_PROPERTY, org.springframework.boot.context.properties.bind.Bindable.listOf(String.class))
|
||||||
|
.orElseGet(Collections::emptyList)
|
||||||
|
.stream()
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> resolveScanBasePackages(Set<String> scanPackagePatterns) {
|
||||||
|
Set<String> basePackages = new LinkedHashSet<>();
|
||||||
|
for (String packagePattern : scanPackagePatterns) {
|
||||||
|
String basePackage = resolveScanBasePackage(packagePattern);
|
||||||
|
if (StringUtils.isNotBlank(basePackage)) {
|
||||||
|
basePackages.add(basePackage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return basePackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveScanBasePackage(String packagePattern) {
|
||||||
|
int wildcardIndex = packagePattern.indexOf('*');
|
||||||
|
if (wildcardIndex < 0) {
|
||||||
|
return packagePattern;
|
||||||
|
}
|
||||||
|
String packagePrefix = packagePattern.substring(0, wildcardIndex);
|
||||||
|
packagePrefix = StringUtils.substringBeforeLast(packagePrefix, ".");
|
||||||
|
return StringUtils.defaultString(packagePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesConfiguredPackage(String className, Set<String> scanPackagePatterns) {
|
||||||
|
if (scanPackagePatterns.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String packageName = ClassUtils.getPackageName(className);
|
||||||
|
for (String packagePattern : scanPackagePatterns) {
|
||||||
|
if (PACKAGE_MATCHER.match(packagePattern, packageName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
package org.dromara.common.http.support;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
|
import org.dromara.common.core.annotation.RemoteHttpService;
|
||||||
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.UndeclaredThrowableException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 远程 HTTP 代理 fallback 包装器.
|
||||||
|
*
|
||||||
|
* <p>仅包装注册器生成的远程 HTTP 代理 Bean。代理调用报错时,
|
||||||
|
* 按接口上声明的 fallback 实现兜底,不处理本地 provider Bean。
|
||||||
|
*
|
||||||
|
* <p>这里故意保持和之前 mock/stub 类似的简单约束:
|
||||||
|
* fallback 必须实现接口本身,且方法签名与接口保持一致。</p>
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public class RemoteHttpFallbackProxyPostProcessor
|
||||||
|
implements BeanPostProcessor, BeanFactoryAware, BeanClassLoaderAware {
|
||||||
|
|
||||||
|
private static final String HTTP_SERVICE_GROUP_NAME_ATTRIBUTE = "httpServiceGroupName";
|
||||||
|
private static final String FALLBACK_WRAPPED_ATTRIBUTE = "remoteHttpFallbackWrapped";
|
||||||
|
|
||||||
|
private ConfigurableListableBeanFactory beanFactory;
|
||||||
|
private ClassLoader beanClassLoader;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanFactory(org.springframework.beans.factory.BeanFactory beanFactory) throws BeansException {
|
||||||
|
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.beanClassLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||||
|
if (bean instanceof FallbackDecoratedProxy) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
Class<?> serviceInterface = resolveRemoteServiceInterface(beanName, bean);
|
||||||
|
if (serviceInterface == null) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
RemoteHttpService remoteHttpService = serviceInterface.getAnnotation(RemoteHttpService.class);
|
||||||
|
if (remoteHttpService == null || remoteHttpService.fallback() == void.class) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
Class<?> fallbackClass = remoteHttpService.fallback();
|
||||||
|
if (!serviceInterface.isAssignableFrom(fallbackClass)) {
|
||||||
|
throw new IllegalStateException("Fallback class must implement remote service interface: "
|
||||||
|
+ fallbackClass.getName() + " -> " + serviceInterface.getName());
|
||||||
|
}
|
||||||
|
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||||
|
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(bean.getClass(), this.beanClassLoader));
|
||||||
|
proxyFactory.addInterface(FallbackDecoratedProxy.class);
|
||||||
|
proxyFactory.addAdvice((MethodInterceptor) invocation -> {
|
||||||
|
Method method = invocation.getMethod();
|
||||||
|
if (method.getDeclaringClass() == Object.class) {
|
||||||
|
return invocation.proceed();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return invocation.proceed();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return invokeFallback(serviceInterface, fallbackClass, method, invocation.getArguments(), ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
markWrapped(beanName);
|
||||||
|
return proxyFactory.getProxy(this.beanClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> resolveRemoteServiceInterface(String beanName, Object bean) {
|
||||||
|
if (this.beanFactory == null || !this.beanFactory.containsBeanDefinition(beanName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(beanName);
|
||||||
|
if (beanDefinition.getAttribute(HTTP_SERVICE_GROUP_NAME_ATTRIBUTE) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (Boolean.TRUE.equals(beanDefinition.getAttribute(FALLBACK_WRAPPED_ATTRIBUTE))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Class<?> beanClass = resolveBeanClass(beanDefinition);
|
||||||
|
if (beanClass != null && beanClass.isInterface() && beanClass.isAnnotationPresent(RemoteHttpService.class)) {
|
||||||
|
return beanClass;
|
||||||
|
}
|
||||||
|
for (Class<?> interfaceType : ClassUtils.getAllInterfacesForClass(bean.getClass(), this.beanClassLoader)) {
|
||||||
|
if (interfaceType.isAnnotationPresent(RemoteHttpService.class)) {
|
||||||
|
return interfaceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> resolveBeanClass(BeanDefinition beanDefinition) {
|
||||||
|
String beanClassName = beanDefinition.getBeanClassName();
|
||||||
|
return beanClassName == null ? null : ClassUtils.resolveClassName(beanClassName, this.beanClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object invokeFallback(Class<?> serviceInterface, Class<?> fallbackClass, Method method, Object[] args, Throwable ex)
|
||||||
|
throws Throwable {
|
||||||
|
Object fallbackInstance = instantiateFallback(fallbackClass);
|
||||||
|
Method fallbackMethod = ReflectionUtils.findMethod(fallbackClass, method.getName(), method.getParameterTypes());
|
||||||
|
if (fallbackMethod == null) {
|
||||||
|
throw unwrap(ex);
|
||||||
|
}
|
||||||
|
ReflectionUtils.makeAccessible(fallbackMethod);
|
||||||
|
return invokeMethod(fallbackInstance, fallbackMethod, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object instantiateFallback(Class<?> fallbackClass) {
|
||||||
|
if (this.beanFactory == null) {
|
||||||
|
throw new IllegalStateException("BeanFactory not initialized for remote fallback: " + fallbackClass.getName());
|
||||||
|
}
|
||||||
|
return this.beanFactory.getBean(fallbackClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markWrapped(String beanName) {
|
||||||
|
if (this.beanFactory == null || !this.beanFactory.containsBeanDefinition(beanName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.beanFactory.getBeanDefinition(beanName).setAttribute(FALLBACK_WRAPPED_ATTRIBUTE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object invokeMethod(Object target, Method method, Object[] args) throws Throwable {
|
||||||
|
try {
|
||||||
|
return method.invoke(target, args);
|
||||||
|
} catch (InvocationTargetException ex) {
|
||||||
|
throw unwrap(ex.getTargetException());
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
throw new IllegalStateException("Could not invoke remote fallback method: " + method, ex);
|
||||||
|
} catch (UndeclaredThrowableException ex) {
|
||||||
|
throw unwrap(ex);
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
throw unwrap(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Throwable unwrap(Throwable throwable) {
|
||||||
|
Throwable current = throwable;
|
||||||
|
while (current instanceof InvocationTargetException invocationTargetException && invocationTargetException.getTargetException() != null) {
|
||||||
|
current = invocationTargetException.getTargetException();
|
||||||
|
}
|
||||||
|
while (current instanceof UndeclaredThrowableException undeclaredThrowableException && undeclaredThrowableException.getUndeclaredThrowable() != null) {
|
||||||
|
current = undeclaredThrowableException.getUndeclaredThrowable();
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface FallbackDecoratedProxy {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.dromara.common.http.config.RemoteHttpAutoConfiguration
|
||||||
@@ -20,12 +20,6 @@
|
|||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package org.dromara.common.loadbalance.config;
|
|
||||||
|
|
||||||
import org.springframework.boot.EnvironmentPostProcessor;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.env.ConfigurableEnvironment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dubbo自定义负载均衡配置注入
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
|
||||||
System.setProperty("dubbo.consumer.loadbalance", "customDubboLoadBalancer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return Ordered.HIGHEST_PRECEDENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package org.dromara.common.loadbalance.core;
|
|
||||||
|
|
||||||
import cn.hutool.core.net.NetUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.dubbo.common.URL;
|
|
||||||
import org.apache.dubbo.rpc.Invocation;
|
|
||||||
import org.apache.dubbo.rpc.Invoker;
|
|
||||||
import org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义 Dubbo 负载均衡算法
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class CustomDubboLoadBalancer extends AbstractLoadBalance {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
|
||||||
for (Invoker<T> invoker : invokers) {
|
|
||||||
if (NetUtil.localIpv4s().contains(invoker.getUrl().getHost())) {
|
|
||||||
return invoker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return invokers.get(ThreadLocalRandom.current().nextInt(invokers.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
customDubboLoadBalancer=org.dromara.common.loadbalance.core.CustomDubboLoadBalancer
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
|
||||||
org.dromara.common.loadbalance.config.CustomEnvironmentPostProcessor
|
|
||||||
@@ -27,12 +27,6 @@
|
|||||||
<artifactId>ruoyi-common-json</artifactId>
|
<artifactId>ruoyi-common-json</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import cn.hutool.http.useragent.UserAgent;
|
import cn.hutool.http.useragent.UserAgent;
|
||||||
import cn.hutool.http.useragent.UserAgentUtil;
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.common.core.constant.Constants;
|
import org.dromara.common.core.constant.Constants;
|
||||||
import org.dromara.common.core.utils.ServletUtils;
|
import org.dromara.common.core.utils.ServletUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
@@ -27,12 +27,11 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class LogEventListener {
|
public class LogEventListener {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteLogService remoteLogService;
|
||||||
private RemoteLogService remoteLogService;
|
private final RemoteClientService remoteClientService;
|
||||||
@DubboReference
|
|
||||||
private RemoteClientService remoteClientService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存系统日志记录
|
* 保存系统日志记录
|
||||||
|
|||||||
@@ -21,12 +21,6 @@
|
|||||||
<artifactId>ruoyi-common-satoken</artifactId>
|
<artifactId>ruoyi-common-satoken</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
|
|||||||
import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler;
|
import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler;
|
||||||
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
|
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
|
||||||
import org.dromara.common.mybatis.service.SysDataScopeService;
|
import org.dromara.common.mybatis.service.SysDataScopeService;
|
||||||
|
import org.dromara.system.api.RemoteDataScopeService;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
@@ -117,8 +118,8 @@ public class MybatisPlusConfiguration {
|
|||||||
* 数据权限处理实现
|
* 数据权限处理实现
|
||||||
*/
|
*/
|
||||||
@Bean("sdss")
|
@Bean("sdss")
|
||||||
public SysDataScopeService sysDataScopeService() {
|
public SysDataScopeService sysDataScopeService(RemoteDataScopeService remoteDataScopeService) {
|
||||||
return new SysDataScopeService();
|
return new SysDataScopeService(remoteDataScopeService);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.dromara.common.mybatis.filter;
|
|
||||||
|
|
||||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.dubbo.common.constants.CommonConstants;
|
|
||||||
import org.apache.dubbo.common.extension.Activate;
|
|
||||||
import org.apache.dubbo.rpc.*;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dubbo 数据权限参数传递
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Activate(group = {CommonConstants.CONSUMER})
|
|
||||||
public class DubboDataPermissionFilter implements Filter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
|
||||||
RpcServiceContext context = RpcContext.getServiceContext();
|
|
||||||
Map<String, Object> dataPermissionContext = DataPermissionHelper.getContext();
|
|
||||||
context.setObjectAttachment(DataPermissionHelper.DATA_PERMISSION_KEY, dataPermissionContext);
|
|
||||||
return invoker.invoke(invocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.dromara.common.mybatis.service;
|
package org.dromara.common.mybatis.service;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.constant.CacheNames;
|
import org.dromara.common.core.constant.CacheNames;
|
||||||
import org.dromara.system.api.RemoteDataScopeService;
|
import org.dromara.system.api.RemoteDataScopeService;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
@@ -15,10 +15,10 @@ import org.springframework.stereotype.Service;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Service("sdss")
|
@Service("sdss")
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SysDataScopeService {
|
public class SysDataScopeService {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteDataScopeService remoteDataScopeService;
|
||||||
private RemoteDataScopeService remoteDataScopeService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取角色自定义权限语句
|
* 获取角色自定义权限语句
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
dubboDataPermissionFilter=org.dromara.common.mybatis.filter.DubboDataPermissionFilter
|
|
||||||
@@ -12,7 +12,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
public class RateLimiterConfig {
|
public class RateLimiterConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RateLimiterAspect rateLimiterAspect() {
|
public RateLimiterAspect plusRateLimiterAspect() {
|
||||||
return new RateLimiterAspect();
|
return new RateLimiterAspect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,6 @@
|
|||||||
<artifactId>ruoyi-common-core</artifactId>
|
<artifactId>ruoyi-common-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo.extensions</groupId>
|
|
||||||
<artifactId>dubbo-filter-seata</artifactId>
|
|
||||||
<version>3.3.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringBoot Seata -->
|
<!-- SpringBoot Seata -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
@@ -37,10 +31,6 @@
|
|||||||
<groupId>org.apache.logging.log4j</groupId>
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
<artifactId>*</artifactId>
|
<artifactId>*</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.dubbo.extensions</groupId>
|
|
||||||
<artifactId>dubbo-filter-seata</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>io.seata</groupId>
|
<groupId>io.seata</groupId>
|
||||||
<artifactId>seata-spring-boot-starter</artifactId>
|
<artifactId>seata-spring-boot-starter</artifactId>
|
||||||
|
|||||||
@@ -28,11 +28,5 @@
|
|||||||
<artifactId>ruoyi-api-system</artifactId>
|
<artifactId>ruoyi-api-system</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ package org.dromara.common.core.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.constant.CacheNames;
|
import org.dromara.common.core.constant.CacheNames;
|
||||||
import org.dromara.common.core.service.DictService;
|
import org.dromara.common.core.service.DictService;
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.system.api.RemoteDictService;
|
import org.dromara.system.api.RemoteDictService;
|
||||||
import org.dromara.system.api.domain.vo.RemoteDictDataVo;
|
import org.dromara.system.api.domain.vo.RemoteDictDataVo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -21,13 +20,12 @@ import java.util.stream.Collectors;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class DictServiceImpl implements DictService {
|
public class DictServiceImpl implements DictService {
|
||||||
|
|
||||||
@Autowired
|
private final Cache<Object, Object> ceffeine;
|
||||||
private Cache<Object, Object> ceffeine;
|
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteDictService remoteDictService;
|
||||||
private RemoteDictService remoteDictService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据字典类型和字典值获取字典标签
|
* 根据字典类型和字典值获取字典标签
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.dromara.common.core.service.impl;
|
package org.dromara.common.core.service.impl;
|
||||||
|
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.service.PermissionService;
|
import org.dromara.common.core.service.PermissionService;
|
||||||
import org.dromara.system.api.RemotePermissionService;
|
import org.dromara.system.api.RemotePermissionService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -13,10 +13,10 @@ import java.util.Set;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class PermissionServiceImpl implements PermissionService {
|
public class PermissionServiceImpl implements PermissionService {
|
||||||
|
|
||||||
@DubboReference
|
private final RemotePermissionService remotePermissionService;
|
||||||
private RemotePermissionService remotePermissionService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getRolePermission(Long userId) {
|
public Set<String> getRolePermission(Long userId) {
|
||||||
|
|||||||
@@ -27,11 +27,6 @@
|
|||||||
<artifactId>ruoyi-common-service-impl</artifactId>
|
<artifactId>ruoyi-common-service-impl</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-api-resource</artifactId>
|
<artifactId>ruoyi-api-resource</artifactId>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.dromara.common.translation.core.handler.TranslationBeanSerializerModi
|
|||||||
import org.dromara.common.translation.core.handler.TranslationHandler;
|
import org.dromara.common.translation.core.handler.TranslationHandler;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||||
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import tools.jackson.databind.ser.SerializerFactory;
|
import tools.jackson.databind.ser.SerializerFactory;
|
||||||
@@ -42,13 +43,4 @@ public class TranslationConfig {
|
|||||||
TranslationHandler.TRANSLATION_MAPPER.putAll(map);
|
TranslationHandler.TRANSLATION_MAPPER.putAll(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JsonMapperBuilderCustomizer translationInitCustomizer() {
|
|
||||||
return builder -> {
|
|
||||||
SerializerFactory serializerFactory = builder.serializerFactory();
|
|
||||||
serializerFactory = serializerFactory.withSerializerModifier(new TranslationBeanSerializerModifier());
|
|
||||||
builder.serializerFactory(serializerFactory);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.dromara.common.translation.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.translation.core.handler.TranslationBeanSerializerModifier;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import tools.jackson.databind.ser.SerializerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻译模块额外修改jackson配置
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@AutoConfiguration(before = JacksonAutoConfiguration.class)
|
||||||
|
public class TranslationJacksonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public JsonMapperBuilderCustomizer translationInitCustomizer() {
|
||||||
|
return builder -> {
|
||||||
|
SerializerFactory serializerFactory = builder.serializerFactory();
|
||||||
|
serializerFactory = serializerFactory.withSerializerModifier(new TranslationBeanSerializerModifier());
|
||||||
|
builder.serializerFactory(serializerFactory);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import org.dromara.common.translation.constant.TransConstant;
|
|||||||
import org.dromara.common.translation.core.TranslationInterface;
|
import org.dromara.common.translation.core.TranslationInterface;
|
||||||
import org.dromara.system.api.RemoteDeptService;
|
import org.dromara.system.api.RemoteDeptService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门翻译实现
|
* 部门翻译实现
|
||||||
@@ -16,8 +15,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
|
|||||||
@TranslationType(type = TransConstant.DEPT_ID_TO_NAME)
|
@TranslationType(type = TransConstant.DEPT_ID_TO_NAME)
|
||||||
public class DeptNameTranslationImpl implements TranslationInterface<String> {
|
public class DeptNameTranslationImpl implements TranslationInterface<String> {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteDeptService remoteDeptService;
|
||||||
private RemoteDeptService remoteDeptService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.dromara.common.translation.core.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
import org.dromara.common.core.constant.CacheNames;
|
import org.dromara.common.core.constant.CacheNames;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.redis.utils.CacheUtils;
|
import org.dromara.common.redis.utils.CacheUtils;
|
||||||
@@ -23,8 +22,7 @@ import java.util.List;
|
|||||||
@TranslationType(type = TransConstant.USER_ID_TO_NICKNAME)
|
@TranslationType(type = TransConstant.USER_ID_TO_NICKNAME)
|
||||||
public class NicknameTranslationImpl implements TranslationInterface<String> {
|
public class NicknameTranslationImpl implements TranslationInterface<String> {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import org.dromara.common.translation.constant.TransConstant;
|
|||||||
import org.dromara.common.translation.core.TranslationInterface;
|
import org.dromara.common.translation.core.TranslationInterface;
|
||||||
import org.dromara.resource.api.RemoteFileService;
|
import org.dromara.resource.api.RemoteFileService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OSS翻译实现
|
* OSS翻译实现
|
||||||
@@ -16,8 +15,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
|
|||||||
@TranslationType(type = TransConstant.OSS_ID_TO_URL)
|
@TranslationType(type = TransConstant.OSS_ID_TO_URL)
|
||||||
public class OssUrlTranslationImpl implements TranslationInterface<String> {
|
public class OssUrlTranslationImpl implements TranslationInterface<String> {
|
||||||
|
|
||||||
@DubboReference(mock = "true")
|
private final RemoteFileService remoteFileService;
|
||||||
private RemoteFileService remoteFileService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.dromara.common.translation.constant.TransConstant;
|
|||||||
import org.dromara.common.translation.core.TranslationInterface;
|
import org.dromara.common.translation.core.TranslationInterface;
|
||||||
import org.dromara.system.api.RemoteUserService;
|
import org.dromara.system.api.RemoteUserService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.dubbo.config.annotation.DubboReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户名翻译实现
|
* 用户名翻译实现
|
||||||
@@ -20,8 +19,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
|
|||||||
@TranslationType(type = TransConstant.USER_ID_TO_NAME)
|
@TranslationType(type = TransConstant.USER_ID_TO_NAME)
|
||||||
public class UserNameTranslationImpl implements TranslationInterface<String> {
|
public class UserNameTranslationImpl implements TranslationInterface<String> {
|
||||||
|
|
||||||
@DubboReference
|
private final RemoteUserService remoteUserService;
|
||||||
private RemoteUserService remoteUserService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String translation(Object key, String other) {
|
public String translation(Object key, String other) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
org.dromara.common.translation.config.TranslationConfig
|
org.dromara.common.translation.config.TranslationConfig
|
||||||
|
org.dromara.common.translation.config.TranslationJacksonConfig
|
||||||
org.dromara.common.translation.core.impl.DeptNameTranslationImpl
|
org.dromara.common.translation.core.impl.DeptNameTranslationImpl
|
||||||
org.dromara.common.translation.core.impl.DictTypeTranslationImpl
|
org.dromara.common.translation.core.impl.DictTypeTranslationImpl
|
||||||
org.dromara.common.translation.core.impl.OssUrlTranslationImpl
|
org.dromara.common.translation.core.impl.OssUrlTranslationImpl
|
||||||
|
|||||||
@@ -52,24 +52,6 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.dreamlu</groupId>
|
|
||||||
<artifactId>mica-metrics</artifactId>
|
|
||||||
<version>2.7.6</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>net.dreamlu</groupId>
|
|
||||||
<artifactId>mica-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.dreamlu</groupId>
|
|
||||||
<artifactId>mica-core</artifactId>
|
|
||||||
<version>2.7.6</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class GlobalExceptionHandler {
|
|||||||
*/
|
*/
|
||||||
@ResponseStatus(org.springframework.http.HttpStatus.UNAUTHORIZED)
|
@ResponseStatus(org.springframework.http.HttpStatus.UNAUTHORIZED)
|
||||||
@ExceptionHandler(SseException.class)
|
@ExceptionHandler(SseException.class)
|
||||||
public String handleNotLoginException(SseException e, HttpServletRequest request) {
|
public String handleSseException(SseException e, HttpServletRequest request) {
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
log.debug("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
|
log.debug("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
|
||||||
return JsonUtils.toJsonString(R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"));
|
return JsonUtils.toJsonString(R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"));
|
||||||
@@ -140,7 +140,7 @@ public class GlobalExceptionHandler {
|
|||||||
* sse 连接超时异常 不需要处理
|
* sse 连接超时异常 不需要处理
|
||||||
*/
|
*/
|
||||||
@ExceptionHandler(AsyncRequestTimeoutException.class)
|
@ExceptionHandler(AsyncRequestTimeoutException.class)
|
||||||
public void handleRuntimeException(AsyncRequestTimeoutException e) {
|
public void handleAsyncRequestTimeoutException(AsyncRequestTimeoutException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
org.dromara.common.web.config.FilterConfig
|
org.dromara.common.web.config.FilterConfig
|
||||||
org.dromara.common.web.config.I18nConfig
|
org.dromara.common.web.config.I18nConfig
|
||||||
org.dromara.common.web.config.UndertowConfig
|
|
||||||
org.dromara.common.web.config.ResourcesConfig
|
org.dromara.common.web.config.ResourcesConfig
|
||||||
|
|||||||
@@ -47,11 +47,6 @@
|
|||||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dromara</groupId>
|
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-redis</artifactId>
|
<artifactId>ruoyi-common-redis</artifactId>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class AuthFilter implements WebMvcConfigurer {
|
|||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
.addPathPatterns("/**")
|
.addPathPatterns("/**")
|
||||||
.excludePathPatterns("/favicon.ico", "/actuator", "/actuator/**", "/resource/sse");
|
.excludePathPatterns("/favicon.ico", "/actuator", "/actuator/**", "/resource/sse" , "/error");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,13 +2,19 @@ package org.dromara.gateway.handler;
|
|||||||
|
|
||||||
import cn.dev33.satoken.exception.NotLoginException;
|
import cn.dev33.satoken.exception.NotLoginException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.constant.HttpStatus;
|
import org.dromara.common.core.constant.HttpStatus;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网关统一异常处理
|
* 网关统一异常处理
|
||||||
*
|
*
|
||||||
@@ -19,23 +25,34 @@ import org.springframework.web.server.ResponseStatusException;
|
|||||||
public class GatewayExceptionHandler {
|
public class GatewayExceptionHandler {
|
||||||
|
|
||||||
@ExceptionHandler(NotLoginException.class)
|
@ExceptionHandler(NotLoginException.class)
|
||||||
public R<Void> handleNotLogin(HttpServletRequest request, NotLoginException ex) {
|
public void handleNotLogin(HttpServletRequest request, HttpServletResponse response, NotLoginException ex) throws IOException {
|
||||||
log.warn("[网关认证失败]请求路径:{},异常信息:{}", request.getRequestURI(), ex.getMessage());
|
log.warn("[网关认证失败]请求路径:{},异常信息:{}", request.getRequestURI(), ex.getMessage());
|
||||||
return R.fail(HttpStatus.UNAUTHORIZED, ex.getMessage());
|
writeJson(response, HttpStatus.UNAUTHORIZED, ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Throwable.class)
|
@ExceptionHandler(Throwable.class)
|
||||||
public R<Void> handle(HttpServletRequest request, Throwable ex) {
|
public void handle(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws IOException {
|
||||||
|
int code;
|
||||||
String msg;
|
String msg;
|
||||||
if ("NotFoundException".equals(ex.getClass().getSimpleName())) {
|
if ("NotFoundException".equals(ex.getClass().getSimpleName())) {
|
||||||
|
code = HttpStatus.NOT_FOUND;
|
||||||
msg = "服务未找到";
|
msg = "服务未找到";
|
||||||
} else if (ex instanceof ResponseStatusException responseStatusException) {
|
} else if (ex instanceof ResponseStatusException responseStatusException) {
|
||||||
|
code = responseStatusException.getStatusCode().value();
|
||||||
msg = responseStatusException.getMessage();
|
msg = responseStatusException.getMessage();
|
||||||
} else {
|
} else {
|
||||||
|
code = HttpStatus.ERROR;
|
||||||
msg = "内部服务器错误";
|
msg = "内部服务器错误";
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error("[网关异常处理]请求路径:{},异常信息:{}", request.getRequestURI(), ex.getMessage(), ex);
|
log.error("[网关异常处理]请求路径:{},异常信息:{}", request.getRequestURI(), ex.getMessage(), ex);
|
||||||
return R.fail(msg);
|
writeJson(response, code, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeJson(HttpServletResponse response, int code, String msg) throws IOException {
|
||||||
|
response.setStatus(code);
|
||||||
|
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||||
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
response.getWriter().write(JsonUtils.toJsonString(R.fail(code, msg)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,15 +51,14 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-security</artifactId>
|
<artifactId>ruoyi-common-security</artifactId>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.dromara.gen;
|
package org.dromara.gen;
|
||||||
|
|
||||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||||
@@ -10,7 +9,6 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@EnableDubbo
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class RuoYiGenApplication {
|
public class RuoYiGenApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.dromara.job;
|
package org.dromara.job;
|
||||||
|
|
||||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||||
@@ -10,7 +9,6 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@EnableDubbo
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class RuoYiJobApplication {
|
public class RuoYiJobApplication {
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,12 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-dubbo</artifactId>
|
<artifactId>ruoyi-common-seata</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-seata</artifactId>
|
<artifactId>ruoyi-common-http</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.dromara.resource;
|
package org.dromara.resource;
|
||||||
|
|
||||||
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||||
@@ -11,7 +10,6 @@ import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
|||||||
*
|
*
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@EnableDubbo
|
|
||||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
||||||
public class RuoYiResourceApplication {
|
public class RuoYiResourceApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.dromara.resource.dubbo;
|
|||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
@@ -17,7 +17,6 @@ import org.dromara.resource.domain.SysOssExt;
|
|||||||
import org.dromara.resource.domain.bo.SysOssBo;
|
import org.dromara.resource.domain.bo.SysOssBo;
|
||||||
import org.dromara.resource.domain.vo.SysOssVo;
|
import org.dromara.resource.domain.vo.SysOssVo;
|
||||||
import org.dromara.resource.service.ISysOssService;
|
import org.dromara.resource.service.ISysOssService;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,9 +27,8 @@ import java.util.List;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@DubboService
|
@RemoteServiceController
|
||||||
public class RemoteFileServiceImpl implements RemoteFileService {
|
public class RemoteFileServiceImpl implements RemoteFileService {
|
||||||
|
|
||||||
private final ISysOssService sysOssService;
|
private final ISysOssService sysOssService;
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package org.dromara.resource.dubbo;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.mail.utils.MailUtils;
|
import org.dromara.common.mail.utils.MailUtils;
|
||||||
import org.dromara.resource.api.RemoteMailService;
|
import org.dromara.resource.api.RemoteMailService;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮件服务
|
* 邮件服务
|
||||||
@@ -15,8 +14,7 @@ import org.springframework.stereotype.Service;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service
|
@RemoteServiceController
|
||||||
@DubboService
|
|
||||||
public class RemoteMailServiceImpl implements RemoteMailService {
|
public class RemoteMailServiceImpl implements RemoteMailService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package org.dromara.resource.dubbo;
|
|||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.dubbo.config.annotation.DubboService;
|
import org.dromara.common.http.annotation.RemoteServiceController;
|
||||||
import org.dromara.common.sse.dto.SseMessageDTO;
|
import org.dromara.common.sse.dto.SseMessageDTO;
|
||||||
import org.dromara.common.sse.utils.SseMessageUtils;
|
import org.dromara.common.sse.utils.SseMessageUtils;
|
||||||
import org.dromara.resource.api.RemoteMessageService;
|
import org.dromara.resource.api.RemoteMessageService;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -17,8 +16,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Service
|
@RemoteServiceController
|
||||||
@DubboService
|
|
||||||
public class RemoteMessageServiceImpl implements RemoteMessageService {
|
public class RemoteMessageServiceImpl implements RemoteMessageService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user