【J2EE核心开发学习笔记 005】Servlet开发
来源:互联网 发布:测试网络命令 trac 编辑:程序博客网 时间:2024/05/21 17:33
一、Servlet简介
Servlet是sun公司提供的一门用于开发动态web资源的技术。Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。
二、Servlet架构及运行过程。
(1) Servlet架构
使用 Servlet,我们可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。Servlet 在 Web 应用程序中的位置如下。
(2) Servlet运行过程
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
三、Servlet的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的
init() 方法
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化。当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。service() 方法
service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。所以,我们不需要对 service() 方法做任何动作,只需要根据来自客户端的请求类型来重载 doGet() 或 doPost() 即可,doGet() 和 doPost() 方法是每次服务请求中最常用的方法。
doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
四、使用MyEclipse开发Servlet
在MyEclipse中新建一个web project工程,myeclipse会自动创建下图所示目录结构:
4.1 Servlet接口实现类
Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。
HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
4.2 通过MyEclipse创建和编写Servlet
选中bobo.servlet.study包,右键→New→Servlet,如下图所示:
这样,我们就通过MyEclipse帮我们创建好一个名字为ServletDemo1的Servlet,创建好的ServletDemo01里面会有如下代码:
package bobo.servlet.study;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletDemo1 extends HttpServlet {/** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<HTML>");out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");out.println(" <BODY>");out.print(" This is ");out.print(this.getClass());out.println(", using the GET method");out.println(" </BODY>");out.println("</HTML>");out.flush();out.close();}/** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<HTML>");out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");out.println(" <BODY>");out.print(" This is ");out.print(this.getClass());out.println(", using the POST method");out.println(" </BODY>");out.println("</HTML>");out.flush();out.close();}}这些代码都是MyEclipse自动生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>两对标签,这两对标签是配置ServletDemo1的,如下图所示:
这里我们需要注意,由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。 一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
(1) 同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
(2) 我们也可以在 <url-pattern>正则表达式</url-pattern>中使用正则表达式,匹配的原则就是"谁长得更像就找谁"
(3) 如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
(4) 当然在Servlet中存在线程安全问题,即当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。我们可以尝试给Servlet对象加一把锁,保证任何时候都只有一个线程在访问该Servlet对象里面的资源,这样就不存在线程安全问题了,这种做法虽然解决了线程安全问题,但是编写Servlet却万万不能用这种方式处理线程安全问题,假如有10000个人同时访问这个Servlet,那么这10000个人必须按先后顺序排队轮流访问。
然后发布程序到Tomcat上,我们就可以通过浏览器访问ServletDemo1这个Servlet,如下图所示:
五、Servlet开发相关
5.1 通过ServletConfig获取Servlet的初始化参数
我们可以在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。例如
<servlet> <servlet-name>ServletConfigDemo1</servlet-name> <servlet-class>bobo.servlet.study.ServletConfigDemo1</servlet-class> <!-- 配置ServletConfigDemo1的初始化参数 --> <init-param> <param-name>name</param-name> <param-value>DaveBobo</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>123</param-value> </init-param> <init-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> </servlet>当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,我们通过ServletConfig对象就可以得到当前servlet的初始化参数信息。比如
package bobo.servlet.study;import java.io.IOException;import java.util.Enumeration;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletConfigDemo1 extends HttpServlet { private ServletConfig config;//定义ServletConfig对象来接收配置的初始化参数 /** * 当servlet配置了初始化参数后,web容器在创建servlet实例对象时, * 会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时, * 将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以 * 得到当前servlet的初始化参数信息。 */ public void init(ServletConfig config) throws ServletException{ this.config = config; } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取在web.xml中配置的初始化参数 String paramVal = this.config.getInitParameter("name"); response.getWriter().print(paramVal); response.getWriter().print("<hr/>"); //获取所有的初始化参数 Enumeration<String> e = config.getInitParameterNames(); while(e.hasMoreElements()){ String name = e.nextElement(); String value = config.getInitParameter(name); response.getWriter().print(name +"=" + value + "<br/>"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}我们运行结果可以看到
5.2 ServletContext对象开发应用
(1) 多个Servlet通过ServletContext对象实现数据共享
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
例如:ServletContextDemo1和ServletContextDemo2通过ServletContext对象实现数据共享
package bobo.servlet.study;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String data = "DaveBobo";/** * ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时, * 可以通过ServletConfig.getServletContext方法获得ServletContext对象。 */ServletContext context = this.getServletConfig().getServletContext();//获得ServletContext对象context.setAttribute("data", data);//将data存储到ServletContext对象中}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request,response);}}
package bobo.servlet.study;import java.io.IOException;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo2 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();String data = (String) context.getAttribute("data");//从ServletContext对象中取出数据response.getWriter().print("data="+data);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}先运行ServletContextDemo1,将数据data存储到ServletContext对象中,然后运行ServletContextDemo2就可以从ServletContext对象中取出数据了,这样就实现了数据共享,如下图所示:
(2) 获取WEB应用的初始化参数
在web.xml文件中使用<context-param>标签配置WEB应用的初始化参数,如下所示:
<?xml version="1.0" encoding="UTF-8"?><web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <!-- 配置WEB应用的初始化参数 --> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/test</param-value> </context-param> <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>ServletContextDemo3</servlet-name> <servlet-class>bobo.servlet.study.ServletContextDemo3</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletContextDemo3</servlet-name> <url-pattern>/servlet/ServletContextDemo3</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>获取Web应用的初始化参数,代码如下:
package bobo.servlet.study;import java.io.IOException;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo3 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();//获取整个web站点的初始化参数String contextInitParam = context.getInitParameter("url");response.getWriter().print(contextInitParam);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}运行结果
(3) 用servletContext实现请求转发
ServletContextDemo4.java
package bobo.servlet.study;import java.io.IOException;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = "<h1><font color='red'>DaveBobo</font></h1>"; response.getOutputStream().write(data.getBytes()); ServletContext context = this.getServletContext();//获取ServletContext对象 RequestDispatcher rd = context.getRequestDispatcher("/servlet/ServletContextDemo5");//获取请求转发对象(RequestDispatcher) rd.forward(request, response);//调用forward方法实现请求转发 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }}
ServletContextDemo5.java
package bobo.servlet.study;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo5 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getOutputStream().write("servletDemo5".getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doGet(request, response);}}
访问的是ServletContextDemo4,浏览器显示的却是ServletContextDemo5的内容,这就是使用ServletContext实现了请求转发
(4) 利用ServletContext对象读取资源文件
项目目录结构如下:
使用servletContext读取资源文件
package bobo.servlet.study;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.text.MessageFormat;import java.util.Properties;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * 使用servletContext读取资源文件 * * @author DaveBobo * */public class ServletContextDemo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /** * response.setContentType("text/html;charset=UTF-8");目的是控制浏览器用UTF-8进行解码; * 这样就不会出现中文乱码了 */ response.setHeader("content-type","text/html;charset=UTF-8"); readSrcDirPropCfgFile(response);//读取src目录下的properties配置文件 } /** * 通过ServletContext对象读取src目录下的properties配置文件 * @param response * @throws IOException */ private void readSrcDirPropCfgFile(HttpServletResponse response) throws IOException { /** * 通过ServletContext对象读取src目录下的db.properties配置文件 */ InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); Properties prop = new Properties(); prop.load(in); String driver = prop.getProperty("driver"); String url = prop.getProperty("url"); String username = prop.getProperty("username"); String password = prop.getProperty("password"); response.getWriter().println("读取src目录下的db.properties配置文件:<br/>"); response.getWriter().println( MessageFormat.format( "driver={0},url={1},username={2},password={3}", driver,url, username, password)); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}运行结果
另外我们也可以使用类装载器来读取资源文件这里就不介绍了。
(5) 在客户端缓存Servlet的输出
对于不经常变化的数据,在servlet中可以为其设置合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能。例如:
package bobo.servlet.study;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class ServletContextDemo5 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { /** * 设置数据合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能 * 这里是将数据的缓存时间设置为1天 */ response.setDateHeader("expires",System.currentTimeMillis() + 24 * 3600 * 1000);response.getOutputStream().write("servletDemo5".getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doGet(request, response);}}
- 【J2EE核心开发学习笔记 005】Servlet开发
- 【J2EE核心开发学习笔记 011】Struts2常用开发技能
- 【J2EE核心开发学习笔记 009】MyBatis3操作数据库(CURD)
- 【J2EE核心开发学习笔记 006】HTTP协议
- 【J2EE核心开发学习笔记 007】 Cookie Session会话管理
- 【J2EE核心开发学习笔记 001】IO基础
- 【J2EE核心开发学习笔记 002】线程基础
- 【J2EE核心开发学习笔记 003】网络基础
- J2EE开发之servlet
- J2EE Servlet 学习笔记
- 【J2EE核心开发学习笔记 008】JSP的九大内置对象和四个作用域
- 【J2EE核心开发学习笔记 012】Struts2文件的上传与下载
- 《Servlet学习笔记》Servlet开发细节
- J2EE开发学习笔记(4)
- [J2EE学习笔记01]配置标准的J2EE开发环境
- Servlet资源注解(一步一步学习J2EE开发)
- J2EE Servlet 学习笔记2
- J2EE Servlet 学习笔记3
- linux下的tomcat和jdk配置
- Atcoder KUPC2016 E柵 / Fences 最小割
- 电路设计_850和940红外发射管的区别
- Java-IO之BufferedInputStream(缓冲输入流)
- Python——字符串格式化与字符串操作
- 【J2EE核心开发学习笔记 005】Servlet开发
- 利用javaScript做一个简易的图片展示
- Swift学习记录 -- 14.闭包的使用和解决循环引用方法
- Mac上cpu 跑17个卷集层的resent
- 欢迎使用CSDN-markdown编辑器
- Listview 设置不同类型的item
- 算术运算、关系运算
- Android网络开源库-Retrofit(四)文件相关
- android 自定义开关