Servlet

1. Servlet

1.1 什么是Servlet

Servlet 是一个小的 Java 程序,但这个程序需要运行在 Web 容器,它用于接收并响应客户端发来的请求,这些请求通常是 HTTP 请求。

我们要实现 Servlet 功能,有三种方式:第一种是实现 javax.serlvet.Servlet 接口;第二种是继承 javax.servlet.GenericServlet 类;第三种是继承 javax.servlet.http.HttpServlet 类。

一个 Servlet 程序有三个生命周期方法:初始化容器方法、处理请求的方法、销毁容器的方法。它们的调用顺序如下:

  • 当客户端发来请求时,会执行初始化方法,这个方法只会执行一次
  • 处理请求并响应
  • 当容器销毁时,会调用Servlet 的销毁方法

1.2 第一个Servlet

1.2.1 创建Web项目

在 IDEA 中创建一个模块或工程,然后填写项目名和类型后,完成工程创建。

1.2.2 添加依赖

在项目的 pom.xml 文件中添加 Servlet 的依赖。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

1.2.3 修改项目为web

在 pom.xml 文件中添加如下代码

<packaging>war</packaging>

然后刷新 Maven 工程,并在 src 下的 main 目录下创建 webapp 目录,用于存放 web 相关的资源。

1.2.4 配置Web容器

我们以 tomcat 为例来进行配置。

1.从tomcat的官网下载tomcat,然后解压。

2.在idea中添加应用服务

File | Settings | Build, Execution, Deployment | Application Servers

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZlKJUC2-1654505083467)(image/image-20220224101721067.png)]

点击 + 号选择 Tomcat Server ,然后找到 tomcat 的安装目录。

3.部署项目到 tomcat 中运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbOpAKWT-1654505083468)(image/image-20220224101837263.png)]

点击上图中的向下箭头,找到 Edit Configuration…, 点击后进入配置界面,找到 Tomcat Servlet 下的 Local,进行项目配置界面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dq2HlTCU-1654505083468)(image/image-20220224101948978.png)]

在右边的 Deployment 标签中去点击 + 号选择 Artifact…,然后选择带有 expload…的war包进行部署。

1.2.5 编写Servlet程序

package com.xianopeng.servelt;

import javax.servlet.*;
import java.io.IOException;

/**
 * @Description 第一个Servlet 程序,去实现 Servlet 接口
 * @Author Jock
 * @Date 2022/2/24
 */
public class FirstServlet implements Servlet {
    // 初始化方法
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("FirstServlet 已经初始化了........");
    }

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

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("接收到了请求");
        res.getWriter().write("hello");
    }

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

    @Override
    public void destroy() {
        System.out.println("容器已经销毁");
    }
}

1.2.6 配置Servlet程序

在项目中创建 web.xml 文件,这个文件的路径应该是在 src/main/webapp/WEB-INF/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 -->
    <servlet>
        <servlet-name>firstServlet</servlet-name>
        <servlet-class>com.xianopeng.servelt.FirstServlet</servlet-class>
        <load-on-startup>3</load-on-startup>
        <init-param>
            <param-name>name</param-name>
            <param-value>zs</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>firstServlet</servlet-name>
        <url-pattern>/first</url-pattern>
    </servlet-mapping>

</web-app>

在 web.xml 文件中,使用 标签来配置一个 Servlet 程序,它里有两个很重要子标签:

  • servlet-name:用于定义 servlet 的名称,它也就是引用名称,或者是实例化的名称,在同一个 web.xml 文件,这个名称必须唯一。一般是类名首字母小写
  • servlet-class:就是 Servlet 类的完整名称(包名 + 类名)
  • load-on-startup:用于指定这个 Servlet 的加载时机,一般在 1 之后,如果希望更早的加载,那么可以定义为1。值越小越先加载。
  • init-param:用于对这个 Servlet 进行参数配置,可以有多个
    • param-name:参数名
    • param-value:参数值
  • servlet-mapping:用于对Servlet 进行映射
    • servlet-name:必须和 servlet 标签中的 servlet-name 标签中配置的名称一致
    • url-pattern:用于配置请求的路径,必须是以 / 线开头

1.2.7 继承 GenericServlet

除了实现 Servlet 接口外,还可以继承 GenericServlet 抽象类来编写Servlet程序

package com.xianopeng.servelt;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * @Description 第二个Servlet程序
 * @Author Jock
 * @Date 2022/2/24
 * 
 */
public class SecondServlet extends GenericServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("ok");
        res.getWriter().write("ok");
    }
}

GenericServlet这个类已经实现 Servlet 接口中大部分的方法,但没有实现 service() 这个核心方法,所以它是一个抽象类

配置:

    <servlet>
        <servlet-name>secondServlet</servlet-name>
        <servlet-class>com.xianopeng.servelt.SecondServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>secondServlet</servlet-name>
        <url-pattern>/second</url-pattern>
    </servlet-mapping>

1.2.8 继承HttpServlet

我们的请求绝大部分都是 HTTP 请求,因此我们在真正开发中使用的是继承 HttpServlet 这个类。这也是我们需要掌握的实现方式。

package com.xianopeng.servelt;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description 第三个Servlet,继承HttpServlet
 * @Author Jock
 * @Date 2022/2/24
 */
public class ThirdServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ok");
        resp.getWriter().write("ok ok");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

配置 Servlet

    <servlet>
        <servlet-name>thirdServlet</servlet-name>
        <servlet-class>com.xianopeng.servelt.ThirdServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>thirdServlet</servlet-name>
        <url-pattern>/third</url-pattern>
    </servlet-mapping>

1.3 使用注解

从 Servlet3.0开始,已经支持注解方式的开发。

package com.xianopeng.servelt;

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;

/**
 * @Description 使用注解
 * @Author Jock
 * @Date 2022/2/24
 */
@WebServlet(name = "fourServlet", value = "/four")
public class FourServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("fourServlet");
    }
}

WebServlet注解的源码:

package javax.servlet.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
    String name() default "";

    String[] value() default {};

    String[] urlPatterns() default {};

    int loadOnStartup() default -1;

    WebInitParam [] initParams() default {};
    
    boolean asyncSupported() default false;
    
    String smallIcon() default "";

    String largeIcon() default "";

    String description() default "";

    String displayName() default "";
}

在这个类中 name 属性对应 web.xml 文件中的 servlet-name 标签,value 和 urlPatterns 对应 servlet-mapping 中的 url-pattern 标签。

2. ServletConfig

这个类的源码为:

package javax.servlet;
import java.util.Enumeration;

 public interface ServletConfig {
    public String getServletName();

    public ServletContext getServletContext();

    public String getInitParameter(String name);

    public Enumeration<String> getInitParameterNames();
}

这个类定义了获取 Servlet 的名称、Servlet 初始化参数和 ServletContext 对象。

使用示例:

package com.xianopeng.servelt;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet(name = "fiveServlet", urlPatterns = "/five",
        initParams = {
            @WebInitParam(name = "driver", value = "com.mysql.jdbc.Driver"),
            @WebInitParam(name = "username", value = "root"),
            @WebInitParam(name = "password", value = "123456")
        })
public class FiveServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取Servlet的名称
        String servletName = this.getServletConfig().getServletName();
        System.out.println("servletName = " + servletName);

        // 获取初始化参数
        String driver = this.getServletConfig().getInitParameter("driver");
        System.out.println("driver = " + driver);
        String username = this.getServletConfig().getInitParameter("username");
        System.out.println("username = " + username);

        // 获取所有的初始化参数名称
        Enumeration<String> names = this.getServletConfig().getInitParameterNames();
        while (names.hasMoreElements()) {
            String key = names.nextElement();
            String val = this.getServletConfig().getInitParameter(key);
            System.out.println(key + " = " + val);
        }

        // 获取servletContext对象
        ServletContext servletContext = this.getServletConfig().getServletContext();
        System.out.println("servletContext = " + servletContext);
    }
}

输出结果为:

servletName = fiveServlet
driver = com.mysql.jdbc.Driver
username = root
password = 123456
driver = com.mysql.jdbc.Driver
username = root
servletContext = org.apache.catalina.core.ApplicationContextFacade@54f59b62

3. ServletContext

这个类也是一个接口,它定义Servlet 运行上下文环境,这个类中的方法如下:

我们用得比较多的就是 getContextPath() 方法。

package com.xianopeng.servelt;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * @Description TODO
 * @Author Jock
 * @Date 2022/2/24
 */
@WebServlet(name = "fiveServlet", urlPatterns = "/five")
public class FiveServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取servletContext对象
        ServletContext servletContext = this.getServletConfig().getServletContext();
        System.out.println("servletContext = " + servletContext);

        // 获取我们的项目名称
        String contextPath = servletContext.getContextPath();
        System.out.println("contextPath = " + contextPath);

        // 获取项目的绝对路径
        String realPath = servletContext.getRealPath("/");
        System.out.println("realPath = " + realPath);

        // 设置全局变量
        servletContext.setAttribute("aaa", "bbbb");
        // 获取全局变量
        Object aaa = servletContext.getAttribute("aaa");
        System.out.println("aaa = " + aaa);

    }
}

运行后输出的结果为:

servletContext = org.apache.catalina.core.ApplicationContextFacade@4c69231a
contextPath = /servlet_first
realPath = D:\Workspace\Idea\JavaWeb\servlet-first\target\servlet-first-1.0-SNAPSHOT\
aaa = bbbb

4. HttpServletRequest

HttpServletRequest 是一个接口,它封装了 HTTP 请求相关的信息,由 Servlet 容器来创建它的实例对象并传入到 service() 方法中。接口中定义的方法如下:

image-20220224114319220

4.1 获取请求参数

为了更好的演示我们的功能,我们再次创建一个 Maven 的 web 模块。

然后添加 servlet 依赖和 tomcat 插件。

pom.xml 文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xianopeng</groupId>
    <artifactId>servlet-demo</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
        </plugins>
    </build>

</project>

4.2 编写HTML页面

我们在 webapp 目录下创建 index.html 页面,在这个页面中我们添加一个表单,用户向 Servlet 请求数据。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<form action="/login" method="post">
    <input type="text" name="account" placeholder="账号"><br>
    <input type="password" name="password" placeholder="密码"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>

4.3 编写登录Servlet

package com.xianopeng.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("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置编码格式
        req.setCharacterEncoding("utf-8");

        // 获取请求参数
        String account = req.getParameter("account");
        System.out.println("account = " + account);

        String password = req.getParameter("password");
        System.out.println("password = " + password);

    }
}

运行项目后,在 index.html 表单输入相应的信息后,就可以在 Servlet 程序中获取到。

4.4 常用方法介绍

package com.xianopeng.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 javax.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置编码格式
        req.setCharacterEncoding("utf-8");

        // 获取请求参数
        String account = req.getParameter("account");
        System.out.println("account = " + account);

        String password = req.getParameter("password");
        System.out.println("password = " + password);

        // HttpServletRequest 常用方法介绍
        // 1. 获取请求的方式
        String method = req.getMethod();
        System.out.println("method = " + method);

        // 2. 获取指定的请求头
        String header = req.getHeader("Content-Type");
        System.out.println("header = " + header);

        // 3. 获取Session 对象
        HttpSession session = req.getSession();
        System.out.println("session = " + session);

        // 4. 设置属性
        req.setAttribute("name", account);

        // 5. 获取属性
        Object name = req.getAttribute("name");
        System.out.println("name = " + name);

    }
}

运行后结果为:

account = 西安
password = 123456
method = POST
header = application/x-www-form-urlencoded
session = org.apache.catalina.session.StandardSessionFacade@54f818f1
name = 西安

4.5 转发

在 HttpServletRequest 对象有一个实现转发的方法。为了演示转发功能,我们编写两个 Servlet 程序。

1)FromServlet.java

package com.xianopeng.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("/from")
public class FromServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 向 HttpServletRequest 对象中存入一个值
        req.setAttribute("name", "zhang san");

        // 转发到 ToServlet 中
        req.getRequestDispatcher("/to").forward(req, resp);
    }
}

2)ToServlet.java

package com.xianopeng.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("/to")
public class ToServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取 HttpServletRequest 对象中的 name 属性值
        String name = (String) req.getAttribute("name");
        System.out.println("name = " + name);
    }
}

我们运行服务,然后在浏览器地址栏中输入 /from 来查看效果。

从运行的结果可以发现,在控制台中输出了 zhang san,说明请求已经从 from 转发到了 to。

4.6 重定向

要实现重定向功能,需要使用 HttpServletResponse 对象中的 sendRedirect(String local) 方法。

修改 FromServlet.java 类中页面跳转方式。

package com.xianopeng.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("/from")
public class FromServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 向 HttpServletRequest 对象中存入一个值
        req.setAttribute("name", "zhang san");

        // 转发到 ToServlet 中
        // req.getRequestDispatcher("/to").forward(req, resp);

        // 重定向
        resp.sendRedirect(req.getContextPath() + "/to");
    }
}

而 ToServlet.java 代码无需修改。

程序运行后的结果发现在 ToServlet 中不能成功获取到 name 属性的值。

4.7 转发和重定向的区别

1.转发的方法是 HttpServletRequest 对象中的方法,而重定向是 HttpServletReponse 对象中的方法。

2.转发发送一次请求,而重定向会发出多次请求。

3.转发浏览器地址栏不会发生变化,而重定向浏览器地址栏会发生变化。

4.在一个转发链中可以使用 HttpServletRequest 对象中的属性,而重定向不能使用 HttpServletRequest 对象中的属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值