一.导言

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------

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

SpringBoot集成WebServlet出现自定义单servlet请求失败的问题的更多相关文章

  1. SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author l ...

  2. 关于SpringBoot集成myBatis时,mapper接口注入失败的问题

    问题描述: 在Spring Boot集成myBatis时,发现启动时,mapper接口一直注入失败. 现象如下: VehicleDAO就是需要的mapper对象,一个简单的接口. 已经在applica ...

  3. SpringBoot集成Spring Security(4)——自定义表单登录

    通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...

  4. SpringBoot自定义servlet、注册自定义的servlet、过滤器、监听器、拦截器、切面、webmvcconfigureradapter过时问题

    [转]https://www.cnblogs.com/NeverCtrl-C/p/8191920.html 1 servlet简介 servlet是一种用于开发动态web资源的技术 参考博客:serv ...

  5. springboot扫描自定义的servlet和filter代码详解_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** ...

  6. SpringBoot集成thymeleaf(自定义)模板中文乱码的解决办法

    楼主今天在学习SpringBoot集成thymelaf的时候报了中文乱码的错误,经过网上的搜索,现在得到解决的办法,分享给大家: package com.imooc.config; import or ...

  7. SpringBoot(10) Servlet3.0的注解:自定义原生Servlet、自定义原生Listener

    一.自定义原生Servlet 1.启动类里面增加注解 @ServletComponentScan 2.Servlet上添加注解  @WebServlet(name = "userServle ...

  8. springboot集成swagger添加消息头(header请求头信息)

    springboot集成swagger上篇文章介绍: https://blog.csdn.net/qiaorui_/article/details/80435488 添加头信息: package co ...

  9. 基于Springboot集成security、oauth2实现认证鉴权、资源管理

    1.Oauth2简介 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAu ...

  10. SpringBoot09 自定义servlet、注册自定义的servlet、过滤器、监听器、拦截器、切面、webmvcconfigureradapter过时问题

    1 servlet简介 servlet是一种用于开发动态web资源的技术 参考博客:servlet基础知识     httpservlet详解 2 在springboot应用中添加servlet sp ...

随机推荐

  1. 问题解决:curl: (7) Failed to connect to raw.githubusercontent.com port 443: 拒绝连接

    Ubuntu20.04下,安装Ros 指令curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key 报错:cur ...

  2. WebClient 用法小结

    进来的项目中要实现能够在windows service中调用指定项目的链接页面.由于访问页面时候使用的是ie浏览器或其他浏览器,所以想起用webclient类. 如果只想从特定的URI请求文件,则使用 ...

  3. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

    本文由爱奇艺技术团队原创分享,原题<构建通用WebSocket推送网关的设计与实践>,有优化和改动. 1.引言 丛所周之,HTTP协议是一种无状态.基于TCP的请求/响应模式的协议,即请求 ...

  4. 鸿蒙ArkUI-X简介

    ArkUI是一套构建分布式应用的声明式UI开发框架.它具备简洁自然的UI信息语法.丰富的UI组件.多维的状态管理,以及实时界面预览等相关能力,帮助您提升应用开发效率,并能在多种设备上实现生动而流畅的用 ...

  5. CDS标准视图:维护任务清单数据 I_MaintenanceTaskListData

    视图名称:维护任务清单数据 I_MaintenanceTaskListData 视图类型:基础 视图代码: 点击查看代码 @AbapCatalog.sqlViewName: 'IPMTASKLISTD ...

  6. w3cschool-Lua编程入门

    https://www.w3cschool.cn/nhycto/ https://www.w3cschool.cn/cf_web/cf_web-dvxc32qu.html 1. Lua 基础知识 (1 ...

  7. Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践

    title: Python 与 PostgreSQL 集成:深入 psycopg2 的应用与实践 date: 2025/2/4 updated: 2025/2/4 author: cmdragon e ...

  8. Git操作的基本命令

    git命令常用步骤 初始化,把当前文件夹作为git本地仓库 git init 把本地仓库与选程仓库关联 git remote add origin http://gitee.com/ 把项目区中做了修 ...

  9. Q:linux(群晖)修改网卡速率

    问题:群晖速度莫名其妙变成了1MB/s左右,查看网络状态 网卡配置变成 全双工10Mb/s 解决方法 首先开启ssh登录权限 1.控制面板 – 终端机和SNMP里,开启SSH功能. 2.通过ssh连接 ...

  10. Luogu P1983 车站分级 题解 [ 绿 ] [ 拓扑排序 ] [ 图论建模 ] [ 虚点 ]

    车站分级:很好的拓扑排序题,细节有点多. 图论建模 首先观察对于一条线路,我们可以从中直接得到什么信息: 假设这条线路的开头为 \(st\),结尾为 \(ed\),那么在 \([st,ed]\) 的车 ...