SpringBoot集成WebServlet出现自定义单servlet请求失败的问题

一.导言

 SpringBoot的真正核心是快速整合以及自动装配,所以在spring家族中springBoot不仅整合了Spring的IOC容器还兼容了WebServlet容器;这使得springBoot项目不仅支持快速开发微服务,同时具备开发MVC模式下的项目。

其中MVC模式的实现者之一就是WebServlet;由于springBoot的整合,在其项目中开发WebServlet也是可行方案之一。但是在使用servlet技术时我们遇到了一个问题:即在SpringBoot中,以Bean的方式注册servlet需要自定义两个及以上的servlet。

这是为什么呢?

二.测试验证问题

 首先验证一个servlet的情况

先配置servlet实现类:

public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet 1 的实现类");
        resp.getWriter().print("this is servlet 1");
    }
}

 

在config配置类中注册这个servletBean:

@Configuration
public class RegisterBean {
    @Bean
    public OneServlet createOneServlet(){
        //注册servlet 1
        return new OneServlet();
    }
}

 

直接启动springBoot启动器查看是否可以完成一次servlet的请求

地址栏输入:

http://localhost:9000/createOneServlet/

 

或者:

http://localhost:9000/OneServlet/

 

显示都是错误页面:

 验证两个servlet的情况

拓展一个servlet实现类:

public class TwoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet 2 的实现类");
        resp.getWriter().print("this is servlet 2");
    }
}

 

以及使用Bean的方式完成注入:

@Configuration
public class RegisterBean {
    @Bean
    public OneServlet createOneServlet(){
        //注册servlet 1
        return new OneServlet();
    }
        @Bean
    public TwoServlet createTwoServlet(){
        //注册servlet 2
        return new TwoServlet();
    }
}

 

再次启动springBoot启动器:

运行:

http://localhost:9000/createOneServlet/

结果可以拿到请求,正常处理

 运行:

http://localhost:9000/createTwoServlet/

结果依旧可以拿到,正常处理请求:

 这就出现了刚开始提到的那个问题:springBoot项目运行时,一个servlet无法进行请求,当有两个时却可以进行请求

 解决这问题之前,我们需要一点前言知识,那就是需要先了解SpringMVC中的DispatcherServlet

三.解决单servlet无法正常请求的问题

 DispatcherServlet 是 Spring MVC 框架的核心组件,它充当前端控制器(Front Controller)的角色,负责接收所有的 HTTP 请求并将其分发到相应的处理器(Handler)。通过这种方式,DispatcherServlet 实现了请求的集中管理和分发。请求分发:接收所有进入的应用程序的HTTP请求,并根据配置将它们分发给合适的处理器(Controller)。

 当然DispatcherServlet的功能还有很多,我们只把关系到问题的部分单独拿出来。我们知道SpringMVC在JavaWeb的基础之上,演化了DispatcherServlet,它的本质依旧是一个servlet,在SpringMVC中将其单独拿出来作为前后端连接的大脑,通常它会将前端所有的请求都拦截下来,然后经过一系列验证之后移交给controller处理,处理完成之后又返回给它,返回给视图层。

由于springBoot中整合了SpringMVC,故而DispatcherServlet存在于spring容器中的。

 回到刚刚的问题,一个servlet为什么执行不起来,这还得分析我们注入servlet的方式

@Bean
    public OneServlet createOneServlet(){
        //注册servlet 1
        return new OneServlet();
    }

 

 由于我们注入使用的是最简单的注入方式,并没有配置这个servlet的请求路径;

DeepSeek:如果没有显式配置路径映射,Spring Boot 会尝试为 Servlet 分配默认路径,通常是 Servlet 的名称或类名的小写形式。如果默认路径与其他映射冲突,或 Servlet 未正确注册,可能导致无法访问。

在第一种情况下,springBoot是在尝试进行为servlet命名的,只是为其命名的映射路径刚好和DispatcherServlet的拦截请求冲突了,故而失败了

我们在失败的情况下编写一个controller,看相同的请求是不是交给DispatcherServlet处理了

controller:

@RestController
public class ServletTest {
    @GetMapping("/createOneServlet/")
    public String test(){
        return "return from Spring MVC";
    }
}

 

和第一次失败测试一样的请求:

http://localhost:9000/createOneServlet/

结果

 可以发现,配置一个controller之后确实请求被DispatcherServlet接管了,故而有springMVC框架进行返回

知道了问题所在就可以进行修改了,推荐两种解决方案

1.更改DispatcherServlet的默认拦截路径

在SpringBoot中DispatcherServlet的默认拦截路径是  "/*" ;故而将其改到其它位置后,他就不会影响SpringBoot为没有配置映射路径的servlet命名了

更改application.properties文件:

spring.mvc.servlet.path= /test/

 

将DispatcherServlet的默认匹配路径更改到   “ /test/* ”  下

注销controller类的实现:

//    @GetMapping("/createOneServlet/")
//    public String test(){
//        return "return from Spring MVC";
//    }

 

再次启动,测试单servlet未配置路径是否有问题:

http://localhost:9000/createOneServlet/

 

结果:

 

可以看到,servlet成功将其请求处理了

2.配置单个servlet的请求路径

配置servlet实现类使用@WebServlet注解:

@WebServlet(urlPatterns = "/createOneServlet")
public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet 1 的实现类");
        resp.getWriter().print("this is servlet 1");
    }
}

 

在springBoot启动器上配置自动扫描servlet的注解@ServletComponentScan:

@SpringBootApplication
@ServletComponentScan
public class ServletTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServletTestApplication.class, args);
    }

}

 

启动测试:

http://localhost:9000/createOneServlet/

 

结果:

 可以发现依旧运行出来了结果

如上就是推荐在SpringBoot中注册servlet的两种方式

为什么两个自定义servlet不写映射却可以呢?

DeepSeek:两个自定义 Servlet 可以访问的原因

自动注册:当有多个 Servlet 时,Spring Boot 会为每个 Servlet 生成默认路径,通常基于类名或者Bean。
路径唯一性:多个 Servlet 的默认路径通常不会冲突,因此可以正常访问。

也就是基于这样的原因,DispatcherServlet没有产生拦截,因为这两个自定义servlet已经在Servlet容器中完成注册,根据Java servlet的匹配规范,即最长匹配原则,/(类名|Bean)的匹配长度比DispatcherServlet /* 精度更高,故而两个servlet的情况下,即使不修改SpringMVC的配置依旧可以正常访问。

 

------END------

本文虽经反复斟酌,但仍可能存在疏漏或不当之处,衷心希望得到各位同行的批评指正,以期进一步完善。

posted @ 2025-03-12 19:25  回忆也交给时间  阅读(194)  评论(0编辑  收藏  举报