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下的资源,目标资源可以是外部资源
相关推荐
陌上花开࿈2 小时前
调用第三方接口
java
Aileen_0v03 小时前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
桂月二二4 小时前
Java与容器化:如何使用Docker和Kubernetes优化Java应用的部署
java·docker·kubernetes
liuxin334455665 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
小马爱打代码5 小时前
设计模式详解(建造者模式)
java·设计模式·建造者模式
栗子~~5 小时前
idea 8年使用整理
java·ide·intellij-idea
2301_801483696 小时前
Maven核心概念
java·maven
Q_19284999066 小时前
基于Spring Boot的电影售票系统
java·spring boot·后端
我要学编程(ಥ_ಥ)7 小时前
初始JavaEE篇 —— 网络原理---传输层协议:深入理解UDP/TCP
java·网络·tcp/ip·udp·java-ee
就爱学编程7 小时前
重生之我在异世界学编程之C语言:数据在内存中的存储篇(下)
java·服务器·c语言