文章目录
- [1. 概念](#1. 概念)
- 2.基础案例
- 3.servlet生命周期
- 4.ServletConfig接口
- 5.ServletContext对象
- 6.HttpServlet抽象类
- 7.中文乱码问题
- 8.请求转发与重定向
1. 概念
- Servlet 是 JavaEE 规范之一。 规范就是接口
- Servlet 就 JavaWeb 三大组件之一。 三大组件分别是: Servlet 程序、 Filter 过滤器、 Listener 监
听器。 - Servlet服务于HTTP协议的服务端的一个小程序,"接收请求,解析请求,根据请求执行业务逻辑,
做出响应
也就是说 servlet是一个用来处理 请求 做出回应的容器,对于每一个应用程序,Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象。
2.基础案例
从Servlet3.0开始,配置Servlet支持注解方式,但还是保留了配置web.xml方式,所有使用Servlet有两
种方式:
(1)Servlet类上使用@WebServlet注解进行配置
(2)web.xml文件中配置
1.基于注解的配置
这个基于注解的配置关键在于@WebServlet("/hello")
这个用来设置虚拟路径然后才有了访问的地址
@WebServlet常用属性
- loadOnStartup属性::标记容器是否在启动应用时就加载Servlet,默认不配置或数值为负数时表示客户端第一次请求Servlet时再加载;0或正数表示启动应用就加载,正数情况下,数值越小,加载该Servlet的优先级越高;
go
@WebServlet(value="/test1",loadOnStartup=1)
- urlPatterns的常用规则:
- /*或者/:拦截所有(所谓拦截也就是意思只有这个范围下的地址可以被访问)
如果放行特定的请求比如静态资源html,css,jpg,可以配置如下:
go
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
-
*.do:拦截指定后缀
-
使用注解时,需要注意
根元素中不能配置属性metadata-complete="true",否则无法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解,为Web应用程序构建有效的元数据;metadata-complete="true",会在启动时不扫描注解(annotation)。如果不扫描注解的话,用注解进行的配置就无法生效,例如:@WebServlet
1.引入依赖
2.创建HttpServlet
bash
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
BufferedReader in = new BufferedReader(new
InputStreamReader(request.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
}
@Override
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
System.out.println("queryString = " + request.getQueryString());
response.getWriter().print(request.getQueryString());
}
}
3.表单访问
bash
<h4>get</h4>
<form action="http://localhost:8080/servlet-demo/hello" method="get">
<input type="text" name="username" value="mickey"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
<h4>post</h4>
<form action="http://localhost:8080/servlet-demo/hello" method="post">
<input type="text" name="username" value="mickey"><br>
<input type="text" name="password" value="123456"><br>
<input type="submit" value="提交">
</form>
2.基于XML配置
这个基于XML配置的关键就在于下面图的资源路径 也就是虚拟路径 这样才可以找到这个页面
web.xml
bash
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lxs.demo.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
执行地址到servlet的关系
3.servlet生命周期
Servlet 是 Java Web 开发中的一种用于处理请求和响应的组件。它具有自己的生命周期,包括以下几个阶段:
-
加载:当容器启动 或首次请求到达时,Servlet 容器会加载 Servlet 类。这个阶段会创建 Servlet 类的实例,并调用其 init() 方法进行初始化。
-
初始化:在加载后,Servlet 容器会调用 Servlet 实例的 init() 方法进行初始化。在初始化阶段,可以执行一些必要的设置,例如读取配置文件、建立数据库连接等。init() 方法在 Servlet 的生命周期中只会被调用一次。
-
处理请求:在初始化完成后,Servlet 容器会根据每个请求创建一个线程,调用 Servlet 实例的 service() 方法来处理请求。在 service() 方法中,可以根据请求的类型(如 GET、POST 等)执行相应的逻辑,生成响应数据。
-
销毁:当容器关闭或者需要卸载 Servlet 时,会调用 Servlet 实例的 destroy() 方法进行清理操作。在该方法中,可以进行资源释放、数据库连接关闭等善后工作。destroy() 方法也只会被调用一次。
需要注意的是,每次请求都会创建一个单独的线程来处理,而不是每个请求都创建一个新的 Servlet 实例。Servlet 实例是多线程共享的,因此需要在实现中保证线程安全性。
配置参数解决输出中文乱码问题
bash
-Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
4.ServletConfig接口
当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。
配置参数都在web.xml里面配置
其中几个方法如下
-
String getServletName()
:获取当前 Servlet 的名称。 -
ServletContext getServletContext()
:获取与当前 Servlet 相关联的 Servlet 上下文对象。 -
String getInitParameter(String name)
:根据给定参数名获取相应的初始化参数值。 -
Enumeration<String> getInitParameterNames()
:获取所有初始化参数的名称的枚举。
总之,ServletConfig
接口提供了一种机制,允许 Servlet 访问它的配置信息和初始化参数。这些信息对于 Servlet 的运行时行为和逻辑可能会非常有用。
5.ServletContext对象
ServletContext
对象是 Java Web 应用程序中的一个接口,它代表了整个 Web 应用程序的上下文环境。每个 Web 应用程序只有一个 ServletContext
实例,由 Servlet 容器在启动应用程序时创建,并在关闭应用程序时销毁。
ServletContext
接口提供了一系列方法,用于访问和操作与当前 Web 应用程序相关的信息和资源,包括:
-
获取初始化参数:可以使用
getInitParameter(String name)
方法获取部署描述符(如 web.xml 文件)中配置的初始化参数的值。通过getInitParameterNames()
方法可以获取所有初始化参数的名称。 -
获取上下文路径:可以使用
getContextPath()
方法获取当前 Web 应用程序的上下文路径(Context Path)。上下文路径是 Web 应用程序被部署后的访问路径的一部分。 -
获取真实路径:可以使用
getRealPath(String path)
方法将给定的相对路径转换为在文件系统中的真实路径。此方法通常用于获取在 Web 应用程序中的资源的物理路径。 -
获取资源:可以使用
getResource(String path)
或getResourceAsStream(String path)
方法获取位于 Web 应用程序中的某个资源的 URL 或输入流。 -
设置和获取属性:可以使用
setAttribute(String name, Object value)
方法设置一个在 ServletContext 中的属性。使用getAttribute(String name)
方法可以获取指定名称的属性的值。
除了以上几点,ServletContext 还提供了其他一些方法,用于获取 Servlet 注册信息、获取和操作 ServletContext 初始化参数等。通过 ServletContext 对象,可以在整个 Web 应用程序范围内共享数据和资源,以及访问应用程序的配置信息
6.HttpServlet抽象类
HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应 HttpServletRequest和HttpServletResponse对象。
在实现这个抽象类之后我们可以通过重写Service方法来处理请求即可
HttpServlet 类定义了以下几个主要方法:
-
void service(HttpServletRequest request, HttpServletResponse response)
:这是 HttpServlet 的核心方法,用于处理 HTTP 请求和生成 HTTP 响应。在该方法中,可以根据不同的 HTTP 方法(如 GET、POST 等)执行相应的逻辑来处理请求的参数、生成响应内容等。 -
protected void doGet(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP GET 请求的方法。默认情况下,service() 方法会调用此方法来处理 GET 请求。 -
protected void doPost(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP POST 请求的方法。默认情况下,service() 方法会调用此方法来处理 POST 请求。 -
protected void doPut(HttpServletRequest request, HttpServletResponse response)
:用于处理 HTTP PUT 请求的方法。 -
protected void doDelete(HttpServletRequest request,HttpServletResponse response)
:用于处理 HTTP DELETE 请求的方法。
除了上述方法,HttpServlet 还提供了一些其他的方法,如 doOptions() 用于处理 HTTP OPTIONS 请求,doHead() 用于处理 HTTP HEAD 请求等。这些方法可以根据需要进行覆盖,以实现对不同类型的 HTTP 请求的处理
7.中文乱码问题
出现中文乱码问题通常就是编码和解码不一致导致
- Get 请求的中文乱码解决:
get的默认编码utf-8,以前老版本tomcat中get编码是iso-8859-1
go
// 获取请求参数
String username = req.getParameter("username");
//1 先以 iso8859-1 进行编码
//2 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
- POST 请求的中文乱码解决
go
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException,
IOException {
// 设置请求体的字符集为 UTF-8, 从而解决 post 请求的中文乱码问题
req.setCharacterEncoding("UTF-8");
System.out.println("-------------doPost------------");
// 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobby");
System.out.println("用户名: " + username);
System.out.println("密码: " + password);
System.out.println("兴趣爱好: " + Arrays.asList(hobby));
}
- response的乱码解决
方式1:
go
// 设置服务器字符集为 UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头, 设置浏览器也使用 UTF-8 字符集
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
解决响应中文乱码方案二(推荐) :
go
// 它会同时设置服务器和客户端都使用 UTF-8 字符集, 还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");
8.请求转发与重定向
二者区别:
一次请求与两次请求!
-
- 定义:请求转发是在服务器内部进行的一种机制,将请求从一个组件(如 Servlet)直接转发给另一个组件。重定向是通过发送特殊的响应状态码和 URL 到客户端浏览器,让浏览器重新发送一个新的请求来达到页面跳转的目的。
-
- 浏览器行为:请求转发是在服务器内部完成的,对浏览器是透明的,浏览器的 URL 不会发生变化。而重定向会向浏览器发送一个新的响应,浏览器会根据响应中的 URL 进行请求的重新发送,因此浏览器的 URL 会发生变化。
-
- 请求次数:请求转发只需要一次请求和响应的往返,所以在网络传输上效率更高。而重定向会导致两次请求和响应的往返,一次是原始请求的响应,一次是重定向后新请求的响应,相对来说会增加一定的网络开销。
-
- 共享数据:请求转发时,可以共享同一个 request 对象,在多个组件之间传递数据。而重定向是两次请求,每个请求都会有一个新的 request 对象,数据不能直接共享,需要使用其他机制(如 URL 参数、Session 等)来传递数据。
-
- 场景应用:请求转发常用于在服务器内部进行组件之间的流转,如多个 Servlet 之间的数据交互,MVC 架构中的控制器转发等。重定向常用于页面的跳转,错误处理,或者需要刷新页面的场景。
1.请求转发
请求转发(Request Forwarding)是一种在服务器端将请求从一个 Servlet 转发给另一个 Servlet 或 JSP 页面的机制。在请求转发中,客户端只发送一次请求,而服务器在内部将请求从一个组件传递到另一个组件,然后将响应返回给客户端。
- 在要进行请求转发的 Servlet 中,获得 RequestDispatcher 实例,可以使用以下代码:
go
RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet");
其中,/targetServlet 是目标 Servlet 的路径。
- 调用 forward() 方法来执行请求转发:
go
dispatcher.forward(request, response);
其中,request 和 response 分别是当前 Servlet 的 HttpServletRequest 和 HttpServletResponse 对象。
请求转发的主要优点是:
- 内部流转:客户端对转发过程毫无察觉,URL 保持不变。
- 资源共享:由于转发操作使用同一个 request 对象,可以方便地在多个组件之间共享数据。
- 减少网络开销:只有一次请求和响应的往返,减少了网络开销。
请求转发通常用于以下情况:
- Servlet 之间数据交互:可以将请求从一个 Servlet 转发到另一个 Servlet,以便在它们之间共享数据。
- MVC 架构中的控制器转发:根据请求的不同,将请求转发到不同的控制器来处理特定的业务逻辑。
- 错误处理:在出现错误时,转发到专门的错误处理 Servlet 或 JSP 页面来显示错误信息。
servlet1代码
go
package Servlet;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
System.out.println(("在Servlet1(柜台1)中查看参数(材料):"+username));
req.setAttribute("key1","柜台1的章");
RequestDispatcher requestDispatcher =
req.getRequestDispatcher("/servlet2");
requestDispatcher.forward(req,resp);
}
}
servlet2代码
go
package Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet2")
public class servlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
// 查看 柜台1 是否有盖章
Object key1 = req.getAttribute("key1");
System.out.println("柜台1是否有章:" + key1);
// 处理自己的业务
System.out.println("Servlet2 处理自己的业务 ");
}
}
2.请求重定向
请求重定向是客户端向服务器发送请求后,服务器告诉客户端要通过新的地址进行访问的过程。这个过程中,浏览器的地址栏会发生变化,发生两次请求。与请求转发不同的是,请求重定向不能共享Request域中的数据,也不能直接访问WEB-INF下的资源,但可以访问工程外的资源。123
方式一:
go
// 设置响应状态码 302 , 表示重定向, (已搬迁)
resp.setStatus(302);
// 设置响应头, 说明 新的地址在哪里
resp.setHeader("Location", "http://localhost:8080");
方式二:
go
resp.sendRedirect("http://localhost:8080");
servlet3:
go
package chongdingxiang;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet3")
public class servlet3 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
System.out.println(("在Servlet3(柜台1)中查看参数(材料):"+username));
this.getServletContext().setAttribute("globalKey", "hello servlet global");
req.setAttribute("key3","柜台3的章");
// resp.sendRedirect("http://localhost:8080/servletdemo1/servlet4");
resp.setStatus(HttpServletResponse.SC_FOUND);
resp.setHeader("Location","http://localhost:8080/servletdemo1/servlet4");
}
}
servlet4:
go
package chongdingxiang;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/servlet4")
public class servlet4 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
System.out.println("在Servlet4(柜台4)中查看参数(材料):" + username);
System.out.println(this.getServletContext().getAttribute("globalKey"));
// 查看 柜台1 是否有盖章
Object key1 = req.getAttribute("key3");
System.out.println("柜台3是否有章:" + key1);
// 处理自己的业务
System.out.println("Servlet4 处理自己的业务 ");
}
}