[+]
This commit is contained in:
@@ -14,8 +14,8 @@ import org.springframework.stereotype.Component;
|
||||
* @author acgist
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Component
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Client {
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import java.lang.annotation.Target;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 监听
|
||||
* 事件监听
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Component
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface EventListener {
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ import org.springframework.stereotype.Component;
|
||||
* @author acgist
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Component
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Manager {
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ import org.springframework.stereotype.Component;
|
||||
* @author acgist
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Component
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Protocol {
|
||||
|
||||
|
||||
@@ -90,11 +90,9 @@ public class BootAutoConfiguration {
|
||||
|
||||
@Value("${spring.application.name:taoyao}")
|
||||
private String name;
|
||||
@Value("${taoyao.webrtc.framework:MOON}")
|
||||
private String framework;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@@ -169,13 +167,12 @@ public class BootAutoConfiguration {
|
||||
log.info("用户目录:{}", System.getProperty("user.home"));
|
||||
log.info("临时目录:{}", System.getProperty("java.io.tmpdir"));
|
||||
log.info("文件编码:{}", System.getProperty("file.encoding"));
|
||||
this.context.getBeansOfType(TaskExecutor.class).forEach((k, v) -> {
|
||||
this.applicationContext.getBeansOfType(TaskExecutor.class).forEach((k, v) -> {
|
||||
log.info("系统任务线程池:{}-{}", k, v);
|
||||
});
|
||||
this.context.getBeansOfType(TaskScheduler.class).forEach((k, v) -> {
|
||||
this.applicationContext.getBeansOfType(TaskScheduler.class).forEach((k, v) -> {
|
||||
log.info("系统定时任务线程池:{}-{}", k, v);
|
||||
});
|
||||
log.info("WebRTC架构:{}", this.framework);
|
||||
this.registerException();
|
||||
}
|
||||
|
||||
@@ -203,7 +200,6 @@ public class BootAutoConfiguration {
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
log.info("系统关闭:{}", this.name);
|
||||
// TODO:通知关闭
|
||||
// 刷出日志缓存
|
||||
final ILoggerFactory factory = LoggerFactory.getILoggerFactory();
|
||||
if (factory instanceof LoggerContext context) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
import com.acgist.taoyao.boot.property.SecurityProperties;
|
||||
import com.acgist.taoyao.boot.property.TaoyaoProperties;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
@@ -31,9 +30,15 @@ import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
@Configuration
|
||||
@ConditionalOnClass(OpenAPI.class)
|
||||
public class SpringDocAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Basic认证
|
||||
*/
|
||||
private static final String BASIC = "Basic";
|
||||
|
||||
@Value("${server.port:8888}")
|
||||
private Integer port;
|
||||
|
||||
@Autowired
|
||||
private TaoyaoProperties taoyaoProperties;
|
||||
|
||||
@@ -101,7 +106,7 @@ public class SpringDocAutoConfiguration {
|
||||
private List<SecurityRequirement> buildSecurity() {
|
||||
return List.of(
|
||||
new SecurityRequirement()
|
||||
.addList(SecurityProperties.BASIC)
|
||||
.addList(BASIC)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,7 +115,7 @@ public class SpringDocAutoConfiguration {
|
||||
*/
|
||||
private Components buildComponents() {
|
||||
return new Components()
|
||||
.addSecuritySchemes(SecurityProperties.BASIC, this.buildSecurityScheme());
|
||||
.addSecuritySchemes(BASIC, this.buildSecurityScheme());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +123,8 @@ public class SpringDocAutoConfiguration {
|
||||
*/
|
||||
private SecurityScheme buildSecurityScheme() {
|
||||
return new SecurityScheme()
|
||||
.name(SecurityProperties.BASIC)
|
||||
.scheme(SecurityProperties.BASIC)
|
||||
.name(BASIC)
|
||||
.scheme(BASIC)
|
||||
.in(SecurityScheme.In.HEADER)
|
||||
.type(SecurityScheme.Type.HTTP);
|
||||
}
|
||||
|
||||
@@ -20,15 +20,15 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class WebMvcConfigurerAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
this.context.getBeansOfType(InterceptorAdapter.class).entrySet().stream()
|
||||
this.applicationContext.getBeansOfType(InterceptorAdapter.class).entrySet().stream()
|
||||
.sorted((a, z) -> a.getValue().compareTo(z.getValue()))
|
||||
.forEach(entry -> {
|
||||
final InterceptorAdapter value = entry.getValue();
|
||||
log.info("加载拦截器:{}-{}", entry.getKey(), value.name());
|
||||
log.info("加载拦截器:{} - {}", String.format("%-32s", entry.getKey()), value.name());
|
||||
registry.addInterceptor(value).addPathPatterns(value.pathPattern());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,29 +10,29 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 请求响应头部
|
||||
* 消息头部
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema( title = "请求响应头部", description = "请求响应头部")
|
||||
@Schema( title = "消息头部", description = "消息头部")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Header implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* 请求响应版本
|
||||
* 消息版本
|
||||
*/
|
||||
@Schema(title = "请求响应版本", description = "请求响应版本")
|
||||
@Schema(title = "消息版本", description = "消息版本")
|
||||
private String v;
|
||||
/**
|
||||
* 请求响应标识
|
||||
* 消息标识
|
||||
*/
|
||||
@Schema(title = "请求响应标识", description = "请求响应标识")
|
||||
@Schema(title = "消息标识", description = "消息标识")
|
||||
private String id;
|
||||
/**
|
||||
* 终端标识
|
||||
@@ -45,4 +45,9 @@ public class Header implements Serializable {
|
||||
@Schema(title = "协议标识", description = "协议标识")
|
||||
private String signal;
|
||||
|
||||
@Override
|
||||
public Header clone() {
|
||||
return new Header(this.v, this.id, this.sn, this.signal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 请求响应消息
|
||||
* 消息
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema(title = "请求响应消息", description = "请求响应消息")
|
||||
@Schema(title = "消息", description = "消息")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@@ -29,28 +29,28 @@ public class Message implements Cloneable, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 响应编码
|
||||
* 状态编码
|
||||
*/
|
||||
@Schema(title = "响应编码", description = "响应消息标识响应状态")
|
||||
@Schema(title = "状态编码", description = "状态编码")
|
||||
private String code;
|
||||
/**
|
||||
* 响应描述
|
||||
* 状态描述
|
||||
*/
|
||||
@Schema(title = "响应描述", description = "响应消息描述响应编码")
|
||||
@Schema(title = "状态描述", description = "状态描述")
|
||||
private String message;
|
||||
/**
|
||||
* 请求响应头部
|
||||
* 消息头部
|
||||
*/
|
||||
@Schema(title = "请求响应头部", description = "请求响应头部")
|
||||
@Schema(title = "消息头部", description = "消息头部")
|
||||
private Header header;
|
||||
/**
|
||||
* 请求响应主体
|
||||
* 消息主体
|
||||
*/
|
||||
@Schema(title = "请求响应主体", description = "请求响应主体")
|
||||
@Schema(title = "消息主体", description = "消息主体")
|
||||
private Object body;
|
||||
|
||||
/**
|
||||
* 覆盖
|
||||
* 重载方法
|
||||
*
|
||||
* @param code 状态编码
|
||||
*/
|
||||
@@ -60,27 +60,20 @@ public class Message implements Cloneable, Serializable {
|
||||
|
||||
/**
|
||||
* @param code 状态编码
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public Message setCode(MessageCode code) {
|
||||
this.code = code.getCode();
|
||||
this.message = code.getMessage();
|
||||
return this;
|
||||
public void setCode(MessageCode code) {
|
||||
this.setCode(code, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 响应编码
|
||||
* @param message 响应描述
|
||||
* @param code 状态编码
|
||||
* @param message 状态描述
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public Message setCode(MessageCode code, String message) {
|
||||
if(StringUtils.isEmpty(message)) {
|
||||
message = code.getMessage();
|
||||
}
|
||||
this.code = code.getCode();
|
||||
this.message = message;
|
||||
this.message = StringUtils.isEmpty(message) ? code.getMessage() : message;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -92,14 +85,13 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param body 主体
|
||||
* @param body 消息主体
|
||||
*
|
||||
* @return 成功消息
|
||||
*/
|
||||
public static final Message success(Object body) {
|
||||
final Message message = new Message();
|
||||
message.code = MessageCode.CODE_0000.getCode();
|
||||
message.message = MessageCode.CODE_0000.getMessage();
|
||||
message.setCode(MessageCode.CODE_0000, null);
|
||||
message.body = body;
|
||||
return message;
|
||||
}
|
||||
@@ -112,16 +104,7 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message 主体
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(String message) {
|
||||
return fail(null, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 响应编码
|
||||
* @param code 状态编码
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
@@ -130,8 +113,37 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 响应编码
|
||||
* @param message 响应描述
|
||||
* @param code 状态编码
|
||||
* @param body 消息主体
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(MessageCode code, Object body) {
|
||||
return fail(code, null, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message 状态描述
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(String message) {
|
||||
return fail(null, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message 状态描述
|
||||
* @param body 消息主体
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(String message, Object body) {
|
||||
return fail(null, message, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 状态编码
|
||||
* @param message 状态描述
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
@@ -140,58 +152,33 @@ public class Message implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 响应编码
|
||||
* @param body 主体
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(MessageCode code, Object body) {
|
||||
return fail(code, null, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param code 响应编码
|
||||
* @param message 响应描述
|
||||
* @param body 主体
|
||||
* @param code 状态编码
|
||||
* @param message 状态描述
|
||||
* @param body 消息主体
|
||||
*
|
||||
* @return 错误消息
|
||||
*/
|
||||
public static final Message fail(MessageCode code, String message, Object body) {
|
||||
if(code == null) {
|
||||
code = MessageCode.CODE_9999;
|
||||
}
|
||||
if (StringUtils.isEmpty(message)) {
|
||||
message = code.getMessage();
|
||||
}
|
||||
final Message failMessage = new Message();
|
||||
failMessage.code = code.getCode();
|
||||
failMessage.message = message;
|
||||
failMessage.setCode(code == null ? MessageCode.CODE_9999 : code, message);
|
||||
failMessage.body = body;
|
||||
return failMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message clone() {
|
||||
try {
|
||||
return (Message) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return new Message(this.code, this.message, this.header, this.body);
|
||||
}
|
||||
return new Message(this.code, this.message, this.header.clone(), this.body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆排除主体
|
||||
* 克隆排除消息主体
|
||||
*
|
||||
* @return 请求响应消息
|
||||
* @return 克隆消息
|
||||
*/
|
||||
public Message cloneWidthoutBody() {
|
||||
try {
|
||||
final Message message = (Message) super.clone();
|
||||
message.setBody(null);
|
||||
return message;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return new Message(this.code, this.message, this.header, null);
|
||||
}
|
||||
final Message message = this.clone();
|
||||
message.setBody(null);
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,10 +5,10 @@ import lombok.Getter;
|
||||
/**
|
||||
* 状态编码
|
||||
*
|
||||
* 1xxx=前置错误:数据校验
|
||||
* 2xxx=内部错误
|
||||
* 3xxx=请求错误:HTTP错误
|
||||
* 9999=未知错误
|
||||
* 1xxx = 前置错误
|
||||
* 2xxx = 内部错误
|
||||
* 3xxx = 请求错误
|
||||
* 9999 = 未知错误
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@@ -43,8 +43,8 @@ public enum MessageCode {
|
||||
/**
|
||||
* HTTP状态编码前缀
|
||||
*/
|
||||
public static final String HTTP_STATUS = "3";
|
||||
|
||||
private static final String HTTP_STATUS = "3";
|
||||
|
||||
/**
|
||||
* 状态编码
|
||||
*/
|
||||
@@ -80,7 +80,7 @@ public enum MessageCode {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status HTTPStatus
|
||||
* @param status HTTP Status
|
||||
*
|
||||
* @return 状态编码
|
||||
*/
|
||||
|
||||
@@ -7,59 +7,59 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 媒体终端配置
|
||||
* 媒体服务配置
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Schema(title = "Mediasoup配置", description = "Mediasoup配置")
|
||||
@Schema(title = "媒体服务配置", description = "媒体服务配置")
|
||||
public class MediasoupProperties {
|
||||
|
||||
/**
|
||||
* Mediasoup名称
|
||||
* 名称
|
||||
*/
|
||||
@Schema(title = "Mediasoup名称", description = "Mediasoup名称")
|
||||
@Schema(title = "名称", description = "名称")
|
||||
private String name;
|
||||
/**
|
||||
* Mediasoup主机
|
||||
* 是否启用
|
||||
*/
|
||||
@Schema(title = "Mediasoup主机", description = "Mediasoup主机")
|
||||
@Schema(title = "是否启用", description = "是否启用")
|
||||
private Boolean enabled;
|
||||
/**
|
||||
* 主机
|
||||
*/
|
||||
@Schema(title = "主机", description = "主机")
|
||||
private String host;
|
||||
/**
|
||||
* Mediasoup端口
|
||||
* 端口
|
||||
*/
|
||||
@Schema(title = "Mediasoup端口", description = "Mediasoup端口")
|
||||
@Schema(title = "端口", description = "端口")
|
||||
private Integer port;
|
||||
/**
|
||||
* Mediasoup协议
|
||||
* 协议
|
||||
*/
|
||||
@Schema(title = "Mediasoup协议", description = "Mediasoup协议")
|
||||
@Schema(title = "协议", description = "协议")
|
||||
private String schema;
|
||||
/**
|
||||
* Mediasoup地址
|
||||
* 用户
|
||||
*/
|
||||
@Schema(title = "Mediasoup地址", description = "Mediasoup地址")
|
||||
private String websocket;
|
||||
/**
|
||||
* Mediasoup用户
|
||||
*/
|
||||
@Schema(title = "Mediasoup用户", description = "Mediasoup用户")
|
||||
@Schema(title = "用户", description = "用户")
|
||||
@JsonIgnore
|
||||
private String username;
|
||||
/**
|
||||
* Mediasoup密码
|
||||
* 密码
|
||||
*/
|
||||
@Schema(title = "Mediasoup密码", description = "Mediasoup密码")
|
||||
@Schema(title = "密码", description = "密码")
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* @return 完整Mediasoup地址
|
||||
* @return 完整地址
|
||||
*/
|
||||
@Schema(title = "完整Mediasoup地址", description = "完整Mediasoup地址")
|
||||
@Schema(title = "完整地址", description = "完整地址")
|
||||
public String getAddress() {
|
||||
return this.schema + "://" + this.host + ":" + this.port + this.websocket;
|
||||
return this.schema + "://" + this.host + ":" + this.port;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,25 +17,25 @@ import lombok.Setter;
|
||||
public class NodeProperties {
|
||||
|
||||
/**
|
||||
* 节点主机
|
||||
* 主机
|
||||
*/
|
||||
@Schema(title = "节点主机", description = "节点主机")
|
||||
@Schema(title = "主机", description = "主机")
|
||||
private String host;
|
||||
/**
|
||||
* 节点端口
|
||||
* 端口
|
||||
*/
|
||||
@Schema(title = "节点端口", description = "节点端口")
|
||||
@Schema(title = "端口", description = "端口")
|
||||
private Integer port;
|
||||
/**
|
||||
* 用户
|
||||
*/
|
||||
@Schema(title = "节点用户", description = "节点用户")
|
||||
@Schema(title = "用户", description = "用户")
|
||||
@JsonIgnore
|
||||
private String username;
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Schema(title = "节点密码", description = "节点密码")
|
||||
@Schema(title = "密码", description = "密码")
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
/**
|
||||
|
||||
@@ -15,11 +15,6 @@ import lombok.Setter;
|
||||
@ConfigurationProperties(prefix = "taoyao.security")
|
||||
public class SecurityProperties {
|
||||
|
||||
/**
|
||||
* Basic认证
|
||||
*/
|
||||
public static final String BASIC = "Basic";
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
|
||||
@@ -30,19 +30,19 @@ public class WebrtcProperties {
|
||||
@Schema(title = "媒体最大端口", description = "媒体最大端口")
|
||||
private Integer maxPort;
|
||||
/**
|
||||
* stun服务器
|
||||
* STUN服务器
|
||||
*/
|
||||
@Schema(title = "stun服务器", description = "stun服务器")
|
||||
@Schema(title = "STUN服务器", description = "STUN服务器")
|
||||
private String[] stun;
|
||||
/**
|
||||
* turn服务器
|
||||
* TURN服务器
|
||||
*/
|
||||
@Schema(title = "turn服务器", description = "turn服务器")
|
||||
@Schema(title = "TURN服务器", description = "TURN服务器")
|
||||
private String[] turn;
|
||||
/**
|
||||
* Mediasoup配置
|
||||
* 媒体服务配置
|
||||
*/
|
||||
@Schema(title = "Mediasoup配置", description = "Mediasoup配置")
|
||||
@Schema(title = "媒体服务配置", description = "媒体服务配置")
|
||||
private List<MediasoupProperties> mediasoupList;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.acgist.taoyao.boot.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
|
||||
import jakarta.websocket.Session;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* WebSocket工具
|
||||
*
|
||||
* @author acgist
|
||||
*/
|
||||
@Slf4j
|
||||
public class WebSocketUtils {
|
||||
|
||||
private WebSocketUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param session WebSocket
|
||||
*
|
||||
* @return 远程地址
|
||||
*/
|
||||
public static final String getRemoteAddress(Session session) {
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
return (String) getField(session.getAsyncRemote(), "base.socketWrapper.remoteAddr");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object 对象
|
||||
* @param fieldPath 属性路径
|
||||
*
|
||||
* @return 属性
|
||||
*/
|
||||
private static final Object getField(Object object, String fieldPath) {
|
||||
final String fields[] = StringUtils.split(fieldPath, '.');
|
||||
for (String field : fields) {
|
||||
object = getField(object, object.getClass(), field);
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object 对象
|
||||
* @param clazz 属性类型
|
||||
* @param fieldName 属性名称
|
||||
*
|
||||
* @return 属性
|
||||
*/
|
||||
private static final Object getField(Object object, Class<?> clazz, String fieldName) {
|
||||
try {
|
||||
return FieldUtils.getField(clazz, fieldName, true).get(object);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
log.error("读取属性异常:{}-{}", clazz, fieldName, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user