统一 boot 和 cloud 代码

This commit is contained in:
YunaiV 2023-10-24 13:59:20 +08:00
parent 51f96686f8
commit 57330054de
20 changed files with 245 additions and 156 deletions

View File

@ -138,6 +138,12 @@
<artifactId>jsoup</artifactId> <artifactId>jsoup</artifactId>
</dependency> </dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -41,7 +41,7 @@ public class CommonResult<T> implements Serializable {
* 因为 A 方法返回的 CommonResult 对象不满足调用其的 B 方法的返回所以需要进行转换 * 因为 A 方法返回的 CommonResult 对象不满足调用其的 B 方法的返回所以需要进行转换
* *
* @param result 传入的 result 对象 * @param result 传入的 result 对象
* @param <T> 返回的泛型 * @param <T> 返回的泛型
* @return 新的 CommonResult 对象 * @return 新的 CommonResult 对象
*/ */
public static <T> CommonResult<T> error(CommonResult<?> result) { public static <T> CommonResult<T> error(CommonResult<?> result) {

View File

@ -1,5 +1,9 @@
package cn.iocoder.yudao.framework.common.pojo; package cn.iocoder.yudao.framework.common.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -7,6 +11,9 @@ import java.io.Serializable;
* *
* 类名加了 ing 的原因是避免和 ES SortField 重名 * 类名加了 ing 的原因是避免和 ES SortField 重名
*/ */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SortingField implements Serializable { public class SortingField implements Serializable {
/** /**
@ -27,30 +34,4 @@ public class SortingField implements Serializable {
*/ */
private String order; private String order;
// 空构造方法解决反序列化
public SortingField() {
}
public SortingField(String field, String order) {
this.field = field;
this.order = order;
}
public String getField() {
return field;
}
public SortingField setField(String field) {
this.field = field;
return this;
}
public String getOrder() {
return order;
}
public SortingField setOrder(String order) {
this.order = order;
return this;
}
} }

View File

@ -27,7 +27,7 @@ public class ServletUtils {
* 返回 JSON 字符串 * 返回 JSON 字符串
* *
* @param response 响应 * @param response 响应
* @param object 对象会序列化成 JSON 字符串 * @param object 对象会序列化成 JSON 字符串
*/ */
@SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE否则会乱码 @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE否则会乱码
public static void writeJSON(HttpServletResponse response, Object object) { public static void writeJSON(HttpServletResponse response, Object object) {
@ -40,7 +40,7 @@ public class ServletUtils {
* *
* @param response 响应 * @param response 响应
* @param filename 文件名 * @param filename 文件名
* @param content 附件内容 * @param content 附件内容
*/ */
public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
// 设置 header contentType // 设置 header contentType
@ -88,6 +88,8 @@ public class ServletUtils {
return ServletUtil.getClientIP(request); return ServletUtil.getClientIP(request);
} }
// TODO @疯狂terminal 还是从 ServletUtils 里拿更容易全局治理
public static boolean isJsonRequest(ServletRequest request) { public static boolean isJsonRequest(ServletRequest request) {
return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE); return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
} }
@ -107,4 +109,5 @@ public class ServletUtils {
public static Map<String, String> getParamMap(HttpServletRequest request) { public static Map<String, String> getParamMap(HttpServletRequest request) {
return ServletUtil.getParamMap(request); return ServletUtil.getParamMap(request);
} }
} }

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.common.util.spring;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.DefaultParameterNameDiscoverer;
@ -87,47 +86,4 @@ public class SpringExpressionUtils {
return result; return result;
} }
/**
* JoinPoint 切面 批量解析 EL 表达式转换 jspl参数
*
* @param joinPoint 切面点
* @param info 返回值
* @param expressionStrings EL 表达式数组
* @return Map<String, Object> 结果
* @author 陈賝
* @since 2023/6/18 11:20
*/
// TODO @chenchen: 这个方法 parseExpressions 比较接近是不是可以合并下
public static Map<String, Object> parseExpression(JoinPoint joinPoint, Object info, List<String> expressionStrings) {
// 如果为空则不进行解析
if (CollUtil.isEmpty(expressionStrings)) {
return MapUtil.newHashMap();
}
// 第一步构建解析的上下文 EvaluationContext
// 通过 joinPoint 获取被注解方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 使用 spring ParameterNameDiscoverer 获取方法形参名数组
String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
// Spring 的表达式上下文对象
EvaluationContext context = new StandardEvaluationContext();
if (ArrayUtil.isNotEmpty(parameterNames)) {
//获取方法参数值
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
// 替换 SP EL 里的变量值为实际值 比如 #user --> user对象
context.setVariable(parameterNames[i], args[i]);
}
context.setVariable("info", info);
}
// 第二步逐个参数解析
Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
expressionStrings.forEach(key -> {
Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
result.put(key, value);
});
return result;
}
} }

View File

@ -17,7 +17,7 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Constraint( @Constraint(
validatedBy = InEnumValidator.class validatedBy = {InEnumValidator.class, InEnumCollectionValidator.class}
) )
public @interface InEnum { public @interface InEnum {

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.framework.common.validation;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class InEnumCollectionValidator implements ConstraintValidator<InEnum, Collection<Integer>> {
private List<Integer> values;
@Override
public void initialize(InEnum annotation) {
IntArrayValuable[] values = annotation.value().getEnumConstants();
if (values.length == 0) {
this.values = Collections.emptyList();
} else {
this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList());
}
}
@Override
public boolean isValid(Collection<Integer> list, ConstraintValidatorContext context) {
// 校验通过
if (CollUtil.containsAll(values, list)) {
return true;
}
// 校验不通过自定义提示语句因为注解上的 value 是枚举类无法获得枚举类的实际值
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()
.replaceAll("\\{value}", CollUtil.join(list, ","))).addConstraintViolation(); // 重新添加错误提示语句
return false;
}
}

View File

@ -0,0 +1,64 @@
package cn.iocoder.yudao.framework.common.util.collection;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.BiFunction;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link CollectionUtils} 的单元测试
*/
public class CollectionUtilsTest {
@Data
@AllArgsConstructor
private static class Dog {
private Integer id;
private String name;
private String code;
}
@Test
public void testDiffList() {
// 准备参数
Collection<Dog> oldList = Arrays.asList(
new Dog(1, "花花", "hh"),
new Dog(2, "旺财", "wc")
);
Collection<Dog> newList = Arrays.asList(
new Dog(null, "花花2", "hh"),
new Dog(null, "小白", "xb")
);
BiFunction<Dog, Dog, Boolean> sameFunc = (oldObj, newObj) -> {
boolean same = oldObj.getCode().equals(newObj.getCode());
// 如果相等的情况下需要设置下 id后续好更新
if (same) {
newObj.setId(oldObj.getId());
}
return same;
};
// 调用
List<List<Dog>> result = CollectionUtils.diffList(oldList, newList, sameFunc);
// 断言
assertEquals(result.size(), 3);
// 断言 create
assertEquals(result.get(0).size(), 1);
assertEquals(result.get(0).get(0), new Dog(null, "小白", "xb"));
// 断言 update
assertEquals(result.get(1).size(), 1);
assertEquals(result.get(1).get(0), new Dog(1, "花花2", "hh"));
// 断言 delete
assertEquals(result.get(2).size(), 1);
assertEquals(result.get(2).get(0), new Dog(2, "旺财", "wc"));
}
}

View File

@ -507,7 +507,7 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme
// 单条规则的条件 // 单条规则的条件
String tableName = MyBatisUtils.getTableName(table); String tableName = MyBatisUtils.getTableName(table);
Expression oneExpress = rule.getExpression(tableName, table.getAlias()); Expression oneExpress = rule.getExpression(tableName, table.getAlias());
if(oneExpress == null){ if (oneExpress == null){
continue; continue;
} }
// 拼接到 allExpression // 拼接到 allExpression

View File

@ -1,8 +1,7 @@
package cn.iocoder.yudao.framework.datapermission.core.util; package cn.iocoder.yudao.framework.dict.core.util;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;

View File

@ -11,40 +11,40 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/ */
public interface SmsFrameworkErrorCodeConstants { public interface SmsFrameworkErrorCodeConstants {
ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析"); ErrorCode SMS_UNKNOWN = new ErrorCode(2_001_000_000, "未知错误,需要解析");
// ========== 权限 / 限流等相关 2001000100 ========== // ========== 权限 / 限流等相关 2-001-000-100 ==========
ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限"); ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2_001_000_100, "没有发送短信的权限");
ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信"); ErrorCode SMS_IP_DENY = new ErrorCode(2_001_000_100, "IP 不允许发送短信");
// 阿里云将短信发送频率限制在正常的业务限流范围内默认短信验证码使用同一签名对同一个手机号验证码支持 1 / 分钟5 / 小时累计 10 / // 阿里云将短信发送频率限制在正常的业务限流范围内默认短信验证码使用同一签名对同一个手机号验证码支持 1 / 分钟5 / 小时累计 10 /
ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流"); ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2_001_000_102, "指定手机的发送限流");
// 阿里云已经达到您在控制台设置的短信日发送量限额值在国内消息设置 > 安全设置修改发送总量阈值 // 阿里云已经达到您在控制台设置的短信日发送量限额值在国内消息设置 > 安全设置修改发送总量阈值
ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流"); ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2_001_000_103, "每天的发送限流");
ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词"); ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2_001_000_104, "短信内容有敏感词");
// 腾讯云为避免骚扰用户营销短信只允许在8点到22点发送 // 腾讯云为避免骚扰用户营销短信只允许在8点到22点发送
ErrorCode SMS_SEND_MARKET_LIMIT_CONTROL = new ErrorCode(2001000105, "营销短信发送时间限制"); ErrorCode SMS_SEND_MARKET_LIMIT_CONTROL = new ErrorCode(2_001_000_105, "营销短信发送时间限制");
// ========== 模板相关 2001000200 ========== // ========== 模板相关 2-001-000-200 ==========
ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在 ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2_001_000_200, "短信模板不合法"); // 包括短信模板不存在
ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确"); ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2_001_000_201, "模板参数不正确");
// ========== 签名相关 2001000300 ========== // ========== 签名相关 2-001-000-300 ==========
ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用"); ErrorCode SMS_SIGN_INVALID = new ErrorCode(2_001_000_300, "短信签名不可用");
// ========== 账户相关 2001000400 ========== // ========== 账户相关 2-001-000-400 ==========
ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足"); ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2_001_000_400, "账户余额不足");
ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在"); ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2_001_000_401, "apiKey 不存在");
// ========== 其它相关 2001000900 开头 ========== // ========== 其它相关 2-001-000-900 开头 ==========
ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失"); ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2_001_000_900, "请求参数缺失");
ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确"); ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2_001_000_901, "手机格式不正确");
ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中"); ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2_001_000_902, "手机号在黑名单中");
ErrorCode SMS_APP_ID_INVALID = new ErrorCode(2001000903, "SdkAppId不合法"); ErrorCode SMS_APP_ID_INVALID = new ErrorCode(2_001_000_903, "SdkAppId不合法");
ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常"); ErrorCode EXCEPTION = new ErrorCode(2_001_000_999, "调用异常");
} }

View File

@ -8,6 +8,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.BatchStrategies;
import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
@ -62,10 +63,12 @@ public class YudaoCacheAutoConfiguration {
@Bean @Bean
public RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate, public RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate,
RedisCacheConfiguration redisCacheConfiguration) { RedisCacheConfiguration redisCacheConfiguration,
YudaoCacheProperties yudaoCacheProperties) {
// 创建 RedisCacheWriter 对象 // 创建 RedisCacheWriter 对象
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
// 创建 TenantRedisCacheManager 对象 // 创建 TenantRedisCacheManager 对象
return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration); return new TimeoutRedisCacheManager(cacheWriter, redisCacheConfiguration);
} }

View File

@ -7,11 +7,17 @@ import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
import cn.iocoder.yudao.framework.jackson.core.databind.NumberSerializer; import cn.iocoder.yudao.framework.jackson.core.databind.NumberSerializer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List; import java.util.List;
@AutoConfiguration @AutoConfiguration
@ -27,6 +33,10 @@ public class YudaoJacksonAutoConfiguration {
// 新增 Long 类型序列化规则数值超过 2^53-1 JS 会出现精度丢失问题因此 Long 自动序列化为字符串类型 // 新增 Long 类型序列化规则数值超过 2^53-1 JS 会出现精度丢失问题因此 Long 自动序列化为字符串类型
.addSerializer(Long.class, NumberSerializer.INSTANCE) .addSerializer(Long.class, NumberSerializer.INSTANCE)
.addSerializer(Long.TYPE, NumberSerializer.INSTANCE) .addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// 新增 LocalDateTime 序列化反序列化规则 // 新增 LocalDateTime 序列化反序列化规则
.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE) .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE); .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.framework.jackson.core.databind; package cn.iocoder.yudao.framework.jackson.core.databind;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonDeserializer;
@ -20,7 +19,7 @@ public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer(); public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer();
@Override @Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault()); return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
} }
} }

View File

@ -258,12 +258,12 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
Long id = fileConfig.getId(); Long id = fileConfig.getId();
// mock 获得 Client // mock 获得 Client
FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig()); FileClient fileClient = new LocalFileClient(id, new LocalFileClientConfig());
when(fileClientFactory.getFileClient(eq(0L))).thenReturn(fileClient); when(fileClientFactory.getFileClient(eq(fileConfig.getId()))).thenReturn(fileClient);
// 调用并断言 // 调用并断言
assertSame(fileClient, fileConfigService.getMasterFileClient()); assertSame(fileClient, fileConfigService.getMasterFileClient());
// 断言缓存 // 断言缓存
verify(fileClientFactory).createOrUpdateFileClient(eq(0L), eq(fileConfig.getStorage()), verify(fileClientFactory).createOrUpdateFileClient(eq(fileConfig.getId()), eq(fileConfig.getStorage()),
eq(fileConfig.getConfig())); eq(fileConfig.getConfig()));
} }

View File

@ -18,33 +18,39 @@ public enum SocialTypeEnum implements IntArrayValuable {
/** /**
* Gitee * Gitee
* 文档链接https://gitee.com/api/v5/oauth_doc#/ *
* @see <a href="https://gitee.com/api/v5/oauth_doc#/">接入文档</a>
*/ */
GITEE(10, "GITEE"), GITEE(10, "GITEE"),
/** /**
* 钉钉 * 钉钉
* 文档链接https://developers.dingtalk.com/document/app/obtain-identity-credentials *
* @see <a href="https://developers.dingtalk.com/document/app/obtain-identity-credentials">接入文档</a>
*/ */
DINGTALK(20, "DINGTALK"), DINGTALK(20, "DINGTALK"),
/** /**
* 企业微信 * 企业微信
* 文档链接https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html *
* @see <a href="https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html">接入文档</a>
*/ */
WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"),
/** /**
* 微信公众平台 - 移动端 H5 * 微信公众平台 - 移动端 H5
* 文档链接https://www.cnblogs.com/juewuzhe/p/11905461.html *
* @see <a href="https://www.cnblogs.com/juewuzhe/p/11905461.html">接入文档</a>
*/ */
WECHAT_MP(31, "WECHAT_MP"), WECHAT_MP(31, "WECHAT_MP"),
/** /**
* 微信开放平台 - 网站应用 PC 端扫码授权登录 * 微信开放平台 - 网站应用 PC 端扫码授权登录
* 文档链接https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证 *
* @see <a href="https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证">接入文档</a>
*/ */
WECHAT_OPEN(32, "WECHAT_OPEN"), WECHAT_OPEN(32, "WECHAT_OPEN"),
/** /**
* 微信小程序 * 微信小程序
* 文档链接https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html *
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html">接入文档</a>
*/ */
WECHAT_MINI_APP(34, "WECHAT_MINI_APP"), WECHAT_MINI_APP(34, "WECHAT_MINI_APP"),
; ;

View File

@ -6,17 +6,17 @@ import cn.iocoder.yudao.framework.ip.core.Area;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.framework.ip.core.utils.IPUtils; import cn.iocoder.yudao.framework.ip.core.utils.IPUtils;
import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO; import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO;
import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeSimpleRespVO;
import cn.iocoder.yudao.module.system.convert.ip.AreaConvert; import cn.iocoder.yudao.module.system.convert.ip.AreaConvert;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -34,28 +34,6 @@ public class AreaController {
return success(AreaConvert.INSTANCE.convertList(area.getChildren())); return success(AreaConvert.INSTANCE.convertList(area.getChildren()));
} }
@GetMapping("/get-children")
@Operation(summary = "获得地区的下级区域")
@Parameter(name = "id", description = "区域编号", required = true, example = "150000")
public CommonResult<List<AreaNodeSimpleRespVO>> getChildren(@RequestParam("id") Integer id) {
Area area = AreaUtils.getArea(id);
Assert.notNull(area, String.format("获取不到 id : %d 的区域", id));
return success(AreaConvert.INSTANCE.convertList2(area.getChildren()));
}
// 4)方法改成 getAreaChildrenList 获得子节点们5url 可以已改成 children-list
//@芋艿 是不是叫 getAreaListByIds 更合适 因为不一定是子节点 用于前端树选择获取缓存数据 <el-tree-select :cache-data="areaCache">
@GetMapping("/get-by-ids")
@Operation(summary = "通过区域 ids 获得地区列表")
@Parameter(name = "ids", description = "区域编号 ids", required = true, example = "1,150000")
public CommonResult<List<AreaNodeSimpleRespVO>> getAreaListByIds(@RequestParam("ids") Set<Integer> ids) {
List<Area> areaList = new ArrayList<>(ids.size());
for (Integer areaId : ids) {
areaList.add(AreaUtils.getArea(areaId));
}
return success(AreaConvert.INSTANCE.convertList2(areaList));
}
@GetMapping("/get-by-ip") @GetMapping("/get-by-ip")
@Operation(summary = "获得 IP 对应的地区名") @Operation(summary = "获得 IP 对应的地区名")
@Parameter(name = "ip", description = "IP", required = true) @Parameter(name = "ip", description = "IP", required = true)

View File

@ -1,19 +0,0 @@
package cn.iocoder.yudao.module.system.controller.admin.ip.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 简洁的地区节点 Response VO")
@Data
public class AreaNodeSimpleRespVO {
@Schema(description = "编号", required = true, example = "110000")
private Integer id;
@Schema(description = "名字", required = true, example = "北京")
private String name;
@Schema(description = "是否叶子节点", required = false, example = "false")
private Boolean leaf;
}

View File

@ -1,4 +1,39 @@
package cn.iocoder.yudao.module.system.controller.app.dict; package cn.iocoder.yudao.module.system.controller.app.dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.app.dict.vo.AppDictDataRespVO;
import cn.iocoder.yudao.module.system.convert.dict.DictDataConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "用户 App - 字典数据")
@RestController
@RequestMapping("/system/dict-data")
@Validated
public class AppDictDataController { public class AppDictDataController {
@Resource
private DictDataService dictDataService;
@GetMapping("/type")
@Operation(summary = "根据字典类型查询字典数据信息")
@Parameter(name = "type", description = "字典类型", required = true, example = "common_status")
public CommonResult<List<AppDictDataRespVO>> getDictDataListByType(@RequestParam("type") String type) {
List<DictDataDO> list = dictDataService.getEnabledDictDataListByType(type);
return success(DictDataConvert.INSTANCE.convertList03(list));
}
} }

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.system.controller.app.dict.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "用户 App - 字典数据信息 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AppDictDataRespVO {
@Schema(description = "字典数据编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "字典标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
private String label;
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
private String value;
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
private String dictType;
}