
18 changed files with 2113 additions and 57 deletions
@ -0,0 +1,223 @@ |
|||||
|
package com.yxt.ss.gateway.api; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.yxt.ss.gateway.api.authutils.*; |
||||
|
import com.yxt.ss.gateway.api.utils.AppKeyConfig; |
||||
|
import com.yxt.ss.gateway.api.utils.ResultBean; |
||||
|
import com.yxt.ss.gateway.api.utils.SignatureUtil; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain; |
||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter; |
||||
|
import org.springframework.core.Ordered; |
||||
|
import org.springframework.core.io.buffer.DataBuffer; |
||||
|
import org.springframework.core.io.buffer.DataBufferUtils; |
||||
|
import org.springframework.http.HttpMethod; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.util.MultiValueMap; |
||||
|
import org.springframework.web.server.ServerWebExchange; |
||||
|
import reactor.core.publisher.Mono; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.io.UnsupportedEncodingException; |
||||
|
import java.net.URLDecoder; |
||||
|
import java.nio.CharBuffer; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.time.Instant; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description 网关鉴权 |
||||
|
*/ |
||||
|
@Component |
||||
|
public class AuthFilter implements GlobalFilter, Ordered { |
||||
|
|
||||
|
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); |
||||
|
|
||||
|
@Autowired |
||||
|
private IgnoreWhiteProperties ignoreWhite; |
||||
|
@Autowired |
||||
|
private AppKeyConfig appKeyConfig; |
||||
|
|
||||
|
public String getSecret(String appKey) { |
||||
|
return appKeyConfig.getKeys().get(appKey); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
||||
|
String url = exchange.getRequest().getURI().getPath(); |
||||
|
// 1. URI 白名单过滤:如果请求路径在白名单中,直接放行
|
||||
|
if (isWhitelisted(url)) { |
||||
|
return chain.filter(exchange); |
||||
|
} |
||||
|
|
||||
|
// 2. 提取请求参数并进行验证
|
||||
|
return extractParameters(exchange) |
||||
|
.flatMap(parameters -> { |
||||
|
// 校验请求参数
|
||||
|
ResultBean validationResult = validate(parameters); |
||||
|
// 校验失败,返回 401 Unauthorized 错误响应
|
||||
|
if (!validationResult.getSuccess()) { |
||||
|
return setUnauthorizedResponse(exchange, validationResult.getMsg()); |
||||
|
} |
||||
|
|
||||
|
// 3. 如果需要,可以从参数中提取信息并添加到请求头
|
||||
|
ServerHttpRequest mutableReq = exchange.getRequest().mutate() |
||||
|
.header(CacheConstants._APP, parameters.get("_app")) |
||||
|
.build(); |
||||
|
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build(); |
||||
|
// 4. 继续执行后续过滤器链
|
||||
|
return chain.filter(mutableExchange); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 提取请求参数方法:根据请求类型 (GET 或 POST) 提取参数
|
||||
|
private Mono<Map<String, String>> extractParameters(ServerWebExchange exchange) { |
||||
|
HttpMethod method = exchange.getRequest().getMethod(); |
||||
|
// 1. 如果是 GET 请求,从 URL 查询参数中提取
|
||||
|
if (method == HttpMethod.GET) { |
||||
|
return Mono.just(exchange.getRequest().getQueryParams().toSingleValueMap()); |
||||
|
} |
||||
|
// 如果是 POST、PUT 或 DELETE 请求,从请求体中提取参数
|
||||
|
if (exchange.getRequest().getMethod() == HttpMethod.POST || |
||||
|
exchange.getRequest().getMethod() == HttpMethod.PUT || |
||||
|
exchange.getRequest().getMethod() == HttpMethod.DELETE) { |
||||
|
|
||||
|
String contentType = exchange.getRequest().getHeaders().getContentType().toString(); |
||||
|
if (contentType.contains("application/json")) { |
||||
|
return exchange.getRequest().getBody() |
||||
|
.collectList() |
||||
|
.map(dataBuffers -> { |
||||
|
// 将 DataBuffer 转换为字符串
|
||||
|
StringBuilder bodyBuilder = new StringBuilder(); |
||||
|
dataBuffers.forEach(dataBuffer -> { |
||||
|
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer()); |
||||
|
bodyBuilder.append(charBuffer); |
||||
|
}); |
||||
|
|
||||
|
// 解析 JSON 请求体
|
||||
|
try { |
||||
|
return parseJsonBody(bodyBuilder.toString()); |
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return new HashMap<String, String>(); // 如果解析失败,返回空 Map
|
||||
|
}); |
||||
|
} else if (contentType.contains("application/x-www-form-urlencoded")) { |
||||
|
// 处理 x-www-form-urlencoded 格式
|
||||
|
return exchange.getRequest().getBody() |
||||
|
.collectList() |
||||
|
.map(dataBuffers -> { |
||||
|
StringBuilder bodyBuilder = new StringBuilder(); |
||||
|
dataBuffers.forEach(dataBuffer -> { |
||||
|
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer()); |
||||
|
bodyBuilder.append(charBuffer); |
||||
|
}); |
||||
|
try { |
||||
|
return parseFormBody(bodyBuilder.toString()); |
||||
|
} catch (UnsupportedEncodingException e) { |
||||
|
e.printStackTrace(); |
||||
|
} |
||||
|
return new HashMap<String, String>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 其他情况返回空 Map
|
||||
|
return Mono.just(new HashMap<>()); |
||||
|
} |
||||
|
|
||||
|
//解析 JSON 请求体的方法
|
||||
|
private Map<String, String> parseJsonBody(String body) throws IOException { |
||||
|
ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
return objectMapper.readValue(body, Map.class); |
||||
|
} |
||||
|
|
||||
|
// 辅助方法:解析 form-data 格式字符串
|
||||
|
private Map<String, String> parseFormBody(String body) throws UnsupportedEncodingException { |
||||
|
Map<String, String> parameters = new HashMap<>(); |
||||
|
// 按照 & 分割每一对键值
|
||||
|
String[] pairs = body.split("&"); |
||||
|
for (String pair : pairs) { |
||||
|
String[] keyValue = pair.split("="); |
||||
|
if (keyValue.length == 2) { |
||||
|
// 解码键和值
|
||||
|
parameters.put(URLDecoder.decode(keyValue[0], "UTF-8"), |
||||
|
URLDecoder.decode(keyValue[1], "UTF-8")); |
||||
|
} |
||||
|
} |
||||
|
return parameters; |
||||
|
} |
||||
|
|
||||
|
// 设置未授权响应方法
|
||||
|
private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String message) { |
||||
|
// 设置响应状态码为 401 Unauthorized
|
||||
|
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); |
||||
|
// 设置响应内容类型为 JSON
|
||||
|
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); |
||||
|
// 创建返回的错误信息
|
||||
|
DataBuffer buffer = exchange.getResponse().bufferFactory() |
||||
|
.wrap(("{\"error\":\"" + message + "\"}").getBytes(StandardCharsets.UTF_8)); |
||||
|
return exchange.getResponse().writeWith(Mono.just(buffer)); |
||||
|
} |
||||
|
|
||||
|
private boolean isWhitelisted(String url) { |
||||
|
return StringUtils.matches(url, ignoreWhite.getWhites()) || |
||||
|
StringUtils.matchesTwo(url, ignoreWhite.getWhitesTwo()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getOrder() { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
ResultBean validate(Map<String, String> data) { |
||||
|
ResultBean rb = ResultBean.fireFail(); |
||||
|
// 解析参数
|
||||
|
String app = data.get("_app"); |
||||
|
if (org.springframework.util.StringUtils.isEmpty(app)) { |
||||
|
return rb.setMsg("_app参数缺失或无效"); |
||||
|
} |
||||
|
// 获取 secret 值
|
||||
|
String secret = getSecret(app); |
||||
|
if (org.springframework.util.StringUtils.isEmpty(secret)) { |
||||
|
return rb.setMsg("_app参数不正确"); |
||||
|
} |
||||
|
// 校验时间戳 _t 参数
|
||||
|
String timestampStr = data.get("_t"); |
||||
|
if (org.springframework.util.StringUtils.isEmpty(timestampStr)) { |
||||
|
return rb.setMsg("_t参数缺失"); |
||||
|
} |
||||
|
long timestamp; |
||||
|
try { |
||||
|
timestamp = Long.parseLong(timestampStr); |
||||
|
} catch (NumberFormatException e) { |
||||
|
return rb.setMsg("_t参数格式不正确"); |
||||
|
} |
||||
|
// 时间范围校验
|
||||
|
long currentTimestamp = Instant.now().getEpochSecond(); |
||||
|
long timeDifference = Math.abs(currentTimestamp - timestamp); |
||||
|
final int ALLOWED_TIME_DIFF = 300; // 最大允许时间偏差(秒)
|
||||
|
if (timeDifference > ALLOWED_TIME_DIFF) { |
||||
|
return rb.setMsg("时间已超过5分钟,时间失效"); |
||||
|
} |
||||
|
|
||||
|
// 签名验证
|
||||
|
ResultBean<Boolean> resultBean = SignatureUtil.validateSignature(data, secret); |
||||
|
if (!resultBean.getSuccess()) { |
||||
|
return rb.setMsg(resultBean.getMsg()); |
||||
|
} |
||||
|
|
||||
|
return rb.success(); |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description 缓存的key 常量 |
||||
|
*/ |
||||
|
|
||||
|
public class CacheConstants { |
||||
|
|
||||
|
/** |
||||
|
* 令牌自定义标识 |
||||
|
*/ |
||||
|
public static final String HEADER = "token"; |
||||
|
|
||||
|
/** |
||||
|
* 令牌前缀 |
||||
|
*/ |
||||
|
public static final String TOKEN_PREFIX = "Bearer "; |
||||
|
|
||||
|
/** |
||||
|
* 用户名字段 |
||||
|
*/ |
||||
|
public static final String DETAILS_USERNAME = "userName"; |
||||
|
public static final String _APP = "_app"; |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
import java.nio.charset.Charset; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description |
||||
|
*/ |
||||
|
|
||||
|
public class CharsetKit { |
||||
|
|
||||
|
/** |
||||
|
* ISO-8859-1 |
||||
|
*/ |
||||
|
public static final String ISO_8859_1 = "ISO-8859-1"; |
||||
|
/** |
||||
|
* UTF-8 |
||||
|
*/ |
||||
|
public static final String UTF_8 = "UTF-8"; |
||||
|
/** |
||||
|
* GBK |
||||
|
*/ |
||||
|
public static final String GBK = "GBK"; |
||||
|
|
||||
|
/** |
||||
|
* ISO-8859-1 |
||||
|
*/ |
||||
|
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); |
||||
|
/** |
||||
|
* UTF-8 |
||||
|
*/ |
||||
|
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); |
||||
|
/** |
||||
|
* GBK |
||||
|
*/ |
||||
|
public static final Charset CHARSET_GBK = Charset.forName(GBK); |
||||
|
|
||||
|
/** |
||||
|
* 转换为Charset对象 |
||||
|
* |
||||
|
* @param charset 字符集,为空则返回默认字符集 |
||||
|
* @return Charset |
||||
|
*/ |
||||
|
public static Charset charset(String charset) { |
||||
|
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换字符串的字符集编码 |
||||
|
* |
||||
|
* @param source 字符串 |
||||
|
* @param srcCharset 源字符集,默认ISO-8859-1 |
||||
|
* @param destCharset 目标字符集,默认UTF-8 |
||||
|
* @return 转换后的字符集 |
||||
|
*/ |
||||
|
public static String convert(String source, String srcCharset, String destCharset) { |
||||
|
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换字符串的字符集编码 |
||||
|
* |
||||
|
* @param source 字符串 |
||||
|
* @param srcCharset 源字符集,默认ISO-8859-1 |
||||
|
* @param destCharset 目标字符集,默认UTF-8 |
||||
|
* @return 转换后的字符集 |
||||
|
*/ |
||||
|
public static String convert(String source, Charset srcCharset, Charset destCharset) { |
||||
|
if (null == srcCharset) { |
||||
|
srcCharset = StandardCharsets.ISO_8859_1; |
||||
|
} |
||||
|
|
||||
|
if (null == destCharset) { |
||||
|
destCharset = StandardCharsets.UTF_8; |
||||
|
} |
||||
|
|
||||
|
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) { |
||||
|
return source; |
||||
|
} |
||||
|
return new String(source.getBytes(srcCharset), destCharset); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @return 系统字符集编码 |
||||
|
*/ |
||||
|
public static String systemCharset() { |
||||
|
return Charset.defaultCharset().name(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,849 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.math.BigInteger; |
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.nio.charset.Charset; |
||||
|
import java.text.NumberFormat; |
||||
|
import java.util.Set; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description |
||||
|
*/ |
||||
|
|
||||
|
public class Convert { |
||||
|
|
||||
|
/** |
||||
|
* 转换为字符串<br> |
||||
|
* 如果给定的值为null,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String toStr(Object value, String defaultValue) { |
||||
|
if (null == value) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof String) { |
||||
|
return (String) value; |
||||
|
} |
||||
|
return value.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为字符串<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String toStr(Object value) { |
||||
|
return toStr(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为字符<br> |
||||
|
* 如果给定的值为null,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Character toChar(Object value, Character defaultValue) { |
||||
|
if (null == value) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Character) { |
||||
|
return (Character) value; |
||||
|
} |
||||
|
|
||||
|
final String valueStr = toStr(value, null); |
||||
|
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为字符<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Character toChar(Object value) { |
||||
|
return toChar(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为byte<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Byte toByte(Object value, Byte defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Byte) { |
||||
|
return (Byte) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).byteValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return Byte.parseByte(valueStr); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为byte<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Byte toByte(Object value) { |
||||
|
return toByte(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Short<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Short toShort(Object value, Short defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Short) { |
||||
|
return (Short) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).shortValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return Short.parseShort(valueStr.trim()); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Short<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Short toShort(Object value) { |
||||
|
return toShort(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Number<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Number toNumber(Object value, Number defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return (Number) value; |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return NumberFormat.getInstance().parse(valueStr); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Number<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Number toNumber(Object value) { |
||||
|
return toNumber(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为int<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Integer toInt(Object value, Integer defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Integer) { |
||||
|
return (Integer) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).intValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return Integer.parseInt(valueStr.trim()); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为int<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Integer toInt(Object value) { |
||||
|
return toInt(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Integer数组<br> |
||||
|
* |
||||
|
* @param str 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Integer[] toIntArray(String str) { |
||||
|
return toIntArray(",", str); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Long数组<br> |
||||
|
* |
||||
|
* @param str 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Long[] toLongArray(String str) { |
||||
|
return toLongArray(",", str); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Integer数组<br> |
||||
|
* |
||||
|
* @param split 分隔符 |
||||
|
* @param split 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Integer[] toIntArray(String split, String str) { |
||||
|
if (StringUtils.isEmpty(str)) { |
||||
|
return new Integer[]{}; |
||||
|
} |
||||
|
String[] arr = str.split(split); |
||||
|
final Integer[] ints = new Integer[arr.length]; |
||||
|
for (int i = 0; i < arr.length; i++) { |
||||
|
final Integer v = toInt(arr[i], 0); |
||||
|
ints[i] = v; |
||||
|
} |
||||
|
return ints; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Long数组<br> |
||||
|
* |
||||
|
* @param split 分隔符 |
||||
|
* @param str 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Long[] toLongArray(String split, String str) { |
||||
|
if (StringUtils.isEmpty(str)) { |
||||
|
return new Long[]{}; |
||||
|
} |
||||
|
String[] arr = str.split(split); |
||||
|
final Long[] longs = new Long[arr.length]; |
||||
|
for (int i = 0; i < arr.length; i++) { |
||||
|
final Long v = toLong(arr[i], null); |
||||
|
longs[i] = v; |
||||
|
} |
||||
|
return longs; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为String数组<br> |
||||
|
* |
||||
|
* @param str 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String[] toStrArray(String str) { |
||||
|
return toStrArray(",", str); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为String数组<br> |
||||
|
* |
||||
|
* @param split 分隔符 |
||||
|
* @param split 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String[] toStrArray(String split, String str) { |
||||
|
return str.split(split); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为long<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Long toLong(Object value, Long defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Long) { |
||||
|
return (Long) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).longValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
// 支持科学计数法
|
||||
|
return new BigDecimal(valueStr.trim()).longValue(); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为long<br> |
||||
|
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Long toLong(Object value) { |
||||
|
return toLong(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为double<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Double toDouble(Object value, Double defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Double) { |
||||
|
return (Double) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).doubleValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
// 支持科学计数法
|
||||
|
return new BigDecimal(valueStr.trim()).doubleValue(); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为double<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Double toDouble(Object value) { |
||||
|
return toDouble(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Float<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Float toFloat(Object value, Float defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Float) { |
||||
|
return (Float) value; |
||||
|
} |
||||
|
if (value instanceof Number) { |
||||
|
return ((Number) value).floatValue(); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return Float.parseFloat(valueStr.trim()); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Float<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Float toFloat(Object value) { |
||||
|
return toFloat(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为boolean<br> |
||||
|
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Boolean toBool(Object value, Boolean defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof Boolean) { |
||||
|
return (Boolean) value; |
||||
|
} |
||||
|
String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
valueStr = valueStr.trim().toLowerCase(); |
||||
|
switch (valueStr) { |
||||
|
case "true": |
||||
|
return true; |
||||
|
case "false": |
||||
|
return false; |
||||
|
case "yes": |
||||
|
return true; |
||||
|
case "ok": |
||||
|
return true; |
||||
|
case "no": |
||||
|
return false; |
||||
|
case "1": |
||||
|
return true; |
||||
|
case "0": |
||||
|
return false; |
||||
|
default: |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为boolean<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static Boolean toBool(Object value) { |
||||
|
return toBool(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Enum对象<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* |
||||
|
* @param clazz Enum的Class |
||||
|
* @param value 值 |
||||
|
* @param defaultValue 默认值 |
||||
|
* @return Enum |
||||
|
*/ |
||||
|
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (clazz.isAssignableFrom(value.getClass())) { |
||||
|
@SuppressWarnings("unchecked") |
||||
|
E myE = (E) value; |
||||
|
return myE; |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return Enum.valueOf(clazz, valueStr); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为Enum对象<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* |
||||
|
* @param clazz Enum的Class |
||||
|
* @param value 值 |
||||
|
* @return Enum |
||||
|
*/ |
||||
|
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) { |
||||
|
return toEnum(clazz, value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为BigInteger<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static BigInteger toBigInteger(Object value, BigInteger defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof BigInteger) { |
||||
|
return (BigInteger) value; |
||||
|
} |
||||
|
if (value instanceof Long) { |
||||
|
return BigInteger.valueOf((Long) value); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return new BigInteger(valueStr); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为BigInteger<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static BigInteger toBigInteger(Object value) { |
||||
|
return toBigInteger(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为BigDecimal<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @param defaultValue 转换错误时的默认值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) { |
||||
|
if (value == null) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
if (value instanceof BigDecimal) { |
||||
|
return (BigDecimal) value; |
||||
|
} |
||||
|
if (value instanceof Long) { |
||||
|
return new BigDecimal((Long) value); |
||||
|
} |
||||
|
if (value instanceof Double) { |
||||
|
return new BigDecimal((Double) value); |
||||
|
} |
||||
|
if (value instanceof Integer) { |
||||
|
return new BigDecimal((Integer) value); |
||||
|
} |
||||
|
final String valueStr = toStr(value, null); |
||||
|
if (StringUtils.isEmpty(valueStr)) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
try { |
||||
|
return new BigDecimal(valueStr); |
||||
|
} catch (Exception e) { |
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 转换为BigDecimal<br> |
||||
|
* 如果给定的值为空,或者转换失败,返回默认值<br> |
||||
|
* 转换失败不会报错 |
||||
|
* |
||||
|
* @param value 被转换的值 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static BigDecimal toBigDecimal(Object value) { |
||||
|
return toBigDecimal(value, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将对象转为字符串<br> |
||||
|
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 |
||||
|
* |
||||
|
* @param obj 对象 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String utf8Str(Object obj) { |
||||
|
return str(obj, CharsetKit.CHARSET_UTF_8); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将对象转为字符串<br> |
||||
|
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 |
||||
|
* |
||||
|
* @param obj 对象 |
||||
|
* @param charsetName 字符集 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String str(Object obj, String charsetName) { |
||||
|
return str(obj, Charset.forName(charsetName)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将对象转为字符串<br> |
||||
|
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 |
||||
|
* |
||||
|
* @param obj 对象 |
||||
|
* @param charset 字符集 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String str(Object obj, Charset charset) { |
||||
|
if (null == obj) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (obj instanceof String) { |
||||
|
return (String) obj; |
||||
|
} else if (obj instanceof byte[] || obj instanceof Byte[]) { |
||||
|
return str((Byte[]) obj, charset); |
||||
|
} else if (obj instanceof ByteBuffer) { |
||||
|
return str((ByteBuffer) obj, charset); |
||||
|
} |
||||
|
return obj.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将byte数组转为字符串 |
||||
|
* |
||||
|
* @param bytes byte数组 |
||||
|
* @param charset 字符集 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String str(byte[] bytes, String charset) { |
||||
|
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 解码字节码 |
||||
|
* |
||||
|
* @param data 字符串 |
||||
|
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台 |
||||
|
* @return 解码后的字符串 |
||||
|
*/ |
||||
|
public static String str(byte[] data, Charset charset) { |
||||
|
if (data == null) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (null == charset) { |
||||
|
return new String(data); |
||||
|
} |
||||
|
return new String(data, charset); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将编码的byteBuffer数据转换为字符串 |
||||
|
* |
||||
|
* @param data 数据 |
||||
|
* @param charset 字符集,如果为空使用当前系统字符集 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String str(ByteBuffer data, String charset) { |
||||
|
if (data == null) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return str(data, Charset.forName(charset)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将编码的byteBuffer数据转换为字符串 |
||||
|
* |
||||
|
* @param data 数据 |
||||
|
* @param charset 字符集,如果为空使用当前系统字符集 |
||||
|
* @return 字符串 |
||||
|
*/ |
||||
|
public static String str(ByteBuffer data, Charset charset) { |
||||
|
if (null == charset) { |
||||
|
charset = Charset.defaultCharset(); |
||||
|
} |
||||
|
return charset.decode(data).toString(); |
||||
|
} |
||||
|
|
||||
|
// ----------------------------------------------------------------------- 全角半角转换
|
||||
|
|
||||
|
/** |
||||
|
* 半角转全角 |
||||
|
* |
||||
|
* @param input String. |
||||
|
* @return 全角字符串. |
||||
|
*/ |
||||
|
public static String toSBC(String input) { |
||||
|
return toSBC(input, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 半角转全角 |
||||
|
* |
||||
|
* @param input String |
||||
|
* @param notConvertSet 不替换的字符集合 |
||||
|
* @return 全角字符串. |
||||
|
*/ |
||||
|
public static String toSBC(String input, Set<Character> notConvertSet) { |
||||
|
char c[] = input.toCharArray(); |
||||
|
for (int i = 0; i < c.length; i++) { |
||||
|
if (null != notConvertSet && notConvertSet.contains(c[i])) { |
||||
|
// 跳过不替换的字符
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (c[i] == ' ') { |
||||
|
c[i] = '\u3000'; |
||||
|
} else if (c[i] < '\177') { |
||||
|
c[i] = (char) (c[i] + 65248); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
return new String(c); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 全角转半角 |
||||
|
* |
||||
|
* @param input String. |
||||
|
* @return 半角字符串 |
||||
|
*/ |
||||
|
public static String toDBC(String input) { |
||||
|
return toDBC(input, null); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 替换全角为半角 |
||||
|
* |
||||
|
* @param text 文本 |
||||
|
* @param notConvertSet 不替换的字符集合 |
||||
|
* @return 替换后的字符 |
||||
|
*/ |
||||
|
public static String toDBC(String text, Set<Character> notConvertSet) { |
||||
|
char c[] = text.toCharArray(); |
||||
|
for (int i = 0; i < c.length; i++) { |
||||
|
if (null != notConvertSet && notConvertSet.contains(c[i])) { |
||||
|
// 跳过不替换的字符
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (c[i] == '\u3000') { |
||||
|
c[i] = ' '; |
||||
|
} else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { |
||||
|
c[i] = (char) (c[i] - 65248); |
||||
|
} |
||||
|
} |
||||
|
String returnString = new String(c); |
||||
|
|
||||
|
return returnString; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数字金额大写转换 先写个完整的然后将如零拾替换成零 |
||||
|
* |
||||
|
* @param n 数字 |
||||
|
* @return 中文大写数字 |
||||
|
*/ |
||||
|
public static String digitUppercase(double n) { |
||||
|
String[] fraction = {"角", "分"}; |
||||
|
String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; |
||||
|
String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}}; |
||||
|
|
||||
|
String head = n < 0 ? "负" : ""; |
||||
|
n = Math.abs(n); |
||||
|
|
||||
|
String s = ""; |
||||
|
for (int i = 0; i < fraction.length; i++) { |
||||
|
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); |
||||
|
} |
||||
|
if (s.length() < 1) { |
||||
|
s = "整"; |
||||
|
} |
||||
|
int integerPart = (int) Math.floor(n); |
||||
|
|
||||
|
for (int i = 0; i < unit[0].length && integerPart > 0; i++) { |
||||
|
String p = ""; |
||||
|
for (int j = 0; j < unit[1].length && n > 0; j++) { |
||||
|
p = digit[integerPart % 10] + unit[1][j] + p; |
||||
|
integerPart = integerPart / 10; |
||||
|
} |
||||
|
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; |
||||
|
} |
||||
|
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.cloud.context.config.annotation.RefreshScope; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description 放行白名单配置 |
||||
|
*/ |
||||
|
@Configuration |
||||
|
@RefreshScope |
||||
|
@ConfigurationProperties(prefix = "ignore") |
||||
|
public class IgnoreWhiteProperties { |
||||
|
|
||||
|
/** |
||||
|
* 放行白名单配置,网关不校验此处的白名单 |
||||
|
*/ |
||||
|
private List<String> whites = new ArrayList<>(); |
||||
|
|
||||
|
public List<String> getWhites() { |
||||
|
return whites; |
||||
|
} |
||||
|
|
||||
|
public void setWhites(List<String> whites) { |
||||
|
this.whites = whites; |
||||
|
} |
||||
|
|
||||
|
private List<String> whitesTwo = new ArrayList<>(); |
||||
|
|
||||
|
public List<String> getWhitesTwo() { |
||||
|
return whitesTwo; |
||||
|
} |
||||
|
|
||||
|
public void setWhitesTwo(List<String> whitesTwo) { |
||||
|
this.whitesTwo = whitesTwo; |
||||
|
} |
||||
|
} |
@ -0,0 +1,75 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description |
||||
|
*/ |
||||
|
|
||||
|
public class StrFormatter { |
||||
|
|
||||
|
public static final String EMPTY_JSON = "{}"; |
||||
|
public static final char C_BACKSLASH = '\\'; |
||||
|
public static final char C_DELIM_START = '{'; |
||||
|
public static final char C_DELIM_END = '}'; |
||||
|
|
||||
|
/** |
||||
|
* 格式化字符串<br> |
||||
|
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br> |
||||
|
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> |
||||
|
* 例:<br> |
||||
|
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> |
||||
|
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> |
||||
|
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> |
||||
|
* |
||||
|
* @param strPattern 字符串模板 |
||||
|
* @param argArray 参数列表 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String format(final String strPattern, final Object... argArray) { |
||||
|
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) { |
||||
|
return strPattern; |
||||
|
} |
||||
|
final int strPatternLength = strPattern.length(); |
||||
|
|
||||
|
// 初始化定义好的长度以获得更好的性能
|
||||
|
StringBuilder sbuf = new StringBuilder(strPatternLength + 50); |
||||
|
|
||||
|
int handledPosition = 0; |
||||
|
int delimIndex;// 占位符所在位置
|
||||
|
for (int argIndex = 0; argIndex < argArray.length; argIndex++) { |
||||
|
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); |
||||
|
if (delimIndex == -1) { |
||||
|
if (handledPosition == 0) { |
||||
|
return strPattern; |
||||
|
} else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
|
||||
|
sbuf.append(strPattern, handledPosition, strPatternLength); |
||||
|
return sbuf.toString(); |
||||
|
} |
||||
|
} else { |
||||
|
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) { |
||||
|
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) { |
||||
|
// 转义符之前还有一个转义符,占位符依旧有效
|
||||
|
sbuf.append(strPattern, handledPosition, delimIndex - 1); |
||||
|
sbuf.append(Convert.utf8Str(argArray[argIndex])); |
||||
|
handledPosition = delimIndex + 2; |
||||
|
} else { |
||||
|
// 占位符被转义
|
||||
|
argIndex--; |
||||
|
sbuf.append(strPattern, handledPosition, delimIndex - 1); |
||||
|
sbuf.append(C_DELIM_START); |
||||
|
handledPosition = delimIndex + 1; |
||||
|
} |
||||
|
} else { |
||||
|
// 正常占位符
|
||||
|
sbuf.append(strPattern, handledPosition, delimIndex); |
||||
|
sbuf.append(Convert.utf8Str(argArray[argIndex])); |
||||
|
handledPosition = delimIndex + 2; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// 加入最后一个占位符后所有的字符
|
||||
|
sbuf.append(strPattern, handledPosition, strPattern.length()); |
||||
|
|
||||
|
return sbuf.toString(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,525 @@ |
|||||
|
package com.yxt.ss.gateway.api.authutils; |
||||
|
|
||||
|
import java.util.Collection; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @description |
||||
|
*/ |
||||
|
|
||||
|
public class StringUtils extends org.apache.commons.lang3.StringUtils { |
||||
|
|
||||
|
/** |
||||
|
* 空字符串 |
||||
|
*/ |
||||
|
private static final String NULLSTR = ""; |
||||
|
|
||||
|
/** |
||||
|
* 下划线 |
||||
|
*/ |
||||
|
private static final char SEPARATOR = '_'; |
||||
|
|
||||
|
/** |
||||
|
* 星号 |
||||
|
*/ |
||||
|
private static final String START = "*"; |
||||
|
|
||||
|
/** |
||||
|
* 获取参数不为空值 |
||||
|
* |
||||
|
* @param value defaultValue 要判断的value |
||||
|
* @return value 返回值 |
||||
|
*/ |
||||
|
public static <T> T nvl(T value, T defaultValue) { |
||||
|
return value != null ? value : defaultValue; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个Collection是否为空, 包含List,Set,Queue |
||||
|
* |
||||
|
* @param coll 要判断的Collection |
||||
|
* @return true:为空 false:非空 |
||||
|
*/ |
||||
|
public static boolean isEmpty(Collection<?> coll) { |
||||
|
return isNull(coll) || coll.isEmpty(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个Collection是否非空,包含List,Set,Queue |
||||
|
* |
||||
|
* @param coll 要判断的Collection |
||||
|
* @return true:非空 false:空 |
||||
|
*/ |
||||
|
public static boolean isNotEmpty(Collection<?> coll) { |
||||
|
return !isEmpty(coll); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个对象数组是否为空 |
||||
|
* |
||||
|
* @param objects 要判断的对象数组 |
||||
|
* * @return true:为空 false:非空 |
||||
|
*/ |
||||
|
public static boolean isEmpty(Object[] objects) { |
||||
|
return isNull(objects) || (objects.length == 0); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个对象数组是否非空 |
||||
|
* |
||||
|
* @param objects 要判断的对象数组 |
||||
|
* @return true:非空 false:空 |
||||
|
*/ |
||||
|
public static boolean isNotEmpty(Object[] objects) { |
||||
|
return !isEmpty(objects); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个Map是否为空 |
||||
|
* |
||||
|
* @param map 要判断的Map |
||||
|
* @return true:为空 false:非空 |
||||
|
*/ |
||||
|
public static boolean isEmpty(Map<?, ?> map) { |
||||
|
return isNull(map) || map.isEmpty(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个Map是否为空 |
||||
|
* |
||||
|
* @param map 要判断的Map |
||||
|
* @return true:非空 false:空 |
||||
|
*/ |
||||
|
public static boolean isNotEmpty(Map<?, ?> map) { |
||||
|
return !isEmpty(map); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个字符串是否为空串 |
||||
|
* |
||||
|
* @param str String |
||||
|
* @return true:为空 false:非空 |
||||
|
*/ |
||||
|
public static boolean isEmpty(String str) { |
||||
|
return isNull(str) || NULLSTR.equals(str.trim()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个字符串是否为非空串 |
||||
|
* |
||||
|
* @param str String |
||||
|
* @return true:非空串 false:空串 |
||||
|
*/ |
||||
|
public static boolean isNotEmpty(String str) { |
||||
|
return !isEmpty(str); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个对象是否为空 |
||||
|
* |
||||
|
* @param object Object |
||||
|
* @return true:为空 false:非空 |
||||
|
*/ |
||||
|
public static boolean isNull(Object object) { |
||||
|
return object == null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个对象是否非空 |
||||
|
* |
||||
|
* @param object Object |
||||
|
* @return true:非空 false:空 |
||||
|
*/ |
||||
|
public static boolean isNotNull(Object object) { |
||||
|
return !isNull(object); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* * 判断一个对象是否是数组类型(Java基本型别的数组) |
||||
|
* |
||||
|
* @param object 对象 |
||||
|
* @return true:是数组 false:不是数组 |
||||
|
*/ |
||||
|
public static boolean isArray(Object object) { |
||||
|
return isNotNull(object) && object.getClass().isArray(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 去空格 |
||||
|
*/ |
||||
|
public static String trim(String str) { |
||||
|
return (str == null ? "" : str.trim()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 截取字符串 |
||||
|
* |
||||
|
* @param str 字符串 |
||||
|
* @param start 开始 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String substring(final String str, int start) { |
||||
|
if (str == null) { |
||||
|
return NULLSTR; |
||||
|
} |
||||
|
|
||||
|
if (start < 0) { |
||||
|
start = str.length() + start; |
||||
|
} |
||||
|
|
||||
|
if (start < 0) { |
||||
|
start = 0; |
||||
|
} |
||||
|
if (start > str.length()) { |
||||
|
return NULLSTR; |
||||
|
} |
||||
|
|
||||
|
return str.substring(start); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 截取字符串 |
||||
|
* |
||||
|
* @param str 字符串 |
||||
|
* @param start 开始 |
||||
|
* @param end 结束 |
||||
|
* @return 结果 |
||||
|
*/ |
||||
|
public static String substring(final String str, int start, int end) { |
||||
|
if (str == null) { |
||||
|
return NULLSTR; |
||||
|
} |
||||
|
|
||||
|
if (end < 0) { |
||||
|
end = str.length() + end; |
||||
|
} |
||||
|
if (start < 0) { |
||||
|
start = str.length() + start; |
||||
|
} |
||||
|
|
||||
|
if (end > str.length()) { |
||||
|
end = str.length(); |
||||
|
} |
||||
|
|
||||
|
if (start > end) { |
||||
|
return NULLSTR; |
||||
|
} |
||||
|
|
||||
|
if (start < 0) { |
||||
|
start = 0; |
||||
|
} |
||||
|
if (end < 0) { |
||||
|
end = 0; |
||||
|
} |
||||
|
|
||||
|
return str.substring(start, end); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 格式化文本, {} 表示占位符<br> |
||||
|
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br> |
||||
|
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> |
||||
|
* 例:<br> |
||||
|
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> |
||||
|
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> |
||||
|
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> |
||||
|
* |
||||
|
* @param template 文本模板,被替换的部分用 {} 表示 |
||||
|
* @param params 参数值 |
||||
|
* @return 格式化后的文本 |
||||
|
*/ |
||||
|
public static String format(String template, Object... params) { |
||||
|
if (isEmpty(params) || isEmpty(template)) { |
||||
|
return template; |
||||
|
} |
||||
|
return StrFormatter.format(template, params); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 下划线转驼峰命名 |
||||
|
*/ |
||||
|
public static String toUnderScoreCase(String str) { |
||||
|
if (str == null) { |
||||
|
return null; |
||||
|
} |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
// 前置字符是否大写
|
||||
|
boolean preCharIsUpperCase = true; |
||||
|
// 当前字符是否大写
|
||||
|
boolean curreCharIsUpperCase = true; |
||||
|
// 下一字符是否大写
|
||||
|
boolean nexteCharIsUpperCase = true; |
||||
|
for (int i = 0; i < str.length(); i++) { |
||||
|
char c = str.charAt(i); |
||||
|
if (i > 0) { |
||||
|
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); |
||||
|
} else { |
||||
|
preCharIsUpperCase = false; |
||||
|
} |
||||
|
|
||||
|
curreCharIsUpperCase = Character.isUpperCase(c); |
||||
|
|
||||
|
if (i < (str.length() - 1)) { |
||||
|
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); |
||||
|
} |
||||
|
|
||||
|
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { |
||||
|
sb.append(SEPARATOR); |
||||
|
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { |
||||
|
sb.append(SEPARATOR); |
||||
|
} |
||||
|
sb.append(Character.toLowerCase(c)); |
||||
|
} |
||||
|
|
||||
|
return sb.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 是否包含字符串 |
||||
|
* |
||||
|
* @param str 验证字符串 |
||||
|
* @param strs 字符串组 |
||||
|
* @return 包含返回true |
||||
|
*/ |
||||
|
public static boolean inStringIgnoreCase(String str, String... strs) { |
||||
|
if (str != null && strs != null) { |
||||
|
for (String s : strs) { |
||||
|
if (str.equalsIgnoreCase(trim(s))) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld |
||||
|
* |
||||
|
* @param name 转换前的下划线大写方式命名的字符串 |
||||
|
* @return 转换后的驼峰式命名的字符串 |
||||
|
*/ |
||||
|
public static String convertToCamelCase(String name) { |
||||
|
StringBuilder result = new StringBuilder(); |
||||
|
// 快速检查
|
||||
|
if (name == null || name.isEmpty()) { |
||||
|
// 没必要转换
|
||||
|
return ""; |
||||
|
} else if (!name.contains("_")) { |
||||
|
// 不含下划线,仅将首字母大写
|
||||
|
return name.substring(0, 1).toUpperCase() + name.substring(1); |
||||
|
} |
||||
|
// 用下划线将原始字符串分割
|
||||
|
String[] camels = name.split("_"); |
||||
|
for (String camel : camels) { |
||||
|
// 跳过原始字符串中开头、结尾的下换线或双重下划线
|
||||
|
if (camel.isEmpty()) { |
||||
|
continue; |
||||
|
} |
||||
|
// 首字母大写
|
||||
|
result.append(camel.substring(0, 1).toUpperCase()); |
||||
|
result.append(camel.substring(1).toLowerCase()); |
||||
|
} |
||||
|
return result.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 驼峰式命名法 例如:user_name->userName |
||||
|
*/ |
||||
|
public static String toCamelCase(String s) { |
||||
|
if (s == null) { |
||||
|
return null; |
||||
|
} |
||||
|
s = s.toLowerCase(); |
||||
|
StringBuilder sb = new StringBuilder(s.length()); |
||||
|
boolean upperCase = false; |
||||
|
for (int i = 0; i < s.length(); i++) { |
||||
|
char c = s.charAt(i); |
||||
|
|
||||
|
if (c == SEPARATOR) { |
||||
|
upperCase = true; |
||||
|
} else if (upperCase) { |
||||
|
sb.append(Character.toUpperCase(c)); |
||||
|
upperCase = false; |
||||
|
} else { |
||||
|
sb.append(c); |
||||
|
} |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 |
||||
|
* |
||||
|
* @param str 指定字符串 |
||||
|
* @param strs 需要检查的字符串数组 |
||||
|
* @return 是否匹配 |
||||
|
*/ |
||||
|
public static boolean matchesTwo(String str, List<String> strs) { |
||||
|
if (isEmpty(str) || isEmpty(strs)) { |
||||
|
return false; |
||||
|
} |
||||
|
for (String testStr : strs) { |
||||
|
if (matchesTwo(str, testStr)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static boolean matches(String str, List<String> strs) { |
||||
|
if (isEmpty(str) || isEmpty(strs)) { |
||||
|
return false; |
||||
|
} |
||||
|
for (String testStr : strs) { |
||||
|
if (matches(str, testStr)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找指定字符串是否匹配指定字符串数组中的任意一个字符串 |
||||
|
* |
||||
|
* @param str 指定字符串 |
||||
|
* @param strs 需要检查的字符串数组 |
||||
|
* @return 是否匹配 |
||||
|
*/ |
||||
|
public static boolean matches(String str, String... strs) { |
||||
|
if (isEmpty(str) || isEmpty(strs)) { |
||||
|
return false; |
||||
|
} |
||||
|
for (String testStr : strs) { |
||||
|
if (matches(str, testStr)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public static boolean matches(String str, String pattern) { |
||||
|
if (isEmpty(pattern) || isEmpty(str)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
pattern = pattern.replaceAll("\\s*", ""); // 替换空格
|
||||
|
int beginOffset = 0; // pattern截取开始位置
|
||||
|
int formerStarOffset = -1; // 前星号的偏移位置
|
||||
|
int latterStarOffset = -1; // 后星号的偏移位置
|
||||
|
|
||||
|
String remainingURI = str; |
||||
|
String prefixPattern = ""; |
||||
|
String suffixPattern = ""; |
||||
|
|
||||
|
boolean result = false; |
||||
|
do { |
||||
|
formerStarOffset = indexOf(pattern, START, beginOffset); |
||||
|
prefixPattern = substring(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length()); |
||||
|
|
||||
|
// 匹配前缀Pattern
|
||||
|
result = remainingURI.equals(prefixPattern); |
||||
|
// 已经没有星号,直接返回
|
||||
|
if (formerStarOffset == -1) { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 匹配失败,直接返回
|
||||
|
if (!result) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!isEmpty(prefixPattern)) { |
||||
|
remainingURI = substringAfter(str, prefixPattern); |
||||
|
} |
||||
|
|
||||
|
// 匹配后缀Pattern
|
||||
|
latterStarOffset = indexOf(pattern, START, formerStarOffset + 1); |
||||
|
suffixPattern = substring(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length()); |
||||
|
|
||||
|
result = remainingURI.equals(suffixPattern); |
||||
|
// 匹配失败,直接返回
|
||||
|
if (!result) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!isEmpty(suffixPattern)) { |
||||
|
remainingURI = substringAfter(str, suffixPattern); |
||||
|
} |
||||
|
|
||||
|
// 移动指针
|
||||
|
beginOffset = latterStarOffset + 1; |
||||
|
|
||||
|
} |
||||
|
while (!isEmpty(suffixPattern) && !isEmpty(remainingURI)); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查找指定字符串是否匹配 |
||||
|
* |
||||
|
* @param str 指定字符串 |
||||
|
* @param pattern 需要检查的字符串 |
||||
|
* @return 是否匹配 |
||||
|
*/ |
||||
|
public static boolean matchesTwo(String str, String pattern) { |
||||
|
if (isEmpty(pattern) || isEmpty(str)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
pattern = pattern.replaceAll("\\s*", ""); // 替换空格
|
||||
|
int beginOffset = 0; // pattern截取开始位置
|
||||
|
int formerStarOffset = -1; // 前星号的偏移位置
|
||||
|
int latterStarOffset = -1; // 后星号的偏移位置
|
||||
|
|
||||
|
String remainingURI = str; |
||||
|
String prefixPattern = ""; |
||||
|
String suffixPattern = ""; |
||||
|
|
||||
|
boolean result = false; |
||||
|
do { |
||||
|
formerStarOffset = indexOf(pattern, START, beginOffset); |
||||
|
prefixPattern = substring(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length()); |
||||
|
|
||||
|
// 匹配前缀Pattern
|
||||
|
result = remainingURI.contains(prefixPattern); |
||||
|
// 已经没有星号,直接返回
|
||||
|
if (formerStarOffset == -1) { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// 匹配失败,直接返回
|
||||
|
if (!result) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!isEmpty(prefixPattern)) { |
||||
|
remainingURI = substringAfter(str, prefixPattern); |
||||
|
} |
||||
|
|
||||
|
// 匹配后缀Pattern
|
||||
|
latterStarOffset = indexOf(pattern, START, formerStarOffset + 1); |
||||
|
suffixPattern = substring(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length()); |
||||
|
|
||||
|
result = remainingURI.contains(suffixPattern); |
||||
|
// 匹配失败,直接返回
|
||||
|
if (!result) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!isEmpty(suffixPattern)) { |
||||
|
remainingURI = substringAfter(str, suffixPattern); |
||||
|
} |
||||
|
|
||||
|
// 移动指针
|
||||
|
beginOffset = latterStarOffset + 1; |
||||
|
|
||||
|
} |
||||
|
while (!isEmpty(suffixPattern) && !isEmpty(remainingURI)); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@SuppressWarnings("unchecked") |
||||
|
public static <T> T cast(Object obj) { |
||||
|
return (T) obj; |
||||
|
} |
||||
|
} |
@ -0,0 +1,128 @@ |
|||||
|
package com.yxt.ss.gateway.api.rest; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import com.yxt.ss.gateway.api.authutils.StringUtils; |
||||
|
import com.yxt.ss.gateway.api.service.ClientService; |
||||
|
import com.yxt.ss.gateway.api.utils.AppKeyConfig; |
||||
|
import com.yxt.ss.gateway.api.utils.ResultBean; |
||||
|
import com.yxt.ss.gateway.api.utils.SignatureQuery; |
||||
|
import okhttp3.*; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.io.UnsupportedEncodingException; |
||||
|
import java.security.NoSuchAlgorithmException; |
||||
|
import java.util.Map; |
||||
|
import java.util.TreeMap; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* @description: |
||||
|
* @author: dimengzhe |
||||
|
* @date: 2024/12/10 |
||||
|
**/ |
||||
|
@RestController |
||||
|
@RequestMapping("/ApiTestRest") |
||||
|
public class ApiTestRest { |
||||
|
|
||||
|
@Autowired |
||||
|
private ClientService clientService; |
||||
|
|
||||
|
|
||||
|
//appkey
|
||||
|
static final String APPKEY = "appKey4"; |
||||
|
static final String SECRET = "secret"; |
||||
|
|
||||
|
//开发端,生成签名并调用服务器端验证签名、appKey等值。
|
||||
|
@PostMapping("/getSign") |
||||
|
ResultBean getSign(SignatureQuery query) { |
||||
|
ResultBean<String> rb = ResultBean.fireFail(); |
||||
|
try { |
||||
|
Map<String, String> formData = query.getParameters(); |
||||
|
//使用treeMap排序
|
||||
|
Map<String, String> tree = new TreeMap<>(formData); |
||||
|
tree.put("_app", APPKEY); |
||||
|
tree.put("_t", String.valueOf(System.currentTimeMillis() / 1000)); |
||||
|
tree.put("_s", ""); |
||||
|
// 生成签名
|
||||
|
String sign = clientService.generateSignature(tree, SECRET); |
||||
|
//添加签名值map
|
||||
|
tree.put("_sign", sign); |
||||
|
//发起请求
|
||||
|
ResultBean resultBean = client(tree); |
||||
|
if (!resultBean.getSuccess()) { |
||||
|
return rb.setMsg(resultBean.getMsg()); |
||||
|
} |
||||
|
//通过验证继续调用接口
|
||||
|
|
||||
|
|
||||
|
return rb.success(); |
||||
|
} catch (UnsupportedEncodingException e) { |
||||
|
return rb.setMsg("Unsupported encoding: " + e.getMessage()); |
||||
|
} catch (NoSuchAlgorithmException e) { |
||||
|
return rb.setMsg("Algorithm not found: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//发起请求验证签名等
|
||||
|
public ResultBean client(Map<String, String> data) { |
||||
|
ResultBean rb = ResultBean.fireFail(); |
||||
|
OkHttpClient client = new OkHttpClient.Builder() |
||||
|
.connectTimeout(10, TimeUnit.SECONDS) |
||||
|
.writeTimeout(10, TimeUnit.SECONDS) |
||||
|
.readTimeout(30, TimeUnit.SECONDS) |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
// 构建URL
|
||||
|
String endPoint = "http://127.0.0.1:9999"; |
||||
|
String path = "/signature/validate"; |
||||
|
|
||||
|
// 创建FormData
|
||||
|
FormBody.Builder formBuilder = new FormBody.Builder(); |
||||
|
for (Map.Entry<String, String> entry : data.entrySet()) { |
||||
|
formBuilder.add(entry.getKey(), entry.getValue()); |
||||
|
} |
||||
|
RequestBody formBody = formBuilder.build(); |
||||
|
|
||||
|
// 构建POST请求
|
||||
|
String url = endPoint + path; |
||||
|
System.out.println("Request URL: " + url); |
||||
|
System.out.println("Request Data: " + data); |
||||
|
|
||||
|
Request request = new Request.Builder() |
||||
|
.url(url) |
||||
|
.post(formBody) |
||||
|
.build(); |
||||
|
|
||||
|
// 发送请求
|
||||
|
try (Response response = client.newCall(request).execute()) { |
||||
|
String responseBody = response.body().string(); |
||||
|
// 使用 Jackson 解析 JSON 响应
|
||||
|
ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
JsonNode jsonNode = objectMapper.readTree(responseBody); |
||||
|
String success = jsonNode.path("success").asText(); |
||||
|
String msg = jsonNode.path("msg").asText(); |
||||
|
if ("false".equals(success)) { |
||||
|
return rb.setMsg(msg); |
||||
|
} |
||||
|
if (response.isSuccessful()) { |
||||
|
System.out.println("Response: " + response.body().string()); |
||||
|
} else { |
||||
|
System.err.println("Request failed: " + response.message()); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
System.err.println("Network error: " + e.getMessage()); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("Unexpected error: " + e.getMessage()); |
||||
|
} |
||||
|
return rb.success(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package com.yxt.ss.gateway.api.utils; |
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.server.WebFilter; |
||||
|
|
||||
|
/** |
||||
|
* @description: |
||||
|
* @author: dimengzhe |
||||
|
* @date: 2024/12/11 |
||||
|
**/ |
||||
|
@Configuration |
||||
|
public class WebFluxLoggingConfig { |
||||
|
|
||||
|
@Bean |
||||
|
public WebFilter loggingFilter() { |
||||
|
return (exchange, chain) -> { |
||||
|
// 打印请求信息
|
||||
|
System.out.println("Request: " + exchange.getRequest().getURI()); |
||||
|
|
||||
|
// 继续处理请求
|
||||
|
return chain.filter(exchange) |
||||
|
.doOnTerminate(() -> { |
||||
|
// 打印响应信息
|
||||
|
System.out.println("Response: " + exchange.getResponse().getStatusCode()); |
||||
|
}); |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -1,4 +1,4 @@ |
|||||
app: |
appkey: |
||||
keys: |
keys: |
||||
appKey1: secret1 |
appKey1: secret1 |
||||
appKey2: secret2 |
appKey2: secret2 |
||||
|
Loading…
Reference in new issue