欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

servlet

程序员文章站 2022-06-03 10:37:47
...

 

什么是Servlet?

定义

Servlet的全称是 Server Applet,顾名思义,就是用 Java 编写的服务器端程序

Servlet 是一个 Java Web开发标准,狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

 

功能

其主要功能在于:交互式地浏览和修改数据,生成动态Web内容。

Java Web 应用程序中所有的请求-响应都是由 Servlet 来完成的。Servlet 并没有

 

Java Web 开发的发展历程

Web 开发技术主要是从静态网页技术动态网页技术的变迁。

由于本文主要介绍 Java Web 开发技术,所以对其他语言的 Web 技术不做介绍。

Java Web 开发的大致发展历程如下:静态HTML –> CGI –> Servlet –> JSP

至于SpringStruts等著名的框架则是在这些技术基础上的最佳编程实践。

 

静态网页技术

早期的Web 开发只能提供静态的 HTML 页面。这样的模式显然存在很多弊端:不利于系统扩展,不利于和用户之间进行交互。于是,有了动态页面技术(如大家熟悉的JSPASPPHP等等)。

 

动态网页技术

CGI

CGI (Common Gateway Interface,公共网关接口)是最重要的 Web 技术之一。它是最早的动态页面技术。

CGI 是外部应用程序与 Web 服务器之间的接口标准。

绝大多数的CGI程序被用来解释处理来自表单的输入信息: CGI 允许服务器调用外部程序来处理输入信息,并将相应的输出反馈给浏览器。CGI程序使网页具有交互功能

注:最流行的CGI 语言是 Perl Shell 脚本,但是也可以使用 CC++ 以及Java 等语言来编写。

CGI 解决了静态页面不利于交互的问题,但其自身也存在缺陷

l  需要为每个请求启动一个操作 CGI 程序的系统进程。如果请求频繁,会带来很大的系统开销。

如果用Java编写 CGI,除了需要为每个请求启动一个系统进程外,还要在进程中启动一个 JVM ,这将十分低效。

l  需要重复编写处理网络协议的代码,非常耗时。

 

Servlet

知道了 Java 编写 CGI 的不足。我们不禁要问,如果有办法可以只运行一个系统进程和一个 JVM ,岂不是能大大减少开销吗?

Servlet 正是为此应运而生。

与传统的 CGI 技术相比,Servlet优势在于:

l  传统的 CGI 中,每个请求都要启动一个新的进程;而在 Servlet 中,每个请求由一个轻量级的 Java 线程处理。

l  传统的 CGI 中,如果有 N 个并发的对同一个 CGI程序的请求,则该CGI程序的代码在内存中重复装载了 N 次;而对于Servlet,处理请求的是 N 个线程,只需要一份 Servlet 类代码。

 

Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。

 

JSP

JSP(Java Server Page)是一种实现静态HTML 和动态 HTML 混合编码的技术,它是Servlet API 的一个扩展。

 

Servlet 生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

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

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

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

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

如下图:

servlet

执行流程为:

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

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

然后 Servlet 容器处理由多个线程产生的多个请求(GETPOST 等类型),每个线程执行一个单一的 Servlet 实例的 service() 方法。service() 会根据请求类型分发到对应的方法中去处理。

 

init () 方法

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

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

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

 

service() 方法

service() 方法遵循 HTTP 协议标准,负责将 HTTP 请求分发给对应类型的处理方法。

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

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GETPOSTPUTDELETE 等),并在适当的时候调用 doGetdoPostdoPutdoDelete 等方法。

注意:service 方法不需要覆写。

 

doGet()方法

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

 

doPost()方法

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

 

destroy() 方法

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

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

httpservlet的doGet doPost方法实例

RequestMethodServlet.java

package com.songdanlee.firstapp.servlet;

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

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

public class RequestMethodServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		PrintWriter out = response.getWriter();
		out.write("this is doGet Method");
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		PrintWriter out = response.getWriter();
		out.write("this is doPost Method");
	}
	
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<servlet>
		<servlet-name>RequestMethodServlet</servlet-name>
		<servlet-class>com.songdanlee.firstapp.servlet.RequestMethodServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>RequestMethodServlet</servlet-name>
		<url-pattern>/RequestMethodServlet</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>ServletNumber</servlet-name>
		<servlet-class>com.songdanlee.firstapp.servlet.ServletNumber</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ServletNumber</servlet-name>
		<url-pattern>/ServletNumber</url-pattern>
	</servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

form.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  
    
    <title>my first servlet demo</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
   <form action="/ServletDemo/RequestMethodServlet" >
   	姓名<input type="text" name="name"/></br>
   	密码<input type="text" name="pwd"/></br>
   	<input type="submit" value="提交"/>
   	 	
   </form>
   
  </body>
</html>

结构图

servlet

运行结果

servlet

servlet

servlet实现网页访问统计

ServletNumber.java

package com.songdanlee.firstapp.servlet;

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

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;



public class ServletNumber extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		ServletContext context = this.getServletContext();
		Integer count = (Integer) context.getAttribute("counter");
		if(count == null){
			count = 1;
			context.setAttribute("counter", count);
		}else {
			count++;
			context.setAttribute("counter", count);
		}
		response.setContentType("text/html;charset=utf-8");  
		PrintWriter out = response.getWriter();
		 int  num = Integer.parseInt(context.getAttribute("counter").toString());
		out.println("你访问的次数是"+num);
		out.flush();
		out.close();
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}
	
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<servlet>
		<servlet-name>RequestMethodServlet</servlet-name>
		<servlet-class>com.songdanlee.firstapp.servlet.RequestMethodServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>RequestMethodServlet</servlet-name>
		<url-pattern>/RequestMethodServlet</url-pattern>
	</servlet-mapping>
	<servlet>
		<servlet-name>ServletNumber</servlet-name>
		<servlet-class>com.songdanlee.firstapp.servlet.ServletNumber</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ServletNumber</servlet-name>
		<url-pattern>/ServletNumber</url-pattern>
	</servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

运行结果

servlet

中文乱码问题以及网页定时刷新

乱码问题	
//第一种方式
		reponse.setCharacterEncoding("utf-8");
		reponse.setHeader("Context-Type", "text/html;charset=utf-8");
//第二种
		reponse.setContentType("text/html;charset=utf-8");
定时刷新并跳转
	reponse.setHeader("Refresh","2;URL=https://www.baidu.com");
package com.songdanlee.firstapp.servlet;

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

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


public class ChineseServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse reponse)
			throws ServletException, IOException {
		/*//第一种方式
		reponse.setCharacterEncoding("utf-8");
		reponse.setHeader("Context-Type", "text/html;charset=utf-8");*/
		
		
		//设置编码
		reponse.setContentType("text/html;charset=utf-8");
		//2秒后刷新并跳转到百度首页
		reponse.setHeader("Refresh","2;URL=https://www.baidu.com");
		String  data = "中国啊";
		PrintWriter out = reponse.getWriter();
		out.println(data);
		out.flush();
		out.close();
	
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}

}

请求重定向

所谓冲定向,就是web服务器接收到客户端的请求后,可能由于某些限制条件,不能访问当前请求URL所指的web资源,而是指定了一个新的资源路径,让客户端重新发送客户端请求。

1.请求Servlet1

2.Servlet1通知浏览器重定向到Servlet2

3.请求Servlet2

4.Servlet2回送响应消息

实例如下

login.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>Insert title here</title>
</head>
<body>
	<!-- 把表单内容提交到LoginServlet -->
	<form action="/ServletDemo/LoginServlet" method="post">
		用户名<input type="text" name="username"/> </br>
		  密码  <input type="password" name="password"/> </br>
		  <input type="submit" name="登录"/>
	</form>
</body>
</html>

welcome.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>Insert title here</title>
</head>
<body>
登录成功,欢迎
</body>
</html>

LoginServlet.java

package com.songdanlee.firstapp.servlet;

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

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



public class LoginServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse reponse)
			throws ServletException, IOException {
		reponse.setContentType("text/html;charset=utf-8");
		//用httpServletRequest对象的getparameter()方法来获取用户名和密码
		String username = request.getParameter("username");
		String password = request.getParameter("password");

		if(("root").equals(username)&&("1234").equals(password)){
			//如果用户名正确,重定向到welcom.xml
			reponse.sendRedirect("/ServletDemo/welcome.jsp");
		}else {
			//如果用户名错误,重定向到login.xml
			//reponse.sendRedirect("/ServletDemo/login.jsp");
			PrintWriter out = reponse.getWriter();
			out.write("登录失败");
		}
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(req, resp);
	}

}

xml配置

<servlet>
		<servlet-name>LoginServlet</servlet-name>
		<servlet-class>com.songdanlee.firstapp.servlet.LoginServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>LoginServlet</servlet-name>
		<url-pattern>/LoginServlet</url-pattern>
	</servlet-mapping>