update 优化 统一补全代码注释

This commit is contained in:
疯狂的狮子Li
2026-03-13 19:36:14 +08:00
parent 916282ba68
commit 48992b574d
201 changed files with 2554 additions and 465 deletions

View File

@@ -20,6 +20,11 @@ import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties(XssProperties.class)
public class FilterConfig {
/**
* 注册 XSS 过滤器。
*
* @return XSS 请求过滤器实例
*/
@Bean
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
@FilterRegistration(
@@ -32,6 +37,11 @@ public class FilterConfig {
return new XssFilter();
}
/**
* 注册可重复读取请求体过滤器。
*
* @return 请求包装过滤器实例
*/
@Bean
@FilterRegistration(name = "repeatableFilter", urlPatterns = "/*")
public RepeatableFilter repeatableFilter() {

View File

@@ -14,6 +14,11 @@ import org.springframework.web.servlet.LocaleResolver;
@AutoConfiguration(before = WebMvcAutoConfiguration.class)
public class I18nConfig {
/**
* 注册自定义国际化区域解析器。
*
* @return Locale 解析器实例
*/
@Bean
public LocaleResolver localeResolver() {
return new I18nLocaleResolver();

View File

@@ -25,12 +25,22 @@ import java.util.Date;
@AutoConfiguration
public class ResourcesConfig implements WebMvcConfigurer {
/**
* 注册全局拦截器。
*
* @param registry 拦截器注册表
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 全局访问性能拦截
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
}
/**
* 注册全局格式转换器。
*
* @param registry 格式化器注册表
*/
@Override
public void addFormatters(FormatterRegistry registry) {
// 全局日期格式转换配置
@@ -43,12 +53,19 @@ public class ResourcesConfig implements WebMvcConfigurer {
});
}
/**
* 注册静态资源处理器。
*
* @param registry 资源处理器注册表
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
/**
* 跨域配置
*
* @return 全局 Cors 过滤器
*/
@Bean
public CorsFilter corsFilter() {
@@ -71,6 +88,8 @@ public class ResourcesConfig implements WebMvcConfigurer {
/**
* 全局异常处理器
*
* @return 全局异常处理器实例
*/
@Bean
public GlobalExceptionHandler globalExceptionHandler() {

View File

@@ -12,6 +12,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "captcha")
public class CaptchaProperties {
/**
* 是否启用验证码校验。
*/
private Boolean enable;
/**

View File

@@ -7,7 +7,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* xss过滤 配置属性
* XSS 过滤配置属性,用于控制过滤器开关及排除路径。
*
* @author Lion Li
*/
@@ -16,12 +16,12 @@ import java.util.List;
public class XssProperties {
/**
* Xss开关
* XSS 过滤总开关
*/
private Boolean enabled;
/**
* 排除路径
* 跳过 XSS 过滤的请求路径集合。
*/
private List<String> excludeUrls = new ArrayList<>();

View File

@@ -32,6 +32,9 @@ public class BaseController {
/**
* 页面跳转
*
* @param url 目标跳转地址
* @return Spring MVC 重定向路径表达式
*/
public String redirect(String url) {
return StringUtils.format("redirect:{}", url);

View File

@@ -7,12 +7,18 @@ import jakarta.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* 获取请求头国际化信息
* 基于请求头解析国际化区域信息的语言解析器。
*
* @author Lion Li
*/
public class I18nLocaleResolver implements LocaleResolver {
/**
* 从请求头 {@code content-language} 中解析本次请求的区域信息,缺省时回退到系统默认区域。
*
* @param httpServletRequest 当前请求
* @return 当前请求对应的区域设置
*/
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String language = httpServletRequest.getHeader("content-language");
@@ -23,6 +29,13 @@ public class I18nLocaleResolver implements LocaleResolver {
return locale;
}
/**
* 当前项目不在服务端主动切换区域信息,因此保留空实现。
*
* @param httpServletRequest 当前请求
* @param httpServletResponse 当前响应
* @param locale 目标区域
*/
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

View File

@@ -14,7 +14,7 @@ import java.io.Serial;
import java.util.concurrent.ThreadLocalRandom;
/**
* 带干扰线、波浪、圆的验证码
* 带干扰线、波浪和圆形干扰元素的验证码实现,用于增强验证码识别难度。
*
* @author Lion Li
*/
@@ -23,27 +23,70 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
@Serial
private static final long serialVersionUID = 1L;
// 构造方法(略,与之前一致)
/**
* 构造默认长度为 4 的验证码。
*
* @param width 图片宽度
* @param height 图片高度
*/
public WaveAndCircleCaptcha(int width, int height) {
this(width, height, 4);
}
/**
* 构造指定验证码长度的验证码对象。
*
* @param width 图片宽度
* @param height 图片高度
* @param codeCount 验证码字符数
*/
public WaveAndCircleCaptcha(int width, int height, int codeCount) {
this(width, height, codeCount, 6);
}
/**
* 构造指定字符数与干扰数的验证码对象。
*
* @param width 图片宽度
* @param height 图片高度
* @param codeCount 验证码字符数
* @param interfereCount 干扰元素数量
*/
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount) {
this(width, height, new RandomGenerator(codeCount), interfereCount);
}
/**
* 使用指定验证码生成器构造验证码对象。
*
* @param width 图片宽度
* @param height 图片高度
* @param generator 验证码生成器
* @param interfereCount 干扰元素数量
*/
public WaveAndCircleCaptcha(int width, int height, CodeGenerator generator, int interfereCount) {
super(width, height, generator, interfereCount);
}
/**
* 构造带字体缩放比例的验证码对象。
*
* @param width 图片宽度
* @param height 图片高度
* @param codeCount 验证码字符数
* @param interfereCount 干扰元素数量
* @param size 字体相对尺寸
*/
public WaveAndCircleCaptcha(int width, int height, int codeCount, int interfereCount, float size) {
super(width, height, new RandomGenerator(codeCount), interfereCount, size);
}
/**
* 生成验证码图片并绘制文字、扭曲效果及干扰图形。
*
* @param code 验证码文本
* @return 生成后的验证码图片
*/
@Override
public Image createImage(String code) {
final BufferedImage image = new BufferedImage(
@@ -65,6 +108,12 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
return image;
}
/**
* 绘制验证码文本并开启文字抗锯齿。
*
* @param g 图形上下文
* @param code 验证码文本
*/
private void drawString(Graphics2D g, String code) {
// 设置抗锯齿(让字体渲染更清晰)
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -77,6 +126,11 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
GraphicsUtil.drawStringColourful(g, code, this.font, this.width, this.height);
}
/**
* 绘制圆形与波浪线干扰元素。
*
* @param g 图形上下文
*/
protected void drawInterfere(Graphics2D g) {
ThreadLocalRandom random = RandomUtil.getRandom();
int circleCount = Math.max(0, this.interfereCount - 1);
@@ -98,6 +152,12 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
}
}
/**
* 绘制平滑波浪线干扰轨迹。
*
* @param g 图形上下文
* @param random 随机数生成器
*/
private void drawSmoothWave(Graphics2D g, ThreadLocalRandom random) {
int amplitude = random.nextInt(8) + 5; // 波动幅度
int wavelength = random.nextInt(40) + 30; // 波长
@@ -122,6 +182,14 @@ public class WaveAndCircleCaptcha extends AbstractCaptcha {
g.drawPolyline(xPoints, yPoints, width);
}
/**
* 生成指定 RGB 范围内的随机颜色。
*
* @param min 最小颜色值
* @param max 最大颜色值
* @param random 随机数生成器
* @return 随机颜色
*/
private Color getRandomColor(int min, int max, ThreadLocalRandom random) {
int range = max - min;
return new Color(

View File

@@ -8,16 +8,32 @@ import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* Repeatable 过滤器
* 可重复读取请求体的过滤器,仅对 JSON 请求包装可重复消费的请求对象。
*
* @author ruoyi
*/
public class RepeatableFilter implements Filter {
/**
* 过滤器初始化入口,当前无额外初始化逻辑。
*
* @param filterConfig 过滤器配置
* @throws ServletException 过滤器初始化异常
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* 为 JSON 请求创建可重复读取的包装器,便于日志、验签等场景多次读取请求体。
*
* @param request 原始请求
* @param response 当前响应
* @param chain 过滤器链
* @throws IOException IO 异常
* @throws ServletException Servlet 异常
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
@@ -33,6 +49,9 @@ public class RepeatableFilter implements Filter {
}
}
/**
* 过滤器销毁入口,当前无额外资源需要释放。
*/
@Override
public void destroy() {

View File

@@ -15,13 +15,20 @@ import java.io.IOException;
import java.io.InputStreamReader;
/**
* 构建可重复读取inputStream的request
* 构建可重复读取输入流的请求包装器,缓存请求体以支持多次读取。
*
* @author ruoyi
*/
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
/**
* 读取原始请求体并缓存到内存,统一设置请求与响应编码。
*
* @param request 原始请求
* @param response 当前响应
* @throws IOException 读取请求体异常
*/
public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding(Constants.UTF8);
@@ -30,11 +37,23 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
body = IoUtil.readBytes(request.getInputStream(), false);
}
/**
* 基于缓存的请求体构造字符读取器。
*
* @return 可重复读取的字符流
* @throws IOException IO 异常
*/
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
/**
* 返回基于缓存请求体重新生成的输入流。
*
* @return 可重复读取的输入流
* @throws IOException IO 异常
*/
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);

View File

@@ -13,22 +13,37 @@ import java.util.ArrayList;
import java.util.List;
/**
* 防止XSS攻击的过滤器
* 防止 XSS 攻击的过滤器,对非排除请求执行参数与请求体清洗。
*
* @author ruoyi
*/
public class XssFilter implements Filter {
/**
* 排除链接
* 跳过 XSS 过滤的请求路径集合。
*/
public List<String> excludes = new ArrayList<>();
/**
* 初始化过滤器并加载配置中的排除路径。
*
* @param filterConfig 过滤器配置
* @throws ServletException 过滤器初始化异常
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
XssProperties properties = SpringUtils.getBean(XssProperties.class);
excludes.addAll(properties.getExcludeUrls());
}
/**
* 对请求执行 XSS 包装处理,命中排除规则时直接放行。
*
* @param request 原始请求
* @param response 当前响应
* @param chain 过滤器链
* @throws IOException IO 异常
* @throws ServletException Servlet 异常
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
@@ -42,6 +57,13 @@ public class XssFilter implements Filter {
chain.doFilter(xssRequest, response);
}
/**
* 判断当前请求是否需要跳过 XSS 过滤。
*
* @param request 当前请求
* @param response 当前响应
* @return true 表示跳过过滤
*/
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
String url = request.getServletPath();
String method = request.getMethod();
@@ -52,6 +74,9 @@ public class XssFilter implements Filter {
return StringUtils.matches(url, excludes);
}
/**
* 过滤器销毁入口,当前无额外资源需要释放。
*/
@Override
public void destroy() {

View File

@@ -20,18 +20,27 @@ import java.util.HashMap;
import java.util.Map;
/**
* XSS过滤处理
* XSS 请求包装器,统一清洗参数与 JSON 请求体中的 HTML 标签内容。
*
* @author ruoyi
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* @param request
* 使用原始请求构造 XSS 包装器。
*
* @param request 原始请求
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* 获取并清洗单个请求参数。
*
* @param name 参数名
* @return 清洗后的参数值
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
@@ -41,6 +50,11 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
return HtmlUtil.cleanHtmlTag(value).trim();
}
/**
* 获取并清洗整组请求参数。
*
* @return 清洗后的参数映射
*/
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> valueMap = super.getParameterMap();
@@ -65,6 +79,12 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
return map;
}
/**
* 获取并清洗指定参数的多值数组。
*
* @param name 参数名
* @return 清洗后的参数值数组
*/
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
@@ -80,6 +100,12 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
return escapseValues;
}
/**
* 获取输入流并在 JSON 场景下对请求体执行清洗。
*
* @return 清洗后的输入流
* @throws IOException 读取请求体异常
*/
@Override
public ServletInputStream getInputStream() throws IOException {
// 非json类型直接返回
@@ -125,7 +151,9 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
}
/**
* 是否是Json请求
* 判断当前请求是否为 JSON 请求
*
* @return true 表示 JSON 请求
*/
public boolean isJsonRequest() {
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);

View File

@@ -26,7 +26,7 @@ import java.util.Map;
import java.util.Set;
/**
* web调用时间统计拦截器
* Web 调用时间统计拦截器,同时记录请求参数并对敏感字段做脱敏处理。
*
* @author Lion Li
* @since 3.3.0
@@ -36,6 +36,15 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
/**
* 请求进入控制器前记录入参并启动耗时统计。
*
* @param request 当前请求
* @param response 当前响应
* @param handler 目标处理器
* @return 始终返回 true继续后续处理流程
* @throws Exception 读取请求体或解析 JSON 失败时抛出
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = request.getMethod() + " " + request.getRequestURI();
@@ -71,6 +80,12 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
return true;
}
/**
* 递归移除 JSON 节点中的敏感字段,避免在日志中输出密码等敏感信息。
*
* @param node 当前 JSON 节点
* @param excludeProperties 需要排除的字段名集合
*/
private void removeSensitiveFields(JsonNode node, String[] excludeProperties) {
if (node == null) {
return;
@@ -100,6 +115,15 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
}
/**
* 请求完成后输出最终耗时,并清理线程内缓存的计时器。
*
* @param request 当前请求
* @param response 当前响应
* @param handler 目标处理器
* @param ex 请求处理过程中的异常
* @throws Exception 拦截器链路抛出的异常
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
StopWatch stopWatch = KEY_CACHE.get();