一、Servlet基本介绍

Servlet 是 Java提供的一门动态web资源开发技术Servlet 是JavaEE 规范之一,其实就是一个接口,将来我们需要定义Servlet类实现Servlet接口,并由web服务器运行Servlet

一、1、注意事项

对于tomcat10.0版本,maven3.9.0,jdk17的Servlet的maven插件

jakarta.servlet

jakarta.servlet-api

5.0.0

provided//scope依赖范围:在编译和测试环境有效,在运行环境无效。

里面的注意事项,记得在pom.xml里面修改包的导出方式(默认是jar)

war

一、2、快速入门

第一步:创建 web项目,导入 Servlet依赖坐标

jakarta.servlet

jakarta.servlet-api

5.0.0

provided//scope依赖范围:在编译和测试环境有效,在运行环境无效。

第二步: 创建:定义一个类,实现 Servlet接口,并重写接口中所有方法配置:在类上使用@WebServlet 注解,配置该 Servlet的访问路径(或者在pom.xml下配置访问路径)访问:启动 Tomcat,浏览器输入URL 访问该Servlet:http://localhost:8080/+配置的访问路径(以下面的为例子)

http://localhost:8080/demo03

//@WebServlet(value = "/demo04",loadOnStartup = 1)//loadOnStartup的参数是设置servlet对象创建的时机的

// @WebServlet(value = "/demo04")是使用@WebServlet注解设置访问Servlet的访问路径的,相当于用xml文件配置

// xml的配置如下(在web.xml下的web-app标签里面配置)

/*

demo03

Dao.servletDemo03

demo03

/demo03

*/

//1. 负整数:第一次被访问时创建Servlet对象。(默认情况)

//2. 0或正整数:服务器启动时创建Servlet对象,数字越小,优先级越高

@WebServlet(loadOnStartup = 1)

public class servletDemo03 implements Servlet {

/**

* init:初始化方法

* 1. 调用时机:默认情况下,Servlet被第一次访问时,调用

* @WebServlet(loadOnStartup = 1)就是调用访问的时机的

* 2. 调用次数:1次

* @param servletConfig

* @throws ServletException

*/

@Override

public void init(ServletConfig servletConfig) throws ServletException {

System.out.println("你好,Servlet-demo03,init");

}

@Override

public ServletConfig getServletConfig() {

return null;

}

/**

* service:服务方法

* 1. 调用时机:每一次servlet被访问时,调用此方法

* 2. 调用次数:多次

*

* @param servletRequest

* @param servletResponse

* @throws ServletException

* @throws IOException

*/

@Override

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

System.out.println("hello ,servlet-demo03");

}

@Override

public String getServletInfo() {

return null;

}

/**

* destroy:销毁方法

* 1. 调用时机:内存释放或者服务器关闭的时候,servlet会被销毁,然后就会调用此方法

* 2. 调用次数:1次

*/

@Override

public void destroy() {

}

}

一、3、Servlet执行流程

Servlet 由谁创建?Servlet方法由谁调用?

Servlet由web服务器创建,Servlet方法由web服务器调用。 服务器怎么知道Servlet中一定有service方法?

因为我们自定义的Servlet,必须实现Servlet接口并复写其方法,而Servlet接口中有service方法

一、4、Servlet的生命周期

对象的生命周期指一个对象从被创建到被销毁的整个过程Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:

1)加载和实例化:默认情况下,当Servlet第一次被访问时,由容器(web服务器)创建Servlet对象2)初始化:在Servlet实例化之后,容器将调用Servlet的init()方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作。该方法只调用一次3)请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理。4)服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的destroy()方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收

一、5、Servlet体系结构

一、5.1、HttpServlet 原理:

HTTP 协议中,GET 和 POST 请求方式的数据格式不一样,将来要想在Servlet中处理请求参数,得在service方法中判断请求方式,并且根据请求方式的不同,分别进行处理: HttpServlet中为什么要根据请求方式的不同,调用不同方法?

因为get和post的请求方式它们的请求消息不太一样,,所以需要分别去处理 如何调用?

获取请求方式,作出不同的逻辑判断 HttpServlet 使用步骤

继承HttpServlet重写doGet和doPost方法 HttpServlet原理

获取请求方式,并根据不同的请求方式,调用不同的doXxx方法

一、6、Servlet的urlPattern(或者是value)配置

Servlet 要想被访问,必须配置其访问路径(urlPattern)

一个Servlet,可以配置多个 urlPattern

@WebServlet(urlPatterns = {"/demo111","/demo222"})

public class demo01 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

System.out.println("demo01//......");

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}

}

urlPattern 配置规则

1)精确匹配2)目录匹配3)扩展名匹配4)任意匹配

/ 和 /* 区别: (默认的DefaultServle(它的访问路径就是"/"):在输入静态资源html等的路径的时候是t能够访问静态资源) 但是当我们的项目中的Servlet配置了“/”,会覆盖掉tomcat中的DefaultServlet(会导致静态资源无法访问),当其他的 url-pattern都匹配不上时都会走这个Servlet(DefaultServlet),在输入静态资源的路径后就会出现访问不到静态资源的问题,所以一般不推荐使用这中匹配方式 当我们的项目中配置了“/*”,意味着匹配任意访问路径

匹配的优先级 精确路径 > 目录路径 > 扩展名路径 > /* > /

一、7、XML配置方式编写Servlet

Servlet 从3.0版本后开始支持使用注解配置,3.0版本前只支持 XML 配置文件的配置方式步骤:

1):编写 Servlet类2):在 web.xml中配置该Servlet

二、Request和Respond

request:用于获取请求数据(浏览器向服务器发出的请求)

浏览器会发送HTTP请求到后台服务器[Tomcat]HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务 respond:用于设置响应数据(服务器向浏览器发出的响应)

业务处理完后,后台就需要给前端返回业务处理的结果即响应数据把响应数据封装到response对象中后台服务器[Tomcat]会解析response对象,按照[响应行+响应头+响应体]格式拼接结果浏览器最终解析结果,把内容展示在浏览器给用户浏览

@WebServlet("/demo3")

public class ServletDemo3 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//使用request对象 获取请求数据

String name = request.getParameter("name");//url?name=zhangsan

//使用response对象 设置响应数据

response.setHeader("content-type","text/html;charset=utf-8");

response.getWriter().write("

"+name+",欢迎您!

");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("Post...");

}

}

启动成功后就可以通过浏览器来访问,并且根据传入参数的不同就可以在页面上展示不同的内容

二、1、Request

二、1.1、 Request继承体系

2. Request的继承体系为ServletRequest–>HttpServletRequest–>RequestFacade 3. Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法 4. 使用request对象,可以查阅JavaEE API文档的HttpServletRequest接口中方法说明 5. Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat] 来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建

二、1.2、Request获取请求数据

二、1.2.1、获取请求行的数据

请求行包含三块内容,分别是请求方式、请求资源路径、HTTP协议及版本

获取请求方式: GET

String getMethod()

获取虚拟目录(项目访问路径): /request-demo

String getContextPath()

获取URL(统一资源定位符): http://localhost:8080/request-demo/req1

StringBuffer getRequestURL()

获取URI(统一资源标识符): /request-demo/req1

String getRequestURI()

获取请求参数(GET方式): username=zhangsan&password=123

String getQueryString()

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet(urlPatterns = {"/demo333","/demo444"})

public class demo03 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String method = req.getMethod();//获取请求方式

System.out.println(method);

String contextPath = req.getContextPath(); //获取虚拟目录(即项目的访问路径)

System.out.println(contextPath);

StringBuffer requestURL = req.getRequestURL();//获取全路径

System.out.println(requestURL.toString());

String requestURI = req.getRequestURI();//获取较短的路径

System.out.println(requestURI);

String queryString = req.getQueryString();//获取请求参数

System.out.println(queryString);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}

}

结果:

二、1.2.2、获取请求头的信息

对于请求头的数据,格式为key: value如下 所以根据请求头名称获取对应值的方法为:

String getHeader(String name)

要获取客户端浏览器的版本信息:

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet(urlPatterns = {"/demo333","/demo444"})

public class demo03 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//获取请求头: user-agent: 浏览器的版本信息

String agent = req.getHeader("user-agent");

System.out.println(agent);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}

}

二、1.2.3、获取请求体 (浏览器发送的POST请求才有请求体)

浏览器在发送GET请求的时候是没有请求体的,所以需要把请求方式变更为POST,请求体中的数据格式如下: 对于请求体中的数据,Request对象提供了如下两种方式来获取其中的数据,分别是:

获取字节输入流,如果前端发送的是字节数据,比如传递的是文件数据,则使用该方法

ServletInputStream getInputStream()

该方法可以获取字节

获取字符输入流,如果前端发送的是纯文本数据,则使用该方法

BufferedReader getReader()

具体实现的步骤如下:

1.准备一个页面,在页面中添加form表单,用来发送post请求

2.在Servlet的doPost方法中获取请求体数据

3.在doPost方法中使用request的getReader()或者getInputStream()来获取

4.访问测试

注意:BufferedReader流是通过request对象来获取的,当请求完成后request对象就会被销毁,request对象被销毁后,BufferedReader流就会自动关闭,所以此处就不需要手动关闭流了

Title

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.BufferedReader;

import java.io.IOException;

@WebServlet(urlPatterns = {"/demo333","/demo444"})

public class demo03 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//

//获取post 请求体:请求参数

//1. 获取字符输入流

BufferedReader br = req.getReader();

//2. 读取数据

String line = br.readLine();

System.out.println(line);

}

}

二、1.3、获取请求参数的通用方式

在学习下面内容之前,我们先提出两个问题:

1)什么是请求参数?2)请求参数和请求数据的关系是什么?

1.1)什么是请求参数?

为了能更好的回答上述两个问题,我们拿用户登录的例子来说明1.1 想要登录网址,需要进入登录页面1.2 在登录页面输入用户名和密码1.3 将用户名和密码提交到后台1.4 后台校验用户名和密码是否正确1.5 如果正确,则正常登录,如果不正确,则提示用户名或密码错误 上述例子中,用户名和密码其实就是我们所说的请求参数。 1)什么是请求数据?

请求数据则是包含请求行、请求头和请求体的所有数据 2)请求参数和请求数据的关系是什么?

2.1 请求参数是请求数据中的部分内容2.2 如果是GET请求,请求参数在请求行中2.3 如果是POST请求,请求参数一般在请求体中 对于请求参数的获取,常用的有以下两种: GET方式:

String getQueryString()

POST方式:

BufferedReader getReader();

doGet和doPost方法由于获取请求参数的方式不一样,因此存在很多的重复业务代码。解决办法: 当然,也可以在doGet中调用doPost,在doPost中完成参数的获取和打印,另外需要注意的是,doGet和doPost方法都必须存在,不能删除任意一个。

GET请求和POST请求获取请求参数的方式不一样,在获取请求参数这块该如何实现呢?

GET请求方式和POST请求方式区别主要在于获取请求参数的方式不一样,

是否可以提供一种统一获取请求参数的方式,从而统一doGet和doPost方法内的代码

方法一(不推荐使用)

@WebServlet("/req1")

public class RequestDemo1 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {

//获取请求方式

String method = req.getMethod();

//获取请求参数

String params = "";

if("GET".equals(method)){

params = req.getQueryString();

}else if("POST".equals(method)){

BufferedReader reader = req.getReader();

params = reader.readLine();

}

//将请求参数进行打印控制台

System.out.println(params);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {

this.doGet(req,resp);

}

}

使用request的getMethod()来获取请求方式,根据请求方式的不同分别获取请求参数值,这样就可以解决上述问题,但是以后每个Servlet都需要这样写代码,实现起来比较麻烦,这种方案我们不采用 方法二 request对象已经将上述获取请求参数的方法进行了封装,并且request提供的方法实现的功能更强大,以后只需要调用request提供的方法即可,在request的方法中都实现了哪些操作? (1)根据不同的请求方式获取请求参数,获取的内容如下: (2)把获取到的内容进行分割,内容如下: (3)把分割后端数据,存入到一个Map集合中: 注意:因为参数的值可能是一个,也可能有多个,所以Map的值的类型为String数组

request对象为我们提供了如下方法:

获取所有参数Map集合

Map getParameterMap()

根据名称获取参数值(数组)

String[] getParameterValues(String name)

根据名称获取参数值(单个值)

String getParameter(String name)

String getParameter(String name):这里的name是html的input标签的name属性的值。

Title



游泳

爬山

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.Map;

@WebServlet(urlPatterns = {"/demo444"})

public class demo04 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//GET请求逻辑

System.out.println("get....");

//1. 获取所有参数的Map集合(获取GET方式的所有请求参数)

Map map = req.getParameterMap();

for (String key : map.keySet()) {

// username:zhangSan lisi

System.out.print(key + ":");

//获取值

String[] values = map.get(key);

for (String value : values) {

System.out.print(value + " ");

}

System.out.println();

}

//获取GET请求参数中的爱好,结果是数组值

System.out.println("------------");

String[] hobbies = req.getParameterValues("hobby");

for (String hobby : hobbies) {

System.out.println(hobby);

}

// 获取单个值

String username = req.getParameter("username");

String password = req.getParameter("password");

System.out.println(username);

System.out.println(password);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

this.doGet(req,resp);//这个代替下面的重复代码

// System.out.println("post....");

// //1. 获取所有参数的Map集合

// Map map = req.getParameterMap();

// for (String key : map.keySet()) {

// // username:zhangSan lisi

// System.out.print(key + ":");

//

// //获取值

// String[] values = map.get(key);

// for (String value : values) {

// System.out.print(value + " ");

// }

//

// System.out.println();

// }

//...

// System.out.println("------------");

// String[] hobbies = req.getParameterValues("hobby");

// for (String hobby : hobbies) {

// System.out.println(hobby);

// }

}

}

二、1.4、请求参数中文乱码问题(tomcat8.0版本以前才存在的问题)

post的请求方式的乱码:

分析出现中文乱码的原因:

POST的请求参数是通过request的getReader()来获取流中的数据 TOMCAT在获取流的时候采用的编码是ISO-8859-1 ISO-8859-1编码是不支持中文的,所以会出现乱码 解决方案:

页面设置的编码格式为UTF-8 把TOMCAT在获取流数据之前的编码设置为UTF-8 通过request.setCharacterEncoding(“UTF-8”)设置编码,UTF-8也可以写成小写 request.setCharacterEncoding(“utf-8”)是设置request处理流的编码

//1. 解决乱码: POST getReader()

//设置字符输入流的编码,设置的字符集要和页面保持一致

request.setCharacterEncoding("UTF-8");

get请求方式的乱码

首先我们需要先分析下GET请求出现乱码的原因:

(1)浏览器通过HTTP协议发送请求和数据给后台服务器(Tomcat)(2)浏览器在发送HTTP的过程中会对中文数据进行URL编码(3)在进行URL编码的时候会采用页面标签指定的UTF-8的方式进行编码,张三编码后的结果为%E5%BC%A0%E4%B8%89(4)后台服务器(Tomcat)接收到%E5%BC%A0%E4%B8%89后会默认按照ISO-8859-1进行URL解码(5)由于前后编码与解码采用的格式不一样,就会导致后台获取到的数据为乱码。 思考: 如果把req.html页面的标签的charset属性改成ISO-8859-1 ,后台不做操作,能解决中文乱码问题么?

答案是否定的,因为ISO-8859-1本身是不支持中文展示的,所以改了标签的charset属性后,会导致页面上的中文内容都无法正常展示。 分析完上面的问题后,我们会发现,其中有两个我们不熟悉的内容就是URL编码和URL解码,什么是URL编码,什么又是URL解码呢?

编码:

java.net.URLEncoder.encode("需要被编码的内容","字符集(UTF-8)")

解码:

java.net.URLDecoder.decode("需要被解码的内容","字符集(UTF-8)")

public static void main(String[] args) throws UnsupportedEncodingException

{

String username = "张三";

//1. URL编码

String encode = URLEncoder.encode(username, "utf-8");

System.out.println(encode); //打印:%E5%BC%A0%E4%B8%89

//2. URL解码

//String decode = URLDecoder.decode(encode, "utf-8");//打印:张三

String decode = URLDecoder.decode(encode, "ISO-8859-1");//打印:`å¼ ä¸ `

System.out.println(decode);

}

}

解决方案

public class RequestDemo4 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//1. 解决乱码:POST,getReader()

//request.setCharacterEncoding("UTF-8");//设置字符输入流的编码

//2. 获取username

String username = request.getParameter("username");

System.out.println("解决乱码前:"+username);

//3. GET,获取参数的方式:getQueryString

// 乱码原因:tomcat进行URL解码,默认的字符集ISO-8859-1

/* //3.1 先对乱码数据进行编码:转为字节数组

byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);

//3.2 字节数组解码

username = new String(bytes, StandardCharsets.UTF_8);*/

username = new

String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);

System.out.println("解决乱码后:"+username);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

把request.setCharacterEncoding(“UTF-8”)代码注释掉后,会发现GET请求参数乱码解决方案 同时也可以把POST请求参数乱码的问题也解决了只不过对于POST请求参数一般都会比较多,采用这种方式解决乱码起来比较麻烦,所以对于POST请求还是建议使用设置编码的方式进行。

二、1.5、Request请求转发(实现在转发多个资源之间共享数据)

请求转发(forward):一种在服务器内部的资源跳转方式。

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求(2)资源A处理完请求后将请求发给资源B(3)资源B处理完后将结果响应给浏览器(4)请求从资源A到资源B的过程就叫请求转发 请求转发的实现方式:

req.getRequestDispatcher("资源B路径").forward(req,resp);

请求转发资源间共享数据:使用Request对象,此处主要解决的问题是把请求从/req5转发到/req6的时候,如何传递数据给/req6。需要使用request对象提供的三个方法:

1)存储数据到request域[范围,数据是存储在request对象]中 void setAttribute(String name,Object o);2)根据key获取值 Object getAttribute(String name);3)根据key删除该键值对 void removeAttribute(String name);

1.在RequestDemo5的doGet方法中转发请求之前,将数据存入request域对象中

2.在RequestDemo6的doGet方法从request域对象中获取数据,并将数据打印到控制台

3.启动访问测试

rep5

@WebServlet("/req5")

public class RequestDemo5 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("demo5...");

//存储数据

request.setAttribute("msg","hello");

//请求转发

request.getRequestDispatcher("/req6").forward(request,response);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

rep6

@WebServlet("/req6")

public class RequestDemo6 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("demo6...");

//获取数据

Object msg = request.getAttribute("msg");

System.out.println(msg);

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request, response);

}

}

请求转发的特点:

浏览器地址栏路径不发生变化,虽然后台从/req5转发到/req6 ,但是浏览器的地址一直是/req5 ,未发生变化只能转发到当前服务器的内部资源,不能从一个服务器通过转发访问另一台服务器一次请求,可以在转发资源间使用request共享数据,虽然后台从/req5转发到/req6,但是这个只有一次请求

二、2、Respond

二、2.1、 Respond继承体系

二、2.2、Response设置响应数据功能介绍

HTTP响应数据总共分为三部分内容,分别是响应行、响应头、响应体,对于这三部分内容的数据, respone对象都提供了哪些方法来进行设置?

响应行 对于响应头,比较常用的就是设置响应状态码:

void setStatus(int sc);

响应头 设置响应头键值对:

void setHeader(String name,String value);

响应体 对于响应体,是通过字符、字节输出流的方式往浏览器写,

获取字符输出流:

PrintWriter getWriter();

获取字节输出流:

ServletOutputStream getOutputStream();

二、2.3、Respond请求重定向

重定向是一种资源跳转方式

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求(2)资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径(3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B(4)资源B接收到请求后进行处理并最终给浏览器响应结果,这整个过程就叫重定向 重定向的实现方式:

resp.setStatus(302);

resp.setHeader("location","资源B的访问路径");

package Respond1;

import jakarta.servlet.*;

import jakarta.servlet.http.*;

import jakarta.servlet.annotation.*;

import java.io.IOException;

@WebServlet("/resp1")

public class RespondServlet1 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("resp1....");

//重定向

//1.设置响应状态码 302

// response.setStatus(302);

//2. 设置响应头 Location

// response.setHeader("Location","/Tomcat_demo04_war/resp2");

// 总的来说,上面这个方法除了那个路径是需要改变的,其他都是固定的,因此,可以改写成下面的方法

//response.sendRedirect("/Tomcat_demo04_war/resp2");

// 下面的是更值得推荐使用的方法:

//简化方式完成重定向

//动态获取虚拟目录

String contextPath = request.getContextPath();

response.sendRedirect(contextPath+"/resp2");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request,response);

}

}

package Respond1;

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/resp2")

public class RespondServlet2 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("resp2....");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request,response);

}

}

重定向的特点: 1)当进行重定向访问的时候浏览器地址栏路径发生变化,由于是由浏览器发送的两次请求,所以地址会发生变化 2)可以重定向到任何位置的资源(服务内容、外部均可) 因为第一次响应结果中包含了浏览器下次要跳转的路径,所以这个路径是可以任意位置资源。 3)两次请求,不能在多个资源使用request共享数据因为浏览器发送了两次请求,是两个不同的request对象,就无法通过request对象进行共享数据

二、2.4、Request和Respond请求转发的对比

二、2.5、请求转向的路径问题

问题1:请求转发的时候路径上没有加/Tomcat_demo04_war而重定向加了,那么到底什么时候需要加,什么时候不需要加呢?

// 请求转发

request.getRequestDispatcher("/demo06").forward(request,response);//这里的demo06的作用跟下面的resp2作用一样

// 重定向

response.sendRedirect("/Tomcat_demo04_war/resp2");

其实判断的依据很简单,只需要记住下面的规则即可:

浏览器使用:需要加虚拟目录(项目访问路径)服务端使用:不需要加虚拟目录 对于转发来说,因为是在服务端进行的,所以不需要加虚拟目录 对于重定向来说,路径最终是由浏览器来发送请求,就需要添加虚拟目录

掌握了这个规则,接下来就通过一些练习来强化下知识的学习: 问题:

req.getRequestDispatcher("路径")

resp.sendRedirect("路径")

答案:

1.超链接,从浏览器发送,需要加

2.表单,从浏览器发送,需要加

3.转发,是从服务器内部跳转,不需要加

4.重定向,是由浏览器进行跳转,需要加。

问题2:在重定向的代码中,/request-demo是固定编码的,如果后期通过Tomcat插件配置了项目的访问路径,那么所有需要重定向的地方都需要重新修改,该如何优化? 答案也比较简单,我们可以在代码中动态去获取项目访问的虚拟目录,具体如何获取,我们可以借助前面咱们所学习的request对象中的getContextPath()方法,修改后的代码如下:

package Respond1;

import jakarta.servlet.*;

import jakarta.servlet.http.*;

import jakarta.servlet.annotation.*;

import java.io.IOException;

@WebServlet("/resp1")

public class RespondServlet1 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

System.out.println("resp1....");

//简化方式完成重定向

//动态获取虚拟目录

String contextPath = request.getContextPath();

response.sendRedirect(contextPath+"/resp2");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request,response);

}

}

作用:降低代码的耦合度。(提高维护性,或者说:让代码的每个模块尽可能的独立完成某个特定的子功能) 耦合度:其实就是各个模块之间的依赖性

二、2.6、Respond响应字符数据

要想将字符数据写回到浏览器,我们需要两个步骤:

通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();通过字符输出流写数据: writer.write(“aaa”);

package Respond1;

import jakarta.servlet.ServletException;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.io.PrintWriter;

@WebServlet("/resp3")

public class RespondServlet3 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// response.setContentType("text/html;;charset=utf-8");(注意:目前tomcat10.0版本,不存在乱码问题)

// 获取字符输出流

PrintWriter writer = response.getWriter();

// content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签

response.setHeader("content-type","text/html");

writer.write("你好");

writer.write("

bbb

");

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request,response);

}

}

注意:一次请求响应结束后,response对象就会被销毁掉,所以不要手动关闭流。tomcat10.0版本不存在中文乱码问题。

二、2.7、Response响应字节数据

要想将字节数据写回到浏览器,我们需要两个步骤:

通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();通过字节输出流写数据: outputStream.write(字节数据);

package Respond1;

import jakarta.servlet.ServletException;

import jakarta.servlet.ServletOutputStream;

import jakarta.servlet.annotation.WebServlet;

import jakarta.servlet.http.HttpServlet;

import jakarta.servlet.http.HttpServletRequest;

import jakarta.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import java.io.FileInputStream;

import java.io.IOException;

/*

响应字节数据

*/

@WebServlet("/resp4")

public class RespondServlet4 extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//1. 读取文件

FileInputStream fis = new FileInputStream("d://1.jpg");

//2. 获取response字节输出流

ServletOutputStream os = response.getOutputStream();

//3. 完成流的copy

// byte[] buff = new byte[1024];

// int len = 0;

// while ((len = fis.read(buff))!= -1){

// os.write(buff,0,len);

// }

// 使用工具类方法

IOUtils.copy(fis,os);

// 4. 流的关闭

fis.close();

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

this.doGet(request,response);

}

}

上述代码中,对于流的copy的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码的开发,具体的步骤是:

(1)pom.xml添加依赖

commons-io

commons-io

2.6

调用工具类方法

//fis:输入流

//os:输出流

IOUtils.copy(fis,os);

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: