ruoyi的spring cloud项目详解(九)-CSDN博客
接着上篇文章我们一起学习
com/ruoyi/common/utils/spring/SpringContextHolder.java
package com.ruoyi.common.utils.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* spring工具类 方便在非spring管理环境中获取bean
*
* @author ruoyi
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
SpringUtils.beanFactory = beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException
{
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name)
{
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getAliases(name);
}
}
以下是对这段代码的分析:
一、功能
- 提供在非 Spring 管理的环境中方便地获取 Spring 容器中的 bean 的方法。
二、主要功能
- 实现
BeanFactoryPostProcessor接口,在 Spring 容器初始化 bean 工厂后执行特定的处理逻辑。 - 存储 Spring 的
ConfigurableListableBeanFactory,以便在后续方法中使用。 - 提供一系列静态方法用于获取 bean、检查 bean 是否存在、判断 bean 的单例性、获取 bean 的类型和别名等。
三、代码逻辑
- 使用
@Component注解将这个类标记为一个 Spring 组件,以便被 Spring 容器管理。 - 定义静态变量
beanFactory用于存储ConfigurableListableBeanFactory。 - 实现
BeanFactoryPostProcessor接口的postProcessBeanFactory方法,在这个方法中,将传入的ConfigurableListableBeanFactory赋值给静态变量beanFactory,这样在其他静态方法中就可以使用这个 bean 工厂。 getBean(String name)方法:根据给定的 bean 名称从 bean 工厂中获取 bean 的实例,并进行类型转换。getBean(Class<T> clz)方法:根据给定的类型从 bean 工厂中获取 bean 的实例。containsBean(String name)方法:检查 bean 工厂中是否包含给定名称的 bean。isSingleton(String name)方法:判断给定名称的 bean 是否是单例的。getType(String name)方法:获取给定名称的 bean 的类型。getAliases(String name)方法:获取给定名称的 bean 的别名。
四、用途
- 在一些非 Spring 管理的环境中,比如某些工具类或独立的模块中,可以使用
SpringUtils提供的静态方法方便地获取 Spring 容器中的 bean,而无需直接依赖 Spring 的上下文。 - 可以用于在运行时动态地获取特定类型的 bean,进行一些灵活的业务处理。
- 方便进行一些依赖注入的检查和调试工作。
以下是对这段代码按代码块进行分析:
一、导入和注解部分
package com.ruoyi.common.utils.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
- 导入了一些与 Spring 相关的类和接口,包括用于处理 bean 工厂的
BeanFactoryPostProcessor和ConfigurableListableBeanFactory,以及用于处理异常的BeansException和NoSuchBeanDefinitionException。 - 使用
@Component注解将这个类标记为一个 Spring 组件,以便被 Spring 容器管理。
二、类定义和静态变量部分
@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
- 定义了一个名为
SpringUtils的类,并使用@Component注解使其成为一个可被 Spring 容器管理的组件。 - 声明了一个静态变量
beanFactory,用于存储ConfigurableListableBeanFactory,这是 Spring 容器的一种类型,用于管理 bean 的定义和实例。
三、实现接口的方法部分
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
SpringUtils.beanFactory = beanFactory;
}
- 实现了
BeanFactoryPostProcessor接口的postProcessBeanFactory方法。这个方法在 Spring 容器初始化 bean 工厂后被调用。 - 在这个方法中,将传入的
ConfigurableListableBeanFactory赋值给静态变量beanFactory,以便在其他静态方法中使用这个 bean 工厂。
四、获取 bean 的方法部分
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}
public static <T> T getBean(Class<T> clz) throws BeansException {
T result = (T) beanFactory.getBean(clz);
return result;
}
- 提供了两个静态方法
getBean用于获取 Spring 容器中的 bean。 - 第一个方法
getBean(String name)根据给定的 bean 名称从 bean 工厂中获取 bean 的实例,并进行类型转换。使用了@SuppressWarnings("unchecked")注解来抑制未经检查的类型转换警告。 - 第二个方法
getBean(Class<T> clz)根据给定的类型从 bean 工厂中获取 bean 的实例。
五、检查 bean 存在性和属性的方法部分
public static boolean containsBean(String name) {
return beanFactory.containsBean(name);
}
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
return beanFactory.isSingleton(name);
}
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getType(name);
}
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
return beanFactory.getAliases(name);
}
containsBean(String name)方法用于检查 bean 工厂中是否包含给定名称的 bean。isSingleton(String name)方法用于判断给定名称的 bean 是否是单例的。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。getType(String name)方法用于获取给定名称的 bean 的类型。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。getAliases(String name)方法用于获取给定名称的 bean 的别名。如果 bean 定义不存在,会抛出NoSuchBeanDefinitionException异常。
我们接着研究
com/ruoyi/common/xss/XssFilter.java
package com.ruoyi.common.xss;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
/**
* 防止XSS攻击的过滤器
*
* @author ruoyi
*/
public class XssFilter implements Filter
{
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
/**
* xss过滤开关
*/
public boolean enabled = false;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String tempExcludes = filterConfig.getInitParameter("excludes");
String tempEnabled = filterConfig.getInitParameter("enabled");
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] url = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++)
{
excludes.add(url[i]);
}
}
if (StringUtils.isNotEmpty(tempEnabled))
{
enabled = Boolean.valueOf(tempEnabled);
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp))
{
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
if (!enabled)
{
return true;
}
if (excludes == null || excludes.isEmpty())
{
return false;
}
String url = request.getServletPath();
for (String pattern : excludes)
{
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find())
{
return true;
}
}
return false;
}
@Override
public void destroy()
{
}
}
以下是对这段代码的分析:
一、功能
- 提供一个过滤器来防止跨站脚本攻击(XSS)。
二、主要功能
- 可配置排除特定 URL 的 XSS 过滤。
- 根据配置开关决定是否启用 XSS 过滤。
- 对请求进行 XSS 过滤处理后再传递给后续的处理链。
三、代码逻辑
- 定义成员变量和构造函数:
public List<String> excludes = new ArrayList<>();:用于存储需要排除进行 XSS 过滤的 URL 列表。public boolean enabled = false;:XSS 过滤的开关,默认关闭。
- 初始化方法(init):
- 从过滤器的配置参数中读取
excludes和enabled的值。 - 如果
excludes参数有值,将其分割成数组,然后添加到排除列表中。 - 如果
enabled参数有值,将其转换为布尔值并设置过滤开关。
- 从过滤器的配置参数中读取
- 过滤方法(doFilter):
- 将
ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse。 - 调用
handleExcludeURL方法判断当前请求的 URL 是否需要排除在 XSS 过滤之外。 - 如果需要排除,直接将请求传递给后续处理链并返回。
- 如果不需要排除,创建一个
XssHttpServletRequestWrapper对象包装原始请求,对请求进行 XSS 过滤处理,然后将包装后的请求传递给后续处理链。
- 将
- 排除 URL 处理方法(handleExcludeURL):
- 如果 XSS 过滤开关关闭,返回
true,表示不进行过滤。 - 如果排除列表为空,返回
false,表示不排除任何 URL。 - 遍历排除列表,使用正则表达式匹配当前请求的 URL,如果匹配成功,返回
true,表示该 URL 需要排除在 XSS 过滤之外。 - 如果没有任何 URL 匹配成功,返回
false,表示该 URL 需要进行 XSS 过滤。
- 如果 XSS 过滤开关关闭,返回
- 销毁方法(destroy):
- 目前为空方法,可用于在过滤器被销毁时进行清理操作。
四、用途
- 在 Web 应用中,通过配置这个过滤器,可以有效地防止 XSS 攻击。
- 可以根据实际需求配置排除特定 URL 的 XSS 过滤,例如对于一些信任的内部接口或者不需要进行 XSS 过滤的资源请求。
- 通过设置过滤开关,可以方便地在不同环境下开启或关闭 XSS 过滤功能。
以下是对这段代码按代码块进行讲解:
一、包声明和导入部分
package com.ruoyi.common.xss;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
- 声明了包名
com.ruoyi.common.xss。 - 导入了一系列用于处理 Servlet 过滤器、正则表达式匹配、输入输出流以及自定义工具类
StringUtils所需的类和接口。
二、过滤器类定义部分
public class XssFilter implements Filter {
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
/**
* xss过滤开关
*/
public boolean enabled = false;
- 定义了一个名为
XssFilter的类,实现了Filter接口,表示这是一个 Servlet 过滤器。 - 声明了一个
List<String>类型的成员变量excludes,用于存储需要排除进行 XSS 过滤的 URL 列表。 - 声明了一个
boolean类型的成员变量enabled,作为 XSS 过滤的开关,默认值为false,表示关闭过滤。
三、初始化方法部分
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String tempExcludes = filterConfig.getInitParameter("excludes");
String tempEnabled = filterConfig.getInitParameter("enabled");
if (StringUtils.isNotEmpty(tempExcludes)) {
String[] url = tempExcludes.split(",");
for (int i = 0; url!= null && i < url.length; i++) {
excludes.add(url[i]);
}
}
if (StringUtils.isNotEmpty(tempEnabled)) {
enabled = Boolean.valueOf(tempEnabled);
}
}
- 重写了
Filter接口的init方法,用于在过滤器初始化时从过滤器配置中读取参数。 - 通过
filterConfig.getInitParameter("excludes")获取配置中的排除 URL 列表参数,如果该参数不为空,使用逗号分割字符串得到 URL 数组,然后遍历数组将每个 URL 添加到excludes列表中。 - 通过
filterConfig.getInitParameter("enabled")获取配置中的过滤开关参数,如果该参数不为空,将其转换为布尔值并设置给enabled变量。
四、过滤方法部分复制
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp)) {
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
- 重写了
Filter接口的doFilter方法,这是过滤器的核心处理方法。 - 将
ServletRequest和ServletResponse强制转换为HttpServletRequest和HttpServletResponse,以便进行 HTTP 特定的操作。 - 调用
handleExcludeURL方法判断当前请求的 URL 是否需要排除在 XSS 过滤之外。如果是,直接将原始请求传递给后续处理链并返回;如果不是,创建一个XssHttpServletRequestWrapper对象包装原始请求,对请求进行 XSS 过滤处理,然后将包装后的请求传递给后续处理链。
五、排除 URL 处理方法部分
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
if (!enabled) {
return true;
}
if (excludes == null || excludes.isEmpty()) {
return false;
}
String url = request.getServletPath();
for (String pattern : excludes) {
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find()) {
return true;
}
}
return false;
}
- 定义了一个私有方法
handleExcludeURL,用于判断当前请求的 URL 是否应该被排除在 XSS 过滤之外。 - 如果 XSS 过滤开关
enabled为false,直接返回true,表示不进行过滤。 - 如果排除列表
excludes为null或者为空,返回false,表示不排除任何 URL。 - 获取当前请求的 URL(通过
request.getServletPath()),然后遍历排除列表中的每个模式。对于每个模式,使用正则表达式Pattern.compile("^" + pattern)进行编译,然后使用Matcher对象进行匹配。如果匹配成功,返回true,表示该 URL 需要排除在 XSS 过滤之外;如果没有任何 URL 匹配成功,返回false,表示该 URL 需要进行 XSS 过滤。
六、销毁方法部分
@Override
public void destroy() {
}
- 重写了
Filter接口的destroy方法,目前为空方法,可用于在过滤器被销毁时进行清理操作。
接着看
com/ruoyi/common/xss/XssHttpServletRequestWrapper.java
package com.ruoyi.common.xss;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
/**
* XSS过滤处理
*
* @author ruoyi
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request)
{
super(request);
}
@Override
public String[] getParameterValues(String name)
{
String[] values = super.getParameterValues(name);
if (values != null)
{
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++)
{
// 防xss攻击和过滤前后空格
escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
}
return escapseValues;
}
return super.getParameterValues(name);
}
}
以下是对这段代码的分析:
一、功能
提供对 HTTP 请求参数进行 XSS(跨站脚本攻击)过滤的功能。
二、主要功能
- 继承
HttpServletRequestWrapper类,对请求进行包装,以便在不改变原始请求对象的情况下对请求参数进行处理。 - 重写
getParameterValues方法,对请求参数进行 XSS 过滤和前后空格的去除。
三、代码逻辑
- 类定义和构造函数:
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper:定义一个名为XssHttpServletRequestWrapper的类,继承自HttpServletRequestWrapper。public XssHttpServletRequestWrapper(HttpServletRequest request):构造函数,接收一个HttpServletRequest对象,并将其传递给父类构造函数进行初始化。
- 重写
getParameterValues方法:- 首先调用父类的
getParameterValues方法获取请求参数的值数组。 - 如果参数值数组不为
null,遍历数组中的每个值。 - 对于每个值,使用
Jsoup.clean(values[i], Whitelist.relaxed())进行 XSS 过滤,这里使用了Jsoup库的clean方法,并传入一个较为宽松的白名单(Whitelist.relaxed())。 - 对过滤后的字符串进行前后空格的去除(
.trim())。 - 将处理后的参数值存储到新的数组中,并返回这个新数组。
- 如果参数值数组为
null,直接返回父类的getParameterValues方法的结果。
- 首先调用父类的
用途:
在 Web 应用中,此代码可用于防止用户输入的恶意脚本被执行,从而提高应用的安全性。通常在 Servlet 过滤器中调用这个包装类来处理请求。例如,在一个防止 XSS 攻击的过滤器中,可以像这样使用这个包装类:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.xss.XssHttpServletRequestWrapper;
public class XssFilter implements Filter {
//...
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 使用 XssHttpServletRequestWrapper 包装原始请求
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(req);
chain.doFilter(xssRequest, response);
}
//...
}
在上述示例中,XssFilter过滤器在处理请求时,使用XssHttpServletRequestWrapper对原始的HttpServletRequest进行包装,确保请求参数经过 XSS 过滤后再传递给后续的处理逻辑。这样,在整个 Web 应用的请求处理流程中,就可以有效地防止 XSS 攻击。
以下是对这段代码按代码块进行分析:
一、包声明和导入部分
package com.ruoyi.common.xss;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
- 声明了包名
com.ruoyi.common.xss。 - 导入了
HttpServletRequest和HttpServletRequestWrapper,用于对 HTTP 请求进行包装和扩展。 - 导入了
Jsoup库中的Jsoup类和Whitelist枚举,用于进行 XSS 过滤。
二、类定义部分
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
- 定义了一个名为
XssHttpServletRequestWrapper的类,继承自HttpServletRequestWrapper。 - 提供了一个构造函数,接收一个
HttpServletRequest对象,并将其传递给父类的构造函数进行初始化。
三、重写getParameterValues方法部分
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values!= null) {
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
// 防xss攻击和过滤前后空格
escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
}
return escapseValues;
}
return super.getParameterValues(name);
}
- 重写了父类的
getParameterValues方法,用于获取指定参数名的参数值数组。 - 首先调用父类的方法获取参数值数组。
- 如果参数值数组不为
null,则进行以下处理:- 计算参数值数组的长度,并创建一个新的同长度的字符串数组
escapseValues。 - 遍历参数值数组,对于每个值,使用
Jsoup.clean(values[i], Whitelist.relaxed())进行 XSS 过滤,这里使用了Jsoup库的clean方法,并传入一个较为宽松的白名单(Whitelist.relaxed())。然后对过滤后的字符串进行前后空格的去除(.trim()),并将结果存储到新的数组中。 - 最后返回处理后的新数组。
- 计算参数值数组的长度,并创建一个新的同长度的字符串数组
- 如果参数值数组为
null,则直接返回父类方法的结果。
&spm=1001.2101.3001.5002&articleId=141833105&d=1&t=3&u=a2b9dd3b51f24b4b859f041189306f3a)
920

被折叠的 条评论
为什么被折叠?



