一、Servlet生命周期(即运行过程)
(1)初始阶段,调用init()方法
(2)响应客户请求阶段,调用service()方法。由service()方法根据提交方式不同执行doGet()或doPost()方法,其中service()方法判断了到底执行doGet()还是doPost()方法。
(3)终止阶段,调用destroy()方法。(服务器关闭)
Servlet生命周期中需要注意一下几点:
1)Servlet是长期贮存内存中的,当Servlet实例加载后,Servlet对象是长期保存在服务器内存中的。
2)Servlet被装载后,Web容器创建一个Servlet实例并且调用Servlet的init()方法进行初始化。在Servlet的整个生命周期内,init()方法只被调用一次。而service()方法在每次客户端请求的时候都会调用。
3)HttpServlet中有两个Service()方法,HttpServlet中两个service()方法的区别:
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException { // TODO Auto-generated method stub super.service(arg0, arg1); }
protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { // TODO Auto-generated method stub super.service(arg0, arg1); }
A:其中第一种方法是由tomcat自动调用,它将接收的客户端请求转交给HttpServlet中的第二个service()方法,此保护类行的service()方法再把请求分发给doPost()、doGet()方法进行下一步处理。
B:HttpServlet类继承自GenericServlet,HttpServletRequest和HttpServletResponse分别继承自ServletRequest,ServletResponse,简单说,就是第一个方法是HttpServlet的,第二个方法是GenericServlet的,HttpServlet因为继承GenericServlet,所以继承了这个service()方法。
二、Servlet与九大内置对象
Servlet中如何获取JSP的九大内置对象
JSP对象 | 怎样获得 | 作用域 |
out | response.getWriter() | page |
request | service方法中的request参数 | request |
response | service方法中的response参数 | response |
session | request.getSession()函数 | session |
application | this.getServletContext()函数 | Application |
exception | new Throwable() | page |
page | this | page |
pageContext | new pageContext() | page |
config | this.getSerletConfig()函数 | page |
将这九大对象分为
1、out对象和session对象
out对象是通过service()中的response的getWriter()方法获得,而response.getWriter()的返回的是PrintWriter类对象,而out对象是JspWriter类的实例,我们不妨对比一下两个类的方法。不难发现两个类都主要以print()方法为主。
session对象是通过service()中的request的getSession()方法获得,返回的对象就是对应了session实例。
代码示例(以out对象举例):
index.jsp代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <a href="Servlets/ServletDemo1"><h1>测试servletDemo1 servlet</h1></a> </body> </html>
servletDemo1.java代码
package Servlets; import java.io.IOException; import java.io.PrintWriter;import javax.el.ELContext; import javax.servlet.Servlet;import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.JspWriter;public class ServletDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //resp.setHeader("Content-type", "text/html;charset=gbk");
//resp.setCharacterEncoding("gbk");
System.out.println("测试ServletDemo1 doGet方法成功!"); PrintWriter out=resp.getWriter(); StringBuffer bf=new StringBuffer("<h1>这里是ServletDemo1 servlet!</h1>"); out.print(bf); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
运行结果截图:
分析:绿色背景的代码实现了在servlet中获取out对象,并进行相应操作。但是我们发现通过out对象打印输出的汉字出现了乱码。
关于Servlet中的printWriter中文乱码的问题:
先分析原因:首先我们应该了解servlet中的两个参数request和response分别用来存储客户端发送的请求、储存服务器端返回的数据,而不管是储存还是取出都涉及到重新编码解析的问题,在这个过程如果存储和取出时使用的编码方式不同,势必会导致乱码。printWriter对象是通过response参数调用getWriter()函数获得的,作为响应的信息会在响应存储的时候进行编码的相关操作,而sun公司使用的码表是ISO8859-1之类的码表,而当浏览器显示响应结果时,也会去查码表,而中文的windows下的浏览器使用的一般是gbk或者gb2312,这样两次编码就不同。
解决方法:(两种)
(1)doxxx()方法中添加:response.setCharacterEncoding("gbk");
(2)doxxx()方法中添加:response.setHeader("content-type","text/html;charset=gbk");
上面代码中蓝色部分就是解决方法示例:
运行之后的结果截图:
当然,通过request的getSession()方法获得的session对象对于中文字符也可能出现乱码的问题,我们也可以通过添加:request.setCharaterEncoding("utf-8/gbk");
2、request对象和response对象
request和response对象都是通过service()方法传进的参数获得的,并且这两个参数直接被传入doGet()和doPost()的参数中。
public void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { // TODO Auto-generated method stub super.service(arg0, arg1); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); }
3、page对象、config对象和application对象
page对象代表了JSP转译的servlet实例对象,而在继承HttpServlet类的自定义Servlet类中,其当前实例对象在类中的表达,很明显使用this。所以page对象对应this完美。
config对象其实是通过自定义Servlet类的getSerletConfig()方法获取,自定义Servlet类继承自HttpServlet类,而getServletConfig()方法是HttpServlet类继承自其父类GenericServlet类而来,返回类型为ServletConfig对应了config的类。既然是调用其自定义Servlet类本身的getServletConfig()方法,则调用的写法应该是:this.getServletConfig();
application对象其实是通过自定义Servlet类的getSerletcontext()方法获取,自定义Servlet类继承自HttpServlet类,而getServletContext()方法是HttpServlet类继承自其父类GenericServlet类而来,返回类型为ServletContext对应了application的类。既然是调用其自定义Servlet类本身的getSerletcontext()方法,则调用的写法应该是:this.getSerletcontext()。
代码演示:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <% application.setAttribute("name", "小帅哥"); %> <a href="Servlets/ServletDemo1"><h1>测试servletDemo1 servlet</h1></a> </body> </html>
package Servlets; import java.io.IOException; import java.io.PrintWriter; import java.net.URLDecoder; import java.util.Enumeration; import javax.el.ELContext; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.el.ExpressionEvaluator; import javax.servlet.jsp.el.VariableResolver; public class ServletDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("content-type", "text/html;charset=gbk"); ServletConfig sc=this.getServletConfig(); Enumeration e=sc.getInitParameterNames(); ServletContext application= this.getServletContext(); String name=(String)application.getAttribute("name"); PrintWriter out=resp.getWriter(); out.print("<h2>name:"+name+"</h2>"); out.print("<h1>初始化的参数名:</h1>"); if(e.hasMoreElements()){ out.print(e.nextElement()+" "); }else{ out.print("该Servlet没有初始化参数!"); } //req.getRequestDispatcher("/index1.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
运行结果截图:
4、pageContext对象和exception对象
pageContex是通过在Servlet中通过构造起自己构造的,构造的方法是:PageContext pc=new pageContext(),但是pageContext类是抽象类,通过直接new的方式可以获得pageContext对象,但是其中的方法需要覆盖重写才有意义,而重写的,里面的方法的实现大多都需要借助于其他内置对象,pageContext是一个集大成者的内置对象,他的出现就是能实现,一个内置对象能够访问其他内置对象。
PageContext pc=new PageContext() { @Override public void setAttribute(String arg0, Object arg1, int arg2) { // TODO Auto-generated method stub } @Override public void setAttribute(String arg0, Object arg1) { // TODO Auto-generated method stub } @Override public void removeAttribute(String arg0, int arg1) { // TODO Auto-generated method stub } @Override public void removeAttribute(String arg0) { // TODO Auto-generated method stub } @Override public VariableResolver getVariableResolver() { // TODO Auto-generated method stub return null; } @Override public JspWriter getOut() { // TODO Auto-generated method stub return null; } @Override public ExpressionEvaluator getExpressionEvaluator() { // TODO Auto-generated method stub return null; } @Override public ELContext getELContext() { // TODO Auto-generated method stub return null; } @Override public int getAttributesScope(String arg0) { // TODO Auto-generated method stub return 0; } @Override public Enumeration<String> getAttributeNamesInScope(int arg0) { // TODO Auto-generated method stub return null; } @Override public Object getAttribute(String arg0, int arg1) { // TODO Auto-generated method stub return null; } @Override public Object getAttribute(String arg0) { // TODO Auto-generated method stub return null; } @Override public Object findAttribute(String arg0) { // TODO Auto-generated method stub return null; } @Override public void release() { // TODO Auto-generated method stub } @Override public void initialize(Servlet arg0, ServletRequest arg1, ServletResponse arg2, String arg3, boolean arg4, int arg5, boolean arg6) throws IOException, IllegalStateException, IllegalArgumentException { // TODO Auto-generated method stub } @Override public void include(String arg0, boolean arg1) throws ServletException, IOException { // TODO Auto-generated method stub } @Override public void include(String arg0) throws ServletException, IOException { // TODO Auto-generated method stub } @Override public void handlePageException(Throwable arg0) throws ServletException, IOException { // TODO Auto-generated method stub } @Override public void handlePageException(Exception arg0) throws ServletException, IOException { // TODO Auto-generated method stub } @Override public HttpSession getSession() { // TODO Auto-generated method stub return null; } @Override public ServletContext getServletContext() { // TODO Auto-generated method stub return null; } @Override public ServletConfig getServletConfig() { // TODO Auto-generated method stub return null; } @Override public ServletResponse getResponse() { // TODO Auto-generated method stub return null; } @Override public ServletRequest getRequest() { // TODO Auto-generated method stub return null; } @Override public Object getPage() { // TODO Auto-generated method stub return null; } @Override public Exception getException() { // TODO Auto-generated method stub return null; } @Override public void forward(String arg0) throws ServletException, IOException { // TODO Auto-generated method stub } };
exception对象是一个异常对象,当一个JSP页面发生异常时就会产生这个对象,这个对象在Servlet中对应着Throwable类,调用的方法是:Throwable tb=new Throwable();而Throwable类的子类有Exception。几乎不使用这个。
三、Servlet路径跳转(假设在index.jsp页面进行跳转)
Servlet中有两种方式获得转发对象(RequestDispatcher):一种是通过HttpServletRequest的getRwquestDispatcher()方法获得,一种是通过ServletContext的getRequestDispatcher()方法获得。重定向的方法只有一种:HttpServletResponse的sendRedirect()方法。这三种方法的参数都是一个URL形式的字符串,但在使用相对路径或绝对路径上有所区别。
1、HttpServletResponse.sendRedirect(String):
(1)相对路径:
response.sendRedirect("index1.jsp");
(2)绝对路径:
response.sendRedirect("/index1.jsp"); 其中"/"表示是项目根目录
response.sendRedirect(request.getContextPath()+"/index.jsp"); request.getContextPath()获得项目的根目录路径
(3)其他Web应用:
response.sendRedirect("http://www.baidu.com");
2、HttpServletRequest.getRequestDispatcher(String)
(1)相对路径:
HttpServletRequest.getRequestDispacher("../index1.jsp").forward(request,response); 其中“../”表明返回上层目录
HttpServletRequest.getRequestDispacher("index1.jsp").forward(request,response);
(2)绝对路径:
HttpServletRequest.getRequestDispacher("/index1.jsp").forward(request,response); 其中“/”表示根目录路径
HttpServletRequest.getRequestDispacher(request.getContextPath()+"/index1.jsp").forward(request,response); request.getContextPath()获得项目的根目录路径
3、ServletContext.getRequestDispatcher():
(1)绝对路径:
ServletContext.getRequestDispatcher("/index1.jsp").forward(request,response); 其中“/”表示根目录路径
注意:HttpServletRequest.getRequestDispatcher(String)和ServletContext.getRequestDispatcher()的区别,其中ServletContext.getRequestDispatcher():只能使用绝对路径传值URL,且绝对路径必须是以"/"开头,其他都不行。而三种页面跳转只有HttpServletResponse.sendRedirect(String)可以实现非项目目录的跳转。