为什么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对象创建销毁进行监听
    • ServletContextAttributeListener
      对ServletContext属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
  • 监听用户请求对象(ServletRequest)
    • ServletRequestListener
      对ServletRequest对象创建销毁进行监听
    • ServletRequestAttributeListener
      对ServletRequest属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
  • 监听用户会话对象(HTTPSession)
    • HttpSessionListener
      对HttpSession对象创建销毁进行监听
    • HttpSessionAttributeListener
      对HttpSession属性监听器,当这些对象对应的属性有增删改的变化的时候,这些监听器就会被触发。
    • HttpSessionActivationListener
      监听Session在持久化时,磁盘或者从磁盘中从新加载到jvm中,触发的监听器。
    • HttpSessionBindingListener
      在Session对象进行调用attribute方法和removeattribute方法时进行调用。

##监听器的应用场景

  • 应用统计
    对用户登录进行统计,每个用户对应一个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上增加这个关键字,对性能损耗大
  • 属性的线程安全

    • ServletContext线程不安全
      可以多线程同时读写ServletContext属性的
    • HttpSession理论上线程安全 - 实际不安全
      当发生同一浏览器,打开多个标签页,同时多次访问Servlet时,会启动多线程对Servlet进行使用。则会对同一HttpSession进行操作,导致线程不安全。
    • 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应用相关推荐

  1. Java Servlet 技术简介

    开始之前 关于本教程 在您最喜欢的 Web 浏览器中,您所阅读的页面是如何出现的呢?当登录到您最喜欢的 Web 站点时,该 Web 站点如何知道登录的用户是您?而 Web 零售商又如何接受您的在线订购 ...

  2. JSP+JavaBean+Servlet技术(MVC模型)

    一,Servlet开发 用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这 ...

  3. Servlet技术简介与编写、编译Servlet程序

    1.Servlet技术简介 Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的WEB服务器端编程技术,主要用于在WEB服务器端获得客户端的访问请求信息和动态生成 ...

  4. Java Servlet技术

    Java Servlet技术 Stephanie Bodoff 当Web刚开始被用来传送服务时,服务提供者就已经意识到了动态内容的需要.Applet是为了实现这个目标的一种最早的尝试,它主要关注使用客 ...

  5. java Servlet技术·笔记

    Servlet基础 Servlet技术简介 Servlet是一种独立于平台和协议的服务器端的java技术,可以用来动态的生成Web界面.Servlet具有非常好的可移植性.强大的功能.更少的投资.更高 ...

  6. JSP程序设计实训(十一)——JSP与Servlet技术(一)

    JSP与Servlet技术 一.Servlet 基础知识 Servlet 是 Java Web 应用程序中的组件技术,是运行在服务器端的 Java 应用程序,实现与 JSP 类似的功能.Servlet ...

  7. java第八章习题,第八章 Servlet技术习题

    第八章 Servlet技术 一.选择题 1.下面对Servlet.Applet的那一项描述错误?( ) A)Servelt与Applet相对应 B)Applet运行在客户端浏览器 C)Servlet运 ...

  8. Java Web学习笔记 3 深入Servlet技术

    第3章 深入Servlet技术 请求-响应模式就是典型的Web应用程序访问过程,Java Web应用程序中,处理请求并发送响应的过程是由一种叫做Servlet的程序来完成的. 请求request,响应 ...

  9. HTTP协议和Servlet技术

    一.HTTP协议 1.HTTP协议介绍 IP.端口.协议(TCP和UDP).Socket编程. HTTP协议:属于应用层的协议,底层使用的依然是TCP. HTTP:超文本传输协议.主要应用在互联网中. ...

  10. 使用JSP/Servlet技术开发新闻发布系统

               第一章:动态网页开发基础  动态网页:是指在 服务器端运行的,使用程序语言设计的交互式网页,它们会根据某种条件的变化,返回不同的网页内容 动态网页需要使用服务器端的脚本语言,例如 ...

最新文章

  1. linux正则表达式sed
  2. PL/SQL Developer下设置“长SQL自己主动换行”
  3. Codeforces Beta Round #11 B. Jumping Jack 思维
  4. 22Exchange Server 2010跨站点部署-邮件流测试及重定向
  5. 【EMNLP2020】“自言自语”来实现无监督常识问答
  6. 汽车行业如何进行数字化转型
  7. Java 设计模式 Factory Method 工厂方法 模式
  8. axure share联网失败
  9. springboot集成ureport2
  10. Arduino 控制的双足机器人
  11. android auto 墙纸,AA壁纸(Android Auto车载系统壁纸)
  12. springboot整合腾讯云短信服务
  13. c语言反步法编程,CCM模式下Boost电路的反步法非线性控制与仿真.pdf
  14. java计算机毕业设计高校防疫物资管理系统MyBatis+系统+LW文档+源码+调试部署
  15. 快递100企业版接口(API)实时查询、订阅推送、云打印、电子面单实现.Net版
  16. 计算机中主频的定义,计算机的主频指的
  17. html字体文件过大导致加载缓慢如何解决?
  18. Learning to Rank(LTR)
  19. 做母婴微商怎么线上引流?做母婴产品如何线上引流?
  20. echarts之 数据可视化简单页面模板

热门文章

  1. kafka 查看待消费数据_通过Kafka Connect进行数据迁移
  2. java change方法作用_程序员必看之Java中方法的参数传递问题
  3. for...in、for...of、forEach()有什么区别
  4. SpringBoot(十七)_springboot跨域处理
  5. abrt-hook-ccpp: Saved core dump of pid 12224导致dn挂掉问题
  6. Cisco交换机设备配置镜像端口
  7. Java并发系列—并发编程基础
  8. IdentityServer的基本概念与特性
  9. 大B与小b的区别(Bps与bps)
  10. linux 修改默认语言