目录
3. 在web.xml为UseServlet配置请求的映射路径
七、ServletConfig和ServletContext
(2)ServletConfig是一个接口,定义了如下API
B.配置Servlet(下面是web.xml配置文件配置,还有注解配置,前面注解有)
B.在Servlet中获取ServletContext并获取参数
(1)相对路径情况1:web/index.html中引入web/static/img/logo.png
(2)相对路径情况2:web/a/b/c/test.html中引入web/static/img/logo.png
(3)相对路径情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
(1)绝对路径情况1:web/index.html中引入web/static/img/logo.png
(2)绝对路径情况2:web/a/b/c/test.html中引入web/static/img/logo.png
(3)绝对路径情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
(2)index.html 和a/b/c/test.html 以及view1Servlet 中的路径处理
一、静态资源和动态资源
1.静态资源
无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源. 例如:html css js img ,音频文件和视频文件
2.动态资源
需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时动态生成,例如Servlet,Thymeleaf ... ...
动态资源指的不是视图上的动画效果或者是简单的人机交互效果
所以接下来就介绍动态资源的生成
二、Servlet简介
Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口
作用
1.用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求、协同调度功能以及响应数据。我们可以把Servlet称为Web应用中的控制器
2.不是所有的JAVA类都能用于处理客户端请求,能处理客户端请求并做出响应的一套技术标准就是Servlet
3.Servlet是运行在服务端的,所以 Servlet必须在WEB项目中开发且在Tomcat这样的服务容器中运行
三、Servlet配置文件方式配置
1. 开发一个web类型的module
前面一篇有说
2.开发一个UserServlet
public class UserServlet extends HttpServlet { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { //1.从request对象中获取请求参数 String username = request.getParameter("username"); //2.逻辑业务处理 String info= "OK"; if (username.equals("zhangsan")){ info ="NO"; } //3.要响应的数据放入response //应该设置content-Type响应头 //response.setHeader("Content-Type","text/html"); response.setContentType("text/html"); PrintWriter writer = response.getWriter(); //方法返回的是一个向响应体中打印字符串的打印流 writer.write(info); } }
自定义一个类,要继承HttpServlet类
重写service方法,该方法主要就是用于处理用户请求的服务方法
HttpServletRequest 代表请求对象,是有请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息
HttpServletResponse 代表响应对象,该对象会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息
Servlet对象的生命周期(创建,初始化,处理服务,销毁)是由tomcat管理的,无需我们自己new
HttpServletRequest HttpServletResponse 两个对象也是有tomcat负责转换,在调用service方法时传入给我们用的
3. 在web.xml为UseServlet配置请求的映射路径
<?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-name可以同时对应多个urL-pattern //一个servLet标签可以同时对应多个servLet-mapping标签 <servlet> <!--给UserServlet起一个别名--> <servlet-name>userServlet</servlet-name> <servlet-class>com.atguigu.servlet.UserServlet</servlet-class> </servlet> <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.启动项目,访问index.html ,提交表单测试
四、Servlet注解方式配置
1.@WebServlet注解源码
package jakarta.servlet.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @since Servlet 3.0
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
/**
* The name of the servlet
* 相当于 servlet-name
* @return the name of the servlet
*/
String name() default "";
/**
* The URL patterns of the servlet
* 如果只配置一个url-pattern ,则通过该属性即可,和urlPatterns属性互斥
* @return the URL patterns of the servlet
*/
String[] value() default {};
/**
* The URL patterns of the servlet
* 如果要配置多个url-pattern ,需要通过该属性,和value属性互斥
* @return the URL patterns of the servlet
*/
String[] urlPatterns() default {};
/**
* The load-on-startup order of the servlet
* 配置Servlet是否在项目加载时实例化
* 没在注解处声明的话默认是-1,第一次访问时才初始化
* 非负就在项目加载的时候实例化跑完生命周期前两个
* 6就代表第六个初始化 尽量不要和Tomcat占用的序号冲突
* @return the load-on-startup order of the servlet
*/
int loadOnStartup() default -1;
/**
* The init parameters of the servlet
* 配置初始化参数
* @return the init parameters of the servlet
*/
WebInitParam[] initParams() default {};
/**
* Declares whether the servlet supports asynchronous operation mode.
*
* @return {@code true} if the servlet supports asynchronous operation mode
* @see jakarta.servlet.ServletRequest#startAsync
* @see jakarta.servlet.ServletRequest#startAsync( jakarta.servlet.ServletRequest,jakarta.servlet.ServletResponse)
*/
boolean asyncSupported() default false;
/**
* The small-icon of the servlet
*
* @return the small-icon of the servlet
*/
String smallIcon() default "";
/**
* The large-icon of the servlet
*
* @return the large-icon of the servlet
*/
String largeIcon() default "";
/**
* The description of the servlet
*
* @return the description of the servlet
*/
String description() default "";
/**
* The display name of the servlet
*
* @return the display name of the servlet
*/
String displayName() default "";
}
2. @WebServlet注解使用
@WebServlet(
name = "userServlet",
//value = "/user",//一个路径写法
urlPatterns = {"/userServlet1","/userServlet2","/userServlet"},
initParams = {@WebInitParam(name = "encoding",value = "UTF-8")},
loadOnStartup = 6 //第6个初始化的servlet
)
public class UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String encoding = getServletConfig().getInitParameter("encoding");
System.out.println(encoding);
// 获取请求中的参数
String username = req.getParameter("username");
if("atguigu".equals(username)){
//通过响应对象响应信息
resp.getWriter().write("NO");
}else{
resp.getWriter().write("YES");
}
}
}
五、Servlet生命周期
1.四个周期
2.线程安全问题
线程安全问题,多个service线程修改成员变量
ServLet在Tomcat中是单例的
ServLet的成员变量在多个线程栈之中是共享的
不建议在service方法中修改成员变量在并发请求时,会引发线程安全问题
default-servLet用于加载静态资源的servlet,默认随服务启动,默认启动序号为1
3.总结
通过生命周期测试我们发现Servlet对象在容器中是单例的
容器是可以处理并发的用户请求的,每个请求在容器中都会开启一个线程
多个线程可能会使用相同的Servlet对象,所以在Servlet中,我们不要轻易定义一些容易经常发生修改的成员变量
load-on-startup中定义的正整数表示实例化顺序,如果数字重复了,容器会自行解决实例化顺序问题,但是应该避免重复
Tomcat容器中,已经定义了一些随系统启动实例化的servlet,我们自定义的servlet的load-on-startup尽量不要占用数字1-5
六、Servlet的继承结构
1.Servlet接口
2. GenericServlet 抽象类
GenericServlet 抽象类是对Servlet接口一些固定功能的粗糙实现,以及对service方法的再次抽象声明,并定义了一些其他相关功能方法
主要的作用就是提供得到servletConfig和servletContext的方法
3.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";
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*** 方法都在故意响应错误信息
4.自定义servlet
自定义Servlet中,必须要对处理请求的方法进行重写
要么重写service方法,要么重写doGet/doPost方法
七、ServletConfig和ServletContext
1.ServletConfig的使用
(1)作用
为Servlet提供初始配置参数的一种对象,每个Servlet都有自己独立唯一的ServletConfig对象
容器会为每个Servlet实例化一个ServletConfig对象,并通过Servlet生命周期的init方法传入给Servlet作为属性
(2)ServletConfig是一个接口,定义了如下API
package jakarta.servlet; import java.util.Enumeration; public interface ServletConfig { String getServletName(); ServletContext getServletContext(); String getInitParameter(String var1); Enumeration<String> getInitParameterNames(); }
(3)使用
A.定义Servlet
public class ServletA extends HttpServlet {
@Override
protected 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 {
@Override
protected 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));
}
}
}
B.配置Servlet(下面是web.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>
2.ServletContext的使用
(1)作用
ServletContext对象有称呼为上下文对象,或者叫应用域对象(后面统一讲解域对象)
容器会为每个app创建一个独立的唯一的ServletContext对象
ServletContext对象为所有的Servlet所共享
ServletContext可以为所有的Servlet提供初始配置参数
(2) 使用
A.配置ServletContext参数
<?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>
B.在Servlet中获取ServletContext并获取参数
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从ServletContext中获取为所有的Servlet准备的参数
ServletContext servletContext = this.getServletContext();
String valueA = servletContext.getInitParameter("paramA");
System.out.println("paramA:"+valueA);
// 获取所有参数名
Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
// 迭代并获取参数名
while (initParameterNames.hasMoreElements()) {
String paramaterName = initParameterNames.nextElement();
System.out.println(paramaterName+":"+servletContext.getInitParameter(paramaterName));
}
}
}
3.ServletContext其他重要API
(1)获取资源的真实路径 就是资源在本机电脑的绝对路径
String realPath = servletContext.getRealPath("资源在web目录中的路径");
(2)获取项目的上下文路径 就是接着端口号后面的一级/web1_demo1
String contextPath = servletContext.getContextPath();
(3)域对象的相关API
域对象: 一些用于存储数据和传递数据的对象,传递数据不同的范围,我们称之为不同的域,不同的域对象代表不同的域,共享数据的范围也不同
ServletContext代表应用,所以ServletContext域也叫作应用域,是webapp中最大的域,可以在本应用内实现数据的共享和传递 比如在一个servlet用下面的第一个API设置键值对数据,在另外一个servlet可以通过第二个API获取对应的值
webapp中的三大域对象,分别是应用域,会话域,请求域
八、HttpServletRequest
1.简介
HttpServletRequest是一个接口,其父接口是ServletRequest
HttpServletRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入
HttpServletRequest代表客户端发来的请求,所有请求中的信息都可以通过该对象获得
2.常见API
(1)获取请求行信息相关(方式,请求的url,协议及版本)
(2)获得请求头信息相关 (k-v,k-v..)
(3)获得请求参数相关
使用
(4)其他API
九、HttpServletResponse
1.简介
HttpServletResponse是一个接口,其父接口是ServletResponse
HttpServletResponse是Tomcat预先创建的,在Tomcat调用service方法时传入
HttpServletResponse代表对客户端的响应,该对象会被转换成响应的报文发送给客户端,通过该对象我们可以设置响应信息
2.常用API
(1)设置响应行相关
(2)设置响应头相关
(3)设置响应体相关
(4)其他API
3.MIME类型
MIME类型,可以理解为文档类型,用户表示传递的数据是属于什么类型的文档
浏览器可以根据MIME类型决定该用什么样的方式解析接收到的响应体数据
可以这样理解: 前后端交互数据时,告诉对方发给对方的是 html/css/js/图片/声音/视频/... ...
tomcat/conf/web.xml中配置了常见文件的拓展名和MIMIE类型的对应关系
常见的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
十、请求转发和响应重定向
1.概述
-
请求转发和响应重定向是web应用中间接访问项目资源的两种手段,也是Servlet控制页面跳转的两种手段
-
请求转发通过HttpServletRequest实现,响应重定向通过HttpServletResponse实现
-
请求转发生活举例: 张三找李四借钱,李四没有,李四找王五,让王五借给张三
-
响应重定向生活举例:张三找李四借钱,李四没有,李四让张三去找王五,张三自己再去找王五借钱
2.请求转发
(1)请求转发特点(背诵)
请求转发通过HttpServletRequest对象获取请求转发器实现
请求转发是服务器内部的行为,对客户端是屏蔽的
客户端只发送了一次请求,客户端地址栏不变
服务端只产生了一对请求和响应对象,这一对请求和响应对象会继续传递给下一个资源
因为全程只有一个HttpServletRequset对象,所以请求参数可以传递,请求域中的数据也可以传递
请求转发可以转发给其他Servlet动态资源,也可以转发给一些静态资源以实现页面跳转
请求转发可以转发给WEB-INF下受保护的资源
请求转发不能转发到本项目以外的外部资源
(2)请求转发测试代码
ServletA代码
@WebServlet("/servletA") public class ServletA extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求转发器 // 转发给servletB ok RequestDispatcher requestDispatcher = req.getRequestDispatcher("servletB"); // 转发给一个视图资源 ok //RequestDispatcher requestDispatcher = req.getRequestDispatcher("welcome.html"); // 转发给WEB-INF下的资源 ok //RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html"); // 转发给外部资源 no //RequestDispatcher requestDispatcher = req.getRequestDispatcher("http://www.atguigu.com"); // 获取请求参数 String username = req.getParameter("username"); System.out.println(username); // 向请求域中添加数据 req.setAttribute("reqKey","requestMessage"); // 做出转发动作 requestDispatcher.forward(req,resp); } }
ServletB代码
@WebServlet("/servletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求参数 String username = req.getParameter("username"); System.out.println(username); // 获取请求域中的数据 String reqMessage = (String)req.getAttribute("reqKey"); System.out.println(reqMessage); // 做出响应 resp.getWriter().write("servletB response"); } }
打开浏览器,输入以下url测试
http://localhost:8080/web03_war_exploded/servletA?username=atguigu
3.响应重定向
(1)响应重定向特点
响应重定向通过HttpServletResponse对象的sendRedirect方法实现
响应重定向是服务端通过302响应码和路径,告诉客户端自己去找其他资源,是在服务端提示下的,客户端的行为
客户端至少发送了两次请求,客户端地址栏是要变化的
服务端产生了多对请求和响应对象,且请求和响应对象不会传递给下一个资源
因为全程产生了多个HttpServletRequset对象,所以请求参数不可以传递,请求域中的数据也不可以传递
重定向可以是其他Servlet动态资源,也可以是一些静态资源以实现页面跳转
重定向不可以到给WEB-INF下受保护的资源
重定向可以到本项目以外的外部资源
(2)响应重定向测试代码
ServletA
@WebServlet("/servletA") public class ServletA extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求参数 String username = req.getParameter("username"); System.out.println(username); // 向请求域中添加数据 req.setAttribute("reqKey","requestMessage"); // 响应重定向 // 重定向到servlet动态资源 OK resp.sendRedirect("servletB"); // 重定向到视图静态资源 OK //resp.sendRedirect("welcome.html"); // 重定向到WEB-INF下的资源 NO //resp.sendRedirect("WEB-INF/views/view1"); // 重定向到外部资源 //resp.sendRedirect("http://www.atguigu.com"); } }
ServletB
@WebServlet("/servletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求参数 String username = req.getParameter("username"); System.out.println(username); // 获取请求域中的数据 String reqMessage = (String)req.getAttribute("reqKey"); System.out.println(reqMessage); // 做出响应 resp.getWriter().write("servletB response"); } }
打开浏览器,输入以下url测试
http://localhost:8080/web03_war_exploded/servletA?username=atguigu
十一、路径问题
1.前端相对路径
以当前资源的所在路径为出发点去找目标资源
语法:不以/开头
./表示当前资源的路径
../表示当前资源的上一层路径
缺点:目标资源路径受到当前资源路径的影响不同的位置,相对路径写法不同
(1)相对路径情况1:web/index.html中引入web/static/img/logo.png
index.html中定义的了 :
<img src="static/img/logo.png"/>
寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/)后拼接src属性值(static/img/logo.png),正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<img src="static/img/logo.png">
</body>
</html>
(2)相对路径情况2:web/a/b/c/test.html中引入web/static/img/logo.png
访问test.html的url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
当前资源为 : test.html
当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/a/b/c/
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
test.html中定义的了 :
<img src="../../../static/img/logo.png"/>
寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/a/b/c/)后拼接src属性值(../../../static/img/logo.png),其中 ../可以抵消一层路径,正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- ../代表上一层路径 -->
<img src="../../../static/img/logo.png">
</body>
</html>
(3)相对路径情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
view1.html在WEB-INF下,需要通过Servlet请求转发获得
@WebServlet("/view1Servlet") public class View1Servlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html"); requestDispatcher.forward(req,resp); } }
访问view1.html的url为 : http://localhost:8080/web03_war_exploded/view1Servlet
当前资源为 : view1Servlet
当前资源的所在路径为 : http://localhost:8080/web03_war_exploded/
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
view1.html中定义的了 :
<img src="static/img/logo.png"/>
寻找方式就是在当前资源所在路径(http://localhost:8080/web03_war_exploded/)后拼接src属性值(static/img/logo.png),正好是目标资源正常获取的url(http://localhost:8080/web03_war_exploded/static/img/logo.png)
是相对于客户端的url的,不只是简单的目录结构
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <img src="static/img/logo.png"> </body> </html>
2.前端绝对路径
始终以固定的路径作为出发点去找目标资源和当前资源的所在路径没有关系
语法:以/开头
不同的项目中,固定的路径出发点可能不一致,可以测试一下http://localhost:8080/demo05/static/img/logo.png
优点:目标资源路径的写法不会受到当前资源路径的影响,不同的位置,绝对路径写法一致
缺点:绝对路径要补充项目的上下文项目上下文是可以改变的
通过head>base>href属性,定义相对路径公共前缀,通过公共前缀把一个相对路径转换为绝对路径(不完美)
<base href="/dθ5/">
(1)绝对路径情况1:web/index.html中引入web/static/img/logo.png
访问index.html的url为 : http://localhost:8080/web03_war_exploded/index.html
绝对路径的基准路径为 : http://localhost:8080
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
index.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/web03_war_exploded/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 绝对路径写法 --> <img src="/web03_war_exploded/static/img/logo.png"> </body> </html>
(2)绝对路径情况2:web/a/b/c/test.html中引入web/static/img/logo.png
访问test.html的url为 : http://localhost:8080/web03_war_exploded/a/b/c/test.html
绝对路径的基准路径为 : http://localhost:8080
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
test.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/web03_war_exploded/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 绝对路径写法 --> <img src="/web03_war_exploded/static/img/logo.png"> </body> </html>
(3)绝对路径情况3:web/WEB-INF/views/view1.html中引入web/static/img/logo.png
view1.html在WEB-INF下,需要通过Servlet请求转发获得
@WebServlet("/view1Servlet") public class View1Servlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { RequestDispatcher requestDispatcher = req.getRequestDispatcher("WEB-INF/views/view1.html"); requestDispatcher.forward(req,resp); } }
访问view1.html的url为 : http://localhost:8080/web03_war_exploded/view1Servlet
绝对路径的基准路径为 : http://localhost:8080
要获取的目标资源url为 : http://localhost:8080/web03_war_exploded/static/img/logo.png
view1.html中定义的了 :
<img src="/web03_war_exploded/static/img/logo.png"/>
寻找方式就是在基准路径(http://localhost:8080)后面拼接src属性值(/static/img/logo.png),得到的正是目标资源访问的正确路径
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <img src="/web03_war_exploded/static/img/logo.png"> </body> </html>
3.前端base标签的使用
(1)base标签定义页面相对路径公共前缀
base 标签定义在head标签中,用于定义相对路径的公共前缀
base 标签定义的公共前缀只在相对路径上有效,绝对路径中无效
如果相对路径开头有 ./ 或者../修饰,则base标签对该路径同样无效
(2)index.html 和a/b/c/test.html 以及view1Servlet 中的路径处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--定义相对路径的公共前缀,将相对路径转化成了绝对路径-->
<base href="/web03_war_exploded/">
</head>
<body>
<img src="static/img/logo.png">
</body>
</html>
(3)项目上下文路径变化问题
通过 base标签虽然解决了相对路径转绝对路径问题,但是base中定义的是项目的上下文路径
项目的上下文路径是可以随意变化的
一旦项目的上下文路径发生变化,所有base标签中的路径都需要改
(4)解决方案
将项目的上下文路径进行缺省设置,设置为 /,所有的绝对路径中就不必填写项目的上下文了,直接就是/开头即可
4.响应重定向的路径问题
ServletA代码
@WebServlet("/a/b/c/ServletA") public class ServletA extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ServletA"); //1.响应重定向相对路径 resp.sendRedirect("../../../ServletB"); //2.响应重定向绝对路径 /项目上下文/servlet的uri resp.sendRedirect("/web03/ServletB"); } }
ServletB代码
@WebServlet("/ServletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp){ System.out.println("ServletB"); } }
测试浏览器输入url
http://ip:port/项目上下文/a/b/c/ServletA
5.请求转发的路径问题
ServletA代码
@WebServlet("/a/b/c/ServletA") public class ServletA extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ServletA"); //1.相对路径写法 和前端的一致 RequestDispatcher requestDispatcher = req.getRequestDispatcher("../../../ServletB"); //2. 绝对路径 //不需要项目上下文 直接另外一个servlet的uri RequestDispatcher requestDispatcher = req.getRequestDispatcher("/ServletB"); requestDispatcher.forward(req,resp); } }
ServletB代码
@WebServlet("/ServletB") public class ServletB extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp){ System.out.println("ServletB"); } }
测试
http://ip:port/项目上下文/a/b/c/ServletA