动态资源和静态资源
静态资源
无需在程序运行时通过代码运行生成的资源
动态资源
需要在程序运行时通过代码生成的资源,在程序运行之前无法确定的数据,运行时动态生成,例如Servlet,Thymeleaf......
Servlet简介
- Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口
- 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器
- 不是所有的JAVA类都能用于处理客户端请求,能处理客户端请求并做出响应的一套技术标准就是Servlet
- Servlet是运行在服务端的,所以 Servlet必须在WEB项目中开发且在Tomcat这样的服务容器中运行
Servlet是JavaWeb中后端的重点
servlet运行步骤
- tomcat接受到请求后,将请求报文的信息转换为一个HttpServletRequest对象,该对象中包含了请求中的所有信息。
- tomcat同时创建了一个HttpServletResponse对象,该对象用于承装要响应给客户端的信息,后面,该对象会被转化为响应的报文。
- tomcat根据请求中的资源路径找到对应的servlet,将servlet实例化,调用service方法,同时将HttpServletRequest和HttpServletResponse对象传入。
servlet开发流程
- 创建JavaWeb项目,同时将tomcat添加为当前项目的依赖
- 重写service方法
- 在service方法中,定义业务处理代码
- 在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 用来设置路径名
注:
- 一个servlet-name可以对应多个url-pattern
- 一个servlet标签可以对应多个servlet-mapping标签
- 每个url-pattern设置的路径名不能重复
url-pattern的写法
精确匹配
格式:/路径名
要输入完全一样的路径名才能访问
模糊匹配
*作为通配符, *在哪里,哪里就是模糊不确定的
格式①:/
只有一个/符号,意味着无论后面的内容是什么,都认作为此路径,jsp文件除外
格式②:/*无论后面的内容是什么,都认作为此路径,jsp文件不除外
格式③:/(字符或字符串)*匹配前缀,以指定字符为开头的路径,即都认作此路径
格式④:*(字符或字符串)匹配后缀,以指定字符为开头的路径,即都认作此路径
注解方式配置servlet
使用注解@WebServlet()即可快速配置路径名
参数直接写一个路径名格式的字符串即可(也可以是value="路径名"或urlPattern="路径名"),若要给一个servlet多个路径名,参数写value={"路径名1","路径名2",......}( 或urlPattern={"路径名1","路径名2",......} )
Servlet生命周期
- 实例化:即调用定义的Servlet类的构造器
- 初始化:调用init方法进行初始化
- 接受请求,处理请求:调用service方法
- 销毁:调用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>
总结:
- 通过生命周期测试我们发现Servlet对象在容器中是单例的
- 容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程
- 多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量
- load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复
- 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);
注:(重点)
- 请求转发是通过HttpServletRequest对象实现的
- 请求转发是服务器内部行为,对客户端是屏蔽的
- 在此期间,客户端只产生了一次请求,服务器只产生了一对request和reponse对象
- 客户端的地址是不变的
- 请求的参数是可以继续传递的
- 请求转发的目标资源可以是Servlet动态资源,也可以是静态资源,也可以是WEB-INF下的受保护的资源(该方式也是WEB-INF下的资源的唯一访问方式),不可以是外部资源(比如其他网页地址)
响应重定向
- 响应重定向是ServletA收到请求后,响应给客户端让客户端重新发请求给ServletB,Servlet再处理请求并响应给客户端
API
sendRedirect("servlet1"):设置响应状态码为302,同时设置location为参数内的路径,调用者为HttpServletResponse对象
java
response.sendRedirect("servlet2");
注:(重点)
- 响应重定向是通过HttpServletResponse对象实现
- 响应重定向是在服务器下的客户端的行为
- 客户端的地址会转到location的路径,客户端产生了多次请求(至少两次)
- 请求产生多次,后端就有多个request对象,此时请求中的参数不能继续自动传递
- 目标资源可以是视图资源,不能是WEB-INF下的资源,目标资源可以是外部资源