目录

前言:

一、Servlet简介

二、生命周期

三、Servlet实例

四、Servlet表单数据

五、客户端HTTP请求。

六、Servlet服务器HTTP响应

七、Servlet HTTP状态码

八、编写过滤器

九、Servlet异常处理

十、Cookie处理

十一、Session跟踪

十二、Servlet数据库访问

十三、Servlet文件上传

十四、Servlet处理日期

十五、网页重定向

十六、Servlet点击计数器

十七、Servlet自动刷新页面

十八、发送电子邮件

十九、Servlet包

二十、调试

二十一、国际化

JSP教程

一、JSP简介

二、开发环境搭建

三、JSP结构

四、JSP生命周期

五、JSP语法

六、JSP指令

七、JSP动作元素

八、JSP隐式对象

九、JSP客户端请求

十、服务器响应

十一、JSP标准标签库(JSTL)

十二、JavaBean

十三、JSP自定义标签

十四、表达式语言

十五、JSP异常处理

十六、调试、国际化:与servlet一致。

后记:


前言:

     Servlet为创建基于web的应用程序提供了组件、独立于开发的平台,可以不受CGI程序(公共网关接口(Common Gateway Interface,CGI))的性能限制。Servlet有权限访问所有的javaAPI,包括访问企业级数据库的JDBC API。


一、Servlet简介

     Java Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。

     使用Servlet,你可以收集来自网页表单的用户输入,呈现来自数据库或其他源的记录,还可以动态创建网页。

     Java Servlet通常情况下与使用CGI实现的程序可以达到异曲同工的效果。但是相比CGI,Servlet有以下优势:

  • 性能明显更好。

  • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。

  • Servlet 是独立于平台的,因为它们是用 Java 编写的。

  • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。

  • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互

1、Servlet框架

 

2、Servlet任务

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。

  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。

  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。

  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。

  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

3、Servlet包

     Java Servlet是运行在带有支持Java Servlet规范的解释器的web服务器上的java类。

     Servlet可以使用java.servlet和javax.servlet.http包创建,它是Java企业级的标准组成部分,Java企业版是支持大型开发项目的Java类库的扩展版本。

     这些类实现Java Servlet和JSP规范,下列教程为Java Servlet2.5和JSP2.1。

     Java Servlet就像任何其他的java类一样已经被创建和编译。在你安装Servlet包并把它们添加到你的计算机上的Classpath类路径中之后,你就可以通过JDK的java编译器或任何其他编译器来编译Servlet。


二、生命周期

     Servlet生命周期可被定义为从创建直到毁灭的整个过程:

  • Servlet 通过调用 init () 方法进行初始化。

  • Servlet 调用 service() 方法来处理客户端的请求。

  • Servlet 通过调用 destroy() 方法终止(结束)。

  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

1、init()方法

init方法被设计成只调用一次。它在第一次创建Servlet时被调用,在后续每次用户请求时不再调用,因此,它是用于一次性初始化,就像Appelt的init方法一样。

Servlet创建用户第一次调用对应于该Servlet的URL时,你可以指定Servlet在服务器第一次启动时被加载。

当用户调用一个Servlet时,就会创建一个Servlet实例,每一个用户请求都会产生一个新的线程,适当的时候一角给doGet或doPost方法。init()方法简单地创建或加载一些数据,这些数据被用于Servlet的整个生命周期。

init方法的定义如下:

public void init() throws ServletException {
  // 初始化代码...
}

2、service()方法

     service()方法是执行实际任务的主要方法。Servlet容器(即Web服务器)调用service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

     每次服务器接收到一个Servlet请求时,服务器会产生一个新的线程并调用服务。service()方法检查HTTP请求类型(GET、POST、PUT、DELETE等),并在适当是时候调用doGet、doPost、doPut、doDelete等方法。

public void service(ServletRequest request, 
                    ServletResponse response) 
      throws ServletException, IOException{
}

     service()方法由容器调用,service方法在适当的时候调用odGet、doPost、doPut、doDelete等方法。所以,你不用对service方法做任何动作,只需要根据来自客户端类型来重写doGet()或doPost()即可。

     doGet()和doPost()方法是每次服务请求中最常用的方法。

3、doGet()方法

GET请求来自于一个URL的正常请求,或者来自于一个未指定METHOD的HTML表单,它由doGet()方法处理。

public void doGet(HttpServletRequest request,
                  HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}

4、doPost()方法

     POST请求来自于一个特别指定了METHOD为POST的HTML表单,它由doPost()方法处理。

public void doPost(HttpServletResquest requers,HttpServletResponse response)
    throws ServletException,IOException{
    //Servlet代码
}

5、destroy()方法

     destroy()方法只会被调用一次,在Servlet生命周期结束时被调用。destroy()方法可以让你的Servlet关闭数据库连接、停止后台线程、把Cookie列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

     在调用destroy()方法之后,servlet对象被标记为垃圾回收。

public void destroy(){
    //终止化代码
}

6、架构图:

Servlet生命周期方案:

  • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。

  • Servlet 容器在调用 service() 方法之前加载 Servlet。

  • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

 


三、Servlet实例

Servlet是服务HTTP请求并实现javax.servlet.Servlet接口的java类。Web应用程序开发人员通常编写Servlet来扩展javax.servlet.http.HttpServlet,并实现Servlet接口的抽象类专门用来处理HTTP请求。

1、Hello World实例:

//导入必须的java库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
​
//扩展HttpServlet类
public class HelloWorld extends HttpServlet{
    private String message;
    public void init()throws ServletException
    {
        //执行必需的初始化
        message = "Hello World";
    }
    public void doGet(HttpServletRequest request,
                HttpServletResponse response)
        throws ServletException,IOException
    {
        //设置响应内容类型
        response.setContentType("text/html");
        //实际的逻辑是在这里
        PrintWriter out = response.getWriter();
        out.println("<h1>" + message +"</h1>");
    }
    public void destroy()
    {
        //什么也不做
    }
}

2、Servlet部署

我们找到<Tomcat-installation-directory>/webapps/ROOT/WEB-INF/的web.xml文件中创建一下条目,或者找到你的Javaweb项目的web.xml即可。

<web-app>      
    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>
    </servlet>
​
    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>
</web-app>  

上面的条目要被创建在web.xml文件中的<web-app>...</web-app>标签内。到这里,启动Tomcat服务器输入 http://localhost:8080/HelloWorld即可。


四、Servlet表单数据

很多情况下,需要传递一些信息,从浏览器到Web服务器,最终到Web服务器,最终到后台程序。浏览器使用两种方法可将这些信息传递到Web服务器,分别为GET方法和POST方法。

1、GET方法

GET方法向页面请求发送已编码的用户信息。页面和已编码的信息中间用?字符分割,如下:

http://www.test.com/hello?key1=value1&key2=value2

GET方法是默认的从浏览器向Web服务器传递信息的方法,它会产生一个很长的字符串,出现在浏览器的地址栏中。如果你要向服务器传递的是密码或其它的敏感信息,请不要使用GET方法。GET方法有大小限制:请求字符串最多只能有1024字符。

这些信息使用QUERY_STRING头传递,并可以通过QUERY_STRING环境变量访问,Servlet使用doGet()方法处理这种类型的请求。

2、POST方法

另一个向后台程序传递信息的比较可靠的方法是POST方法。POST方法打包信息的方式与GET方法基本相同,但是POST方法不是把信息作为URL中?字符后的文本字符串进行发送,而是把这心信息作为一个单独的消息。消息以标准输出的形式传到后台程序,你可以解析和使用这些标准输出。Servlet使用doPost()方法处理这种类型的请求。

3、使用Servlet读取表单数据

Servlet处理表单数据,这些数据会根据不同的情况使用不同的方法自动解析:

  • getParameter():您可以调用 request.getParameter() 方法来获取表单参数的值。

  • getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。

  • getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。

4、使用URL的GET方法实例

下面是一个简单的URL,将使用GET方法向HelloForm程序传递两个值。http:localhost:8080/TomcatTest/HelloForm?name=菜鸟教程&url=www.runoob.com

下面是处理Web浏览器输入的HelloForm.java Servlet程序。为我们将使用getParameter()方法,可以很容易地传递信息:

package com.runoob.test;
​
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;
​
/**
 * Servlet implementation class HelloForm
 */
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloForm() {
        super();
        // TODO Auto-generated constructor stub
    }
​
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
​
        PrintWriter out = response.getWriter();
        String title = "使用 GET 方法读取表单数据";
        // 处理中文
        String name =new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");
        String docType = "<!DOCTYPE html> \n";
        out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<ul>\n" +
            "  <li><b>站点名</b>:"
            + name + "\n" +
            "  <li><b>网址</b>:"
            + request.getParameter("url") + "\n" +
            "</ul>\n" +
            "</body></html>");
    }
    
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

然后我们在web.xml文件中创建以下条目:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>HelloForm</servlet-name>
    <servlet-class>com.runoob.test.HelloForm</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloForm</servlet-name>
    <url-pattern>/TomcatTest/HelloForm</url-pattern>
  </servlet-mapping>
</web-app>

然后浏览器中输入http://localhost:8080/TomcatTest/HelloForm?name=菜鸟教程&url=www.runoob.com 即可。

 

5、使用表单的GET方法实例

下面是一个简单的实例,使用HTML表单和提交按钮传递两个值。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<form action="HelloForm" method="GET">
网址名:<input type="text" name="name">
<br />
网址:<input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

输入网址之后就可以了。

 

6、使用表单的POST方法实例

我们对上面的Servlet做小小的修改,以便它可以处理GET和POST方法。下面的HelloForm.java Servlet程序使用GET和POST方法处理由Web浏览器给出的输入(如果中文数据则需要转码:String name =new String(request.getParameter("name").getBytes("ISO8859-1"),"UTF-8");)。

package com.runoob.test;

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;

/**
 * Servlet implementation class HelloForm
 */
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloForm() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        String title = "使用 POST 方法读取表单数据";
        // 处理中文
        String name =new String(request.getParameter("name").getBytes("ISO8859-1"),"UTF-8");
        String docType = "<!DOCTYPE html> \n";
        out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<ul>\n" +
            "  <li><b>站点名</b>:"
            + name + "\n" +
            "  <li><b>网址</b>:"
            + request.getParameter("url") + "\n" +
            "</ul>\n" +
            "</body></html>");
    }
    
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

编译部署Servlet,使用带有POST方法的hello.html进行测试:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<form action="HelloForm" method="POST">
网址名:<input type="text" name="name">
<br />
网址:<input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

 

7、将复选框数据传递到Servlet程序

下面是一个HTML代码实例checkbox.html,一个带有两个复选框的表单。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<form action="CheckBox" method="POST" target="_blank">
<input type="checkbox" name="runoob" checked="checked" /> 菜鸟教程
<input type="checkbox" name="google"  /> Google
<input type="checkbox" name="taobao" checked="checked" /> 淘宝
<input type="submit" value="选择站点" />
</form>
</body>
</html>

下面是Servlet程序,处理Web浏览器给出的复选框输入。

package com.runoob.test;

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;

/**
 * Servlet implementation class CheckBox
 */
@WebServlet("/CheckBox")
public class CheckBox extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        String title = "读取复选框数据";
        String docType = "<!DOCTYPE html> \n";
            out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                "<ul>\n" +
                "  <li><b>菜鸟按教程标识:</b>: "
                + request.getParameter("runoob") + "\n" +
                "  <li><b>Google 标识:</b>: "
                + request.getParameter("google") + "\n" +
                "  <li><b>淘宝标识:</b>: "
                + request.getParameter("taobao") + "\n" +
                "</ul>\n" +
                "</body></html>");
    }
    
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

设置对应的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>CheckBox</servlet-name>
    <servlet-class>com.runoob.test.CheckBox</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>CheckBox</servlet-name>
    <url-pattern>/TomcatTest/CheckBox</url-pattern>
  </servlet-mapping>
</web-app>

8、读取所有的表单参数

使用HttpServletRequest的getParameterNames()方法读取所有可用的表单参数。该方法返回一个枚举,其中包含未指定顺序的参数名。

一旦我们有一个枚举,我们可以以标准方式循环枚举,使用hasMoreElements()方法来确定何时停止,使用nextElement()方法来获取每个参数的名称。

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
​
/**
 * Servlet implementation class ReadParams
 */
@WebServlet("/ReadParams")
public class ReadParams extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ReadParams() {
        super();
        // TODO Auto-generated constructor stub
    }
​
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        String title = "读取所有的表单数据";
        String docType =
            "<!doctype html public \"-//w3c//dtd html 4.0 " +
            "transitional//en\">\n";
            out.println(docType +
            "<html>\n" +
            "<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n" +
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<table width=\"100%\" border=\"1\" align=\"center\">\n" +
            "<tr bgcolor=\"#949494\">\n" +
            "<th>参数名称</th><th>参数值</th>\n"+
            "</tr>\n");
​
        Enumeration paramNames = request.getParameterNames();
​
        while(paramNames.hasMoreElements()) {
            String paramName = (String)paramNames.nextElement();
            out.print("<tr><td>" + paramName + "</td>\n");
            String[] paramValues =
            request.getParameterValues(paramName);
            // 读取单个值的数据
            if (paramValues.length == 1) {
                String paramValue = paramValues[0];
                if (paramValue.length() == 0)
                    out.println("<td><i>没有值</i></td>");
                else
                    out.println("<td>" + paramValue + "</td>");
            } else {
                // 读取多个值的数据
                out.println("<td><ul>");
                for(int i=0; i < paramValues.length; i++) {
                out.println("<li>" + paramValues[i]);
            }
                out.println("</ul></td>");
            }
            out.print("</tr>");
        }
        out.println("\n</table>\n</body></html>");
    }
​
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
​
}

现在,通过表单尝试上面的Servlet:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>

<form action="ReadParams" method="POST" target="_blank">
<input type="checkbox" name="maths" checked="checked" /> 数学
<input type="checkbox" name="physics"  /> 物理
<input type="checkbox" name="chemistry" checked="checked" /> 化学
<input type="submit" value="选择学科" />
</form>

</body>
</html>

当然,我们还要设置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>ReadParams</servlet-name>
    <servlet-class>com.runoob.test.ReadParams</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ReadParams</servlet-name>
    <url-pattern>/TomcatTest/ReadParams</url-pattern>
  </servlet-mapping>
</web-app>

五、客户端HTTP请求。

当浏览器请求网页时,它会向Web服务器发送特定消息,这些信息不能被直接取用,,因为这些信息是作为HTTP请求的头的一部分进行传输的。

头信息描述
Accept这个头信息指定浏览器或其他客户端可以处理的 MIME 类型。值 image/pngimage/jpeg 是最常见的两种可能值。
Accept-Charset这个头信息指定浏览器可以用来显示信息的字符集。例如 ISO-8859-1。
Accept-Encoding这个头信息指定浏览器知道如何处理的编码类型。值 gzipcompress 是最常见的两种可能值。
Accept-Language这个头信息指定客户端的首选语言,在这种情况下,Servlet 会产生多种语言的结果。例如,en、en-us、ru 等。
Authorization这个头信息用于客户端在访问受密码保护的网页时识别自己的身份。
Connection这个头信息指示客户端是否可以处理持久 HTTP 连接。持久连接允许客户端或其他浏览器通过单个请求来检索多个文件。值 Keep-Alive 意味着使用了持续连接。
Content-Length这个头信息只适用于 POST 请求,并给出 POST 数据的大小(以字节为单位)。
Cookie这个头信息把之前发送到浏览器的 cookies 返回到服务器。
Host这个头信息指定原始的 URL 中的主机和端口。
If-Modified-Since这个头信息表示只有当页面在指定的日期后已更改时,客户端想要的页面。如果没有新的结果可以使用,服务器会发送一个 304 代码,表示 Not Modified 头信息。
If-Unmodified-Since这个头信息是 If-Modified-Since 的对立面,它指定只有当文档早于指定日期时,操作才会成功。
Referer这个头信息指示所指向的 Web 页的 URL。例如,如果您在网页 1,点击一个链接到网页 2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。
User-Agent这个头信息识别发出请求的浏览器或其他客户端,并可以向不同类型的浏览器返回不同的内容。

1、读取HTTP头的方法

下面的方法可用在Servlet程序中读取HTTP头,这些方法通过HttpServletRequest对象可用。

序号方法 & 描述
1Cookie[] getCookies() 返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
2Enumeration getAttributeNames() 返回一个枚举,包含提供给该请求可用的属性名称。
3Enumeration getHeaderNames() 返回一个枚举,包含在该请求中包含的所有的头名。
4Enumeration getParameterNames() 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
5HttpSession getSession() 返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。
6HttpSession getSession(boolean create) 返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。
7Locale getLocale() 基于 Accept-Language 头,返回客户端接受内容的首选的区域设置。
8Object getAttribute(String name) 以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
9ServletInputStream getInputStream() 使用 ServletInputStream,以二进制数据形式检索请求的主体。
10String getAuthType() 返回用于保护 Servlet 的身份验证方案的名称,例如,"BASIC" 或 "SSL",如果JSP没有受到保护则返回 null。
11String getCharacterEncoding() 返回请求主体中使用的字符编码的名称。
12String getContentType() 返回请求主体的 MIME 类型,如果不知道类型则返回 null。
13String getContextPath() 返回指示请求上下文的请求 URI 部分。
14String getHeader(String name) 以字符串形式返回指定的请求头的值。
15String getMethod() 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
16String getParameter(String name) 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
17String getPathInfo() 当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。
18String getProtocol() 返回请求协议的名称和版本。
19String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。
20String getRemoteAddr() 返回发送请求的客户端的互联网协议(IP)地址。
21String getRemoteHost() 返回发送请求的客户端的完全限定名称。
22String getRemoteUser() 如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。
23String getRequestURI() 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
24String getRequestedSessionId() 返回由客户端指定的 session 会话 ID。
25String getServletPath() 返回调用 JSP 的请求的 URL 的一部分。
26String[] getParameterValues(String name) 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
27boolean isSecure() 返回一个布尔值,指示请求是否使用安全通道,如 HTTPS。
28int getContentLength() 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
29int getIntHeader(String name) 返回指定的请求头的值为一个 int 值。
30int getServerPort() 返回接收到这个请求的端口号。
31int getParameterMap() 将参数封装成 Map 类型。

2、HTTP标头

下面的实例使用HttpServletRequest的getHeaderNames()方法读取HTTP头信息。该方法返回一个枚举,包含与当前的HTTP请求相关的头信息。

一旦我们有一个枚举,我们就可以以标准方式循环枚举,使用hasMoreElements()方法来确定何时停止,使用nextElement()方法获取每个参数的名称。

//导入必需的 java 库
import java.io.IOException;import java.io.IOException;
import java.io.PrintWriter;import java.io.PrintWriter;
import java.util.Enumeration;import java.util.Enumeration;

import javax.servlet.ServletException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponse;

@WebServlet("/DisplayHeader")@WebServlet("/DisplayHeader")

//扩展 HttpServlet 类//扩展 HttpServlet 类
public class DisplayHeader extends HttpServlet {public class DisplayHeader extends HttpServlet {

    // 处理 GET 方法请求的方法// 处理 GET 方法请求的方法
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOExceptionpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {{
        // 设置响应内容类型// 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();PrintWriter out = response.getWriter();
        String title = "HTTP Header 请求实例 - 菜鸟教程实例";String title = "HTTP Header 请求实例 - 菜鸟教程实例";
        String docType =String docType =
            "<!DOCTYPE html> \n";"<!DOCTYPE html> \n";
            out.println(docType +out.println(docType +
            "<html>\n" +"<html>\n" +
            "<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+"<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
            "<body bgcolor=\"#f0f0f0\">\n" +"<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +"<h1 align=\"center\">" + title + "</h1>\n" +
            "<table width=\"100%\" border=\"1\" align=\"center\">\n" +"<table width=\"100%\" border=\"1\" align=\"center\">\n" +
            "<tr bgcolor=\"#949494\">\n" +"<tr bgcolor=\"#949494\">\n" +
            "<th>Header 名称</th><th>Header 值</th>\n"+"<th>Header 名称</th><th>Header 值</th>\n"+
            "</tr>\n");"</tr>\n");

        Enumeration headerNames = request.getHeaderNames();Enumeration headerNames = request.getHeaderNames();

        while(headerNames.hasMoreElements()) {while(headerNames.hasMoreElements()) {
            String paramName = (String)headerNames.nextElement();String paramName = (String)headerNames.nextElement();
            out.print("<tr><td>" + paramName + "</td>\n");out.print("<tr><td>" + paramName + "</td>\n");
            String paramValue = request.getHeader(paramName);String paramValue = request.getHeader(paramName);
            out.println("<td> " + paramValue + "</td></tr>\n");out.println("<td> " + paramValue + "</td></tr>\n");
        }}
        out.println("</table>\n</body></html>");out.println("</table>\n</body></html>");
    }}
    // 处理 POST 方法请求的方法// 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);(request, response);
    }}
}}

之后我们肯定是配置web.xml

<?xml version="1.0" encoding="UTF-8"?>  xml version="1.0" encoding="UTF-8"?>  
<web-app>  <web-app>  
  <servlet>  <servlet>  
    <!-- 类名 -->  <!-- 类名 -->  
    <servlet-name>DisplayHeader</servlet-name>  <servlet-name>DisplayHeader</servlet-name>  
    <!-- 所在的包 -->  <!-- 所在的包 -->  
    <servlet-class>com.runoob.test.DisplayHeader</servlet-class>  <servlet-class>com.runoob.test.DisplayHeader</servlet-class>  
  </servlet>  </servlet>  
  <servlet-mapping>  <servlet-mapping>  
    <servlet-name>DisplayHeader</servlet-name>  <servlet-name>DisplayHeader</servlet-name>  
    <!-- 访问的网址 -->  <!-- 访问的网址 -->  
    <url-pattern>/TomcatTest/DisplayHeader</url-pattern>  <url-pattern>/TomcatTest/DisplayHeader</url-pattern>  
  </servlet-mapping>  </servlet-mapping>  
</web-app></web-app>

之后直接访问http://localhost:8080/TomcatTest/DisplayHeader就可以了。


六、Servlet服务器HTTP响应

当一个Web服务器响应一个HTTP请求时,响应通常包括一个状态行、一些响应报头、一个空行和文档。例如:

HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
  (Blank Line)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>

状态行包括HTTP版本(为HTTP/1.1)、一个状态码(本例中为200)和一个对应状态码的短消息(本例中为OK)。

下标总结了从Web服务器返回到浏览器的最有用的HTTP1.1响应报头,你会在Web编程中频繁的使用它:

头信息描述
Allow这个头信息指定服务器支持的请求方法(GET、POST 等)。
Cache-Control这个头信息指定响应文档在何种情况下可以安全地缓存。可能的值有:public、privateno-cache 等。Public 意味着文档是可缓存,Private 意味着文档是单个用户私用文档,且只能存储在私有(非共享)缓存中,no-cache 意味着文档不应被缓存。
Connection这个头信息指示浏览器是否使用持久 HTTP 连接。值 close 指示浏览器不使用持久 HTTP 连接,值 keep-alive 意味着使用持久连接。
Content-Disposition这个头信息可以让您请求浏览器要求用户以给定名称的文件把响应保存到磁盘。
Content-Encoding在传输过程中,这个头信息指定页面的编码方式。
Content-Language这个头信息表示文档编写所使用的语言。例如,en、en-us、ru 等。
Content-Length这个头信息指示响应中的字节数。只有当浏览器使用持久(keep-alive)HTTP 连接时才需要这些信息。
Content-Type这个头信息提供了响应文档的 MIME(Multipurpose Internet Mail Extension)类型。
Expires这个头信息指定内容过期的时间,在这之后内容不再被缓存。
Last-Modified这个头信息指示文档的最后修改时间。然后,客户端可以缓存文件,并在以后的请求中通过 If-Modified-Since 请求头信息提供一个日期。
Location这个头信息应被包含在所有的带有状态码的响应中。在 300s 内,这会通知浏览器文档的地址。浏览器会自动重新连接到这个位置,并获取新的文档。
Refresh这个头信息指定浏览器应该如何尽快请求更新的页面。您可以指定页面刷新的秒数。
Retry-After这个头信息可以与 503(Service Unavailable 服务不可用)响应配合使用,这会告诉客户端多久就可以重复它的请求。
Set-Cookie这个头信息指定一个与页面关联的 cookie。

1、设置HTTP响应报头的方法

下面的方法可用于在Servlet程序中设置HTTP响应报头。这些方法通过HttpServletResponse对象可用。

序号方法 & 描述
1String encodeRedirectURL(String url) 为 sendRedirect 方法中使用的指定的 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
2String encodeURL(String url) 对包含 session 会话 ID 的指定 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
3boolean containsHeader(String name) 返回一个布尔值,指示是否已经设置已命名的响应报头。
4boolean isCommitted() 返回一个布尔值,指示响应是否已经提交。
5void addCookie(Cookie cookie) 把指定的 cookie 添加到响应。
6void addDateHeader(String name, long date) 添加一个带有给定的名称和日期值的响应报头。
7void addHeader(String name, String value) 添加一个带有给定的名称和值的响应报头。
8void addIntHeader(String name, int value) 添加一个带有给定的名称和整数值的响应报头。
9void flushBuffer() 强制任何在缓冲区中的内容被写入到客户端。
10void reset() 清除缓冲区中存在的任何数据,包括状态码和头。
11void resetBuffer() 清除响应中基础缓冲区的内容,不清除状态码和头。
12void sendError(int sc) 使用指定的状态码发送错误响应到客户端,并清除缓冲区。
13void sendError(int sc, String msg) 使用指定的状态发送错误响应到客户端。
14void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
15void setBufferSize(int size) 为响应主体设置首选的缓冲区大小。
16void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
17void setContentLength(int len) 设置在 HTTP Servlet 响应中的内容主体的长度,该方法设置 HTTP Content-Length 头。
18void setContentType(String type) 如果响应还未被提交,设置被发送到客户端的响应的内容类型。
19void setDateHeader(String name, long date) 设置一个带有给定的名称和日期值的响应报头。
20void setHeader(String name, String value) 设置一个带有给定的名称和值的响应报头。
21void setIntHeader(String name, int value) 设置一个带有给定的名称和整数值的响应报头。
22void setLocale(Locale loc) 如果响应还未被提交,设置响应的区域。
23void setStatus(int sc) 为该响应设置状态码。

2、HTTP Header响应实例

我们用setIIntHeader()方法来设置Refresh头。

//导入必需的 java 库
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/Refresh")

//扩展 HttpServlet 类
public class Refresh extends HttpServlet {

    // 处理 GET 方法请求的方法
      public void doGet(HttpServletRequest request,
                        HttpServletResponse response)
                throws ServletException, IOException
      {
          // 设置刷新自动加载时间为 5 秒
          response.setIntHeader("Refresh", 5);
          // 设置响应内容类型
          response.setContentType("text/html;charset=UTF-8");
         
          //使用默认时区和语言环境获得一个日历  
          Calendar cale = Calendar.getInstance();  
          //将Calendar类型转换成Date类型  
          Date tasktime=cale.getTime();  
          //设置日期输出的格式  
          SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
          //格式化输出  
          String nowTime = df.format(tasktime);
          PrintWriter out = response.getWriter();
          String title = "自动刷新 Header 设置 - 菜鸟教程实例";
          String docType =
          "<!DOCTYPE html>\n";
          out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n"+
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<p>当前时间是:" + nowTime + "</p>\n");
      }
      // 处理 POST 方法请求的方法
      public void doPost(HttpServletRequest request,
                         HttpServletResponse response)
          throws ServletException, IOException {
         doGet(request, response);
      }
}

然后我们设置web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app>  
  <servlet>  
     <!-- 类名 -->  
    <servlet-name>Refresh</servlet-name>  
    <!-- 所在的包 -->  
    <servlet-class>com.runoob.test.Refresh</servlet-class>  
  </servlet>  
  <servlet-mapping>  
    <servlet-name>Refresh</servlet-name>  
    <!-- 访问的网址 -->  
    <url-pattern>/TomcatTest/Refresh</url-pattern>  
    </servlet-mapping>  
</web-app> 

七、Servlet HTTP状态码

HTTP请求和HTTP响应消息的格式是类似的:

  • 初始状态行 + 回车换行符(回车+换行)

  • 零个或多个标题行+回车换行符

  • 一个空白行,即回车换行符

  • 一个可选的消息主体,比如文件、查询数据或查询输出

例如,服务器的响应头如下:

HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
  (Blank Line)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>

状态行包括HTTP版本、一个状态码和一个对应于状态码的短消息。

以下是可能从Web服务器返回的HTTP状态码和相关的信息列表:

代码消息描述
100Continue只有请求的一部分已经被服务器接收,但只要它没有被拒绝,客户端应继续该请求。
101Switching Protocols服务器切换协议。
200OK请求成功。
201Created该请求是完整的,并创建一个新的资源。
202Accepted该请求被接受处理,但是该处理是不完整的。
203Non-authoritative Information 
204No Content 
205Reset Content 
206Partial Content 
300Multiple Choices链接列表。用户可以选择一个链接,进入到该位置。最多五个地址。
301Moved Permanently所请求的页面已经转移到一个新的 URL。
302Found所请求的页面已经临时转移到一个新的 URL。
303See Other所请求的页面可以在另一个不同的 URL 下被找到。
304Not Modified 
305Use Proxy 
306Unused在以前的版本中使用该代码。现在已不再使用它,但代码仍被保留。
307Temporary Redirect所请求的页面已经临时转移到一个新的 URL。
400Bad Request服务器不理解请求。
401Unauthorized所请求的页面需要用户名和密码。
402Payment Required您还不能使用该代码。
403Forbidden禁止访问所请求的页面。
404Not Found服务器无法找到所请求的页面。.
405Method Not Allowed在请求中指定的方法是不允许的。
406Not Acceptable服务器只生成一个不被客户端接受的响应。
407Proxy Authentication Required在请求送达之前,您必须使用代理服务器的验证。
408Request Timeout请求需要的时间比服务器能够等待的时间长,超时。
409Conflict请求因为冲突无法完成。
410Gone所请求的页面不再可用。
411Length Required"Content-Length" 未定义。服务器无法处理客户端发送的不带 Content-Length 的请求信息。
412Precondition Failed请求中给出的先决条件被服务器评估为 false。
413Request Entity Too Large服务器不接受该请求,因为请求实体过大。
414Request-url Too Long服务器不接受该请求,因为 URL 太长。当您转换一个 "post" 请求为一个带有长的查询信息的 "get" 请求时发生。
415Unsupported Media Type服务器不接受该请求,因为媒体类型不被支持。
417Expectation Failed 
500Internal Server Error未完成的请求。服务器遇到了一个意外的情况。
501Not Implemented未完成的请求。服务器不支持所需的功能。
502Bad Gateway未完成的请求。服务器从上游服务器收到无效响应。
503Service Unavailable未完成的请求。服务器暂时超载或死机。
504Gateway Timeout网关超时。
505HTTP Version Not Supported服务器不支持"HTTP协议"版本。

1、设置HTTP状态代码的方法

下面的方法可用于在Servlet程序中设置HTTP状态码。这些方法通过HttpServletResponse对象可用。

序号方法 & 描述
1public void setStatus ( int statusCode ) 该方法设置一个任意的状态码。setStatus 方法接受一个 int(状态码)作为参数。如果您的响应包含了一个特殊的状态码和文档,请确保在使用 PrintWriter 实际返回任何内容之前调用 setStatus。
2public void sendRedirect(String url) 该方法生成一个 302 响应,连同一个带有新文档 URL 的 Location 头。
3public void sendError(int code, String message) 该方法发送一个状态码(通常为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。

2、HTTP状态码实例

下面的例子把407错误代码发送到客户端浏览器,浏览器会显示Need authentication!!!消息

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import javax.servlet.annotation.WebServlet;
​
@WebServlet("/showError")
// 扩展 HttpServlet 类
public class showError extends HttpServlet {
 
  // 处理 GET 方法请求的方法
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置错误代码和原因
      response.sendError(407, "Need authentication!!!" );
  }
  // 处理 POST 方法请求的方法
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}

八、编写过滤器

Servlet过滤器可用动态地拦截请求和相应,以变换或使用包含在请求或响应中的信息。

可用将一个或多个Servlet过滤器附加到一个Servlet或一组Servlet。Servlet过滤器也可以附加到JavaServerPages(JSP)文件和HTML页面。调用Servlet前调用所有附加的Servlet过滤器。

Servlet过滤器是可用于Servlet编程的java类,可以实现以下目的:

  • 在客户端的请求访问后端资源之前,拦截这些请求。

  • 在服务器的响应发送回客户端之前,处理这些响应。

根据规范建议的各种类型的过滤器:

  • 身份验证过滤器(Authentication Filters)。

  • 数据压缩过滤器(Data compression Filters)。

  • 加密过滤器(Encryption Filters)。

  • 触发资源访问事件过滤器。

  • 图像转换过滤器(Image Conversion Filters)。

  • 日志记录和审核过滤器(Logging and Auditing Filters)。

  • MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)。

  • 标记化过滤器(Tokenizing Filters)。

  • XSL/T 过滤器(XSL/T Filters),转换 XML 内容。

过滤器通过Web部署描述符(web.xml)中的XML标签来声明,然后映射到你的应用程序的部署描述符中的Servlet名称或URL模式。

当Web容器启动Web应用程序时,它会成为你在部署描述符中声明的每一个过滤器创建一个实例。

Filter的执行顺序与在web.xml配置文件中的配置顺序一致,一般把Filter配置在所有的Servlet之前。

1、Servlet过滤器方法

过滤器是一个实现了javax.servlet.Filter接口的java类。javax.servlet.Filter接口定义了三个方法:

序号方法 & 描述
1public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
2public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
3public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

2、FilterConfig使用

Filter的init方法中提供了一个FilterConfig对象。

如web.xml文件配置如下:

<filter>
    <filter-name>LogFilter</filter-name>
    <filter-class>com.runoob.test.LogFilter</filter-class>
    <init-param>
        <param-name>Site</param-name>
        <param-value>菜鸟教程</param-value>
    </init-param>
</filter>

在init方法使用FilterConfig对象获取参数:

public void  init(FilterConfig config) throws ServletException {
    // 获取初始化参数
    String site = config.getInitParameter("Site"); 
    // 输出初始化参数
    System.out.println("网站名称: " + site); 
}

3、Servlet过滤器实例

以下是Servlet过滤器的实例,将输出网站名称和地址。

package com.runoob.test;

//导入必需的 java 库
import javax.servlet.*;
import java.util.*;

//实现 Filter 类
public class LogFilter implements Filter  {
    public void  init(FilterConfig config) throws ServletException {
        // 获取初始化参数
        String site = config.getInitParameter("Site"); 

        // 输出初始化参数
        System.out.println("网站名称: " + site); 
    }
    public void  doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {

        // 输出站点名称
        System.out.println("站点网址:http://www.runoob.com");

        // 把请求传回过滤链
        chain.doFilter(request,response);
    }
    public void destroy( ){
        /* 在 Filter 实例被 Web 容器从服务移除之前调用 */
    }
}

这里使用DisplayHeader.java为例子:

//导入必需的 java 库
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/DisplayHeader")

//扩展 HttpServlet 类
public class DisplayHeader extends HttpServlet {

    // 处理 GET 方法请求的方法
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();
        String title = "HTTP Header 请求实例 - 菜鸟教程实例";
        String docType =
            "<!DOCTYPE html> \n";
            out.println(docType +
            "<html>\n" +
            "<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<table width=\"100%\" border=\"1\" align=\"center\">\n" +
            "<tr bgcolor=\"#949494\">\n" +
            "<th>Header 名称</th><th>Header 值</th>\n"+
            "</tr>\n");

        Enumeration headerNames = request.getHeaderNames();

        while(headerNames.hasMoreElements()) {
            String paramName = (String)headerNames.nextElement();
            out.print("<tr><td>" + paramName + "</td>\n");
            String paramValue = request.getHeader(paramName);
            out.println("<td> " + paramValue + "</td></tr>\n");
        }
        out.println("</table>\n</body></html>");
    }
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

4、Web.xml中的Servlet过滤器映射(Servlet Filter Mapping)

定义过滤器,然后映射到一个URL或Servlet,这与定义Servlet,然后映射到一个URL模式方式大致相同:

<?xml version="1.0" encoding="UTF-8"?>  
<web-app>  
<filter>
  <filter-name>LogFilter</filter-name>
  <filter-class>com.runoob.test.LogFilter</filter-class>
  <init-param>
    <param-name>Site</param-name>
    <param-value>菜鸟教程</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>LogFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>  
  <!-- 类名 -->  
  <servlet-name>DisplayHeader</servlet-name>  
  <!-- 所在的包 -->  
  <servlet-class>com.runoob.test.DisplayHeader</servlet-class>  
</servlet>  
<servlet-mapping>  
  <servlet-name>DisplayHeader</servlet-name>  
  <!-- 访问的网址 -->  
  <url-pattern>/TomcatTest/DisplayHeader</url-pattern>  
</servlet-mapping>  
</web-app>  

上述过滤器适用于所有的Servlet,因为我们在配置中指定/*。如果你只想在少数的Servlet上应用过滤器,你可以指定一个特定的Servlet路径。

5、使用多个过滤器

Web应用程序可以根据特定的目的定义若干个不同的过滤器。假设你定义了两个过滤器AuthenFilter和LogFilter。你需要创建一个如下所述的不同的映射,其余的处理过程大致相同:

<filter>
   <filter-name>LogFilter</filter-name>
   <filter-class>com.runoob.test.LogFilter</filter-class>
   <init-param>
      <param-name>test-param</param-name>
      <param-value>Initialization Paramter</param-value>
   </init-param>
</filter>

<filter>
   <filter-name>AuthenFilter</filter-name>
   <filter-class>com.runoob.test.AuthenFilter</filter-class>
   <init-param>
      <param-name>test-param</param-name>
      <param-value>Initialization Paramter</param-value>
   </init-param>
</filter>

<filter-mapping>
   <filter-name>LogFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
   <filter-name>AuthenFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

6、过滤器的应用顺序

web..xml中的filter-mapping元素的顺序决定了Web容器应用过滤器到Servlet的顺序。若要反转过滤器的顺序,你只需要在web.xml文件中反转filter-mapping元素即可。

7、web.xml配置各节点说明

  • <filter>

    指定一个过滤器。

    • <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。

    • <filter-class>元素用于指定过滤器的完整的限定类名。

    • <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。

    • 在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

  • <filter-mapping>

    元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径

    • <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字

    • <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)

  • <servlet-name>指定过滤器所拦截的Servlet名称。

  • <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。

  • <dispatcher>

    子元素可以设置的值及其意义

    • REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。

    • INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

    • FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

    • ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。


九、Servlet异常处理

当一个Servlet抛出一个异常时,Web容器在使用了exception-type元素的web.xml中搜索与抛出异常类型相匹配的配置。

你必须在web.xml中使用error-page元素来指定对特定异常或HTTP状态码作出相应的Servlet调用。

1、web.xml配置

假设,有一个ErrorHandler的Servlet在任何已定义的异常或错误出现时被调用。以下将是在web.xml中创建的项。

<!-- servlet 定义 -->
<servlet>
        <servlet-name>ErrorHandler</servlet-name>
        <servlet-class>ErrorHandler</servlet-class>
</servlet>
<!-- servlet 映射 -->
<servlet-mapping>
        <servlet-name>ErrorHandler</servlet-name>
        <url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>

<!-- error-code 相关的错误页面 -->
<error-page>
    <error-code>404</error-code>
    <location>/ErrorHandler</location>
</error-page>
<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>

<!-- exception-type 相关的错误页面 -->
<error-page>
    <exception-type>
          javax.servlet.ServletException
    </exception-type >
    <location>/ErrorHandler</location>
</error-page>

<error-page>
    <exception-type>java.io.IOException</exception-type >
    <location>/ErrorHandler</location>
</error-page>

如果你想对所有的异常有一个通用的错误处理程序,那么应该定义下面的error-page,而不是为每个异常定义单独的error-page元素。

<error-page>
    <exception-type>java.lang.Throwable</exception-type >
    <location>/ErrorHandler</location>
</error-page>

以下是关于上面web.xml异常处理要注意的点:

  • Servlet ErrorHandler 与其他的 Servlet 的定义方式一样,且在 web.xml 中进行配置。

  • 如果有错误状态代码出现,不管为 404(Not Found 未找到)或 403(Forbidden 禁止),则会调用 ErrorHandler 的 Servlet。

  • 如果 Web 应用程序抛出 ServletExceptionIOException,那么 Web 容器会调用 ErrorHandler 的 Servlet。

  • 您可以定义不同的错误处理程序来处理不同类型的错误或异常。上面的实例是非常通用的,希望您能通过实例理解基本的概念。

2、请求属性-错误/异常

以下是错误处理的Servlet可以访问的请求属性列表,用来分析错误/异常的性质。

序号属性 & 描述
1javax.servlet.error.status_code 该属性给出状态码,状态码可被存储,并在存储为 java.lang.Integer 数据类型后可被分析。
2javax.servlet.error.exception_type 该属性给出异常类型的信息,异常类型可被存储,并在存储为 java.lang.Class 数据类型后可被分析。
3javax.servlet.error.message 该属性给出确切错误消息的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
4javax.servlet.error.request_uri 该属性给出有关 URL 调用 Servlet 的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
5javax.servlet.error.exception 该属性给出异常产生的信息,信息可被存储,并在存储为 java.lang.Throwable 数据类型后可被分析。
6javax.servlet.error.servlet_name 该属性给出 Servlet 的名称,名称可被存储,并在存储为 java.lang.String 数据类型后可被分析。

3、Servlet错误处理程序实例

//导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

//扩展 HttpServlet 类
public class ErrorHandler extends HttpServlet {

    // 处理 GET 方法请求的方法
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        Throwable throwable = (Throwable)
        request.getAttribute("javax.servlet.error.exception");
        Integer statusCode = (Integer)
        request.getAttribute("javax.servlet.error.status_code");
        String servletName = (String)
        request.getAttribute("javax.servlet.error.servlet_name");
        if (servletName == null){
            servletName = "Unknown";
        }
        String requestUri = (String)
        request.getAttribute("javax.servlet.error.request_uri");
        if (requestUri == null){
            requestUri = "Unknown";
        }
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
    
        PrintWriter out = response.getWriter();
        String title = "菜鸟教程 Error/Exception 信息";
       
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
            "<html>\n" +
             "<head><title>" + title + "</title></head>\n" +
             "<body bgcolor=\"#f0f0f0\">\n");
           out.println("<h1>菜鸟教程异常信息实例演示</h1>");
           if (throwable == null && statusCode == null){
              out.println("<h2>错误信息丢失</h2>");
              out.println("请返回 <a href=\"" + 
            response.encodeURL("http://localhost:8080/") + 
                "\">主页</a>。");
           }else if (statusCode != null) {
              out.println("错误代码 : " + statusCode);
        }else{
               out.println("<h2>错误信息</h2>");
              out.println("Servlet Name : " + servletName + 
                              "</br></br>");
              out.println("异常类型 : " + 
                              throwable.getClass( ).getName( ) + 
                              "</br></br>");
              out.println("请求 URI: " + requestUri + 
                              "<br><br>");
              out.println("异常信息: " + 
                                  throwable.getMessage( ));
           }
           out.println("</body>");
           out.println("</html>");
    }
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request,
                      HttpServletResponse response)
       throws ServletException, IOException {
        doGet(request, response);
    }
}

配置web.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<web-app>  
<servlet>
        <servlet-name>ErrorHandler</servlet-name>
        <servlet-class>com.runoob.test.ErrorHandler</servlet-class>
</servlet>
<!-- servlet mappings -->
<servlet-mapping>
        <servlet-name>ErrorHandler</servlet-name>
        <url-pattern>/TomcatTest/ErrorHandler</url-pattern>
</servlet-mapping>
<error-page>
    <error-code>404</error-code>
    <location>/TomcatTest/ErrorHandler</location>
</error-page>
<error-page>
    <exception-type>java.lang.Throwable</exception-type >
    <location>/ErrorHandler</location>
</error-page>
</web-app>  

如果你尝试输入错误的URL,就会触发Web容器调用ErrorHandler的Servlet,并显示适当的消息。


十、Cookie处理

Cookie是存储在客户端计算机上的文本文件,并保留了各种跟踪信息。java servlet显然支持HTTP Cookie。

识别返回用户包括三个步骤:

  • 服务器脚本向浏览器发送一组 Cookie。例如:姓名、年龄或识别号码等。

  • 浏览器将这些信息存储在本地计算机上,以备将来使用。

  • 当下一次浏览器向 Web 服务器发送任何请求时,浏览器会把这些 Cookie 信息发送到服务器,服务器将使用这些信息来识别用户。

(Servlet Cookie处理需要中文进行编码与解码,方法为:

String   str   =   java.net.URLEncoder.encode("中文","UTF-8");            //编码
String   str   =   java.net.URLDecoder.decode("编码后的字符串","UTF-8");   // 解码

 

1、Cookie剖析

Cookie通常设置在HTTP头信息中(虽然JavaScript也可以直接在浏览器上设置一个Cookie)。设置Cookie的Servlet会发送如下的头信息:

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT; 
                 path=/; domain=runoob.com
Connection: close
Content-Type: text/html

所以,Set-Cookie头包含了一个名称值对、一个GMT日期、一个路径和一个域。名称和值会被URL编码。expires字段是一个指令,告诉浏览器在给定的时间和日期之后“忘记”该Cookie。

如果浏览器被配置为存储Cookie,它将会保留次信息知道到期日期。如果用户的浏览器指向任何匹配该Cookie的路径和域的界面,它会重新发送Cookie到服务器。浏览器的头信息可能如下:

GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz

Servlet就能通过请求方法request.getCookies()访问Cookie,该方法将返回一个Cookie对象的数组。

 

2、Cookie方法

以下是在Servlet中操作Cookie时可使用的有用的方法列表:

序号方法 & 描述
1public void setDomain(String pattern) 该方法设置 cookie 适用的域,例如 runoob.com。
2public String getDomain() 该方法获取 cookie 适用的域,例如 runoob.com。
3public void setMaxAge(int expiry) 该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。
4public int getMaxAge() 该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。
5public String getName() 该方法返回 cookie 的名称。名称在创建后不能改变。
6public void setValue(String newValue) 该方法设置与 cookie 关联的值。
7public String getValue() 该方法获取与 cookie 关联的值。
8public void setPath(String uri) 该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。
9public String getPath() 该方法获取 cookie 适用的路径。
10public void setSecure(boolean flag) 该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。
11public void setComment(String purpose) 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。
12public String getComment() 获取 cookie 的注释,如果 cookie 没有注释则返回 null。

3、通过Servlet设置Cookie

通过Servlet设置Cookie包括三个步骤:

1)创建一个Cookie对象:你可以调用带有cookie名称和cookie值的Cookie构造函数,cookie名称和cookie值都是字符串。

Cookie cookie = new Cookie("key","value");

无论是名字还是值,都不能包含空格或以下任何字符:[]()=,"/?@:;'

2)设置最大生命周期:你可以使用setMaxAge方法来指定cookie能够保持有效的时间(以秒为单位)。下面将设置一个最长有效期为24小时的cookie。

cookie.setMaxAge(60*60*24);

3)发送Cookie到HTTP响应头:你可以使用response.addCookie来添加HTTP响应头中的Cookie,如下:

response.addCookie(cookie);

4、实例

让我们修改我们的表单数据实例,为名字和姓氏设置Cookie。

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class HelloServlet
 */
@WebServlet("/HelloForm")
public class HelloForm extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HelloForm() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // 为名字和姓氏创建 Cookie      
        Cookie name = new Cookie("name",
                URLEncoder.encode(request.getParameter("name"), "UTF-8")); // 中文转码
        Cookie url = new Cookie("url",
                      request.getParameter("url"));
        
        // 为两个 Cookie 设置过期日期为 24 小时后
        name.setMaxAge(60*60*24); 
        url.setMaxAge(60*60*24); 
        
        // 在响应头中添加两个 Cookie
        response.addCookie( name );
        response.addCookie( url );
        
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        
        PrintWriter out = response.getWriter();
        String title = "设置 Cookie 实例";
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                "<ul>\n" +
                "  <li><b>站点名:</b>:"
                + request.getParameter("name") + "\n</li>" +
                "  <li><b>站点 URL:</b>:"
                + request.getParameter("url") + "\n</li>" +
                "</ul>\n" +
                "</body></html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

然后配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet> 
    <!-- 类名 -->  
    <servlet-name>HelloForm</servlet-name>
    <!-- 所在的包 -->
    <servlet-class>com.runoob.test.HelloForm</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloForm</servlet-name>
    <!-- 访问的网址 -->
    <url-pattern>/TomcatTest/HelloForm</url-pattern>
  </servlet-mapping>
</web-app>

然后用下面的HTML页面来调用Servlet。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<form action="/TomcatTest/HelloForm" method="GET">
站点名 :<input type="text" name="name">
<br />
站点 URL:<input type="text" name="url" /><br>
<input type="submit" value="提交" />
</form>
</body>
</html>

5、通过Servlet读取Cookie

要读取Cookie,你需要通过调用HttpServletRequest的getCookies()方法创建一个javax.servlet.http.Cookie对象的数组。然后循环遍历数组,并使用getName()和getValue()方法来访问每个cookie和关联的值。

实例:

我们读取上面实例中设置的Cookie

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ReadCookies
 */
@WebServlet("/ReadCookies")
public class ReadCookies extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ReadCookies() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        Cookie cookie = null;
        Cookie[] cookies = null;
        // 获取与该域相关的 Cookie 的数组
        cookies = request.getCookies();
         
         // 设置响应内容类型
         response.setContentType("text/html;charset=UTF-8");
    
         PrintWriter out = response.getWriter();
         String title = "Delete Cookie Example";
         String docType = "<!DOCTYPE html>\n";
         out.println(docType +
                   "<html>\n" +
                   "<head><title>" + title + "</title></head>\n" +
                   "<body bgcolor=\"#f0f0f0\">\n" );
          if( cookies != null ){
            out.println("<h2>Cookie 名称和值</h2>");
            for (int i = 0; i < cookies.length; i++){
               cookie = cookies[i];
               if((cookie.getName( )).compareTo("name") == 0 ){
                    cookie.setMaxAge(0);
                    response.addCookie(cookie);
                    out.print("已删除的 cookie:" + 
                                 cookie.getName( ) + "<br/>");
               }
               out.print("名称:" + cookie.getName( ) + ",");
               out.print("值:" +  URLDecoder.decode(cookie.getValue(), "utf-8") +" <br/>");
            }
         }else{
             out.println(
               "<h2 class=\"tutheader\">No Cookie founds</h2>");
         }
         out.println("</body>");
         out.println("</html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

6、通过Servlet删除Cookie

删除Cookie是非常简单的,如果你想删除一个cookie,那么你只需要以下三个步骤:

  • 读取一个现有的 cookie,并把它存储在 Cookie 对象中。

  • 使用 setMaxAge() 方法设置 cookie 的年龄为零,来删除现有的 cookie。

  • 把这个 cookie 添加到响应头。

实例:

下面的例子将删除现有的名为"url"的cookie,当你下次运行ReadCookies的Servlet时,它会返回url为null。

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class DeleteCookies
 */
@WebServlet("/DeleteCookies")
public class DeleteCookies extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DeleteCookies() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        Cookie cookie = null;
        Cookie[] cookies = null;
        // 获取与该域相关的 Cookie 的数组
        cookies = request.getCookies();
        
            // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
   
        PrintWriter out = response.getWriter();
        String title = "删除 Cookie 实例";
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                  "<html>\n" +
                  "<head><title>" + title + "</title></head>\n" +
                  "<body bgcolor=\"#f0f0f0\">\n" );
         if( cookies != null ){
           out.println("<h2>Cookie 名称和值</h2>");
           for (int i = 0; i < cookies.length; i++){
              cookie = cookies[i];
              if((cookie.getName( )).compareTo("url") == 0 ){
                   cookie.setMaxAge(0);
                   response.addCookie(cookie);
                   out.print("已删除的 cookie:" + 
                                cookie.getName( ) + "<br/>");
              }
              out.print("名称:" + cookie.getName( ) + ",");
              out.print("值:" + cookie.getValue( )+" <br/>");
           }
        }else{
            out.println(
              "<h2 class=\"tutheader\">No Cookie founds</h2>");
        }
        out.println("</body>");
        out.println("</html>");
        }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

十一、Session跟踪

HTTP是一种“无状态”协议,这就意味着每次客户端检索网页时,客户端打开一个单独的连接到Web服务器,服务器会自动不保留之前客户端请求的任何记录。

但是仍然有以下三种方式来维持Web客户端和Web服务器之间的session会话:

1、Cookies

一个Web服务器可以分配一个唯一的session会话ID作为每个Web客户端的cookie,对于客户端的后续请求可以使用接收到的cookie来识别。

这可能不是一个有效的方法,因为很多浏览器不支持cookie,所以我们建议不要使用这种方式来维持session会话。

2、隐藏的表单字段

一个Web服务器可以发送一个隐藏的HTML表单字段,以及一个唯一的session会话,如下:

<input type="hidden" name="sessionid" value="12345">

该条目意味着,当表单被提交时,指定的名称和值会被自动包含在GET和POST数据中。每次当Web浏览器发送回请求时,session_id值用于保持不同的Web浏览器的跟踪。

这个可能是一种保持session会发跟踪的有效方式,但是点击常规的超文本链接不会导致表单提交,因此隐藏的表单字段也不支持常规的session会话跟踪。

3、URL重写

你在在每个URL末尾追加一些额外的数据来表示session会话,服务器会把该session会话标识符与已存储的有关session会话的数据相关联。

例如:http://w3cshcool.cc/file.html;sessionid=123456,session会话标识符被附加为sessionid=12345,标识符可被Web服务器识别客户端。

URL重写是一种更好的维持session会话的方式,它在浏览器不支持cookie时能够很好的工作,但是它的缺点是会动态生成每个URL来为页面分配一个session会话ID,即使是在很简单的静态HTML页面中也会如此。

4、HttpSession对象

Servlet还提供了HttpSession接口,该接口提供了一种跨多个页面请求或访问网站时识别用户以及存储有关用户信息的方式。

Servlet容器使用这个接口来创建一个HTTP客户端和HTTP服务器之间的session会话。会话持续一个指定的时间段,跨多个连接或页面请求。

你可以通过调用HttpServletRequset的公共方法getSession()来获取HttpSession对象,例如:

HttpSession session = request.getSession();

你需要在向客户端发送任何文档内容之前调用request.getSession()。下面总结了HttpSession对象中可用的几个重要的方法:

序号方法 & 描述
1public Object getAttribute(String name) 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。
2public Enumeration getAttributeNames() 该方法返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。
3public long getCreationTime() 该方法返回该 session 会话被创建的时间,自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。
4public String getId() 该方法返回一个包含分配给该 session 会话的唯一标识符的字符串。
5public long getLastAccessedTime() 该方法返回客户端最后一次发送与该 session 会话相关的请求的时间自格林尼治标准时间 1970 年 1 月 1 日午夜算起,以毫秒为单位。
6public int getMaxInactiveInterval() 该方法返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位。
7public void invalidate() 该方法指示该 session 会话无效,并解除绑定到它上面的任何对象。
8public boolean isNew() 如果客户端还不知道该 session 会话,或者如果客户选择不参入该 session 会话,则该方法返回 true。
9public void removeAttribute(String name) 该方法将从该 session 会话移除指定名称的对象。
10public void setAttribute(String name, Object value) 该方法使用指定的名称绑定一个对象到该 session 会话。
11public void setMaxInactiveInterval(int interval) 该方法在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。

5、session跟踪实例

本实例说明了如何使用HttpSession对象获取session会话创建时间和最后访问时间。如果不存在session会话,我们将通过请求创建一个新的session会话。

package com.runoob.test;
​
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
​
/**
 * Servlet implementation class SessionTrack
 */
@WebServlet("/SessionTrack")
public class SessionTrack extends HttpServlet {
    private static final long serialVersionUID = 1L;
​
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // 如果不存在 session 会话,则创建一个 session 对象
        HttpSession session = request.getSession(true);
        // 获取 session 创建时间
        Date createTime = new Date(session.getCreationTime());
        // 获取该网页的最后一次访问时间
        Date lastAccessTime = new Date(session.getLastAccessedTime());
         
        //设置日期输出的格式  
        SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    
        String title = "Servlet Session 实例 - 菜鸟教程";
        Integer visitCount = new Integer(0);
        String visitCountKey = new String("visitCount");
        String userIDKey = new String("userID");
        String userID = new String("Runoob");
        if(session.getAttribute(visitCountKey) == null) {
            session.setAttribute(visitCountKey, new Integer(0));
        }
​
    
        // 检查网页上是否有新的访问者
        if (session.isNew()){
            title = "Servlet Session 实例 - 菜鸟教程";
             session.setAttribute(userIDKey, userID);
        } else {
             visitCount = (Integer)session.getAttribute(visitCountKey);
             visitCount = visitCount + 1;
             userID = (String)session.getAttribute(userIDKey);
        }
        session.setAttribute(visitCountKey,  visitCount);
    
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
    
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                 "<h2 align=\"center\">Session 信息</h2>\n" +
                "<table border=\"1\" align=\"center\">\n" +
                "<tr bgcolor=\"#949494\">\n" +
                "  <th>Session 信息</th><th>值</th></tr>\n" +
                "<tr>\n" +
                "  <td>id</td>\n" +
                "  <td>" + session.getId() + "</td></tr>\n" +
                "<tr>\n" +
                "  <td>创建时间</td>\n" +
                "  <td>" +  df.format(createTime) + 
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>最后访问时间</td>\n" +
                "  <td>" + df.format(lastAccessTime) + 
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>用户 ID</td>\n" +
                "  <td>" + userID + 
                "  </td></tr>\n" +
                "<tr>\n" +
                "  <td>访问统计:</td>\n" +
                "  <td>" + visitCount + "</td></tr>\n" +
                "</table>\n" +
                "</body></html>"); 
    }
}

在web.xml配置:

?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet> 
    <!-- 类名 -->  
    <servlet-name>SessionTrack</servlet-name>
    <!-- 所在的包 -->
    <servlet-class>com.runoob.test.SessionTrack</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>SessionTrack</servlet-name>
    <!-- 访问的网址 -->
    <url-pattern>/TomcatTest/SessionTrack</url-pattern>
  </servlet-mapping>
</web-app>

6、删除Session会话数据

  • 移除一个特定的属性:您可以调用 public void removeAttribute(String name) 方法来删除与特定的键相关联的值。

  • 删除整个 session 会话:您可以调用 public void invalidate() 方法来丢弃整个 session 会话。

  • 设置 session 会话过期时间:您可以调用 public void setMaxInactiveInterval(int interval) 方法来单独设置 session 会话超时。

  • 注销用户:如果使用的是支持 servlet 2.4 的服务器,您可以调用 logout 来注销 Web 服务器的客户端,并把属于所有用户的所有 session 会话设置为无效。

  • web.xml 配置:如果您使用的是 Tomcat,除了上述方法,您还可以在 web.xml 文件中配置 session 会话超时,如下所示:

 <session-config>
    <session-timeout>15</session-timeout>
  </session-config>

上面实例的超时时间是以分钟为单位,将覆盖Tomcat中默认的30分钟超时时间。


十二、Servlet数据库访问

访问数据库,演示如何使用Servlet访问数据库:

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class DatabaseAccess
 */
@WebServlet("/DatabaseAccess")
public class DatabaseAccess extends HttpServlet {
    private static final long serialVersionUID = 1L;
    // JDBC 驱动名及数据库 URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
    static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
    
    // 数据库的用户名与密码,需要根据自己的设置
    static final String USER = "root";
    static final String PASS = "123456"; 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public DatabaseAccess() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Connection conn = null;
        Statement stmt = null;
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        String title = "Servlet Mysql 测试 - 菜鸟教程";
        String docType = "<!DOCTYPE html>\n";
        out.println(docType +
        "<html>\n" +
        "<head><title>" + title + "</title></head>\n" +
        "<body bgcolor=\"#f0f0f0\">\n" +
        "<h1 align=\"center\">" + title + "</h1>\n");
        try{
            // 注册 JDBC 驱动器
            Class.forName("com.mysql.jdbc.Driver");
            
            // 打开一个连接
            conn = DriverManager.getConnection(DB_URL,USER,PASS);

            // 执行 SQL 查询
            stmt = conn.createStatement();
            String sql;
            sql = "SELECT id, name, url FROM websites";
            ResultSet rs = stmt.executeQuery(sql);

            // 展开结果集数据库
            while(rs.next()){
                // 通过字段检索
                int id  = rs.getInt("id");
                String name = rs.getString("name");
                String url = rs.getString("url");
    
                // 输出数据
                out.println("ID: " + id);
                out.println(", 站点名称: " + name);
                out.println(", 站点 URL: " + url);
                out.println("<br />");
            }
            out.println("</body></html>");

            // 完成后关闭
            rs.close();
            stmt.close();
            conn.close();
        } catch(SQLException se) {
            // 处理 JDBC 错误
            se.printStackTrace();
        } catch(Exception e) {
            // 处理 Class.forName 错误
            e.printStackTrace();
        }finally{
            // 最后是用于关闭资源的块
            try{
                if(stmt!=null)
                stmt.close();
            }catch(SQLException se2){
            }
            try{
                if(conn!=null)
                conn.close();
            }catch(SQLException se){
                se.printStackTrace();
            }
        }
       
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}

配置web.xml文件:

 <servlet>
        <servlet-name>DatabaseAccess</servlet-name>
        <servlet-class>com.runoob.test.DatabaseAccess</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DatabaseAccess</servlet-name>
        <url-pattern>/TomcatTest/DatabaseAccess</url-pattern>
    </servlet-mapping>

十三、Servlet文件上传

Servlet可以与HTML表单标签一起使用,来允许用户上传文件到服务器。上传的文件可以是文本文件或图像文件或任何文档。

使用到的文件有:

  • upload.jsp:文件上传表单。

  • message.jsp:提交成功后替换页面。

  • UploadServlet.java:上传处理Servlet。

  • 需要约会的jar文件:commons-fileupload-1.3.2,commons-io-2.5.jar。

1、创建一个文件上传表单

下面的HTML代码创建了一个文件上传表单,需要注意:

  • 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法。

  • 表单 enctype 属性应该设置为 multipart/form-data.

  • 表单 action 属性应该设置为在后端服务器上处理文件上传的 Servlet 文件。下面的实例使用了 UploadServlet Servlet 来上传文件。

  • 上传单个文件,您应该使用单个带有属性 type="file" 的 <input .../> 标签。为了允许多个文件上传,请包含多个 name 属性值不同的 input 标签。输入标签具有不同的名称属性的值。浏览器会为每个 input 标签关联一个浏览按钮。

upload.jsp文件代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html><html>
<head><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传实例 - 菜鸟教程</title><title>文件上传实例 - 菜鸟教程</title>
</head></head>
<body><body>
<h1>文件上传实例 - 菜鸟教程</h1><h1>文件上传实例 - 菜鸟教程</h1>
<form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data"><form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data">
    选择一个文件:
    <input type="file" name="uploadFile" /><input type="file" name="uploadFile" />
    <br/><br/><br/><br/>
    <input type="submit" value="上传" /><input type="submit" value="上传" />
</form></form>
</body></body>
</html></html>

2、编写后台Servlet

以下是UploadServlet的源代码,用于处理文件上传,在这之前我们先确保依赖包已经引入到项目的WEB-INF/lib目录下:

package com.runoob.test; com.runoob.test;

import java.io.File;import java.io.File;
import java.io.IOException;import java.io.IOException;
import java.io.PrintWriter;import java.io.PrintWriter;
import java.util.List;import java.util.List;
 
import javax.servlet.ServletException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
 

/**
 * Servlet implementation class UploadServlet
 */
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
     
    // 上传文件存储目录
    private static final String UPLOAD_DIRECTORY = "upload";
 
    // 上传配置
    private static final int MEMORY_THRESHOLD   = 1024 * 1024 * 3;  // 3MB
    private static final int MAX_FILE_SIZE      = 1024 * 1024 * 40; // 40MB
    private static final int MAX_REQUEST_SIZE   = 1024 * 1024 * 50; // 50MB
 
    /**
     * 上传数据及保存文件
     */
    protected void doPost(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException {
        // 检测是否为多媒体上传
        if (!ServletFileUpload.isMultipartContent(request)) {
            // 如果不是则停止
            PrintWriter writer = response.getWriter();
            writer.println("Error: 表单必须包含 enctype=multipart/form-data");
            writer.flush();
            return;
        }
 
        // 配置上传参数
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
        factory.setSizeThreshold(MEMORY_THRESHOLD);
        // 设置临时存储目录
        factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
 
        ServletFileUpload upload = new ServletFileUpload(factory);
         
        // 设置最大文件上传值
        upload.setFileSizeMax(MAX_FILE_SIZE);
         
        // 设置最大请求值 (包含文件和表单数据)
        upload.setSizeMax(MAX_REQUEST_SIZE);

        // 中文处理
        upload.setHeaderEncoding("UTF-8"); 

        // 构造临时路径来存储上传的文件
        // 这个路径相对当前应用的目录
        String uploadPath = request.getServletContext().getRealPath("./") + File.separator + UPLOAD_DIRECTORY;
       
         
        // 如果目录不存在则创建
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdir();
        }
 
        try {
            // 解析请求的内容提取文件数据
            @SuppressWarnings("unchecked")
            List<FileItem> formItems = upload.parseRequest(request);
 
            if (formItems != null && formItems.size() > 0) {
                // 迭代表单数据
                for (FileItem item : formItems) {
                    // 处理不在表单中的字段
                    if (!item.isFormField()) {
                        String fileName = new File(item.getName()).getName();
                        String filePath = uploadPath + File.separator + fileName;
                        File storeFile = new File(filePath);
                        // 在控制台输出文件的上传路径
                        System.out.println(filePath);
                        // 保存文件到硬盘
                        item.write(storeFile);
                        request.setAttribute("message",
                            "文件上传成功!");
                    }
                }
            }
        } catch (Exception ex) {
            request.setAttribute("message",
                    "错误信息: " + ex.getMessage());
        }
        // 跳转到 message.jsp
        request.getServletContext().getRequestDispatcher("/message.jsp").forward(
                request, response);
    }
}

message.jsp文件代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>文件上传结果</title>
</head>
<body>
    <center>
        <h2>${message}</h2>
    </center>
</body>
</html>

编译运行Servlet,配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<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_2_5.xsd"
    id="WebApp_ID" version="2.5">
  <servlet>
    <display-name>UploadServlet</display-name>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.runoob.test.UploadServlet</servlet-class>
  </servlet>
   
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/TomcatTest/UploadServlet</url-pattern>
  </servlet-mapping>
</web-app>

十四、Servlet处理日期

使用Servlet的最重要的优势之一是,可以使用核心java中大多数可用方法。例如java提供的java.tuilt包中Date类,封装了当前的时间和日期。

1、构造函数

Date或者Date(long millisec)

序号方法 & 描述
1boolean after(Date date) 如果调用的 Date 对象中包含的日期在 date 指定的日期之后,则返回 true,否则返回 false。
2boolean before(Date date) 如果调用的 Date 对象中包含的日期在 date 指定的日期之前,则返回 true,否则返回 false。
3Object clone( ) 重复调用 Date 对象。
4int compareTo(Date date) 把调用对象的值与 date 的值进行比较。如果两个值是相等的,则返回 0。如果调用对象在 date 之前,则返回一个负值。如果调用对象在 date 之后,则返回一个正值。
5int compareTo(Object obj) 如果 obj 是 Date 类,则操作等同于 compareTo(Date)。否则,它会抛出一个 ClassCastException。
6boolean equals(Object date) 如果调用的 Date 对象中包含的时间和日期与 date 指定的相同,则返回 true,否则返回 false。
7long getTime( ) 返回 1970 年 1 月 1 日以来经过的毫秒数。
8int hashCode( ) 为调用对象返回哈希代码。
9void setTime(long time) 设置 time 指定的时间和日期,这表示从 1970 年 1 月 1 日午夜以来经过的时间(以毫秒为单位)。
10String toString( ) 转换调用的 Date 对象为一个字符串,并返回结果。

2、获取当前时间

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class CurrentDate
 */
@WebServlet("/CurrentDate")
public class CurrentDate extends HttpServlet {
    private static final long serialVersionUID = 1L;
   
    public CurrentDate() {
        super();
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
          String title = "显示当前的日期和时间";
        Date date = new Date();
        String docType = "<!DOCTYPE html> \n";
          out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<h2 align=\"center\">" + date.toString() + "</h2>\n" +
            "</body></html>");
    }

}

十五、网页重定向

当文档移动到新的位置,我们需要向客户端发送这个新位置时,我们需要使用到网页重定向。当然,也可能是为了负载均衡,或者只是为了简单的随机,这些情况都有可能用到网页重定向。

重定向请求到另一个网页的最简单的方式是使用response对象的sendRedirect()方法。下面是该方法的定义:

public void HttpServletResponse.sendRedirect(String location)
throws IOException 

该方法把响应连同状态码和新网页的位置发送回浏览器,你可以通过把setStatus()和setHeader()方法一起使用来达到同样的效果:

String site = "http://www.runoob.com" ;
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site); 

实例:展示Servlet如何进行网页重定向到另一个位置:

package com.runoob.test;

import java.io.IOException;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class PageRedirect
 */
@WebServlet("/PageRedirect")
public class PageRedirect extends HttpServlet{
    
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html;charset=UTF-8");

      // 要重定向的新位置
      String site = new String("http://www.runoob.com");

      response.setStatus(response.SC_MOVED_TEMPORARILY);
      response.setHeader("Location", site);    
    }
} 

然后配置web.xml,访问接口看到效果。


十六、Servlet点击计数器

很多时候,你很有兴趣知道网站的某个特定页面的总点击量。使用Servlet来计算这些点击量是非常简单的。因为一个Servlet的生命周期是由它运行所在的容器控制的。

一下是实现一个简单的基于Servlet生命周期的网页点击计数器步骤:

  • 在 init() 方法中初始化一个全局变量。

  • 每次调用 doGet() 或 doPost() 方法时,都增加全局变量。

  • 如果需要,您可以使用一个数据库表来存储全局变量的值在 destroy() 中。在下次初始化 Servlet 时,该值可在 init() 方法内被读取。这一步是可选的。

  • 如果您只想对一个 session 会话计数一次页面点击,那么请使用 isNew() 方法来检查该 session 会话是否已点击过相同页面。这一步是可选的。

  • 您可以通过显示全局计数器的值,来在网站上展示页面的总点击量。这一步是可选的。

实例:实现一个简单的网页点击计数器

package com.runoob.test;

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;

/**
 * Servlet implementation class PageHitCounter
 */
@WebServlet("/PageHitCounter")
public class PageHitCounter extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private int hitCount; 
    
    public void init() 
    { 
        // 重置点击计数器
        hitCount = 0;
    } 
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        // 增加 hitCount 
        hitCount++; 
        PrintWriter out = response.getWriter();
        String title = "总点击量";
        String docType = "<!DOCTYPE html> \n";
        out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n" +
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<h2 align=\"center\">" + hitCount + "</h2>\n" +
            "</body></html>");
    }
    
    public void destroy() 
    { 
        // 这一步是可选的,但是如果需要,您可以把 hitCount 的值写入到数据库
    } 

}

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>PageHitCounter</servlet-name>
    <servlet-class>com.runoob.test.PageHitCounter</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>PageHitCounter</servlet-name>
    <url-pattern>/TomcatTest/PageHitCounter</url-pattern>
  </servlet-mapping>
</web-app>

1、网站点击计数器

很多时候,你可能有兴趣知道整个网站的总点击量,在Servlet中,这也是非常简单的,我们使用过滤器做到这一点。

步骤:

  • 在过滤器的 init() 方法中初始化一个全局变量。

  • 每次调用 doFilter 方法时,都增加全局变量。

  • 如果需要,您可以在过滤器的 destroy() 中使用一个数据库表来存储全局变量的值。在下次初始化过滤器时,该值可在 init() 方法内被读取, 这一步是可选的。

在这里,我们假设 Web 容器将无法重新启动。如果是重新启动或 Servlet 被销毁,点击计数器将被重置。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class SiteHitCounter implements Filter{
    
  private int hitCount; 
               
  public void  init(FilterConfig config) 
                    throws ServletException{
     // 重置点击计数器
     hitCount = 0;
  }

  public void  doFilter(ServletRequest request, 
              ServletResponse response,
              FilterChain chain) 
              throws java.io.IOException, ServletException {

      // 把计数器的值增加 1
      hitCount++;

      // 输出计数器
      System.out.println("网站访问统计:"+ hitCount );

      // 把请求传回到过滤器链
      chain.doFilter(request,response);
  }
  public void destroy() 
  { 
      // 这一步是可选的,但是如果需要,您可以把 hitCount 的值写入到数据库
  } 
} 

十七、Servlet自动刷新页面

假设有一个网页,它是显示现场比赛成绩或股票市场状况或货币兑换率。这些所有类型的页面,你需要定期刷新网页。

java Servlet提供了一个机制,使得网页会在给定的时间间隔自动刷新。

刷新网页的最简单的方式是使用响应对象的方法setIntHeader():

public void setIntHeader(String header, int headerValue)

1、自动刷新网页实例

演示Servlet如何使用setIntHeader()方法设置Refresh头信息,从而实现自动刷新页面。

package com.runoob.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;

import java.util.GregorianCalendar;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class Refresh
 */
@WebServlet("/Refresh")
public class Refresh extends HttpServlet {
    private static final long serialVersionUID = 1L;
   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 设置刷新自动加载的事件间隔为 5 秒
        response.setIntHeader("Refresh", 5);
     
        // 设置响应内容类型
        response.setContentType("text/html;charset=UTF-8");
     
        // 获取当前的时间
        Calendar calendar = new GregorianCalendar();
        String am_pm;
        int hour = calendar.get(Calendar.HOUR);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        if(calendar.get(Calendar.AM_PM) == 0)
            am_pm = "AM";
        else
            am_pm = "PM";
     
        String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
        
        PrintWriter out = response.getWriter();
        String title = "使用 Servlet 自动刷新页面";
        String docType = "<!DOCTYPE html> \n";
        out.println(docType +
            "<html>\n" +
            "<head><title>" + title + "</title></head>\n"+
            "<body bgcolor=\"#f0f0f0\">\n" +
            "<h1 align=\"center\">" + title + "</h1>\n" +
            "<p>当前时间是:" + CT + "</p>\n");
    }

}

十八、发送电子邮件

使用Servlet发送一封电子邮件是很简单的,但是首先你必须在你的计算机上安装JavaMail API和Java Activation Framework(JAF)。

  • 您可以从 Java 网站下载最新版本的 JavaMail,打开网页右侧有个 Downloads 链接,点击它下载。

  • 您可以从 Java 网站下载最新版本的 JAF(版本 1.1.1)

1、发送一封简单的电子邮件

// 文件名 SendEmail.java
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
 
public class SendEmail extends HttpServlet{
    
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 收件人的电子邮件 ID
      String to = "abcd@gmail.com";
 
      // 发件人的电子邮件 ID
      String from = "web@gmail.com";
 
      // 假设您是从本地主机发送电子邮件
      String host = "localhost";
 
      // 获取系统的属性
      Properties properties = System.getProperties();
 
      // 设置邮件服务器
      properties.setProperty("mail.smtp.host", host);
 
      // 获取默认的 Session 对象
      Session session = Session.getDefaultInstance(properties);
      
      // 设置响应内容类型
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();

      try{
         // 创建一个默认的 MimeMessage 对象
         MimeMessage message = new MimeMessage(session);
         // 设置 From: header field of the header.
         message.setFrom(new InternetAddress(from));
         // 设置 To: header field of the header.
         message.addRecipient(Message.RecipientType.TO,
                                  new InternetAddress(to));
         // 设置 Subject: header field
         message.setSubject("This is the Subject Line!");
         // 现在设置实际消息
         message.setText("This is actual message");
         // 发送消息
         Transport.send(message);
         String title = "发送电子邮件";
         String res = "成功发送消息...";
         String docType = "<!DOCTYPE html> \n";
         out.println(docType +
         "<html>\n" +
         "<head><title>" + title + "</title></head>\n" +
         "<body bgcolor=\"#f0f0f0\">\n" +
         "<h1 align=\"center\">" + title + "</h1>\n" +
         "<p align=\"center\">" + res + "</p>\n" +
         "</body></html>");
      }catch (MessagingException mex) {
         mex.printStackTrace();
      }
   }
} 

详细的应用当你用到的时候可以自行查阅更加清楚的信息。


十九、Servlet包

涉及到WEB-INF子目录的Web应用程序结构是所有的Java web应用程序的标准,并由Servlet API规范制定。给定一个顶级目录名myapp,目录结构如下:

/myapp
    /images
    /WEB-INF
        /classes
        /lib

WEB-INF子目录中包含应用程序的部署描述符,名为web.xml。所有的HTML文件都位于顶层目录myapp下。对于admin用户,你会发现ROOT目录是myApp的父目录(这个是eclipse上的)。

1、创建包中的Servlet

WEB-INF/classes目录包含了所有的Servlet类和其它类文件。

2、编译、部署就是之前我们一直在做的工作。


二十、调试

测试/调试Servlte始终是开发过程中的难点。Servlet往往涉及大量的客户端/服务器交互,可能会发生错误但又难以重现。所以这里有一些建议。

1、Systeem.out.println()

System.out.println() 是作为一个标记来使用的,用来测试一段特定的代码是否被执行。我们也可以打印出变量的值。此外:

  • 由于 System 对象是核心 Java 对象的一部分,它可以在不需要安装任何额外类的情况下被用于任何地方。这包括 Servlet、JSP、RMI、EJB's、普通的 Beans 和类,以及独立的应用程序。

  • 与在断点处停止不同,写入到 System.out 不会干扰到应用程序的正常执行流程,这使得它在时序是至关重要的时候显得尤为有价值。

2、消息日志

使用适当的日志记录方法来记录所有调试、警告和错误信息,推荐使用log4J来记录所有的消息。

3、当然,也可以调试,使用注解等等。


二十一、国际化

我们先看三个重要术语:

  • 国际化(i18n):这意味着一个网站提供了不同版本的翻译成访问者的语言或国籍的内容。

  • 本地化(l10n):这意味着向网站添加资源,以使其适应特定的地理或文化区域,例如网站翻译成印地文(Hindi)。

  • 区域设置(locale):这是一个特殊的文化或地理区域。它通常指语言符号后跟一个下划线和一个国家符号。例如 "en_US" 表示针对 US 的英语区域设置。

1、检查区域设置

序号方法 & 描述
1String getCountry() 该方法以 2 个大写字母形式的 ISO 3166 格式返回该区域设置的国家/地区代码。
2String getDisplayCountry() 该方法返回适合向用户显示的区域设置的国家的名称。
3String getLanguage() 该方法以小写字母形式的 ISO 639 格式返回该区域设置的语言代码。
4String getDisplayLanguage() 该方法返回适合向用户显示的区域设置的语言的名称。
5String getISO3Country() 该方法返回该区域设置的国家的三个字母缩写。
6String getISO3Language() 该方法返回该区域设置的语言的三个字母的缩写。

 

 

 


JSP教程

JSP与PHP、ASP、ASP.NET等语言类似,运行在服务端的语言。

JSP(全称Java Server Pages)是由Sun Microsystems公司倡导和许多公司参与共同建造的一种使软件开发者可以响应客户端请求,而动态生成HTML、XML或或其它格式文档的Web网页的技术标准。

JSP技术是以java语言作为脚本语言的,JSP网页为整个服务器端的java库单元提供了一个接口来服务于HTTP的应用程序。

JSP文件后缀名为*.jsp,开发的WEB应用可以跨平台使用,既可以运行在Linux上也能运行在Windows上。

来第一个JSP程序

<html>
    <head>
           <title>第一个 JSP 程序</title>
    </head>
    <body>
           <%
                  out.println("Hello World!");
           %>
    </body>
</html>

一、JSP简介

1、什么是Java Server Pages?

JSP全称Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入java代码。标签通常以<%开头,以%>结束。

JSP是一种java servlet,主要用于实现java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。

JSP通过网页表单获取用户输入数据、访问数据库以及其他数据源,然后动态创建网页。

JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。

2、为什么使用JSP?

JSP程序与CGI程序有着相似的功能,但和CGI程序相比,JSP程序有如下优势:

  • 性能更加优越,因为JSP可以直接在HTML网页中动态嵌入元素而不需要单独引用CGI文件。

  • 服务器调用的是已经编译好的JSP文件,而不像CGI/Perl那样必须先载入解释器和目标脚本。

  • JSP 基于Java Servlet API,因此,JSP拥有各种强大的企业级Java API,包括JDBC,JNDI,EJB,JAXP等等。

  • JSP页面可以与处理业务逻辑的 Servlet 一起使用,这种模式被Java servlet 模板引擎所支持。

最后,JSP是Java EE不可或缺的一部分,是一个完整的企业级应用平台。这意味着JSP可以用最简单的方式来实现最复杂的应用。

3、JSP的优势

  • 与ASP相比:JSP有两大优势。首先,动态部分用Java编写,而不是VB或其他MS专用语言,所以更加强大与易用。第二点就是JSP易于移植到非MS平台上。

  • 与纯 Servlet 相比:JSP可以很方便的编写或者修改HTML网页而不用去面对大量的println语句。

  • 与SSI相比:SSI无法使用表单数据、无法进行数据库链接。

  • 与JavaScript相比:虽然JavaScript可以在客户端动态生成HTML,但是很难与服务器交互,因此不能提供复杂的服务,比如访问数据库和图像处理等等。

  • 与静态HTML相比:静态HTML不包含动态信息。


二、开发环境搭建

这里的话其实也就是配置好java的开发环境就好,如果你需要在eclipse里面配置环境,可以搜索相关的教程,如果是IEDA就好很多。

但这里在列出一下Tomcat的目录结构回忆一下:

 

  • bin:二进制执行文件。里面最常用的文件是startup.bat,如果是 Linux 或 Mac 系统启动文件为 startup.sh

  • conf:配置目录。里面最核心的文件是server.xml。可以在里面改端口号等。默认端口号是8080,也就是说,此端口号不能被其他应用程序占用。

  • lib:库文件。tomcat运行时需要的jar包所在的目录

  • logs:日志

  • temp:临时产生的文件,即缓存

  • webapps:web的应用程序。web应用放置到此目录下浏览器可以直接访问

  • work:编译以后的class文件。


三、JSP结构

网络服务器需要一个JSP引擎,也就是一个容器来处理JSP页面。容器负责截获对JSP页面的请求。JSP容器与Web服务器协同合作,为JSP的正常运行提供必要的运行环境和其它服务,并且能够正确识别专属于JSP网页的特殊元素。

 

1、JSP处理

Web服务器是如何使用JSP来创建网页的:

  • 就像其他普通的网页一样,您的浏览器发送一个 HTTP 请求给服务器。

  • Web 服务器识别出这是一个对 JSP 网页的请求,并且将该请求传递给 JSP 引擎。通过使用 URL或者 .jsp 文件来完成。

  • JSP 引擎从磁盘中载入 JSP 文件,然后将它们转化为 Servlet。这种转化只是简单地将所有模板文本改用 println() 语句,并且将所有的 JSP 元素转化成 Java 代码。

  • JSP 引擎将 Servlet 编译成可执行类,并且将原始请求传递给 Servlet 引擎。

  • Web 服务器的某组件将会调用 Servlet 引擎,然后载入并执行 Servlet 类。在执行过程中,Servlet 产生 HTML 格式的输出并将其内嵌于 HTTP response 中上交给 Web 服务器。

  • Web 服务器以静态 HTML 网页的形式将 HTTP response 返回到您的浏览器中。

  • 最终,Web 浏览器处理 HTTP response 中动态产生的HTML网页,就好像在处理静态网页一样。

 

一般情况下,JSP引擎会检查JSP文件对应的Servlet是否已经存在,并且检查JSP文件的修改日期是否早于Servlet。如果JSP文件的修改日期早于对应的Servlet,那么容器就可以确定JSP文件没有被修改过并且Servlet有效。这使得整个流程与其它脚本语言(比如PHP)相比要高效快捷一些。

总的来说,JSP网页就是用另一种方式来编写Servlet而不用成为java编程高手。除了解释阶段外,JSP网页几乎可以被当成一个普通的Servlet来对待。


四、JSP生命周期

理解JSP底层功能的关键就是去理解它们所遵循的生命周期。

JSP生命周期就是从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成servlet。

  • 编译阶段:

    servlet容器编译servlet源文件,生成servlet类

  • 初始化阶段:

    加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法

  • 执行阶段:

    调用与JSP对应的servlet实例的服务方法

  • 销毁阶段:

    调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例

1、JSP编译

当浏览器请求JSP页面时,JSP引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个JSP文件。

编译的过程包括三个步骤:

  • 解析JSP文件。

  • 将JSP文件转为servlet。

  • 编译servlet。

2、JSP初始化

容器载入JSP文件后,它会在为请求提供任何服务前调用jspInit()方法。如果你需要执行自定义的JSP初始化任务,复写jspInit()方法就行:

public void jspInit(){
  // 初始化代码
}

一般来讲程序只初始化依次,servlet也是如此。通常情况下你可以在jspInit()方法中初始化数据库连接、打开文件和创建查询表。

3、JSP执行

这一阶段描述了JSP生命周期中一切与请求相关的交互行为,知道被销毁。

当JSP网页完成初始化后,JSP引擎会调用_jspService()方法。

_jspService()方法需要一个HttpServletRequest对象和一个HttpServletResponse对象作为它的参数,就像下面这样:

void _jspService(HttpServletRequest request,
                 HttpServletResponse response)
{
   // 服务端处理代码
}

_jspService()方法在每个request中被调用一次并且负责产生与之对象的response,并且它还负责产生所有7个HTTP方法的回应,比如GET、POST、DELETE等等。

4、JSP清理

JSP生命周期的销毁阶段描述了当一个JSP网页从容器中被移除时发生的一切。

jspDestroy()方法在JSP中等价于servlet中的销毁方法。当你需要执行任何清理工作时复写jspDestroy()方法,比如释放数据库连接或者关闭文件夹等等。

public void jspDestroy()
{
   // 清理代码
}

5、实例

JSP生命周期代码实例:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<title>life.jsp</title>
</head>
<body>

<%! 
  private int initVar=0;
  private int serviceVar=0;
  private int destroyVar=0;
%>
  
<%!
  public void jspInit(){
    initVar++;
    System.out.println("jspInit(): JSP被初始化了"+initVar+"次");
  }
  public void jspDestroy(){
    destroyVar++;
    System.out.println("jspDestroy(): JSP被销毁了"+destroyVar+"次");
  }
%>

<%
  serviceVar++;
  System.out.println("_jspService(): JSP共响应了"+serviceVar+"次请求");

  String content1="初始化次数 : "+initVar;
  String content2="响应客户请求次数 : "+serviceVar;
  String content3="销毁次数 : "+destroyVar;
%>
<h1>菜鸟教程 JSP 测试实例</h1>
<p><%=content1 %></p>
<p><%=content2 %></p>
<p><%=content3 %></p>

</body>
</html>

五、JSP语法

1、脚本程序

脚本程序可以包含任意量的Java语句、变量、方法或表达式,只要它们在脚本语言中是有效的。

脚本程序的语法格式:

<% 代码片段 %>

或者,你也可以编写与其等价的XML语句,就像这样:

<jsp:scriptlet>
   代码片段
</jsp:scriptlet>

任何文本、HTML标签、JSP元素必须写在脚本程序的外面:

<html>
<head><title>Hello World</title></head>
<body>
Hello World!<br/>
<%
out.println("Your IP address is " + request.getRemoteAddr());
%>
</body>
</html>

2、中文编码问题

如果我们要在页面正常显示中文,我们需要在JSP文件头部添加以下代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

3、JSP声明

一个声明语法可以声明一个或多个变量、方法,供后面的Java代码使用。在JSP文件中,你必须先声明这些变量和方法然后才能使用它们。

JSP声明的语法格式:

<%! declaration;[declaration; ]+...%>

或者你也可以编写与其等价的XML语句:

<jsp:declaration>
   代码片段
</jsp:declaration>

示例:

<%! int i = 0; %> 
<%! int a, b, c; %> 
<%! Circle a = new Circle(2.0); %> 

4、JSP表达式

一个JSP表达式中包含的脚本语言表达式,先被转换成String,然后插入到表达式出现的地方。

由于表达式的值会被转化成String,所以你可以在一个文本行中使用表达式而不用去管它是否是HTML标签。

表达式元素中可以包含任何符合Java语言规范的表达式,但是不能使用分号来结束表达式。

JSP表达式的语法格式:

<%=表达式 %>

程序示例:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<p>
   今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
</body> 
</html> 

运行后得到:

今天的日期是:2020-6-3 13:40:07

5、JSP注释

JSP注释主要有两个作用:为代码作注释以及将某段代码注释掉。

JSP注释的语法格式:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<%-- 该部分注释在网页中不会被显示--%> 
<p>
   今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>
</body> 
</html> 
语法描述
<%-- 注释 --%>JSP注释,注释内容不会被发送至浏览器甚至不会被编译
<!-- 注释 -->HTML注释,通过浏览器查看网页源代码时可以看见注释内容
<\%代表静态 <%常量
%>代表静态 %> 常量
'在属性中使用的单引号
"在属性中使用的双引号

6、JSP指令

JSP指令用来设置与整个JSP页面相关的属性。

JSP指令语法格式:

<%@ directive attribute="value"%>

这里有三种指令标签:

指令描述
<%@ page ... %>定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include ... %>包含其他文件
<%@ taglib ... %>引入标签库的定义,可以是自定义标签

7、JSP行为

JSP行为标签使用XML语法结构来控制servlet引擎。它能动态插入一个文本,重用JavaBean组件,引导用户去另一个界面,为Java插件产生相关的HTML等等。

行为标签只有一种语法格式,为:

<jsp:action_name attribute="value" />

行为标签基本上是一些预先就定义好的函数,下标罗列了一些可用的JSP行为标签:

语法描述
jsp:include用于在当前页面中包含静态或动态资源
jsp:useBean寻找和初始化一个JavaBean组件
jsp:setProperty设置 JavaBean组件的值
jsp:getProperty将 JavaBean组件的值插入到 output中
jsp:forward从一个JSP文件向另一个文件传递一个包含用户请求的request对象
jsp:plugin用于在生成的HTML页面中包含Applet和JavaBean对象
jsp:element动态创建一个XML元素
jsp:attribute定义动态创建的XML元素的属性
jsp:body定义动态创建的XML元素的主体
jsp:text用于封装模板数据

8、JSP隐含对象

JSP支持九个自动定义的内联,称为隐含对象:

对象描述
requestHttpServletRequest类的实例
responseHttpServletResponse类的实例
outPrintWriter类的实例,用于把结果输出至网页上
sessionHttpSession类的实例
applicationServletContext类的实例,与应用上下文有关
configServletConfig类的实例
pageContextPageContext类的实例,提供对JSP页面所有对象以及命名空间的访问
page类似于Java类中的this关键字
ExceptionException类的对象,代表发生错误的JSP页面中对应的异常对象

9、控制流语句

JSP提供对java语言的全面支持,所以这里我们就看看具体是怎么使用的。

1)判断语句:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%! int day = 3; %> 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h3>IF...ELSE 实例</h3>
<% if (day == 1 | day == 7) { %>
      <p>今天是周末</p>
<% } else { %>
      <p>今天不是周末</p>
<% } %>
</body> 
</html> 

2)For循环实例

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%! int fontSize=0; %> 
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h3>While 循环实例</h3>
<%while ( fontSize <= 3){ %>
   <font color="green" size="<%= fontSize %>">
    菜鸟教程
   </font><br />
<%fontSize++;%>
<%}%>
</body> 
</html> 

10、运算符和字面量

JSP运算符和java是一致的,字面量也就是:

  • 布尔值(boolean):true 和 false;

  • 整型(int):与 Java 中的一样;

  • 浮点型(float):与 Java 中的一样;

  • 字符串(string):以单引号或双引号开始和结束;

  • Null:null。


六、JSP指令

JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言。

语法格式:

<%@ directive attribute="value" %>

指令可以有很多个属性,它们以键值对的形式存在,并用逗号隔开。

JSP中的三种指令标签:

指令描述
<%@ page ... %>定义网页依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include ... %>包含其他文件
<%@ taglib ... %>引入标签库的定义

1、Page指令

Page指令为容器提供当前页面的使用说明。一个JSP页面可以包含很多个page指令。

语法格式:

<%@ page attribute="value" %>

1)属性

属性描述
buffer指定out对象使用缓冲区的大小
autoFlush控制out对象的 缓存区
contentType指定当前JSP页面的MIME类型和字符编码
errorPage指定当JSP页面发生异常时需要转向的错误处理页面
isErrorPage指定当前页面是否可以作为另一个JSP页面的错误处理页面
extends指定servlet从哪一个类继承
import导入要使用的Java类
info定义JSP页面的描述信息
isThreadSafe指定对JSP页面的访问是否为线程安全
language定义JSP页面所用的脚本语言,默认是Java
session指定JSP页面是否使用session
isELIgnored指定是否执行EL表达式
isScriptingEnabled确定脚本元素能否被使用

2、Include指令

JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分,会被同时编译执行。

Include指令的语法格式:

<%@ include file="文件相对 url 地址" %>

3、Taglib指令

JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。

Taglib指令引入一个自定义标签集合的定义,包括库路径、自定义标签。

Taglib指令的语法:

<%@ taglib uri="uri" prefix="prefixOfTag" %>

uri属性确定标签库的位置,prefix属性指定标签库的前缀。

等价的XML语法:

<jsp:directive.taglib uri="uri" prefix="prefixOfTag" />

七、JSP动作元素

与JSP指令元素不同的是,JSP动作元素在请求处理阶段起作用。JSP动作元素是用XML语法写的。

利用JSP动作可以动态地插入文件、重用JavaBean组件、把用户重定向到另外的页面、为Java插件生成HTML代码。

语法:

<jsp:action_name attribute="value" />

动作元素基本都是预定义的函数,JSP规范定义了一系列的标准动作,它用JSP作为前缀,可用的标准动作元素如下:

语法描述
jsp:include在页面被请求的时候引入一个文件。
jsp:useBean寻找或者实例化一个JavaBean。
jsp:setProperty设置JavaBean的属性。
jsp:getProperty输出某个JavaBean的属性。
jsp:forward把请求转到一个新的页面。
jsp:plugin根据浏览器类型为Java插件生成OBJECT或EMBED标记。
jsp:element定义动态XML元素
jsp:attribute设置动态定义的XML元素属性。
jsp:body设置动态定义的XML元素内容。
jsp:text在JSP页面和文档中使用写入文本的模板

1、常见的属性

所有的动作要素都有两个属性:id属性和scope属性。

  • id属性:

    id属性是动作元素的唯一标识,可以在JSP页面中引用。动作元素创建的id值可以通过PageContext来调用。

     

  • scope属性:

    该属性用于识别动作元素的生命周期。 id属性和scope属性有直接关系,scope属性定义了相关联id对象的寿命。 scope属性有四个可能的值: (a) page, (b)request, (c)session, 和 (d) application。

2、<jsp:include>动作元素

<jsp:include>动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下:

<jsp:include page="相对 URL 地址"flush="true" />

include指令是在JSP文件被转换成Servlet的时候引入文件,而这里的jsp:include动作不同,插入文件的时间是在页面被请求的时候。

属性:

属性描述
page包含在页面中的相对URL地址。
flush布尔属性,定义在包含资源前是否刷新缓存区

实例:

有date.jsp文件代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<p>
   今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>

有main.jsp文件代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>

<h2>include 动作实例</h2>
<jsp:include page="date.jsp" flush="true" />

</body>
</html>

3、<jsp:useBean>动作元素

jsp:useBean动作用来加载一个将在JSP页面中使用的JavaBean。

这个功能非常有用,因为它使得我们可以发挥Java组件复用的优势。

jsp:userBean动作最简单的语法为:

<jsp:useBean id="name" class="package.class" />

在类载入后,我们就可以通过jsp:setProperty和jsp:getProperty来修改和检索bean的属性。

属性描述
class指定Bean的完整包名。
type指定将引用该对象变量的类型。
beanName通过 java.beans.Beans 的 instantiate() 方法指定Bean的名字。

4、<jsp:setProperty>动作元素

jsp:setProperty用来设置已经实例化的Bean对象的属性,有两种用法。首先,你可以在jsp:useBean元素的外面(后面)使用jsp:setProperty,如下所示:

<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="someProperty" .../>

此时,不管jsp:useBean是找到了一个现有的Bean,还是新建了一个Bean实例,jsp:setProperty都会执行。

第二种用法是把jsp:setProperty放入jap:useBean元素的内部,如下:

<jsp:useBean id="myName" ... >
...
   <jsp:setProperty name="myName" property="someProperty" .../>
</jsp:useBean>

此时,jsp:setProperty只有在新建Bean实例时才会执行,如果是使用现有实例则不执行jsp:setProperty。

jsp:setProperty动作有四个属性:

属性描述
namename属性是必需的。它表示要设置属性的是哪个Bean。
propertyproperty属性是必需的。它表示要设置哪个属性。有一个特殊用法:如果property的值是"*",表示所有名字和Bean属性名字匹配的请求参数都将被传递给相应的属性set方法。
valuevalue 属性是可选的。该属性用来指定Bean属性的值。字符串数据会在目标类中通过标准的valueOf方法自动转换成数字、boolean、Boolean、 byte、Byte、char、Character。例如,boolean和Boolean类型的属性值(比如"true")通过 Boolean.valueOf转换,int和Integer类型的属性值(比如"42")通过Integer.valueOf转换。   value和param不能同时使用,但可以使用其中任意一个。
paramparam 是可选的。它指定用哪个请求参数作为Bean属性的值。如果当前请求没有参数,则什么事情也不做,系统不会把null传递给Bean属性的set方法。因此,你可以让Bean自己提供默认属性值,只有当请求参数明确指定了新值时才修改默认属性值。

5、<jsp:getProperty>动作元素

jsp:getProperty动作提取指定Bean属性的值,转换成字符串,然后输出。语法格式如下:

<jsp:useBean id="myName" ... />
...
<jsp:getProperty name="myName" property="someProperty" .../>

getProperty属性:

属性描述
name要检索的Bean属性名称。Bean必须已定义。
property表示要提取Bean属性的值

6、<jsp:forward>动作元素

jsp:forward动作把请求转到另外的页面。jsp:forward标记只有一个属性page。语法格式如下:

<jsp:forward page="相对 URL 地址" />
属性描述
pagepage属性包含的是一个相对URL。page的值既可以直接给出,也可以在请求的时候动态计算,可以是一个JSP页面或者一个 Java Servlet.

7、<jsp:plugin>动作元素

jsp:plugin动作用来根据浏览器的类型,插入通过java插件运行Java Applet所必需的OBJECT或EMBED元素。如果需要的插件不存在,它会下载插件,然后执行Java组件。Java组件可以是一个applet或一个JavaBean。plugin动作有多个对应HTML元素的属性用于格式化Java组件。param元素可用于向Applet或Bean传递参数。

例如:

<jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
                           width="60" height="80">
   <jsp:param name="fontcolor" value="red" />
   <jsp:param name="background" value="black" />
 
   <jsp:fallback>
      Unable to initialize Java Plugin
   </jsp:fallback>
 
</jsp:plugin>

8、<jsp:element><jap:attribute><jsp:body>动作元素

<jsp:element><jap:attribute><jsp:body>动作元素动态定义XML元素。动态是非常重要的,这就意味着XML元素在编译时是动态生成的而非静态。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<jsp:element name="xmlElement">
<jsp:attribute name="xmlElementAttr">
   属性值
</jsp:attribute>
<jsp:body>
   XML 元素的主体
</jsp:body>
</jsp:element>
</body>
</html>

9、<jsp:text>动作元素

<jsp:text>动作元素允许在JSP页面和文档中使用写入文本的模板,语法格式如下:

<jsp:text>模板数据</jsp:text>

以上文本模板不能包含重复元素,只能包含文本和EL表达式。请注意,在XML文件中,你不能使用表达式如${whatever>0},因为>符号是非法的。你可以使用${wharever gt 0}表达式或者嵌入一个在CDATA部分的值。

<jsp:text><![CDATA[<br>]]></jsp:text>

如果你需要在XHTML中声明DOCTYPPE,必须使用到<jsp:text>动作元素,实例如下:

<jsp:text><![CDATA[<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">]]>
</jsp:text>
<head><title>jsp:text action</title></head>
<body>

<books><book><jsp:text>  
    Welcome to JSP Programming
</jsp:text></book></books>

</body>
</html>

八、JSP隐式对象

JSP隐式对象是JSP容器为每个页面提供的java对象,开发者可以直接使用它们而不用显示声明。JSP隐式对象也被称为预定义变量。

JSP所支持的九大隐式对象:

对象描述
requestHttpServletRequest 接口的实例
responseHttpServletResponse 接口的实例
outJspWriter类的实例,用于把结果输出至网页上
sessionHttpSession类的实例
applicationServletContext类的实例,与应用上下文有关
configServletConfig类的实例
pageContextPageContext类的实例,提供对JSP页面所有对象以及命名空间的访问
page类似于Java类中的this关键字
ExceptionException类的对象,代表发生错误的JSP页面中对应的异常对象

九、JSP客户端请求

当浏览器请求一个网页时,它会向服务器发送一系列不能被直接读取的信息,因为这些信息是作为HTTP信息头的一部分来传送的。

信息描述
Accept指定浏览器或其他客户端可以处理的MIME类型。它的值通常为 image/pngimage/jpeg
Accept-Charset指定浏览器要使用的字符集。比如 ISO-8859-1
Accept-Encoding指定编码类型。它的值通常为 gzipcompress
Accept-Language指定客户端首选语言,servlet会优先返回以当前语言构成的结果集,如果servlet支持这种语言的话。比如 en,en-us,ru等等
Authorization在访问受密码保护的网页时识别不同的用户
Connection表明客户端是否可以处理HTTP持久连接。持久连接允许客户端或浏览器在一个请求中获取多个文件。Keep-Alive 表示启用持久连接
Content-Length仅适用于POST请求,表示 POST 数据的字节数
Cookie返回先前发送给浏览器的cookies至服务器
Host指出原始URL中的主机名和端口号
If-Modified-Since表明只有当网页在指定的日期被修改后客户端才需要这个网页。 服务器发送304码给客户端,表示没有更新的资源
If-Unmodified-Since与If-Modified-Since相反, 只有文档在指定日期后仍未被修改过,操作才会成功
Referer标志着所引用页面的URL。比如,如果你在页面1,然后点了个链接至页面2,那么页面1的URL就会包含在浏览器请求页面2的信息头中
User-Agent用来区分不同浏览器或客户端发送的请求,并对不同类型的浏览器返回不同的内容

至于其中的HttpServletRequest类与HTTP信息头与servlet是一致的。


十、服务器响应

Response响应对象主要将JSP容器处理后的结果传回到客户端。可以通过response变量设置HTTP的状态和向客户端发送数据,如Cookie、HTTP文件头信息。

其中响应头、HttpServletResponse类都是和servlet一样的,这里我们看看HTTP响应头程序示例:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h2>自动刷新实例</h2>
<%
   // 设置每隔5秒自动刷新
   response.setIntHeader("Refresh", 5);
   // 获取当前时间
   Calendar calendar = new GregorianCalendar();
   String am_pm;
   int hour = calendar.get(Calendar.HOUR);
   int minute = calendar.get(Calendar.MINUTE);
   int second = calendar.get(Calendar.SECOND);
   if(calendar.get(Calendar.AM_PM) == 0)
      am_pm = "AM";
   else
      am_pm = "PM";
   String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
   out.println("当前时间: " + CT + "\n");
%>
</body>
</html>

 

     HTTP状态码、表单处理、过滤器、Cookie处理、Session、文件上传、日期处理、页面重定向、点击量统计、自动刷新、发送邮件等部分和servlet是一致的,只是代码部分符合的是JSP语法规则而已。


十一、JSP标准标签库(JSTL)

JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的核心功能。

JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。

根据JSTL标签所提供的功能,可以将其分为5个类别:

  • 核心标签

  • 格式化标签

  • SQL 标签

  • XML 标签

  • JSTL 函数

1、JSTL库安装

Apache Tomcat安装JSTL库步骤如下:

从Apache的标准标签库中下载的二进包(jakarta-taglibs-standard-current.zip)。解压之后,将jakarta-taglibs-standard-1.1.2/lib下的两个jar文件:standard.jar和jstl.jar文件拷贝到/WEB-INF/lib下。配置web.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <jsp-config>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
    <taglib-location>/WEB-INF/fmt.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/fmt-rt</taglib-uri>
    <taglib-location>/WEB-INF/fmt-rt.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
    <taglib-location>/WEB-INF/c.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/core-rt</taglib-uri>
    <taglib-location>/WEB-INF/c-rt.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/sql</taglib-uri>
    <taglib-location>/WEB-INF/sql.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/sql-rt</taglib-uri>
    <taglib-location>/WEB-INF/sql-rt.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/x</taglib-uri>
    <taglib-location>/WEB-INF/x.tld</taglib-location>
    </taglib>
    <taglib>
    <taglib-uri>http://java.sun.com/jsp/jstl/x-rt</taglib-uri>
    <taglib-location>/WEB-INF/x-rt.tld</taglib-location>
    </taglib>
    </jsp-config>
</web-app>

使用任何库,你必须在每个JSP文件中的头部包含<taglib>标签。

2、核心标签

核心标签是最常用的JSTL标签。引用核心标签库的语法如下:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
标签描述
<c:out>用于在JSP中显示数据,就像<%=...>
<c:set>用于保存数据
<c:remove>用于删除数据
<c:catch>用来处理产生错误的异常状况,并且将错误信息存储起来
<c:if>与我们一般程序中用的if一样
<c:choose>本身值当做<c:when><c:otherwise>的父标签
<c:when><c:choose>的字标签,用来判断条件是否成立
<c:ohterwise><c:choose>的字标签,接在<c:when>标签判断为false时被执行
<c:import>检索一个绝对或相对URL,然后将其内容暴露给页面
<c:forEach>基础迭代标签,接受多种结合类型
<c:forTokens>根据指定的分隔符来分隔内容并迭代输出
<c:param>用来给包含或重定向的页面传递参数
<c:redirect>重定向至一个新的URL
<c:url>使用可选的查询参数来创造一个URL

3、格式化标签

JSTL格式化标签用来格式化并输出文本、日期、时间、数字。引用格式化标签库的语法如下:

%@ taglib prefix="fmt" 
           uri="http://java.sun.com/jsp/jstl/fmt" %>
标签描述
<fmt:formatNumber>使用指定的格式或精度格式化数字
<fmt:parseNumber>解析一个代表着数字,货币或百分比的字符串
<fmt:formatDate>使用指定的风格或模式格式化日期和时间
<fmt:parseDate>解析一个代表着日期或时间的字符串
<fmt:bundle>绑定资源
<fmt:setLocale>指定地区
<fmt:setBundle>绑定资源
<fmt:timeZone>指定时区
<fmt:setTimeZone>指定时区
<fmt:message>显示资源配置文件信息
<fmt:requestEncoding>设置request的字符编码

4、SQL标签。

JSTL SQL标签库提桶了与关系型数据库(Oracle,MySQL,SQL Server等等)进行交互的标签。引用SQL标签库的语法如下:

<%@ taglib prefix="sql" 
           uri="http://java.sun.com/jsp/jstl/sql" %>
标签描述
<sql:setDataSource>指定数据源
<sql:query>运行SQL查询语句
<sql:update>运行SQL更新语句
<sql:param>将SQL语句中的参数设为指定值
<sql:dateParam>将SQL语句中的日期参数设为指定的java.util.Date 对象值
<sql:ransaction>在共享数据库连接中提供嵌套的数据库行为元素,将所有语句以一个事务的形式来运行

5、XML标签

JSTL XML标签库提供了创建和操作XML文档的标签。引用XML标签库的语法如下:

<%@ taglib prefix="x" 
           uri="http://java.sun.com/jsp/jstl/xml" %>
x:out与<%= ... >,类似,不过只用于XPath表达式
x:parse解析 XML 数据
x:set设置XPath表达式
x:if判断XPath表达式,若为真,则执行本体中的内容,否则跳过本体
x:forEach迭代XML文档中的节点
x:choosex:when和x:otherwise的父标签
x:whenx:choose的子标签,用来进行条件判断
x:otherwisex:choose的子标签,当x:when判断为false时被执行
x:transform将XSL转换应用在XML文档中
x:param与x:transform共同使用,用于设置XSL样式表

6、JSTL函数

JSTL包含一系列标准函数,大部分是通用的字符串处理函数。引用JSTL函数库的语法如下:

<%@ taglib prefix="fn" 
           uri="http://java.sun.com/jsp/jstl/functions" %>
函数描述
fn:contains()测试输入的字符串是否包含指定的子串
fn:containsIgnoreCase()测试输入的字符串是否包含指定的子串,大小写不敏感
fn:endsWith()测试输入的字符串是否以指定的后缀结尾
fn:escapeXml()跳过可以作为XML标记的字符
fn:indexOf()返回指定字符串在输入字符串中出现的位置
fn:join()将数组中的元素合成一个字符串然后输出
fn:length()返回字符串长度
fn:replace()将输入字符串中指定的位置替换为指定的字符串然后返回
fn:split()将字符串用指定的分隔符分隔然后组成一个子字符串数组并返回
fn:startsWith()测试输入字符串是否以指定的前缀开始
fn:substring()返回字符串的子集
fn:substringAfter()返回字符串在指定子串之后的子集
fn:substringBefore()返回字符串在指定子串之前的子集
fn:toLowerCase()将字符串中的字符转为小写
fn:toUpperCase()将字符串中的字符转为大写
fn:trim()移除首尾的空白符

十二、JavaBean

JavaBean是特殊的Java类,使用Java语言书写,并遵守JavaBean API规范。与其它java类相比,JavaBean:

  • 提供一个默认的无参构造函数。

  • 需要被序列化并且实现了 Serializable 接口。

  • 可能有一系列可读写属性。

  • 可能有一系列的 getter 或 setter 方法。

1、JavaBean属性

一个JavaBean对象的属性应该是可访问的。这个属性可以是任意合法的java数据类型,包括自定义java类。

一个JavaBean对象的属性可以是可读写,或只读,或只写。JavaBean对象的属性通过JavaBean实现类中提供的两个方法来访问:

方法描述
getPropertyName()举例来说,如果属性的名称为 myName,那么这个方法的名字就要写成 getMyName() 来读取这个属性。这个方法也称为访问器。
setPropertyName()举例来说,如果属性的名称为 myName,那么这个方法的名字就要写成 setMyName()来写入这个属性。这个方法也称为写入器。

一个只读的属性只提供getPropertyName()方法,一个只写的属性只提供setPropertyName()方法。

2、JavaBean程序示例

package com.runoob;
​
public class StudentsBean implements java.io.Serializable
{
   private String firstName = null;
   private String lastName = null;
   private int age = 0;
​
   public StudentsBean() {
   }
   public String getFirstName(){
      return firstName;
   }
   public String getLastName(){
      return lastName;
   }
   public int getAge(){
      return age;
   }
​
   public void setFirstName(String firstName){
      this.firstName = firstName;
   }
   public void setLastName(String lastName){
      this.lastName = lastName;
   }
   public void setAge(int age) {
      this.age = age;
   }
}

3、访问JavaBean

<jsp:useBean>标签可以在JSP中声明一个JavaBean,然后使用。声明后,JavaBean对象就变成了脚本变量,可以通过脚本元素或其它自定义标签来访问。语法格式:

<jsp:useBean id="bean 的名字" scope="bean 的作用域" typeSpec/>

其中,根据具体情况,scope的值可以是page,request,session或application。id值可以任意只要不和同一JSP文件的其它id值一样就行。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<title>useBean 实例</title>
</head>
<body>
​
<jsp:useBean id="date" class="java.util.Date" /> 
<p>日期为:<%= date %>
​
</body>
</html>

4、访问JavaBean对象的属性

<jsp:useBean>标签主题中使用<jsp:getProperty/>标签来调用getter方法,使用<jsp:setProperty/>标签来调用setter方法,语法格式:

<jsp:useBean id="id" class="bean 编译的类" scope="bean 作用域">
   <jsp:setProperty name="bean 的 id" property="属性名"  
                    value="value"/>
   <jsp:getProperty name="bean 的 id" property="属性名"/>
   ...........
</jsp:useBean>

十三、JSP自定义标签

自定义标签是用户定义的JSP语言元素。当JSP页面包含一个自定义标签时将被转化为servlet,标签转化为对tag handler的对象的操作,即当servlet执行时Web container调用那些操作。

JSP标签扩展可以让你创建新的标签并且可以直接插入到一个JSP页面。你可以继承SimpleTagSupport类并重写doTag()方法来开发一个最简单的自定义标签。

1、创建“Hello”标签

标签格式为:

<ex:Hello />

要创建自定义的JSP标签,首先必须创建处理标签的java类,所以我们创建一个HelloTag类:

package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

  public void doTag() throws JspException, IOException {
    JspWriter out = getJspContext().getOut();
    out.println("Hello Custom Tag!");
  }
}

最后创建标签库:<Tomcat安装目录>webapps\ROOT\WEB-INF\custom.tld。

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.runoob.HelloTag</tag-class>
    <body-content>empty</body-content>
  </tag>
</taglib>

之后就可以使用了:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello/>
  </body>
</html>

十四、表达式语言

JSP表达式语言(EL)使得访问存储在JavaBean中的数据变得非常简单。JSP EL既可以用来创建算数表达式,也可以用来创建逻辑表达式。在JSP EL表达式内可以使用整形术、浮点数、字符串、常量true、false、还有null。

1、一个简单的语法:

典型的,当你需要在JSP标签中指定一个属性值时,只需要简单的使用字符串接口:

<jsp:setProperty name="box" property="perimeter" value="100"/>

JSP EL允许你指定一个表达式来表示属性值,一个简单的语法如下:

${expr}

其中,expr指的是表达式。在JSP EL中通用的操作符是.和{}。这两个操作符允许你通过内嵌的JSP对象访问各种各样的JavaBean属性。

例如:上面的<jsp:setProperty>标签可以使用表达式语言改写成如下形式:

<jsp:setProperty name="box" property="perimeter" 
                 value="${2*box.width+2*box.height}"/>

当JSP编译器在属性中见到“${}”格式后,它会产生代码来计算这个表达式。

你也可以在标签的末班文本中使用表达式语言,比如<jsp:text>标签简单的将其主体中的文本插入到JSP输出中:

<jsp:text>
<h1>Hello JSP!</h1>
</jsp:text>

现在,在<jsp:text>标签主体使用表达式:

<jsp:text>
Box Perimeter is: ${2*box.width + 2*box.height}
</jsp:text>

想要停止对EL表达式的评估,需要使用page执行将isELlgnored属性值设为true:

<%@ page isELIgnored ="true|false" %>

2、EL中的基本操作符

操作符描述
.访问一个Bean属性或者一个映射条目
[]访问一个数组或者链表的元素
( )组织一个子表达式以改变优先级
+
-减或负
*
/ or div
% or mod取模
== or eq测试是否相等
!= or ne测试是否不等
< or lt测试是否小于
> or gt测试是否大于
<= or le测试是否小于等于
>= or ge测试是否大于等于
&& or and测试逻辑与
|| or or测试逻辑或
! or not测试取反
empty测试是否空值

3、JSP EL中的函数

JSP EL允许你在表达式中使用函数,这些函数必须被定义在自定义标签库中:

${ns:func(param1, param2, ...)}

ns指的是命名空间(namespace),func指的是函数的名称,param1指的是第一个参数,param2指的是第二个参数,以此类推。比如,有函数fn:length,在JSTL库中定义,可以像下面这样来获取一个字符串的长度:

${fn:length("Get my length")}

4、JSP EL隐含对象

隐含对象描述
pageScopepage 作用域
requestScoperequest 作用域
sessionScopesession 作用域
applicationScopeapplication 作用域
paramRequest 对象的参数,字符串
paramValuesRequest对象的参数,字符串集合
headerHTTP 信息头,字符串
headerValuesHTTP 信息头,字符串集合
initParam上下文初始化参数
cookieCookie值
pageContext当前页面的pageContext

十五、JSP异常处理

1、使用Exception对象

序号方法**&描述**
1public String getMessage()返回异常的信息。这个信息在Throwable构造函数中被初始化
2public ThrowablegetCause()返回引起异常的原因,类型为Throwable对象
3public String toString()返回类名
4public void printStackTrace()将异常栈轨迹输出至System.err
5public StackTraceElement [] getStackTrace()以栈轨迹元素数组的形式返回异常栈轨迹
6public ThrowablefillInStackTrace()使用当前栈轨迹填充Throwable对象
<%@ page errorPage="ShowError.jsp" %>

<html>
<head>
   <title>Error Handling Example</title>
</head>
<body>
<%
   // Throw an exception to invoke the error page
   int x = 1;
   if (x == 1)
   {
      throw new RuntimeException("Error condition!!!");
   }
%>
</body>
</html>

2、在错误页面中使用JSTL标签

可以利用JSTL标签来编写错误页面。

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isErrorPage="true" %>
<html>
<head>
<title>Show Error Page</title>
</head>
<body>
<h1>Opps...</h1>
<table width="100%" border="1">
<tr valign="top">
<td width="40%"><b>Error:</b></td>
<td>${pageContext.exception}</td>
</tr>
<tr valign="top">
<td><b>URI:</b></td>
<td>${pageContext.errorData.requestURI}</td>
</tr>
<tr valign="top">
<td><b>Status code:</b></td>
<td>${pageContext.errorData.statusCode}</td>
</tr>
<tr valign="top">
<td><b>Stack trace:</b></td>
<td>
<c:forEach var="trace" 
         items="${pageContext.exception.stackTrace}">
<p>${trace}</p>
</c:forEach>
</td>
</tr>
</table>
</body>
</html>

3、使用try...catch块

<html>
<head>
   <title>Try...Catch Example</title>
</head>
<body>
<%
   try{
      int i = 1;
      i = i / 0;
      out.println("The answer is " + i);
   }
   catch (Exception e){
      out.println("An exception occurred: " + e.getMessage());
   }
%>
</body>
</html>

十六、调试、国际化:与servlet一致。


后记:

     本篇博客侧重基础,没有个人的思考。要先有基础,才能更好地思考呀~~~冲冲冲

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐