From 07b0c37c26eccecbb0cfab4423b9db24d97becd3 Mon Sep 17 00:00:00 2001 From: Doghole Date: Mon, 12 May 2025 18:14:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9E=9A=E4=B8=BE=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=B3=A8=E8=A7=A3=E6=89=AB=E6=8F=8F=E6=B3=A8=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rich/emoney/config/ReflectionsConfig.java | 6 +- .../emoney/entity/config/ProxyConfig.java | 75 ++++++++++++ .../interceptor/EnumOptionsInterceptor.java | 113 ++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/main/java/quant/rich/emoney/entity/config/ProxyConfig.java create mode 100644 src/main/java/quant/rich/emoney/interceptor/EnumOptionsInterceptor.java diff --git a/src/main/java/quant/rich/emoney/config/ReflectionsConfig.java b/src/main/java/quant/rich/emoney/config/ReflectionsConfig.java index 722d30d..772354f 100644 --- a/src/main/java/quant/rich/emoney/config/ReflectionsConfig.java +++ b/src/main/java/quant/rich/emoney/config/ReflectionsConfig.java @@ -18,7 +18,11 @@ public class ReflectionsConfig { @Bean("reflections") Reflections reflections() { return new Reflections(new ConfigurationBuilder() - .addScanners(Scanners.MethodsAnnotated, Scanners.SubTypes, Scanners.TypesAnnotated) + .addScanners( + Scanners.MethodsAnnotated, + Scanners.SubTypes, + Scanners.FieldsAnnotated, + Scanners.TypesAnnotated) .forPackages("quant.rich.emoney")); } diff --git a/src/main/java/quant/rich/emoney/entity/config/ProxyConfig.java b/src/main/java/quant/rich/emoney/entity/config/ProxyConfig.java new file mode 100644 index 0000000..dccabce --- /dev/null +++ b/src/main/java/quant/rich/emoney/entity/config/ProxyConfig.java @@ -0,0 +1,75 @@ +package quant.rich.emoney.entity.config; + +import java.net.Proxy; +import java.time.LocalDateTime; +import java.util.Objects; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import lombok.AccessLevel; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; +import quant.rich.emoney.entity.config.DeviceInfoConfig.DeviceInfo; +import quant.rich.emoney.interceptor.EnumOptionsInterceptor.EnumOptions; +import quant.rich.emoney.interfaces.ConfigInfo; +import quant.rich.emoney.interfaces.IConfig; +import quant.rich.emoney.interfaces.ValidEmoneyRequestConfig; +import quant.rich.emoney.patch.okhttp.PatchOkHttp; +import quant.rich.emoney.util.EncryptUtils; +import quant.rich.emoney.util.SpringContextHolder; +import quant.rich.emoney.util.TextUtils; + +/** + * 独立出来一个代理设置的原因是后续可能需要做一个代理池,这样的话独立配置比较适合后续扩展 + */ +@Data +@Accessors(chain = true) +@Slf4j +@ValidEmoneyRequestConfig +@ConfigInfo(field = "proxy", name = "代理设置", initDefault = true) +public class ProxyConfig implements IConfig { + + /** + * 代理类型 + */ + @EnumOptions("ProxyTypeEnum") + private Proxy.Type proxyType = Proxy.Type.DIRECT; + + /** + * 代理主机 + */ + private String proxyHost = ""; + + /** + * 代理端口 + */ + private Integer proxyPort = 0; + + /** + * 是否忽略 HTTPS 证书校验 + */ + private Boolean ignoreHttpsVerification = false; + + public void afterBeanInit() { + + } + + + public ProxyConfig() {} + + +} diff --git a/src/main/java/quant/rich/emoney/interceptor/EnumOptionsInterceptor.java b/src/main/java/quant/rich/emoney/interceptor/EnumOptionsInterceptor.java new file mode 100644 index 0000000..2c94c88 --- /dev/null +++ b/src/main/java/quant/rich/emoney/interceptor/EnumOptionsInterceptor.java @@ -0,0 +1,113 @@ +package quant.rich.emoney.interceptor; + + +import org.reflections.Reflections; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AliasFor; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.*; + +import jakarta.servlet.http.*; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.Entry; +import java.lang.annotation.*; + +@Component +@Slf4j +public class EnumOptionsInterceptor implements HandlerInterceptor { + + @Autowired + Reflections reflections; + + private Map>> options = null; + + private Map optionNameMap = new HashMap<>(); + + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, + Object handler) throws Exception { + + // 只在 Controller(HandlerMethod)里才做注入 + if (!(handler instanceof HandlerMethod)) { + // 静态资源、图片、css、js 都会被 ResourceHttpRequestHandler 处理, + // 这里一律跳过 + return true; + } + + // 排除 @ResponseBody/json 接口 + HandlerMethod hm = (HandlerMethod) handler; + if (hm.hasMethodAnnotation(ResponseBody.class) + || hm.getBeanType().isAnnotationPresent(RestController.class)) { + return true; + } + + if (options == null) { + options = new HashMap<>(); + Set enumOptionFields = reflections.getFieldsAnnotatedWith(EnumOptions.class); + for (Field f : enumOptionFields) { + if (!f.isAnnotationPresent(EnumOptions.class)) continue; + if (!Enum.class.isAssignableFrom(f.getType())) continue; + + // 拿到注解和名前缀 + EnumOptions anno = f.getAnnotation(EnumOptions.class); + String prefix = anno.value().isBlank() ? + f.getName() + "Enum" : + anno.value(); + + prefix = prefix.toUpperCase().charAt(0) + prefix.substring(1); + + if (optionNameMap.containsKey(prefix)) { + log.warn("EnumOption name {}:{} has already been taken by {}, please check", + prefix, f.getType().getName(), optionNameMap.get(prefix)); + continue; + } + + optionNameMap.put(prefix, f.getType().getName()); + + // enum 值列表 + @SuppressWarnings("unchecked") + Class> enumType = (Class>) f.getType(); + Enum[] constants = enumType.getEnumConstants(); + + // 构造 Map + Map> optionsMap = new LinkedHashMap<>(); + for (Enum c : constants) { + optionsMap.put(c.name(), c); + } + + // 放到 Model 里 + options.put(prefix, optionsMap); + } + + } + for (Entry>> entry : options.entrySet()) { + request.setAttribute(entry.getKey(), entry.getValue()); + log.debug("Inject enums {}: {} to request {}", + entry.getKey(), optionNameMap.get(entry.getKey()), + request.getRequestURI()); + } + return true; + } + + + @Target(ElementType.FIELD) + @Retention(RetentionPolicy.RUNTIME) + @Documented + public static @interface EnumOptions { + /** + * 注入到 Model 时用的属性名前缀, + * 默认:字段名 + "Options" + */ + String value() default ""; + } + + +} \ No newline at end of file