Servlet技术
Servlet是JavaEE规范(接口)之一,是JavaWeb三大组件之一,三大组件分别是Servlet程序、Filter过滤器、Listener监听器。Servlet是运行在服务器上的小型java程序,通常通过Http(超文本传输协议)接受和响应来自Web客户端的请求。
实现Servlet程序
1.编写一个类实现Servlet接口;
2.实现service方法,处理请求并响应数据;
package com.pero.servlet.servlet_for_web;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
public class HelloServlet implements Servlet {
public HelloServlet() {
System.out.println("1构造器被调用");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2初始化方法init被调用");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3service方法被调用");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("4销毁方法");
}
}
3.到web.xml中配置Servlet程序访问地址
<?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标签给tomcat配置Servlet程序 -->
<servlet>
<!-- servlet-name标签给servlet程序起一个别名,一般为类名 -->
<servlet-name>HelloServlet</servlet-name>
<!-- servlet-class 是Servlet程序的全类名 -->
<servlet-class>com.pero.servlet.servlet_for_web.HelloServlet</servlet-class>
</servlet>
<!-- servlet-mapping标签给Servlet程序配置访问地址 -->
<servlet-mapping>
<!-- servlet-name标签作用是告诉服务器,当前配置的地址是给哪一个Servlet程序使用 -->
<servlet-name>HelloServlet</servlet-name>
<!-- url-pattern标签配置访问地址
/ 斜杠在服务器解析的时候比奥是地址为http://ip:port/工程路径 <br/>
hello 表示地址为:http://ip:port/工程路径/hello
-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
4.在客户端(浏览器)输入http://ip地址:port端口号/工程路径/资源路径来访问服务器,通过IP地址定位服务器,通过端口号定位tomcat,通过工程路径确定访问工程(查找web.xml中的servlet和servletmapping,通过servlet和servletmapping找到相应的类执行功能代码)。
Servlet生命周期
1.执行Servlet构造方法(在第一次访问时创建servlet程序会被调用,并且只会被调用一次)
2.执行inti初始化方法(在第一次访问时创建servlet程序会被调用,并且只会被调用一次)
3.执行service方法(每次访问都会调用)
4.执行destroy销毁方法(在Web工程停止时会被调用)
请求的分发处理
通过service方法中获取请求方式,然后根据不同的请求方式调用不同的请求方法
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//类型转换
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
//获取请求方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)){
doGet();
} else if ("POST".equals(method)) {
doPost();
}
}
/**
* doGet方法
*/
public void doGet(){
System.out.println("get请求");
System.out.println("get请求");
}
/**
* doPost方法
*/
public void doPost(){
System.out.println("post请求");
System.out.println("post请求");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/Servlet_For_Web/hello" method="POST">
<input type="submit">
</form>
</body>
</html>
通过继承HttpServlet实现Servlet程序
在实际开发过程中都是使用继承HttpServlet类的方式实现Servlet程序
1.编写一个类继承HttpServlet类
2.根据业务需求编写doGet或者doPost方法
package com.pero.servlet.servlet_for_web;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class HelloServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("HelloServlet2的doGet方法");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("HelloServlet2的doPost方法");
}
}
3.到web.xml中配置Servlet程序的访问地址
<servlet>
<servlet-name>HelloServlet2</servlet-name>
<servlet-class>com.pero.servlet.servlet_for_web.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet2</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
使用IDEA创建Servlet程序
鼠标右键点击目标文件包->new->Servlet->编辑Servlet属性并创建
package com.pero.servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "HelloServlet3", value = "/HelloServlet3")
public class HelloServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("HelloServlet3的doGet方法");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("HelloServlet3的doPost方法");
}
}
Servlet类的继承体系
Interface Servlet | Servlet接口负责定义Servlet程序的访问规范 |
实现↑接口 | |
Class GenericServlet | GenericServlet类实现了Servlet接口,做了许多空实现 持有ServletConfig类的引用,对ServletConfig的使用做一些方法 |
继↑承 | |
Class HttpServlet | HttpServlet抽取类实现了Service()方法,实现了请求的分发处理 String method = req.getMethod(); ↓ ↓ GET POST ↓ ↓ doGet() doPost() 负责抛出异常,表达不支持Get/Post请求 |
继↑承 | ↑ 重写 ↑ |
自定义Servlet程序 | doGet() doPost() 根据业务需要重写doGet或doPost方法 |
ServletConfig类
ServletConfig类是Servlet程序的配置信息类,Servlet程序和ServletConfig对象都是由Tomcat负责创建,程序员负责使用,每一个Servlet程序创建时就创建一个对应的ServletConfig对象,主要有三个作用:
1.获取Servlet程序的别名servlet-name的值
2.获取初始化参数init-param
3.获取ServletContext对象
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2初始化方法init被调用");
//1.获取Servlet程序的别名servlet-name的值
System.out.println("HelloServlet程序的别名是:" + servletConfig.getServletName());
//2.获取初始化参数init-param
System.out.println("HelloServlet程序初始化参数username:" + servletConfig.getInitParameter("username"));
System.out.println("HelloServlet程序初始化参数url:" + servletConfig.getInitParameter("url"));
//3.获取ServletContext对象
System.out.println("HelloServlet程序的ServletContext对象:" + servletConfig.getServletContext());
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package jakarta.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package jakarta.servlet;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.ResourceBundle;
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final long serialVersionUID = -8592279577370996712L;
private static final String LSTRING_FILE = "jakarta.servlet.LocalStrings";
private static ResourceBundle lStrings = ResourceBundle.getBundle("jakarta.servlet.LocalStrings");
private transient ServletConfig config;
......
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package jakarta.servlet;
import jakarta.servlet.descriptor.JspConfigDescriptor;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
public interface ServletContext {
String TEMPDIR = "jakarta.servlet.context.tempdir";
String ORDERED_LIBS = "jakarta.servlet.context.orderedLibs";
String getContextPath();
ServletContext getContext(String var1);
......
}
注意:重写init方法时必须添加super.init(config)
ServletContext接口
1.ServletContext接口表示Servlet程序的上下文对象
2.一个web工程只有一个ServletContext对象实例
3.ServletContext对象是一个域对象,是可以像Map对象一样存储数据的对象,存储数据用setAttribute()方法,取数据用getAttribute()方法,删除数据用removeAttribute()方法
4.ServletContext实在web工程部署启动的时候创建,在web工程停止的时候销毁
常见作用如下:
1.获取web.xml配置的上下文参数context.param
2.获取当前工程路径,格式:/工程路径
3.获取工程部署后在服务器硬盘上的绝对路径
4.像Map一样存取数据
<!-- context-param是上下文参数属于整个web工程 -->
<context-param>
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
package com.pero.servlet.servlet_for_web;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class ContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
//1.获取web.xml配置的上下文参数context.param
String username = servletContext.getInitParameter("username");
System.out.println(username);
String password = servletContext.getInitParameter("password");
System.out.println(password);
//2.获取当前工程路径,格式:/工程路径
String contextPath = servletContext.getContextPath();
System.out.println(contextPath); // /Servlet_For_Web
//3.获取工程部署后在服务器硬盘上的绝对路径
String realPath = servletContext.getRealPath("/"); //E:\IdeaProjects\Web_Servlet\Servlet_For_Web\target\Servlet_For_Web-1.0-SNAPSHOT\
System.out.println(realPath);
//4.像Map一样存取数据
System.out.println("存储数据之前获取数据"+servletContext.getAttribute("key")); //存储数据之前获取数据null
servletContext.setAttribute("key","value");
System.out.println("存储数据之后获取数据"+servletContext.getAttribute("key")); //存储数据之后获取数据value
// servletContext.removeAttribute("key");
// System.out.println("删除数据之后获取数据"+servletContext.getAttribute("key"));
System.out.println(servletContext); //org.apache.catalina.core.ApplicationContextFacade@2881b8a8
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
package com.pero.servlet.servlet_for_web;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class ContextServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
System.out.println(servletContext); //org.apache.catalina.core.ApplicationContextFacade@2881b8a8
System.out.println("存储数据之后获取数据"+servletContext.getAttribute("key")); //存储数据之后获取数据value
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
HTTP协议
客户端和服务器端之间通信时发送数据需要遵守的规则称为HTTP协议,HTTP协议中的数据叫做报文。客户端给服务器发送数据叫做请求,服务器给客户端发送数据叫做响应。
GET请求
①请求行:
请求方式:GET;
请求的资源路径[+?+请求参数];
请求的协议版本号:HTTP/1.1
②请求头:key:value组成,不同的键值对表示不同的含义
Accept:告诉服务器客户端可以接收的数据类型
Accept-Language:告诉服务器客户端可以接收的语言类型
zh_CN:中文中国
en_US:英文美国
User_Agent:浏览器的信息
Accept-Encoding:告诉服务器客户端可以接收的数据编码(压缩)格式
Host:表示请求的服务器ip和端口号
Connection:告诉服务器请求连接如何处理
Keep-Alive:告诉服务器回传数据不要马上关闭,保持一小段时间的链接
Closed:马上关闭
POST请求
①请求行:
请求方式:POST;
请求的资源路径[+?+请求参数];
请求的协议版本号:HTTP/1.1
②请求头:key:value组成,不同的键值对表示不同的含义
Accept:表示客户端可以接收的数据类型
Accept-Language:表示客户端可以接收的语言类型
Referer:表示请求发起时浏览器地址栏中的地址(从哪里来的)
User-Agent:表示浏览器的信息
Content-Type:表示发送的数据类型
application/x-www-form-urlencoded:表示提交的数据格式是name=value&name=value,然后对其进行url编码,url编码就是把非英文内容转换为:%xx%xx
multipart/form-data:表示以多段的形式提交数据给服务器(以流的形式提交,用于上传)
Content-Length:表示发送数据的长度
Connection:告诉服务器请求连接如何处理
Cache-Control:表示如何控制缓存,no-cache不缓存
空行
③请求体:发送给服务器的数据
使用GET和POST请求的情况
使用GET请求
1.form标签method=get
2.a标签
3.link标签引入css
4.Script标签引入js文件
5.img标签引入图片
6.iframe引入html页面
7.在浏览器地址栏中输入地址后敲回车键
使用POST请求
1.form标签method=post
响应的HTTP协议
1.相应行
①相应的协议和版本号 HTTP/1.1
②响应状态码 200
③响应状态描述符 OK
2.响应头
①key:value 不同响应头,有其不同含义
Server:表示服务器的信息
Content-Type:表示响应体的数据类型
Content-Length:响应体的长度
Date:请求响应的时间(格林时间)
空行
3.响应体(回传给客户端的数据)
常用的响应码说明
①200:表示请求成功
②302:表示请求重定向
③404:表示请求服务器已收到,但是要的数据不存在
④500:表示服务器已经收到请求,但是服务器内部错误(代码错误)
MIME类型说明
MIME是HTTP协议中的数据类型,全称为“Multipurpose Internet Mail Extensions”多功能Internet邮件扩充服务,MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。
常见的MIME类型:
文件 | MIME类型 |
超文本标记语言文本 | .html,.htm text/html |
普通文本 | .txt text/plain |
RTF文本 | .rtf application/rtf |
GIF图形 | .gif image/gif |
JPEG图形 | .jpeg,.jpg image/jpeg |
AU声音文件 | .au audio/basic |
MIDI音乐文件 | .mid,.midi audio/midi,audio/x-midi |
RealAudio音乐文件 | .ra,.ram audio/x-pn-realaudio |
MPEG文件 | .mpg,.mpeg video/mpeg |
AVI文件 | .avi video/x-msvideo |
GZIP文件 | .gz application/x-gzip |
TAR文件 | .tar application/x-tar |
HttpServletRequest类
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法(doGet和doPost)中来使用,可以通过HttpServletRequest对象获取多有请求信息。
常用方法:
①getRequestURI():获取请求的资源路径
②getRequestURL():获取请求的统一资源定位符(绝对路径)
③getRemoteHost():获取客户端的ip地址
④getHeader():获取请求头
⑤getParameter():获取请求参数
⑥getParameterValues():获取请求参数(多个值的时候使用)
⑦getMethod():获取请求方式GET或POST
⑧setAttribute(key,value):设置域数据
⑨getAttribute(key):获取域数据
⑩getRequestDispatcher():获取请求转发对象
package com.pero.request.request_servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RequestAPIServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//①getRequestURI():获取请求的资源路径
System.out.println("URI:" + req.getRequestURI()); //URI:/Request_Servlet/request
//②getRequestURL():获取请求的统一资源定位符(绝对路径)
System.out.println("URL:" + req.getRequestURL()); //URL:http://localhost:8080/Request_Servlet/request
//③getRemoteHost():获取客户端的ip地址
System.out.println("客户端ip地址是:" + req.getRemoteHost()); //客户端ip地址是:0:0:0:0:0:0:0:1
//④getHeader():获取请求头
System.out.println("请求头:" + req.getHeader("User-Agent")); //请求头:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
//⑦getMethod():获取请求方式GET或POST
System.out.println("请求方式:"+req.getMethod()); //请求方式:GET
}
}
package com.pero.request.request_servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username + password+ Arrays.asList(hobbies));
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/Request_Servlet/parameterServlet" method="get">
用户名:<input type="text" name="username" ><br/>
密码:<input type="password" name="password"><br/>
兴趣爱好:<input type="checkbox" name="hobby" value="cpp">C+
<input type="checkbox" name="hobby" value="java">Java
<input type="checkbox" name="hobby" value="js">JavaScript
<input type="submit">
</form>
</body>
</html>
<servlet>
<servlet-name>ParameterServlet</servlet-name>
<servlet-class>com.pero.request.request_servlet.ParameterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ParameterServlet</servlet-name>
<url-pattern>/parameterServlet</url-pattern>
</servlet-mapping>
解决POST请求中中文乱码问题
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
//设置请求体的字符集为utf-8,从而解决post请求的中文乱码问题
//必须在获取请求参数之前调用该方法才有效
req.setCharacterEncoding("UTF-8");
//获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username + password+ Arrays.asList(hobbies));
}
请求的转发
服务器收到请求后,从一个资源跳转到另一个服务器资源的操作叫做请求转发
客户端 | 服务器端 | |||||
http://ip:port/工程名/servlet1 用户收到最终的结果 | Servlet1 | Servlet2 | ||||
→ | 1.有没有带请求的参数(办事材料) 2.处理完业务,加盖一个章(request.setAttribute("key",value)) 3.问路,Servlet2怎么走(request.getRequestDispatcher()) 4.走到Servlet2(requestDispatcher.forward()) | 从Servlet1到Servlet2的操作 → 叫做请求转发 | 1.获取请求参数(查看材料) 2.检查有没有Servlet1的章 3.处理自己的业务 | |||
← | Servlet1和Servlet2可以共同完成一项业务功能 ← (Servlet2处理完业务后响应是经过Servlet1后传递给客户端) | |||||
请求转发特点:
①浏览器地址栏没有变化
②Servlet1和Servlet2处理的请求是一次请求
③Servlet1和Servlet2共享Request域中的数据
④可以通过请求转发将请求访问地址转到WEB-INF目录下
⑤请求转发不能够访问工程以外的资源
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
System.out.println("在Servlet1中查看参数:" + username);
//给材料盖章并传递到Servlet2查看
request.setAttribute("key","Servlet1的章");
//问路:Servlet2怎么走
/**
* 请求转发必须要以"/"打头,斜杠表示地址为:http://ip:port/工程名/,映射到idea代码的web目录<br/>
*/
//RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
//RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/form.html");
RequestDispatcher requestDispatcher = request.getRequestDispatcher("http://www.baidu.com");
//走向Servlet2
requestDispatcher.forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
System.out.println("在Servlet2中查看参数:" + username);
//查看Servlet1中是否盖章
Object key = request.getAttribute("key");
System.out.println("查看Servlet1中是否有盖章" + key);
//处理自己的业务
System.out.println("Servlet2处理自己的业务");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<servlet>
<servlet-name>Servlet1</servlet-name>
<servlet-class>com.pero.request.request_servlet.Servlet1</servlet-class>
</servlet>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>com.pero.request.request_servlet.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/servlet2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/servlet1</url-pattern>
</servlet-mapping>
base标签的作用
base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转。
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class ForWardC extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("经过ForWardC程序");
request.getRequestDispatcher("/a/b/c.html").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
这是web下的index.html页面<br/>
<a href="a/b/c.html">a/b/c.html</a>
<a href="http://localhost:8080/Request_Servlet/forWardC">请求转发:a/b/c.html</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是a下的b下的c.html页面
<a href="../../index.html">跳回首页</a>
</body>
</html>
<servlet>
<servlet-name>ForWardC</servlet-name>
<servlet-class>com.pero.request.request_servlet.ForWardC</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ForWardC</servlet-name>
<url-pattern>/forWardC</url-pattern>
</servlet-mapping>
当点击a标签进行跳转时,浏览器地址栏中的地址为:http://localhost:8080/Request_Servlet/a/b/c.html 跳转回a标签路径是:../../index.html 所有相对路径在工作时候都会参照当前浏览器地址栏中的地址来进行跳转。 那么参照后得到的地址:http://localhost:8080/Request_Servlet/index.html 该路径为正确的路径 |
base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转。 |
当使用请求转发进行跳转时,浏览器地址栏中的地址是:http://localhost:8080/Request_Servlet/forWardC 跳转回a标签路径是:../../index.html 所有相对路径在工作时候都会参照当前浏览器地址栏中的地址来进行跳转。 那么参照后得到的地址:http://localhost:8080/index.html 该路径为错误路径 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- base标签设置页面相对路径工作是参照的地址 href属性就是参照的地址 -->
<base href="http://localhost:8080/Request_Servlet/a/b/c.html">
</head>
<body>
这是a下的b下的c.html页面
<a href="../../index.html">跳回首页</a>
</body>
</html>
Web中的相对路径和绝对路径
相对路径:
. 表示当前目录
.. 表示上一级目录
资源名 表示当前目录/资源名
绝对路径:
http://ip:port/工程路径/资源路径
Web中/斜杠的不同意义
在Web中 / 斜杠是一种绝对路径
/ 斜杠如果被浏览器解析,得到的地址是:http://ip:port/
例如:<a href="/">斜杠</a>
/ 斜杠如果被服务器解析,得到的地址是:http://ip:port/工程路径
例如:①<url-pattern>/servlet1<url-pattern>
②servletContext.getRealpath("/");
③request.getRequestDispatcher("/");
特殊情况:response.sendRediect("/"); 把斜杠发送给浏览器解析,得到http://ip:port/
HttpServletResponse类
每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用,HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,如果需要设置返回给客户端的信息,都需要通过HttpServletResponse对象来进行设置
两个响应流的说明
①字节流: reponse.getOutputStream(); 常用于下载(传递二进制数据)
②字符流:response.getWriter(); 常用于回传字符串(常用)
★注意:两个流只能使用一个,使用了字符流就不能使用字节流,反之亦然,否则报错
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter();
response.getOutputStream(); //报错
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
往客户端回传字符串数据
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer = response.getWriter();
writer.write("reponse's content!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
解决响应中文乱码
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding()); //UTF-8
/**
* setContentType()方法必须设置在响应流之前,否则会失效
* 会同时设置服务器和客户端都是用UTF-8字符集,并且还设置了响应头
*/
response.setContentType("text/html;charset=UTF-8"); //解决中文乱码
PrintWriter writer = response.getWriter();
writer.write("reponse's content!");
writer.write("我爱JavaWeb"); //出现乱码
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
请求重定向
客户端(浏览器) | 服务器(Tomcat) | |||
http://ip:port/工程路径/response1 解析Response1的响应结果,得知已经搬迁,再次发起新地址的请求 收到最终的返回响应,解析战士在页面上 | ||||
发送请求 → | Response1程序 随着时间的推移和项目的不断更新升级,Response1这个接口慢慢被废弃,有新的接口Response2所取代。 有义务告知客户端,该端口已经搬迁。=》响应码302 并且告知新的地址。=》响应头Location | |||
← 响应状态码:302 Location响应头,新地址 | ||||
根据新地址再次发送请求 → | Response2程序 Response2程序取代了Response1,功能更加完善,安全性更高。 | |||
← 回传响应 | ||||
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("到此一游 Response1");
request.setAttribute("key","value");
//设置响应状态码302,表示重定向(已经搬迁)
response.setStatus(302);
//设置响应头说明新的地址
response.setHeader("Location","http://localhost:8080/Request_Servlet/response2");
//response.setHeader("Location","http://localhost:8080/Request_Servlet/WEB-INF/response2"); //不能访问
//response.setHeader("Location","https://www.baidu.com"); //可以访问
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getAttribute("key")); //null
response.getWriter().write("response2 result!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<servlet>
<servlet-name>Response1</servlet-name>
<servlet-class>com.pero.request.request_servlet.Response1</servlet-class>
</servlet>
<servlet>
<servlet-name>Response2</servlet-name>
<servlet-class>com.pero.request.request_servlet.Response2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Response2</servlet-name>
<url-pattern>/response2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Response1</servlet-name>
<url-pattern>/response1</url-pattern>
</servlet-mapping>
请求重定向的特点
①浏览器地址栏会发生变化
②客户端实际是向服务器发送两次请求
③不共享Request域中的数据
④不能访问WEB-INF下的资源
⑤可以访问工程外的资源
请求重定向的第二种方法
package com.pero.request.request_servlet;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("到此一游 Response1");
request.setAttribute("key","value");
//设置响应状态码302,表示重定向(已经搬迁)
//response.setStatus(302);
//设置响应头说明新的地址
//response.setHeader("Location","http://localhost:8080/Request_Servlet/response2");
//response.setHeader("Location","http://localhost:8080/Request_Servlet/WEB-INF/response2"); //不能访问
//response.setHeader("Location","https://www.baidu.com"); //可以访问
//第二种重定向方式
response.sendRedirect("http://localhost:8080/Request_Servlet/response2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}