在Sling Servlet Filter中通过SlingHttpServletRequestWrapper添加自定义请求参数时,如何实例化抽象类RequestParameter?
嘿,这个问题我之前也碰到过!核心就是RequestParameter是抽象类没法直接实例化,但Sling其实给我们留了好几种解决办法,我给你详细说下:
方案一:使用RequestParameterFactory和自定义包装类(兼容大多数Sling版本)
Sling提供了RequestParameterFactory这个OSGi服务,专门用来创建RequestParameter实例。我们可以把它注入到Filter里,再配合自定义的请求包装类来合并原有参数和新参数。
第一步:修改Filter代码,注入工厂并创建参数
import org.apache.sling.api.request.RequestParameterFactory; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import javax.servlet.*; import java.io.IOException; import java.util.TreeMap; @Component(service = Filter.class, property = { "sling.filter.scope=REQUEST", // 根据你的业务需求调整scope "sling.filter.order=100" // 调整执行顺序,确保在目标Servlet之前执行 }) public class BrandParameterFilter implements Filter { @Reference private RequestParameterFactory requestParameterFactory; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if(!(request instanceof SlingHttpServletRequest) || !(response instanceof SlingHttpServletResponse)) { chain.doFilter(request, response); return; } final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request; final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response; String[] selectors = slingRequest.getRequestPathInfo().getSelectors(); if(selectors != null && selectors.length > 0) { String selector = slingRequest.getRequestPathInfo().getSelectorString(); // 创建自定义参数:这里以添加名为"brand"的参数为例 RequestParameter brandParam = requestParameterFactory.createRequestParameter( "brand", selector.getBytes(), "text/plain", selector ); TreeMap<String, RequestParameter[]> newParams = new TreeMap<>(); newParams.put("brand", new RequestParameter[]{brandParam}); // 包装请求并继续执行过滤器链 BrandSlingWrappedRequest requestWrapper = new BrandSlingWrappedRequest(slingRequest, newParams); chain.doFilter(requestWrapper, slingResponse); } else { chain.doFilter(request, response); } } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
第二步:完善请求包装类,正确合并参数
你的原有包装类有个小问题:直接putAll会覆盖同名参数,我们需要合并数组,同时覆写所有参数相关方法保证一致性:
import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.request.RequestParameter; import org.apache.sling.api.request.RequestParameterMap; import org.apache.sling.api.wrappers.RequestParameterMapWrapper; import org.apache.sling.api.wrappers.SlingHttpServletRequestWrapper; import java.util.Map; import java.util.TreeMap; public class BrandSlingWrappedRequest extends SlingHttpServletRequestWrapper { private final Map<String, RequestParameter[]> additionalParams; private RequestParameterMap mergedParameterMap; public BrandSlingWrappedRequest(final SlingHttpServletRequest request, final Map<String, RequestParameter[]> additionalParams) { super(request); this.additionalParams = additionalParams; } @Override public RequestParameterMap getRequestParameterMap() { if (mergedParameterMap == null) { // 获取原有参数并转为可修改的Map RequestParameterMap originalMap = super.getRequestParameterMap(); Map<String, RequestParameter[]> mergedMap = new TreeMap<>(originalMap); // 合并新参数,处理同名参数的情况 for (Map.Entry<String, RequestParameter[]> entry : additionalParams.entrySet()) { String paramName = entry.getKey(); RequestParameter[] newValues = entry.getValue(); if (mergedMap.containsKey(paramName)) { // 合并原有参数和新参数的数组 RequestParameter[] originalValues = mergedMap.get(paramName); RequestParameter[] combined = new RequestParameter[originalValues.length + newValues.length]; System.arraycopy(originalValues, 0, combined, 0, originalValues.length); System.arraycopy(newValues, 0, combined, originalValues.length, newValues.length); mergedMap.put(paramName, combined); } else { mergedMap.put(paramName, newValues); } } // 用Sling自带的包装类转为RequestParameterMap mergedParameterMap = new RequestParameterMapWrapper(mergedMap); } return mergedParameterMap; } // 覆写其他参数方法,保证和getRequestParameterMap的结果一致 @Override public String getParameter(String name) { RequestParameter param = getRequestParameter(name); return param != null ? param.getString() : null; } @Override public String[] getParameterValues(String name) { RequestParameter[] params = getRequestParameterMap().get(name); if (params == null) return null; String[] values = new String[params.length]; for (int i = 0; i < params.length; i++) { values[i] = params[i].getString(); } return values; } @Override public RequestParameter getRequestParameter(String name) { RequestParameter[] params = getRequestParameterMap().get(name); return params != null && params.length > 0 ? params[0] : null; } }
方案二:使用Sling Request Builder API(简洁高效,适合Sling API 2.12.0+)
如果你的项目使用的是Sling API 2.12.0或更高版本,可以直接用Request Builder API,不需要自己写包装类,代码会简洁很多:
import org.apache.sling.api.request.RequestBuilder; // 其他import和注解和方案一一致 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if(!(request instanceof SlingHttpServletRequest) || !(response instanceof SlingHttpServletResponse)) { chain.doFilter(request, response); return; } final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request; final SlingHttpServletResponse slingResponse = (SlingHttpServletResponse) response; String[] selectors = slingRequest.getRequestPathInfo().getSelectors(); if(selectors != null && selectors.length > 0) { String selector = slingRequest.getRequestPathInfo().getSelectorString(); // 直接用RequestBuilder构建修改后的请求 SlingHttpServletRequest modifiedRequest = RequestBuilder.newBuilder(slingRequest) .withRequestParameter("brand", selector) .build(); chain.doFilter(modifiedRequest, slingResponse); } else { chain.doFilter(request, response); } }
这个API会自动帮你处理参数合并、RequestParameter实例化等问题,非常省心!
几点注意事项
- 确保Filter的
scope和order配置正确,保证你的Filter在目标Servlet/Resource之前执行 - 如果处理POST请求,要注意请求体是否已经被读取(如果原有请求已经解析过请求体,包装类可能无法修改POST参数)
- 方案一中的
RequestParameterFactory是OSGi服务,要确保你的Filter是作为OSGi组件注册的(用@Component注解)
内容的提问来源于stack exchange,提问作者k.h.t
相关产品推荐
相关产品推荐

