Servlet

文章目录


1. 概念

  1. Servlet 是 JavaEE 规范之一。 规范就是接口
  2. Servlet 就 JavaWeb 三大组件之一。 三大组件分别是: Servlet 程序、 Filter 过滤器、 Listener 监
    听器。
  3. 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常用属性

  1. loadOnStartup属性::标记容器是否在启动应用时就加载Servlet,默认不配置或数值为负数时表示客户端第一次请求Servlet时再加载;0或正数表示启动应用就加载,正数情况下,数值越小,加载该Servlet的优先级越高;
go 复制代码
@WebServlet(value="/test1",loadOnStartup=1)
  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 开发中的一种用于处理请求和响应的组件。它具有自己的生命周期,包括以下几个阶段:

  1. 加载:当容器启动首次请求到达时,Servlet 容器会加载 Servlet 类。这个阶段会创建 Servlet 类的实例,并调用其 init() 方法进行初始化。

  2. 初始化:在加载后,Servlet 容器会调用 Servlet 实例的 init() 方法进行初始化。在初始化阶段,可以执行一些必要的设置,例如读取配置文件、建立数据库连接等。init() 方法在 Servlet 的生命周期中只会被调用一次。

  3. 处理请求:在初始化完成后,Servlet 容器会根据每个请求创建一个线程,调用 Servlet 实例的 service() 方法来处理请求。在 service() 方法中,可以根据请求的类型(如 GET、POST 等)执行相应的逻辑,生成响应数据。

  4. 销毁:当容器关闭或者需要卸载 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里面配置

其中几个方法如下

  1. String getServletName():获取当前 Servlet 的名称。

  2. ServletContext getServletContext():获取与当前 Servlet 相关联的 Servlet 上下文对象。

  3. String getInitParameter(String name):根据给定参数名获取相应的初始化参数值。

  4. Enumeration<String> getInitParameterNames():获取所有初始化参数的名称的枚举。

总之,ServletConfig 接口提供了一种机制,允许 Servlet 访问它的配置信息和初始化参数。这些信息对于 Servlet 的运行时行为和逻辑可能会非常有用。

5.ServletContext对象

ServletContext 对象是 Java Web 应用程序中的一个接口,它代表了整个 Web 应用程序的上下文环境。每个 Web 应用程序只有一个 ServletContext 实例,由 Servlet 容器在启动应用程序时创建,并在关闭应用程序时销毁。

ServletContext 接口提供了一系列方法,用于访问和操作与当前 Web 应用程序相关的信息和资源,包括:

  1. 获取初始化参数:可以使用 getInitParameter(String name) 方法获取部署描述符(如 web.xml 文件)中配置的初始化参数的值。通过 getInitParameterNames() 方法可以获取所有初始化参数的名称。

  2. 获取上下文路径:可以使用 getContextPath() 方法获取当前 Web 应用程序的上下文路径(Context Path)。上下文路径是 Web 应用程序被部署后的访问路径的一部分。

  3. 获取真实路径:可以使用 getRealPath(String path) 方法将给定的相对路径转换为在文件系统中的真实路径。此方法通常用于获取在 Web 应用程序中的资源的物理路径。

  4. 获取资源:可以使用 getResource(String path)getResourceAsStream(String path) 方法获取位于 Web 应用程序中的某个资源的 URL 或输入流。

  5. 设置和获取属性:可以使用 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 类定义了以下几个主要方法:

  1. void service(HttpServletRequest request, HttpServletResponse response):这是 HttpServlet 的核心方法,用于处理 HTTP 请求和生成 HTTP 响应。在该方法中,可以根据不同的 HTTP 方法(如 GET、POST 等)执行相应的逻辑来处理请求的参数、生成响应内容等。

  2. protected void doGet(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP GET 请求的方法。默认情况下,service() 方法会调用此方法来处理 GET 请求。

  3. protected void doPost(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP POST 请求的方法。默认情况下,service() 方法会调用此方法来处理 POST 请求。

  4. protected void doPut(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP PUT 请求的方法。

  5. protected void doDelete(HttpServletRequest request,HttpServletResponse response):用于处理 HTTP DELETE 请求的方法。

除了上述方法,HttpServlet 还提供了一些其他的方法,如 doOptions() 用于处理 HTTP OPTIONS 请求,doHead() 用于处理 HTTP HEAD 请求等。这些方法可以根据需要进行覆盖,以实现对不同类型的 HTTP 请求的处理

7.中文乱码问题

出现中文乱码问题通常就是编码和解码不一致导致

  1. 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");
  1. 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));
}
  1. 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.请求转发与重定向

二者区别:

一次请求与两次请求!

    1. 定义:请求转发是在服务器内部进行的一种机制,将请求从一个组件(如 Servlet)直接转发给另一个组件。重定向是通过发送特殊的响应状态码和 URL 到客户端浏览器,让浏览器重新发送一个新的请求来达到页面跳转的目的。
    1. 浏览器行为:请求转发是在服务器内部完成的,对浏览器是透明的,浏览器的 URL 不会发生变化。而重定向会向浏览器发送一个新的响应,浏览器会根据响应中的 URL 进行请求的重新发送,因此浏览器的 URL 会发生变化。
    1. 请求次数:请求转发只需要一次请求和响应的往返,所以在网络传输上效率更高。而重定向会导致两次请求和响应的往返,一次是原始请求的响应,一次是重定向后新请求的响应,相对来说会增加一定的网络开销。
    1. 共享数据:请求转发时,可以共享同一个 request 对象,在多个组件之间传递数据。而重定向是两次请求,每个请求都会有一个新的 request 对象,数据不能直接共享,需要使用其他机制(如 URL 参数、Session 等)来传递数据。
    1. 场景应用:请求转发常用于在服务器内部进行组件之间的流转,如多个 Servlet 之间的数据交互,MVC 架构中的控制器转发等。重定向常用于页面的跳转,错误处理,或者需要刷新页面的场景。

1.请求转发

请求转发(Request Forwarding)是一种在服务器端将请求从一个 Servlet 转发给另一个 Servlet 或 JSP 页面的机制。在请求转发中,客户端只发送一次请求,而服务器在内部将请求从一个组件传递到另一个组件,然后将响应返回给客户端。

  1. 在要进行请求转发的 Servlet 中,获得 RequestDispatcher 实例,可以使用以下代码:
go 复制代码
RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet");

其中,/targetServlet 是目标 Servlet 的路径。

  1. 调用 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 处理自己的业务 ");
    }
}
相关推荐
小熊软糖^O^26 分钟前
Hive中查看字段中是否包含某些字符串的函数
数据仓库·hive·hadoop
Yz987632 分钟前
Hive简介 | 体系结构
大数据·linux·数据仓库·hive·hadoop·bigdata
时差95344 分钟前
使用PyCharm连接虚拟机运行spark任务,本地开发:远程提交测试
大数据·服务器·hadoop·python·pycharm·spark
songqq273 小时前
【抽取数据简单方式】spark实现hive中数据抽取到MySQL
hive·mysql·spark·数据抽取
爬山算法5 小时前
Tomcat(6) 什么是Servlet容器?
java·servlet·tomcat
一个散步者的梦6 小时前
shell中执行hive指令以及hive中执行shell和hdfs指令语法
hive·hadoop·hdfs
Mephisto.java6 小时前
【大数据学习 | HBASE】hbase shell基础实操
大数据·hive·sql·oracle·hbase·database
上辈子杀猪这辈子学IT6 小时前
【Hadoop和Hbase集群配置】3台虚拟机、jdk+hadoop+hbase下载和安装、环境配置和集群测试
java·大数据·hadoop·分布式·hbase
小菜日记^_^10 小时前
增删改查基础项目总结
java·数据库·spring boot·后端·spring·servlet·tomcat
dogplays10 小时前
sqoop资源优化记录
hive·hadoop·sqoop