学习JavaWeb这一篇就够了01

202 阅读18分钟

学习 JavaWeb 这一篇就够了

目录第一章 开发工具 1.1、JDK 安装 1.2、Tomcat 安装 1.3、IDEA 安装 1.4、IDEA 集成 Tomcat1.5、IDEA 运行 JavaWeb 第二章 XML2.1、XML 的概述 2.2、XML 的语法......

配套资料,免费下载 链接:pan.baidu.com/s/1DNouClLL… 提取码:dq2w 复制这段内容后打开百度网盘手机 App,操作更方便哦

1.1、JDK 安装

第一步:打开官网进行下载www.oracle.com/java/techno…

img

第二步:运行程序进行安装

全部默认下一步即可,不用管路径是不是存在中文和空格,无碍!

注意:如果自己会配置 JDK,可以更改它的安装路径,那相应的环境变量也需要修改!

第三步:系统环境变量配置

此电脑 》 右键 》 属性 》 高级系统设置 》 环境变量 》 系统变量 》 新建(需要新建两个,然后修改一个)

新建两个:JAVA_HOME 代表 Java 的安装目录、CLASSPATH 代表程序运行的时候,优先加载当前目录中的类,然后再加载指定的类库

变量名变量值
JAVA_HOMEC:\Program Files\Java\jdk1.8.0_261
CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

修改一个:编辑 PATH 环境变量,它会打开一个窗口,新添两条路径,如下图所示

  • %JAVA_HOME%\bin
  • %JAVA_HOME%\jre\bin

img

第四步:测试 JDK 是否安装成功

打开一个 cmd 命令行窗口,输入以下两个命令查看,如果有内容输出则证明已经配置成功!

  • java -version
  • javac -version

img

1.2、Tomcat 安装

第一步:打开官网进行下载和安装tomcat.apache.org/)

img

img

第二步:系统环境变量配置

此电脑 》 右键 》 属性 》 高级系统设置 》 环境变量 》 系统变量 》 新建(需要新建两个,然后修改三个)

新建两个:CATALINA_BASE 和 CATALINA_HOME 均代表 Tomcat 的安装目录

变量名变量值
CATALINA_BASEC:\DevTools\apache-tomcat-8.5.57 (输入自己解压的 Tomcat 目录,不要照抄我的)
CATALINA_HOMEC:\DevTools\apache-tomcat-8.5.57 (输入自己解压的 Tomcat 目录,不要照抄我的)

修改一个:编辑 CLASSPATH 环境变量,它会打开一个窗口,具体修改,如下所示

  • 未修改前:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
  • 修改以后:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\lib\servlet-api.jar;

修改两个:编辑 PATH 环境变量,它会打开一个窗口,新添两条路径,如下所示

  • %CATALINA_HOME%\bin
  • %CATALINA_HOME%\lib

img

第三步:测试 Tomcat 是否安装成功

打开一个 cmd 命令行窗口,输入以下一个命令查看,如果有内容输出则证明已经配置成功!

  • catalina run

img

img

如果看到上边这个界面了,就把刚才打开的 cmd 窗口关掉,否则可能会影响后边 IDEA 集成 Tomcat。

1.3、IDEA 安装

注意:官网的版本会隔一段时间更新一次,我这里只是告诉大家怎么下载,不一定要用最新的,我这套课程使用的是 IdeaIU-2020.1.2,如果你不是这个版本,那么我建议你改为这个版本,否则后边可能会出现一些问题。

第一步:打开官网进行下载和安装www.jetbrains.com/idea/)

img

img

第二步:运行程序进行安装

全部默认下一步即可,如果遇到需要一页打勾的很多,就把有 64 的那个勾上,它代表在桌面创建一个 64 位的快捷方式,没勾选也没事,可以在开始菜单打开 IDEA!

第三步:关于激活的问题

由于 IDEA 是收费软件,请大家自行购买激活码,然后激活,不激活也可以试用 30 天!

第四步:常见的设置页面

img

img

img

第五步:最终的效果图

img

1.4、IDEA 集成 Tomcat

img

img

1.5、IDEA 运行 JavaWeb

img

img

img

注意:这个弹窗意思是你需不需要每天都让我提示你一些小技巧,我们选择关闭,不用搭理他!

img

注意:如果你有依赖的 JAR 包,就放到 lib 文件夹中,然后添加到工程中,方便项目移动的时候,不会丢失 JAR 包。

至于 classes 是否需要创建,在这里我个人认为是不需要创建的,因为编译器会自动创建,如果你创建了,还必须要修改配置信息,很麻烦,所以我建议就不要创建了,一般我们也不会创建。

img

img

注意:Fix 并不是所有电脑都需要点击的,如果它弹出了这个窗口你就点击,没弹出来就不用管了!

img

注意:只有上边点击了 Fix 才会出来这个页面,没有点击 Fix,这一步忽略即可,不用纠结!

img

img

img

img

img

img

img

img

img

一般浏览器也会正常显示刚才 JSP 中的文件内容

img

img

2.1、XML 的概述

XML 是可扩展标记语言(eXtensible Markup Language),它被设计用来传输和存储数据,我们一般使用 XML 文件来做应用程序的配置文件。

2.2、XML 的语法

案例演示:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book category="COOKING">
		<title lang="en">Everyday Italian</title>
		<author>Giada De Laurentiis</author>
		<year>2005</year>
		<price>30.00</price>
	</book>
	<book category="CHILDREN">
		<title lang="en">Harry Potter</title>
		<author>J K. Rowling</author>
		<year>2005</year>
		<price>29.99</price>
	</book>
	<book category="WEB">
		<title lang="en">Learning XML</title>
		<author>Erik T. Ray</author>
		<year>2003</year>
		<price>39.95</price>
	</book>
</bookstore>

树状结构:

img

支持语法:

  • 嵌套标签
  • 单级标签
  • 内含属性

注意:根节点只能有一个

注释语法:

<!-- comment -->

2.3、XML 的解析

解析方式:

  • DOM(Document Object Model):在解析的时候,它会把整个 XML 文档读入内存中,形成一个树状结构。整个文档称之为 Document 对象,所有元素节点对应 Element 对象,属性对应 Attribute 对象,文本对应 Text 对象,以上所有对象都可以称之为 Node 节点。如果 XML 特别大,可能会造成内存溢出。这种解析方式可以对 XML 文档进行增删改查操作。
  • SAX(Simple API For XML):它是基于事件驱动的一种解析方式,也就是读取一行,解析一行。在读取较大的 XML 文件的时候,也不会造成内存溢出,但是这种解析方式只能进行查询,不能进行增删改操作。

案例演示:

工程名称:XMLDemo

包的名称:com.caochenlei.xml.parse

依赖文件:dom4j-1.6.1.jar、jaxen-1.1-beta-6.jar、JUnit 4

测试文件:bookstore.xml(全路径:/XMLDemo/bookstore.xml)

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book category="COOKING">
		<title lang="en">Everyday Italian</title>
		<author>Giada De Laurentiis</author>
		<year>2005</year>
		<price>30.00</price>
	</book>
	<book category="CHILDREN">
		<title lang="en">Harry Potter</title>
		<author>J K. Rowling</author>
		<year>2005</year>
		<price>29.99</price>
	</book>
	<book category="WEB">
		<title lang="en">Learning XML</title>
		<author>Erik T. Ray</author>
		<year>2003</year>
		<price>39.95</price>
	</book>
</bookstore>

代码名称:XMLParse.java(全路径:/XMLDemo/src/com/caochenlei/xml/parse/XMLParse.java)

package com.caochenlei.xml.parse;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class XMLParse {

	
	@Test
	public void test1() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();
			List<Element> bookElements = rootElement.elements("book");
			for (Element bookElement : bookElements) {
				Attribute category = bookElement.attribute("category");
				String title = bookElement.element("title").getText();
				String author = bookElement.element("author").getText();
				String year = bookElement.element("year").getText();
				String price = bookElement.element("price").getText();
				System.out.println(Arrays.asList(category.getText(), title, author, year, price));
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test2() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Element bookElement = rootElement.addElement("book");
			bookElement.addAttribute("category", "Hibernate");
			bookElement.addElement("title").addText("Learing Hibernate");
			bookElement.addElement("author").addText("caochenlei");
			bookElement.addElement("year").addText("1997");
			bookElement.addElement("price").addText("99.99");

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test3() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Node singleNode = rootElement.selectSingleNode("//book[@category='Hibernate']");
			rootElement.remove(singleNode);

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test4() {
		try {
			SAXReader domReader = new SAXReader();
			Document document = domReader.read(new File("bookstore.xml"));
			Element rootElement = document.getRootElement();

			Node singleNode = rootElement.selectSingleNode("//book[@category='WEB']");
			singleNode.selectSingleNode("title").setText("Learning JavaWeb");
			singleNode.selectSingleNode("author").setText("张三");
			singleNode.selectSingleNode("year").setText("2020");
			singleNode.selectSingleNode("price").setText("09.09");

			XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("bookstore.xml"), OutputFormat.createPrettyPrint());
			xmlWriter.write(document);
			xmlWriter.close();
		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

3.1、YAML 的概述

YAML(YAML Ain’t Markup Language)是一种可读性高并且容易被人类阅读,容易和脚本语言交互,用来表达资料序列的编程语言,类似于 XML 但比 XML 更简洁。

3.2、YAML 的语法

YAML 语法:

  • 大小写敏感
  • 使用空格缩进表示层级关系
  • 缩进不允许使用 tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 相同层级的键不能重复

YAML 对象:

对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格,也可以使用 key:{key1: value1, key2: value2, …},还可以使用缩进表示层级关系。

key: 
  child-key1: value1
  child-key2: value2

较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的 key,配合一个冒号加一个空格代表一个 value:

? 
  - complexkey1
  - complexkey2
: 
  - complexvalue1
  - complexvalue2

意思即对象的属性是一个数组 [complexkey1,complexkey2],对应的值也是一个数组 [complexvalue1,complexvalue2]

YAML 数组:

以 - 开头的行表示构成一个数组:

- A
- B
- C

YAML 支持多维数组,可以使用行内表示:

key: [value1, value2, ...]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格:

-
 - A
 - B
 - C

一个相对复杂的例子:意思是 companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。

companies:
 -
  id: 1
  name: company1
  price: 200W
 -
  id: 2
  name: company2
  price: 500W

数组也可以使用流式 (flow) 的方式表示:

companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]

YAML 纯量:

纯量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

使用一个例子来快速了解纯量的基本使用:

boolean: 
  - TRUE                          
  - FALSE                         
float:
  - 3.14                          
  - 6.8523015e+5                  
int:
  - 123                           
  - 0b1010_0111_0100_1010_1110    
null:
  nodeName: 'node'
  parent: ~                       
string:
  - 哈哈
  - 'Hello World'                 
  - comment1:                     
      newline1
      newline2
  - comment2: >                   
      newline3
      newline4
  - comment3: |                   
      newline3
      newline4
date:
  - 2018-02-17 15:02:31           
datetime: 
  - 2018-02-17T15:02:31+08:00     

YAML 引用:

& 锚点和 * 别名,可以用来引用:

defaults: &defaults
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  <<: *defaults

test:
  database: myapp_test
  <<: *defaults

上边的代码相当于:

defaults:
  adapter: postgres
  host: localhost

development:
  database: myapp_development
  adapter: postgres
  host: localhost

test:
  database: myapp_test
  adapter: postgres
  host: localhost

类型指定:

YAML 虽然有类型自动解析,但是有时候我们写了一个数字,但是我们想让它是字符串类型,就用到了类型指定,只要在值的前边写上相对应的类型标识就行了,常见的类型标识有以下几个:

!!null ''                   
!!bool 'yes'                
!!int '3...'                
!!float '3.14...'           
!!binary '...base64...'     
!!timestamp 'YYYY-...'      
!!omap [ ... ]              
!!pairs [ ... ]             
!!set { ... }               
!!str '...'                 
!!seq [ ... ]               
!!map { ... }               

3.3、YAML 的解析

工程名称:YAMLDemo

包的名称:com.caochenlei.yaml.parse

依赖文件:snakeyaml-1.17.jar、JUnit 4

测试文件:user.yaml(全路径:/YAMLDemo/user.yaml)、users.yaml(全路径:/YAMLDemo/users.yaml)

参考网站:bitbucket.org/asomov/snak…

User.java(全路径:/YAMLDemo/src/com/caochenlei/yaml/parse/User.java)

package com.caochenlei.yaml.parse;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

public class User {
	private long id;
	private String name;
	private String phone;
	private List<String> hobby;
	private Map<String, BigDecimal> balance;
	private Address address;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public List<String> getHobby() {
		return hobby;
	}

	public void setHobby(List<String> hobby) {
		this.hobby = hobby;
	}

	public Map<String, BigDecimal> getBalance() {
		return balance;
	}

	public void setBalance(Map<String, BigDecimal> balance) {
		this.balance = balance;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", phone=" + phone + ", hobby=" + hobby + ", balance=" + balance + ", address=" + address + "]";
	}
}

Address.java(全路径:/YAMLDemo/src/com/caochenlei/yaml/parse/Address.java)

package com.caochenlei.yaml.parse;

public class Address {
	private String county;
	private String province;
	private String city;

	public String getCounty() {
		return county;
	}

	public void setCounty(String county) {
		this.county = county;
	}

	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	@Override
	public String toString() {
		return "Address [county=" + county + ", province=" + province + ", city=" + city + "]";
	}
}

YAMLDemo.java(全路径:/YAMLDemo/src/com/caochenlei/yaml/parse/YAMLDemo.java)

package com.caochenlei.yaml.parse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;
import org.yaml.snakeyaml.Yaml;

public class YAMLDemo {

	
	@Test
	public void test1() {
		try {
			Yaml yaml = new Yaml();
			Object user = yaml.load(new FileInputStream(new File("user.yaml")));
			System.out.println(user);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test2() {
		try {
			Yaml yaml = new Yaml();
			User user = yaml.loadAs(new FileInputStream(new File("user.yaml")), User.class);
			System.out.println(user);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test3() {
		try {
			Yaml yaml = new Yaml();
			Map<String, Object> user = (Map<String, Object>) yaml.load(new FileInputStream(new File("user.yaml")));
			System.out.println(user.get("id"));
			System.out.println(user.get("name"));
			System.out.println(user.get("phone"));
			System.out.println(user.get("hobby"));
			System.out.println(user.get("balance"));
			System.out.println(user.get("address"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test4() {
		try {
			Yaml yaml = new Yaml();
			Iterable<Object> users = yaml.loadAll(new FileInputStream(new File("users.yaml")));
			for (Object user : users) {
				System.out.println(user);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test5() {
		try {
			Yaml yaml = new Yaml();
			User user = new User();
			user.setId(123456);
			user.setName("王五");
			user.setPhone("15633029014");
			user.setHobby(Arrays.asList("aaa", "bbb", "c"));
			HashMap<String, BigDecimal> balance = new HashMap<String, BigDecimal>();
			balance.put("wechat", new BigDecimal(19.99));
			balance.put("alipay", new BigDecimal(29.99));
			user.setBalance(balance);
			Address address = new Address();
			address.setCity("China");
			address.setProvince("HeBei");
			address.setCity("XingTai");
			user.setAddress(address);
			Writer output = new FileWriter("myuser.yaml");
			yaml.dump(user, output);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	@Test
	public void test6() {
		try {
			Yaml yaml = new Yaml();
			HashMap<String, Object> user = new HashMap<String, Object>();
			user.put("id", 123456);
			user.put("name", "王五");
			user.put("phone", "15633029014");
			user.put("hobby", Arrays.asList("aaa", "bbb", "c"));
			HashMap<String, BigDecimal> balance = new HashMap<String, BigDecimal>();
			balance.put("wechat", new BigDecimal(19.99));
			balance.put("alipay", new BigDecimal(29.99));
			user.put("balance", balance);
			Address address = new Address();
			address.setCity("China");
			address.setProvince("HeBei");
			address.setCity("XingTai");
			user.put("address", address);
			Writer output = new FileWriter("mymap.yaml");
			yaml.dump(user, output);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

4.1、Servlet 概述

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

4.2、Servlet 语法格式

第一步:创建包(com.caochenlei.servlet.demo)

第二步:创建类(com.caochenlei.servlet.demo.MyServlet),并且需要实现 Servlet 接口中的所有方法

package com.caochenlei.servlet.demo;

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

public class MyServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("MyServlet init ...");
    }

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

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
            throws ServletException, IOException {
        System.out.println("MyServlet service ...");
    }

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

    @Override
    public void destroy() {
        System.out.println("MyServlet destroy ...");
    }
}

方法介绍:

  • init:Servlet 初始化时调用的方法
  • getServletConfig:获取当前 Servlet 的配置信息
  • service:调用 Servlet 真正去处理逻辑的方法
  • getServletInfo:它提供有关 Servlet 的信息,如作者、版本、版权
  • destroy:Servlet 销毁时调用的方法

第三步:配置映射(web.xml 中新增以下代码)

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/MyServlet</url-pattern>
    </servlet-mapping>

配置介绍:

servlet 标签用于配置 Servlet 的基本信息

  1. servlet-class:代表当前 Servlet 的具体类路径,注意最后不包含. java
  2. servlet-name:代表当前 Servlet 的别名,可以和原 Servlet 名称一样,也可以不一样,一般我们就一样就行了

servlet-mapping 标签用于配置请求路径与具体处理 Servlet 的对应关系

  1. url-pattern:这里写你要匹配的地址路径
  2. servlet-name:如果匹配到请求,该交给哪一个 Servlet 处理,这里的 servlet-name 其实就是一个 Servlet 的别名

第四步:启动应用,然后浏览器输入地址访问http://localhost:8080/myJavaWebDemo_war_exploded/MyServlet)

img

第五步:正常关闭 Tomcat 服务器,我们会看到调用销毁方法,如下图所示:

img

4.3、Servlet 执行过程

img

4.4、Servlet 生命周期

Servlet 运行在 Servlet 容器中,其生命周期由容器来管理。

Servlet 的生命周期通过 javax.servlet.Servlet 接口中的 init()、service() 和 destroy() 方法来表示。

Servlet 的生命周期包含了下面 4 个阶段:

  1. 类加载和实例化
  2. 初始化:init()
  3. 请求处理:service()
  4. 销毁:destroy()

4.5、Servlet 继承体系

其实我们不难发现,现有的 Servlet 它的方法比较多,而且大多需要我们自己来实现,那有没有一种它的实现子类,把大部分方法都是实现了,而我们只要关注请求处理就行了,那答案肯定是有的,这个类就是 HttpServlet,我们只要继承这个类重写 GET、POST 方法就能实现一个简单的 Servlet 请求处理,Servlet 的继承体系如下图:

img

既然我们知道 HttpServlet 这个类了,我们就要使用一下:

第一步:创建类(com.caochenlei.servlet.demo.MyHttpServlet),并且需要继承 HttpServlet 实现 doPost、doGet 方法。

package com.caochenlei.servlet.demo;

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 MyHttpServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        System.out.println("doPost method invoke ...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        System.out.println("doGet method invoke ...");
    }
}

第二步:配置映射(在 web.xml 文件中新增以下代码)

    <servlet>
        <servlet-name>MyHttpServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.MyHttpServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyHttpServlet</servlet-name>
        <url-pattern>/MyHttpServlet</url-pattern>
    </servlet-mapping>

第三步:重启应用,然后浏览器访问http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)**,观察控制台**

注意:doPost 需要提交表单模拟,这里就不演示了,效果都一样!

img

我们注意 url-pattern 它可以有多种拦截形式:

  • 全路径匹配:/a
  • 前半段匹配:/a/b/c/*
  • 扩展名匹配:*.action

4.6、ServletContext

每个 web 工程都只有一个 ServletContext 对象,也就是不管在哪个 Servlet 里面,获取到的这个类的对象都是同一个,它用来获取 Servlet 的上下文,在服务器启动的时候,会为托管的每一个 web 应用程序,创建一个 ServletContext 对象,当从服务器移除托管或者是关闭服务器时,ServletContext 将会被销毁。它主要有以下几方面作用:

  1. 获取全局配置参数
  2. 获取 web 工程中的资源
  3. 在 servlet 间共享数据域对象

4.6.1、获取全局配置参数

第一步:在 web.xml 中新增以下代码

    <context-param>
        <param-name>username</param-name>
        <param-value>zhangsan</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </context-param>

第二步:在 MyHttpServlet 的 doGet 方法中新增以下代码

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while(initParameterNames.hasMoreElements()){
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName+":"+initParameterValue);
    }
}

第三步:重启 Tomcat 服务器,在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)

img

4.6.2、获取 web 工程中的资源

第一步:在 myJavaWebDemo 的 web 文件夹中右键创建 a.txt 文件,内容为 Hello,World!

img

第二步:在 MyHttpServlet 的 doGet 方法中新增以下代码

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }

    
    String realPath = getServletContext().getRealPath("a.txt");
    System.out.println(realPath);

    
    InputStream resourceAsStream = getServletContext().getResourceAsStream("a.txt");
    System.out.println(resourceAsStream);
}

第三步:重启 Tomcat 服务器,在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)

注意:当你能拿到一个文件的绝对路径或者输入流以后,就可以对它进行操作了!

img

4.6.3、在 Servlet 间共享数据域对象

第一步:创建 LoginServlet 并配置请求映射

LoginServlet

package com.caochenlei.servlet.demo;

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 LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }
}

web.xml

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/LoginServlet</url-pattern>
    </servlet-mapping>

第二步:在 LoginServlet 的 doGet 中实现登录次数的修改,默认为 1

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    
    Integer count = (Integer) getServletContext().getAttribute("count");
    
    if (count == null) {
        getServletContext().setAttribute("count", 1);
    } else {
        getServletContext().setAttribute("count", count + 1);
    }
}

第三步:在 MyHttpServlet 的 doGet 中新增以下查看代码,用于查看当前登录次数

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("doGet method invoke ...");

    
    Enumeration<String> initParameterNames = getServletContext().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletContext().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }

    
    String realPath = getServletContext().getRealPath("a.txt");
    System.out.println(realPath);

    
    InputStream resourceAsStream = getServletContext().getResourceAsStream("a.txt");
    System.out.println(resourceAsStream);

    
    Integer count = (Integer) getServletContext().getAttribute("count");
    
    if (count == null) {
        response.getWriter().write("no login!");
    } else {
        response.getWriter().write("count:" + count);
    }
}

第四步:重启 Tomcat 服务器

在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)**,查看是否登录**

img

在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/LoginServlet)**,模拟登录场景**

img

在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/MyHttpServlet)**,查看登录次数**

img

4.7、ServletConfig

通过 ServletConfig 对象可以获取 servlet 在配置的时候一些信息。

第一步:创建类(HelloServlet)

package com.caochenlei.servlet.demo;

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 HelloServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }
}

第二步:在 web.xml 中配置映射关系

<servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.HelloServlet</servlet-class>
        
        <init-param>
            <param-name>driver</param-name>
            <param-value>com.mysql.jdbc.Driver</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/test</param-value>
        </init-param>
        <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>
        
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/HelloServlet</url-pattern>
    </servlet-mapping>

第三步:在 HelloServlet 的 doGet 方法中新增以下代码

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    Enumeration<String> initParameterNames = getServletConfig().getInitParameterNames();
    while (initParameterNames.hasMoreElements()) {
        String initParameterName = initParameterNames.nextElement();
        String initParameterValue = getServletConfig().getInitParameter(initParameterName);
        System.out.println(initParameterName + ":" + initParameterValue);
    }
}

第四步:重启 Tomcat 服务器,在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/HelloServlet)

img

4.8、HttpServletRequest

HttpServletRequest 这个对象封装了客户端提交过来的一切数据。

第一步:修改 index.jsp

<form action="RegisterServlet" method="get">
    账户:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
         <input type="submit" value="注册">
</form>

第二步:创建类(RegisterServlet)

package com.caochenlei.servlet.demo;

import javafx.print.Collation;

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

public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            System.out.println(headerName + ":" + headerValue);
        }
        System.out.println("====================");

        
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            String parameterValue = request.getParameter(parameterName);
            
            System.out.println(parameterName + ":" + parameterValue);
        }
        System.out.println("====================");

        
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> names = parameterMap.keySet();
        for (String name : names) {
            String[] value = parameterMap.get(name);
            System.out.println(name + ":" + Arrays.toString(value));
        }
        System.out.println("====================");

        
        StringBuffer requestURL = request.getRequestURL();
        String requestURI = request.getRequestURI();
        String servletPath = request.getServletPath();
        String queryString = request.getQueryString();
        System.out.println("requestURL:" + requestURL);
        System.out.println("requestURI:" + requestURI);
        System.out.println("servletPath:" + servletPath);
        System.out.println("queryString:" + queryString);
    }
}

第三步:在 web.xml 中新增映射信息

    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/RegisterServlet</url-pattern>
    </servlet-mapping>

第四步:重启 Tomcat 服务器,在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/)

在表单输入数据,然后点击提交

img

查看 IDEA 的控制台信息

host:localhost:8080
connection:keep-alive
upgrade-insecure-requests:1
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site:same-origin
sec-fetch-mode:navigate
sec-fetch-user:?1
sec-fetch-dest:document
referer:http://localhost:8080/myJavaWebDemo_war_exploded/
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9
cookie:JSESSIONID=4342FA7CB5F51C5E4A5251E485E36E38
====================
username:zhangsan
password:123456
====================
username:[zhangsan]
password:[123456]
====================
requestURL:http://localhost:8080/myJavaWebDemo_war_exploded/RegisterServlet
requestURI:/myJavaWebDemo_war_exploded/RegisterServlet
servletPath:/RegisterServlet
queryString:username=zhangsan&password=123456

如何解决请求数据中文乱码问题?

  • GET 方式

    • String newUsername = new String(username.getBytes("ISO-8859-1"), "UTF-8");
      
  • POST 方式

    • request.setCharacterEncoding("UTF-8");
      

4.9、HttpServletResponse

HttpServletResponse 这个对象负责返回数据给客户端。

第一步:创建类(DisplayServlet)

package com.caochenlei.servlet.demo;

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 DisplayServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        
        response.getWriter().write("<h1>hello response 111 ...</h1>");

        
        
    }
}

第二步:在 web.xml 文件中新增以下映射信息

    <servlet>
        <servlet-name>DisplayServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.DisplayServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DisplayServlet</servlet-name>
        <url-pattern>/DisplayServlet</url-pattern>
    </servlet-mapping>

第三步:重启 Tomcat 服务器,在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/DisplayServlet)

img

如何解决响应数据中文乱码问题?

  • 以字符流输出:response.getWriter()

    • response.setCharacterEncoding("UTF-8");
      response.setHeader("Content-Type", "text/html; charset=UTF-8");
      response.getWriter().write("你好,世界!");
      
  • 以字节流输出:response.getOutputStream()

    • response.setHeader("Content-Type", "text/html;charset=UTF-8");
      response.getOutputStream().write("你好,世界!".getBytes("UTF-8"));
      

4.10、重定向和请求转发

  • 重定向
	// 第一种:使用示例
	response.setStatus(302);
	response.setHeader("Location", "login_success.html");*/
		
	// 第二种:使用示例
	response.sendRedirect("login_success.html");

	1. 地址上显示的是最后的那个资源的路径地址。

	2. 请求次数最少有两次,服务器在第一次请求后,会返回302以及一个地址,浏览器在根据这个地址,执行第二次访问。

	3. 可以跳转到任意路径,不是自己的工程也可以跳。

	4. 效率稍微低一点,执行两次请求。 

	5. 后续的请求,没法使用上一次的request存储的数据,或者没法使用上一次的request对象,因为这是两次不同的请求。
  • 请求转发
	// 使用示例:
	request.getRequestDispatcher("login_success.html").forward(request, response);

	1. 地址上显示的是请求servlet的地址,返回200ok。

	2. 请求次数只有一次,因为是服务器内部帮客户端执行了后续的工作。 

	3. 只能跳转自己项目的资源路径。  

	4. 效率上稍微高一点,因为只执行一次请求。 

	5. 可以使用上一次的request对象。

4.11、Cookie

Cookie 其实是一份小数据,它是服务器给客户端并且存储在客户端上的一份小数据。

第一步:创建类(CookieServlet)

package com.caochenlei.servlet.demo;

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

public class CookieServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        Cookie[] cookies = request.getCookies();
        if (cookies.length == 1) {
            System.out.println("没有其它Cookie存在,只有JSESSIONID这个Cookie存在!");

            
            
            Cookie cookie = new Cookie("username", "zhangsan");
            
            cookie.setComment("用户账号Cookie");
            
            
            
            cookie.setMaxAge(60 * 60 * 24 * 7);
            
            cookie.setValue("lisi");
            
            cookie.setDomain("localhost");
            
            cookie.setPath("/myJavaWebDemo_war_exploded/CookieServlet");
            

            
            response.addCookie(cookie);
        } else {
            for (Cookie cookie : cookies) {
                if ("username".equals(cookie.getName())) {
                    System.out.println(cookie.getName() + "====" + cookie.getValue());
                }
            }
        }
        
    }
}

第二步:在 web.xml 中新增映射信息

    <servlet>
        <servlet-name>CookieServlet</servlet-name>
        <servlet-class>com.caochenlei.servlet.demo.CookieServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CookieServlet</servlet-name>
        <url-pattern>/CookieServlet</url-pattern>
    </servlet-mapping>

第三步:重启 Tomcat 服务器

在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/CookieServlet)

img

在浏览器中访问http://localhost:8080/myJavaWebDemo_war_exploded/DisplayServlet)

img