【Java Web初级系列教程】Servlet教程

前言:刚上手Java Web的时候,想寻找好一点的网上教程,发现网上资源鱼龙混杂,框架满天飞,对于新手刚开始就希望从基础的原理性的开始一步步了解,索性自己搜集材料开始写。

      本系列教程专门为Java Web初级开发者设计,阶梯式的循序渐进,没有用到任何框架,都是基础篇,一步步带你揭开Java Web应用的面纱,这是第二篇。

       背景说明

            任何事物的产生都是有原因的,为什么会有Servlet呢?请看上一篇文章,laugh.gifuploading.4e448015.gif转存失败重新上传取消大笑

上一篇文章:【Java Web初级系列教程】Web基础知识介绍了 Java Web应用基础知识;Web服务器、Web客户端、HTTP、HTML、Web容器、用Servlet和JSP创建简单应用,并查看了效果,这篇文章给你介绍关于Java Servlet更多细节、Java Servlet API核心接口、Servlet 3.0 annotation、Servlet生命周期、最后同样会有机哥的Demo:登录应用。

     目录:

          1.Servlet简介

          2.Common Gateway Interface(CGI)

          3.CGI vs Servlet

          4.Servlet API  层级* 

              4.1 Servlet Interface

              4.2 ServletConfig Interface

              4.3 ServletContext Interface

              4.4 ServletRequest Interface

              4.5 ServletResponse Interface

              4.6 RequestDispatcher Interface

              4.7 GenericServlet Interface

              4.8 HttpServer class 

          5.Servlet 属性(Attributes)

          6.Servlet3 Annotations

          7.Java Servlet登录Demo

 1.Servlet简介

     上一篇说过,如果你要处理客户端请求,应该创建Servlet,javax.servlet和javax.servlet.http包给我们提供了实现Servlet的接口和类。当初设计这二个包的时候,设计的人觉得Servlet(Server Applet)服务小程序应该是一种抽象的服务,不依赖具体的协议,但是后来我们发现这么多年基本servlet都是基于HTTP协议的,所以我们基本上看到实现的Servlet都是继承HttpServlet的。HttpServlet提供了Servlet基本的方法,例如doGet()和doPost().

2.Common Gateway Interface(CGI)

 

       在Java Servlet API之前,CGI技术被用来创建动态Web应用。CGI技术有很多缺点:为每一个请求都创建进程,平台独立代码(C、C++),高内存消耗以及低性能。

3.CGI vs Servlet

     Servlet呢就克服了CGI技术的短板:
          1.Servlet处理时间、内存利用率都比CGI优秀。Servlet使用多线程并且为每一个请求创建一个新线程,CGI则是为每一个请求创建一个新对象;
          2.Servlet可移植性更好。用Servlet做的Web应用能够运行在Web容器中:Tomcat、JBoss、Glassfish等,操作系统Windows、Linux、Unix、Solaris.Mac都可以;
          3.Servlet很强大。因为Web容器实现了servlet的生命周期管理,我们不需要担心内存泄漏、安全和垃圾回收等;
          4.Servlet很容易维护,学习曲线很平缓,因为所有我们需要去做的就是关系业务逻辑。

4.Servlet API  层级* 

     这部分内容会比较枯燥,但是很多时候学习一门技术或者一项技能,你刚开始可能要先死记住一些规范,就像武功秘籍中的心法口诀,然后再在实践中慢慢领悟使用,乃至提升,最后成为武林高手,这一部分内容就是需要先记住,然后后面慢慢用的过程中体会、领悟。
     javax.servlet.Servlet是Servlet API的最基础的接口。接下来我会介绍一些其他的接口和类都是我们需要记住的,未来开发的时候会用到的。下面是Servlet API的层级图:
   4.1 Servlet Interface
        说过, javax.servlet.Servlet是最基础的接口,这里声明了Servlet的生命周期管理,你应该理解生命周期管理吧。好吧,我还是解释一下,生命周期指的是创建、初始化、执行、销毁等不同阶段,体现在Servlet中就是一个个函数,构造函数就是创建、init()函数初始化、service()执行、destory()销毁。那在 javax.servlet.Servlet接口中的方法有:
     (1). public abstract void init(ServletConfig paramServletConfig) throws ServletException  –这个方法非常非常重要,这个方法是被Web容器来调用的,用来初始化servlet和ServletConfig参数。这个方法执行结束之后Servlet才准备好去处理客户的请求。这个方法在Servlet生命周期中只调用一次,并且让这个和别的Java类不一样。我们可以继承这个方法,在这个方法内初始化Servlet需要用到的资源,数据准备工作,例如数据库连接、Socket连接等。
     (2). public abstract ServletConfig getServletConfig()  –这个方法返回一个Servlet 配置对象,这个对象包含了这个Servlet的初始化参数和启动配置,具体一点讲,我们可以拿到在发布描述(web.xml)或者Servlet 3 annotation定义的初始化参数。后面我们会讲到ServletConfig接口。
      (3). public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException -这个方法就是实际负责处理客户端请求的方法,无论Servlet容器接受到任何请求,它会创建新的线程来执行service()方法,把request和response作为参数传入。Servlet通常运行在多线程环境中,所以要注意的是让共享的资源通过同步达到线程安全。
    (4). public abstract String getServletInfo() - 这个方法返回的字符串包括Servlet的信息,如:作者、版本、版权。
   4.2 ServletConfig Interface
        javax.servlet.ServletConfigServlet的配置信息用这个对象存储。每一个Servlet都有自己的ServletConfig对象,ServletConfig对象是Web容器负责创建和初始化的。我们可以通过在web.xml或者WebInitParam annotation设置Servlet的初始化参数。ServletConfig接口重要的方法是:
      (1). public abstract ServletContext getServletContext()  –这个方法返回ServletContext对象,这里重点说下和ServletConfig区别,ServletConfig是每个Servlet都带有一个,是专属的Servlet配置,ServletContext是所有Servlet共享一个Context,所以如果想在多个Servlet中共享数据,可以把数据放在ServletContext中。
      (2). public abstract Enumeration<String> getInitParameterNames()  –这个方法返回Servlet的初始化参数的枚举,没有没有初始化,这个是个空的枚举。
       (3). public abstract String getInitParameter(String paramString)  –这个方法获取指定名称的值,paramString是参数名称,如果没有这个参数,这个函数返回null。
   4.3 ServletContext Interface
        javax.servlet.ServletContext接口提供了当问Web应用程序变量的方法。一个Java Web应用只有一个ServletContext对象,这个对象对所有Servlet都是可见的,所以如果我们想在多个Servlet中共享初始的参数,那我们可以在web.xml中使用 <context-param>元素初始化参数。我们·可以通过ServletConfig的getServletContext() 方法获取到ServletContext。ServletContext接口也有些重要的函数:
     (1). public abstract ServletContext getContext(String uripath)  –这个方法获取指定URL的Context,我们前面讲过,一个Web应用只有一个Context,应用之间的交互可以通过另一个应用的URL路径来找到。
     (2). public abstract URL getResource(String path) throws MalformedURLException  –这个函数根据给定的资源路径返回一个URL对象,你可能会奇怪,URL不就是资源路径嘛,怎么还会根据路径找路径,这里的路径不一样,URL是HTTP协议的绝对路径,这里的path可以是文件相对路径,可以是数据库,可以是网络路径等等。
       (3). public abstract InputStream getResourceAsStream(String path)  –这个方法根据给定path返回InputStream对象,这个方法主要是让path路径下的资源对外部Servlet可访问。
       (4) . public abstract RequestDispatcher getRequestDispatcher(String urlpath)  –这个方法大部分时候是用来获取另一个Servlet的引用。在获取RequestDispatcher对象之后, Servlet可以将请求转发到RequestDispatcher引用的资源对象上,或者将请求数据的内容取出来发给RequestDispatcher引用的资源对象。这里可能有点费解,后面在Demo中详细解释。
       (5). public abstract Object getAttribute(String name) - 这个函数返回对于属性名称的值对象
       (6). public abstract void setAttribute(String paramString, Object paramObject)  –这个函数用来设置应用作用域的属性,这个属性对于所有Servlet都是开放的,是应用级的。
       (7). String getInitParameter(String name)  –这个方法返回在web.xml中定义的初始参数的值
说明:说实话,这个接口的名称应该称为ApplicationContext,不是任何指定的Servlet的。不要和 ServletContext getContext(String uripath)  混淆,getContext(String uripath) 是用来获取别的应用的Context的,这个用在应用间的通信。
      4.4 ServletRequest Interface
        ServletRequest 是Web容器创建的,封装了客户端的请求信息,Web容器会将它作为参数传给service()方法调用。ServletRequest 有几个比较终于的方法:
      (1). Object getAttribute(String name)  –这个方法获取请求信息的值(对象)
        (2). String getParameter(String name)  –这个方法返回请求参数值(字符串)
      (3). String getServerName()  –返回请求中的主机名
      (4). int getServerPort()  – 获取服务端口
 注意:一般我们用的比较多的是ServletRequest 子接口HttpServletRequest,上一篇说过,请求中包含很多信息,HTTP协议形式封装好了这些信息。 HttpServletRequest还包含一些其他方法用来:Session管理、cookie 和请求授权。
    4.5 ServletResponse interface
         ServletResponse interface也是Web容器创建,用来发送应答信息给客户端。Web服务器将ServletResponse作为参数传递给service().HttpServletResponse中一些重要的方法:
     (1). void addCookie(Cookie cookie)  –将cookie信息添加到Response
       (2). void addHeader(String name, String value)  –用给定的name和value添加到response header中
       (3). String encodeURL(java.lang.String url) - 将Session Id编码到指定的URL,如果URL不需要编码,返回null。
       (4). void sendRedirect(String location)  –使用location指定的URL发送一个临时的重定向response给客户端。
       (5). void setStatus(int sc)  –被用来设置response的状态码。
    4.6 RequestDispatcher Interface
          RequestDispatcher interface 有二种使用方法,一种是将请求发给指定的资源,资源可以是HTML、JSP或同一个Context下其他Servlet,另一种用法是将其他资源发给Response。这个接口一般用来在同一个Context下的Servlet通信。
       (1). void forward(ServletRequest request, ServletResponse response)  –将来自一个Servlet的请求发给另一个资源;
       (2). void include(ServletRequest request, ServletResponse response)  –在Response中包含资源的内容
    4.7 GenericServlet Interface
          GenericServlet是个实现 ServletConfig、Serializable 、Servlet的抽象类,这个类实现了所有的Servlet的生命周期管理、ServletConfig函数、并且使我们继承这个类更容易。最重要的方法是init()方法。
    4.8 HttpServer class 
          HttpServer类是我们最常用的,基本上我们都是继承这个类来写我们自己的Servlet,这个类继承  GenericServlet,提供了基本的HTTP 操作,我们继承这个类以后的子类需要重写以下几个方法中的一个或几个:
  1. doGet(), for HTTP GET requests
  2. doPost(), for HTTP POST requests
  3. doPut(), for HTTP PUT requests
  4. doDelete(), for HTTP DELETE requests

 5.Servlet 属性(Attributes)

     Servlet属性是用来内部Servlet通信的,有三种作用域的属性:request作用域、session作用域、应用作用域。
ServletRequest、HttpSession和ServletContext提供了get/set/remove方法可以对三种作用域的属性进行操作。
另外特别注意的是:Attribute和Parameter不同,Parameter是在web.xml声明或annotation声明的。

 6.Servlet3 Annotations

     在Servlet 3之前,所有的servlet 映射和parameter初始化都在web.xml中完成。现在可以更简单啦。。有些重要的Servlet annotation:
     1.WebServlet -  我们用这个annotation声明初始化Servlet和参数
     2.WebInitParam – 可以用在Servlet或者Filter,定义初始化参数,包含name和value
      3.WebFilter和WebListener  后面会详细讲解。

7.Java Servlet登录Demo

      现在我们上硬菜,这个Demo主要验证用户登录。
    首先是登录页面  login.jsp ,我们在web.xml欢迎页设置为login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <title>login.html</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  
  <body>
  	<form action="LoginServlet" method="post">
  		用户名:<input type="text" name="user">
  		<br>
  		密码:<input type="password" name="pwd">
  		<br>
  		<input type="submit" value="Login">
  	</form>
  </body>
</html>

 
如果用户登录成功,跳转到LoginSuccess.jsp。Jsp文件如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>  
    <title>Login Success page</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  
  <body>
   	<h3>欢迎机哥,登录成功</h3>
	<a href="login.html">登录页面</a>
  </body>
</html>
那负责处理请求的LoginServlet如下:
import java.io.IOException;
import java.io.PrintWriter;

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

@WebServlet(
	description = "Login Servlet",
	urlPatterns = {"/LoginServlet"},
	initParams = { 
			@WebInitParam(name = "user", value = "机哥"),
			@WebInitParam(name = "password", value = "123456")
	}
)
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private ServletContext servletContext;
	
	public LoginServlet() {
		super();
	}

	public void init() throws ServletException {
		servletContext = getServletContext();
		//一般我们会在做一些初始化操作,耗时的
		if(servletContext.getInitParameter("dbURL").equals("jdbc:mysql://localhost/mysql_db")&&
				servletContext.getInitParameter("dbUser").equals("mysql_user")&&
				servletContext.getInitParameter("dbUserPwd").equals("mysql_pwd")){
			servletContext.setAttribute("DB_success", "true");
		}else throw new ServletException("DB Connection error");
	}
	
	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		String user = request.getParameter("user");
		String pwd = request.getParameter("pwd");
		
		String userID = getServletConfig().getInitParameter("user");
		String password = getServletConfig().getInitParameter("password");
		
		System.out.println("user:"+user +"pwd:"+pwd);
		System.out.println("userID:"+userID +"password:"+password);
		response.setHeader("Content-type", "text/html;charset=UTF-8");  
		response.setCharacterEncoding("UTF-8"); 
		response.setContentType("text/html;charset=UTF-8");
		
		if(userID.equals(user) && password.equals(pwd)){
			
			response.sendRedirect("LoginSuccess.jsp");
		}else{
			PrintWriter out = response.getWriter();
			out.println("<font color=red>用户名或密码不对</font>");		
			RequestDispatcher rq = servletContext.getRequestDispatcher("/login.jsp");		
			rq.include(request, response);
		}
	}
}
注意@WebServlet和@WebInitParm,这是我们说过的Java annotation。
 
login.jsp
 
loginSuccess.jsp
 
嗯嗯嗯,最后的话,机哥留个公众号:java流水账

这里没有敷衍的复制粘贴,博眼球的面试资料分享,有的只是尽可能清晰的讲清个人开发中遇到的一个个问题和总结。欢迎大家关注Java流水账,纯粹的个人技术公众号。
在这里插入图片描述

发布了11 篇原创文章 · 获赞 233 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zhengwangzw/article/details/60132680