在springboot 中配置使用servlet

2023-11-19

1.前言

还记得,说到web项目,最早接触的就是servlet,实际上SSH项目,也是依赖于servlet,在web.xml文件中进行配置。那么使用了springboot之后,不仅有一个疑问,虽然SpringMVC已经帮我们很容易的实现了spring web项目的使用,只需要@Controller就能搞定。但是我们需要使用servlet该如何做呢?虽然这种需求非常少,但是在springboot的官方文档对servlet的使用有过描述。下面我们来看看在springboot中如何使用和配置servlet。

2.servlet

在com.dhb.servlet包中定义一个myservlet类。通过@webServlet注解定义其name和urlPatterns。
同时继承父类HttpServlet的doGet和doPost方法。这样就是我们之前经常使用的Servlet了。

package com.dhb.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "myServlet",urlPatterns = "/srv")
public class MyServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("servlet doGet method called...");
		resp.getWriter().println("doGet method called url is ["+req.getRequestURL()+"] time is ["+System.currentTimeMillis()+"]");
		resp.getWriter().flush();
		resp.getWriter().close();
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("servlet doPost method called...");
		resp.getWriter().println("doPost method called url is ["+req.getRequestURL()+"] time is ["+System.currentTimeMillis()+"]");
		resp.getWriter().flush();
		resp.getWriter().close();
	}
}

这个Servlet配置完成之后,我们要如何让其生效呢,下一步就是配置springboot的启动类。

3.springboot配置

在包com.dhb中定义一个Bean。
需要注意的是,由于使用了@ServletComponentScan,这个注解中没有指定具体的package,那么就需要确保被扫描的类位于该类所在的子目录中。也就是在本文中,其所在的package 在com.dhb中。

package com.dhb;

import com.dhb.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@ServletComponentScan
public class MySpringBootApplication {

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

	//将servlet 添加到springboot容器中
	@Bean
	public ServletRegistrationBean<MyServlet> webServletRegistrationBean() {
		ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(new MyServlet());
		bean.setLoadOnStartup(1);
		return bean;
	}
}

4.启动项目

在上一篇中介绍了jrebel,现在就通过jribel启动:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UkkSc7KV-1614049960768)(https://upload-images.jianshu.io/upload_images/3237432-6786c290ad477285.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

然后我们通过postman访问:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKxXktVE-1614049960774)(https://upload-images.jianshu.io/upload_images/3237432-ff9bbef1c81b544e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

可以看到收到了预期的响应。

5.UrlMapping设置

在springboot的启动类中定义了的Bean里面,可以设置urlMapping。但是需要注意的是,这样一来,Servlet设置的urlPatterns将不再生效。
我们将代码改为如下:

ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(new MyServlet(),"/s2");

之后重启,由于使用了Jrebel,则不需要重启,系统会自动加载。
可以看到http://127.0.0.1:8084/s2访问成功:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-45Uju4wm-1614049960776)(https://upload-images.jianshu.io/upload_images/3237432-4f8f6254900a066b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

但是之前的http://127.0.0.1:8084/srv则返回了404错误。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eaNxLBHb-1614049960779)(https://upload-images.jianshu.io/upload_images/3237432-16aa7b6c670ad33e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

6.Filter

Filter的使用也很简单,建立一个package com.dhb.servlet.filter 。

package com.dhb.servlet.filter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


@WebFilter(filterName = "MyFilter",urlPatterns = "/s2")
public class MyFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Filter init ...");
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("do Filter ...");
		chain.doFilter(request,response);
	}

	@Override
	public void destroy() {
		System.out.println("destroy ... ");
	}
}

然后我们重启服务,可以看到filter已经被初始化:

2021-02-22 19:41:51.512  INFO 11532 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-02-22 19:41:51.620  INFO 11532 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-02-22 19:41:51.620  INFO 11532 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1289 ms
2021-02-22 19:41:51.682  INFO 11532 --- [           main] o.s.boot.web.servlet.RegistrationBean    : Servlet myServlet was not registered (possibly already registered?)
Filter init ...
2021-02-22 19:41:52.018  INFO 11532 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-02-22 19:41:52.365  INFO 11532 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2021-02-22 19:41:52.397  INFO 11532 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8084 (http) with context path ''
2021-02-22 19:41:52.406  INFO 11532 --- [           main] com.dhb.MySpringBootApplication          : Started MySpringBootApplication in 2.904 seconds (JVM running for 6.273)

之后请求设置的路径。
http://127.0.0.1:8084/s2
可以看到输出:

2021-02-22 19:41:52.365  INFO 11532 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2021-02-22 19:41:52.397  INFO 11532 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8084 (http) with context path ''
2021-02-22 19:41:52.406  INFO 11532 --- [           main] com.dhb.MySpringBootApplication          : Started MySpringBootApplication in 2.904 seconds (JVM running for 6.273)
do Filter ...
servlet doPost method called...

需要注意的是,我们在filter中的chain.doFilter(request,response);这就是责任链模式,request链条上的filter执行完毕之后,再回过来按照逆序执行response上的filter。

7.Listener

Listener是servlet规范中的一中特殊类,用于监听servletContext,HttpSession和ServletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件,用于在事件的发生前,发生后做一些必要的处理,可用于如下场景:

  • 1.统计在线人数和在线用户数
  • 2.系统启动时加载初始化信心
  • 3.统计网站访问信心
  • 4.记录用户访问路径

我们来创建一个Listener如下:

package com.dhb.servlet.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyHttpSessionListener implements HttpSessionListener {
	
	public static int online = 0;

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		System.out.println("创建session id is ["+se.getSession().getId()+"]");
		online ++;
		System.out.println("当前session总数:["+online+"]");
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("销毁session id is ["+se.getSession().getId()+"]");
		online --;
		System.out.println("当前session总数:["+online+"]");
	}
}

同样,需要在MySpringBootApplication中配置一个bean

@Bean
public ServletListenerRegistrationBean listenerRegistrationBean() {
	ServletListenerRegistrationBean srb = new ServletListenerRegistrationBean();
	srb.setListener(new MyHttpSessionListener());
	System.out.println("listener 创建成功");
	return srb;
}

官方文档建议Listener和Filter都用@Bean 注释方法的方式来创建。这样可以更加灵活控制。
启动Jrebel:

2021-02-23 10:46:38.126  INFO 18368 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-02-23 10:46:38.126  INFO 18368 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1218 ms
listener 创建成功
2021-02-23 10:46:38.201  INFO 18368 --- [           main] o.s.boot.web.servlet.RegistrationBean    : Servlet myServlet was not registered (possibly already registered?)
Filter init ...
2021-02-23 10:46:38.442  INFO 18368 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-02-23 10:46:38.774  INFO 18368 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2021-02-23 10:46:38.815  INFO 18368 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8084 (http) with context path ''
2021-02-23 10:46:38.825  INFO 18368 --- [           main] com.dhb.MySpringBootApplication          : Started MySpringBootApplication in 2.696 seconds (JVM running for 6.132)

可以看到,Listener实际上在Filter之前被初始化。
但是此时我们需要注意的是,请求任意url,session并没有增加。这是因为我们需要在请求后面增加session的操作。
修改Controller中的代码:

@Controller
public class HelloController {

	@RequestMapping("/hello")
	@ResponseBody
	public String hello(HttpSession session) {
		session.setAttribute("aa","aa");
		return "hello";
	}

}

现在再来请求http://127.0.0.1:8084/hello,通过不同浏览器可以看到输出:

创建session id is [06327B8BE718B12F0B3CAA829160B162]
当前session总数:[1]
创建session id is [BC09536518EB4ED9F94D2290E6578DD9]
当前session总数:[2]

这样监听器就配置成功了。

8.总结

在SpringBoot中使用servlet是很少见的,毕竟SpringMVC使用起来非常方便,几乎没有直接使用servlet的必要。但是这并不意味着我们可以忽略servlet的存在。毕竟SpringMVC也是通过servlet演化而来。对于servlet规范中的filter和listener,我们可能使用的场景会非常多。特别是Listener,用在初始化数据的load等操作上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在springboot 中配置使用servlet 的相关文章

随机推荐

  • 远程桌面dos开启

    lt DOCTYPE html PUBLIC WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml strictdtd gt 注册表内容 Windows Registry Editor Versio
  • 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 前置知识 1 算法稳定性 在一个序列中 能保证两个相等的数 经过排序之后 其在序列的前后位置顺序不变 A1 A2 排序前 A1 在 A2 前面 排序后 A1 还在 A2 前面 2 时间复杂度 时间复杂度是用于衡
  • Sublimewebinspector 断点不能打上的解决方法

    最近老大在sublime上开发出了我们产品的开发包 这个开发包能像ZenCoding一样快速打出前端代码 这样开发者用我们产品的概率就大多了 但是对于产品中的js代码 现在还没有很好的工具 搬砖的我小有雄心壮志的想给我们的产品开发一个JS代
  • 生成专题4

    文章转自微信公众号 机器学习炼丹术 作者 陈亦新 欢迎交流共同进步 联系方式 微信cyx645016617 学习论文 Analyzing and Improving the Image Quality of StyleGAN 文章目录 4
  • vue学习语法校验笔记总结

    vue语法校验需要安装eslint plugins vue插件 插件安装完成后 进入 插件配置 即可找到刚才安装插件 它的对应的配置文件是 eslintrc js 选项对应说明如下 module exports extends plugin
  • ES6之Map和Set有什么不同?

    一 Map 1 定义 Map是ES6提供的一种新的数据结构 它是键值对的集合 类似于对象 但是键的范围不限于字符串 各种类型的值都可以当做键 Object结构是 字符串 值 的对应 Map结构则是 值 值 的对应 2 代码示例 Map本身是
  • Mybatis的注解方式开发

    目录 一 环境搭建与测试 二 注解方式的单表CRUD 三 注解方式的复杂关系映射 属性与列的对应关系 多表查询 一对一 一对多 四 注解方式使用二级缓存 前面的文章使用的都是XML配置的方式进行开发 当然 Mybatis也可以使用注解的方式
  • c++ for循环的新写法

    for循环遍历一个数组 string类 vector类等 老写法 include
  • gzip压缩的json文件在谷歌浏览器(chrome)中可以正常解析,但是在safari浏览器乱码

    gzip压缩的json文件在谷歌浏览器 chrome 中可以正常解析 但是在safari浏览器乱码 挺奇怪的一个问题 json数据通过gzip压缩之后 axios接收到的数据在chrome中是正常的 但是在safari中却是乱码 文件流 后
  • jsp页面中获取参数值

    1 GET方法用根据URL获取参数值 1 1 jsp页面 1 2 3 6 7 8 9 10
  • oracle 不完整恢复,Oracle——不完全恢复

    不完全恢复分为用户不完全恢复和RMAN不完全恢复 若联机重做日志文件或者归档日志文件有丢失 则只能进行不完全恢复 一 不完全恢复的分类 1 time recover选项 指定恢复到某个时间点 常用 2 cancel recover选项 停止
  • buuctf - crypto - Rabbit

    rabbit 加解密 在线Rabbit加密 Rabbit解密 在线工具
  • 把路由器设置为交换机或者二级路由设置联网

    五台电脑用了一个路由 还有一台没有连上 结果又买了一个路由 问问能把剩下的电脑接上吗 该怎么接法 1 做二级路由 把第二個路由器作为二级路由用 接线的方法就像你接第一个主路由器那样 从第一个路由器LAN口出来的一条网线接在第二个路由器的WA
  • 姿态估计之2D人体姿态估计 - (OpenPose) Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields

    参见 论文翻译 openpose magic ll的博客 CSDN博客 OpenPose论文解读 知乎 Openpose论文阅读 jmucvm的博客 CSDN博客 openpose论文总结 htt789的博客 CSDN博客 OpenPifP
  • ELK配置记录(filebeat+kafka+Logstash+Elasticsearch+Kibana)

    一 简介 elk日志平台 日志收集 分析和展示的解决方案 满足用户对 志的查询 排序 统计需求 elk架构 filebeat 采集 kafka Logstash 管道 Elasticsearch 存储 搜索 Kibana 日志应用 各组件功
  • 离散仿真引擎基础作业与练习

    作业内容 一 简答题 1 解释 GameObjects 和 Assets 的区别与联系 2 下载几个游戏案例 分别总结资源 对象组织的结构 3 使用 debug 验证 MonoBehaviour 基本行为或事件触发条件 4 了解 GameO
  • zip.h解析

    返回值 define ZIP OK 0 define ZIP EOF 0 define ZIP ERRNO Z ERRNO define ZIP PARAMERROR 102 define ZIP BADZIPFILE 103 define
  • 《区块链技术与应用》学习笔记10——ETH数据结构

    在以太坊中 有三棵树的说法 分别是状态数 收据树和交易树 一 引入 我们要实现从账户地址到账户状态的映射 在以太坊中 账户地址为160位 表示为40个16进制数 状态包含了余额 alance 交易次数 nonce 合约账户中还包含了code
  • C#winform导出DataGridView数据到Excel表

    前提 NuGet安装EPPlus 选择合适的能兼容当前 net framwork的版本 主要代码 private void btn export Click object sender EventArgs e SaveFileDialog
  • 在springboot 中配置使用servlet

    文章目录 1 前言 2 servlet 3 springboot配置 4 启动项目 5 UrlMapping设置 6 Filter 7 Listener 8 总结 1 前言 还记得 说到web项目 最早接触的就是servlet 实际上SSH