新增 RequireAuthAndProxyAspect 切片, 用于确保一些需要鉴权的方法有合法鉴权
This commit is contained in:
@@ -11,7 +11,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
|||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@EnableFeignClients
|
@EnableFeignClients
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableCaching(proxyTargetClass=true)
|
|
||||||
public class EmoneyAutoApplication {
|
public class EmoneyAutoApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package quant.rich.emoney.component;
|
package quant.rich.emoney.component;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
import org.aspectj.lang.annotation.*;
|
import org.aspectj.lang.annotation.*;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -20,9 +20,19 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注解在受 Spring 管理的类的成员方法上,使其在执行前校验代理状态、鉴权状态
|
||||||
|
* <p>需要开启 AOP:在任意配置类上增加注解:<i><code>@EnableAspectJAutoProxy</code></i>
|
||||||
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Aspect
|
@Aspect
|
||||||
public class RequireAuthAndProxyAspect {
|
public class RequireAuthAndProxyAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用链深度,用以判断同线程同类型切点命中的次数
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Integer> DEPTH =
|
||||||
|
ThreadLocal.withInitial(() -> 0);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
RequestInfoService requestInfoService;
|
RequestInfoService requestInfoService;
|
||||||
@@ -30,9 +40,30 @@ public class RequireAuthAndProxyAspect {
|
|||||||
@Autowired
|
@Autowired
|
||||||
ProxySettingService proxySettingService;
|
ProxySettingService proxySettingService;
|
||||||
|
|
||||||
@Around("@annotation(quant.rich.emoney.component.RequireAuthAndProxyAspect.RequireAuthAndProxy)")
|
@Pointcut("@annotation(quant.rich.emoney.component.RequireAuthAndProxyAspect.RequireAuthAndProxy)")
|
||||||
public Object around(ProceedingJoinPoint pjp) throws Throwable {
|
public void pointCut() {}
|
||||||
|
|
||||||
|
@Before("pointCut()")
|
||||||
|
public void before(JoinPoint jp) throws Throwable {
|
||||||
|
int depth = DEPTH.get();
|
||||||
|
if (depth++ == 0) {
|
||||||
|
beforeRoot(jp);
|
||||||
|
}
|
||||||
|
DEPTH.set(depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After("pointCut()")
|
||||||
|
public void after() {
|
||||||
|
int depth = DEPTH.get() - 1;
|
||||||
|
if (depth == 0) {
|
||||||
|
DEPTH.remove();
|
||||||
|
} else {
|
||||||
|
DEPTH.set(depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beforeRoot(JoinPoint jp) throws Throwable {
|
||||||
|
|
||||||
ProxySetting defualtProxySetting = proxySettingService.getDefaultProxySetting();
|
ProxySetting defualtProxySetting = proxySettingService.getDefaultProxySetting();
|
||||||
|
|
||||||
if (defualtProxySetting == null) {
|
if (defualtProxySetting == null) {
|
||||||
@@ -45,7 +76,7 @@ public class RequireAuthAndProxyAspect {
|
|||||||
throw new RuntimeException("需要配置默认请求信息");
|
throw new RuntimeException("需要配置默认请求信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
MethodSignature signature = (MethodSignature) jp.getSignature();
|
||||||
Method method = signature.getMethod();
|
Method method = signature.getMethod();
|
||||||
RequireAuthAndProxy annotation = method.getAnnotation(RequireAuthAndProxy.class);
|
RequireAuthAndProxy annotation = method.getAnnotation(RequireAuthAndProxy.class);
|
||||||
|
|
||||||
@@ -60,13 +91,21 @@ public class RequireAuthAndProxyAspect {
|
|||||||
else if (!EmoneyClient.reloginCheck()) {
|
else if (!EmoneyClient.reloginCheck()) {
|
||||||
throw new RuntimeException("检查重鉴权失败");
|
throw new RuntimeException("检查重鉴权失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
return pjp.proceed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在方法上添加此注解,则进入该方法前先校验 defaultRequestInfo 已鉴权、代理已配置,否则不允许进入方法
|
* 在方法上添加此注解,则进入该方法前先校验 defaultRequestInfo 已鉴权、代理已配置,否则不允许进入方法
|
||||||
* <p>需要开启 AOP:在任意配置类上增加注解:<i><code>@EnableAspectJAutoProxy</code></i>
|
* <p>
|
||||||
|
* <b><font color="red">由于 AOP 特性使然, 必须为 public 方法才能生效</font></b>
|
||||||
|
* <p>
|
||||||
|
* 为防止反复重登录验证, 在同一调用链中的校验, 仅在首次调用时进行检查, 如:
|
||||||
|
* A、B 和 C 方法都添加了本注解, A 中调用 B, B 中调用 C, 则仅在 A 方法执行时才进行检查。
|
||||||
|
* <p>
|
||||||
|
* 为了安全起见, 无论 autoLogin 是否为 true, 只要添加了本注解, 在执行方法前, 最终都会进行
|
||||||
|
* EmoneyClient.reloginCheck(), 如果检查重鉴权失败, 被注解的方法将不会执行,
|
||||||
|
* 并由切片方法抛出异常。如果某个方法并不需要严格控制鉴权的, 可以不用本注解,
|
||||||
|
* 而是由在方法内自行编写逻辑来替代。
|
||||||
|
*
|
||||||
* @see RequireAuthAndProxyAspect
|
* @see RequireAuthAndProxyAspect
|
||||||
*/
|
*/
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@@ -74,7 +113,8 @@ public class RequireAuthAndProxyAspect {
|
|||||||
@Documented
|
@Documented
|
||||||
public static @interface RequireAuthAndProxy {
|
public static @interface RequireAuthAndProxy {
|
||||||
/**
|
/**
|
||||||
* 当存在默认请求配置但未鉴权时,是否自动鉴权
|
* 当存在默认请求配置但未鉴权时,是否自动鉴权。由于某些场景下,
|
||||||
|
* 鉴权信息需要系统统一维护,故此区分
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean autoLogin() default false;
|
boolean autoLogin() default false;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package quant.rich.emoney.config;
|
package quant.rich.emoney.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@@ -17,8 +19,10 @@ import quant.rich.emoney.service.ConfigService;
|
|||||||
* @author Doghole
|
* @author Doghole
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@EnableAspectJAutoProxy
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@EnableAsync(proxyTargetClass=true)
|
||||||
|
@EnableCaching(proxyTargetClass=true)
|
||||||
|
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
|
||||||
@Import(ConfigAutoRegistrar.class)
|
@Import(ConfigAutoRegistrar.class)
|
||||||
public class EmoneyAutoConfig implements WebMvcConfigurer {
|
public class EmoneyAutoConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package quant.rich.emoney.pojo;
|
package quant.rich.emoney.pojo.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -8,10 +8,14 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@Validated
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain=true)
|
@Accessors(chain=true)
|
||||||
public class MultiIndexPlanDetail {
|
public class MultiIndexPlanDetail {
|
||||||
@@ -19,11 +23,14 @@ public class MultiIndexPlanDetail {
|
|||||||
/**
|
/**
|
||||||
* 指标
|
* 指标
|
||||||
*/
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty
|
||||||
List<MultiIndexPlanPart> indexes;
|
List<MultiIndexPlanPart> indexes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 抓取的 K 线粒度
|
* 抓取的 K 线粒度
|
||||||
*/
|
*/
|
||||||
|
@NotEmpty
|
||||||
List<Integer> periods;
|
List<Integer> periods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +62,7 @@ public class MultiIndexPlanDetail {
|
|||||||
return periods;
|
return periods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Validated
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain=true)
|
@Accessors(chain=true)
|
||||||
public static class MultiIndexPlanPart {
|
public static class MultiIndexPlanPart {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package quant.rich.emoney.pojo;
|
package quant.rich.emoney.pojo.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -23,6 +23,7 @@ import org.jsoup.nodes.Document;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
@@ -71,6 +72,10 @@ public class IndexDetailService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
RequestInfoService requestInfoService;
|
RequestInfoService requestInfoService;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Autowired
|
||||||
|
IndexDetailService self;
|
||||||
|
|
||||||
static final String filePath = "./conf/extra/indexDetail/";
|
static final String filePath = "./conf/extra/indexDetail/";
|
||||||
static final ObjectMapper mapper = new ObjectMapper();
|
static final ObjectMapper mapper = new ObjectMapper();
|
||||||
static final Context jsContext = Context.create("js");
|
static final Context jsContext = Context.create("js");
|
||||||
@@ -86,25 +91,24 @@ public class IndexDetailService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@CacheEvict(cacheNames="@indexDetailService.getIndexDetail(Serializable)", key="#indexCode.toString()")
|
@CacheEvict(cacheNames="@indexDetailService.getIndexDetail(Serializable)", key="#indexCode.toString()")
|
||||||
@RequireAuthAndProxy(autoLogin = true)
|
|
||||||
public IndexDetail forceRefreshAndGetIndexDetail(Serializable indexCode) {
|
public IndexDetail forceRefreshAndGetIndexDetail(Serializable indexCode) {
|
||||||
|
|
||||||
// 刷新的本质就是从网络获取,因为此处已经清理了缓存,所以直接从网络获取后再
|
// 刷新的本质就是从网络获取,因为此处已经清理了缓存,所以直接从网络获取后再
|
||||||
// 走一次 getIndexDetail,获取到的就是从网络保存到了本地的,此时缓存也更新了
|
// 走一次 getIndexDetail,获取到的就是从网络保存到了本地的,此时缓存也更新了
|
||||||
|
|
||||||
if (!hasParams(indexCode)) {
|
if (!hasParams(indexCode)) {
|
||||||
getNonParamsIndexDetailOnline(indexCode);
|
self.getNonParamsIndexDetailOnline(indexCode);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
getParamsIndexDetailOnline(indexCode);
|
self.getParamsIndexDetailOnline(indexCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getIndexDetail(indexCode);
|
// 此处用 self 是为了在本次调用时就设置缓存
|
||||||
|
return self.getIndexDetail(indexCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Cacheable(cacheNames="@indexDetailService.getIndexDetail(Serializable)", key="#indexCode.toString()")
|
@Cacheable(cacheNames="@indexDetailService.getIndexDetail(Serializable)", key="#indexCode.toString()")
|
||||||
@RequireAuthAndProxy(autoLogin = true)
|
|
||||||
public IndexDetail getIndexDetail(Serializable indexCode) {
|
public IndexDetail getIndexDetail(Serializable indexCode) {
|
||||||
|
|
||||||
if (indexCode == null) {
|
if (indexCode == null) {
|
||||||
@@ -136,7 +140,7 @@ public class IndexDetailService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 从网络获取
|
// 从网络获取
|
||||||
return getParamsIndexDetailOnline(indexCode);
|
return self.getParamsIndexDetailOnline(indexCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,7 +150,8 @@ public class IndexDetailService {
|
|||||||
* @see RequestInfoService#getDefaultRequestInfo()
|
* @see RequestInfoService#getDefaultRequestInfo()
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private ParamsIndexDetail getParamsIndexDetailOnline(Serializable indexCode) {
|
@RequireAuthAndProxy(autoLogin = true)
|
||||||
|
public ParamsIndexDetail getParamsIndexDetailOnline(Serializable indexCode) {
|
||||||
RequestInfo requestInfo = requestInfoService.getDefaultRequestInfo();
|
RequestInfo requestInfo = requestInfoService.getDefaultRequestInfo();
|
||||||
if (requestInfo == null || StringUtils.isBlank(requestInfo.getAuthorization())) {
|
if (requestInfo == null || StringUtils.isBlank(requestInfo.getAuthorization())) {
|
||||||
throw new RuntimeException("无法获取已鉴权的 RequestInfo");
|
throw new RuntimeException("无法获取已鉴权的 RequestInfo");
|
||||||
@@ -221,26 +226,29 @@ public class IndexDetailService {
|
|||||||
log.warn("无法获取本地无参数指标说明,将尝试重新从网络获取 indexCode: {}", indexCode, e);
|
log.warn("无法获取本地无参数指标说明,将尝试重新从网络获取 indexCode: {}", indexCode, e);
|
||||||
}
|
}
|
||||||
if (detail != null) {
|
if (detail != null) {
|
||||||
loadImages(detail);
|
self.loadImages(detail);
|
||||||
saveIndexDetail(detail);
|
saveIndexDetail(detail);
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 从网络获取
|
// 从网络获取
|
||||||
return getNonParamsIndexDetailOnline(indexCode);
|
return self.getNonParamsIndexDetailOnline(indexCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从网络获取指定 indexCode 的无参指标详情
|
* 从网络获取指定 indexCode 的无参指标详情
|
||||||
* <p>本例用到的 requestInfo 不需要 PatchOkHttp 覆写,但要求鉴权参数拼接到 url 中,故要求鉴权
|
* <p>本例用到的 requestInfo 不需要 PatchOkHttp 覆写,但要求鉴权参数拼接到 url 中,故要求鉴权
|
||||||
* <p>会一并尝试获取其他在本地未有的无参指标</p>
|
* <p>会一并尝试获取其他在本地未有的无参指标</p>
|
||||||
|
* <p>由于本例需要鉴权, 故在方法上开启了 {@code @RequireAuthAndProxy}, 而本方法被类内其他方法调用, 需要 proxy 才能使 AOP 生效,
|
||||||
|
* 为了使 self 调用成功, 需要在任意配置类上添加 {@code @EnableAspectJAutoProxy(exposeProxy = true)}
|
||||||
* @param indexCode
|
* @param indexCode
|
||||||
* @see RequestInfo#getWebviewUserAgent()
|
* @see RequestInfo#getWebviewUserAgent()
|
||||||
* @see RequestInfoService#getDefaultRequestInfo()
|
* @see RequestInfoService#getDefaultRequestInfo()
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private NonParamsIndexDetail getNonParamsIndexDetailOnline(Serializable indexCode) {
|
@RequireAuthAndProxy(autoLogin = true)
|
||||||
String url = buildNonParamsIndexUrl(indexCode);
|
public NonParamsIndexDetail getNonParamsIndexDetailOnline(Serializable indexCode) {
|
||||||
|
String url = self.buildNonParamsIndexUrl(indexCode);
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.header("Host", "appstatic.emoney.cn")
|
.header("Host", "appstatic.emoney.cn")
|
||||||
@@ -370,7 +378,7 @@ public class IndexDetailService {
|
|||||||
String path = getIndexDetailPath(detail);
|
String path = getIndexDetailPath(detail);
|
||||||
// 判断是否是需求的 detail
|
// 判断是否是需求的 detail
|
||||||
if (indexCode.toString().equals(detail.getIndexCode())) {
|
if (indexCode.toString().equals(detail.getIndexCode())) {
|
||||||
loadImages(detail);
|
self.loadImages(detail);
|
||||||
targetDetail = detail;
|
targetDetail = detail;
|
||||||
}
|
}
|
||||||
// 清洗内容:凡是文本类型的内容的,都要清洗一遍,判断是否有脚本、
|
// 清洗内容:凡是文本类型的内容的,都要清洗一遍,判断是否有脚本、
|
||||||
@@ -434,7 +442,8 @@ public class IndexDetailService {
|
|||||||
* @return
|
* @return
|
||||||
* @see RequestInfo
|
* @see RequestInfo
|
||||||
*/
|
*/
|
||||||
private NonParamsIndexDetail loadImages(NonParamsIndexDetail detail) {
|
@RequireAuthAndProxy(autoLogin = true)
|
||||||
|
public NonParamsIndexDetail loadImages(NonParamsIndexDetail detail) {
|
||||||
OkHttpClient client = OkHttpClientProvider.getInstance();
|
OkHttpClient client = OkHttpClientProvider.getInstance();
|
||||||
for (NonParamsIndexDetailData data : detail.getData()) {
|
for (NonParamsIndexDetailData data : detail.getData()) {
|
||||||
String imageUrl = data.getImage();
|
String imageUrl = data.getImage();
|
||||||
@@ -465,7 +474,7 @@ public class IndexDetailService {
|
|||||||
.header("Sec-Fetch-Mode", "no-cors")
|
.header("Sec-Fetch-Mode", "no-cors")
|
||||||
.header("Sec-Fetch-Dest", "image")
|
.header("Sec-Fetch-Dest", "image")
|
||||||
.header("Accept-Encoding", "gzip, deflate")
|
.header("Accept-Encoding", "gzip, deflate")
|
||||||
.header("Referer", buildNonParamsIndexUrl(detail.getIndexCode()))
|
.header("Referer", self.buildNonParamsIndexUrl(detail.getIndexCode()))
|
||||||
.header("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7")
|
.header("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -567,7 +576,8 @@ public class IndexDetailService {
|
|||||||
* @return
|
* @return
|
||||||
* @see RequestInfo
|
* @see RequestInfo
|
||||||
*/
|
*/
|
||||||
private String buildNonParamsIndexUrl(Serializable indexCode) {
|
@RequireAuthAndProxy(autoLogin = true)
|
||||||
|
public String buildNonParamsIndexUrl(Serializable indexCode) {
|
||||||
|
|
||||||
RequestInfo requestInfo = requestInfoService.getDefaultRequestInfo();
|
RequestInfo requestInfo = requestInfoService.getDefaultRequestInfo();
|
||||||
if (requestInfo == null || StringUtils.isBlank(requestInfo.getAuthorization())) {
|
if (requestInfo == null || StringUtils.isBlank(requestInfo.getAuthorization())) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import jakarta.validation.ConstraintValidator;
|
import jakarta.validation.ConstraintValidator;
|
||||||
import jakarta.validation.ConstraintValidatorContext;
|
import jakarta.validation.ConstraintValidatorContext;
|
||||||
import quant.rich.emoney.entity.sqlite.ProxySetting;
|
import quant.rich.emoney.entity.sqlite.ProxySetting;
|
||||||
|
import quant.rich.emoney.interfaces.IValidator;
|
||||||
|
|
||||||
public class ProxySettingValidator implements IValidator, ConstraintValidator<ProxySettingValid, ProxySetting> {
|
public class ProxySettingValidator implements IValidator, ConstraintValidator<ProxySettingValid, ProxySetting> {
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import jakarta.validation.ConstraintValidator;
|
|||||||
import jakarta.validation.ConstraintValidatorContext;
|
import jakarta.validation.ConstraintValidatorContext;
|
||||||
import quant.rich.emoney.entity.config.DeviceInfoConfig;
|
import quant.rich.emoney.entity.config.DeviceInfoConfig;
|
||||||
import quant.rich.emoney.entity.sqlite.RequestInfo;
|
import quant.rich.emoney.entity.sqlite.RequestInfo;
|
||||||
|
import quant.rich.emoney.interfaces.IValidator;
|
||||||
|
|
||||||
public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> {
|
public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> {
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,11 @@
|
|||||||
{"id":"46","name":"DKBY","nameCode":"10008500","data":[{"title":"DKBY指标说明:","items":["多空博弈","1.当“多方”线向上与“空方”线“金叉”时为买点。","2.当“多方”线向下与“空方”线“死叉”时为卖点。"],"image":null}],"original":"{\"id\":46,\"data\":[{\"title\":\"DKBY指标说明:\",\"items\":[\"多空博弈\",\"1.当“多方”线向上与“空方”线“金叉”时为买点。\",\"2.当“多方”线向下与“空方”线“死叉”时为卖点。\"]}],\"name\":\"DKBY\",\"nameCode\":\"10008500\"}","indexCode":"10008500","indexName":"DKBY","details":[{"content":"DKBY指标说明:","type":"TITLE"},{"content":"多空博弈","type":"TEXT"},{"content":"1.当“多方”线向上与“空方”线“金叉”时为买点。","type":"TEXT"},{"content":"2.当“多方”线向下与“空方”线“死叉”时为卖点。","type":"TEXT"}]}
|
{
|
||||||
|
"id" : "46",
|
||||||
|
"name" : "DKBY",
|
||||||
|
"nameCode" : "10008500",
|
||||||
|
"data" : [ {
|
||||||
|
"title" : "DKBY指标说明:",
|
||||||
|
"items" : [ "多空博弈", "1.当“多方”线向上与“空方”线“金叉”时为买点。", "2.当“多方”线向下与“空方”线“死叉”时为卖点。" ],
|
||||||
|
"image" : null
|
||||||
|
} ],
|
||||||
|
"original" : "{\"id\":46,\"data\":[{\"title\":\"DKBY指标说明:\",\"items\":[\"多空博弈\",\"1.当“多方”线向上与“空方”线“金叉”时为买点。\",\"2.当“多方”线向下与“空方”线“死叉”时为卖点。\"]}],\"name\":\"DKBY\",\"nameCode\":\"10008500\"}"
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user