Servlet介绍

本文摘自:李刚 《Java EE企业级应用实战——Struts2+Spring+Hibernate》

 

 

        Servlet是一种比JSP 更早的动态网页编程技术。在没有JSP之前, Servlet也是同时充当视图层、业务逻辑层及持久层角色。Servlet 的开发效率非常低,特别是当使用Servlet 生成表现层页面时,页面中所有的HTML 标签,都需采用Servlet 的输出流来输出,因此极其烦琐。由于Servlet是个标准的Java 类,因此必须由程序员开发,其修改难度大,美工人员根本无法参与Servlet 页面的开发。这一系列的问题,都阻碍了Servlet 作为表现层的使用。自MVC 规范出现后, Servlet 的责任开始明确下来,仅仅作为控制器使用,不再需要生成页面标签,也不再作为视图层角色使用。

 

一. Servlet开发

 

       Servlet ,通常称为服务器端小程序,是运行在服务器端的程序,用于处理及响应客户端的请求。

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

       (1)doGet:用于响应客户端的get 请求。

       (2)doPost:用于响应客户端的post 请求。

       (3)doPut:用于响应客户端的put 请求。

       (4)doDelete:用于响应客户端的delete 请求。

       事实上,客户端的请求通常只有get 和post 两种; Servlet 为了响应这两种请求,必须重写doGet 和doPost 两个方法。如果Servlet 为了响应四个方法,则需要同时重写上面的四个方法。

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

       (1)init(ServletConfig config):创建Servlet 实例时,调用的初始化方法。

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

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

       注意:如果重写了init(ServletConfig config)方法,则应在重写该方法的第一行调用super.init(config) 。该方法将调用HttpServlet的init 方法。

        下面提供一个Servlet 的示例,该Servlet 将获取表单请求参数,并将请求参数显示给客户端:

package ppp;

import java.io.PrintStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//Servlet必须继承HttpServlet 类
public class FirstServlet extends HttpServlet {
	// 客户端的响应方法,使用该方法可以响应客户端所有类型的请求
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, java.io.IOException {
		// 设置解码方式
		request.setCharacterEncoding("GBK");
		// 获取name 的请求参数值
		String name = request.getParameter("name");
		// 获取gender 的请求参数值
		String gender = request.getParameter("gender");
		// 获取color 的请求参数值
		String[] color = request.getParameterValues("color");
		// 获取country 的请求参数值
		String national = request.getParameter("country");
		// 获取页面输出流
		PrintStream out = new PrintStream(response.getOutputStream());
		// 输出HTML 页面标签
		out.println("<!DOCTYPE HTML PUBLIC\"-//W3C//DTD HTML 4.0 Transitional//EN\">");
		out.println("<HTML>");
		out.println("<HEAD>");
		out.println("<TITLE>Servlet测试</TITLE>");
		out.println("</HEAD>");
		out.println("<BODY>");
		// 输出请求参数的值: name
		out.println("您的名字: n" + name + " <hr> ");
		// 输出请求参数的值: gender
		out.println("您的性别: " + gender + "<hr>");
		// 输出请求参数的值: color
		out.println("您喜欢的颜色: ");
		for (String c : color)
			out.println(c + " ");
		out.println("chr>");
		out.println("您喜欢的颜色:");
		// 输出请求参数的值: national
		out.println("您来自的国家: " + national + "<hr>");
		out.println("c/BODY>");
		out.println("c/HTML>");
	}
}

       Servlet 和JSP 的区别在于:Servlet 中没有内置对象,原来JSP中的内置对象都必须通过HttpServletRequest对象,或由HttpServletResponse 对象生成;对于静态的HTML 标签, Servlet 都必须使用页面输出流逐行输出。

 

 

二. Servlet的配置

 

       编辑好的Servlet源文件并不能响应用户请求,还必须将其编译成class 文件。将编译后的FirstServlet. class 文件放在WEB-INF/classes 路径下,如果Servlet有包,则还应该将class 文件放在对应的包路径下。

       为了让Servlet 能响应用户请求,还必须将Servlet 配置在Web 应用中。配置Servlet时,需要修改web.xrnl 文件。

配置Servlet 需要配置两个部分。

       (1)配置Servlet 的名字:对应web.xml 文件中的<Servlet!>元素。

       (2)配置Servlet 的URL:对应web.xrnl 文件中的<servlet-mapping/>元素。

       因此,配置一个能响应客户请求的Servlet ,至少需要配置两个元素,关于上面FirstServlet 的配置如下:

<!--配置Servlet 的名字>
<servlet>
<!--指定Servlet 的名字-->
<servlet-name>firstServlet</servlet-name>
<!-- 指定Servlet 的实现类-->
<servlet-class>ppp.firstServlet</servlet-class>
</servlet>
<!--配置Servlet的URL-->
<servlet-mapping>
<!--指定Servlet的名字-->
<servlet-name>firstservlet</servlet-name>
<!--指定Servlet映射的URL地址-->
<url-pattern>/firstServlet</url-pattern>
</servlet-mapping>

 

 

 

三. Servlet 的生命周期

 

       Servlet 在容器中运行,其实例的创建及销毁等都不是由程序员决定的,而是由容器进行控制。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 方法处理并响应请求。对于不同的请求,有不同的
处理方法,或者统一使用service 方法处理来响应用户请求。

       (4)Web 容器角色销毁Servlet 时,调用Servlet 的destroy 方法,通常在关闭Web容器之时销毁Servlet。

Servlet生命周期如下所示:

 

 

四. 使用Servlet创作为控制器

 

       在标准的MVC模式中,Servlet仅作为控制器使用。下面介绍一个使用Servlet 作为控制器的MVC 应用,该应用演示了一个简单的登录验证:

首先是一个标准的登录页面,该页面将收集的用户名及密码,提交到Servlet。

<%@ page language="java" contentType="text/html;charset=gb23l2" errorPage=
"error.jsp"%>
<html>
<head>
<title>登录</title>
</head>
<body>
<!--输出出错提示-->
<font color="red">
<%
if(request.getAttribute("err")!= null)
{
    out.println(request.getAttribute("err"));
}
%>
</font>
请输入用户名和密码:
<!--登录表单,该表单提交到一个Servlet-->
<form id="login" method="post" action="login">
用户名: <input type="text" name="username"/><br>
密  码: <input type="password" name="pass"/><br>
<input type="submit" value="登录"/><br>
</form>
</body>
</html>

 

       在这里,Servlet充当控制器角色,控制器Servlet 的源代码如下:

package ppp;

import java.sql.ResultSet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginServlet extends HttpServlet {
	// 响应客户端请求
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, java.io.IOException {
		// Servlet本身并不输出响应到客户端,因此必须将请求转发
		RequestDispatcher rd;
		// 获取请求参数
		String username = request.getParameter("username");
		String pass = request.getParameter("pass");
		String errMsg = request.getParameter("errMsg");
		try {
			// Servlet 本身,并不执行任何的业务逻辑处理,它调用JavaBean处理用户请求
			DbDao dd = DbDao.instance("com.mysql. jdbc. Driver",
					"jdbc:mysql:lllocalhost:3306/liuyan", "root", "32147");
			// 查询结果集
			ResultSet rs = dd.query("select password from user_table where username ='"
							+ username + "'");
			if (rs.next()) {
				// 用户名和密码匹配
				if (rs.getString("password").equals(pass)) {
					// 获取session 对象
					HttpSession session = request.getSession(true);
					// 设置session属性,跟踪用户会话状态
					session.setAttribute("name", username);
					// 获取转发对象
					rd = request.getRequestDispatcher("/welcome.jsp");
					// 转发请求
					rd.forward(request, response);
				} else {
					// 用户名和密码不匹配时
					errMsg += "您的用户名密码不符合,请重新输入";
				}
			} else {
				// 用户名不存在时
				errMsg += "您的用户名不存在,请先注册";
			}
		} catch (Exception e) {
			rd = request.getRequestDispatcher("/error.jsp");
			request.setAttribute("exception", "业务异常");
			rd.forward(request, response);
		}
		// 如果出错,转发到重新登录
		if (errMsg != null && !errMsg.equals("")) {
			rd = request.getRequestDispatcher("/login.jsp");
			request.setAttribute("err", errMsg);
			rd.forward(request, response);
		}
	}
}


      

        控制器负责接收客户端的请求,它既不直接对客户端输出晌应,也不处理用户请求,只将请求转发到JSP 页,通过调用JavaBean 来处理用户请求。

        下面是Model JavaBean 的源代码:

package ppp;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class DbDao {
	// 该JavaBean 做成单态模式
	private static DbDao op;
	private Connection conn;
	private String driver;
	private String url;
	private String username;
	private String pass;

	// 构造器私有
	private DbDao() {
	}

	// 构造器私有
	private DbDao(String driver, String url, String username, String pass)
			throws Exception {
		this.driver = driver;
		this.url = url;
		this.username = username;
		this.pass = pass;
		Class.forName(driver);
		conn = DriverManager.getConnection(url, username, pass);
	}

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

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

	public void setUsername(String username) {
		this.username = username;
	}

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

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

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

	public String getUsername() {
		return (this.username);
	}

	public String getPass() {
		return (this.pass);
	}

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

	// 实例化JavaBean 的入口
	public static DbDao instance() {
		if (op == null)
			op = new DbDao();
		return op;
	}

	// 实例化JavaBean 的入口
	public static DbDao instance(String driver, String url, String username,
			String pass) throws Exception {
		if (op == null) {
			op = new DbDao(driver, url, username, pass);
		}
		return op;
	}

	// 插入记录
	public boolean insert(String sql) throws Exception {
		getConnection();
		Statement stmt = this.conn.createStatement();
		if (stmt.executeUpdate(sql) != 1) {
			return false;
		}
		return true;
	}

	// 执行查询
	public ResultSet query(String sql) throws Exception {
		getConnection();
		Statement stmt = this.conn.createStatement();
		return stmt.executeQuery(sql);
	}

	// 执行删除
	public void delete(String sql) throws Exception {
		getConnection();
		Statement stmt = this.conn.createStatement();
		stmt.executeUpdate(sql);
	}

	// 执行更新
	public void update(String sql) throws Exception {
		getConnection();
		Statement stmt = this.conn.createStatement();
		stmt.executeUpdate(sql);
	}
}

       由此可见,其整个结构非常清晰,下面是MVC 中各个角色的对应组件。

       M:Model,即模型,对应JavaBean 。

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

       C:Controller,即控制器,对应Servlet。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值