Files
timi-spring/src/main/java/com/imyeyu/spring/TimiSpring.java
Timi 13ae5016e8
All checks were successful
CI/CD / build-deploy (pull_request) Successful in 13s
v0.0.3
2026-02-10 18:55:53 +08:00

511 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.imyeyu.spring;
import com.google.gson.Gson;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.Language;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.bean.timi.TimiResponse;
import com.imyeyu.java.ref.Ref;
import com.imyeyu.spring.bean.RequestRange;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
/**
* TimiSpring
*
* <p>如果使用本依赖相关组件,务必让 SpringBoot 扫描本依赖的包,在 SpringApplication 上加上注解
* <pre>
* &#64;ComponentScan({"自己扫描的包", "com.imyeyu.spring"})
* </pre>
*
* @author 夜雨
* @version 2021-11-20 17:16
*/
public class TimiSpring {
/** 版本号 */
public static final String VERSION = "0.0.1";
private static final Logger log = LoggerFactory.getLogger(TimiSpring.class);
private static final Gson GSON = new Gson();
/**
* 工具类禁止实例化
*/
private TimiSpring() {
}
/**
* 回调数据
*
* @param response 返回
* @param resp 返回结果
*/
public static void render(HttpServletResponse response, TimiResponse<?> resp) {
try {
HttpSession session = getSession();
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(GSON.toJson(resp).getBytes(StandardCharsets.UTF_8));
out.flush();
out.close();
} catch (Exception e) {
log.error("TimiSpring.render Error", e);
}
}
/**
* 回调错误
*
* @param response 返回
* @param code 代码
* @param msgKey 消息映射键
*/
public static void renderError(HttpServletResponse response, TimiCode code, String msgKey) {
try {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(GSON.toJson(code.toResponse().msg(msgKey)).getBytes(StandardCharsets.UTF_8));
out.flush();
out.close();
} catch (Exception e) {
log.error("TimiSpring.renderError error", e);
}
}
/**
* 获取 Servlet 请求属性
*
* @return Servlet 请求属性
* @throws TimiException 请求异常
*/
public static ServletRequestAttributes getServletRequestAttributes() {
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes sra) {
return sra;
}
throw new TimiException(TimiCode.ERROR_NPE_VARIABLE);
}
/**
* 获取 HttpServlet 请求
*
* @return HttpServlet 请求
*/
public static HttpServletRequest getRequest() {
return getServletRequestAttributes().getRequest();
}
/**
* 获取请求域名
*
* @return 请求域名
*/
public static String getDomain() {
return getRequest().getServerName();
}
/**
* 获取完整域名(含协议与端口)
*
* @return 完整域名
*/
public static String getFullDomain() {
HttpServletRequest req = getRequest();
String port = req.getServerPort() == 80 || req.getServerPort() == 443 ? "" : ":" + req.getServerPort();
return "%s://%s%s".formatted(req.getScheme(), getDomain(), port);
}
/**
* 获取请求 URL
*
* @return 请求 URL
*/
public static String getURL() {
return getRequest().getRequestURL().toString();
}
/**
* 获取请求 URI
*
* @return 请求 URI
*/
public static String getURI() {
return getRequest().getRequestURI();
}
/**
* 从 URI 指定标记开始截取
*
* @param flag 标记
* @return 截取后的 URI
*/
public static String cutURIStartAt(String flag) {
int indexOf = getURI().indexOf(flag);
TimiException.requiredTrue(-1 < indexOf, "not found flag: %s".formatted(flag));
return getURI().substring(indexOf + flag.length());
}
/**
* 获取 HttpServlet 回调
*
* @return HttpServlet 回调
*/
public static HttpServletResponse getResponse() {
return getServletRequestAttributes().getResponse();
}
/**
* 获取 Http 会话
*
* @return Http 会话
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
/**
* 获取请求地理区域
*
* @return 地区
*/
public static Locale getLocale() {
return getRequest().getLocale();
}
/**
* 获取请求头属性
*
* @param key 属性键
* @return 属性值
*/
public static String getHeader(String key) {
return getRequest().getHeader(key);
}
/**
* 获取会话数据
*
* @param key 键
* @return 值
*/
public static Object getSessionAttr(String key) {
return getSession().getAttribute(key);
}
/**
* 获取会话数据
*
* @param key 键
* @return 值
*/
public static boolean hasSessionAttr(String key) {
return getSessionAttr(key) != null;
}
/**
* 获取会话数据(字符串)
*
* @param key 键
* @return 值
*/
public static String getSessionAttrAsString(String key) {
Object sessionAttr = getSessionAttr(key);
if (sessionAttr == null) {
return null;
}
return sessionAttr.toString();
}
/**
* 获取会话数据
*
* @param key 键
* @param clazz 值类型
* @param <T> 值类型
* @return 值
*/
public static <T> T getSessionAttr(String key, Class<T> clazz) {
return clazz.cast(getSessionAttr(key));
}
/**
* 设置会话数据
*
* @param key 键
* @param t 值
* @param <T> 值类型
*/
public static <T> void setSessionAttr(String key, T t) {
getSession().setAttribute(key, t);
}
/**
* 移除会话数据
*
* @param key 键
*/
public static void removeSessionAttr(String key) {
getSession().removeAttribute(key);
}
/**
* 获取请求数据
*
* @param key 键
* @return 值
*/
public static Object getRequestAttr(String key) {
return getRequest().getAttribute(key);
}
/**
* 获取请求数据
*
* @param key 键
* @return 值
*/
public static boolean hasRequestAttr(String key) {
return getRequestAttr(key) != null;
}
/**
* 获取请求数据(字符串)
*
* @param key 键
* @return 值
*/
public static String getRequestAttrAsString(String key) {
Object reqAttr = getRequestAttr(key);
if (reqAttr == null) {
return null;
}
return reqAttr.toString();
}
/**
* 获取请求数据
*
* @param key 键
* @param clazz 值类型
* @param <T> 值类型
* @return 值
*/
public static <T> T getRequestAttr(String key, Class<T> clazz) {
return clazz.cast(getRequestAttr(key));
}
/**
* 设置请求数据
*
* @param key 键
* @param t 值
* @param <T> 值类型
*/
public static <T> void setRequestAttr(String key, T t) {
getRequest().setAttribute(key, t);
}
/**
* 移除请求数据
*
* @param key 键
*/
public static void removeRequestAttr(String key) {
getRequest().removeAttribute(key);
}
/**
* 获取请求 URL 参数
*
* @param key 键
* @return 参数值
*/
public static String getRequestArg(String key) {
return getRequest().getParameter(key);
}
/**
* 获取请求 URL 参数(多值)
*
* @param key 键
* @return 参数值
*/
public static String[] getRequestArgs(String key) {
return getRequest().getParameterValues(key);
}
/**
* 添加 Cookie
*
* @param cookie Cookie
*/
public static void addCookie(Cookie cookie) {
getResponse().addCookie(cookie);
}
/**
* 添加 Cookie
*
* @param key 键
* @param value 值
*/
public static void addCookie(String key, String value) {
addCookie(new Cookie(key, value));
}
/**
* 获取 Cookie
*
* @param key 键
* @return Cookie
*/
public static Cookie getCookie(String key) {
Cookie[] cookies = getRequest().getCookies();
if (cookies == null) {
return null;
}
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals(key)) {
return cookies[i];
}
}
return null;
}
/**
* 获取请求令牌,键为 Token 或 token包括请求头和 URI
*
* @return 令牌
*/
public static String getToken() {
return TimiJava.firstNotEmpty(getHeader("Token"), getHeader("token"), getRequestArg("token"), getRequestArg("Token"));
}
/**
* 获取原始语言头
*
* @return 语言头
*/
public static String getLanguageRaw() {
return getHeader("Accept-Language");
}
/**
* 获取客户端地区语言
*
* @return 客户端地区语言
*/
public static Language.Enum getLanguage() {
String name = getRequestArg("lang");
if (TimiJava.isEmpty(name)) {
name = getLanguageRaw();
}
if (TimiJava.isNotEmpty(name)) {
List<Locale.LanguageRange> rangeList = Locale.LanguageRange.parse(name);
for (Locale.LanguageRange item : rangeList) {
if (item.getRange().contains("-")) {
name = item.getRange();
break;
}
}
}
if (TimiJava.isNotEmpty(name)) {
name = name.replace("-", "_");
}
if (TimiJava.isEmpty(name)) { // use for not support
return Language.Enum.zh_CN;
}
return Ref.toType(Language.Enum.class, name);
}
/**
* 获取请求 IP
*
* @return 请求 IP
* @throws TimiException 服务异常
*/
public static String getRequestIP() {
String ip = getHeader("x-forwarded-for");
// nginx 转发
if (TimiJava.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = getHeader("X-Forwarded-For");
}
if (TimiJava.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = getHeader("X-Real-IP");
}
// 默认获取
if (TimiJava.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = getRequest().getRemoteAddr();
}
// 本地 IP
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
/**
* 是否本地 IP
*
* @return true 为本地 IP
*/
public static boolean isLocalIP() {
return getRequestIP().startsWith("127");
}
/**
* 解析 Range 请求范围
*
* @param fileLength 文件长度
* @return 请求范围
* @throws IOException IO 异常
*/
public static RequestRange requestRange(long fileLength) throws IOException {
HttpServletResponse resp = getResponse();
String range = getRequestAttrAsString("Range");
if (range == null || !range.startsWith("bytes=")) {
return null;
}
// 处理 bytes=0-999 格式
String rangeValue = range.substring("bytes=".length());
String[] ranges = rangeValue.split("-");
TimiException.requiredTrue(2 == ranges.length, "Invalid Range format");
long start = Long.parseLong(ranges[0]);
long end = ranges[1].isEmpty() ? fileLength - 1 : Long.parseLong(ranges[1]);
// 验证范围有效性
if (start < 0 || fileLength <= end || end < start) {
resp.setHeader("Content-Range", "bytes */" + fileLength);
resp.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
return null;
}
return new RequestRange(start, end);
}
public static void copyPropertiesNotNull(Object source, Object target) {
BeanWrapper srcBean = new BeanWrapperImpl(source);
BeanWrapper targetBean = new BeanWrapperImpl(target);
for (PropertyDescriptor pd : srcBean.getPropertyDescriptors()) {
String propertyName = pd.getName();
Object srcValue = srcBean.getPropertyValue(propertyName);
if (srcValue != null && targetBean.isWritableProperty(propertyName)) {
targetBean.setPropertyValue(propertyName, srcValue);
}
}
}
}