首页 > 代码库 > Servlet学习应该注意的几点

Servlet学习应该注意的几点

一、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="http://www.mamicode.com/">
    
    <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="http://www.mamicode.com/styles.css">
    -->
  </head>
  
  <body>
    <a href="http://www.mamicode.com/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="http://www.mamicode.com/">
    
    <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="http://www.mamicode.com/styles.css">
    -->
  </head>
  
  <body>
  <%
  application.setAttribute("name", "小帅哥");
   %>
    <a href="http://www.mamicode.com/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)可以实现非项目目录的跳转。

Servlet学习应该注意的几点