Servlet技术 - Servlet应用
为什么80%的码农都做不了架构师?>>>
#转发与重定向 浏览器把请求发送给ServletA,ServletA把请求传递给ServletB,由ServletB进行继续处理,最后输出资源响应。
#转发 ##请求转发
- forward
ServletA调用forward方法把请求转发给ServletB - 将当前的request和response对象交给指定的web组件处理
浏览器不知道ServletA转发请求给了ServletB,对于浏览器来说发出一次请求,获取一次响应 - 一次请求,一次响应
请求转发过程中,浏览器URL地址栏不会发生变化
##转发对象
- RequestDispatcher对象
由Servlet容器创建,用来封装一个由路径所标示的服务器资源,该对象有两个比较重要的方法forward方法和include方法,forward方法是指转发,include方法指包含,把请求转发后,原有组件和新组件都输出响应信息。 ###通过两种方式获取转发对象 - 通过
HttpServletRequest
获取 - 通过
ServletContext
获取
##转发实例 ###通过request.getRequestDispatcher 转发路径:注意这里是转发Servlet路径,可以填写绝对路径和相对路径的
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {// 通过request对象获取转发对象RequestDispatcher requestDispatcher = req.getRequestDispatcher("/forwardExample");// 转发requestDispatcher .forward(req, resp);}
通过URL进行访问与测试
http://localhost:8080/web_project_template/forward?user=123
输出结果
Class ServletForward Method init
Class ServletForward Method doGet [request]:org.apache.catalina.connector.RequestFacade@5f36101b
Class ServletForwardExample Method init
Class ServletForwardExample Method doGet [request]:org.apache.catalina.core.ApplicationHttpRequest@51eeeb5b
可以看到实现了转发功能并显示出ServletForwardExample的返回结果
###通过ServletContext获取转发对象 ServletContext有两种方式获取转发对象,通过this.getServletContext().getNamedDispatcher
是需要知道Servlet名称(备注:在web.xml查看)。通过this.getServletContext.getRequestDispatcher
只能够填写绝对路径
// ServletContext可以通过两种方式获取转发对象requestDispatcher = this.getServletContext().getNamedDispatcher("ServletForwardExample");requestDispatcher = this.getServletContext().getRequestDispatcher("/forwardExample");
##用户登录流程 浏览器发送登录请求给服务器,服务器返回登录响应,在登录验证完成之后,我们通常会发现我们的浏览器会跳转到另外的页面。而且浏览器上的地址栏也改变了。这里我们做了一次请求,在我们登录验证完成之后,服务器端向浏览器返回了另外一个URL地址的响应信息。浏览器在接收到该响应信息后,会自动的向服务器请求返回地址,然后服务器端会返回对应的跳转结果。浏览器进入到另外一个页面。
#请求重定向 服务器是希望用户在登录后,进入到用户界面。也就是说服务器端希望ServletA处理结束,ServletB继续为用户服务。
- sendRedirect方法
ServletA调用sendRedirect方法,将客户端的请求重定向到ServletB - 请求重定向:通过response对象发送给浏览器一个新的URL地址,让其重新请求
- 两次请求,两次响应
过程对用户是透明的,浏览器默认把第二次请求做掉了,需要注意,在请求重定向后,浏览器地址栏会发生响应的改变。
##请求重定向实例 可以使用绝对路径,或者相对路径
resp.sendRedirect("redirectExample");
浏览器访问路径
http://localhost:8080/web_project_template/redirect?user=123
Chrome开发者模式,可以看到有两次应答
注意:请求转发是同一个请求对象,只进行一次响应;请求重定向是两次请求,两次响应。如果在跳转中的URL并没有对应的parameter,则获取的值为空。
通过Chrome查看第一次响应的Location内容
###重定向绝对路径问题
resp.sendRedirect("/redirectExample");
如果这样填写重定向的绝对路径,如果使用maven启动,或者在部署时,并不是部署到ROOT。则会发生访问的路径为
http://localhost:8080/redirectExample
而不是,我们所需要的
http://localhost:8080/web_project_template/redirectExample
##转发&重定向总结
- 浏览器地址栏变化
转发地址栏不发生变化,重定向地址栏将会变成重定向的地址 - 请求范围
转发是在同一个web应用中进行转发,而重定向既可以重定向到本web应用,也可以重定向到外部URL。 - 请求过程
请求转发是一次请求一次响应,请求重定向是两次请求两次响应。
#过滤器与监听器
#过滤器
- 过滤请求与响应
- 自定义过滤规则
按照过滤器的规范,编写对应代码 - 用于对用户请求进行预处理,和对请求响应进行后处理的web应用组件
过滤器能够对Servlet的请求和响应对象进行检查和修改,Servlet过滤器本身并不生成请求和响应对象。提供过滤功能,过滤器能够在Servlet调用之前检查Request对象,并能够修改Request header和Request内容,在Servlet被调用之后,能够检查Response对象,修改Response的Header和内容。
##过滤器工作原理
- 1.首先通过客户端,发送原始请求到Servlet容器,由于有过滤器,则请求发送给过滤器
- 2 经过过滤器处理,请求转发给对应的Servlet
- 3 Servlet处理完成后,将原始响应发送给过滤器
- 4 最后由过滤器发送过滤后的响应给客户端
##过滤器应用场景
- 用户认证
过滤非法用户,确定用户有没有登录,是否有权限访问页面。 - 编解码处理
如果我们的请求有乱码的问题,我们可以通过过滤器进行预处理,处理完成后将正确的结果发还给Servlet进行处理 - 数据压缩处理
当我们请求的数据比较,我们可以通过过滤器进行压缩,然后再将数据发到对应的服务端,这样减轻服务端的处理压力
##过滤器生命周期 filter的创建和销毁,同样由Servlet容器负责。Web应用启动的时候,Servlet容器会根据部署描述符的配置,创建filter的实例对象。调用filter的init方法,完成过滤器的初始化。为后续的拦截请求做准备。过滤器在生命周期中只会创建一次,所以init方法只会执行一次。
跟Servlet一样,在部署描述符的filter当中,也可以配置filterconfig的对象,用来存储filter的一些配置信息。在filter完成初始化工作之后,进入正式的过滤操作doFilter方法。这个方法与servlet的service方法类似,完成过滤的实际操作。对每个请求响应做出响应处理。
当客户端请求访问与过滤器相关联的URL时,Servlet过滤器就会执行对应的doFilter方法。我们可以在这个方法当中做前置处理和后置处理。
过滤器当Web应用被移除,或者容器服务重启时,执行destory销毁方法。当Servlet容器卸载掉对应的Filter对象之前,destory方法将会被调用。只执行一次。释放过滤器资源。
##过滤器实例 Servlet部署描述符(web.xml)配置filter,部署描述符当中的Filter对象下的init-param所添加的参数,在TestFilter当中的doFilter方法通过FilterConfig参数传递并使用。
filter-mapping的url-pattern使用规则与servlet一致
<filter><init-param><param-name>filterParam</param-name><param-value>111</param-value></init-param><filter-name>TestFilter</filter-name><filter-class>com.netease.server.example.web.controller.filter.TestFilter</filter-class></filter><filter-mapping><filter-name>TestFilter</filter-name><url-pattern>/hello/world/*</url-pattern></filter-mapping>
创建TestFilter并继承Filter接口
public class TestFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("Class TestFilter Method init");String value = filterConfig.getInitParameter("filterParam");System.out.println("Class TestFilter Method init [filter.config key=filterParam]:" + value);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("Class TestFilter Method doFilter");
// TODO}@Overridepublic void destroy() {System.out.println("Class TestFilter Method destroy");}
登录过的用户,直接跳转,如果没有登录的用户跳转到登录界面
@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {System.out.println("Class TestFilter Method doFilter");// 登录过的用户,直接跳转,如果没有登录的用户跳转到登录界面HttpServletRequest req = (HttpServletRequest) request;HttpSession session = req.getSession();if (session.getAttribute("userName") == null) {HttpServletResponse res = (HttpServletResponse) response;res.sendRedirect("../index.html");} else {chain.doFilter(request, response);}}
**注意:**相对路径../index.html
的..
为返回上一层路径
FilterChain参数,有doFilter方法,主要是把请求向下传递,请求将会传递到下一个过滤器,或者是客户端所请求的Servlet。
当我们没有登录的时候,在浏览器中输入http://localhost:8080/web_project_template/hello/world
会自动跳转登录界面。
登录结束后,当我们再次在浏览器中输入http://localhost:8080/web_project_template/hello/world
会跳转到对应的资源页面。
##过滤器链 我们在Web应用中会有多个filter,这些filter组成filter链。一个请求通过filter-mapping匹配到多个filter,这个时候web服务器就会根据filter在部署描述符中的先后顺序,决定首先调用哪个filter。当第一个filter方法被调用时,servlet容器会创建一个代表filter链的FilterChain对象,传递给Filter的doFilter方法。如果开发者在doFilter方法中,调用了FilterChain对象的doFilter方法。则会传递给下一个Filter或者被调用资源的Servlet对象。
###过滤器链请求过程
- 客户端原始请求首先发送给第一个Filter
- 第一个filter调用了doFilter方法,就会把请求传递给下一个filter,如果第二个filter下还有filter,则继续传递
- 如果没有filter则把过滤后的请求,传递给被调用资源或者servlet对象。
- Servlet处理结果后,把原始响应传送给对应的filter
#监听器 监听器一般理解,有监听器监听信息,有终端接收信息。所以监听器分为两个部分,我们需要监听的东西称之为事件源。另外就是我们的监听器。
监听器首先向某个事件源进行注册,把监听器放到我们需要监听的地方,当事件发生后,事件源将会通知发送到对应的监听器,监听后的信息,我们需要进行相应的处理。
##定义
- 监听事件发生,在事件发生前后能够做出响应处理的web应用组件
这里我们需要注意的是,Servlet监听器注册,不是注册到事件源上,而是由Servlet容器负责注册。开发人员只需要在部署描述符中进行配置,然后servlet容器就会自动的把对应的监听器注册到对应的事件源中。
##监听器分类 Listener按照监听对象进行总体划分,还可以继续划分
- 监听应用程序环境(ServletContext)
- ServletContextListener
对ServletContext对象创建销毁进行监听
- ServletContextListener
- ServletContextAttributeListener
对ServletContext属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
- ServletContextAttributeListener
- 监听用户请求对象(ServletRequest)
- ServletRequestListener
对ServletRequest对象创建销毁进行监听
- ServletRequestListener
- ServletRequestAttributeListener
对ServletRequest属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
- ServletRequestAttributeListener
- 监听用户会话对象(HTTPSession)
- HttpSessionListener
对HttpSession对象创建销毁进行监听
- HttpSessionListener
- HttpSessionAttributeListener
对HttpSession属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
- HttpSessionAttributeListener
- HttpSessionActivationListener
监听Session在持久化时,磁盘或者从磁盘中从新加载到jvm中,触发的监听器。
- HttpSessionActivationListener
- HttpSessionBindingListener
在Session对象进行调用attribute方法和removeattribute方法时进行调用。
- HttpSessionBindingListener
##监听器的应用场景
- 应用统计
对用户登录进行统计,每个用户对应一个session,所以我们可以通过监听器对一个站点用户登录进行统计。 - 任务触发
比如招聘系统中,发现招聘者的状态发生了变化,举例:面试者的状态是面试成功,则给这个应聘者发送邮件通知。 - 业务需求
##监听器启动顺序 监听器的启动顺序与过滤器是一致的,在部署描述符中出现的越靠前,我们就会 越早的进行注册(初始化)
##监听器、过滤器、Servlet启动顺序 先创建监听器、在创建过滤器、最后创建Servlet
##监听器实例 创建监听器
public class TestListener implements HttpSessionAttributeListener,ServletContextListener, ServletRequestListener {// ServletRequestListener@Overridepublic void requestDestroyed(ServletRequestEvent sre) {System.out.println("listener: request destroy");}@Overridepublic void requestInitialized(ServletRequestEvent sre) {System.out.println("listener: request init");}// ServletContextListener@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("listener: context init");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("listener: context destroy");}// HttpSessionAttributeListener@Overridepublic void attributeAdded(HttpSessionBindingEvent event) {System.out.println("listener: session attribute added.");}@Overridepublic void attributeRemoved(HttpSessionBindingEvent event) {System.out.println("listener: session attribute removed");}@Overridepublic void attributeReplaced(HttpSessionBindingEvent event) {System.out.println("listener: session attribute replaced");}}
在对应的部署描述符中配置
<listener><listener-class>com.netease.server.example.web.controller.listener.TestListener</listener-class></listener>
课程提供的代码修复BUG后的打印输出(该BUG在使用session前就把session注销了)。
listener: context init
Class TestFilter Method init
Class TestFilter Method init [filterconfig key=filterParam]:111
init /hello/*
init /hellolistener: request init
listener: request destroy
listener: request init
listener: request destroy
listener: request init
init /hello/world
Class TestFilter Method doFilter
service method
doGet method
listener: request destroy
listener: request init
second login: 123
listener: session attribute removed
listener: session attribute added.
listener: request destroy
#Servlet并发处理 使用应用开发过程中,多个客户端同时请求同一Servlet。
##线程模型
- 1 客户端发送请求给Servlet容器
- 2 Servlet容器,首先把请求传递给调度器,由调度器统一的进行请求派发。
- 3 调度器会从Servlet容器中的线程池中,选取一个工作组线程 线程池,然后把请求派发给该线程,然后由该线程执行servlet的service方法。
- 4 同时,如果客户端发送第二份请求时,调度器会选取另外一个工作组线程,来服务这个新的请求。如果发现同一servlet收到多个请求,service方法将会在多线程中并发执行。 当线程使用完毕后,会把线程在放回线程池中。
- 5 如果现在线程池中的线程都在服务,如果这时有新的请求,一般情况下进行排队处理。
- 6 Servlet容器可以配置最大请求数量,超过这个数量,Servlet容器会直接拒绝这个请求。
##Servlet并发处理
- 单实例
我们知道Servlet只会初始化一次,只调用一次init方法。也就是说在整个Servlet中只会有一个Servlet对象,不管我们有多少请求,只针对同一Servlet对象实例。 - 多线程
请求处理由多个工作线程进行处理,同时请求线程数量的大小,由线程池的配置决定 - 线程不安全
默认没有加锁操作,则多个线程同时对Servlet的属性进行变更,发生不安全
##Servlet线程安全
变量的线程安全
- 参数变量本地化 - 尽量使用局部变量
- 使用同步块synchronized - 进行加锁处理
加锁时,我们需要注意,尽量缩小synchronized的代码范围,不要在Servlet上增加这个关键字,对性能损耗大
- 使用同步块synchronized - 进行加锁处理
属性的线程安全
- ServletContext线程不安全
可以多线程同时读写ServletContext属性的
- ServletContext线程不安全
- HttpSession理论上线程安全 - 实际不安全
当发生同一浏览器,打开多个标签页,同时多次访问Servlet时,会启动多线程对Servlet进行使用。则会对同一HttpSession进行操作,导致线程不安全。
- HttpSession理论上线程安全 - 实际不安全
- ServletRequest线程安全
每一个工作线程只对应一个ServletRequest,则线程安全
- ServletRequest线程安全
避免在Servlet中创建线程
多个Servlet访问外部对象加锁
Servlet安全问题主要由于使用实例变量,尽量避免使用实例变量。如果在程序设计中无法避免使用实例变量,则使用同步的操作来保护我们需要使用的实例变量,为了保证系统性能。注意同步的范围。
##Servlet线程安全实例 ###Servlet不安全实例 人为制造不安全的Servlet
public class ConcurrentServlet extends HttpServlet {String name;@Overridepublic void init() throws ServletException {System.out.println("Class ConcurrentServlet Method init");super.init();}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {System.out.println("Class ConcurrentServlet Method doGet");// synchronized (this) {// 从URL获取username存放在属性中name = req.getParameter("username");PrintWriter out = resp.getWriter();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}out.println("username: " + name);
// }}@Overridepublic void destroy() {System.out.println("Class ConcurrentServlet Method destroy");super.destroy();}
}
部署描述符(web.xml)配置
<!-- Concurrent Servlet --><servlet><servlet-name>ConcurrentServlet</servlet-name><servlet-class>com.netease.server.example.web.controller.ConcurrentServlet</servlet-class></servlet><servlet-mapping><servlet-name>ConcurrentServlet</servlet-name><url-pattern>/concurrent</url-pattern></servlet-mapping>
首先测试的URL:http://localhost:8080/web_project_template/concurrent?username=ddd
等待5秒后打印了ddd,Chrome开发者模式:
我们在先访问http://localhost:8080/web_project_template/concurrent?username=ddd
,再快速访问(5秒内,实际并发远比这个时间小的多)http://localhost:8080/web_project_template/concurrent?username=aaa
,Chrome开发者模式:
###Servlet修改成为安全实例 添加synchronized同步块进行处理
synchronized (this) {
}
Servlet部分代码
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {System.out.println("Class ConcurrentServlet Method doGet");synchronized (this) {// 从URL获取username存放在属性中name = req.getParameter("username");PrintWriter out = resp.getWriter();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}out.println("username: " + name);}}
Chrome测试结果:
我们可以看到,优先访问的ddd,能够按照正确的时间进行返回,并返回正确的数据内容。
我们也可以看到aaa能够正确返回数据,但是由于添加了同步锁,导致需要之前的同步锁执行结束后,才能够执行当前操作内容,则耗时延长。
转载于:https://my.oschina.net/hava/blog/744367
Servlet技术 - Servlet应用相关推荐
- Java Servlet 技术简介
开始之前 关于本教程 在您最喜欢的 Web 浏览器中,您所阅读的页面是如何出现的呢?当登录到您最喜欢的 Web 站点时,该 Web 站点如何知道登录的用户是您?而 Web 零售商又如何接受您的在线订购 ...
- JSP+JavaBean+Servlet技术(MVC模型)
一,Servlet开发 用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这 ...
- Servlet技术简介与编写、编译Servlet程序
1.Servlet技术简介 Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的WEB服务器端编程技术,主要用于在WEB服务器端获得客户端的访问请求信息和动态生成 ...
- Java Servlet技术
Java Servlet技术 Stephanie Bodoff 当Web刚开始被用来传送服务时,服务提供者就已经意识到了动态内容的需要.Applet是为了实现这个目标的一种最早的尝试,它主要关注使用客 ...
- java Servlet技术·笔记
Servlet基础 Servlet技术简介 Servlet是一种独立于平台和协议的服务器端的java技术,可以用来动态的生成Web界面.Servlet具有非常好的可移植性.强大的功能.更少的投资.更高 ...
- JSP程序设计实训(十一)——JSP与Servlet技术(一)
JSP与Servlet技术 一.Servlet 基础知识 Servlet 是 Java Web 应用程序中的组件技术,是运行在服务器端的 Java 应用程序,实现与 JSP 类似的功能.Servlet ...
- java第八章习题,第八章 Servlet技术习题
第八章 Servlet技术 一.选择题 1.下面对Servlet.Applet的那一项描述错误?( ) A)Servelt与Applet相对应 B)Applet运行在客户端浏览器 C)Servlet运 ...
- Java Web学习笔记 3 深入Servlet技术
第3章 深入Servlet技术 请求-响应模式就是典型的Web应用程序访问过程,Java Web应用程序中,处理请求并发送响应的过程是由一种叫做Servlet的程序来完成的. 请求request,响应 ...
- HTTP协议和Servlet技术
一.HTTP协议 1.HTTP协议介绍 IP.端口.协议(TCP和UDP).Socket编程. HTTP协议:属于应用层的协议,底层使用的依然是TCP. HTTP:超文本传输协议.主要应用在互联网中. ...
- 使用JSP/Servlet技术开发新闻发布系统
第一章:动态网页开发基础 动态网页:是指在 服务器端运行的,使用程序语言设计的交互式网页,它们会根据某种条件的变化,返回不同的网页内容 动态网页需要使用服务器端的脚本语言,例如 ...
最新文章
- linux正则表达式sed
- PL/SQL Developer下设置“长SQL自己主动换行”
- Codeforces Beta Round #11 B. Jumping Jack 思维
- 22Exchange Server 2010跨站点部署-邮件流测试及重定向
- 【EMNLP2020】“自言自语”来实现无监督常识问答
- 汽车行业如何进行数字化转型
- Java 设计模式 Factory Method 工厂方法 模式
- axure share联网失败
- springboot集成ureport2
- Arduino 控制的双足机器人
- android auto 墙纸,AA壁纸(Android Auto车载系统壁纸)
- springboot整合腾讯云短信服务
- c语言反步法编程,CCM模式下Boost电路的反步法非线性控制与仿真.pdf
- java计算机毕业设计高校防疫物资管理系统MyBatis+系统+LW文档+源码+调试部署
- 快递100企业版接口(API)实时查询、订阅推送、云打印、电子面单实现.Net版
- 计算机中主频的定义,计算机的主频指的
- html字体文件过大导致加载缓慢如何解决?
- Learning to Rank(LTR)
- 做母婴微商怎么线上引流?做母婴产品如何线上引流?
- echarts之 数据可视化简单页面模板
热门文章
- kafka 查看待消费数据_通过Kafka Connect进行数据迁移
- java change方法作用_程序员必看之Java中方法的参数传递问题
- for...in、for...of、forEach()有什么区别
- SpringBoot(十七)_springboot跨域处理
- abrt-hook-ccpp: Saved core dump of pid 12224导致dn挂掉问题
- Cisco交换机设备配置镜像端口
- Java并发系列—并发编程基础
- IdentityServer的基本概念与特性
- 大B与小b的区别(Bps与bps)
- linux 修改默认语言