当前位置: 首页 > news >正文

Servlet

一 Servlet

Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口

  • 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器

  • 不是所有的JAVA类都能用于处理客户端请求,能处理客户端请求并做出响应的一套技术标准就是Servlet

  • Servlet是运行在服务端的,所以 Servlet必须在WEB项目中开发且在Tomcat这样的服务容器中运行

1.1 动态资源和静态资源

静态资源

  • 无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源. 例如:html css js img ,音频文件和视频文件

动态资源

  • 需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时动态生成,例如Servlet,Thymeleaf ... ...

  • 动态资源指的不是视图上的动画效果或者是简单的人机交互效果

请求响应与HttpServletRequest和HttpServletResponse之间的对应关系  

2.servlet运行步骤 

  • tomcat接受到请求后,将请求报文的信息转换为一个HttpServletRequest对象,该对象中包含了请求中的所有信息。
  • tomcat同时创建了一个HttpServletResponse对象,该对象用于承装要响应给客户端的信息,后面,该对象会被转化为响应的报文。
  • tomcat根据请求中的资源路径找到对应的servlet,将servlet实例化,调用service方法,同时将HttpServletRequest和HttpServletResponse对象传入。

3. servlet开发流程

  1. 创建JavaWeb项目,同时将tomcat添加为当前项目的依赖
  2. 重写service方法
  3. 在service方法中,定义业务处理代码
  4. 在web.xml中,配置Servlet对应的请求映射路径

例:校验输入的用户名是否不为ergou

步骤1 开发一个web类型的module

步骤2 开发一个UserServlet

 java文件

package com.ergou.servlet;import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServlet;import java.io.IOException;
import java.io.PrintWriter;public class UserServlet extends HttpServlet {@Overridepublic void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException {
//从servletRequest对象中获取请求中的信息
String username = servletRequest.getParameter("username");//该方法是根据参数名获取参数值,即根据key获取value//处理业务的代码
String info = "YES";if("ergou".equals(username)){info = "NO";}
//将要响应的数据放入response
//应该设置Content-type响应头,也可以使用servletResponse.setContentType()
servletResponse.setHeader("Content-type","text/html");
PrintWriter writer = servletResponse.getWriter();//该方法返回的是一个向响应体中打印字符串的打印流
writer.write(info);writer.close();}
}
  • 自定义一个类,要继承HttpServlet类

  • 重写service方法,该方法主要就是用于处理用户请求的服务方法

  • HttpServletRequest 代表请求对象,是有请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息

  • HttpServletResponse 代表响应对象,该对象会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息

  • Servlet对象的生命周期(创建,初始化,处理服务,销毁)是由tomcat管理的,无需我们自己new

  • HttpServletRequest HttpServletResponse 两个对象也是有tomcat负责转换,在调用service方法时传入给我们用的

步骤3 在web.xml为UseServlet配置请求的映射路径

web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="<https://jakarta.ee/xml/ns/jakartaee>"xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>"xsi:schemaLocation="<https://jakarta.ee/xml/ns/jakartaee> <https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd>"version="5.0"><!--配置Servlet类,并起一个别名servlet-class 告诉Tomcat对应的要实例化的Servlet类servlet-name 用于关联请求的映射路径--><servlet><servlet-name>userServlet</servlet-name><servlet-class>com.ergou.servlet.UserServlet</servlet-class></servlet><!--servlet-mapping 用来设置对应servlet-name的映射路径--><servlet-mapping><servlet-name>userServlet</servlet-name><url-pattern>/userServlet</url-pattern></servlet-mapping><servlet-mapping><!--关联别名和映射路径--><servlet-name>userServlet</servlet-name><!--可以为一个Servlet匹配多个不同的映射路径,但是不同的Servlet不能使用相同的url-pattern--><url-pattern>/userServlet</url-pattern><!-- <url-pattern>/userServlet2</url-pattern>--><!--/        表示通配所有资源,不包括jsp文件/*       表示通配所有资源,包括jsp文件/a/*     匹配所有以a前缀的映射路径*.action 匹配所有以action为后缀的映射路径--><!-- <url-pattern>/*</url-pattern>--></servlet-mapping>
</web-app>
  • Servlet并不是文件系统中实际存在的文件或者目录,所以为了能够请求到该资源,我们需要为其配置映射路径

  • servlet的请求映射路径配置在web.xml中

  • servlet-name作为servlet的别名,可以自己随意定义,见名知意就好

  • url-pattern标签用于定义Servlet的请求映射路径

  • 一个servlet可以对应多个不同的url-pattern

  • 多个servlet不能使用相同的url-pattern

  • url-pattern中可以使用一些通配写法

    • / 表示通配所有资源,不包括jsp文件

    • /* 表示通配所有资源,包括jsp文件

    • /a/* 匹配所有以a前缀的映射路径

    • *.action 匹配所有以action为后缀的映射路径

 

步骤4 开发一个form表单,向servlet发送一个get请求并携带username参数

index.html文件:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="get" action="userServlet">用户名:<input type="text" name="username"> <br><input type="submit" value="校验">
</form>
</body>
</html>

Content-type的设置

Content-type响应头,决定响应报文的响应体会被客户端当作什么文件类型处理。

使用ServletResponse对象调用方法setContentType()

关于url-pattern

在web.xml中:

  • servlet-class 告诉Tomcat对应的要实例化的Servlet类
  • servlet-name 用于关联请求的映射路径
  • servlet-mapping 用来设置对应servlet-name的映射路径
  • url-pattern 用来设置路径名

注: 

  1. 一个servlet-name可以对应多个url-pattern
  2. 一个servlet标签可以对应多个servlet-mapping标签
  3. 每个url-pattern设置的路径名不能重复

url-pattern的写法

精确匹配

格式:/路径名

要输入完全一样的路径名才能访问

模糊匹配

*作为通配符, *在哪里,哪里就是模糊不确定的

格式①:/

        只有一个/符号,意味着无论后面的内容是什么,都认作为此路径,jsp文件除外

格式②:/*

        无论后面的内容是什么,都认作为此路径,jsp文件不除外

格式③:/(字符或字符串)*

        匹配前缀,以指定字符为开头的路径,即都认作此路径

格式④:*(字符或字符串)

        匹配后缀,以指定字符为开头的路径,即都认作此路径

4.注解方式配置servlet

使用注解@WebServlet()即可快速配置路径名

参数直接写一个路径名格式的字符串即可(也可以是value=”路径名“或urlPattern=”路径名”),若要给一个servlet多个路径名,参数写value={”路径名1“,”路径名2“,……}( 或urlPattern={”路径名1“,”路径名2“,……} )

5.Servlet生命周期

  1. 实例化:即调用定义的Servlet类的构造器
  2. 初始化:调用init方法进行初始化
  3. 接受请求,处理请求:调用service方法
  4. 销毁:调用destory方法

5.1Servlet的生命周期

  • 应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为——这就是对象的生命周期。

  • 简单的叙述生命周期,就是对象在容器中从开始创建到销毁的过程。

5.2Servlet容器

  • Servlet对象是Servlet容器创建的,生命周期方法都是由容器(目前我们使用的是Tomcat)调用的。这一点和我们之前所编写的代码有很大不同。在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用,开发人员要尽可能多的将精力放在业务逻辑的实现上。

5.3Servlet主要的生命周期执行特点

生命周期对应方法执行时机执行次数
构造对象构造器第一次请求或者容器启动1
初始化init()构造完毕后1
处理服务service(HttpServletRequest req,HttpServletResponse resp)每次请求多次
销毁destory()容器关闭1

于load-on-startup

load-on-startup默认为-1,如果是-1,即默认tomcat启动时不会实例化该servlet

如果是正整数则表示容器在启动时就要实例化Servlet,数字表示的是实例化的顺序

load-on-up的赋值可以在注解@WebServlet()中赋值,若要赋值为6,参数列表为(value=“路径名”,loadOnStartup = 6

也可以在web.xml文件中赋值,例:

 <servlet><servlet-name>servletLifeCycle</servlet-name><servlet-class>com.atguigu.servlet.ServletLifeCycle</servlet-class><!--load-on-startup如果配置的是正整数则表示容器在启动时就要实例化Servlet,数字表示的是实例化的顺序--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>servletLifeCycle</servlet-name><url-pattern>/servletLiftCycle</url-pattern></servlet-mapping>

java文件

@WebServlet("/servletLifeCycle")
public class ServletLifeCycle extends HttpServlet {/*生命周期   对应方法                                            执行时机            执行次数| 构造对象(实例化)      | 构造器                                | 第一次请求或者容器启动 | 1| 初始化               | init()                               | 构造完毕后            | 1| 处理服务 接受请求      | service(HttpServletRequest req,HttpServletResponse resp)           | 每次请求              | 多次| 销毁                 | destory()                           | 容器关闭              | 1生命周期总结1. 通过生命周期测试我们发现Servlet对象在容器中是单例的2. 容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程3. 多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量4. load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复5. Tomcat容器中,已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5default-servlet  当和所有servlet后,匹配不到路径时,执行default-servlet*/public ServletLifeCycle(){System.out.println("构造器");}@Overridepublic void init() throws ServletException {System.out.println("初始化方法");}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("service方法");}@Overridepublic void destroy() {System.out.println("销毁方法");}
}

5.4生命周期总结

  1. 通过生命周期测试我们发现Servlet对象在容器中是单例的

  2. 容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程

  3. 多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量

  4. load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复

  5. Tomcat容器中,已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5

6 Servlet继承结构

 6.1Servlet 接口

源码

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public interface Servlet {/*** 初始化 Servlet,在第一次请求时调用。* * @param config ServletConfig 对象,包含了 Servlet 的初始化参数* @throws ServletException 如果发生 Servlet 异常*/void init(ServletConfig config) throws ServletException;/*** 获取 Servlet 配置。* * @return ServletConfig 对象*/ServletConfig getServletConfig();/*** 处理客户端请求。* * @param req  ServletRequest 对象,代表客户端的请求* @param res  ServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;/*** 返回 Servlet 的信息。* * @return Servlet 的信息*/String getServletInfo();/*** 销毁 Servlet,在 Servlet 被移除时调用。*/void destroy();
}

 方法说明

  1. init(ServletConfig config): 初始化 Servlet。这个方法在 Servlet 第一次被请求时调用,并且只调用一次。ServletConfig 对象包含了 Servlet 的初始化参数。

  2. getServletConfig(): 返回一个 ServletConfig 对象,该对象包含了 Servlet 的配置信息。

  3. service(ServletRequest req, ServletResponse res): 处理客户端的请求。这个方法会根据请求的类型(GET、POST 等)来调用适当的方法(如 doGet 或 doPost)。ServletRequest 和 ServletResponse 对象分别代表客户端的请求和服务器端的响应。

  4. getServletInfo(): 返回一个字符串,包含关于 Servlet 的信息,如作者、版本等。

  5. destroy(): 销毁 Servlet。当 Servlet 被移除时调用,用于释放资源。

扩展接口

Servlet 接口通常由 GenericServlet 类实现,而 GenericServlet 类又实现了 ServletConfig 接口。HttpServlet 类则进一步扩展了 GenericServlet,并提供了处理 HTTP 请求的方法(如 doGet 和 doPost)。

  • Servlet 规范接口,所有的Servlet必须实现

    • public void init(ServletConfig config) throws ServletException;

      • 初始化方法,容器在构造servlet对象后,自动调用的方法,容器负责实例化一个ServletConfig对象,并在调用该方法时传入

      • ServletConfig对象可以为Servlet 提供初始化参数

    • public ServletConfig getServletConfig();

      • 获取ServletConfig对象的方法,后续可以通过该对象获取Servlet初始化参数

    • public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

      • 处理请求并做出响应的服务方法,每次请求产生时由容器调用

      • 容器创建一个ServletRequest对象和ServletResponse对象,容器在调用service方法时,传入这两个对象

    • public String getServletInfo();

      • 获取ServletInfo信息的方法

    • public void destroy();

      • Servlet实例在销毁之前调用的方法

6.2GenericServlet 抽象类

源码

import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;public abstract class GenericServlet implements Servlet {private ServletConfig config;/*** 初始化 Servlet。* * @param config ServletConfig 对象,包含了 Servlet 的初始化参数* @throws ServletException 如果发生 Servlet 异常*/@Overridepublic void init(ServletConfig config) throws ServletException {this.config = config;this.init(); // 调用子类的 init 方法}/*** 子类可以重写这个方法来进行初始化操作。* * @throws ServletException 如果发生 Servlet 异常*/protected void init() throws ServletException {// 子类可以重写这个方法来进行初始化操作}/*** 返回一个 ServletConfig 对象,该对象包含了 Servlet 的配置信息。* * @return ServletConfig 对象*/@Overridepublic ServletConfig getServletConfig() {return config;}/*** 处理客户端的请求。* * @param req  ServletRequest 对象,代表客户端的请求* @param res  ServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/@Overridepublic abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;/*** 返回一个字符串,包含关于 Servlet 的信息,如作者、版本等。* * @return Servlet 的信息*/@Overridepublic String getServletInfo() {return "";}/*** 销毁 Servlet,在 Servlet 被移除时调用。* * @throws ServletException 如果发生 Servlet 异常*/@Overridepublic void destroy() {// 子类可以重写这个方法来进行清理操作}// 其他辅助方法/*** 返回指定名称的初始化参数的值。* * @param name 初始化参数的名称* @return 初始化参数的值*/protected String getInitParameter(String name) {return config.getInitParameter(name);}/*** 返回一个包含所有初始化参数名称的枚举。* * @return 初始化参数名称的枚举*/protected Enumeration<String> getInitParameterNames() {return config.getInitParameterNames();}/*** 返回一个 ServletContext 对象,该对象代表了 Servlet 的运行环境。* * @return ServletContext 对象*/protected ServletContext getServletContext() {return config.getServletContext();}
}

方法说明

  1. init(ServletConfig config): 初始化 Servlet。这个方法在 Servlet 第一次被请求时调用,并且只调用一次。ServletConfig 对象包含了 Servlet 的初始化参数。

  2. getServletConfig(): 返回一个 ServletConfig 对象,该对象包含了 Servlet 的配置信息。

  3. service(ServletRequest req, ServletResponse res): 处理客户端的请求。这个方法会根据请求的类型(GET、POST 等)来调用适当的方法(如 doGet 或 doPost)。ServletRequest 和 ServletResponse 对象分别代表客户端的请求和服务器端的响应。

  4. getServletInfo(): 返回一个字符串,包含关于 Servlet 的信息,如作者、版本等。

  5. destroy(): 销毁 Servlet。当 Servlet 被移除时调用,用于释放资源。

  6. getInitParameter(String name): 返回指定名称的初始化参数的值。

  7. getInitParameterNames(): 返回一个包含所有初始化参数名称的枚举。

  8. getServletContext(): 返回一个 ServletContext 对象,该对象代表了 Servlet 的运行环境。

扩展

GenericServlet 是一个抽象类,它没有实现 service 方法。因此,任何继承 GenericServlet 的类都必须实现 service 方法。然而,GenericServlet 提供了一些辅助方法,如 getInitParameter 和 getServletContext,这些方法可以在子类中使用。

  • GenericServlet 抽象类是对Servlet接口一些固定功能的粗糙实现,以及对service方法的再次抽象声明,并定义了一些其他相关功能方法

    • private transient ServletConfig config;

      • 初始化配置对象作为属性

    • public GenericServlet() { }

      • 构造器,为了满足继承而准备

    • public void destroy() { }

      • 销毁方法的平庸实现

    • public String getInitParameter(String name)

      • 获取初始参数的快捷方法

    • public Enumeration<String> getInitParameterNames()

      • 返回所有初始化参数名的方法

    • public ServletConfig getServletConfig()

      • 获取初始Servlet初始配置对象ServletConfig的方法

    • public ServletContext getServletContext()

      • 获取上下文对象ServletContext的方法

    • public String getServletInfo()

      • 获取Servlet信息的平庸实现

    • public void init(ServletConfig config) throws ServletException()

      • 初始化方法的实现,并在此调用了init的重载方法

    • public void init() throws ServletException

      • 重载init方法,为了让我们自己定义初始化功能的方法

    • public void log(String msg)

    • public void log(String message, Throwable t)

      • 打印日志的方法及重载

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

      • 服务方法再次声明

    • public String getServletName()

      • 获取ServletName的方法

6.3HttpServlet 抽象类

源码

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public abstract class HttpServlet extends GenericServlet {@Overridepublic 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);}/*** 处理 HTTP 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();if (method.equals("GET")) {doGet(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("HEAD")) {doHead(req, resp);} else if (method.equals("OPTIONS")) {doOptions(req, resp);} else if (method.equals("TRACE")) {doTrace(req, resp);} else {// 处理未知 HTTP 方法resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "HTTP method " + method + " not supported");}}/*** 处理 GET 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP GET not supported");}/*** 处理 POST 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP POST not supported");}/*** 处理 PUT 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP PUT not supported");}/*** 处理 DELETE 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP DELETE not supported");}/*** 处理 HEAD 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP HEAD not supported");}/*** 处理 OPTIONS 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP OPTIONS not supported");}/*** 处理 TRACE 请求。* * @param req  HttpServletRequest 对象,代表客户端的请求* @param resp HttpServletResponse 对象,代表服务器端的响应* @throws ServletException 如果发生 Servlet 异常* @throws IOException 如果发生 I/O 异常*/protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {throw new ServletException("HTTP TRACE not supported");}// 其他辅助方法
}

方法说明

  1. service(ServletRequest req, ServletResponse res): 处理客户端的请求。这个方法会根据请求的类型(GET、POST 等)来调用适当的方法(如 doGet 或 doPost)。ServletRequest 和 ServletResponse 对象分别代表客户端的请求和服务器端的响应。

  2. service(HttpServletRequest req, HttpServletResponse resp): 处理 HTTP 请求。这个方法会根据请求的方法(GET、POST 等)来调用适当的方法(如 doGet 或 doPost)。

  3. doGet(HttpServletRequest req, HttpServletResponse resp): 处理 GET 请求。子类可以重写这个方法来处理 GET 请求。

  4. doPost(HttpServletRequest req, HttpServletResponse resp): 处理 POST 请求。子类可以重写这个方法来处理 POST 请求。

  5. doPut(HttpServletRequest req, HttpServletResponse resp): 处理 PUT 请求。子类可以重写这个方法来处理 PUT 请求。

  6. doDelete(HttpServletRequest req, HttpServletResponse resp): 处理 DELETE 请求。子类可以重写这个方法来处理 DELETE 请求。

  7. doHead(HttpServletRequest req, HttpServletResponse resp): 处理 HEAD 请求。子类可以重写这个方法来处理 HEAD 请求。

  8. doOptions(HttpServletRequest req, HttpServletResponse resp): 处理 OPTIONS 请求。子类可以重写这个方法来处理 OPTIONS 请求。

  9. doTrace(HttpServletRequest req, HttpServletResponse resp): 处理 TRACE 请求。子类可以重写这个方法来处理 TRACE 请求。

扩展

HttpServlet 是一个抽象类,它没有实现 service 方法。因此,任何继承 HttpServlet 的类都必须实现 service 方法。然而,HttpServlet 提供了一些处理 HTTP 请求的方法,如 doGet 和 doPost,这些方法可以在子类中使用。

  • abstract class HttpServlet extends GenericServlet HttpServlet抽象类,除了基本的实现以外,增加了更多的基础功能

    • 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";

      • 上述属性用于定义常见请求方式名常量值

    • public HttpServlet() {}

      • 构造器,用于处理继承

    • public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException

      • 对服务方法的实现

      • 在该方法中,将请求和响应对象转换成对应HTTP协议的HttpServletRequest HttpServletResponse对象

      • 调用重载的service方法

    • public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException

      • 重载的service方法,被重写的service方法所调用

      • 在该方法中,通过请求方式判断,调用具体的do***方法完成请求的处理

    • protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

    • protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException

      • 对应不同请求方式的处理方法

      • 除了doOptions和doTrace方法,其他的do*** 方法都在故意响应错误信息

6.4 自定义Servlet

 继承关系图解

注意

  • 自定义Servlet中,必须要对处理请求的方法进行重写

    • 要么重写service方法

    • 要么重写doGet/doPost方法

 7.ServletConfig和ServletContext

7.1 ServletConfig的使用

  • 为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象

  • 容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性

源码

import java.util.Enumeration;public interface ServletConfig {/*** 返回 Servlet 的名称。* * @return Servlet 的名称*/String getServletName();/*** 返回一个 ServletContext 对象,该对象代表了 Servlet 的运行环境。* * @return ServletContext 对象*/ServletContext getServletContext();/*** 返回指定名称的初始化参数的值。* * @param name 初始化参数的名称* @return 初始化参数的值*/String getInitParameter(String name);/*** 返回一个包含所有初始化参数名称的枚举。* * @return 初始化参数名称的枚举*/Enumeration<String> getInitParameterNames();
}

方法说明

  1. getServletName(): 返回 Servlet 的名称。

  2. getServletContext(): 返回一个 ServletContext 对象,该对象代表了 Servlet 的运行环境。

  3. getInitParameter(String name): 返回指定名称的初始化参数的值。

  4. getInitParameterNames(): 返回一个包含所有初始化参数名称的枚举。

    方法名作用
    getServletName()获取<servlet-name>HelloServlet</servlet-name>定义的Servlet名称
    getServletContext()获取ServletContext对象
    getInitParameter()获取配置Servlet时设置的『初始化参数』,根据名字获取值
    getInitParameterNames()获取所有初始化参数名组成的Enumeration对象

ServletConfig 的使用

  • 定义Servlet
    public class ServletA extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletConfig servletConfig = this.getServletConfig();// 根据参数名获取单个参数String value = servletConfig.getInitParameter("param1");System.out.println("param1:"+value);// 获取所有参数名Enumeration<String> parameterNames = servletConfig.getInitParameterNames();// 迭代并获取参数名while (parameterNames.hasMoreElements()) {String paramaterName = parameterNames.nextElement();System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));}}
    }public class ServletB extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletConfig servletConfig = this.getServletConfig();// 根据参数名获取单个参数String value = servletConfig.getInitParameter("param1");System.out.println("param1:"+value);// 获取所有参数名Enumeration<String> parameterNames = servletConfig.getInitParameterNames();// 迭代并获取参数名while (parameterNames.hasMoreElements()) {String paramaterName = parameterNames.nextElement();System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));}}
    }

配置Servlet
<servlet><servlet-name>ServletA</servlet-name><servlet-class>com.atguigu.servlet.ServletA</servlet-class><!--配置ServletA的初始参数--><init-param><param-name>param1</param-name><param-value>value1</param-value></init-param><init-param><param-name>param2</param-name><param-value>value2</param-value></init-param></servlet><servlet><servlet-name>ServletB</servlet-name><servlet-class>com.atguigu.servlet.ServletB</servlet-class><!--配置ServletB的初始参数--><init-param><param-name>param3</param-name><param-value>value3</param-value></init-param><init-param><param-name>param4</param-name><param-value>value4</param-value></init-param></servlet><servlet-mapping><servlet-name>ServletA</servlet-name><url-pattern>/servletA</url-pattern></servlet-mapping><servlet-mapping><servlet-name>ServletB</servlet-name><url-pattern>/servletB</url-pattern></servlet-mapping>

7.2 ServletContext的使用

  • ServletContext对象有称呼为上下文对象,或者叫应用域对象(后面统一讲解域对象)

  • 容器会为每个app创建一个独立的唯一的ServletContext对象

  • ServletContext对象为所有的Servlet所共享

  • ServletContext可以为所有的Servlet提供初始配置参数

7.3ServletContext源码

package javax.servlet;import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Set;/*** 定义了 Servlet 上下文(也就是 Web 应用程序的全局信息)的接口。* 每个 Web 应用程序都有一个 ServletContext 对象,它在 Web 应用启动时创建,* 并在 Web 应用停止时销毁。ServletContext 对象提供了一种在 Web 应用程序中* 存储和共享数据的机制。*/
public interface ServletContext {/*** 获取 Web 应用程序的上下文路径。* 例如,如果应用部署在 Tomcat 的 webapps 目录下的 demo 应用,返回的就是 "/demo"。* 如果部署在 ROOT 目录下,则返回空字符串 ""。*/String getContextPath();/*** 根据资源的路径返回其 Servlet 上下文。* 例如,如果当前应用是 demo,要访问 servlet 容器中的另一个应用 test 中的资源 index.jsp,* 假使资源的路径为 /test/index.jsp,那么可以通过调用 getContext("/test/index.jsp") 获取 test 应用的上下文。* 如果在 servlet 容器中找不到该资源或者该资源限制了外部的访问,则方法返回 null。*/ServletContext getContext(String uripath);/*** 获取当前 servlet 容器支持的 servlet 规范的最高版本。*/int getMajorVersion();/*** 获取当前 servlet 容器支持的 servlet 规范的最低版本。*/int getMinorVersion();/*** 返回文件的 MIME 类型,MIME 类型是容器配置的,可以通过 web.xml 进行配置。*/String getMimeType(String file);/*** 设置一个请求参数。*/void setAttribute(String name, Object value);/*** 获取一个请求参数。*/Object getAttribute(String name);/*** 获取所有请求参数的名称。*/Enumeration<String> getAttributeNames();/*** 移除一个请求参数。*/void removeAttribute(String name);/*** 获取 Servlet 容器的实实际路径。* 可以将一个虚拟路径转换为服务器上的物理路径,这对于文件操作非常有用。*/String getRealPath(String path);/*** 获取 Servlet 容器提供的资源。* @param path 相对于 Servlet 上下文的资源路径* @return 资源的 InputStream,如果找不到资源则返回 null* @throws MalformedURLException 如果路径无效*/InputStream getResourceAsStream(String path) throws MalformedURLException;/*** 获取相对于 Servlet 上下文的资源的 URL。* @param path 资源的路径* @return 资源的 URL,如果找不到资源则返回 null*/URL getResource(String path);/*** 获取 Web 应用程序的初始化参数。* @param name 参数名* @return 对应的参数值,如果没有设置则返回 null*/String getInitParameter(String name);/*** 获取所有初始化参数的名称。* @return 一个 Enumeration,包含所有的参数名称*/Enumeration<String> getInitParameterNames();/*** 获取 Servlet 上下文的名称。*/String getServletContextName();// ... 更多方法 .../*** 获取 Servlet 容器的相关信息,例如服务器信息。*/String getServerInfo();/*** 将 Servlet 上下文与一个登录的会话绑定。* @param session 要绑定的会话* @throws IllegalStateException 如果 Servlet 上下文已经被另一个会话绑定*/void login(String username, String password) throws ServletException;/*** 将 Servlet 上下文与一个登录的会话解绑。*/void logout();// ... 更多方法 ...}

7.4ServletContext其他重要API

获取资源的真实路径

String realPath = servletContext.getRealPath("资源在web目录中的路径");
  • 例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径. 只要使用了servletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题

获取项目的上下文路径

String contextPath = servletContext.getContextPath();
  • 项目的部署名称,也叫项目的上下文路径,在部署进入tomcat时所使用的路径,该路径是可能发生变化的,通过该API动态获取项目真实的上下文路径,可以帮助我们解决一些后端页面渲染技术或者请求转发和响应重定向中的路径问题

域对象的相关API

  • 域对象: 一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同

  • ServletContext代表应用,所以ServletContext域也叫作应用域,是webapp中最大的域,可以在本应用内实现数据的共享和传递

  • webapp中的三大域对象,分别是应用域,会话域,请求域

  • 后续我们会将三大域对象统一进行讲解和演示,三大域对象都具有的API如下

API功能解释
void setAttribute(String key,Object value);向域中存储/修改数据
Object getAttribute(String key);获得域中的数据
void removeAttribute(String key);移除域中的数据

@WebServlet("/servlet04")
public class Servlet4 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//行相关   GET/POST uri http/1.1System.out.println(req.getMethod());//获取请求方式System.out.println(req.getScheme());//获取请求协议System.out.println(req.getProtocol());//获取请求方式System.out.println(req.getRequestURI());//获取请求的uri项目内的资源路径System.out.println(req.getRequestURL());//获取请求的urL项目内资源的完成的路径/*URI统一资源标识符  /demo03/a.html                  interface URI{}             资源定位的要求和规范  动物类URL统一资源定位符  http://IP:port/domo03/a.html   cLass URL impLements URI{}  一个具体的资源路径    哺乳动物类*/System.out.println(req.getLocalPort());//本应用容器的端口号System.out.println(req.getRemotePort());//客户端发请求时使用的System.out.println(req.getRemotePort());//端口号客户端软件的端口号//头相关   key : value key : value ......//根据名字单独获取某个请求头String accept = req.getHeader("Accept");System.out.println("Accept"+accept);//获取本次请求中所有的请求头的名字Enumeration<String> headerNames = req.getHeaderNames();while (headerNames.hasMoreElements()){String hname = headerNames.nextElement();System.out.println(hname+":"+req.getHeader(hname));}}
}

8 HttpServletRequest

8.1HttpServletRequest

  • HttpServletRequest是一个接口,其父接口是ServletRequest

  • HttpServletRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入

  • HttpServletRequest代表客户端发来的请求,所有请求中的信息都可以通过该对象获得

8.2 HttpServletRequest常见API

  • 获取请求行信息相关(方式,请求的url,协议及版本)

API功能解释
StringBuffer getRequestURL();获取客户端请求的url
String getRequestURI();获取客户端请求项目中的具体资源
int getServerPort();获取客户端发送请求时的端口
int getLocalPort();获取本应用在所在容器的端口
int getRemotePort();获取客户端程序的端口
String getScheme();获取请求协议
String getProtocol();获取请求协议及版本号
String getMethod();获取请求方式
  • 获得请求头信息相关

API功能解释
String getHeader(String headerName);根据头名称获取请求头
Enumeration<String> getHeaderNames();获取所有的请求头名字
String getContentType();获取content-type请求头
  • 获得请求参数相关

API功能解释
String getParameter(String parameterName);根据请求参数名获取请求单个参数值
String[] getParameterValues(String parameterName);根据请求参数名获取请求多个参数值数组
Enumeration<String> getParameterNames();获取所有请求参数名
Map<String, String[]> getParameterMap();获取所有请求参数的键值对集合
BufferedReader getReader() throws IOException;获取读取请求体的字符输入流
ServletInputStream getInputStream() throws IOException;获取读取请求体的字节输入流
int getContentLength();获得请求体长度的字节数
  • 其他API

API功能解释
String getServletPath();获取请求的Servlet的映射路径
ServletContext getServletContext();获取ServletContext对象
Cookie[] getCookies();获取请求中的所有cookie
HttpSession getSession();获取Session对象
void setCharacterEncoding(String encoding) ;设置请求体字符集
@WebServlet("/servlet05")
public class Servlet05 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取键值对形式的参数//根据参数名获取个参数值String username = req.getParameter("username");System.out.println(username);String userPWD = req.getParameter("userPWD");System.out.println(userPWD);//根据参数名获取多个参数值String[] hobbies = req.getParameterValues("hobby");System.out.println(hobbies);//获取所有的参数名Enumeration<String> parameterNames = req.getParameterNames();while (parameterNames.hasMoreElements()) {String pname = parameterNames.nextElement();String[] values = req.getParameterValues(pname);if (values.length > 1) {System.out.println(pname + "=" + Arrays.toString(values));} else {System.out.println(pname + "=" + values[0]);}}//返回所有参数的map集合//key =参数名  value =参数值Map<String, String[]> parameterMap = req.getParameterMap();Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entries) {String pname = entry.getKey();String[] value = entry.getValue();if (value.length > 1) {System.out.println(pname + "=" + Arrays.toString(value));} else {System.out.println(pname + "=" + value[0]);}}/**以上API专门用于获取key=value形式的参数,无论这些参数是在url后还是在请求体中  GET   POST请求请求行     方式urihttp/1.1请求头请求体form表单标签提交GET请求时,参数以键值对形式放在urL后不放在请求体里, GET方式的请求也是可以有请求体post*///获得请求体中的非键值对数据?        JSON串   文件//获取一个从请求体中读取字符的字符输入流// BufferedReader reader = req.getReader()    JSON串//获得一个从请求中读取二进制数据字节的输入流//ServLetInputStream inputstream = req.getInputStream();文件}
}

9 HttpServletResponse

9.1 HttpServletResponse

  • HttpServletResponse是一个接口,其父接口是ServletResponse

  • HttpServletResponse是Tomcat预先创建的,在Tomcat调用service方法时传入

  • HttpServletResponse代表对客户端的响应,该对象会被转换成响应的报文发送给客户端,通过该对象我们可以设置响应信息

9.2 HttpServletResponse的常见API

  • 设置响应行相关

API功能解释
void setStatus(int code);设置响应状态码
  • 设置响应头相关

API功能解释
void setHeader(String headerName, String headerValue);设置/修改响应头键值对
void setContentType(String contentType);设置content-type响应头及响应字符集(设置MIME类型)
  • 设置响应体相关

API功能解释
PrintWriter getWriter() throws IOException;获得向响应体放入信息的字符输出流
ServletOutputStream getOutputStream() throws IOException;获得向响应体放入信息的字节输出流
void setContentLength(int length);设置响应体的字节长度,其实就是在设置content-length响应头
  • 其他API

API功能解释
void sendError(int code, String message) throws IOException;向客户端响应错误信息的方法,需要指定响应码和响应信息
void addCookie(Cookie cookie);向响应体中增加cookie
void setCharacterEncoding(String encoding);设置响应体字符集

MIME类型

  • MIME类型,可以理解为文档类型,用户表示传递的数据是属于什么类型的文档

  • 浏览器可以根据MIME类型决定该用什么样的方式解析接收到的响应体数据

  • 可以这样理解: 前后端交互数据时,告诉对方发给对方的是 html/css/js/图片/声音/视频/... ...

  • tomcat/conf/web.xml中配置了常见文件的拓展名和MIMIE类型的对应关系

  • 常见的MIME类型举例如下

文件拓展名MIME类型
.htmltext/html
.csstext/css
.jsapplication/javascript
.png /.jpeg/.jpg/... ...image/jpeg
.mp3/.mpe/.mpeg/ ... ...audio/mpeg
.mp4video/mp4
.m1v/.m1v/.m2v/.mpe/... ...video/mpeg

@WebServlet("/servlet06")
public class Servlet06 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//设置响应行相关的API HTTP/1.1 200/404/405/500/ . . .resp.setStatus(200);String info="<h1>孙俊祥大佬好</h1>";//设置响应体API//resp.setHeader("aaa","value");//resp.setHeader("Content-Type","text/html")//resp.setHeader("Content-Length","text/html")resp.setContentType("text/html");resp.setContentLength(1234);//设置响应体内容API//获得一个向响应体中输入文本字符输入流PrintWriter writer=resp.getWriter();
//        writer.write("<h1>孙俊祥大佬好</h1>");writer.write(info);//获得一个向响应体中输入二进制信息的字节输出流
//        ServletOutputStream outputStream = resp.getOutputStream();}
}

10 请求转发和响应重定向

10.1 概述

什么是请求转发和响应重定向

  • 请求转发和响应重定向是web应用中间接访问项目资源的两种手段,也是Servlet控制页面跳转的两种手段

  • 请求转发通过HttpServletRequest实现,响应重定向通过HttpServletResponse实现

  • 请求转发生活举例: 张三找李四借钱,李四没有,李四找王五,让王五借给张三

  • 响应重定向生活举例:张三找李四借钱,李四没有,李四让张三去找王五,张三自己再去找王五借钱

10.2 请求转发

请求转发运行逻辑图

请求转发特点

  • 请求转发通过HttpServletRequest对象获取请求转发器实现

  • 请求转发是服务器内部的行为,对客户端是屏蔽的

  • 客户端只发送了一次请求,客户端地址栏不变

  • 服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源

  • 因为全程只有一个HttpServletRequset对象,所以请求参数可以传递,请求域中的数据也可以传递

  • 请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转

  • 请求转发可以转发给WEB-INF下受保护的资源

  • 请求转发不能转发到本项目以外的外部资源

    @WebServlet("/servletA")
    public class ServletA extends HttpServlet {/**1请求转发是通过HttpservLetRequest对象实现的*2请求转发是服务器内部行为,对客户端是屏蔽的*3客户端只产生了一次请求服务端只产生了一对 request 利response对象*4客户端的地址栏是不变的*5请求的参数是可以继续传递的*6目标资源可以是servlet动态资源也可以是html静态资源*7目标资源可以是WEB-INF下的受保护的资源该方式也是WEB-工INF下的资源的唯一访问方式*8.外部资源不可以是外部的资源*/@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("servletA 执行了");String money = req.getParameter("money");System.out.println("servletA获得参数:money="+money);//请求转发给ServletB//获得请求转发器//*1请求转发是通过HttpservLetRequest对象实现的//     *2请求转发是服务器内部行为,对客户端是屏蔽的//     *3客户端只产生了一次请求服务端只产生了一对 request 利response对象//     *4客户端的地址栏是不变的//     *5请求的参数是可以继续传递的
    //        RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB");//6目标资源可以是servlet动态资源也可以是html静态资源
    //        RequestDispatcher requestDispatcher = req.getRequestDispatcher("大佬.html");//7目标资源可以是WEB-INF下的受保护的资源该方式也是WEB-工INF下的资源的唯一访问方式
    //        RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/大佬B.html");//8.外部资源不可以是外部的资源RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.bilibili.com");//让请求转发器做出转发动作requestDispatcher.forward(req, resp);}
    }

10.3 响应重定向

响应重定向运行逻辑图

响应重定向特点

  • 响应重定向通过HttpServletResponse对象的sendRedirect方法实现

  • 响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的,客户端的行为

  • 客户端至少发送了两次请求,客户端地址栏是要变化的

  • 服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源

  • 因为全程产生了多个HttpServletRequset对象,所以请求参数不可以传递,请求域中的数据也不可以传递

  • 重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转

  • 重定向不可以到给WEB-INF下受保护的资源

  • 重定向可以到本项目以外的外部资源

    @WebServlet("/servlet1")
    public class Servlet1 extends HttpServlet {/*响应重定向*1.响应重定向是通动HttpServLetResponse对象实现*2.响应重定向是在服务端提示下的,客户端的行为,*3.客户端的地址栏是变化的*4.客户端至少发送了两次请求客户端产生了多次请求*5.请求产生了多次   后端就会有多个request对象    此时请求中的参数不能继续自动传递*6.目标资源资源可以视图资源*7.目标资源不可以是wEB-INF下的资源*8.目标资源可以是外部资源**** 重点:同样能够实现页面跳转,优先使用响应重定向*** */@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//接收用户请求System.out.println("Servlet1 执行了");//*5.请求产生了多次   后端就会有多个request对象    此时请求中的参数不能继续自动传递System.out.println("servlet1 got money="+req.getParameter("money"));//响应重定向         设置响应状态码为302同时设置Location 响应头://*1.响应重定向是通动HttpServLetResponse对象实现//    *2.响应重定向是在服务端提示下的,客户端的行为,//    *3.客户端的地址栏是变化的//    *4.客户端至少发送了两次请求客户端产生了多次请求
    //        resp.sendRedirect("servlet2");//*6.目标资源资源可以视图资源
    //        resp.sendRedirect("a.html");//*7.目标资源不可以是wEB-INF下的资源
    //        resp.sendRedirect("WEB-INF/b.html");//*8.目标资源可以是外部资源resp.sendRedirect("http://www.bilibili.com");}
    }

十一 MVC架构模式

MVC(Model View Controller)是软件工程中的一种软件架构模式,它把软件系统分为模型视图控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

  • M:Model 模型层,具体功能如下

    1. 存放和数据库对象的实体类以及一些用于存储非数据库表完整相关的VO对象

    2. 存放一些对数据进行逻辑运算操作的的一些业务处理代码

  • V:View 视图层,具体功能如下

    1. 存放一些视图文件相关的代码 html css js等

    2. 在前后端分离的项目中,后端已经没有视图文件,该层次已经衍化成独立的前端项目

  • C:Controller 控制层,具体功能如下

    1. 接收客户端请求,获得请求数据

    2. 将准备好的数据响应给客户端

MVC模式下,项目中的常见包

  • M:

    1. 实体类包(pojo /entity /bean) 专门存放和数据库对应的实体类和一些VO对象

    2. 数据库访问包(dao/mapper) 专门存放对数据库不同表格CURD方法封装的一些类

    3. 服务包(service) 专门存放对数据进行业务逻辑运算的一些类

  • C:

    1. 控制层包(controller)

  • V:

    1. web目录下的视图资源 html css js img 等

    2. 前端工程化后,在后端项目中已经不存在了

非前后端分离的MVC

前后端分离的MVC  

举例

张三网络购物买10本<<JAVA从入门到精通>>

相关文章:

Servlet

一 Servlet Servlet (server applet) 是运行在服务端(tomcat)的Java小程序&#xff0c;是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中&#xff0c;Servlet主要负责接收处理请求…...

MySQL用法---MySQL Workbench创建数据库和表

1. 连接数据库 打开软件&#xff0c;点击左下角卡片&#xff0c;输入设置的数据库密码&#xff0c;勾选单选框 2. 了解主页面的组成部分 3. 创建数据库 先点击工具栏的创建按钮 再输入数据库名称 点击 Apply 创建 4. 创建数据表 展开数据库&#xff0c;在Tables上右键&…...

WordPress Elementor Page Builde 任意文件读取漏洞复现(CVE-2024-9935)

0x01 产品描述: WordPress Elementor Page Builder 是一款 WordPress 插件,它允许用户以可视化方式创建和编辑网页。0x02 漏洞描述: WordPress 的 Elementor Page Builder 插件的 PDF 生成器插件在 1.7.5 之前的所有版本中都容易受到路径遍历的攻击,包括 1.7.5 rtw_pgaepb_…...

静态链接和动态链接的特点

静态链接 链接方式‌&#xff1a;在编译时&#xff0c;所有依赖的库代码被直接打包到生成的可执行文件中。这意味着在程序运行时&#xff0c;不需要再加载任何外部库文件‌。 优点‌&#xff1a; 独立性强‌&#xff1a;生成的可执行文件可以在没有依赖库的系统上直接运行&am…...

内核流对象(Kernel Streaming Objects)

内核流对象(Kernel Streaming Objects)是 Windows 系统中用于处理音频、视频等流媒体数据的重要机制。让我详细解释其作用和主要组件&#xff1a; 1. 主要作用&#xff1a; c // 内核流的核心功能 - 音频/视频数据的实时处理 - 多媒体设备驱动开发 - 硬件与软件之间的数据流传…...

Java 在Json对象字符串中查找和提取特定的数据

1、在处理JSON数据时&#xff0c;需要提出个别字段的值&#xff0c;通过正则表达式提取特定的数据 public static void main(String[] args) {//定义多个JSON对象字符串类型&#xff0c;假设每个对象有a,b,c 字段String strJson "{\"a\":1.23,\"b\"…...

21、结构体成员分布

结构体中的成员并不是紧挨着分布的&#xff0c;内存分布遵循字节对齐的原则。 按照成员定义的顺序&#xff0c;遵循字节对齐的原则存储。 字节对齐的原则&#xff1a; 找成员中占据字节数最大的成员&#xff0c;以它为单位进行空间空配 --- 遇到数组看元素的类型 每一个成员距离…...

【深度学习】四大图像分类网络之ResNet

ResNet网络是在2015年由微软实验室中的何凯明等几位提出&#xff0c;在CVPR 2016发表影响深远的网络模型&#xff0c;由何凯明团队提出来&#xff0c;在ImageNet的分类比赛上将网络深度直接提高到了152层&#xff0c;前一年夺冠的VGG只有19层。斩获当年ImageNet竞赛中分类任务第…...

zookeeper学习

解决什么问题&#xff1f; 首先来分析下业务对象&#xff0c;才能对解决的问题进行归纳和总结。它解决的事分布式应用的问题&#xff0c;那么分布式应用会存在哪里问题是由它的业务特性来决定的&#xff0c;这些问题已是为了解决业务的问题。分布式的业务特征有哪些&#xff1…...

Monkey结合appium模拟操作特定界面

目录 1. 使用 Monkey 操作特定界面&#xff08;通过UI标识来限制&#xff09; 2. 结合 uiautomator 或 appium 定位特定元素 步骤&#xff1a; 3. 使用 Monkey Appium 控制特定界面点击 4. 如何结合 Appium 与 Monkey 5. 限制 Monkey 只点击固定界面上的元素 使用 --pc…...

智能指针【C++11】

文章目录 智能指针std::auto_ptr std::unique_ptrstd::shared_ptrstd::shared_ptr的线程安全问题std::weak_ptr 智能指针 std::auto_ptr 管理权转移 auto_ptr是C98中引入的智能指针&#xff0c;auto_ptr通过管理权转移的方式解决智能指针的拷贝问题&#xff0c;保证一个资源…...

plsql 执行存储过程 SYS_REFCURSOR

关键字&#xff1a;plsql 执行存储过程 SYS_REFCURSOR 在PL/SQL中&#xff0c;SYS_REFCURSOR是一种特殊的数据类型&#xff0c;用于表示引用游标&#xff0c;可以用来返回查询结果或者操作数据库中的结果集。 以下是一个使用SYS_REFCURSOR执行存储过程的例子&#xff1a; CR…...

git修改某次commit(白痴版)

第一步 在bash窗口运行 git rebase --interactive commitId^ 比如要改的commitId是 abcedf git rebase --interactive abcedf^键盘 按 i 或者 ins 进入编辑状态 进入insert 编辑状态 在bash窗口手动把对应commit前面的pick改为e或edit 按 esc 进入退出程序 输入 :wq 保存退出…...

设计模式:19、桥接模式

目录 0、定义 1、桥接模式的四种角色 2、桥接模式的UML类图 3、示例代码 0、定义 将抽象部门与实现部分分离&#xff0c;使它们都可以独立地变化。 1、桥接模式的四种角色 抽象&#xff08;Abstraction&#xff09;&#xff1a;一个抽象类&#xff0c;包含实现者&#xf…...

闭包函数的基础知识

上期文章 1. 函数装饰器 2.闭包 2.1变量作用域 python有3种变量作用域 模块全局作用域:在类或函数外部分配定义的。函数局部作用域:通过参数或者在函数主体中定义的。第3种作用域:闭包中的变量环境 2.2全局变量和局部变量 def fun(a):print(a)print(b)fun(10)10---------…...

python3D圣诞树

import pygame import math from pygame.locals import *# 初始化Pygame pygame.init()# 设置屏幕尺寸和标题 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption(3D 圣诞树)# 设置颜色 GREEN (34, 139, 34) BROWN (139,…...

博物馆导览系统方案(一)背景需求分析与核心技术实现

维小帮提供多个场所的室内外导航导览方案&#xff0c;如需获取博物馆导览系统解决方案可前往文章最下方获取&#xff0c;如有项目合作及技术交流欢迎私信我们哦~撒花&#xff01; 一、博物馆导览系统的背景与市场需求 在数字化转型的浪潮中&#xff0c;博物馆作为文化传承和知…...

[代码随想录09]字符串2的总结

前言 处理字符串主要是有思路&#xff0c;同时总结方法。 题目链接 151. 反转字符串中的单词 - 力扣&#xff08;LeetCode&#xff09; 55. 右旋字符串&#xff08;第八期模拟笔试&#xff09; 一、翻转字符串里的单词 这个题目的主要思路&#xff0c;代码采用从后往前遍历字…...

C语言程序设计P5-3【应用函数进行程序设计 | 第三节】——知识要点:函数的嵌套调用和递归调用

知识要点&#xff1a;函数的嵌套调用和递归调用 视频 目录 一、任务分析 二、必备知识与理论 三、任务实施 一、任务分析 本任务要求用递归法求 n!。 我们知道n!n(n-1)(n-2)……1n(n-1)!递归公式为&#xff1a; 1.上面公式分解为n!n(n-1)!&#xff0c;即将求n!的问题变为…...

【Java】protobuf-maven-plugin主动下载protoc编译proto文件

背景: 我们hadoop的代码里,配置的是3.7.1的protocol buffer,但是编译环境上安装的是2.5.0。 能成功编译,且没有什么兼容性问题。这里非常好奇发生了什么,于是研究了一下protobuf-maven-plugin插件, 发现是他去下载的 在使用protobuf-maven-plugin插件时,我们一般会这么…...

Go学习:变量

目录 1. 变量的命名 2. 变量的声明 3. 变量声明时注意事项 4. 变量的初始化 5. 简单例子 变量主要用来存储数据信息&#xff0c;变量的值可以通过变量名进行访问。 1. 变量的命名 在Go语言中&#xff0c;变量名的命名规则 与其他编程语言一样&#xff0c;都是由字母、数…...

AllegroHand 四指灵巧手:机器人领域的创新力量

Allegro Hand 作为一款高性价比且适应性强的机器人四指灵巧手&#xff0c;凭借其四根手指和十六个独立的电流控制接头&#xff0c;成为机器人复杂抓握、柔性操作以及触觉传感器等研究领域的理想之选。 Allegrohand 四指灵巧手技术特点 机械结构 Allegro Hand的机械结构设计高…...

蓝桥杯准备训练(lesson3 ,c++)

变量与常量 4.1 变量的创建4.2 变量初始化4.3 变量的分类4.4 常量4.4.1 字⾯常量4.4.2 #define定义常量4.4.3 const定义常量4.5 练习练习1&#xff1a;买票练习2&#xff1a;AB问题练习3&#xff1a;鸡兔同笼 4.1 变量的创建 了解清楚了类型&#xff0c;我们使⽤类型做什么呢&…...

Conda + JuiceFS :增强 AI 开发环境共享能力

Conda 是当前 AI 应用开发领域中非常流行的环境和包管理系统&#xff0c;因其能够简单便捷地创建与系统资源相隔离的虚拟环境广受欢迎。 Conda 支持在不同的操作系统上重建相同的工作环境&#xff0c;但在环境共享复用方面仍存在一些挑战。比如&#xff0c;在不同机器上复用相…...

小红薯x-s算法最新补环境教程12-06更新(下)

在上一篇文章中已经讲了如何去定位x-s生成的位置&#xff0c;本篇文章就直接开始撸代码吧 如果没看过的话可以看&#xff1a;小红薯最新x-s算法分析12-06&#xff08;x-s 56&#xff09;&#xff08;上&#xff09;-CSDN博客 1、获取加密块代码 首先来到参数生成的位置&…...

强化ASPICE合规与认可度:关键策略与实践路径

确保ASPICE&#xff08;Automotive SPICE&#xff09;标准的合规性和认可度&#xff0c;是一个涉及多方面努力和持续改进的过程。以下是一些关键步骤和建议&#xff0c;以帮助企业实现这一目标&#xff1a; 一、熟悉ASPICE标准 深入阅读和理解&#xff1a;首先&#xff0c;需要…...

没有合理使用线程池,引发的生产环境BUG

引言 随着多线程和并发处理需求的增加&#xff0c;线程池成为了提升系统性能的重要工具。Java 提供了强大的 ThreadPoolExecutor 类&#xff0c;能够高效地管理线程池&#xff0c;减少线程创建和销毁的开销。然而&#xff0c;当线程池达到其最大容量时&#xff0c;如何优雅地处…...

异步处理与后台任务管理:在 FastAPI 中实现高级特性

异步处理与后台任务管理&#xff1a;在 FastAPI 中实现高级特性 目录 ⚡ 背景任务与异步处理概述&#x1f6e0;️ 使用 BackgroundTasks 执行后台任务&#x1f680; 异步视图函数&#xff1a;使用 async 和 await&#x1f504; 处理并发任务&#xff1a;提升应用性能与响应能…...

ceph存储池

1、存储池 1、存储池的概念 存储池就是ceph的逻辑分区&#xff0c;专门用来存储对象的 特点 将文件切片成对象&#xff0c;通过hash算法&#xff0c;找到存储池中的pg&#xff0c;池中的pg根据crush算法找到osd节点 存储中的PG数量对性能有重要的影响&#xff0c;过多和过少…...

STM32基于HAL库的串口接收中断触发机制和适用场景

1. HAL_UART_Receive_DMA函数 基本功能 作用&#xff1a;启动一个固定长度的 DMA 数据接收。特点&#xff1a; 需要预先指定接收数据的长度&#xff08;Size 参数&#xff09;。DMA 会一直工作直到接收到指定数量的数据&#xff0c;接收完成后触发 HAL_UART_RxCpltCallback 回…...

如何查看电脑的屏幕刷新率?

1、按一下键盘的 win i 键&#xff0c;打开如下界面&#xff0c;选择【系统】&#xff1a; 2、选择【屏幕】-【高级显示设置】 如下位置&#xff0c;显示屏幕的刷新率&#xff1a;60Hz 如果可以更改&#xff0c;则选择更高的刷新率&#xff0c;有助于电脑使用起来界面更加流…...

Q3收入回退,盈利与商业化落地步履艰难,文远知行亟待背水一战

撰稿|行星 来源|贝多财经 12月2日&#xff0c;全球商业杂志《Fortune》&#xff08;财富&#xff09;揭晓了2024年“未来50强”&#xff08;The Future 50&#xff09;企业榜单&#xff0c;上市不久的全球Rbotaxi第一股文远知行&#xff08;NASDAQ:WRD&#xff09;位列第26名…...

如何利用Java爬虫获得商品类目

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。获取和分析数据的能力对于任何希望在市场上保持竞争力的企业来说都是至关重要的。对于电子商务平台和市场研究公司而言&#xff0c;获取商品类目数据尤为重要&#xff0c;因为这些数据可以帮助他们更好地理解市场…...

Charts 教程:创建交互式图表的基础

ECharts 是一个开源的、基于 JavaScript 的数据可视化库&#xff0c;它可以帮助你快速创建交互式的图表。无论是简单的柱状图、折线图&#xff0c;还是复杂的地图和关系图&#xff0c;ECharts 都能够轻松应对。本文将带你了解如何在你的网页中使用 ECharts 创建图表&#xff0c…...

Jackson - JsonGenerator创建JSON、JsonParser解析JSON

以下是关于如何使用Jackson的JsonGenerator类来创建JSON内容以及如何使用JsonParser类来读取JSON内容的教程。 依赖项 首先&#xff0c;在pom.xml文件中添加以下依赖项以引入Jackson库&#xff1a; <dependency><groupId>com.fasterxml.jackson.core</groupI…...

数据结构与算法——1202—排序递归

1、选择排序 #include<iostream> #include<vector> using namespace std;void SelectSort(vector<int>& nums) {int i;int j;int minIndex;int length nums.size();if (length 0 || length 1) return;for (i 0; i < length-1; i)//遍历所有元素{…...

Lattice Radiant Software Lattice Propel Builder Lattice Propel 2024.1 安装

因项目需要&#xff0c;对Lattice 器件LIFCL-40 CrossLink进行评估 先从Lattice官网下载Radiant安装包&#xff1a; Lattice Radiant设计软件 新建工程环境...

【Linux系统】 Linux内核与UNIX设计哲学的结合

Linux 内核虽然不是 UNIX 的直接衍生物&#xff0c;但它深受 UNIX 设计哲学的影响。Linux 的开发者&#xff0c;尤其是 Linus Torvalds&#xff0c;在设计和实现 Linux 时&#xff0c;借鉴了 UNIX 的核心思想&#xff0c;使 Linux 成为一个类 UNIX 系统。 以下从 UNIX 设计哲学…...

MKS EDGE Series RF Generators Power Solution 软件

MKS EDGE Series RF Generators Power Solution 软件...

【机器学习 | 基于Lasso回归和随机森林的上海链家二手房房价预测】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 去除重复数据2.4 去除缺失数据2.5 面积、价格、单价、楼层、建筑时间数据提取2.6 朝向数据处理 &#x1f3f3;️‍&#x1f308; 3. 特…...

MyBatis-Plus分页查询方式

分页查询基本方式 SpringBootTest(classes LearningApplication.class) public class MPTest {AutowiredILearningLessonService lessonService;Testpublic void test(){/*** Page<LearningLesson>&#xff1a;MyBatisPlus提供的分页对象* 1&#xff1a;当前页数* 2&am…...

分布式cap

P&#xff08;分区安全&#xff09;都能保证&#xff0c;就是在C&#xff08;强一致&#xff09;和A&#xff08;性能&#xff09;之间做取舍。 &#xff08;即立马做主从同步&#xff0c;还是先返回写入结果等会再做主从同步。类似的还有&#xff0c;缓存和db之间的同步。&am…...

【组件封装】uniapp vue3 封装一个完整的Tabs(标签页)组件教程,功能由简到杂实现讲解。

文章目录 前言一、简单版Tabs代码实现&#xff1a; 二、下划线带动画的TabsAPI回顾&#xff1a;代码实现&#xff1a; 三、内容区域滑动切换切换动画代码实现&#xff1a;&#xff08;2&#xff09;禁用手势滑动切换&#xff08;3&#xff09;内容区域换为插槽 四、标签栏可滚动…...

AI在SEO中的应用与关键词优化探讨

内容概要 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术为搜索引擎优化&#xff08;SEO&#xff09;带来了革命性的改变。传统的SEO主要依赖于人为的经验和判断&#xff0c;而AI则通过算法分析海量数据&#xff0c;提供更加精准和高效的方式优化关键词…...

JUC:Synchronized和锁升级

1. 面试题 谈谈你对Synchronized的理解Sychronized的锁升级你聊聊Synchronized实现原理&#xff0c;monitor对象什么时候生成的&#xff1f;知道monitor的monitorenter和monitorexit这两个是怎么保证同步的嘛&#xff1f;或者说这两个操作计算机底层是如何执行的偏向锁和轻量级…...

如何使用锁实现多进程和多线程的并发执行的安全

多进程和多线程的并发&#xff1a; 多进程和多线程的并发意思是在同一段时间内&#xff0c;多个进程或者线程一起执行&#xff0c;但是这些进程或者线程的执行并不是真正意义上在同一时刻执行&#xff0c;而是在不同的时间里执行&#xff0c;因为每个CPU在同一时间只能处理同一…...

LabVIEW如何用运动控制卡实现伺服电机的转矩控制?

在LabVIEW中&#xff0c;使用运动控制卡实现伺服电机的转矩控制&#xff0c;通常通过以下几个步骤来完成。这里将结合LabVIEW的运动控制功能和伺服电机控制的基本原理进行详细介绍。 ​ 1. 选择合适的运动控制卡 要实现伺服电机的转矩控制&#xff0c;首先需要一张支持伺服电…...

SQL面试题——百度SQL面试题 无效搜索

百度SQL面试题 无效搜索 今天的题目是来自百度的SQL 面试题目 现有一份用户搜索日志,包含用户ID,时间,用户搜索内容。定义 无效搜索:如果用户下一次搜索内容中包含本次搜索内容,则认为本次搜索为无效搜索。请查询用户无效搜索记录 +---------+---------------------+--…...

媒体查询、浏览器一帧渲染过程

文章目录 媒体查询语法示例根据视口宽度应用不同的样式根据设备像素比应用不同的样式根据方向应用不同的样式 使用场景 浏览器一帧的渲染过程 媒体查询 媒体查询&#xff08;Media Query&#xff09;是CSS3中的一个重要特性&#xff0c;它允许开发者根据设备的特定条件&#x…...

实习工作日志

工作日志 遇到的bug 由于不熟悉Python&#xff0c;造成了这个bug python的浅拷贝与深拷贝&#xff0c;一定要创建新的变量&#xff0c;否则只是单纯拷贝地址...

殷涛、邓云生:古代兵学思想中的军队组织形态

军队是随着阶级和国家的出现而出现、发展而发展的,其组织形态亦愈发纷繁复杂,但万变不离其宗,一直遵循其固有之道。正如《大学》所言:&ldquo;物有本末,事有终始。知所先后,则近道矣。&rdquo;大道至简,衍化至繁。军队在兵力来源、人员类别、机构设置、职能定位等…...

何世龙:文明交流互鉴的“新年模式”

&ldquo;新年&rdquo;是人类历史上具有普遍意义的文化时间概念,蕴含着人类面向未来的智慧,传递着辞旧迎新的精神传统。每一个文明都创造了自己的新年,都有自己独特的新年仪式和年节符号,全世界共同建构了以&ldquo;祈福&rdquo;为中心的人类新年文化体系,推进…...

刘振起:阅读王春晓文章的三点认识

油画:遵义会议(邱瑞敏 章德明 等作)阅读1月28日昆仑策发表的王春晓的《1983年〈遵义会议若干情况的调查报告〉失实问题真相》一文,对他严谨的治学态度深感敬佩,同时也强烈的获得三点认识。一、《遵义会议若干情况的调查报告》是历史虚无主义的产物历史虚无主义的表现形式:…...

催人奋进!这台颁奖晚会有看点

&ldquo;为了胜利,向我开炮!&rdquo;这句《英雄儿女》的台词让无数观众记住了王成现实中赵先有烈士便是其原型之一近日第82集团军某营官兵与来队家属齐聚一堂隆重举办&ldquo;赵先有式好战士&rdquo;颁奖典礼此次&ldquo;赵先有式好战士&rdquo;评选坚持事…...

一字千军小论医疗之二

医疗卫生战线上也有激烈的路线斗争。养老和医疗卫生服务应是一个逆市场的反哺行为。免费医疗是对市场失灵的矫正。建议左派积极推动国家实行教育医疗住房免费。医疗改革是医药奇高的根本原因。医改既然不顺应该恢复全民免费医疗。毛主席是中国&ldquo;免费医疗&rdquo;的…...

湖南省韶山管理局下辖景点春节期间全部正常开放

2025年春节假期期间,湖南省韶山管理局下辖毛泽东同志故居、韶山毛泽东同志纪念馆、毛泽东广场、韶山毛泽东图书馆、滴水洞景区等核心景点,全部照常对外开放。其中毛泽东同志故居、韶山毛泽东同志纪念馆(生平展区与专题展区)、滴水洞景区需要实名制预约,请春节期间计划来韶…...