(二)第一个Servlet
一、预备知识
一、Servlet简介
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。
二、Servlet的运行过程(生命周期)
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
三、Servlet与普通Java类的区别
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
举例:
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
用途:为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。
四、缺省Servlet
如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。 例如:
1 <servlet>
2 <servlet-name>ServletDemo2</servlet-name>
3 <servlet-class>gacl.servlet.study.ServletDemo2</servlet-class>
4 <load-on-startup>1</load-on-startup>
5 </servlet>
6
7 <!-- 将ServletDemo2配置成缺省Servlet -->
8 <servlet-mapping>
9 <servlet-name>ServletDemo2</servlet-name>
10 <url-pattern>/</url-pattern>
11 </servlet-mapping>
当访问不存在的Servlet时,就使用配置的默认Servlet进行处理,如下图所示:
- 在myEclipse创建web project
- 在src包下编写一个java类。
public class MyServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request,HttpServletResponse response){ this.doPost(request, response); } protected void doPost(HttpServletRequest request,HttpServletResponse response){ System.out.println("第一个servlet"); } }
解析: MyServlet这个类要继承HttpServlet,而HttpServlet必须引入外部的jar包,tomcat服务器里有这个包,我们可以引入或者自己下载导入。 继承HttpServlet之后,一般覆盖其中的doGet()和doPost()方法。
3.打开webroot/web-inf里的web.xml,点击source,添加下列:
<servlet> <servlet-name>hello</servlet-name> <servlet-class>myServlet.MyServlet</servlet-class> //创建 myServlet包下的MyServlet类的对象 hello
</servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/servlet</url-pattern> //在地址栏里输入/servlet的时候调用对象hello
</servlet-mapping>
4.配置好xml文件之后可以初步使用了。结果如图:
Servlet基础配置
- 配置:1.windows->proference->java->Build path->user library 引入tomcat里的Servletjar包(把开发包和工具关联起来)
- 特别注意版本问题,
- 把文件部署到服务器的三种方法:
- init() 方法
在 Servlet 的生命期中,仅执行一次 init() 方法。它是在服务器装入 Servlet 时执行的。 可以配置服务器,以在启动服务器或客户机首次访问 Servlet 时装入 Servlet。 无论有多少客户机访问 Servlet,都不会重复执行 init() 。
- service() 方法
service() 方法是 Servlet 的核心。每当一个客户请求一个HttpServlet 对象,该对象的service() 方法就要被调用,而且传递给这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数。 在 HttpServlet 中已存在 service() 方法。缺省的服务功能是调用与 HTTP 请求的方法相应的 do 功能。例如, 如果 HTTP 请求方法为 GET,则缺省情况下就调用 doGet() 。Servlet 应该为 Servlet 支持的 HTTP 方法覆盖 do 功能。因为 HttpServlet.service() 方法会检查请求方法是否调用了适当的处理方法,不必要覆盖 service() 方法。只需覆盖相应的 do 方法就可以了。 - destroy() 方法
destroy() 方法仅执行一次,即在服务器停止且卸装Servlet 时执行该方法。典型的,将 Servlet 作为服务器进程的一部分来关闭。缺省的 destroy() 方法通常是符合要求的,但也可以覆盖它,典型的是管理服务器端资源。例如,如果 Servlet 在运行时会累计统计数据,则可以编写一个 destroy() 方法,该方法用于在未装入 Servlet 时将统计数字保存在文件中。另一个示例是关闭数据库连接。
当服务器卸装 Servlet 时,将在所有 service() 方法调用完成后,或在指定的时间间隔过后调用 destroy() 方法。一个Servlet 在运行service() 方法时可能会产生其它的线程,因此请确认在调用 destroy() 方法时,这些线程已终止或完成。 - 当用户第一次访问servlet的时候,容器会根据xml文件中的<url-patting>创建相应的对象,调用的构造方法肯定是无参的构造方法,可是此时如果我们需要向这个对象提供参数呢?所以java在创建对象即调用无参构造方法之后会自动调用init()方法,参数放在web.xml里。当用户请求请求一个HttpServlet 对象的时候,调用service()方法,判断是get还是post,如果是post则调用doPost()方法。对象创建一段时间后,调用destroy()方法销毁对象。
- 当我们在实际开发的时候,经常改变的常量(比如密码)不能直接写在代码里,否则一旦修改就得修改源代码,可以把这些常量写在配置文件里,然后在我们的源代码读取即可,修改的时候只要修改配置文件就行了。
然后在web.xml配置文件里设置参数:
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>myServlet.MyServlet</servlet-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
解析: 在<servlet></servlet>里配置的参数只能在一个servlet里使用,其他的servlet不能使用。
接着在servlet里获取参数:
public class MyServlet extends HttpServlet { private String charset="UTF-8"; //设置默认值 /** * */ private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request,HttpServletResponse response){ this.doPost(request, response); } protected void doPost(HttpServletRequest request,HttpServletResponse response){ response.setContentType("text/html;charset="+charset); PrintWriter out=null; try { out = response.getWriter(); out.print("你好世界!!"); } catch (IOException e) { e.printStackTrace(); }finally{ out.close(); } } @Override public void init(ServletConfig config) throws ServletException { String tmp=config.getInitParameter("charset"); //获取web.xml中的参数charset并赋给tmp charset=(tmp!=null)?tmp:charset; //如果tmp值不是空的,就把tmp值赋给charset,如果是空的就把默认值charset赋给charset } }
结果:
当我们把web.xml文件里的<param-value>ASCII</param-value>改成这样的时候,结果为:
可以看到我们的配置生效了,以后如果要更改编码只要在xml配置文件修改即可无须修改源代码。
- 注: response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。
- 上例的charset参数只能在一个servlet里使用,而如果一个项目有几十个srevlet每个servlet都要使用到同一个参数,按照上例则需要每个servlet都配置一个参数,这样就太麻烦了,
所以我们可以配置一个“全局参数”,这个参数定义的时候不能放在<servlet></servlet>便签里,要单独定义标签,具体如下:
设置配置文件:
<context-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </context-param> <servlet> <servlet-name>hello</servlet-name> <servlet-class>myServlet.MyServlet</servlet-class> </servlet>
读取参数:
public class MyServlet extends HttpServlet {
private String charset="UTF-8"; //设置默认值
/**
*
*/
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,HttpServletResponse response){
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request,HttpServletResponse response){
response.setContentType("text/html;charset="+charset);
PrintWriter out=null;
try {
out = response.getWriter();
out.print("你好世界!!");
} catch (IOException e) {
e.printStackTrace();
}finally{
out.close();
}
}
@Override
public void init(ServletConfig config) throws ServletException {
//String tmp=config.getInitParameter("charset"); //获取web.xml中的参数charset并赋给tmp
String tmp=config.getServletContext().getInitParameter("charset");
charset=(tmp!=null)?tmp:charset; //如果tmp值不是空的,就把tmp值赋给charset,如果是空的就把默认值charset赋给charset
}
}
结果: