如何让Java Servlet仅映射到无扩展名的请求路径?
实现Java Servlet仅处理无扩展名请求的几种方案
要实现你的需求——让Servlet只在请求路径没有扩展名时执行,带.css、.jsp、.js等扩展名的请求走正常流程,其实有几种实用的方式,我给你拆解一下:
方案一:在Servlet内部直接判断请求路径
这种方式最简单,不需要额外组件,直接在你的Servlet里加判断逻辑:
- 把Servlet映射到
/*(确保所有请求都会先进入这个Servlet) - 在
service方法里检查请求URI是否包含需要排除的扩展名,有就转发给容器的默认处理器,没有就执行自己的业务逻辑
代码示例:
public class MyTargetServlet extends HttpServlet { // 定义需要排除的扩展名集合 private final Set<String> EXCLUDED_EXTS = Set.of("css", "js", "jsp", "html", "png", "jpg"); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String requestURI = request.getRequestURI(); int dotPos = requestURI.lastIndexOf("."); // 判断是否存在有效扩展名(.不在末尾,且扩展名在排除列表里) if (dotPos != -1 && dotPos < requestURI.length() - 1) { String ext = requestURI.substring(dotPos + 1).toLowerCase(); if (EXCLUDED_EXTS.contains(ext)) { // 放行给容器处理,比如静态资源交给DefaultServlet,jsp交给JspServlet request.getRequestDispatcher(requestURI).forward(request, response); return; } } // 执行你的核心业务逻辑 response.getWriter().write("Handling request without extension: " + requestURI); } }
然后在web.xml里配置Servlet映射(或者用Servlet 3.0+的@WebServlet("/*")注解):
<servlet> <servlet-name>MyTargetServlet</servlet-name> <servlet-class>com.example.MyTargetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyTargetServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
方案二:用Filter前置拦截(更灵活)
如果你的逻辑需要复用,或者不想在Servlet里掺杂路径判断代码,用Filter是更好的选择——Filter会在所有请求到达Servlet之前拦截,提前过滤掉带指定扩展名的请求:
- 编写一个Filter,检查请求URI的扩展名,符合排除条件就直接放行,否则让请求继续到你的Servlet
- 把Filter映射到
/*,确保所有请求都经过它 - 你的Servlet可以正常映射(比如
/*或者其他路径)
Filter代码示例:
public class NoExtensionFilter implements Filter { private Set<String> excludedExtensions; @Override public void init(FilterConfig config) throws ServletException { // 从配置读取排除的扩展名,方便后期修改 String extParam = config.getInitParameter("excludedExtensions"); if (extParam != null && !extParam.isEmpty()) { excludedExtensions = Set.of(extParam.split(",")); } else { // 默认排除的扩展名 excludedExtensions = Set.of("css", "js", "jsp", "html", "png", "jpg"); } } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; String requestURI = request.getRequestURI(); int dotPos = requestURI.lastIndexOf("."); boolean shouldExclude = false; if (dotPos != -1 && dotPos < requestURI.length() - 1) { String ext = requestURI.substring(dotPos + 1).toLowerCase(); shouldExclude = excludedExtensions.contains(ext); } if (shouldExclude) { // 有需要排除的扩展名,直接放行,让容器处理 chain.doFilter(req, res); } else { // 无扩展名,继续到目标Servlet chain.doFilter(req, res); } } @Override public void destroy() { // 清理资源(如果有的话) } }
web.xml配置Filter和Servlet:
<filter> <filter-name>NoExtensionFilter</filter-name> <filter-class>com.example.NoExtensionFilter</filter-class> <init-param> <param-name>excludedExtensions</param-name> <param-value>css,js,jsp,html,png,jpg,gif</param-value> </init-param> </filter> <filter-mapping> <filter-name>NoExtensionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>MyTargetServlet</servlet-name> <servlet-class>com.example.MyTargetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyTargetServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
如果用Servlet 3.0+注解,Filter可以这样写:
@WebFilter( urlPatterns = "/*", initParams = @WebInitParam(name = "excludedExtensions", value = "css,js,jsp,html") ) public class NoExtensionFilter implements Filter { // 同上的init、doFilter、destroy方法 }
注意事项
- 路径判断要考虑特殊情况:比如
/test/(末尾带斜杠,无扩展名)应该被处理,/test(无斜杠无扩展名)也应该处理,/test.css?param=1(带参数但有扩展名)要排除 - 不同容器的默认Servlet名称可能不同,但方案里的转发方式不需要硬编码默认Servlet名称,直接转发原URI即可,容器会自动找到对应的处理器
- 如果是Spring MVC项目,其实可以通过
@RequestMapping的路径规则或者配置ResourceHandler来更优雅地处理,但你问的是普通Servlet,上面的方案更适用
内容的提问来源于stack exchange,提问作者Ivo Fritsch
相关产品推荐
相关产品推荐

