码迷,mamicode.com
首页 > 其他好文 > 详细

Servlet 介绍

时间:2018-03-25 12:08:56      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:login   metadata   架构   upd   title   display   实现   作用   parameter   

JSP 的本质就是 Servlet,开发者把编写好的 JSP 页面部署在 Web 容器中后,Web 容器会将 JSP 编译成对应的 Servlet。

 

Servlet 的开发

Servlet 是个特殊的 Java 类,这个 Java 类必须继承 HttpServlet。每个 Servlet 可以响应客户端的请求。Servlet 提供不同的方法用于响应客户端请求。

doGet:用于响应客户端的 GET 请求。

doPost:用于响应客户端的 POST 请求。

doPut:用于响应客户端的 PUT 请求。

doDelete:用于响应客户端的 DELETE 请求。

事实上,客户端的请求通常只有 GET 和 POST 两种,Servlet 为了响应者两种请求,必须重写 doGet() 和 doPost() 两个方法。如果 Servlet 为了响应 4 种方式的请求,则需要同时重写上面的 4 个方法。

 

大部分时候,Servlet 对于所有请求的响应都是完全一样的。此时,可以采用重写一个方法来代替上面的几个方法:只需要重写 service() 方法即可响应客户端的所有请求。

另外,HttpServlet 还包含两个方法。

init(ServletConfig config):创建 Servlet 实例时,调用该方法来初始化 Servlet 资源。

destroy():销毁 Servlet 实例时,自动调用该方法回收资源。

通常无需重写 init() 和 destroy() 方法,除非需要在初始化 Servlet 时,完成某些资源初始化的方法,才考虑重写 init 方法。如果需要在销毁 Servlet 之前,先完成某些资源的回收,比如关闭数据库连接等,才需要重写 destroy 方法。

 

package com.baiguiren;

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

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.annotation.*;

// Servlet 必须继承 HttpServlet 类
@WebServlet(name="firstServlet", urlPattern={"/firstServlet"})
public class FirstServlet extends HttpServlet
{
    // 客户端的响应方法,使用该方法可以响应客户端所有类型的请求
    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        // 设置解码方式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        // 获取 name 的请求参数值
        String name = request.getParameter("name");
        // 获取 gender 的请求参数值
        String gender = request.getParameter("gender");
        // 获取 color 的请求参数值
        String[] colors = request.getParameterValues("color");
        // 获取 country 的请求参数值
        String country = request.getParameter("country");
        // 获取页面输出流
        PrintStream out = new PrintStream(response.getOutputStream());
        // 输出 HTML 页面标签
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Servlet测试</title>");
        out.println("</head>");
        out.println("<body>");
        // 输出请求参数的值:name
        out.println("你的名字:" + name + "<br/>");
        // 输出请求参数的值:gender
        out.println("你的性别:" + gender + "<br/>");
        // 输出请求参数的值:color
        out.println("你喜欢的颜色:");
        for (String color : colors)
        {
            out.println(color + " ");
        }
        out.println("<br/>");
        // 输出请求参数的值:country
        out.println("你来自的国家:" + country + "<hr/>");
        out.println("</body>");
        out.println("</html>");
    }
}

 

  

Servlet 的配置

编辑好的 Servlet 源文件并不能直接响应用户请求,还必须将其编译成 class 文件。将编译后的 FirstServlet.class 放在 WEB-INF/classes 路径下,如果 Servlet 有包,则还应将 class 文件放在对应的包路径下。例如,上面的 package 为 com.baiguiren,那么 FirstServlet.class 的最终路径应该是 WEB-INF/classes/com/baiguiren/FirstServlet.class。

 

如果需要直接采用 javac 命令来编译 Servlet 类,则需要将 Servlet API 接口和类添加到系统的 CLASSPATH 环境变量里。也就是将 tomcat 安装目录的 lib 子目录下的 servlet-api.jar 和 jsp-api.jar 添加到 CLASSPATH 环境变量中。

 

为了让 Servlet 能响应用户请求,还必须将 Servlet 配置在 Web 应用中(也就是配置在 web.xml 中)。

从 Servlet3.0 开始,配置 Servlet 有两种方式:

1、在 Servlet 类中使用 @Servlet 注解进行配置

2、通过在 web.xml 文件中进行配置

 

使用 @Servlet 时可指定如下表属性

属性  说明
asyncSupported 指定该 Servlet 是否支持异步操作模式
displayName  指定该 Servlet 的显示名
initParams  用于为该 Servlet 配置参数
loadOnStartup  用于将该 Servlet 配置成 load-on-startup 的 Servlet
name  指定该 Servlet 的名称
urlPatterns/value  这两个属性的作用完全相同,都指定该 Servlet 处理的 URL

 

如果打算用注解来配置 Servlet,有点需要指出

a、不要在 web.xml 文件的根元素 (<web-app.../>) 中指定 metadata-complete="true"

b、不要在 web.xml 文件中配置该 Servlet。

如果打算使用 web.xml 文件来配置该 Servlet,则需要配置如下两个部分。

a、配置 Servlet 的名字:对应 web.xml 文件中的 <servlet/> 元素。

b、配置 Servlet 的 URL:对应 web.xml 文件中的 <servlet-mapping/> 元素。这一步是可选的。但如果没有为 Servlet 配置 URL,则该 Servlet 不能响应用户请求。

 

使用 web.xml 配置 Servlet 示例:

<!-- 配置 Servlet 的名字 -->
<servlet>
    <!-- 指定 Servlet 的名字,相当于指定 @WebServlet 的 name 属性 -->
    <servlet-name>firstServlet</servlet-name>
    <!-- 指定 Servlet 的实现类 -->
    <servlet-class>com.baiguiren.FirstServlet</servlet-class>
</servlet>
<!-- 配置 Servlet 的 URL -->
<servlet-mapping>
    <!-- 指定 Servlet 的名字 -->
    <servlet-name>firstServlet</servlet-name>
    <!-- 指定 Servlet 映射的 URL 地址,相当于指定 @WebServlet 的 urlPatterns 属性 -->
    <url-pattern>/aa</url-pattern>
</servlet-mapping>

  

如果在 web.xml 文件中增加了如上所示的配置片段,则该 Servlet 的 URL 为 /aa。如果没有在 web.xml 中增加上面的片段,那么该 Servlet 类上的 @WebServlet 注解就会起作用,该 Servlet 的 URL 为 /firstServlet。

 

 

JSP/Servlet 的生命周期

JSP 的本质就是 Servlet,开发者编写的 JSP 页面将由 Web 容器编译成对应的 Servlet,当 Servlet 在容器中运行时,其示例的创建及销毁等都不是由程序员决定的。而是由 web 容器进行控制的。

创建 Servlet 示例有两个时机。

1、客户端第一次请求某个 Servlet 时,系统创建该 Servlet 的实例:大部分的 Servlet 都是这种 Servlet

2、web 应用启动时立即创建 Servlet 实例,即 load-on-startup Servlet。

 

每个 Servlet 的运行都遵循如下生命周期:

1、创建 Servlet 实例

2、web 容器调用 Servlet 的 init 方法,对 Servlet 进行初始化。

3、Servlet 初始化后,将一直存在于容器中,用于响应客户端请求。如果客户端发送 GET 请求,容器调用 Servlet 的 doGet 方法处理并响应请求;如果客户端发送 POST 请求,容器调用 Servlet 的 doPost 方法处理并响应请求。或者统一使用 service() 方法处理来响应用户请求。

4、web 容器决定销毁 Servlet 时,先调用 Servlet 的 destroy 方法,通常在关闭 web 应用之时销毁 Servlet。

 

Servlet 的生命周期如下图所示:

技术分享图片

 

load-on-startup Servlet

应用启动时就创建的 Servlet,通常是用于某些后台服务的 Servlet,或者需要拦截很多请求的 Servlet:这种 Servlet 通常作为应用的基础 Servlet 使用,提供重要的后台服务。

配置 load-on-startup 的 Servlet 有两种方式。

1、在 web.xml 文件中通过 <servlet.../> 元素的 <load-on-startup.../> 子元素进行配置

2、通过 @WebServlet 注解的 loadOnStartup 属性指定。

<load-on-startup.../> 元素或 loadOnStartup 属性都只接收一个整型值,这个值越小,Servlet 就越优先实例化。

 

package com.baiguiren;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

import javax.servlet.annotation.*;

// Servlet 必须继承 HttpServlet 类
@WebServlet(loadOnStartup=1)
public class TimerServlet extends HttpServlet
{
    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
        Timer timer = new Timer();
        timer.schedule(new TimerTask(){
        
            @Override
            public void run() {
                System.out.println(new Date());
            }
        }, 1000);
    }
}

  

上面是一个简单的 Servlet,该 Servlet 不响应用户请求,它仅仅执行计时器功能,每隔一段时间在控制台打印出当前时间。

这个 Servlet 没提供 service() 方法,这表明它不能响应用户请求,所以无须为它配置 URL 映射。

上面的 Servlet 使用了注解配置了 load-on-startup Servlet,除此之外,还可以在 web.xml 文件中增加如下配置片段。

 

<servlet>
    <!-- Servlet 名 -->
    <servlet-name>timerServlet</servlet-name>
    <!-- Servlet 实现类 -->
    <servlet-class>com.baiguiren.TimerServlet</servlet-class>
    <!-- 配置应用启动时,创建 Servlet 实例,相当于指定 @WebServlet 的 loadOnStartup 属性 -->
    <load-on-startup>1</load-on-startup>
</servlet>

  

 

访问 Servlet 的配置参数

配置 Servlet 时,还可以增加额外的配置参数。通过使用配置参数,可以实现提供更好的可移植性。

为 Servlet 配置参数有两种方式:

1、通过 @WebServlet 的 initParams 属性来指定。

2、通过在 web.xml 文件的 <servlet.../> 元素中添加 <init-param.../> 子元素来指定。

第二种方式与为 JSP 配置初始化参数极其相似,因为 JSP 的实质就是 Servlet,而且配置 JSP 的实质就是把 JSP 当 Servlet 使用。

 

访问 Servlet 配置参数通过 ServletConfig 对象完成,ServletConfig 提供如下方法:

String getInitParameter(String name):用于获取初始化参数。

JSP 的内置对象 config 就是此处的 ServletConfig。

 

TestServlet.java

package com.baiguiren;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.sql.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

import javax.servlet.annotation.*;

// Servlet 必须继承 HttpServlet 类
@WebServlet(
    name="testServlet", 
    urlPatterns={"/testServlet"},
    initParams={
        @WebInitParam(name="driver", value="com.mysql.jdbc.Driver"),
        @WebInitParam(name="url", value="jdbc:mysql://localhost:3306/jsp"),
        @WebInitParam(name="user", value="root"),
        @WebInitParam(name="pass", value="root")
    }
)
public class TestServlet extends HttpServlet
{
    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
    }

    // 响应客户端请求的方法
    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        try {
            // 获取 ServletConfig 对象
            ServletConfig config = getServletConfig();
            // 通过 ServletConfig 对象获取配置参数:driver
            String driver = config.getInitParameter("driver");
            // 通过 ServletConfig 对象获取配置参数:url
            String url = config.getInitParameter("url");
            // 通过 ServletConfig 对象获取配置参数:user
            String user = config.getInitParameter("user");
            // 通过 ServletConfig 对象获取配置参数:pass
            String pass = config.getInitParameter("pass");

            // 注册驱动
            Class.forName(driver);
            // 获取数据库连接
            Connection conn = DriverManager.getConnection(url, user, pass);
            // 创建 Statement 对象
            Statement stmt = conn.createStatement();
            // 执行查询,获取 ResultSet 对象
            ResultSet rs = stmt.executeQuery("select * from person");

            // 设置响应类型
            response.setContentType("text/html; charset=UTF-8");
            // 获取页面输出流
            PrintStream out = new PrintStream(response.getOutputStream());
            // 输出 HTML 标签
            out.println("<html>");
            out.println("<head>");
            out.println("<title>访问 Servlet 初始化参数测试</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<table border=‘1‘ width=‘480‘>");
            // 遍历结果集
            while(rs.next())
            {
                // 输出结果集内容
                out.println("<tr>");
                out.println("<td>" + rs.getString(1) + "</td>");
                out.println("<td>" + rs.getString(2) + "</td>");
                out.println("</tr>");
            }
            out.println("</table>");
            out.println("</body></html>");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }    
}

  

ServletConfig 获取配置参数的方法和 ServletContext 获取配置参数的方法完全一样,只是 ServletConfig 是取得当前 Servlet 的配置参数,而 ServletContext 是获取整个 Web 应用的配置参数。

以上程序中 @WebServlet 中的 initParams 属性用于为该 Servlet 配置参数,initParams 属性值的每个 @WebInitParam 配置一个初始化参数,每个 @WebInitParam 可指定如下两个属性:

a、name:指定参数名

b、value:指定参数值

类似地,在 web.xml 文件中为 Servlet 配置参数使用 <init-param.../> 元素,该元素可以接受如下两个子元素。

a、param-name:指定配置参数名

b、param-value:指定配置参数值

<servlet>
  <!-- 配置 Servlet 名 -->
  <servlet-name>testServlet</servlet-name>
  <!-- 指定 Servlet 的实现类 -->
  <servlet-class>com.baiguire.TestServlet</servlet-class>
  <!-- 配置 Servlet 的初始化参数:driver -->
  <init-param>
    <param-name>driver</param-name>
    <param-value>com.mysql.jdbc.Driver</param-value>
  </init-param>
  <!-- 配置 Servlet 的初始化参数:url -->
  <init-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/jsp</param-value>
  </init-param>
  <!-- 配置 Servlet 的初始化参数:user -->
  <init-param>
    <param-name>user</param-name>
    <param-value>root</param-value>
  </init-param>
  <!-- 配置 Servlet 的初始化参数:pass -->
  <init-param>
    <param-name>pass</param-name>
    <param-value>root</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <!-- 确定 Servlet 名 -->
  <servlet-name>testServlet</servlet-name>
  <!-- 配置 Servlet 映射的 URL -->
  <url-pattern>/testServlet</url-pattern>
</servlet-mapping>

  

 

使用 Servlet 作为控制器

在标准的 MVC 模式中,Servlet 仅作为控制器使用。JavaEE 应用架构正是遵循 MVC 模式的,对于遵循 MVC 模式的 JavaEE 应用而言,JSP 仅作为表现层 (View) 技术,其作用有两点、

1、负责收集用户请求参数

2、将应用的处理结果、状态数据呈现给用户

 

Servlet 则仅充当控制器 (Controller) 角色,它的作用类似于调度员,所有用户请求都发给 Servlet,Servlet 调用 Model 来处理用户请求,并调用 JSP 来呈现处理结果;或者 Servlet 直接用 JSP 将应用的状态数据呈现给用户。

Model 通常由 JavaBean 来充当,所有业务逻辑、数据访问逻辑都在 Model 中实现。实际上隐藏在 Model 下的可能还有丰富的组件,例如 DAO 组件、领域对象等。

 

login.jsp

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

<html>
    <head>
        <title>login</title>
    </head>
    <body>
       <!-- 输出错误提示 -->
       <span style="color:red; font-weight: bold;">
       <%
       if (request.getAttribute("err") != null) {
           out.println(request.getAttribute("err") + "</br>");
       }
       %>
    </span>
       请输入用户名和密码:
       <!-- 登录表单,该表单提交到一个 Servlet -->
       <form method="POST" action="login">
           用户名:<input type="text" name="username"/><br/>
           密码:<input type="password" name="password"/><br/>
           <input type="submit" value="登录"/><br/>
       </form>
    </body>
</html>

  

LoginServlet.java

package com.baiguiren;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.sql.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

import javax.servlet.annotation.*;

// Servlet 必须继承 HttpServlet 类
@WebServlet(
    name="login", 
    urlPatterns={"/login"}
)
public class LoginServlet extends HttpServlet
{
    public void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        String errMsg = "error: ";
        // Servlet 本身并不输出响应到客户端,因此必须将请求转发到视图页面
        RequestDispatcher rd;
        // 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        try {
            // Servlet 本身并不执行任何的业务逻辑处理,它调用 JavaBean 处理用户请求
            DbDao dao = new DbDao("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/jsp", "root", "root");
            // 查询结果集
            ResultSet rs = dao.query("select password from user where username = ?", username);
            if (rs.next()) {
                // 用户名和密码匹配
                if (rs.getString("password").equals(password)) {
                    // 获取 session 对象
                    HttpSession session = request.getSession(true);
                    // 设置 session 属性,跟踪用户会话状态
                    session.setAttribute("username", username);
                    // 获取转发对象
                    rd = request.getRequestDispatcher("/welcome.jsp");
                    // 转发请求
                    rd.forward(request, response);
                } else {
                    // 用户名和密码不匹配
                    errMsg += "密码不正确";
                }
            } else {
                // 用户名不存在
                errMsg += "用户名不存在";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 如果出错,转发到重新登录
        if (errMsg != null && !(errMsg.equals(""))) {
            rd = request.getRequestDispatcher("/login.jsp");
            request.setAttribute("err", errMsg);
            rd.forward(request, response);
        }
    }
}

  

DbDao.java

package com.baiguiren;

import java.sql.*;

public class DbDao
{
    private Connection connection;
    private String driver;
    private String url;
    private String user;
    private String pass;

    public DbDao() {}

    public DbDao(String driver, String url, String user, String pass)
    {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.pass = pass;
    }

    // 下面是各成员属性的 setter 和 getter 方法
    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getDriver() {
        return this.driver;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUrl() {
        return this.url;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getUser() {
        return this.user;
    }

    public void setPass(String pass) {
        this.pass = pass;
    }

    // 获取数据库连接
    public Connection getConnection() throws Exception {
        if (connection == null) {
            Class.forName(this.driver);
            connection = DriverManager.getConnection(url, user, pass);
        }

        return connection;
    }

    // 插入记录
    public boolean insert(String sql, Object... args) throws Exception {
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            pstmt.setObject(i + 1, args[i]);
        }

        return pstmt.executeUpdate() == 1;
    }

    // 执行查询
    public ResultSet query(String sql, Object... args) throws Exception {
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        for (int i = 0; i < args.length; i ++) {
            pstmt.setObject(i + 1, args[i]);
        }

        return pstmt.executeQuery();
    }

    // 执行修改
    public void modify(String sql, Object... args) throws Exception {
        PreparedStatement pstmt = getConnection().prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            pstmt.setObject(i + 1, args[i]);
        }

        pstmt.executeUpdate();
        pstmt.close();
    }

    // 关闭数据库连接的方法
    public void closeConnection() throws Exception {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}

  

下面是 MVC 中各个角色的对应组件

a、M:Model,即模型,对应 JavaBean

b、V:View,即视图,对应 JSP 页面

c、C:Controller,即控制器,对应 Servlet

 

Servlet 介绍

标签:login   metadata   架构   upd   title   display   实现   作用   parameter   

原文地址:https://www.cnblogs.com/eleven24/p/8635553.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!