第一章:Web资源

1.1 概述

  • Web资源就是运行在服务器上的资源,它一共可以分为两类:静态资源和动态资源。

1.2 静态资源

  • 静态资源就是web页面中供人们浏览的数据始终是不变的,如:HTML、CSS、JS、图片、音视频等。

1.3 动态资源

  • 动态资源就是Web页面中供人们浏览的数据是由程序产生的,不同的用户或者不同时间点访问Web页面看到的内容是各不相同的,如:Servlet、JSP、Freemarker、Velocity、Thymeleaf等。

第二章:Servlet的入门

2.1 Servlet的概念

2.1.1 什么是Servlet?

  • Servlet是运行在服务器端(tomcat)的Java小程序,是SUN公司提供的定义动态资源的规范;从代码层面来讲Servlet就是一个接口。

2.1.2 Servlet的作用

  • 用来接收、处理客户端的请求、响应给浏览器动态的资源。在整个web应用中,Servlet主要负责处理请求、协调调度的功能。我们可以将Servlet称为Web应用中的控制器

  • 示例:

  • 要实现的效果:

Servlet的作用实现效果.png

  • 使用Servlet实现的具体细节:

Servlet的作用实现效果的具体细节.png

2.2 Servlet的入门

2.2.1 目标

  • 在页面上点击超链接,由Servlet处理这个请求,并返回一个响应字符串:Hello,I am Servlet

2.2.2 思路

Servlet入门的思路.jpg

2.2.3 实现步骤

  • ① 使用IDEA创建动态的web模块:略。
  • ② 新建index.html:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <a href="/app/helloServlet">HelloServlet</a>
  9. </body>
  10. </html>
  • ③ 新建HelloServlet.java:
package com.example.javaweb;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.*;

public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse)
        throws ServletException, IOException {
        // 控制台打印,证明这个方法被调用了
        System.out.println("我是HelloServlet,我执行了");

        // 获取能够返回响应数据的字符流对象
        PrintWriter writer = servletResponse.getWriter();
        // 向字符流对象写入数据
        writer.write("Hello,I am Servlet");
    }

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

    @Override
    public void destroy() {

    }
}
  • ④ 在/WEB-INF/web.xml中配置HelloServlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         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名字,需要和servlet-mapping标签中的servlet-name保持一致 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 配置Servlet的全类名 -->
        <servlet-class>com.example.javaweb.HelloServlet</servlet-class>
    </servlet>
    <!-- 将Servlet和访问地址关联起来 -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <!--
            映射路径,Servlet并不是文件系统中实际存在的目录或文件,为了方便浏览器访问,我们创建了映射路径来访问它。
        -->
        <url-pattern>/helloServlet</url-pattern>
    </servlet-mapping>

</web-app>
  • ⑤ 配置应用上下文(applicationContext):

Servlet入门案例之配置应用上下文.png

Servlet的入门案例.jpg

2.3 概念梳理

  • 原生Tomcat:安装在电脑上的实实在在的Tomcat软件。
  • IDEA中的Tomcat实例:通过IDEA的配置在IDEA上集成的Tomcat实例,其实还是使用的原生的Tomcat。
  • IDEA中的Web工程:程序员使用IDEA编写的动态Web工程,该工程只是用于程序员编码,实际上部署运行在Tomcat服务器中的并不是这个工程。
  • 根据Web工程生成的war包:根据程序员创建的动态的Web工程,IDEA会将其打包成一个war包,与此同时,真正部署运行在Tomcat服务器中的其实就是这个war包。
  • 访问静态资源的地址/应用上下文/静态资源本身的路径
  • 访问动态资源的地址/应用上下文/映射路径
  • 应用上下文:应用上下文不是IDEA中的工程或模块的名称。

应用上下文.png

第三章:Servlet的生命周期

3.1 概述

  • Servlet的生命周期就是Servlet从创建到销毁的整个过程,我们需要探讨的是Servlet对象在什么时候创建出来以及什么时候被销毁。
  • 默认情况下,在第一次请求访问该Servlet实例的时候才会创建该Servlet实例对象。
  • 在服务器关闭的时候,或者当前项目从服务器中移除的时候会销毁当前项目中的所有Servlet对象。

3.2 Servlet的生命周期方法

  • Servlet的生命周期方法:在Servlet的生命周期中必然会经历的方法,总共包含3个方法:init()、service()和destroy()。

  • init()方法:该方法会在Servlet实例对象被创建之后执行,我们可以在该方法中获取当前Servlet的初始化参数以及进行一些读取配置文件之类的操作。

  • service()方法:该方法会在Servlet实例对象每次接收到请求的时候执行,我们可以在该方法中接收、处理请求以及将客户端需要的数据响应给客户端。
  • destroy()方法:该方法会在Servlet实例对象销毁之前执行,我们可以在该方法中做一些资源回收、释放、关闭等操作。

3.3 配置Servlet提前创建

  • 有的时候我们希望Servlet创建的时候做一些资源加载等耗时工作,如果Servlet在第一次接收请求的时候才创建的话,必然会影响用户的访问速度,所以此时我们需要让Servlet提前创建,将Servlet的创建提前到服务器启动的时候。
  • 通过修改web.xml中的Servlet的配置可以实现:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         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名字,需要和servlet-mapping标签中的servlet-name保持一致 -->
        <servlet-name>HelloServlet</servlet-name>
        <!-- 配置Servlet的全类名 -->
        <servlet-class>com.example.javaweb.HelloServlet</servlet-class>
        <!-- 配置Servlet启动顺序 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- 将Servlet和访问地址关联起来 -->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <!--
            映射路径,Servlet并不是文件系统中实际存在的目录或文件,为了方便浏览器访问,我们创建了映射路径来访问它。
        -->
        <url-pattern>/helloServlet</url-pattern>
    </servlet-mapping>

</web-app>

第四章:ServletConfig

4.1 ServletConfig接口的源码

  • 源码:
package javax.servlet;

import java.util.Enumeration;

public interface ServletConfig {
    String getServletName();

    ServletContext getServletContext();

    String getInitParameter(String var1);

    Enumeration<String> getInitParameterNames();
}

4.2 方法

  • 获取<servlet-name>HelloServlet</servlet-name>定义的Servlet名称:
String getServletName();
  • 获取ServletContext对象:
ServletContext getServletContext();
  • 获取配置Servlet设置的初始化参数,根据名字获取值:
String getInitParameter(String var1);
  • 获取所有的初始化参数组成的Enumeration对象:
Enumeration<String> getInitParameterNames();

4.3 应用示例

  • 示例:获取Servlet的初始化参数
  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         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-name>HelloServlet</servlet-name>
        <servlet-class>com.example.javaweb.HelloServlet</servlet-class>
        <!-- 初始化参数 -->
        <init-param>
            <param-name>username</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>123456</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/helloServlet</url-pattern>
    </servlet-mapping>

</web-app>
  • HelloServlet.java
package com.example.javaweb;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.*;

public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        Enumeration<String> names = servletConfig.getInitParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            String initParameter = servletConfig.getInitParameter(name);
            System.out.println("param-name = " + name + ",param-value = " + initParameter);
        }
    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse)
        throws ServletException, IOException {
        // 控制台打印,证明这个方法被调用了
        System.out.println("我是HelloServlet,我执行了");

        // 获取能够返回响应数据的字符流对象
        PrintWriter writer = servletResponse.getWriter();
        // 向字符流对象写入数据
        writer.write("Hello,I am Servlet");
    }

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

    @Override
    public void destroy() {

    }
}

第五章:Servlet的体系结构

5.1 类型关系

Servlet的类型关系.png

  • Servlet接口有一个实现类GenericServlet,而GenericServlet有一个子类是HttpServlet,我们创建Servlet的时候会选择继承HttpServlet,因为它相当于实现了Servlet接口,并且也对一些方法做了默认实现,而且子类的功能要比父类更为强大。

5.2 方法关系

Servlet的方法关系.png

  • 我们编写的Servlet类继承HttpServlet的时候,只需要重写doGet()和doPost()方法即可,因为HttpServlet重写了service()方法,在service()方法中判断了请求方式,根据不同的请求方式执行doXxx()方法。

5.3 应用示例

  • 示例:
  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         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-name>DemoServlet</servlet-name>
        <servlet-class>com.example.javaweb.DemoServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DemoServlet</servlet-name>
        <url-pattern>/demoServlet</url-pattern>
    </servlet-mapping>

</web-app>
  • DemoServlet.java
package com.example.javaweb;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        PrintWriter writer = response.getWriter();
        writer.write("Hello DemoServlet");
    }

}

第六章:Servlet的映射路径配置

6.1 映射路径的作用

  • Servlet的映射路径就是告诉别人访问Servlet的路径。如:Servlet的映射路径是/hello,那么在浏览器上访问该Servlet的路径是http://localhost:8080/项目部署名/hello

注意:一个Servlet可以配置多个映射路径,但是多个Servlet不能配置相同的映射路径。

6.2 映射路径的分类

  • ① 完全路径匹配:
    • 访问当前Servlet的路径要和配置的映射路径完全一致。
    • 如:Servlet配置的映射路径是/hello,那么访问该Servlet的时候的访问路径必须是http://localhost:8080/项目部署名/hello
  • ② 目录匹配:
    • /开头,以*结束。
    • 如:Servlet配置的映射路径是/demo/*,那么访问该Servlet的时候的访问路径必须是http://localhost:8080/项目部署名/demo/任意字符串http://localhost:8080/项目部署名/demo/b)。
  • ③ 扩展名匹配:
    • *开头,以.扩展名结尾。
    • 如:Servlet配置的映射路径是*.action,那么访问该Servlet的时候的访问路径必须是http://localhost:8080/项目部署名/任意字符串.actionhttp://localhost:8080/项目部署名/a.action)。

第七章:动态Web工程内编写路径

7.1 为什么要写路径?

  • ① 整个系统需要根据功能拆分成许许多多的独立的资源。
  • ② 资源之间既要完成自己的功能又需要和其他资源配合。
  • ③ 写路径就是为了从一个资源跳转到另一个资源。

7.2 URL

  • URL是Uniform Resource Locater的缩写,中文翻译为统一资源定位符,它是某个互联网上资源的唯一访问地址,客户端可以通过URL访问到具体的互联网资源。
  • URL的组成:

URL的组成.png

  • URL的使用场景:客户端访问服务器的资源或者一个服务器中要访问另外一台服务器上的资源都需要通过URL访问。

7.3 URI

  • URI是Uniform Resource identifier的缩写,中文翻译为同一资源标识符,它是服务器上某个资源的唯一标识,通过URI可以实现同一项目中某个资源访问另外一个资源。
  • URI的组成:/项目部署名/资源路径

URI的组成.png

  • URI的使用场景:在同一个项目中某个资源访问该项目中的另一个资源。

7.4 相对路径

  • 相对路径:相对路径是不以/开头的路径,编写相对路径的原则是以目标资源的uri路径相当于当前资源的uri路径,其中../表示当前目录,../表示上级目录。
  • A资源的uri的路径是:/app/pages/a.html,B资源的uri的路径是:/app/static/vue.js,那么要实现在A资源中访问B资源的相对路径是../static/vue.js

相对路径.png

7.5 绝对路径

  • 绝对路径是以/开头的路径写法,编写绝对路径的原则是通过目标资源的uri访问目标资源,但是特殊情况是请求转发,如果是请求转发访问目标资源的话,那么绝对路径是在uri的基础之上省略/项目部署名
  • A资源的uri的路径是:/app/pages/a.html,B资源的uri的路径是:/app/static/vue.js,那么要实现在A资源中访问B资源的绝对路径是/app/static/vue.js

7.6 动态获取上下文路径

  • 上下文路径(contextPath)就是/部署项目名
  • 在Servlet的HttpServletRequest中有如下的方法动态获取上下文路径:
 String getContextPath();
  • 示例:
package com.example.javaweb;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        this.doPost(request, response);
    }

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

        String path = request.getContextPath() + "/static/vue.js";

        response.sendRedirect(path);
    }
}

第八章:ServletContext

8.1 概述

  • Tomcat服务器会为其部署的每一个应用都创建一个ServletContext对象,ServletContext对象是属于整个项目的,该项目中的所有Servlet都可以共享同一个ServletContext对象。

8.2 获取ServletContext对象

  • ① 调用Servlet自身的getServletContext()方法获取(不怎么用):
public ServletContext getServletContext() {}
  • ② 调用ServletConfig接口的getServletContext()方法获取(不怎么用):
ServletContext getServletContext();
  • ③ 调用HttpServletRequest接口的getServletContext()方法获取:
ServletContext getServletContext();
  • 示例:
package com.example.javaweb;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value = "DemoServlet", urlPatterns = "/demoServlet")
public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 获取ServletContext对象
        ServletContext servletContext = request.getServletContext();
        System.out.println("servletContext = " + servletContext);
    }

}

8.3 ServletContext的应用场景

8.3.1 获取全局初始化参数

  • 示例:
  • 在web.xml中配置全局初始化参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>username</param-name>
        <param-value>root</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>

    <servlet>
        <servlet-name>DemoServlet</servlet-name>
        <servlet-class>com.example.javaweb.DemoServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>DemoServlet</servlet-name>
        <url-pattern>/demoServlet</url-pattern>
    </servlet-mapping>

</web-app>
  • DemoServlet.java
package com.example.javaweb;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        this.doPost(request, response);
    }

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

        ServletContext servletContext = request.getServletContext();
        Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            String paramName = initParameterNames.nextElement();
            String paramValue = servletContext.getInitParameter(paramName);
            System.out.println("paramName = " + paramName + ",paramValue = " + paramValue);
        }

    }
}

8.3.2 ServletContext作为全局的域对象

  • 域对象就是在一定的作用域范围内进行数据共享的对象,ServletContext作为全局域对象可以在整个项目的所有动态资源(包含所有Servlet)中进行数据共享。
  • 向全局域对象中存入数据:
public void setAttribute(String name, Object object);
  • 从全局域对象中获取数据:
public Object getAttribute(String name);
  • 从全局域对象中删除数据:
public void removeAttribute(String name);
  • 获取全局域对象中存储数据的key:
public Enumeration<String> getAttributeNames();
  • 示例:
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/helloServlet">HelloServlet</a>
</body>
</html>
  • HelloServlet.java
package com.example.javaweb;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "HelloServlet", value = "/helloServlet")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        // 向ServletContext域对象中存储值
        ServletContext servletContext = request.getServletContext();
        servletContext.setAttribute("name", "许大仙");
        // 转发
        request.getRequestDispatcher("/demoServlet").forward(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        this.doGet(request, response);
    }
}
  • DemoServlet.java
package com.example.javaweb;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value = "/demoServlet")
public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        this.doPost(request, response);
    }

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

        ServletContext servletContext = request.getServletContext();
        // 从ServletContext域对象中获取值
        Object name = servletContext.getAttribute("name");
        System.out.println("name = " + name);

    }
}

8.3.3 获取资源的真实路径

  • 例如我们的目标是需要获取项目中某个静态资源的路径,不是工程目录中的路径,而是部署目录中的路径;我们如果直接拷贝其在我们电脑中的完整路径的话其实是有问题的,因为如果该项目以后部署到公司服务器上的话,路径肯定是会发生改变的,所以我们需要使用代码动态获取资源的真实路径。
  • 只要使用了ServletContext动态获取资源的真实路径,那么无论项目的部署路径发生什么变化,都会动态获取项目运行时候的实际路径,所以就不会发生由于写死真实路径而导致项目部署位置改变引发的路径错误问题。
  • 获取资源的真实路径:
String realPath = servletContext.getRealPath("资源在web目录中的路径");
  • 示例:
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/app/demoServlet">HelloServlet</a>
</body>
</html>
  • DemoServlet.java
package com.example.javaweb;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(value = "/demoServlet")
public class DemoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

        this.doPost(request, response);
    }

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

        String realPath = request.getServletContext().getRealPath("/index.html");
        System.out.println("realPath = " + realPath);

    }
}