Java Web

  • Java web 是指所有通过 java 语言开发并可以同过浏览器访问的程序的总称,叫 Java Web。
  • Java Web 是基于请求和响应来开发的。
  • 请求和响应成对出现。

Web 资源的分类:按实现技术和呈现效果

  • 静态: html, css, js, txt, mp4。
  • 动态: JSP Page, Servlet 程序, PHP, Asp。

常见服务器

  • Tomcat Apache
  • Jboss
  • GlassFish
  • Resin
  • WebLogic

安装

  • 解压即可

Tomcat 服务器目录解绍

  • bin 可执行文件
  • conf 配置文件
  • lib 服务器的 jar 包
  • logs 运行时输出的日志信息
  • temp 存储临时数据
  • webapps 存放部署的web工程
  • work 工作目录,存放jsp 运行时jsp 翻译为 Servlet 的源码和 Session 钝化的目录。

默认端口

  • MySQL 默认端口 3306
  • Tomcat 默认端口 8080

部署 web 工程到 tomcat

  • 第一种方法:把工程放到 ”webapps/工程名字“ 目录下。
  • 第二种方法: conf 目录下写配置文件。/etc/tomcat9/Catalina/localhost/
<!-- Context 表示一个工程上下文
     path    访问路径
     docBase 工作目录的位置
-->
<Context path="/web01" docBase="/home/larry/"/>

ROOT 工程的访问以及 默认 index.html 页面的访问

  • 访问ROOT目录下的工程,不需要带工程名。–> ROOT/index.html

工程目录结构

  • src 存放自己编写的 java 源代码。
  • web 用来存放 web 工程的资源文件,比如 html page, css, js file。
    • WEB-INF 是一个受服务器保护的目录,浏览器无法直接访问到此目录的内容。
      • web.xml 它是整个动态 web 工程的配置部署描述文件,可以在这里配置 web 工程的组件:如 Servlet 程序,Filter 过滤器,Listener 监听器,Session 超时。
      • lib 存放第三方的 jar 包,(idea) 还需要自己配置导入。

IDEA 工程设置

  • 设置热修改,可以避免每一值修改后都手动更新服务器。 On frame deactivation: Update classes and resources.

Tomcat10 库名更改

Tomcat 更新到10 后,部署服务,发现 javax.servlet. 包,原来是包名改变了。

// Tomcat 10 用以下的 import
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
//----------------------------------------
// Tomcat 9 用以下的 import
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;

Servlet

  • Servlet 是 JAVA EE 的规范之一,是一个接口。
  • JAVA Web 三大组件之一,Servlet 程序, Filter 过滤器, Listen 监听器。
  • Tomcat 相当于一个容器,运行 Servlet。Servlet 可以接收客户端发来的请求,并响应给客户端。

创建 Servlet 程序

  • 编写一个类去实现 Servlet 接口。
  • 实现 servlet 方法,处理请求,并响应方法。
  • 在 web.xml 中配置 servlet 程序的访问地址。

web.xml config(添加资源路径) 斜杠表示工程路径(约定大于配置)

  • servlet : 标签 Tomcat 配置 Servlet 程序
    • servlet-name tag : Servlet 程序起一个別名(一般是类名)
    • servlet-class tag :servlet 程序的全类名,包名在前,类名在后。
  • servlet-mapping tag : 给 Servlet 程序配置访问地址
    • servlet-name tag : 当前配置的地址给那个 Servlet 程序使用
    • url-pattern tag : 配置访问地址, 要以斜杠打头
<web-app>
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.hhh.hello</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-mapping>/helloServlet</url-mapping>
  </servlet-mapping>
</web-app>

servlet 生命周期

  • 执行 Servlet 构造器方法, Servlet 中Service 方法是专门用来处理请求和响应的
  • 执行 init 初始化方法
  • 执行 Service 服务方法
  • 执行 destroy 销毁方法
package com.example.demo4;

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

public class HelloServlet3 implements Servlet {
    public HelloServlet3() {
	System.out.println("1: 构造器方法");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
	System.out.println("2:初始化方法");
    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
	System.out.println("3: 服务器方法");

    }

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

    @Override
    public void destroy() {
	System.out.println("4: Destroy方法");
    }
}

Servlet 构造方法和 init 方法创建时执行,Service 方法每次访问时执行, Destroy 方法停止时执行。

Servlet 请求的分发

GET 与 POST 请求分离。

  • alt + Enter : idea 快捷键: Introduce local variable.
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
    // TODO Auto-generated method stub
    System.out.println("3. service");

    HttpServletRequest httpServletRequest  = (HttpServletRequest) arg0;
    String method = httpServletRequest.getMethod();
    System.out.println(method);
    if ("GET".equals(method)) {
	doGet();
    }else if ("POST".equals(method)) {
	doPost();
    }

    PrintWriter pw = arg1.getWriter();
    pw.println("Hello world");

}

public void doGet() {
    System.out.println("GET request!");
}

public void doPost() {
    System.out.println("POST request!");

}

前端模拟 post 请求

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
  <head>
    <title>JSP - Hello World</title>
  </head>
  <body>
    <form action="http://localhost:8080/demo4_war_exploded/hello3" method="post">
      <input type="submit">
    </form>
  </body>
</html>

通过继承 HttpServlet 实现 Servlet 程序

  • 编写一个类去继承 HttpServlet 类,(HttpServlet 类,抽象类,实现了 service 方法,并实现了请求的分发。
  • 根据业务需要去 重写 doGet 或 doPost 方法
  • 到 web.xml 中配置 Servlet 程序的访问
package com.example.demo4;

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

public class HelloServlet4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	//super.doGet(req, resp);
	System.out.println("HelloServlet4 doGet function!");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	//super.doPost(req, resp);
	System.out.println("HelloServlet4 doPost function!");
    }
}

IDEA 直接新建 Servlet 实现 Servlet 程序

idea -> new Servlet -> web.xml(config servlet-mapping)

ServletConfig 类

Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。

  • Servlet 程序默认是第一次访问的时候创建。
  • ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象。

获取 Servlet 程序的别名 servlet-name 的值

@Override
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("Servlet 别名: " + servletConfig.getServletName());
}

获取初始化参数 init-param

  • 先配置
<servlet>
  <servlet-name>HelloServlet2</servlet-name>
  <servlet-class>com.example.demo4.HelloServlet2</servlet-class>
  <init-param>
    <param-name>username</param-name>
    <param-value>root</param-value>
  </init-param>
  <init-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql:/localhost:3306/test</param-value>
  </init-param>
</servlet>

<servlet-mapping>
  <servlet-name>HelloServlet2</servlet-name>
  <url-pattern>/hello2</url-pattern>
</servlet-mapping>
  • 代码调用
public void init(ServletConfig servletConfig) throws ServletException {
     System.out.println("Servlet 别名: " + servletConfig.getServletName());
     System.out.println("Init param 初始化参数 username is : " + servletConfig.getInitParameter("username"));
     System.out.println("Init param 初始化参数 url is : " + servletConfig.getInitParameter("url"));
 }

获取 ServletContext 对象

public class HelloServlet2 implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
	System.out.println(servletConfig.getServletContext());
    }
}
  • result: org.apache.catalina.core.ApplicationContextFacade@2dbcc9b2

ServletContext 类

  • ServletContext 是一个接口,它表示 Servlet 上下文对象。
  • 一个 web 工程,只有一个 ServletContext 对象实例。
  • ServletContext 对象是一个域对象。

域对象

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

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

ServletContext 类的四个常见作用

  1. 获取 web.xml 中配置的上下文参数 context-param

    context-param tag 是整个上下文参数,它属于整个 web 工程。

    <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">
      <context-param>
        <param-name>username</param-name>
        <param-value>larry</param-value>
      </context-param>
      <context-param>
        <param-name>password</param-name>
        <param-value>1234</param-value>
      </context-param>
    </web-app>
    
    • 代码获取
    package com.example.demo4;
        
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
        
    public class ContextServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	ServletContext context = getServletConfig().getServletContext();
    	String username = context.getInitParameter("username");
    	String password = context.getInitParameter("password");
        
    	System.out.println("context-param 参数: username : " + username);
    	System.out.println("context-param 参数: password : " + password);
        }
        
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        }
    }
    
  2. 获取当前的工程路径:格式: /工程路径

    • 获取工程部署后在服务器硬盘上的绝对路径
    package com.example.demo4;
        
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
        
    public class ContextServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	ServletContext context = getServletConfig().getServletContext();
    	System.out.println("当前工程路径: " + context.getContextPath());
    	System.out.println("工程部署的路径是: " + context.getRealPath("/"));
    	/**
    	 * 当前工程路径: /demo4_war_exploded
    	 * 工程部署的路径是: /home/larry/IdeaProjects/demo4/target/demo4-1.0-SNAPSHOT/
    	 */
        }
        
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        }
    }
        
    
  3. 像 Map 一样存取数据

    package com.example.demo4;
        
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
        
    public class ContextServlet1 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	// 获取 ServletContext 对象
    	ServletContext context = getServletContext();
        
    	context.setAttribute("key1","value1");
    	System.out.println("Context1 中获取数据 key1 的值是: " + context.getAttribute("key1"));
        }
    }
    
    • 创建 contextServlet2.java, 从里面访问 key1
    package com.example.demo4;
        
    import javax.servlet.*;
    import javax.servlet.http.*;
    import java.io.IOException;
        
    public class ContextServlet2 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	ServletContext context = getServletContext();
    	System.out.println("从 ContextServlet2 中获取 key1: " + context.getAttribute("key1"));
        }
    }
    

    先访问 Context2, 再访问 Context1, 最后再访问 Context2。

    • 从 ContextServlet2 中获取 key1: null
    • Context1 中获取数据 key1 的值是: value1
    • 从 ContextServlet2 中获取 key1: value1

    在两个 Servlet 中打印 context 对象: context 值一样。

    /**
     * 从 ContextServlet2 中获取 key1: null
     * context in ContextServlet2 : org.apache.catalina.core.ApplicationContextFacade@2afe71aa
     * Context1 中获取数据 key1 的值是: value1
     * context in ContextServlet1 : org.apache.catalina.core.ApplicationContextFacade@2afe71aa
     * 从 ContextServlet2 中获取 key1: value1
     * context in ContextServlet2 : org.apache.catalina.core.ApplicationContextFacade@2afe71aa
     */
    

HTTP 协议

HTTP 协议中的数据又叫报文。

请求的格式

GET

  • 请求行
    • 请求的方式 GET
    • 请求的资源路径[+?+请求参数]
    • 请求的协议和版本号: HTTP/1.1
  • 请求头:key:value 组成,不同的键值对,表示不同的含义。
    • Accept: 告诉服务器,客户端可以接收的数据类型。
    • Accept-Language: zhCN enUS.
    • User-Agent: 浏览器的信息
    • Accept-Encoding: 告诉服务器,客户端可以接收的数据编码(压缩)格式。
    • Host: 表示服务器的ip和端口号。
    • Connection: 告诉服务器请求链接如何处理:
      • Keep-Alive: 告诉服务器回传数据不要马上关闭,保持一小段时间的链接。
      • Closed: 马上关闭。

POST

  • 请求行
    • 请求的方式 POST
    • 请求的资源路径[+?+请求参数]
    • 请求的协议和版本号: HTTP/1.1
  • 请求头:key:value 组成,不同的键值对,表示不同的含义。
    • Accept: 告诉服务器,客户端可以接收的数据类型。
    • Accept-Language: zhCN enUS.
    • Referer: 表示请求发起时,浏览器地址栏中的地址(从哪来)
    • User-Agent: 浏览器的信息
    • Content-Type: 表示发送的数据的类型。
      • application/x-www-form-urlencoded
        • 表示提交的数据格式是:name=value&name=value, 然后对其进行 url 编码。
        • url 编码把非英文的内容转换为: %xx%xx。
      • multipart.form-data
        • 表示以多段的形式提交数据给服务器(以流的形式提交,用于上传)
    • Content-Length: 发送的数据的长度。
    • Cache-Control: 表示如何控制缓存:no-cache: 不缓存。
  • 空行
  • 请求体:发送给服务器的数据。action=login&username=root

GET & POST 请求有哪些

  1. GET 请求

    • html tag, method=get
    • a tag
    • link tag 引入 css
    • Script tag 引入 js file
    • img tag 引入图片
    • iframe 引入 html 页面
    • 浏览器地址栏中的地址
  2. POST 请求

    • html tag, method=post

响应的格式

  • 响应行
    • 响应的协议和版本号 HTTP/1.1
    • 响应状态码 200
    • 响应状态描述符 OK
  • 响应头:key:value 组成,不同的键值对,表示不同的含义。
    • Server:
    • Content-Type: 响应体的数据类型
    • Content-Length: 响应体的长度
    • Date: 请求响应的时间(这是格林时间)

空行

  • 响应体:

常用的响应码

  • 200 表示请求成功
  • 302 表示请求重定向
  • 404 表示服务器已经收到了,但你要的数据不存在
  • 500 表示服务器已经收到了,但服务器内部错误(代码错误)

MIME类型说明

  • { “.txt”, “text/plain” } 等等

HttpServletRequest 类

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

常用 request 方法

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

代码实现

package com.example.demo4;

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

public class RequestAPIServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	System.out.println("URI: " + request.getRequestURI());
	System.out.println("URL: " + request.getRequestURL());
	System.out.println("客户端 IP 地址: " + request.getRemoteHost());
	System.out.println("获取请求头: " + request.getHeader("User-Agent"));
	System.out.println("请求的方式: " + request.getMethod());
	/**
	 * URI: /demo4_war_exploded/request
	 * URL: http://localhost:8080/demo4_war_exploded/request
	 * 客户端 IP 地址: 0:0:0:0:0:0:0:1
	 * 获取请求头: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
	 * 请求的方式: GET
	 */
    }
}

获取请求的参数

  • html page: form.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>

    <form action="http://localhost:8080/demo4_war_exploded/parameter" method="get">
      用户名: <input type="text" name="username"> <br/>
      密码:  <input type="password" name="password"> <br/>
      兴趣爱好: <input type="checkbox" name="hobby" value="cpp"> CPP
      <input type="checkbox" name="hobby" value="java"> JAVA
      <input type="checkbox" name="hobby" value="php"> PHP
      <input type="submit">
    </form>

    <form action="http://localhost:8080/demo4_war_exploded/parameter" method="post">
      POST:用户名: <input type="text" name="username"> <br/>
      密码:  <input type="password" name="password"> <br/>
      兴趣爱好: <input type="checkbox" name="hobby" value="cpp"> CPP
      <input type="checkbox" name="hobby" value="java"> JAVA
      <input type="checkbox" name="hobby" value="php"> PHP
      <input type="submit">
    </form>
  </body>
</html>
  • java code
  • 中文乱码时要设置字符集
package com.example.demo4;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;

public class ParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String username = request.getParameter("username");
	String password = request.getParameter("password");
	String hobby = request.getParameter("hobby");
	String[] hobbies = request.getParameterValues("hobby"); // 当选择多个值时

	System.out.println("Username : " + username);
	System.out.println("Password : " + password);
	System.out.println("Hobby : " + hobby);
	System.out.println("Hobbies : " + Arrays.asList(hobbies));
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	request.setCharacterEncoding("UTF-8");
	String username = request.getParameter("username");
	String password = request.getParameter("password");
	String hobby = request.getParameter("hobby");
	String[] hobbies = request.getParameterValues("hobby"); // 当选择多个值时

	System.out.println("Username : " + username);
	System.out.println("Password : " + password);
	System.out.println("Hobby : " + hobby);
	System.out.println("Hobbies : " + Arrays.asList(hobbies));
    }
}

请求的转发

服务器收到请求后,从一个资源跳到另一个资源的操作叫转发。Servlet1 -> Servlet2: 两个 Servlet 共同完成一个业务逻辑功能。

请求转发的特点

  • 浏览器地址没发生变化
  • 是一次请求
  • 它们共享 Request 域中的数据
  • 可以转发到 WEB-INF 目录下 // can’t

JAVA 代码实现

  • Servlet1
package com.example.demo4;

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

public class Servlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String username = request.getParameter("username");
	System.out.println("在 Servlet1 查看参数: " + username);

	// 传递到 Servlet2
	request.setAttribute("key","柜台1的章");
	/**
	 * 请求转发必须以斜杠打头, / 斜杠表示地址为 http://localhost:8080/工程名/ , 映射到IDEA代码的 Web 目录下。
	 */
	//RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
	RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/form1.html"); //Can't
	requestDispatcher.forward(request,response);
    }
}
  • Servlet2
package com.example.demo4;

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

public class Servlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String username = request.getParameter("username");
	System.out.println("在 Servlet2 中看参数 " + username);

	// 查看 柜台1 是否盖章
	Object key = request.getAttribute("key");
	System.out.println("柜台1 是否有章: " + key);

	// 处理自己的业务
	System.out.println("Servlet2 处理自己的业务。");
    }
}

请求转发 html 实现跳转

  • index.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
  <head>
    <title>JSP - Hello World</title>
  </head>
  <body>
    这是 web 下的 index.html 页面。<br/>
    <a href="a/b/c.html">跳转 a/b/c.html </a>
  </body>
</html>
  • a/b/c.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
    这是 a/b/c.html <br/>
    <a href="../../index.jsp"> Return to index.html</a>
  </body>
</html>

请求转发 Servlet 实现跳转页面

  • base 标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转回去,如不设置,则以浏览器访问地址作为参考。

  • a/b/c.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <base href="http://localhost:8080/demo4_war_exploded/a/b/c.html">
    <title>Title</title>
  </head>
  <body>
    这是 a/b/c.html <br/>
    <a href="../../index.jsp"> Return to index.html</a>
  </body>
</html>
  • index.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
  <head>
    <title>JSP - Hello World</title>
  </head>
  <body>
    这是 web 下的 index.html 页面。<br/>
    <a href="a/b/c.html">跳转 a/b/c.html </a>
    <a href="http://localhost:8080/demo4_war_exploded/forwardc">请求跳转 a/b/c.html </a>
  </body>
</html>
  • ForwardCServlet.java
package com.example.demo4;

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

public class FrowardC extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	System.out.println("经过 forward C 程序。");
	request.getRequestDispatcher("a/b/c.html").forward(request,response);
    }
}

斜杠的不同意义

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
  <head>
    <title>JSP - Hello World</title>
  </head>
  <body>
    <a href="/">斜杠</a>
  </body>
</html>
<url-pattern>/servlet1</url-pattern>
  • 如一下服务器端代码
servletContext.getRealPath("/");
request.getRequestDispatcher("/");
  • 特殊情况: 请求重定向:把斜杠发送给浏览器解析。
response.sendRedirect("/"); 

HttpServletResponse 类

和 HttpServletRequest 类一样,每次请求进来, Tomcat 都创建一个 Response 对象递给 Servlet 程序去使用。

  • HttpServletRequest 表示请求过来的信息, HttpServletResponse 表示所有响应的信息。

字节流 & 字符流

  • 字节流 getOutputStream() 常用于下载,传递二进制数据。
  • 字符流 getWriter() 常用于回传字符串。
  • 两个流只能用一个。

往客户端回传字符串数据

package com.example.demo4;

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

public class ResponseIOServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	PrintWriter writer = response.getWriter();
	writer.write("Response's content!");
    }
}

回传数据的中文显示问题

  • 设置后端发送的字符集
  • 在响应头设置浏览器显示的字符集
package com.example.demo4;

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

public class ResponseIOServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// 方法一:
	// System.out.println(response.getCharacterEncoding());
	// response.setCharacterEncoding("UTF-8");
	// System.out.println(response.getCharacterEncoding());
	// response.setHeader("Content-Type","text/html; charset=UTF-8");

	// 方法二:
	// 它会同时设置服务器和客户端都使用 UTF-8 字符集, 还设置列响应头。
	// 此方法一定要在获取流之前调用才有效。
	response.setContentType("text/html; charset=UTF-8");
	System.out.println(response.getCharacterEncoding());
	PrintWriter writer = response.getWriter();
	writer.write("Response's content! 中文");
    }
}

请求重定向

请求重定向是指,客户端给服务器发送一个请求,服务器端告诉客户端说,我给你一个新地址,你去新地址访问。(因为之前的地址可能已经废弃)。

  • 响应码 302
  • 响应头 Location 新地址。

  • ResponseServlet1
package com.example.demo4;

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

public class ResponseServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	System.out.println("明到此一游 in Servlet Response 1.");
	request.setAttribute("key1","username");
	response.setStatus(302);
	response.setHeader("Location","http://localhost:8080/demo4_war_exploded/response2");
    }
}
  • ResponseServlet2
package com.example.demo4;

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

public class ResponseServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	response.getWriter().write("Response'2 result! And key1:  " + request.getAttribute("key1"));
    }
}

请求响应的特点

  • 浏览器地址栏发生变化
  • 两次请求
  • 不共享Request 域中的数据
  • 不能访问 WEB-INF 目录下的资源
  • 可以访问工程之外的资源,比如 http://www.baidu.com

请求重定向的第二种方案 sendRedirect()

package com.example.demo4;

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

public class ResponseServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	System.out.println("明到此一游 in Servlet Response 1.");
	response.sendRedirect("http://localhost:8080/demo4_war_exploded/response2");
    }
}

END

本文是我看视频 尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版 后的笔记。如有错误欢迎指正。