Servlet:
javax.servlet.Servlet接口
servlet 是运行在服务器端的servlet容器中,需要继承javax.servlet.Servlet接口。
可以在这里查看servlet的文档:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/index.html
这个接口有5个方法:
如下:
void | destroy() |
getServletConfig() | |
java.lang.String | getServletInfo() |
void | init(ServletConfig config) |
void | service(ServletRequest req,ServletResponse res) |
init 方法:
Servlet 实例化后会调用init方法,可以向其传递一个servletConfig对象,这个对象包括了servlet的配置信息。还可以通过ServletConfig对象获取ServletContext对象,来与servlet进行通信。
service方法:
service 方法处理客户的请求,在调用service之前,必须生成 ServletRequest和ServletResponse对象,前者包含了请求信息,后者包括了响应信息。
destroy方法:
当检测到一个servlet 应该从容器中移除的时候,容器就会调用该servlet的destroy方法。在destroy一般做资源清理工作,比如释放数据库连接,容器会等待service中的方法执行完或者超时了再执行destroy方法。
返回初始化时候传递给servlet的配置信息ServletConfig对象
返回该servlet的信息,比如作者,版权等。
ServletRequest
ServletRequest 包含了所有传递给 servlet的参数,
可以在这里查看其文档:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/ServletRequest.html
ServletResponse
ServletResponse 包含了所有servlet传递给客户端的信息
可以在这里查看其文档:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/ServletResponse.html
Servlet的实现
如果直接使用servlet,是很痛苦的事情,javax包中已经有了对servlet的实现。
他们的关系如下图:
GenericServlet
GenericServlet 提供了一个不依赖于协议的sevlet通用实现,它也实现了ServletConfig
接口和init和destory的简单生命周期,另外它实现了log功能。
文档在:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/GenericServlet.html
HttpServlet
HttpServlet 顾名思义,就是支持http协议的servlet,它是GenericServlet的子类,如图所示。
protected void | doDelete(HttpServletRequest req,HttpServletResponse resp) |
protected void | doGet(HttpServletRequest req,HttpServletResponse resp) |
protected void | doHead(HttpServletRequest req,HttpServletResponse resp) |
protected void | doOptions(HttpServletRequest req,HttpServletResponse resp) |
protected void | doPost(HttpServletRequest req,HttpServletResponse resp) |
protected void | doPut(HttpServletRequest req,HttpServletResponse resp) |
protected void | doTrace(HttpServletRequest req,HttpServletResponse resp) |
protected long | getLastModified(HttpServletRequest req) |
protected void | service(HttpServletRequest req,HttpServletResponse resp) |
void | service(ServletRequest req,ServletResponse res) |
Http方法加了
doGet doPost doPut dohead等几个方法,这几个方法都接受ServletRequest req,ServletResponse res这两个参数。并且重载了两个service方法,
其中doGet doPost等方法的参数第二个service方法的参数是一样的。而且抛出的异常都是ServletException。
我们一般使用的时候不用去修改service,只需要覆盖doXXX方法即可。因为调用过程是这样的:
当一个请求进入servlet 首先调用:
void | service(ServletRequest req,ServletResponse res) |
方法,然后从req中使用getMethod
()
方法
取得请求的类型XXX,再根据XXX调用doXXX方法。所以覆盖doXXX方法即可。
文档在:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/http/HttpServlet.html
HttpServletRequest
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/http/HttpServletRequest.html
HttpServletResponse
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/http/HttpServletResponse.html
实例
hello world
在eclipse javaEE下面建立一个dynamic web project。取名servletJspLearn
在 WEB-INFO
下面建立clases 和 lib 文件夹,建立 web.xml文件。
classes 放编译好的.class文件。
lib放需要的库文件
welcome.jsp是jsp文件。
新建helloworld.java servlet
package junjun.chapter6;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class helloworld extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getServletContext().getContextPath());
PrintWriter p = response.getWriter();
p.println("hello world");
p.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
在web.xml中进行配置 servlet
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<servlet>
<servlet-name>helloworld</servlet-name>
<servlet-class>junjun.chapter6.helloworld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloworld</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
其中 <servlet>定义一个servlet :包括名字(servlet-name)和报名.类名(servlet-class)
其中<servlet-mapping>定义了一个路径与一个servlet的映射关系
下面就可以使用
http://localhost:8080/servletJspLearn/hello访问这个servlet了
打印请求信息
/**
* 打印 请求信息
* @author andyWebsense
*
*/
public class OutputInfo extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html;charset=gb2312");
PrintWriter p = response.getWriter();
p.println("<html><head><title> Info table </title></head>");
p.println("<body>");
p.println("<table border = 1 align = center>");
p.println("<caption>headers the server received </caption>");
p.println("<tr><th>header name</th><th>header value<th></th></tr>");
// 打印 请求报头信息
Enumeration<String> headers = request.getHeaderNames();
while(headers.hasMoreElements())
{
String name = headers.nextElement();
String value = request.getHeader(name);
p.println("<tr><td>"+name+"</td><td>"+value+"</td></tr>");
}
// 获取客户端ip
p.println("<tr><td>"+"remove ip"+"</td><td>"+request.getRemoteAddr()+"</td></tr>");
// 获取客户端端口
p.println("<tr><td>"+"remote port"+"</td><td>"+request.getRemotePort()+"</td></tr>");
// 获取服务器ip
p.println("<tr><td>"+"local ip"+"</td><td>"+request.getLocalAddr()+"</td></tr>");
// 获取服务器端口
p.println("<tr><td>"+"local port"+"</td><td>"+request.getLocalPort()+"</td></tr>");
p.println("</table></body></html>");
p.close();
}
}
Servlet 登陆
注意redirect的使用
public class LoginServlet extends HttpServlet
{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html;charset=gb2312");
String name = req.getParameter("user");
String password = req.getParameter("password");
if (name!=null && password!=null
&& name.equalsIgnoreCase("zhangsan") && password.equals("1234"))
{
//sendRedirect 将用户的请求重定向到 success.jsp中
//该方法通过修改HTTP协议的HEADER部分(设置状态代码302,命令浏览器发重新发送请求),对浏览器下达重定向指令的,
//让浏览器对在location中指定的URL提出请求,使浏览器显示重定向网页的内容
resp.sendRedirect("success.jsp");
}
else
{
resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "服务器忙,请稍后登陆");
}
resp.flushBuffer();
}
}
success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>login success</title>
</head>
<body>
<f:view>
welcome here
</f:view>
</body>
</html>
servlet的生命周期
servlet的生命周期是由servlet容器来管理的。
1、加载与实例化
当容器启动时候或者检测到需要实例化Servlet来相应 request请求的时候,由容器创建一servlet,容器是使用反射来创建servlet的,所以不要提供带参数的servlet。
2、初始化
调用servlet的init方法进行初始化,servlet可以使用容器提供的ServletConfig从web应用程序的配置信息(web.xml)中获取初始化信息。如果发生异常,使用ServletException或者UnavailableException通知容器。
3、服务
调用service方法进行请求处理。从ServletRequest获取请求信息,通过ServletResponse设置返回信息,如果发生错误,抛出ServletException或者UnavailableException,如果UnavailableException只是该servlet永久不可用,调用destroy方法,注销这个servlet,如果有请求返回404,资源不可用。如果UnavailableException只是该servlet暂时不可用,返回503服务器忙。
4、服务终止
当容器检测到一个servlet需要从时候,调用destroy方法。
下面是这个过程的时序图
servlet上下文ServletContext
ServletContext表示一个servlet的上下文,servlet在初始化期间(调用init方法时候),向其传递ServletConfig,通过ServletConfig获取servletContext。servletContext代表web服务器中一个已知的应用的根目录,例如: http://localhost:8080/servletJspLearn/login 的上下文被定定位于http://localhost:8080/servletJspLearn所有与/servletJspLearn为路径的请求都是与这个servlet关联的应用程序。
使用ServletContext实现页面访问统计
/**
* 页面访问量统计 使用 ServletContext来保持访问次数
* @author buptjunjun
*
*/
public class CountServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
ServletContext context = this.getServletConfig().getServletContext();
// 从servletContext中取出访问次数
Integer count = (Integer) context.getAttribute("count");
if(count == null)
count = 1;
else
count++;
String user = request.getParameter("user");
response.setContentType("text/html");
PrintWriter p = response.getWriter();
p.println("<html><head><title> "+"page visit statistics"+" </title></head>");
p.println("<body> this page have been visited"+ count +"times </body></html>");
p.close();
// 将访问次数放入servletContext中
context.setAttribute("count", count);
}
}
RequestDispacher控制转发
在web应用中,一般有一个请求转发的控制器(一个servlet),它接受请求,然后将请求转发给其他的servlet,jsp或者html来处理。这就要用到RequestDispacher.
RequestDispacher 是由servlet容器创建,封装一个资源的路径,使用它的forward和include方法可以把请求转发给其他servlet,jsp或者html。
可以在这里看它描述:
http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/RequestDispatcher.html
Rquest定义了两个方法:
Method Summary | |
|
|
|
|
其实从字面意思就可以了解个大概意思了:
forward 是转发的意思,include是包括的意思。
forward是将请求转发给其他资源,自己就不管了,让其他资源去处理请求。
include是将其他资源包含到"我"的页面来。
forward 必须在响应提交到客户端之前调用,在调用forward之后,原先的没有被提交的响应将会被清除。如果响应被提交后调用,就会抛出IllegalStateException。
Include 会将其他请求转发给其他servlet或者jsp等其他资源,但是这些资源的输出将并入原来的servlet中,由原来的servlet做出响应。
例如下面的例子 注意注释
package junjun.chapter6;
import java.io.IOException;
import java.io.PrintWriter;
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;
/**
* 请求转发
* @author andyWebsense
*
*/
public class PortalServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html;charset=gb2312");
PrintWriter p = resp.getWriter();
p.println("<html><head><title> Info table </title></head><body>");
String name = req.getParameter("user");
String password = req.getParameter("password");
if (name!=null && password!=null
&& name.equalsIgnoreCase("zhangsan") && password.equals("1234"))
{
//p.println("<html><head><title> Info table </title></head><body>"); 的输出将保留
将success.jsp输出的内容插入到PortalServlet
//p.println("hello test</body></html>"); 也会输出
//最后输出时 PortalServlet的输出和success.jsp的输出只和
ServletContext context = this.getServletContext();
RequestDispatcher d = context.getRequestDispatcher("/success.jsp");
d.include(req, resp);
}
else
{
// 将请求转发到login2 servlet,对客户端的响应都由login2来处理。
//前面 p.println("<html><head><title> Info table </title></head><body>"); 的输出将会被清掉,
// p.println("hello test</body></html>"); 也不会输出
//最后输出只是login2的输出,portalServlet的输出被清除掉。
ServletContext context = this.getServletContext();
RequestDispatcher d = context.getRequestDispatcher("/login2");
d.forward(req, resp);
}
p.println("hello test</body></html>");
p.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
this.doGet(req, resp);
}
}
sendRedirect和forward的区别
sendRedirect 和forward都可以将请求重定向到另一个资源。但是二者有本质的区别。
简而言之:sendRedirect是在客户端(浏览器)的重定向,forward 是在服务器端的重定向。
sendRedirect
重定向动作(调用sendRedirect方法时候)发生时候,发生重定向的servlet向客户端(浏览器)发送302,告诉浏览器要访问的资源,浏览器发起另一个请求访问该资源。如图所示,其实浏览器发送了两个请求。所以说重定向发生在客户端。
forward
而forward不同,是在服务器端的重定向,重定向动作发生时候(调用forward方法时候),浏览器将ServletRequest和ServletResponse转到另一个资源,如另一个jsp,这个jsp来相应这个请求,在这个过程中,服务器与客户端的连接是没有中断的。所以是在服务器端的重定向。