一.导言

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. How to Disable SELinux in Ubuntu Server/Desktop

    https://www.configserverfirewall.com/ubuntu-linux/disable-selinux-ubuntu/ In this tutorial I will ex ...

  2. jacoco代码覆盖率报告分析

    一.目的 对Jacoco代码覆盖率统计维度.报告字段说明.报告详细分析描述.并为精准测试.健壮性测试提供指导. 二.Jacoco代码覆盖率统计维度 Jacoco是从代码指令(Instructions, ...

  3. java - Powermock-Failed to transform class with name...ArrayIndexOutOfBoundsException: 3

    I'm trying to run a junit test. i'm using: junit 4.10,easymock 3.0,powermock-core 1.4.10 (uses javas ...

  4. Qt/C++音视频开发54-视频监控控件的极致设计

    一.前言 跌跌撞撞摸爬滚打一步步迭代完善到今天,这个视频监控控件的设计,在现阶段水平上个人认为是做的最棒的(稍微自恋一下),理论上来说应该可以用5年不用推翻重写,推翻重写当然也是程序员爱干的事情,这个 ...

  5. 得物从0到1自研客服IM系统的技术实践之路

    本文由得物技术王卫强分享,为了更好的阅读体验,有较多的内容修订和排版优化. 一.引言 客服IM的核心业务其实就是在线沟通,客服IM的好处是使得客服与用户通过实时沟通的方式可以在最短的时间内帮助用户解决 ...

  6. 不为人知的网络编程(十四):拔掉网线再插上,TCP连接还在吗?一文即懂!

    本文由作者小林coding分享,来自公号"小林coding",有修订和改动. 1.引言 说到TCP协议,对于从事即时通讯/IM这方面应用的开发者们来说,再熟悉不过了.随着对TCP理 ...

  7. Ubuntu 16.04 编译安装Python 2.7.18

    安装python 2.7.18(注)使用apt install python安装的版本是2.7.10,该版本对部分项目存在兼容性问题,因此需要手动编译安装 安装python编译环境sudo apt i ...

  8. ClickHouse-2接口

    客户端 ClickHouse提供了两个网络接口(两个都可以选择包装在TLS中以增加安全性): HTTP, 包含文档,易于使用. Native TCP,简单,方便使用. 在大多数情况下,建议使用适当的工 ...

  9. 项目PMP之十三相关方管理

    项目PMP之十三--相关方管理   一.定义: 核心理念: 每个项目都有相关方,他们会受项目的积极或消极影响,或者能对项目施加积极或消极的影响. 以相关方满意度作为项目目标进行识别和管理,并保持沟通, ...

  10. 一文搞懂SaaS架构建设流程:业务战略设计、架构蓝图设计、领域系统架构设计、架构治理与实施

    大家好,我是汤师爷~ SaaS架构建设是一项复杂的系统工程,不仅需要技术层面的实现,更要从业务战略.架构设计.治理与实施等多个维度进行全面规划. 一个成功的SaaS架构可以帮助企业降低IT成本.提升业 ...