mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-08 16:57:09 +08:00
refactor: 移除 web-core,融合 web-core 和 core 模块
1.移除 web-core,融合 web-core 和 core 模块 2.调整部分依赖顺序
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-web</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-web-core</artifactId>
|
||||
<description>ContiNew Starter Web 模块 - 核心模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON 模块 - Jackson -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-json-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Web(提供 Spring MVC Web 开发能力,默认内置 Tomcat 服务器) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<!-- 移除内置 Tomcat 服务器 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Servlet API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.file.FileNameUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*
|
||||
* @author Zheng Jie(<a href="https://gitee.com/elunez/eladmin">ELADMIN</a>)
|
||||
* @author Charles7c
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class FileUploadUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(FileUploadUtils.class);
|
||||
|
||||
private FileUploadUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传
|
||||
*
|
||||
* @param multipartFile 源文件对象
|
||||
* @param filePath 文件路径
|
||||
* @param isKeepOriginalFilename 是否保留原文件名
|
||||
* @return 目标文件对象
|
||||
*/
|
||||
public static File upload(MultipartFile multipartFile, String filePath, boolean isKeepOriginalFilename) {
|
||||
String originalFilename = multipartFile.getOriginalFilename();
|
||||
String extensionName = FileNameUtil.extName(originalFilename);
|
||||
String fileName;
|
||||
if (isKeepOriginalFilename) {
|
||||
fileName = "%s-%s.%s".formatted(FileNameUtil.getPrefix(originalFilename), DateUtil.format(LocalDateTime
|
||||
.now(), DatePattern.PURE_DATETIME_MS_PATTERN), extensionName);
|
||||
} else {
|
||||
fileName = "%s.%s".formatted(IdUtil.fastSimpleUUID(), extensionName);
|
||||
}
|
||||
try {
|
||||
String pathname = filePath + fileName;
|
||||
File dest = new File(pathname).getCanonicalFile();
|
||||
// 如果父路径不存在,自动创建
|
||||
if (!dest.getParentFile().exists() && (!dest.getParentFile().mkdirs())) {
|
||||
log.error("Create upload file parent path failed.");
|
||||
}
|
||||
// 文件写入
|
||||
multipartFile.transferTo(dest);
|
||||
return dest;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param file 文件
|
||||
*/
|
||||
public static void download(HttpServletResponse response, File file) throws IOException {
|
||||
download(response, new FileInputStream(file), file.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @param inputStream 文件流
|
||||
* @param fileName 文件名
|
||||
* @since 2.5.0
|
||||
*/
|
||||
public static void download(HttpServletResponse response,
|
||||
InputStream inputStream,
|
||||
String fileName) throws IOException {
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLUtil.encode(fileName));
|
||||
try (inputStream; var outputStream = response.getOutputStream()) {
|
||||
response.setContentLengthLong(inputStream.transferTo(outputStream));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 可重复读取请求体的包装器
|
||||
* 支持文件流直接透传,非文件流可重复读取
|
||||
*
|
||||
* @author echo
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private byte[] cachedBody;
|
||||
private final HttpServletRequest originalRequest;
|
||||
|
||||
public RepeatReadRequestWrapper(HttpServletRequest request) throws IOException {
|
||||
super(request);
|
||||
this.originalRequest = request;
|
||||
|
||||
// 判断是否为文件上传请求
|
||||
if (!isMultipartContent(request)) {
|
||||
this.cachedBody = IoUtil.readBytes(request.getInputStream(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
// 如果是文件上传,直接返回原始输入流
|
||||
if (isMultipartContent(originalRequest)) {
|
||||
return originalRequest.getInputStream();
|
||||
}
|
||||
|
||||
// 非文件上传,返回可重复读取的输入流
|
||||
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cachedBody);
|
||||
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return byteArrayInputStream.available() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
// 非阻塞I/O,这里可以根据需要实现
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
return byteArrayInputStream.read();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
// 如果是文件上传,直接返回原始Reader
|
||||
if (isMultipartContent(originalRequest)) {
|
||||
new BufferedReader(new InputStreamReader(originalRequest.getInputStream(), StandardCharsets.UTF_8));
|
||||
}
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否为文件上传请求
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 是否为文件上传请求
|
||||
*/
|
||||
public boolean isMultipartContent(HttpServletRequest request) {
|
||||
return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart/");
|
||||
}
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.WriteListener;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponseWrapper;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 可重复读取响应内容的包装器
|
||||
* 支持缓存响应内容,便于日志记录和后续处理 (不缓存SSE)
|
||||
*
|
||||
* @author echo
|
||||
* @author Charles7c
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
|
||||
|
||||
private final ByteArrayOutputStream cachedOutputStream = new ByteArrayOutputStream();
|
||||
private final PrintWriter writer = new PrintWriter(cachedOutputStream, true);
|
||||
/**
|
||||
* 是否为流式响应
|
||||
*/
|
||||
private boolean isStreamingResponse = false;
|
||||
|
||||
public RepeatReadResponseWrapper(HttpServletResponse response) {
|
||||
super(response);
|
||||
checkStreamingResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type) {
|
||||
super.setContentType(type);
|
||||
// 根据 Content-Type 判断是否为流式响应
|
||||
if (type != null) {
|
||||
String lowerType = type.toLowerCase();
|
||||
isStreamingResponse = lowerType.contains(MediaType.TEXT_EVENT_STREAM_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkStreamingResponse() {
|
||||
String contentType = getContentType();
|
||||
if (contentType != null) {
|
||||
String lowerType = contentType.toLowerCase();
|
||||
isStreamingResponse = lowerType.contains(MediaType.TEXT_EVENT_STREAM_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
checkStreamingResponse();
|
||||
// 对于 SSE 流式响应,直接返回原始响应流,不做额外处理
|
||||
if (isStreamingResponse) {
|
||||
return super.getOutputStream();
|
||||
}
|
||||
return new ServletOutputStream() {
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener writeListener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
cachedOutputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
cachedOutputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
cachedOutputStream.write(b, off, len);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getWriter() throws IOException {
|
||||
checkStreamingResponse();
|
||||
if (isStreamingResponse) {
|
||||
// 对于 SSE 流式响应,直接返回原始响应写入器,不做额外处理
|
||||
return super.getWriter();
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的响应内容
|
||||
*
|
||||
* @return 缓存的响应内容
|
||||
*/
|
||||
public String getResponseContent() {
|
||||
if (!isStreamingResponse) {
|
||||
writer.flush();
|
||||
return cachedOutputStream.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将缓存的响应内容复制到原始响应中
|
||||
*
|
||||
* @throws IOException IO 异常
|
||||
*/
|
||||
public void copyBodyToResponse() throws IOException {
|
||||
if (!isStreamingResponse && cachedOutputStream.size() > 0) {
|
||||
getResponse().getOutputStream().write(cachedOutputStream.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为流式响应
|
||||
*
|
||||
* @return 是否为流式响应
|
||||
*/
|
||||
public boolean isStreamingResponse() {
|
||||
return isStreamingResponse;
|
||||
}
|
||||
}
|
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.json.jackson.util.JSONUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Servlet 工具类
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author echo
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServletUtils extends JakartaServletUtil {
|
||||
|
||||
private ServletUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器及其版本信息
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 浏览器及其版本信息
|
||||
*/
|
||||
public static String getBrowser(HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return null;
|
||||
}
|
||||
return getBrowser(request.getHeader("User-Agent"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器及其版本信息
|
||||
*
|
||||
* @param userAgentString User-Agent 字符串
|
||||
* @return 浏览器及其版本信息
|
||||
*/
|
||||
public static String getBrowser(String userAgentString) {
|
||||
try {
|
||||
UserAgent userAgent = UserAgentUtil.parse(userAgentString);
|
||||
if (userAgent == null || userAgent.getBrowser() == null) {
|
||||
return null;
|
||||
}
|
||||
String browserName = userAgent.getBrowser().getName();
|
||||
String version = userAgent.getVersion();
|
||||
return CharSequenceUtil.isBlank(version) ? browserName : browserName + StringConstants.SPACE + version;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 操作系统
|
||||
*/
|
||||
public static String getOs(HttpServletRequest request) {
|
||||
if (null == request) {
|
||||
return null;
|
||||
}
|
||||
return getOs(request.getHeader("User-Agent"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统
|
||||
*
|
||||
* @param userAgentString User-Agent 字符串
|
||||
* @return 操作系统
|
||||
*/
|
||||
public static String getOs(String userAgentString) {
|
||||
try {
|
||||
UserAgent userAgent = UserAgentUtil.parse(userAgentString);
|
||||
if (userAgent == null || userAgent.getOs() == null) {
|
||||
return null;
|
||||
}
|
||||
return userAgent.getOs().getName();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求方法
|
||||
*
|
||||
* @return {@link String }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getRequestMethod() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? request.getMethod() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求参数
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return {@link String }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getRequestParameter(String name) {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? request.getParameter(name) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求 Ip
|
||||
*
|
||||
* @return {@link String }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getRequestIp() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? getClientIP(request) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求头信息
|
||||
*
|
||||
* @return {@link Map }<{@link String }, {@link String }>
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static Map<String, String> getRequestHeaders() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? getHeaderMap(request) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求 URL(包含 query 参数)
|
||||
* <p>{@code http://localhost:8000/system/user?page=1&size=10}</p>
|
||||
*
|
||||
* @return {@link URI }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static URI getRequestUrl() {
|
||||
HttpServletRequest request = getRequest();
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
String queryString = request.getQueryString();
|
||||
if (CharSequenceUtil.isBlank(queryString)) {
|
||||
return URI.create(request.getRequestURL().toString());
|
||||
}
|
||||
try {
|
||||
StringBuilder urlBuilder = appendQueryString(queryString);
|
||||
return new URI(urlBuilder.toString());
|
||||
} catch (URISyntaxException e) {
|
||||
String encoded = UriUtils.encodeQuery(queryString, StandardCharsets.UTF_8);
|
||||
StringBuilder urlBuilder = appendQueryString(encoded);
|
||||
return URI.create(urlBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求路径
|
||||
*
|
||||
* @return {@link URI }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getRequestPath() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? request.getRequestURI() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求 body 参数
|
||||
*
|
||||
* @return {@link String }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getRequestBody() {
|
||||
HttpServletRequest request = getRequest();
|
||||
if (request instanceof RepeatReadRequestWrapper wrapper && !wrapper.isMultipartContent(request)) {
|
||||
String body = JakartaServletUtil.getBody(request);
|
||||
return JSONUtils.isTypeJSON(body) ? body : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求参数
|
||||
*
|
||||
* @return {@link Map }<{@link String }, {@link Object }>
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static Map<String, Object> getRequestParams() {
|
||||
String body = getRequestBody();
|
||||
return CharSequenceUtil.isNotBlank(body) && JSONUtils.isTypeJSON(body)
|
||||
? JSONUtils.toBean(body, Map.class)
|
||||
: Collections.unmodifiableMap(JakartaServletUtil.getParamMap(Objects.requireNonNull(getRequest())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应状态
|
||||
*
|
||||
* @return int
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static int getResponseStatus() {
|
||||
HttpServletResponse response = getResponse();
|
||||
return response != null ? response.getStatus() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应所有的头(header)信息
|
||||
*
|
||||
* @return header值
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static Map<String, String> getResponseHeaders() {
|
||||
HttpServletResponse response = getResponse();
|
||||
if (response == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Collection<String> headerNames = response.getHeaderNames();
|
||||
final Map<String, String> headerMap = MapUtil.newHashMap(headerNames.size(), true);
|
||||
for (String name : headerNames) {
|
||||
headerMap.put(name, response.getHeader(name));
|
||||
}
|
||||
return headerMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应 body 参数
|
||||
*
|
||||
* @return {@link String }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static String getResponseBody() {
|
||||
HttpServletResponse response = getResponse();
|
||||
if (response instanceof RepeatReadResponseWrapper wrapper && !wrapper.isStreamingResponse()) {
|
||||
String body = wrapper.getResponseContent();
|
||||
return JSONUtils.isTypeJSON(body) ? body : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取响应参数
|
||||
*
|
||||
* @return {@link Map }<{@link String }, {@link Object }>
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static Map<String, Object> getResponseParams() {
|
||||
String body = getResponseBody();
|
||||
return CharSequenceUtil.isNotBlank(body) && JSONUtils.isTypeJSON(body)
|
||||
? JSONUtils.toBean(body, Map.class)
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HTTP Session
|
||||
*
|
||||
* @return HttpSession
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static HttpSession getSession() {
|
||||
HttpServletRequest request = getRequest();
|
||||
return request != null ? request.getSession() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HTTP Request
|
||||
*
|
||||
* @return HttpServletRequest
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static HttpServletRequest getRequest() {
|
||||
ServletRequestAttributes attributes = getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
return attributes.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HTTP Response
|
||||
*
|
||||
* @return HttpServletResponse
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static HttpServletResponse getResponse() {
|
||||
ServletRequestAttributes attributes = getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
return attributes.getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求属性
|
||||
*
|
||||
* @return {@link ServletRequestAttributes }
|
||||
* @since 2.11.0
|
||||
*/
|
||||
public static ServletRequestAttributes getRequestAttributes() {
|
||||
try {
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
return (ServletRequestAttributes)attributes;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加查询字符串
|
||||
*
|
||||
* @param queryString 查询字符串
|
||||
* @return {@link StringBuilder }
|
||||
*/
|
||||
private static StringBuilder appendQueryString(String queryString) {
|
||||
HttpServletRequest request = getRequest();
|
||||
if (request == null) {
|
||||
return new StringBuilder();
|
||||
}
|
||||
return new StringBuilder().append(request.getRequestURL())
|
||||
.append(StringConstants.QUESTION_MARK)
|
||||
.append(queryString);
|
||||
}
|
||||
}
|
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.web.util;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring Web 工具类
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.1
|
||||
*/
|
||||
public class SpringWebUtils {
|
||||
|
||||
private SpringWebUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径是否匹配
|
||||
*
|
||||
* @param path 路径
|
||||
* @param patterns 匹配模式列表
|
||||
* @return 是否匹配
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public static boolean isMatch(String path, List<String> patterns) {
|
||||
return patterns.stream().anyMatch(pattern -> isMatch(path, pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径是否匹配
|
||||
*
|
||||
* @param path 路径
|
||||
* @param patterns 匹配模式列表
|
||||
* @return 是否匹配
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public static boolean isMatch(String path, String... patterns) {
|
||||
return Arrays.stream(patterns).anyMatch(pattern -> isMatch(path, pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* 路径是否匹配
|
||||
*
|
||||
* @param path 路径
|
||||
* @param pattern 匹配模式
|
||||
* @return 是否匹配
|
||||
* @since 2.4.0
|
||||
*/
|
||||
public static boolean isMatch(String path, String pattern) {
|
||||
PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern);
|
||||
PathContainer pathContainer = PathContainer.parsePath(path);
|
||||
return pathPattern.matches(pathContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消注册静态资源映射
|
||||
*
|
||||
* @param handlerMap 静态资源映射
|
||||
*/
|
||||
public static void deRegisterResourceHandler(Map<String, String> handlerMap) {
|
||||
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
|
||||
// 获取已经注册的映射
|
||||
final HandlerMapping resourceHandlerMapping = applicationContext
|
||||
.getBean("resourceHandlerMapping", HandlerMapping.class);
|
||||
final Map<String, Object> oldHandlerMap = (Map<String, Object>)ReflectUtil
|
||||
.getFieldValue(resourceHandlerMapping, "handlerMap");
|
||||
// 移除之前注册的映射
|
||||
for (Map.Entry<String, String> entry : handlerMap.entrySet()) {
|
||||
String pathPattern = CharSequenceUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN);
|
||||
oldHandlerMap.remove(pathPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册静态资源映射
|
||||
*
|
||||
* @param handlerMap 静态资源映射
|
||||
*/
|
||||
public static void registerResourceHandler(Map<String, String> handlerMap) {
|
||||
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
|
||||
// 获取已经注册的映射
|
||||
final HandlerMapping resourceHandlerMapping = applicationContext
|
||||
.getBean("resourceHandlerMapping", HandlerMapping.class);
|
||||
final Map<String, Object> oldHandlerMap = (Map<String, Object>)ReflectUtil
|
||||
.getFieldValue(resourceHandlerMapping, "handlerMap");
|
||||
// 重新注册映射
|
||||
final ServletContext servletContext = applicationContext.getBean(ServletContext.class);
|
||||
final ContentNegotiationManager contentNegotiationManager = applicationContext
|
||||
.getBean("mvcContentNegotiationManager", ContentNegotiationManager.class);
|
||||
final UrlPathHelper urlPathHelper = applicationContext.getBean("mvcUrlPathHelper", UrlPathHelper.class);
|
||||
final ResourceHandlerRegistry resourceHandlerRegistry = new ResourceHandlerRegistry(applicationContext, servletContext, contentNegotiationManager, urlPathHelper);
|
||||
for (Map.Entry<String, String> entry : handlerMap.entrySet()) {
|
||||
// 移除之前注册的映射
|
||||
String pathPattern = CharSequenceUtil.appendIfMissing(CharSequenceUtil.removeSuffix(entry
|
||||
.getKey(), StringConstants.SLASH), StringConstants.PATH_PATTERN);
|
||||
oldHandlerMap.remove(pathPattern);
|
||||
// 重新注册映射
|
||||
String resourceLocations = CharSequenceUtil.appendIfMissing(entry.getValue(), StringConstants.SLASH);
|
||||
resourceHandlerRegistry.addResourceHandler(pathPattern).addResourceLocations("file:" + resourceLocations);
|
||||
}
|
||||
final Map<String, ?> additionalUrlMap = ReflectUtil
|
||||
.<SimpleUrlHandlerMapping>invoke(resourceHandlerRegistry, "getHandlerMapping")
|
||||
.getUrlMap();
|
||||
ReflectUtil.<Void>invoke(resourceHandlerMapping, "registerHandlers", additionalUrlMap);
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-web</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-web-support</artifactId>
|
||||
<description>ContiNew Starter Web 模块 - 增强支持模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Web 模块 - 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-web-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- API 文档模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-api-doc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Undertow 服务器(采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Graceful Response(Spring Boot技术栈下的优雅响应处理组件,可以帮助开发者完成响应数据封装、异常处理、错误码填充等过程,提高开发效率,提高代码质量) -->
|
||||
<dependency>
|
||||
<groupId>com.feiniaojin</groupId>
|
||||
<artifactId>graceful-response</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -9,12 +9,46 @@
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>continew-starter-web</artifactId>
|
||||
<description>ContiNew Starter Web 模块</description>
|
||||
|
||||
<modules>
|
||||
<module>continew-starter-web-core</module>
|
||||
<module>continew-starter-web-support</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<!-- JSON 模块 - Jackson -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-json-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- API 文档模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-api-doc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Web(提供 Spring MVC Web 开发能力,默认内置 Tomcat 服务器) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<!-- 移除内置 Tomcat 服务器 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Undertow 服务器(采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Graceful Response(一个Spring Boot技术栈下的优雅响应处理组件,可以帮助开发者完成响应数据封装、异常处理、错误码填充等过程,提高开发效率,提高代码质量) -->
|
||||
<dependency>
|
||||
<groupId>com.feiniaojin</groupId>
|
||||
<artifactId>graceful-response</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
Reference in New Issue
Block a user