JavaWeb——Servlet

本文详细介绍了Servlet的概念、作用及生命周期,展示了如何实现Servlet接口处理HTTP请求,包括配置Servlet、使用ServletConfig和ServletContext,以及如何通过HttpServlet简化开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Servlet
 1、Servlet简介
  Servlet翻译过来叫做运行在服务器端的小程序,需要运行在Servlet容器中,我们可以将Tomcat服务器理解为Servlet容器。Servlet最终是被服务器进行管理和调用的。
 2、Servlet的作用:
  1️⃣接收浏览器发送的请求
  2️⃣调用其他的Java程序来处理用户的请求,完成前台和后台的交互
  3️⃣向浏览器发送一个响应信息
 3、Servlet的HelloWorld
  ①编写一个类并实现Servlet接口
  ②在web.xml文件中配置Servlet

<servlet>
	<servlet-name>别名</servlet-name>
	<servlet-class>全类名</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>别名</servlet-name>
	<url-pattern>/请求地址</url-pattern>
</servlet-mapping>

  一个Servlet可以配置多个url-pattern,这时用户就可以通过不同的地址访问同一个Servlet了,url-pattern的名字可以是任意的,也可以是通配符,比如:表示所有的以.do结尾的url请求都会访问该Servlet

<servlet-mapping>
	<servlet-name>Hello</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

  Tip
   1️⃣若配成以.html结尾的话可以将服务器资源伪装成一个html页面,因为浏览器地址栏是以.html结尾的
   2️⃣url-pattern的值只有一个/时,表示所有请求都会被该Servlet处理
   3️⃣当多个utl-pattern相互交织时,会匹配最接近的那个Servlet
 4、Servlet的生命周期

public class HelloServlet implements Servlet {

	@Override
	public void destroy() {

	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}

	@Override
	public String getServletInfo() {
		return null;
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		
	}

	@Override
	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {

	}

}

  实现Servlet接口时有四个方法和生命周期相关:构造器、init()、service()、destroy(),构造器和init()只调用一次(说明Servlet是单例的),service()每请求一次调用一次,destroy()在关闭服务的时候调用一次(用以销毁Servlet对象等)。这些方法都是由Servlet容器(如Tomcat)调用的,在调用这些方法的时候容器会传入一些参数如ServletConfig、ServletRequest、ServletResponse等。
  Servlet及其子类是线程不安全的,老式的解决方式是让它实现SingleThreadModel接口,把一个单例的Servlet变为一个普通的类,每访问一次都会创建一个实例,这种方式不好已过时,因为太耗费资源。最好的解决方法是不在Servlet中使用成员变量,全部使用局部变量。
  默认情况下,Servlet实例是当有客户端访问的时候才会创建(只有首次访问时创建),这之前不会创建,但当给Servlet配置一行代码:<load-on-startup>时可以改变Servlet实例创建的时机:<load-on-startup>0</load-on-startup>,值的范围是0-5之间的整数,值越小优先级越高,一旦配置了该行代码,该Servlet实例就会在客户端首次访问之前创建:

<servlet>
	<servlet-name>HelloServlet</servlet-name>
	<servlet-class>com.bdm.servlets.HelloServlet</servlet-class>
	<load-on-startup>3</load-on-startup>
</servlet>

  其他相关接口:
   ①ServletConfig:获取当前Servlet的配置和参数信息,每一个Servlet都有它唯一的ServletConfig对象,该对象封装的是Servlet的配置信息,即web.xml中<Servlet>标签配置的信息,该对象是Tomcat服务器在调用Servlet的init()时传入的,可通过该对象获取到Servlet的别名、初始化参数、ServletContext等
   ②ServletContext:获取整个web应用的配置和参数信息,一个应用只有一个唯一的ServletContext对象,各个Servlet获取到的ServletContext对象都是同一个,该对象在服务器启动(或者说应用部署)时创建,在服务器停止时销毁,可通过ServletConfig.getServletContext()获取该对象也可通过ServletRequest.getServletContext获取,通过ServletContext可以获取整个web应用的初始化参数、资源的真实路径、数据库的配置信息以及作为域对象在整个应用上共享数据(比如在多个Servlet间共享数据,实现各个Servlet间的通信)
Tip
  Ⅰ、在JavaWeb中有四个域对象,这些域对象的信息共享的范围不同:
   1️⃣Application:即ServletContext,作用范围在服务器一开始启动服务,到服务器关闭为止
   2️⃣Session:HTTP会话开始到结束这段时间,可以理解为浏览器从打开到关闭的这段时间
   3️⃣Request:HTTP请求开始到结束这段时间
   4️⃣Page:当前页面(jsp)从打开到关闭这段时间,它只在同一个页面中有效
  Ⅱ、通过ServletContext可以获取项目中的文件,即使在WEB-INF文件夹下也能获取到

//以字节流的形式获取文件:这个path是相对于webroot的路径,项目发布之后也可以用它
InputStream is = this.getServletContext().getResourceAsStream(path);

//获取访问的绝对路径(部署在服务器上的路径):通过该路径在浏览器中可以浏览文件的内容,或者下载文件
String absolutePath =  this.getServletContext().getResource(path).getPath();

//获取文件在服务器端磁盘的绝对路径:通过该路径在浏览器中可以浏览文件的内容,或者下载该文件
String realPath = this.getServletContext().getRealPath(String path);

   src文件夹下的文件在编译之后会出现在WEB-INF下的classes文件夹下,相当于src是classes的子文件夹,所以直接放在src下的文件的路径获取方式如下:

String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/xxx.properties");

   src这种路径较为繁琐,也可以借助ClassLoader来获取,这两种方式中路径的不同点是用ServletContext获取时路径是从webroot下开始填写的,而用ClassLoader.getResourceAsStream(“路径”)时路径是从classes下开始,所以配置文件等文件最好不要放在包下,因为放在包下的时候获取的路径非常繁琐,直接放在src下或者webroot下,另外还要注意使用类的加载器读取配置文件时有弊端:
    a、类的加载器是将文件读取到内存中,如果文件太大的话可能会导致内存溢出,或者内存占用太大
    b、类的加载器只加载一次文件,如果文件有了更改是不会再次加载的,会导致更新不可见

二、GenericServlet
 GenericServlet是一个抽象类,实现了Servlet接口和ServletConfig接口:只将service()方法作为抽象方法供用户实现,让用户更专注于业务

public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {

	private static final long serialVersionUID = 1L;

	private transient ServletConfig config;

	public GenericServlet() {
		// NOOP
	}

	@Override
	public void destroy() {
		// NOOP by default
	}

	@Override
	public String getInitParameter(String name) {
		return getServletConfig().getInitParameter(name);
	}

	@Override
	public Enumeration<String> getInitParameterNames() {
		return getServletConfig().getInitParameterNames();
	}

	@Override
	public ServletConfig getServletConfig() {
		return config;
	}

	@Override
	public ServletContext getServletContext() {
		return getServletConfig().getServletContext();
	}

	@Override
	public String getServletInfo() {
		return "";
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		this.config = config;
		this.init();
	}

	public void init() throws ServletException {
		// NOOP by default
	}

	public void log(String msg) {
		getServletContext().log(getServletName() + ": " + msg);
	}

	public void log(String message, Throwable t) {
		getServletContext().log(getServletName() + ": " + message, t);
	}

	
	@Override
	public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

	@Override
	public String getServletName() {
		return config.getServletName();
	}
}

 继承GenericServlet:只需要重写service方法即可

public class HelloServlet extends GenericServlet {

	private static final long serialVersionUID = 1L;

	@Override
	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

	}
}

三、HttpServlet
 HttpServlet继承了GenericServlet,HttpServlet也是抽象类,将GenericServlet中的请求和响应强转为了Http的方式。
在这里插入图片描述
 高版本的HttpServlet对请求方式的处理做了细化:

public abstract class HttpServlet extends GenericServlet {
	private static final long serialVersionUID = 1L;
	private static final String METHOD_DELETE = "DELETE";
	private static final String METHOD_HEAD = "HEAD";
	private static final String METHOD_GET = "GET";
	private static final String METHOD_OPTIONS = "OPTIONS";
	private static final String METHOD_POST = "POST";
	private static final String METHOD_PUT = "PUT";
	private static final String METHOD_TRACE = "TRACE";
	private static final String HEADER_IFMODSINCE = "If-Modified-Since";
	private static final String HEADER_LASTMOD = "Last-Modified";
	private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
	private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String protocol = req.getProtocol();
		String msg = lStrings.getString("http.method_get_not_supported");
		if (protocol.endsWith("1.1"))
			resp.sendError(405, msg);
		else
			resp.sendError(400, msg);
	}

	protected long getLastModified(HttpServletRequest req) {
		return -1L;
	}

	protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {
			doGet(req, resp);
		} else {
			NoBodyResponse response = new NoBodyResponse(resp);
			doGet(req, response);
			response.setContentLength();
		}
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String protocol = req.getProtocol();
		String msg = lStrings.getString("http.method_post_not_supported");
		if (protocol.endsWith("1.1"))
			resp.sendError(405, msg);
		else
			resp.sendError(400, msg);
	}

	protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String protocol = req.getProtocol();
		String msg = lStrings.getString("http.method_put_not_supported");
		if (protocol.endsWith("1.1"))
			resp.sendError(405, msg);
		else
			resp.sendError(400, msg);
	}

	protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String protocol = req.getProtocol();
		String msg = lStrings.getString("http.method_delete_not_supported");
		if (protocol.endsWith("1.1"))
			resp.sendError(405, msg);
		else
			resp.sendError(400, msg);
	}

	private static Method[] getAllDeclaredMethods(Class<?> c) {
		if (c.equals(HttpServlet.class)) {
			return null;
		}

		Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
		Method[] thisMethods = c.getDeclaredMethods();

		if ((parentMethods != null) && (parentMethods.length > 0)) {
			Method[] allMethods = new Method[parentMethods.length + thisMethods.length];

			System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);

			System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);

			thisMethods = allMethods;
		}

		return thisMethods;
	}

	protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Method[] methods = getAllDeclaredMethods(super.getClass());

		boolean ALLOW_GET = false;
		boolean ALLOW_HEAD = false;
		boolean ALLOW_POST = false;
		boolean ALLOW_PUT = false;
		boolean ALLOW_DELETE = false;
		boolean ALLOW_TRACE = true;
		boolean ALLOW_OPTIONS = true;

		for (int i = 0; i < methods.length; ++i) {
			Method m = methods[i];

			if (m.getName().equals("doGet")) {
				ALLOW_GET = true;
				ALLOW_HEAD = true;
			}
			if (m.getName().equals("doPost"))
				ALLOW_POST = true;
			if (m.getName().equals("doPut"))
				ALLOW_PUT = true;
			if (m.getName().equals("doDelete")) {
				ALLOW_DELETE = true;
			}
		}
		String allow = null;
		if (ALLOW_GET)
			allow = "GET";
		if (ALLOW_HEAD)
			if (allow == null)
				allow = "HEAD";
			else
				allow = new StringBuilder().append(allow).append(", HEAD").toString();
		if (ALLOW_POST)
			if (allow == null)
				allow = "POST";
			else
				allow = new StringBuilder().append(allow).append(", POST").toString();
		if (ALLOW_PUT)
			if (allow == null)
				allow = "PUT";
			else
				allow = new StringBuilder().append(allow).append(", PUT").toString();
		if (ALLOW_DELETE)
			if (allow == null)
				allow = "DELETE";
			else
				allow = new StringBuilder().append(allow).append(", DELETE").toString();
		if (ALLOW_TRACE)
			if (allow == null)
				allow = "TRACE";
			else
				allow = new StringBuilder().append(allow).append(", TRACE").toString();
		if (ALLOW_OPTIONS) {
			if (allow == null)
				allow = "OPTIONS";
			else
				allow = new StringBuilder().append(allow).append(", OPTIONS").toString();
		}
		resp.setHeader("Allow", allow);
	}

	protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String CRLF = "\r\n";
		StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI()).append(" ")
				.append(req.getProtocol());

		Enumeration reqHeaderEnum = req.getHeaderNames();

		while (reqHeaderEnum.hasMoreElements()) {
			String headerName = (String) reqHeaderEnum.nextElement();
			buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));
		}

		buffer.append(CRLF);

		int responseLength = buffer.length();

		resp.setContentType("message/http");
		resp.setContentLength(responseLength);
		ServletOutputStream out = resp.getOutputStream();
		out.print(buffer.toString());
		out.close();
	}

	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String method = req.getMethod();

		if (method.equals("GET")) {
			long lastModified = getLastModified(req);
			if (lastModified == -1L) {
				doGet(req, resp);
			} else {
				long ifModifiedSince;
				try {
					ifModifiedSince = req.getDateHeader("If-Modified-Since");
				} catch (IllegalArgumentException iae) {
					ifModifiedSince = -1L;
				}
				if (ifModifiedSince < lastModified / 1000L * 1000L) {
					maybeSetLastModified(resp, lastModified);
					doGet(req, resp);
				} else {
					resp.setStatus(304);
				}
			}
		} else if (method.equals("HEAD")) {
			long lastModified = getLastModified(req);
			maybeSetLastModified(resp, lastModified);
			doHead(req, resp);
		} else if (method.equals("POST")) {
			doPost(req, resp);
		} else if (method.equals("PUT")) {
			doPut(req, resp);
		} else if (method.equals("DELETE")) {
			doDelete(req, resp);
		} else if (method.equals("OPTIONS")) {
			doOptions(req, resp);
		} else if (method.equals("TRACE")) {
			doTrace(req, resp);
		} else {
			String errMsg = lStrings.getString("http.method_not_implemented");
			Object[] errArgs = new Object[1];
			errArgs[0] = method;
			errMsg = MessageFormat.format(errMsg, errArgs);

			resp.sendError(501, errMsg);
		}
	}

	private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
		if (resp.containsHeader("Last-Modified"))
			return;
		if (lastModified >= 0L)
			resp.setDateHeader("Last-Modified", lastModified);
	}

	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
		HttpServletRequest request;
		HttpServletResponse response;
		try {
			request = (HttpServletRequest) req;
			response = (HttpServletResponse) res;
		} catch (ClassCastException e) {
			throw new ServletException("non-HTTP request or response");
		}
		service(request, response);
	}
}

 HttpServletRequest:封装了浏览器发送给服务器的请求,该对象由服务器创建并在服务器调用相应处理方法时作为参数传给doGet()、doPost()等。HttpServletRequest的作用:
  1️⃣获取用户发送的请求参数
  2️⃣可以获取项目名,主要用来设置绝对路径

String contextPath = request.getContextPath();

  3️⃣可以作为域对象,在不同的web资源之间共享数据。
  4️⃣可以用来做请求的转发

 HttpServletResponse:封装了服务器发送给浏览器的响应,该对象也由服务器创建并作为参数传递给doGet()、doPost()等方法。HttpServletResponse的作用:
  1️⃣向浏览器响应一个页面或者一个页面片段
  2️⃣做请求的重定向

response.sendRedirect("target.html");
Servlet 是 JavaEE 规范中的一部分,是处理 Web 请求的组件。Servlet 运行在服务器端,能够接收客户端发来的请求,并给客户端响应结果。下面我们来看看 Servlet 的基本概念和使用方法。 ## 一、Servlet 的基本概念 ### 1.1 Servlet 的生命周期 Servlet 的生命周期包含以下三个阶段: - 初始化阶段(init):当 Servlet 实例化后,Web 容器会调用其 init() 方法进行初始化操作。在此阶段,Servlet 可以执行一些初始化操作,例如读取配置信息、建立数据库连接等。 - 请求处理阶段(service):当客户端发来请求时,Web 容器会创建一个线程调用 Servlet 的 service() 方法处理请求。在此阶段,Servlet 可以获取请求参数、处理请求并生成响应数据。 - 销毁阶段(destroy):当 Web 应用停止或 Servlet 被卸载时,Web 容器会调用 Servlet 的 destroy() 方法进行清理工作。在此阶段,Servlet 可以释放资源、关闭数据库连接等。 ### 1.2 Servlet 的配置 在使用 Servlet 时,需要在 web.xml 文件中进行配置。以下是一个 Servlet 的基本配置: ```xml <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.example.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/myservlet</url-pattern> </servlet-mapping> ``` 其中,servlet-name 表示 Servlet 的名称,servlet-class 表示 Servlet 的类名,url-pattern 表示请求的 URL 匹配规则。 ## 二、Servlet 的使用方法 ### 2.1 编写 Servlet 编写 Servlet 有两种方法:一种是继承 HttpServlet 类,另一种是实现 Servlet 接口。这里以继承 HttpServlet 类为例: ```java public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 处理 GET 请求 PrintWriter out = resp.getWriter(); out.println("Hello, world!"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 处理 POST 请求 PrintWriter out = resp.getWriter(); out.println("Hello, world!"); } } ``` 在 Servlet 中,doGet() 方法用于处理 GET 请求,doPost() 方法用于处理 POST 请求。通过调用 HttpServletResponse 对象的 getWriter() 方法可以向客户端返回响应数据。 ### 2.2 部署 Servlet 将编写好的 Servlet 部署到 Web 容器中,有两种方法:一种是将 Servlet 类打成 war 包放到 Web 容器的 webapps 目录下,另一种是通过 Eclipse 等开发工具将 Servlet 部署到 Web 容器中。部署完成后,可以通过访问 Servlet 的 URL 来测试 Servlet 是否正常工作。 ## 三、总结 本文介绍了 Servlet 的基本概念和使用方法。Servlet 是 Java Web 开发中非常重要的组件,掌握 Servlet 的使用方法对于 Java Web 开发人员来说是必不可少的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值