作为Web应用

没有servlet能独立存在。当前现代Web应用中,许多之间都在一起协作共同完成一个目标。


Web容器模型

3.1 对于servlet和ServletContext初始化参数:编写servlet代码访问初始化参数,创建部署描述文件元素来声明初始化参数。

3.2 对于基本的servlet属性作用域(请求、会话和上下文):编写servlet代码来增加、获取和删除属性;给定一种使用场景,明确属性适当地作用域;明确与各个作用域有关的多线程问题。

3.3 描述Web容器请求模型的元素:过滤器、过滤链、请求和响应包装器,以及Web资源(servlet或JSP页面)。

3.4 描述请求、会话和Web应用的Web容器生命周期事件模型;为每个作用域生命周期创建和配置监听者类;创建和配置作用域属性监听者类;给定一个场景,明确要使用的适当的属性监听者。

3.5 描述RequestDispatcher机制;编写servlet代码来创建一个请求分派器;编写servlet代码转发或包含目标资源;明确容器向目标资源提供的额外的请求作用域属性。


不用硬编码写在servlet类中

解决之道分2步:

配置DD文件

<init-param><param-name>adminEmail</param-name><param-value>自己的邮箱</param-value>
</init-param>

在servlet中

getServletConfig().getInitParameter("adminEmail");

这里指出,在servlet初始化(init)之前不能使用servlet初始化参数,因为此时还不是一个“真正的servlet”,并且只初始化一次


ServletConfig的UML


测试ServletConfig

项目路径如下:

DD文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><servlet><servlet-name>BeerParamTests</servlet-name><servlet-class>com.example.TestInitParams</servlet-class><init-param><param-name>adminEmail</param-name><param-value>likewecare@wickedlysmart.com</param-value></init-param><init-param><param-name>mainEmail</param-name><param-value>blooper@wickedlysmart.com</param-value></init-param></servlet><servlet-mapping><servlet-name>BeerParamTests</servlet-name><url-pattern>/Tester.do</url-pattern></servlet-mapping></web-app>

Servlet文件如下:

package com.example;import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;public class TestInitParams extends HttpServlet {public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("test init parameters<br>");java.util.Enumeration e = getServletConfig().getInitParameterNames();while(e.hasMoreElements()){out.println("<br>param name = "+e.nextElement()+"<br>");}out.println("main email is "+getServletConfig().getInitParameter("mainEmail"));out.println("<br>");out.println("admin email is "+getServletConfig().getInitParameter("adminEmail"));}
}

编译连接:

放置部署环境下:

运行结果:


针对应用的初始化参数ServletContext(上下文)

DD文件:

<context-param><param-name>adminEmail</param-name><param-value>clientheaderror@wickedlysmart.com</param-value>
</context-param>

servlet代码:

getServletContext().getInitParameter("adminEmail");

ServletConfig与SevletContext区别

上下文初始化参数是<web-app ···></web-app>的孩子元素,应用于整个Web应用。

Servlet初始化参数是<servlet></servlet>的孩子元素,应用于相应的Servlet。

这样,也说明了每个servlet有一个ServletConfig;每个Web应用有一个ServletContext。

这里注意:分布式应用中,每个JVM都有一个ServletContext


ServletContext的UML


有两种不同方式得到ServletContext

  1. getServletConfig().getServletContext()
  2. this.getServeltContext()

监听者ServletContextListener

在应用为客户提供服务之前运行的一些代码

例如,我们需要一个单独的对象,它能做到:

  • 上下文初始化(应用正在得到部署)时得到通知

    • 从ServletContext得到上下文初始化参数
    • 使用初始化参数查找建立一个数据库连接
    • 把数据库连接存储为一个属性,使得Web应用的各个部分都能访问
  • 上下文撤销(应用取消部署或结束)时得到通知

    • 关闭数据库连接

ServletContextListener的UML


一个简单的ServletContextListener例子(思路)

在这里例子中,我们要把String初始化参数转换为一个真正的对象——一个Dog

Dog例子:

- 监听者对象向ServletContextEvent对象请求应用ServletContext对象的一个引用。
- 监听者使用这个ServletContext引用得到“breed”的上下文初始化参数,这是一个String,表示狗的品种。
- 监听者使用这个狗品种String构造一个Dog对象。
- 监听者使用ServletContext引用在ServletContext中设置Dog属性。
- 这个Web应用的测试servlet从ServletContext得到Dog对象,并调用这个Dog的getBreed()方法。

例子实现

为了方便测试,我们将所有类放置同一包下

开发环境:

Dog类:

package com.example;public class Dog{private String breed;public Dog(String breed){this.breed = breed;}public String getBreed(){return breed;}
}

ServletContextListener类:

package com.example;import javax.servlet.*;public class MyServletContextListener implements ServletContextListener{public void contextInitialized(ServletContextEvent event){ServletContext sc = event.getServletContext();String dogBreed = sc.getInitParameter("breed");Dog d = new Dog(dogBreed);sc.setAttribute("dog",d);}public void contextDestroyed(ServletContextEvent event){// nothing to do here}
}

Servlet类:

package com.example;import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;public class ListenerTester extends HttpServlet{public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException , ServletException{response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("test context attributes set by listener<br>");out.println("<br>");Dog dog = (Dog) getServletContext().getAttribute("dog");if(dog==null)return;out.println("Dog's breed is: " + dog.getBreed());}
}

DD文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><servlet><servlet-name>ListenerTester</servlet-name><servlet-class>com.example.ListenerTester</servlet-class></servlet><servlet-mapping><servlet-name>ListenerTester</servlet-name><url-pattern>/ListenTest.do</url-pattern></servlet-mapping><context-param><param-name>breed</param-name><param-value>Great Dane</param-value></context-param><listener><listener-class>com.example.MyServletContextListener</listener-class></listener></web-app>

部署环境,并且启动tomcat,结果如下:


更多的监听者

监听者接口 场景 事件类型
ServletContextAttributeListener 你想知道一个Web应用上下文中是否增加,删除或替补了一个属性 ServletContextAttributeEvent
HttpSessionListener 你想知道有多少个并发用户。也就是说,你想跟踪活动的会话 HttpSessionEvent
ServletRequestListener 每次请求到来时你都想知道,以便建立日志记录 ServletRequestEvent
ServletRequestAttributeListener 增加,删除或替换一个请求属性时你希望能够知道 ServletRequestAttributeEvent
HttpSessionBindingListener 你有一个属性类,而且你希望这个类型的对象绑定到一个会话或者从会话删除时得到通知 HttpSessionBindingEvent
HttpSessionAttributeListener 增加、删除或替补一个会话属性时你希望能够知道 HttpSessionAttributeEvent
ServletContextListener 你想知道是否创建或撤销了一个上下文 ServletContextEvent
HttpSessionActivationListener 你有一个属性类,而且你希望这个类型的对象在其绑定的会话迁移到另一个JVM时得到通知 HttpSessionEvent

这里注意最后一个不是HttpSessionActivationEvent


属性(attribute)与参数(parameter)

* 属性 参数
类型 应用/上下文、请求、会话 应用/上下文初始化参数、请求参数、Servlet初始化参数
设置方法 setAttribute(String name, Object value) 不能设置应用和Servlet初始化参数,请求可以
返回类型 Object String
获取方法 getAttribute(String name) getInitParameter(String name)

上下文、请求和会话的作用域

上下文:

请求:

会话:

我们指出,上下文是线程不安全的,Session对于同一个客户来说也是线程不安全的


SMT(单例Servlet模型)

解决线程不安全问题,不过影响效率。

2种方法:

  1. 容器创建Servlet实例池(各个实例之间线程不安全,比如实例的属性是不一样的)
  2. 排队(线程安全)

请求属性和请求分派

我们经常向下面这么做:

requset.setAttribute("styles",result);
request.getRequestDispatcher("result.jsp");

RequestDispatcher揭密

RequsetDispatcher的UML

获得RequestDispatcher的两种办法:

  • 从ServletRequest得到RequestDispatcher
  • 从ServletContext得到RequestDispatcher

分派方法:在RequestDispatcher上调用forward()

注意:这里指出,如果已经提交了响应,就不能再转发请求!如下:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{response.setContentType("application/jar");ServletContext ctx = getServletContext();InputStream is = ctx.getResourceAsStream("bookCode.jar");int read = 0;byte[] bytes = new byte[1024];OutputStream os = response.getOutputStream();while((read = is.read(bytes))!=-1){os.write(bytes, 0, read);}os.flush();request.getRequestDispatcher("result.jsp").forward(request, response);os.close;
}

这样会报一个大大的 IIIegalStateException 异常


本章完

Head First JSP---随笔三相关推荐

  1. JSP的“三指六动九内”

    JavaWeb--JSP的"三指六动九内" JSP的基本使用 1. JSP模板元素 网页的静态内容.如html标签 JSP脚本 2. JSP的脚本 2.1.小脚本<% Jav ...

  2. java随笔三,真正的class大总结

    java随笔三:class 一.对象与对象引用 class A{} A pa = new A(); 差不多就是A *pa = new A();显然new的是对象,pa是引用(Java毙了指针,把他换个 ...

  3. JSP实验三(1)request对象的使用

    JSP实验三(1)request对象的使用 文章目录 JSP实验三(1)request对象的使用 一.注册页面(练习html语法) 1 zhuce.html 2 zhece.jsp 3 效果展示 二. ...

  4. JSP的三个编译指令-page,include详解

    JSP的编译指令是通知JSP引擎的消息. 常见的编译指令有三个: page:该指令是针对当前页面的指令. include:用于指定如何包含另一个页面. tablib:用于定义和访问自定义标签. 编译指 ...

  5. Java基础——JSP(三)

    一. JavaBean 是一种特殊的java类,它遵从一定的设计模式,开发工具和其他组件可以根据这种模式来调用javaBean.它是使用一种符合某些命名方法和设计规范的java类. -- 这个类是可序 ...

  6. jsp的三种Scriptlet

    1.什么是Scriptlet: jsp文件中在<%%>之中编写Java代码,这样的操作形式就称为Scriptlet 2.根据作用的不同,Scriptlet分为三种 <%%>:只 ...

  7. jsp随笔-工作使用-直播功能

    1.状态功能 <div class="form-group"> <label for="" class="col-md-3 cont ...

  8. jsp前三章测试改错题

    (选择一项) A: B: C: D: 正确答案是 B ,B/S架构并不是C/S架构的替代品,有些程序例如大型的网络游戏一般使用的是C/S架构. (选择多项) A: B: C: D: 正确答案是 A,C ...

  9. JSP前三章测试改错

    分析:文件.数据库都是持久化保存数据的,所以是正确的,而servletcontext是上下文对象当然也可以.所以正确答案为A 分析: A:判断学员是否手动安装过Tomcat(练习熟练度) B:使学员了 ...

  10. Java EE入门教程系列第二章JSP(三)——JSP指令与动作组件

    2.3 指令与动作组件 2.3.1 page指令 page指令的基本语法为: <%@ page 属性1="属性1的值" 属性2="属性2的值"···%&g ...

最新文章

  1. [导入]C#中实现Socket端口复用
  2. mac下的intellij idea常用快捷键
  3. 第五篇:并发控制-隔离
  4. 半监督分类算法_用图网络进行半监督分类
  5. raid卡组不同raid_RAID有哪几种?有什么区别?
  6. sass笔记-1|Sass是如何帮你又快又好地搞定CSS的
  7. [活动 3.30]MAUI 跨平台应用开发实战
  8. 做旋转铁甲机器人_「铁甲评测」柳工CLG921E视频全面讲解
  9. CloudStack4.10+GlusterFS4.10测试
  10. C语言中二级指针的作用
  11. 一条命令关掉centos所有不必要的服务和端口号
  12. 【Python刷题篇】——Python机器学习-鸢尾花分类
  13. 新商用密码产品认证梳理——标准和材料对比
  14. Windows10系统提示 为了对电脑进行保护,已经阻止此应用(管理员已阻止你运行此应用。有关详细信息,请与管理员联系。)的解决办法
  15. 解决webView不支持网页input type=“file“上传功能。接个文章搜索,自己写的代码,确保可以使用。
  16. Gamma.app:由AI驱动,一种呈现想法的新媒介
  17. 产品经理的六大工作职责
  18. Coders @ Work
  19. Linux centOS 7下安装配置Tomcat
  20. 顶会速递 | ICLR 2020录用论文之自然语言处理篇

热门文章

  1. CSE 5/7350 – Project
  2. 超越村后端开发(3:安装djangorestframework+序列化+API开发前期准备)
  3. 5、【设计模式】单列模式
  4. delphi frame 添加 create onshow 事件
  5. ARC 100 C - Linear Approximation题解---三分法
  6. 117. Populating Next Right Pointers in Each Node II
  7. SQL的OPENROWSET开启和使用方法
  8. ACM题目————次小生成树
  9. Chapter 5. Expressions
  10. 一个初学者困惑的Oracle的认证问题