Servlet基础

Servlet

Servlet 为创建基于 web 的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI 程序的性能限制。Servlet 有权限访问所有的 Java API,包括访问企业级数据库的 JDBC API。

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

Servlet 的优势

通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序效果相当。但是相比于 CGI,Servlet 有以下几点优势:

  1. 性能明显更好。
  2. Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
  3. Servlet 是独立于平台的,因为它们是用 Java 编写的。
  4. 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
  5. Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。
Servlet的主要任务
  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

Servlet 在 Web 应用程序中的位置:
在这里插入图片描述

Servlet和JSP
  • servlet和jsp的区别

1、Servlet在Java代码中可以通过HttpServletResponse对象动态输出HTML内容。

2、JSP是在静态HTML内容中嵌入Java代码,然后Java代码在被动态执行后生成HTML内容。

  • servlet和jsp各自的特点

1、Servlet虽然能够很好地组织业务逻辑代码,但是在Java源文件中,因为是通过字符串拼接的方式生成动态HTML内容,这样就容易导致代码维护困难、可读性差。

2、JSP虽然规避了Servlet在生成HTML内容方面的劣势,但是在HTML中混入大量、复杂的业务逻辑。

  • 通过MVC双剑合璧

MVC模式,是Model-View-Controller的简称,是软件工程中的一种软件架构模式,分为三个基本部分,分别是:模型(Model)、视图(View)和控制器(Controller):

Controller——负责转发请求,对请求进行处理

View——负责界面显示

Model——业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现

在JSP/Servlet开发的软件系统中,这三个部分的描述如下所示:
在这里插入图片描述
1、Web浏览器发送HTTP请求到服务端,然后被Controller(Servlet)获取并进行处理(例如参数解析、请求转发)

2、Controller(Servlet)调用核心业务逻辑——Model部分,获得结果

3、Controller(Servlet)将逻辑处理结果交给View(JSP),动态输出HTML内容

4、动态生成的HTML内容返回到浏览器显示

MVC模式在Web开发中有很大的优势,它完美规避了JSP与Servlet各自的缺点,让Servlet只负责业务逻辑部分,而不会生成HTML代码;同时JSP中也不会充斥着大量的业务代码,这样能大提高了代码的可读性和可维护性。

Servlet 环境

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

  • Servlet包

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

  • 设置Java开发环境
  • 设置Web服务器Tomcat
Servlet生命周期

Servlet 通过调用 init () 方法进行初始化,调用 service() 方法来处理客户端的请求,调用 destroy() 方法终止(结束),最后,由 JVM 的垃圾回收器进行垃圾回收的。

  • init()方法

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

Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,也可以指定 Servlet 在服务器第一次启动时被加载。init()方法被设计成只调用一次,在后续每次用户请求时不再调用。

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

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

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

service() 方法由容器调用,所以不用对 service() 方法做任何动作。

public void service(ServletRequest request, 
                    ServletResponse response) 
      throws ServletException, IOException{
}
  • doGet()方法

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

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

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

public void doPost(HttpServletRequest request,
                   HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}
  • destroy()方法

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

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

 public void destroy() {
    // 终止化代码...
  }
  • 架构图
    在这里插入图片描述
Servlet部署
  • 创建Servlet类,并编译
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()
  {
  }
}
  • 默认情况下,Servlet 应用程序位于路径 /webapps/ROOT 下,且类文件放在 /webapps/ROOT/WEB-INF/classes 中。

  • 配置web.xml文件,在 <web-app>...</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>
  • 启动Tomcat,访问http://localhost:8080/HelloWorld
Servlet表单

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

  • GET方法

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

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

  • POST方法

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

  • 读取表单数据
方法描述
getParameter()调用 request.getParameter() 方法来获取表单参数的值。
getParameterValues()如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
getParameterNames()如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。
Servlet客户端请求
  • HTTP请求头信息与读取HTTP请求头信息的常用方法与JSP客户端请求中的相同。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// 扩展 HttpServlet 类
public class DisplayHeader extends HttpServlet {
 
  // 处理 GET 方法请求的方法
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");
 
      PrintWriter out = response.getWriter();
    String title = "HTTP Header 请求实例";
      String docType =
      "<!doctype html public \"-//w3c//dtd html 4.0 " +       "transitional//en\">\n";
      out.println(docType +
        "<html>\n" +
        "<head><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);
  }
}
Servlet服务器响应
  • HTTP响应头信息与读取HTTP响应头信息的常用方法与JSP服务器响应中的相同。
// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// 扩展 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");
 
      // Get current time
      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 = "自动刷新 Header 设置";
      String docType =
      "<!doctype html public \"-//w3c//dtd html 4.0 " +       "transitional//en\">\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");
  }
  // 处理 POST 方法请求的方法
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}
  • HTTP 请求和 HTTP 响应消息的格式是类似的,结构如下:
  1. 初始状态行 + 回车换行符(回车+换行)

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

  3. 一个空白行,即回车换行符

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

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

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)。

Servlet过滤器
  • 详见JSP基础中的JSP过滤器
Servlet异常处理

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

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

  • 定义一个ErrorHandler类,处理异常或错误,在Servlet出现异常或错误时调用。编译后放在/webapps/ROOT/WEB-INF/classes 中。
// 导入必需的 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
  {
      // 分析 Servlet 异常       
      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");
 
      PrintWriter out = response.getWriter();
     String title = "Error/Exception Information";
      String docType =
      "<!doctype html public \"-//w3c//dtd html 4.0 " +       "transitional//en\">\n";
      out.println(docType +
        "<html>\n" +
        "<head><title>" + title + "</title></head>\n" +
        "<body bgcolor=\"#f0f0f0\">\n");

      if (throwable == null && statusCode == null){
         out.println("<h2>Error information is missing</h2>");
         out.println("Please return to the <a href=\"" +             response.encodeURL("http://localhost:8080/") +             "\">Home Page</a>.");
      }else if (statusCode != null){
         out.println("The status code : " + statusCode);
      }else{
         out.println("<h2 class="tutheader">Error information</h2>");
         out.println("Servlet Name : " + servletName + 
                             "</br></br>");
         out.println("Exception Type : " + 
                             throwable.getClass( ).getName( ) + 
                             "</br></br>");
         out.println("The request URI: " + requestUri + 
                             "<br><br>");
         out.println("The exception message: " + 
                                 throwable.getMessage( ));
      }
      out.println("</body>");
      out.println("</html>");
  }
  // 处理 POST 方法请求的方法
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}
  • 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>
  • 请求属性-错误、异常
属性描述
javax.servlet.error.status_code该属性给出状态码,状态码可被存储,并在存储为 java.lang.Integer 数据类型后可被分析。
javax.servlet.error.exception_type该属性给出异常类型的信息,异常类型可被存储,并在存储为 java.lang.Class 数据类型后可被分析。
javax.servlet.error.message该属性给出确切错误消息的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
javax.servlet.error.request_uri该属性给出有关 URL 调用 Servlet 的信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析。
javax.servlet.error.exception该属性给出异常产生的信息,信息可被存储,并在存储为 java.lang.Throwable 数据类型后可被分析。
javax.servlet.error.servlet_name该属性给出 Servlet 的名称,名称可被存储,并在存储为 java.lang.String 数据类型后可被分析。
Servlet Cookies 处理
  • Servlet Cookie 处理需要对中文进行编码与解码,方法如下:

    String str = java.net.URLEncoder.encode("中文Cookies");		//编码
    String str = java.net.URLDecoder.decode("解码后的中文字符串");	// 解码
    
  • 详见JSP基础中的JSP Cookies处理。

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
 
// 扩展 HttpServlet 类
public class HelloForm extends HttpServlet {
 
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 为名字和姓氏创建 Cookies      
      Cookie firstName = new Cookie("first_name",
                      request.getParameter("first_name"));
      Cookie lastName = new Cookie("last_name",
                      request.getParameter("last_name"));

      // 为两个 Cookies 设置过期日期为 24 小时后
      firstName.setMaxAge(60*60*24); 
      lastName.setMaxAge(60*60*24); 

      // 在响应头中添加两个 Cookies
      response.addCookie( firstName );
      response.addCookie( lastName );

      // 设置响应内容类型
      response.setContentType("text/html");
 
      PrintWriter out = response.getWriter();
      String title = "设置 Cookies 实例";
      String docType =
      "<!doctype html public \"-//w3c//dtd html 4.0 " +       "transitional//en\">\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("first_name") + "\n" +
                "  <li><b>姓氏</b>:"
                + request.getParameter("last_name") + "\n" +
                "</ul>\n" +
                "</body></html>");
  }
}
Servlet Session
  • 详见JSP基础中的JSP Session。
  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());

      String title = "欢迎回到我的网站";
      Integer visitCount = new Integer(0);
      String visitCountKey = new String("visitCount");
      String userIDKey = new String("userID");
      String userID = new String("ABCD");

      // 检查网页上是否有新的访问者
      if (session.isNew()){
         title = "欢迎来到我的网站";
         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");
      PrintWriter out = response.getWriter();
}
ServletContext对象

ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放。

WEB容器在启动时,它会为每个Web应用程序都创建一个对应的ServletContext,它代表当前Web应用,并且它被所有客户端共享。

当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁。
在这里插入图片描述

  • ServletContext对象的引用获得
this.getServletContext(); 
this.getServletConfig().getServletContext();
  • ServletContext常用方法
方法描述
public void setAttribute(String name, Object obj)添加属性
public Object getAttribute(String name)得到属性值
public void removeAttribute(String name)删除属性
  • ServletContext的应用
  1. 在所有客户端中共享数据。
  2. 实现Servlet请求转发

之前我们学过的请求转发是通过request对象的:

request.getRequestDispatcher("/url").forward(request, response);

这里要说明的是,ServletContext也可以实现请求转发:

this.getServletContext().getRequestDispatcher("/url").forward(request, response); 

这两个转发效果是一样的。

  1. 获取Web应用的初始化参数

我们可以用<init-param>标签为servlet配置初始化参数,然后使用ServletConfig对象获取这些参数,假如有如下的MyServlet,它的配置为:

<servlet>  
    <servlet-name>MyServlet</servlet-name>  
    <servlet-class>com.gavin.servlet.MyServlet</servlet-class>  
    <init-param>  
        <param-name>encoding</param-name>  
        <param-value>utf-8</param-value>  
    </init-param>  
</servlet>  

可以看到它配置了一个初始化参数:encoding=utf-8,那么我们在MyServlet的源代码中需要这样去得到这个参数:

String encoding = this.getServletConfig().getInitParameter("encoding");

注意,上述的参数配置方法只针对一个特定的Servlet有效,我们可以通过ServletContext来获取全局的、整个Web应用的初始化参数,全局的初始化参数是这样配置在web.xml文件中的:

<!-- 如果希望所有的Servlet都可以使用该配置,则必须这么做 -->
<context-param>
    <param-name>name</param-name>
    <param-value>gavin</param-value>
</context-param>

然后我们可以在任意一个Servlet中使用ServletContext获取这个参数:

String name = this.getServletContext().getInitParameter("name");
  1. 利用ServletContext对象读取资源文件(比如properties文件)

    • 文件在WebRoot文件夹下,即Web应用的根目录。这时候我们可以使用ServletContext来读取该资源文件。

    假设我们Web根目录下有一个配置数据库信息的dbinfo.properties文件,里面配置了name和password属性,这时候可以通过ServletContext去读取这个文件:

    // 这种方法的默认读取路径就是Web应用的根目录
    InputStream stream = this.getServletContext().getResourceAsStream("dbinfo.properties");
    // 创建属性对象
    Properties properties = new Properties();
    properties.load(stream);
    String name = properties.getProperty("name");
    String password = properties.getProperty("password");
    out.println("name="+name+";password="+password);
    
    • 如果这个文件放在了src目录下,这时就不能用ServletContext来读取了,必须要使用类加载器去读取。
    // 类加载器的默认读取路径是src根目录
    InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("dbinfo.properties")
    

    如果这个文件此时还没有直接在src目录下,而是在src目录下的某个包下,比如在com.gavin包下,此时类加载器要加上包的路径,如下:

    InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("com/gavin/dbinfo.properties")
    

    补充一点,ServletContext只有在读取的文件在web应用的根目录下时,才能获取文件的全路径。比如我们在WebRoot文件夹下有一个images文件夹,images文件夹下有一个Servlet.jpg图片,为了得到这个图片的全路径,如下:

    // 如何读取到一个文件的全路径,这里会得到在Tomcat的全路径
    String path = this.getServletContext().getRealPath("/images/Servlet.jpg");
    
  2. 在网站开发中,有很多功能要使用ServletContext,比如

    1. 网站计数器

    2. 网站的在线用户显示

    3. 简单的聊天系统

    总之,如果是涉及到不同用户共享数据,而这些数据量不大(在服务器中一直占用内存),同时又不希望写入数据库中,我们就可以考虑使用ServletContext实现。

Servlet数据库
  • 创建数据库连接类DatabaseAccess
// 加载必需的库
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
 
public class DatabaseAccess extends HttpServlet{
    
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // JDBC 驱动器名称和数据库的 URL
      static final String JDBC_DRIVER="com.mysql.cj.jdbc.Driver";  
      static final String DB_URL="jdbc:mysql://localhost/db_book?serverTimezone=UTC";

      //  数据库的用户名与密码,需要根据自己的设置
      static final String USER = "root";
      static final String PASS = "1234";

      // 设置响应内容类型
      response.setContentType("text/html");
      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><title>" + title + "</title></head>\n" +
         "<body bgcolor=\"#f0f0f0\">\n" +
         "<h1 align=\"center\">" + title + "</h1>\n");
      try{
         // 注册 JDBC 驱动器
         Class.forName(JDBC_DRIVER);

         // 打开一个连接
         Connection conn = DriverManager.getConnection(DB_URL,USER,PASS);

         // 执行 SQL 查询
         Statement stmt = conn.createStatement();
         String sql;
         sql = "SELECT id, first, last, age FROM Employees";
         ResultSet rs = stmt.executeQuery(sql);

         // 展开结果集数据库
         while(rs.next()){
            // 通过字段检索
            int id  = rs.getInt("id");
            int age = rs.getInt("age");
            String first = rs.getString("first");
            String last = rs.getString("last");

            // 输出数据
            out.println("ID: " + id + "<br>");
            out.println(", Age: " + age + "<br>");
            out.println(", First: " + first + "<br>");
            out.println(", Last: " + last + "<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();
         }
      }
   }
} 
  • 配置web.xml文件
 <servlet>
     <servlet-name>DatabaseAccess</servlet-name>
     <servlet-class>DatabaseAccess</servlet-class>
 </servlet>
 
 <servlet-mapping>
     <servlet-name>DatabaseAccess</servlet-name>
     <url-pattern>/DatabaseAccess</url-pattern>
 </servlet-mapping>
Servlet文件上传
  • 文件上传表单
<form action="UploadServlet" method="post"                         enctype="multipart/form-data">
<input type="file" name="file" size="50" />
<br />
<input type="submit" value="上传文件" />
</form>
  • 后台UploadServlet
  1. 下面的实例依赖于 FileUpload,所以一定要确保在您的 classpath 中有最新版本的 commons-fileupload.x.x.jar 文件。可以从 http://commons.apache.org/fileupload/ 下载。

  2. FileUpload 依赖于 Commons IO,所以一定要确保在您的 classpath 中有最新版本的 commons-io-x.x.jar 文件。可以从 http://commons.apache.org/io/ 下载。

// 导入必需的 java 库
import java.io.*;
import java.util.*;
 
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.output.*;

public class UploadServlet extends HttpServlet {
   
   private boolean isMultipart;
   private String filePath;
   private int maxFileSize = 50 * 1024;
   private int maxMemSize = 4 * 1024;
   private File file ;

   public void init( ){
      // 获取文件将被存储的位置
      filePath = 
             getServletContext().getInitParameter("file-upload"); 
   }
   public void doPost(HttpServletRequest request, 
               HttpServletResponse response)
              throws ServletException, java.io.IOException {
      // 检查我们有一个文件上传请求
      isMultipart = ServletFileUpload.isMultipartContent(request);
      response.setContentType("text/html");
      java.io.PrintWriter out = response.getWriter( );
      if( !isMultipart ){
         out.println("<html>");
         out.println("<head>");
         out.println("<title>Servlet upload</title>");  
         out.println("</head>");
         out.println("<body>");
         out.println("<p>No file uploaded</p>"); 
         out.println("</body>");
         out.println("</html>");
         return;
      }
      DiskFileItemFactory factory = new DiskFileItemFactory();
      // 文件大小的最大值将被存储在内存中
      factory.setSizeThreshold(maxMemSize);
      // Location to save data that is larger than maxMemSize.
      factory.setRepository(new File("c:\\temp"));

      // 创建一个新的文件上传处理程序
      ServletFileUpload upload = new ServletFileUpload(factory);
      // 允许上传的文件大小的最大值
      upload.setSizeMax( maxFileSize );

      try{ 
      // 解析请求,获取文件项
      List fileItems = upload.parseRequest(request);
   
      // 处理上传的文件项
      Iterator i = fileItems.iterator();

      out.println("<html>");
      out.println("<head>");
      out.println("<title>Servlet upload</title>");  
      out.println("</head>");
      out.println("<body>");
      while ( i.hasNext () ) 
      {
         FileItem fi = (FileItem)i.next();
         if ( !fi.isFormField () )   
         {
            // 获取上传文件的参数
            String fieldName = fi.getFieldName();
            String fileName = fi.getName();
            String contentType = fi.getContentType();
            boolean isInMemory = fi.isInMemory();
            long sizeInBytes = fi.getSize();
            // 写入文件
            if( fileName.lastIndexOf("\\") >= 0 ){
               file = new File( filePath + 
               fileName.substring( fileName.lastIndexOf("\\"))) ;
            }else{
               file = new File( filePath + 
               fileName.substring(fileName.lastIndexOf("\\")+1)) ;
            }
            fi.write( file ) ;
            out.println("Uploaded Filename: " + fileName + "<br>");
         }
      }
      out.println("</body>");
      out.println("</html>");
   }catch(Exception ex) {
       System.out.println(ex);
   }
   }
   public void doGet(HttpServletRequest request, 
                       HttpServletResponse response)
        throws ServletException, java.io.IOException {
        
        throw new ServletException("GET method used with " +
                getClass( ).getName( )+": POST method required.");
   } 
}
  • 配置web.xml文件
<servlet>
   <servlet-name>UploadServlet</servlet-name>
   <servlet-class>UploadServlet</servlet-class>
</servlet>

<servlet-mapping>
   <servlet-name>UploadServlet</servlet-name>
   <url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>

UploadServlet会接受上传的文件,并把它储存在Tomcat目录下的/webapps/data 中。这个目录名也可以使用外部配置来添加,比如 web.xml 中的 context-param 元素,如下所示:

<web-app>
....
<context-param> 
    <description>Location to store uploaded file</description> 
    <param-name>file-upload</param-name> 
    <param-value>
         c:\apache-tomcat-5.5.29\webapps\data\
     </param-value> 
</context-param>
....
</web-app>
Servlet日期处理
  • 详见JSP基础中的JSP日期处理。
Servlet重定向
  • 重定向方法详见JSP基础中的JSP重定向。
  • 创建重定向类PageRedirect
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class PageRedirect extends HttpServlet{
    
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");

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

      response.setStatus(response.SC_MOVED_TEMPORARILY);
      response.setHeader("Location", site);    
    }
} 
  • 配置web.xml文件
 <servlet>
     <servlet-name>PageRedirect</servlet-name>
     <servlet-class>PageRedirect</servlet-class>
 </servlet>

 <servlet-mapping>
     <servlet-name>PageRedirect</servlet-name>
     <url-pattern>/PageRedirect</url-pattern>
 </servlet-mapping>
Servlet计数器
  • 创建网页点击计数器类PageHitCounter
import java.io.*;
import java.sql.Date;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class PageHitCounter extends HttpServlet{
    
  private int hitCount; 
               
  public void init() 
  { 
     // 重置点击计数器
     hitCount = 0;
  } 

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");
      // 该方法在 Servlet 被点击时执行 
      // 增加 hitCount 
      hitCount++; 
      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><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文件
Servlet 自动刷新页面

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

public void setIntHeader(String header, int headerValue)

此方法把头信息 “Refresh” 连同一个表示时间间隔的整数值(以秒为单位)发送回浏览器。

  • 创建刷新类Refresh
// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
 
// 扩展 HttpServlet 类
public class Refresh extends HttpServlet {
 
  // 处理 GET 方法请求的方法
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置刷新自动加载的事件间隔为 5 秒
      response.setIntHeader("Refresh", 5);
  }
  // 处理 POST 方法请求的方法
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}
  • 配置web.xml
Servlet邮件
  • 创建邮件发送类SendEmail ,详见JSP基础中的JSP邮件。
  • 配置web.xml
Servlet调试
  • 详见JSP基础中的JSP调试。
Servlet国际化
  • 详见JSP基础中的JSP国际化。
Servlet容器

Servlet容器主要是JavaWeb应用提供运行时环境,所以也可以称之为JavaWeb应用容器,或者Servlet/JSP容器。Servlet容器主要负责管理Servlet、JSP的生命周期以及它们的共享数据。

  • Tomcat

Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。

  • Jetty

Jetty 是一个开源的servlet容器,它为基于Java的web容器,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和web连接。

  • Jboss

Jboss是一个基于J2EE的开放源代码的应用服务器。 JBoss代码遵循LGPL许可,可以在任何商业应用中免费使用。JBoss是一个管理EJB的容器和服务器,支持EJB 1.1、EJB 2.0和EJB3的规范。但JBoss核心服务不包括支持servlet/JSP的WEB容器,一般与Tomcat或Jetty绑定使用。

  • Servlet容器负责Servlet和客户的通信以及调用Servlet的方法,Servlet和客户的通信采用“请求/响应”的模式 Servlet可完成如下功能:

1、创建并返回基于客户请求的动态HTML页面

2、创建可嵌入到现有HTML 页面中的部分HTML 页面(HTML 片段)

3、与其它服务器资源(如数据库或基于Java的应用程序)进行通信

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值