JavaWeb,Servlet的学习

动态资源和静态资源

静态资源

无需在程序运行时通过代码运行生成的资源

动态资源

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

Servlet简介

  • Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口
  • 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器
  • 不是所有的JAVA类都能用于处理客户端请求,能处理客户端请求并做出响应的一套技术标准就是Servlet
  • Servlet是运行在服务端的,所以 Servlet必须在WEB项目中开发且在Tomcat这样的服务容器中运行

Servlet是JavaWeb中后端的重点

servlet运行步骤

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

servlet开发流程

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

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

index.html文件:

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>

java文件:

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 {
    @Override
    public 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();
    }
}

web.xml文件:

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>
</web-app>

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文件不除外
格式③:/(字符或字符串)*

匹配前缀,以指定字符为开头的路径,即都认作此路径
格式④:*(字符或字符串)

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

注解方式配置servlet

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

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

Servlet生命周期

  1. 实例化:即调用定义的Servlet类的构造器
  2. 初始化:调用init方法进行初始化
  3. 接受请求,处理请求:调用service方法
  4. 销毁:调用destory方法
生命周期 对应方法 执行时机
构造对象 构造器 第一次请求或者容器启动
初始化 init() 构造完毕后
处理服务 service(HttpServletRequest req,HttpServletResponse resp) 每次请求
销毁 destory() 容器关闭

关于load-on-startup

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

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

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

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

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>

总结:

  1. 通过生命周期测试我们发现Servlet对象在容器中是单例的
  2. 容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程
  3. 多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量
  4. load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复
  5. Tomcat容器中,已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5

defaultServlet

当客户端请求静态资源时,没有匹配到某个servlet,于是就与defaultServlet进行匹配,defaultServlet就去找对应的静态资源响应给客户端。总的来说,defaultServlet是用来请求静态资源的。

Servlet继承结构

Servlet接口

  • 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实例在销毁之前调用的方法

GenericServlet抽象类

  • 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的方法

也不用记这么多,我也是复制粘贴过来的。只要记住GenericServlet 抽象类侧重实现除了service方法之外的其他抽象方法

HttpServlet抽象类

  • 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";1
    • 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*** 方法都在故意响应错误信息

总之,HttpServlet抽象类侧重service方法的实现,并根据请求方式对应具体的处理。

自定义Servlet类

由于HttpServlet抽象类中,service方法调用了do 方法,会响应对应请求方式的错误信息,如果在自定义Servlet类不重写service方法,就会响应错误信息。(也可以选择重写do 方法)

ServletConfig

Servlet是为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象。容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性。

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

配置初始参数

通过xml文件配置:

XML 复制代码
  <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>

通过注解的方式配置:

XML 复制代码
@WebServlet(
        urlPatterns = "/servlet",
        initParams = {@WebInitParam(name = "key1",value = "value1"),@WebInitParam(name = "key1",value = "value1"),......}
)

ServletContext

  • ServletContext对象有称呼为上下文对象,或者叫应用域对象(后面统一讲解域对象)
  • 容器会为每个app创建一个独立的唯一的ServletContext对象
  • ServletContext对象为所有的Servlet所共享
  • ServletContext可以为所有的Servlet提供初始配置参数

使用xml配置ServletContext的参数信息:

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

    <context-param>
        <param-name>paramA</param-name>
        <param-value>valueA</param-value>
    </context-param>
    <context-param>
        <param-name>paramB</param-name>
        <param-value>valueB</param-value>
    </context-param>
</web-app>

API

getServletContext():获取ServletContext对象,调用者可以是servletConfig,也可以是ServletRequest的对象,也可以没有调用者

getRealPath("资源在web目录中的路径"):获取资源的真实路径,调用者为ServletContext的对象(即磁盘路径)

getContextPath():获取项目的上下文路径(即访问路径,在浏览器地址框输入的那个)

域对象

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

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

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

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

HttpServletRequest

  • HttpServletRequest是一个接口,其父接口是ServletRequest
  • HttpServletRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入
  • 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) ; 设置请求体字符集

HttpServletResponse

  • HttpServletResponse是一个接口,其父接口是ServletResponse
  • HttpServletResponse是Tomcat预先创建的,在Tomcat调用service方法时传入
  • 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类型决定该用什么样的方式解析接收到的响应体数据
  • 常见的MIME类型举例如下
文件拓展名 MIME类型
.html text/html
.css text/css
.js application/javascript
.png /.jpeg/.jpg/... ... image/jpeg
.mp3/.mpe/.mpeg/ ... ... audio/mpeg
.mp4 video/mp4
.m1v/.m1v/.m2v/.mpe/... ... video/mpeg

请求转发和响应重定向

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

请求转发

  • 请求转发即ServletA收到请求后向ServletB发送此请求,让ServletB来处理此请求并响应给客户端

API

getRequestDispatcher("servletB"):获取请求转发器,调用者为HttpServletRequest的对象,参数为要转发的Servlet的对象的名字

forward(request,response):做出转发动作,调用者为转发器对象,参数为HttpServletRequest对象与HttpServletResponse对象

java 复制代码
//  获取请求转发器
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("servletB");
//  做出转发动作
        requestDispatcher.forward(request,response);

注:(重点)

  1. 请求转发是通过HttpServletRequest对象实现的
  2. 请求转发是服务器内部行为,对客户端是屏蔽的
  3. 在此期间,客户端只产生了一次请求,服务器只产生了一对request和reponse对象
  4. 客户端的地址是不变的
  5. 请求的参数是可以继续传递的
  6. 请求转发的目标资源可以是Servlet动态资源,也可以是静态资源,也可以是WEB-INF下的受保护的资源(该方式也是WEB-INF下的资源的唯一访问方式),不可以是外部资源(比如其他网页地址)

响应重定向

  • 响应重定向是ServletA收到请求后,响应给客户端让客户端重新发请求给ServletB,Servlet再处理请求并响应给客户端

API

sendRedirect("servlet1"):设置响应状态码为302,同时设置location为参数内的路径,调用者为HttpServletResponse对象

java 复制代码
response.sendRedirect("servlet2");

注:(重点)

  1. 响应重定向是通过HttpServletResponse对象实现
  2. 响应重定向是在服务器下的客户端的行为
  3. 客户端的地址会转到location的路径,客户端产生了多次请求(至少两次)
  4. 请求产生多次,后端就有多个request对象,此时请求中的参数不能继续自动传递
  5. 目标资源可以是视图资源,不能是WEB-INF下的资源,目标资源可以是外部资源
相关推荐
Abladol-aj38 分钟前
并发和并行的基础知识
java·linux·windows
清水白石00838 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
吾日三省吾码6 小时前
JVM 性能调优
java
弗拉唐7 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi778 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3438 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀8 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20208 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深8 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++