- init()方法是servlet生命的起点。一旦加载了某个servlet,服务器将立即调用它的init()方法。在init()方法中,servlet创建和初始化它在处理请求时需要用到的资源。
- service()方法处理客户机发出的所有请求。在init()方法执行之前,它无法开始对请求提供服务,通常,我们不能直接实现这个方法,除非对GenerieServlet抽象类进行扩展。
- destroy()方法标志servlet生命周期的结束。当服务需要关闭时,它调用servlet的destroy()方法。此时,在init()方法中创建的任何资源都应该被清除和释放。如果有打开的数据库连接,应当在此处保存任何在下一次加载时需要用到的永久性信息。
把实现了Servlet接口的java程序叫做:Servlet.
Servlet的作用:
Servlet接口Sun公司有两个默认的内置实现类:
- Servlet接口有一个实现类是GenericServlet,而GenericServlet有一个子类是HttpServlet,我们创建Servlet的时候会选择继承HttpServlet,因为它里面相当于也实现了Servlet接口,并且对一些方法做了默认实现;而且子类的功能会比父类的更加强大
- 我们编写Servlet类继承HttpServlet的时候,只需要重写doGet()和doPost()方法就行了,因为HttpServlet重写了service()方法,在service()方法中判断请求方式,根据不同的请求方式执行doXXX()方法
同时,由上图可知,GenericServler类和HttpServlet等类也实现了ServletConfig接口, 故有必要了解ServletConfig接口中定义的方法:
ServletConfig接口方法介绍:
方法名 | 作用 |
---|---|
getServletName() | 获取HelloServlet定义的Servlet名称 |
getServletContext() | 获取ServletContext对象 |
getInitParameter() | 获取配置Servlet时设置的『初始化参数』,根据名字获取值 |
getInitParameterNames() | 获取所有初始化参数名组成的Enumeration对象 |
package com.carson.servlet;
/*自动用了父模块的包*/
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了doGet方法");
PrintWriter out = resp.getWriter();
out.print("Hello,Carson!I am Servlet!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
为什么需要映射: 我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务即web.xml配置文件中注册我们写的servlet,还需给它一个浏览器能够访问的路径!
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>helloServletservlet-name>
<servlet-class>com.carson.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carsonurl-pattern>
servlet-mapping>
web-app>
什么是Servlet的生命周期
Servlet的生命周期就是servlet从创建到销毁的过程,我们所要去探讨的就是Servlet对象在什么时候创建出来以及在什么时候销毁。
当然创建和销毁Servlet对象的工作是不需要我们去做的。
Servlet对象什么时候创建?
默认情况下是在第一次有请求访问该Servlet实例的时候才会创建该Servlet对象
Servlet对象什么时候销毁?
在服务器关闭,或者当前项目从服务器中移除的时候会销毁当前项目中的所有Servlet对象
在Servlet的生命周期中必然会经历的方法我们称之为Servlet的生命周期方法,总共包含三个方法: init、service、destroy
init方法:
该方法会在Servlet实例对象被创建出来之后执行,我们可以在该方法中获取当前Servlet的初始化参数,以及进行一些读取配置文件之类的操作
service方法:
该方法会在Servlet实例对象每次接收到请求的时候均执行,我们可以在该方法中接收、处理请求,以及将客户端需要的数据响应给客户端
destroy方法:
该方法会在Servlet实例对象销毁之前执行,我们可以在该方法中做一些资源回收、释放、关闭等等操作
为什么Servlet需要提前创建?
有时候我们需要在Servlet创建的时候做一些资源加载等等耗时操作,所以如果Servlet在第一次接收请求的时候才创建的话必然会影响用户的访问速度,所以此时我们需要让Servlet提前创建,将Servlet的创建提前到服务器启动的时候。
具体要如何进行配置Servlet提前创建?
通过修改web.xml中Servlet的配置可以实现:
<servlet>
<servlet-name>HelloServletservlet-name>
<servlet-class>com.drimwai.servlet.HelloServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
项目中可能会因为用户输错地址或其他原因导致404找不到页面的错误.
这个时候可以使用web.xml配置统一处理,当发生404错误的时候统一跳转到一个页面
示例配置:
<error-page>
<error-code>404error-code>
<location>/WEB-INF/view/error.htmllocation>
error-page>
为什么要配置Servlet的映射路径?
『映射路径』:Servlet并不是文件系统中实际存在的目录或文件,所以为了方便浏览器访问,我们创建了映射路径来访问它。
映射路径的作用
Servlet的映射路径是提供一个让别人能够访问该Servlet的路径,例如Servlet的映射路径是"/hello",那么在浏览器上访问该Servlet的路径是http://localhost:8080/项目部署名/hello
注意: 一个Servlet可以配置多个映射路径,但是多个Servlet不能配置相同的映射路径
访问当前Servlet的路径需要和配置的映射路径完全一致,例如Servlet的配置是/demo01
,那么访问该Servlet的时候的路径也必须是http://localhost:8080/项目部署名/demo01
才可以访问到。
以 /
开始需要以 *
结束,
注: Servlet里面用的不多, 但是过滤器里面通常就使用目录匹配。
例如:
配置/*,访问的路径可以是“/任意字符串”,比方: /aa, /aaa;
配置 /aa/*,访问的路径可是“/aa/任意字符串”,比方: /aa/b, /aa/cc
以*
开头,以.扩展名
结束,能够匹配所有以.相同扩展名
结尾的请求路径
例如: *.action;
访问路径可以是: 任意字符串.action
比方: aa.action, bb.action, c.action;
关于web.xml的url映射中/
和/*
的区别:
/
会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url/*
会匹配所有url:路径型的和后缀型的url(包括/login,.jsp,.js和*.html等)
以helloServlet为例
映射路径书写:
<servlet>
<servlet-name>helloServletservlet-name>
<servlet-class>com.carson.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carsonurl-pattern>
servlet-mapping>
映射路径书写:
<servlet>
<servlet-name>helloServletservlet-name>
<servlet-class>com.carson.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carsonurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carson1url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carson2url-pattern>
servlet-mapping>
<servlet>
<servlet-name>helloServletservlet-name>
<servlet-class>com.carson.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/carson/*url-pattern>
servlet-mapping>
<servlet>
<servlet-name>helloServletservlet-name>
<servlet-class>com.carson.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloServletservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<welcome-file-list>
<welcome-file>hellowelcome-file>
welcome-file-list>
【注意: *号前面不能加项目映射的路径/符号】
错误写法:
<url-pattern>/carson/*.carsonurl-pattern>
<url-pattern>/*.carsonurl-pattern>
正确写法:
<url-pattern>*.carsonurl-pattern>
web容器在启动的时候,它会为每个web应用程序都创建一个对应的ServletContext对象,此对象代表了对应的web应用。
域对象就是在一定的作用域范围内进行数据共享的对象,ServletContext作为全局域对象可以在整个项目的所有动态资源(包含所有Servlet)中进行数据共享。
服务器为其部署的每一个应用(项目)都创建了一个ServletContext对象。ServletContext属于整个项目的,该项目中的所有Servlet都可以共享同一个ServletContext对象。
整个web项目部署之后,只会有一个应用域(ServletContext)对象,所有客户端都是共同访问同一个应用域对象,在该项目的所有动态资源中也是共用一个应用域对象。
调用Servlet自身的getServletContext方法获取
ServletContext ServletContext = getServletContext();
调用ServletConfig接口的getServletContext方法
ServletContext servletContext = servletConfig.getServletContext();
//HttpServletRequest对象也实现了ServletConfig接口,所以也有getServletContext()方法
ServletContext ServletContext = request.getServletContext();
目标
在ServletDemo01中往全局域对象中存入"username"为"aobama"的键值对,然后在ServletDemo02中从全局域对象中根据"username"获取对应的值
ServletDemo01中的代码
//1. 获取ServletContext对象
ServletContext servletContext = getServletContext();
//2. 存入数据
String str = "Jay Chow";
//将str设置到servletContext里面
servletContext.setAttribute("str",str);
ServletDemo02中的代码
//1. 获取ServletContext对象
ServletContext servletContext = getServletContext();
//2. 取出数据
String str = (String) servletContext.getAttribute("str");
System.out.println("在ServletDemo02中获取ServletContext域对象中的str = " + str);
web.xml中;
<context-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306/mybatisparam-value>
context-param>
servlet中:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
PrintWriter writer = resp.getWriter();
writer.print(url);
}
servlet中:
package com.carson.servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了SetvletDemo02");
// 转发的请求路径
RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");
// 调用forward(req,resp)实现转发请求
requestDispatcher.forward(req,resp);
System.out.println("已成功转发");
}
}
【注意请求转发时的路径书写: 不需要加上项目名后缀,这里的/代表当前的web应用项目的路径】
新建Propertoes文件的两种方式:
当不在web.xml中进行资源导出配置相关配置时:
上面两种方式 文件都会被打包到同个路径下: 即类文件路径classes中
而当对web.xml中进行资源导出配置相关配置时:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<excludes>
<exclude>**/*.propertiesinclude>
<exclude>**/*.xmlinclude>
excludes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
resources资源目录下新建Properties仍然是输出到类文件路径classes中(如db.properties),而java包目录下新建Properties的方式的输出目录是与.class文件同个目录下(如aa.properties)。
配置文件db.properties中:
username=root
password=root
servlet中读取资源文件:
【注: 读取资源文件需要将其转为一个文件流】
package com.carson.servlet;
import com.mysql.cj.callback.UsernameCallback;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Properties;
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String password = prop.getProperty("password");
PrintWriter out = resp.getWriter();
out.print(username+","+password);
}
}
Web服务器收到客户端的http请求,针对这个请求,其将会分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse对象。
在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。
由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法。
用我们自己的话说: Response就是服务器端一个对象,它里面可以封装要响应给客户端的响应行、头、体的信息。
向浏览器输出超文本: response.getWriter().write(“文本”),
此时如果输出的是中文就会出现中文乱码问题
解决中文乱码问题: response.setContentType("text/html;charset=UTF-8")
响应超文本示例Servlet:
/**
* 使用response:
* 1. 设置响应状态码: setStatus(状态码)
* 常见的状态码:200请求成功、302重定向、403权限拒绝、404资源未找到、500服务器异常
* 2. 设置响应体的内容:
* 2.1 向浏览器输出超文本: response.getWriter().write("文本"),此时如果输出的是中文就会出现中文乱码问题
* 解决中文乱码问题: response.setContentType("text/html;charset=UTF-8")
* 2.2 向浏览器输出文件: response.getOutputStream();获取字节输出流,就可以向客户端输出文件
*/
public class ResponseDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应状态码
response.setStatus(403);
//使用response向浏览器输出一个超文本(字符串)
//解决输出中文文本时候的乱码问题
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("你好世界
");
}
}
向浏览器输出文件所使用的API :
response.getOutputStream();
获取字节输出流,就可以向客户端输出文件
响应图片文件示例Servlet:
public class ResponseDemo02 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//当用户访问ResponseDemo02的时候,我们要向客户端输出一张图片:imgs/logo.png
//1. 使用字节输入流读取img里面的那张logo.png
//1.2 使用ServletContext对象的getRealPath()方法动态获取logo.png的部署目录下的路径
String realPath = getServletContext().getRealPath("imgs/logo.png");
FileInputStream is = new FileInputStream(realPath);
//2. 使用字节输出流将读取到的字节输出到浏览器
//2.1 定义一个缓冲区
byte[] buffer = new byte[1024];
//2.2 定义一个读取到的字节的长度
int len = 0;
//2.3 获取输出流
ServletOutputStream os = response.getOutputStream();
//2.4 使用while循环进行边读编写
while ((len = is.read(buffer)) != -1){
//写
os.write(buffer,0,len);
}
//关流
os.close();
is.close();
}
}
下载文件示例Servlet:
package com.carson.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*1:要获取下载文件的路径*/
String reaLPath = "D:\\360downloads\\wpcache\\卡森.jpg";
/*2:下载的文件名是*/
String fileName = reaLPath.substring(reaLPath.lastIndexOf("\\") + 1);
/*3:通过设置让浏览器支持将要下载的东西(如果包含中文,需要使用URLEncoder.encode()编码,否则乱码)*/
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
/*4:获取下载文件的输入流*/
FileInputStream in = new FileInputStream(reaLPath);
/*5:创建缓冲区*/
int len = 0;
byte[] buffer = new byte[1024];
/*6:获取OutputStream对象*/
ServletOutputStream out = resp.getOutputStream();
/*7:将FileOutputStream流写入到buffer缓冲区中,使用OutputStream流将缓冲区中的数据输出到客户端*/
while((len=in.read(buffer))>0){
out.write(buffer,0,len);
}
/*涉及IO操作,需要关闭资源*/
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
验证码功能示例servlet:
package com.carson.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.FormatFlagsConversionMismatchException;
import java.util.Random;
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*让浏览器隔几秒刷新一次*/
resp.setHeader("refresh","3");
/*在内存中创建一个图片*/
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
/*得到图片的画笔*/
Graphics2D g = (Graphics2D) image.getGraphics();
/*设置图片的背景颜色*/
g.setColor(Color.white);
g.fillRect(0,0,80,20);
/*给图片写数据*/
g.setColor(Color.blue);//重置画笔颜色
g.setFont(new Font(null,Font.BOLD,20));//设置字体
g.drawString(makeNum(),5,20);//写入随机生成的数字字符串
/*告诉浏览器,这个请求用图片的方式打开*/
resp.setContentType("image/jpeg");
/*网站存在缓存,不让浏览器缓存,-1表示不缓存*/
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
/*把图片写给浏览器*/
ImageIO.write(image, "jpg", resp.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
/*生成随机数的函数*/
private String makeNum(){
Random random = new Random();
String num = random.nextInt(999999)+" ";//输入的数字的位数代表生成的数字位数
StringBuffer sb = new StringBuffer();//StringBuffer是可变长和改变的字符串
//保证输出的是6位数
for (int i = 0; i < 6-num.length() ; i++) {
sb.append(0);
}
num = sb.toString()+num;
//返回num(生成的随机数)
return num;
}
}
什么是重定向?
重定向是由项目中的一个资源跳转到另一个资源,在这个过程中客户端会发起新的请求。
重定向的API:
response.sendRedirect("路径");
重定向示例servlet:
package com.carson.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*原理:
resp.setHeader("Location","/response/img");
resp.setStatus(302);临时重定向
*/
//实现重定向(注意路径需要加项目名,这里的/表示的是站点的根目录(不包括项目名))
resp.sendRedirect("/response/img");
}
}
在Servlet API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求头和请求体三部分,因此,在HttpServletRequest接口中定义了获取请求行、请求头和请求消息体的相关方法。
用我们自己的话来理解: Request就是服务器中的一个对象,该对象中封装了HTTP请求的请求行、请求头和请求体的内容。
HttpServletRequest代表客户端的连接,用户通过http协议访问服务器,Http请求中所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获取客户端的信息。
获取请求行的API:
- getMethod(); 获取请求方式
- getContextPath(); 获得当前应用上下文路径
- getRequestURI(); 获得请求地址,不带主机名
- getRequestURL(); 获得请求地址,带主机名
public class RequestDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用request对象获取请求行的信息:
//1. 获取请求的方式(可能会用)
String method = request.getMethod();
//System.out.println("请求方式为:" + method);;
//2. 获取请求的url: 统一资源定位符 http://localhost:8080/requestDemo/demo01
String url = request.getRequestURL().toString();
//System.out.println("此次请求的url是:" + url);
//3. 获取请求的uri: 统一资源标识符,在url的基础上省略了服务器路径"http://loaclhost:8080"
String uri = request.getRequestURI();
System.out.println(uri);
}
}
获取请求头的API:
- getHeader(String name), 根据请求头的name获取请求头的值
public class RequestDemo02 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//根据请求头的name获取value
//目标:获取name为user-agent的请求头的信息
//user-agent请求头中包含的是客户端浏览器信息
String header = request.getHeader("user-agent");
System.out.println("获取的请求头agent为:" + header);
}
}
请求参数的概念:
请求参数是客户端携带给服务器的由键值对组成的数据,例如"username=aobama&password=123456"这种类型的数据
客户端携带请求参数的形式
URL地址后面附着的请求参数,例如http://localhost:8080/app/hellServlet?username=汤姆
表单携带请求参数
Ajax请求携带请求参数
获取请求参数的API:
方法名 | 返回值类型 | 方法描述 |
---|---|---|
request.getParameterMap() | Map |
获取当前请求的所有参数,以键值对的方式存储到Map中 |
request.getParameter(“请求参数的名字”) | String | 根据一个参数名获取一个参数值 |
request.getParameterValues(“请求参数的名字”) | String [] | 根据一个参数名获取多个参数值 |
request.getParameterNames() | Enumeration | 获取当前请求的所有参数的参数名 |
解决获取请求参数乱码:
我们当前使用的Tomcat的版本是Tomcat8以上,所以我们不需要考虑GET方式乱码的问题,因为Tomcat8及以上版本已经在配置中解决了GET请求乱码的问题。
我们只需要解决POST请求乱码问题。
解决POST请求的参数乱码只需要在获取请求参数前调用
request.setCharacterEncoding("UTF-8")
就行了。
什么是请求转发:
请求转发是从一个资源跳转到另一个资源,在这个过程中客户端不会发起新的请求。
请求转发的API:
request.getRequestDispatcher("路径").forward(request,response);
req.getRequestDispatcher("/success.jsp").forward(req,resp);
请求域范围:
请求域的范围只是在一次请求中的动态资源能够共享的一个范围。
每一次请求都有一个请求域对象,当请求结束的时候对应的请求域对象也就销毁了。
请求域对象的API:
request.setAttribute(key,value)
request.getAttribute(key)
使用请求域的前提:
请求域对象一定要和请求转发一起使用,因为请求域的范围是一次请求范围内,所以要在两个动态资源中使用请求域必须要进行请求转发跳转。
请求域应用示例代码:
在RequestDemo06中往请求域中存入"username"作为key,"aobama"作为值的键值对;
然后在RequestDemo07中从请求域中根据"username"取出对应的值。
RequestDemo06
public class RequestDemo06 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo06执行了...")
String username = "aobama";
//将username存储到request域对象中
request.setAttribute("username",username);
//请求转发跳转到RequestDemo07
request.getRequestDispatcher("/RequestDemo07").forward(request, response);
}
}
RequestDemo07
public class RequestDemo07 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = (String)request.getAttribute("username");
System.out.println("在RequestDemo06中获取username:" + username);
}
}
相同点:
页面内容都会变化
不同点:
请求转发
/
代表当前web应用的根目录(即路径携带项目名,如: localhost:8080/项目名)重定向
/
代表整个web站点的根目录(即路径 不携带项目名,如: localhost:8080)url是uniform Resource Locater
的简写,中文翻译为统一资源定位符
,它是某个互联网资源的唯一访问地址,客户端可以通过url访问到具体的互联网资源。
客户端访问服务器的资源,或一台服务器中要访问另外一台服务器的资源都是通过url访问。
URI是Uniform Resource Identifier
的缩写,中文翻译为统一资源标识符
, 它是服务器中某个资源的唯一标识,通过uri可以实现同一项目中的某个资源中访问另一个资源
uri的写法是/项目部署名/资源路径
即: URI = 应用名+资源名
在同一个项目的某个资源中访问该项目中的另一个资源。
URI可以表示一个域,也可以表示一个资源。
URL只能表示一个资源。
相对路径是不以/
开头的路径写法,编写相对路径的原则是以目标资源的uri路径相对当前资源的uri路径
目标: 在A资源中访问B资源
A资源的uri路径: /app/pages/a.html
B资源的uri路径:/app/static/vue.js
那么要实现在A资源中访问B资源的相对路径写法是../static/vue.js
,其中../static
表示找到当前资源的上一级目录下的static目录
绝对路径是以/
开头的路径写法,编写绝对路径的原则是通过目标资源的uri访问目标资源。但是特殊情况是请求转发,如果是请求转发访问目标资源的话,那么绝对路径是在uri的基础之上省略/项目部署名
。
目标: 在A资源中访问B资源
A资源的uri路径: /app/pages/a.html
B资源的uri路径:/app/static/vue.js
那么要实现在A资源中访问B资源的绝对路径写法是/app/static/vue.js
请求转发的时候绝对路径的写法是/资源名
,其实就是在uri的基础上省略/项目部署名
。
是打包后输出的部署web项目的根目录,如下:
编写资源映射路径的基准:
用户通过浏览器访问服务器,而服务器上运行的是部署目录,
所以写路径的时候参考部署目录而不是工程目录
工程目录和部署目录的对应关系:
工程目录下的web目录对应部署目录的根目录,同时部署目录的根目录也是路径中的Web应用的根目录。
Web站点目录(路径):
其相对于上面所说的工作目录的根目录,浏览器路径体现为:
http://localhost:8080
Web应用目录(路径):
其相对于上面所说的部署目录的根目录,浏览器路径体现为:
这里的response_war是web应用名(项目发布路径)
http://localhost/response_war/
上下文路径(context path)=/Web应用名称
因为我们使用绝对路径的时候需要用到资源的uri路径,而uri路径中是包含上下文路径的,所以如果采用静态方式写绝对路径,那么就会将上下文路径写死在绝对路径中;而我们在部署项目的时候,上下文路径是可变的,所以这样就会因为部署时设置的上下文路径不同从而导致绝对路径出错的问题。
request.getContextPath()
使用上述API可以动态获取项目的上下文路径,每一次获取的都是当前环境下实际的上下文路径的值!!
例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径。
String realPath = servletContext.getRealPath("资源在web目录中的路径");
只要使用了servletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题。
The End!!创作不易,欢迎点赞/评论!!欢迎关注个人公众号