JavaWeb中的Servlet

哔哩哔哩视频

文章目录

一、什么是Servlet

servlet的基本概念

1、Servlet是JavaEE的规范之一,规范就是接口
2、Servlet是JavaWeb三大组件之一,三大组件分别是:Servlet程序、Filter过滤器、Listener监听器
3、Servlet是运行在服务器上的一个Java小程序,它可以接收客户端发送的请求,并响应数据给客户端

二、实现Servlet程序

1、编写一个类实现Servlet接口
2、实现Service方法,处理请求,并相应数据
3、到web.xml中去配置servlet程序的访问地址

1、第一个servlet程序

(1)创建HelloServlet类并实现接口Servlet

// 实现Servlet接口,并实现其方法
public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * service方法是专门用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet被访问了!");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

(2)web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!--  servlet标签给Tomcat配置Servlet程序  -->
    <servlet>
        <!-- servlet-name标签 : Servlet程序的别名,一般是servlet类的类名 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- servlet-class标签 : servlet程序的全类名 -->
        <servlet-class>pdsu.edu.wbb.HelloServlet</servlet-class>
    </servlet>
    <!-- servlet-mapping标签 : 给servlet程序配置访问地址 -->
    <servlet-mapping>
        <!-- servlet-name标签 : 告诉服务器当前配置的地址是给那个Servlet程序用的,和servlet标签中的servlet-name的值相同 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- url-pattern标签 : 配置访问地址,在定义 -->
        <url-pattern>/hello</url-pattern>
        <!--
            这里的‘/hello’中,'/'在服务器解析时表示地址为:http://ip:port/工程路径
                            /hello 表示地址为:http://ip:port/工程路径/hello
        -->
    </servlet-mapping>
</web-app>

我们启动并运行项目后,会自动访问index.jsp页面,我们只需要在地址栏中填写 hello 即可访问我们所创建的servlet程序,并在控制台输出相应的提示信息。

此时为index.jsp页面,我们在地址栏输入hello并访问,可以看到控制台输出的信息
在这里插入图片描述
在这里插入图片描述

2、url地址如何定位到servlet程序并访问的?

例如:http://localhost:8080/javaweb_servlet_war_exploded/hello 是我们要访问的一个地址

http://                                                      表示http协议
:localhost                                                服务器ip
:8080                                                        端口号
/javaweb_servlet_war_exploded              工程路径
/hello                                                        资源路径

其中,ip地址是唯一的,8080端口号确定了tomcat服务器,通过工程路径确定访问哪个工程,最后再根据资源路径,访问到web.xml文件,通过web.xml文件找到对应的Servlet类并执行程序

3、Servlet的生命周期

1、执行Servlet构造器方法
2、执行init初始化方法
3、执行service方法
4、执行destroy销毁方法

我们在HelloServlet类中分别在各方法中写入一句话并访问Servlet程序,看控制台输出的内容判断Servlet的生命周期

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;
    }

    /**
     * service方法是专门用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3、service方法");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("4、destroy销毁方法");
    }
}

在这里插入图片描述
在这里插入图片描述

4、Servlet的请求分发处理

(1)通过继承HttpServlet实现Servlet程序

1、编写一个类去继承HttpServlet类
2、根据业务需要重写doGet或doPost方法
3、到web.xml文件中配置Servlet程序的访问地址

(2)代码实现Servlet的请求分发处理

1、创建一个类继承HttpServlet,并实现doGet和doPost方法
public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet方法");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost方法");
    }
}
2、配置web.xml文件
<servlet>
    <servlet-name>HelloServlet2</servlet-name>
    <servlet-class>pdsu.edu.wbb.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>HelloServlet2</servlet-name>
    <url-pattern>/hello2</url-pattern>
</servlet-mapping>
3、写一个jsp页面用于发送post/get请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="hello2" method="post">
    <input type="submit" value="访问">
  </form>
  </body>
</html>

执行程序
当index.jsp中的form表单的method为post时,点击访问按钮,控制台输出 doPost方法

当index.jsp中的form表单的method为get时,点击访问按钮,控制台输出 doGet方法
在这里插入图片描述
在这里插入图片描述

三、Servlet类的继承体系

在这里插入图片描述

(1)ServletConfig类

ServletConfig类的三大作用

1、获取Servlet程序的别名servlet-name的值
2、获取初始化参数init-param
3、获取ServletContext对象

1、在init()方法中使用servletConfig参数调用
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("HelloServlet程序的别名 : " + servletConfig.getServletName());
    System.out.println("初始化参数username的值 : " + servletConfig.getInitParameter("username"));
    System.out.println("初始化参数password的值 : " + servletConfig.getInitParameter("password"));
    System.out.println("ServletContext对象 : " + servletConfig.getServletContext());
}
2、在web.xml文件中配置init-param

在这里插入图片描述

3、访问Servlet程序,控制台输出

在这里插入图片描述

注意:当我们重写init方法时,需要调用父类的super.init(config)操作

在这里插入图片描述

(2)ServletContext类

1、什么是ServletContext?

1、ServletContext 是一个接口,它表示 Servlet 上下文对象
2、一个 web 工程,只有一个ServletContext 对象实例。
3、ServletContext 对象是一个域对象。
4、ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。

2、什么是域对象?

域对象,是可以像 Map 一样存取数据的对象,叫域对象。这里的域指的是存取数据的操作范围,整个 web 工程。

存数据取数据删除数据
Mapput()get()remove()
域对象setAttribute()getAttribute()removeAttribute()

3、ServletContext类的四个作用

1、获取 web.xml 中配置的上下文参数 context-param
2、获取当前的工程路径,格式: /工程路径
3、获取工程部署后在服务器硬盘上的绝对路径
4、像 Map 一样存取数据

(1)创建ContextServlet类并继承HttpServlet类
public class ContextServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1、获取 web.xml 中配置的上下文参数 context-param
        ServletContext servletContext = getServletConfig().getServletContext();
        String username = servletContext.getInitParameter("username");
        System.out.println(username);
//        2、获取当前的工程路径,格式: /工程路径
        System.out.println("当前工程路径: " + servletContext.getContextPath());
//        3、获取工程部署后在服务器硬盘上的绝对路径
        // 这里的 / 被服务器解析为:http://ip:port/工程名/
        System.out.println("工程部署的绝对路径 : " + servletContext.getRealPath("/"));
    }

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

    }
}
(2)配置web.xml文件
<servlet>
    <servlet-name>ContextServlet</servlet-name>
    <servlet-class>pdsu.edu.wbb.ContextServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ContextServlet</servlet-name>
    <url-pattern>/context</url-pattern>
</servlet-mapping>
<!-- context-param是上下文参数,它属于整个web工程,可配置多组 -->
<context-param>
    <param-name>username</param-name>
    <param-value>zhangsan</param-value>
</context-param>
(3)访问Servlet程序

在这里插入图片描述

(4)向ServletContext作用域中存放数据并取出数据
public class ContextServlet2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        servletContext.setAttribute("key1","value");

        System.out.println("从 servletContext作用域中获取数据key1的值 : " + servletContext.getAttribute("key1"));
    }
}

web.xml文件

<servlet>
    <servlet-name>ContextServlet2</servlet-name>
    <servlet-class>pdsu.edu.wbb.ContextServlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ContextServlet2</servlet-name>
    <url-pattern>/context2</url-pattern>
</servlet-mapping>

在这里插入图片描述

四、HttpServletRequest类

1、HttpServletRequest类的作用

每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法(doGet和doPost)进行使用。我们可以通过HttpServletRequest对象获取到所有请求的信息。

2、HttpServletRequest常用方法

方法作用
getRequestURI()获取请求的资源路径
getRequestURL()获取请求的统一资源定位符(绝对路径)
getRemoteHost()获取客户端的 ip 地址
getHeader()获取请求头
getParameter()获取请求的参数
getParameterValues()获取请求的参数(多个值的时候使用)
getMethod()获取请求的方式 GET 或 POST
setAttribute(key, value)设置域数据
getAttribute(key)获取域数据
getRequestDispatcher()获取请求转发对象

(1)创建RequestServlet类

获取请求的资源路径
获取请求的统一资源定位符(绝对路径)
获取客户端的ip地址
获取请求头
获取请求方发GET或POST

public class RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求的资源路径
        System.out.println("URI : " + req.getRequestURI());
        // 获取请求的统一资源定位符(绝对路径)
        System.out.println("URL : " + req.getRequestURL());
        // 获取客户端的ip地址
        System.out.println("IP地址 : " + req.getRemoteHost());
        // 获取请求头
        System.out.println("请求头User-Agent : " + req.getHeader("User-Agent"));
        // 获取请求方发GET或POST
        System.out.println("请求方法 : " + req.getMethod());
    }
}

(2)配置web.xml文件

<servlet>
    <servlet-name>RequestServlet</servlet-name>
    <servlet-class>request.RequestServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>RequestServlet</servlet-name>
    <url-pattern>/requestServlet</url-pattern>
</servlet-mapping>

(3)访问servlet程序,查看控制台的执行结果

在这里插入图片描述
到浏览器中查看请求头中的User-Agent信息
在这里插入图片描述

(5)创建ParamServlet类

获取请求的参数
获取请求的参数(多个值的时候使用)

public class ParamServlet 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);
        System.out.println("密码: " + password);
        System.out.println("兴趣爱好: " + Arrays.asList(hobbies));
    }
}

(6)配置web.xml文件

<servlet>
    <servlet-name>ParamServlet</servlet-name>
    <servlet-class>request.ParamServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ParamServlet</servlet-name>
    <url-pattern>/paramServlet</url-pattern>
</servlet-mapping>

(7)index.jspu页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="paramServlet" 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="C">C
    <input type="submit" value="访问">
  </form>
  </body>
</html>

代码执行的结果,获取到了index.jsp页面发送的内容
在这里插入图片描述

(3)解决Post请求的乱码问题

1、使用post请求获取页面的请求信息会出现中文乱码

当我们使用post请求让doPost方法接收请求参数时,发现中文会出现乱码,get请求和doGet方法却不会

@Override
protected void doPost(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);
    System.out.println("密码: " + password);
    System.out.println("兴趣爱好: " + Arrays.asList(hobbies));
}

在这里插入图片描述
在这里插入图片描述

2、解决post请求乱码

我们只需要在doPost方法的第一行加上req.setCharacterEncoding("utf-8") ,用于设置请求信息的字符集编码即可

// 设置请求信息的字符集编码
req.setCharacterEncoding("utf-8");

在这里插入图片描述

(4)请求转发

1、什么是请求转发

请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发
在这里插入图片描述

2、用代码创建例子进行说明

1、从客户端传入一个request参数,先到Servlet1并在其中向request作用域中存入数据
2、使用请求转发到Servlet2中,检查传到的数据是否有在Servlet1中存放数据

(1)Servlet1类
public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求的参数(办事的材料)查看
        String username = req.getParameter("username");
        System.out.println("在 Servlet1(柜台 1)中查看参数(材料):" + username);
        // 给材料 盖一个章,并传递到 Servlet2(柜台 2)去查看
        req.setAttribute("key1", "柜台 1 的章");
        // 问路:Servlet2(柜台 2)怎么走
        /**
         * 请求转发必须要以斜杠打头,/ 斜杠表示地址为:http://ip:port/工程名/ , 映射到 IDEA 代码的 web 目录
         */
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet2");
        // 走向 Servlet2(柜台 2)
        requestDispatcher.forward(req, resp);
    }
}
(2)Servlet2类
public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(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 处理自己的业务 ");
    }
}
(3)web.xml配置文件
<servlet>
    <servlet-name>Servlet1</servlet-name>
    <servlet-class>request.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Servlet1</servlet-name>
    <url-pattern>/servlet1</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>Servlet2</servlet-name>
    <servlet-class>request.Servlet2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Servlet2</servlet-name>
    <url-pattern>/servlet2</url-pattern>
</servlet-mapping>

我们在浏览器的地址栏中写入 servlet1?username=zhangsan 可以看到编译器的控制台上输出了servlet1和servlet2的内容,说明servlet1和servlet2都被访问了, 地址栏中的地址却始终是servlet1,且request作用域中的数据可以在Servlet2被访问,可以得出客户端向服务器出只发送了一次请求
在这里插入图片描述

3、请求转发的特点

(1)浏览器地址栏没有发生变化可以得出请求转发发送一次请求
(2)他们可以共享到request作用域中的数据
(3)请求转发可以访问到WEB-INF目录下的资源,但不能访问到工程以外的资源

五、HttpServletResponse 类

(1)HttpServletResponse类的作用

HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,
我们如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

(2)HttpServletResponse中的两个输出流的说明

字符流getWriter()常用于回传字符串
字节流getOutputStream()常用于下载(传递二进制数据)

注意:两个流不能一起使用,否则会报错

(3)创建ResponseServlet类

1、在类中创建了两个输出流

public class ResponseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletOutputStream outputStream = resp.getOutputStream();
        PrintWriter writer = resp.getWriter();
    }
}

2、配置web.xml文件

<servlet>
    <servlet-name>ResponseServlet</servlet-name>
    <servlet-class>response.ResponseServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ResponseServlet</servlet-name>
    <url-pattern>/responseServlet</url-pattern>
</servlet-mapping>

3、测试结果

浏览器访问servlet,报错信息 getOutputStream() has already been called for this response 意为 已为此响应调用getOutputStream()
在这里插入图片描述

当将两行代码交换位置时 getWriter() has already been called for this response 意为 已为此响应调用getWriter()

PrintWriter writer = resp.getWriter();
ServletOutputStream outputStream = resp.getOutputStream();

在这里插入图片描述

(4)向客户端回传数据

利用输出流向客户端回传数据,getWriter()

public class ResponseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
//        writer.println("responseServlet ......");
        writer.write("responseServlet ......");
    }
}

在这里插入图片描述
但传输中文数据时,客户端数据出现乱码

writer.write("客户端回传的数据");

在这里插入图片描述

(5)解决响应的乱码问题

我们现获取到服务器的字符集编码,发现是ISO-8859-1,这个字符集编码是不支持中文的,所以我们需要手动设置字符集编码。
在这里插入图片描述
当我们设置了服务器的字符集编码为utf-8后,发现浏览器上的数据还是乱码,这是因为,客户端可服务器端的编码方式不一样
在这里插入图片描述
浏览器当前的字符集编码格式,当然我们可以通过修改浏览器的字符集编码的方式来解决乱码(但是这显然很不明智,这步是需要用户去操作的,所以我们应该通过程序去修改客户端的字符集编码)在这里插入图片描述
设置客户端的字符集编码

// 通过响应头,设置浏览器的字符集编码
resp.setHeader("Content-Type","text/html;charset=utf-8");

在这里插入图片描述
更简单的方式,同时设置客户端和服务器的字符集编码

// 同时设置客户端、服务器和响应头的字符集编码
resp.setContentType("text/html;charset=utf-8");

在这里插入图片描述

注意:该设置字符集编码的方法需要在获取流对象之前设置,否则不会生效

(6)请求重定向

1、请求重定向的概念

请求重定向是指客户端给服务器发送请求,但是服务器由于某些原因不能被访问,但它能给客户端提供一个新的地址去访问。
在这里插入图片描述

2、代码举例演示

(1)Response1类
public class Response1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("response1被访问");

        req.setAttribute("key","value");
        // 请求重定向
        resp.sendRedirect("response2");
    }
}
(2)Response2类
public class Response2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getAttribute("key"));
        System.out.println("response2被访问");
    }
}
(3)web.xml配置文件
<servlet>
    <servlet-name>Response1</servlet-name>
    <servlet-class>response.Response1</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Response1</servlet-name>
    <url-pattern>/response1</url-pattern>
</servlet-mapping>

<servlet>
    <servlet-name>Response2</servlet-name>
    <servlet-class>response.Response2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Response2</servlet-name>
    <url-pattern>/response2</url-pattern>
</servlet-mapping>

在客户端浏览器地址栏中访问response1后,地址栏中地址自动跳转到response2,并且在控制台输出了Response1中的信息。从浏览器可以看到两次的请求信息,第一次的请求状态码是302,表示重定向,第二次200表示请求成功,所以在Response1中保存到request作用域中的数据在Request2中访问不到。
在这里插入图片描述
在这里插入图片描述

3、请求重定向的特点

(1)浏览器地址栏会发生变化,是因为客户端向服务器发送了两次请求
(2)因为客户端向浏览器发送了两次请求,所以request作用域中的数据不共享
(3)不能访问WEB-INF下的资源,但是可以访问工程外的资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值