HTML

HTML入门

概述

HTML(超文本标记语言—HyperText Markup Language)是构成 Web 世界的基础,是一种用来告知浏览器如何组织页面的标记语言

  • 超文本 Hypertext,是指连接单个或者多个网站间的网页的链接。通过链接,就能访问互联网中的内容
  • 标记 Markup ,是用来注明文本,图片等内容,以便于在浏览器中显示,例如

网页的构成

  • HTML:通常用来定义网页内容的含义和基本结构
  • CSS:通常用来描述网页的表现与展示效果
  • JavaScript:通常用来执行网页的功能与行为

参考视频:https://www.bilibili.com/video/BV1Qf4y1T7Hx

组成

标签

HTML 页面由一系列的元素(elements) 组成,而元素是使用标签创建的

一对标签(tags)可以设置一段文字样式,添加一张图片或者添加超链接等等

在 HTML 中,`` 标签表示标题,我们可以使用开始标签结束标签包围文本内容,这样其中的内容就以标题的形式显示

1

1
<h1>开始学习JavaWeb</h1>

2

1
<h2>二级标题</h2>

属性

HTML 标签可以拥有属性

  • 属性是属于标签的,修饰标签,让标签有更多的效果
  • 属性一般定义在起始标签里面
  • 属性一般以属性=属性值的形式出现
  • 属性值一般用 '' 或者 "" 括起来。 不加引号也是可以的(不建议使用)。比如:name=‘value’

1

1
<h1 align="center">开始学习JavaWeb</h1>

在 HTML 标签中,align 属性表示水平对齐方式,我们可以赋值为 center 表示 居中

结构

HTML结构

文档结构介绍:

  • 文档声明:用于声明当前 HTML 的版本,这里的``是 HTML5 的声明
  • html 根标签:除文档声明以外,其它内容全部要放在根标签 html 内部
  • 文档头部配置:head 标签,是当前页面的配置信息,外部引入文件, 例如网页标签、字符集等
    • :这个标签是页面的元数据信息,设置文档使用 utf-8 字符集编码
    • ``:这个标签定义文档标题,位置出现在浏览器标签。在收藏页面时,它可用来描述页面
  • 文档显示内容:body 标签,里边的内容会显示到浏览器页面上

HTML语法

注释方式

将一段 HTML 中的内容置为注释,你需要将其用特殊的记号 包括起来

1

1
<p>我在注释外!</p>

2

1

3

1
<!-- <p>我在注释内!</p> -->

基本元素

空元素

一些元素只有一个标签,叫做空元素。它是在开始标签中进行关闭的。

1

1
第一行文档<br/> 

2

1
第二行文档<br/>

嵌套元素

把元素放到其它元素之中——这被称作嵌套。

1

1
<h2><u>二级标题</u></h2>

块元素

在HTML中有两种重要元素类别,块级元素和内联元素

  • 块级元素:

    独占一行。块级元素(block)在页面中以块的形式展现。相对于其前面的内容它会出现在新的一行,其后的内容也会被挤到下一行展现。比如等。

  • 行内元素

    行内显示。行内元素不会导致换行。通常出现在块级元素中并环绕文档内容的一小部分,而不是一整个段落或者一组内容。比如 等。

注意:一个块级元素不会被嵌套进行内元素中,但可以嵌套在其它块级元素中。

常用的两个标签:(重要

  • 是一个通用的内容容器,并没有任何特殊语义。它可以被用来对其它元素进行分组,一般用于样式化相关的需求。它是一个块级元素。
  • 属性:id、style、class
  • `` 是短语内容的通用行内容器,并没有任何特殊语义。它可以被用来编组元素以达到某种样式。它是一个行内元素

基本属性

标签属性,主要用于拓展标签。属性包含元素的额外信息,这些信息不会出现在实际的内容中。但是可以改变标签的一些行为或者提供数据,属性总是以name = value"的格式展现。

  • 属性名:同一个标签中,属性名不得重复。

  • 大小写:属性和属性值对大小写不敏感。不过W3C标准中,推荐使用小写的属性/属性值。

  • 引号:双引号是最常用的,不过使用单引号也没有问题。

  • 常用属性:

    属性名 作用
    class 定义元素类名,用来选择和访问特定的元素
    id 定义元素唯一标识符,在整个文档中必须是唯一的
    name 定义元素名称,可以用于提交服务器的表单字段
    value 定义在元素内显示的默认值
    style 定义CSS样式,这些样式会覆盖之前设置的样式

特殊字符

在HTML中,字符 <, >,",'& 是特殊字符

原义字符 等价字符引用
< <
> >
" "
'
& &
空格

文本标签

使用文本内容标签设置文字基本样式

标签名 作用
p 表示文本的一个段落
h 表示文档标题, ,呈现了六个不同的级别的标题,级别最高,而 级别最低
hr 表示段落级元素之间的主题转换,一般显示为水平线
li 表示列表里的条目。(常用在ul ol 中)
ul 表示一个无序列表,可含多个元素,无编号显示。
ol 表示一个有序列表,通常渲染为有带编号的列表
em 表示文本着重,一般用斜体显示
strong 表示文本重要,一般用粗体显示
font 表示字体,可以设置样式(已过时)
i 表示斜体
b 表示加粗文本

1

1
<!DOCTYPE html>

2

1
<html lang="en">

3

1
<head>

4

1
<meta charset="UTF-8">

5

1
<title>文本标签演示</title>

6

1
</head>

7

1
<body>

8

1
<!--段落标签:<p>-->

9

1
<p>这些年</p>

10

1
<p>支付宝的诞生就是为了解决淘宝网的客户们的买卖问题</p>

11

1
    

12

1
<!-- 标题标签:<h1> ~ <h6> -->

13

1
<h1>一级标题</h1>

14

1
<h2>二级标题</h2>

15

1
<h3>三级标题</h3>

16

1
<h4>四级标题</h4>

17

1
<h5>五级标题</h5>

18

1
<h6>六级标题</h6>

19

1

20

1
<!--水平线标签:<hr/>

21

1
属性:

22

1
size-大小

23

1
color-颜色

24

1
-->

25

1
<hr size="4" color="red"/>

26

1

27

1
<!--

28

1
无序列表:<ul>

29

1
属性:type-列表样式(disc实心圆、circle空心圆、square实心方块)

30

1
列表项:<li>

31

1
-->

32

1
<ul type="circle">

33

1
<li>javaEE</li>

34

1
<li>HTML</li>

35

1
</ul>

36

1

37

1
<!--

38

1
有序列表:<ol>

39

1
属性:type-列表样式(1数字、A或a字母、I或i罗马字符)   start-起始位置

40

1
列表项:<li>

41

1
-->

42

1
<ol type="1" start="10">

43

1
<li>传智播客</li>

44

1
<li>黑马程序员</li>

45

1
</ol>

46

1

47

1
<!--

48

1
斜体标签:<i>    <em>

49

1
-->

50

1
<i>我倾斜了</i>

51

1
<em>我倾斜了</em>

52

1
<br/>

53

1

54

1
<!--

55

1
加粗标签:<strong>  <b>

56

1
-->

57

1
<strong>加粗文本</strong>

58

1
<b>加粗文本</b>

59

1
<br/>

60

1
<!--

61

1
文字标签:<font>

62

1
属性:

63

1
size-大小

64

1
color-颜色

65

1
-->

66

1
<font size="5" color="yellow">这是一段文字</font>

67

1
</body>

68

1
</html>

效果如下

img

图片标签

img标签中的img其实是英文image的缩写, img标签的作用, 就是告诉浏览器我们需要显示一张图片

1

1
<img src="../img/b.jpg" width="400px" height="200px" alt="" title=""/>
属性名 作用
src 图片路径
title 鼠标悬停(hover)时显示文本。
alt 图片描述,图形不显示时的替换文本。
height 图像的高度。
width 图像的宽度。

超链接

超链接标签的作用: 就是用于控制页面与页面(服务器资源)之间跳转的

1

1
<a href="指定需要跳转的目标路径" target="打开的方式">需要展现给用户的内容</a>

2

1
target属性取值: 

3

1
_blank:新起页面

4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    _self:当前页面(默认)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>超链接标签演示</title>
<style>
a{
/*去掉超链接的下划线*/
text-decoration: none;
/*超链接的颜色*/
color: black;
}

/*鼠标悬浮的样式控制*/
a:hover{
color: red;
}
</style>
</head>
<body>
<!--
超链接标签:<a>
属性:
href-跳转的地址
target-跳转的方式(_self当前页面、_blank新标签页)
-->
<a href="01案例二:样式演示.html" target="_blank">点我跳转到样式演示</a> <br/>
<a href="http://www.itcast.cn" target="_blank">传智播客</a> <br/>
<a href="http://www.itheima.com" target="_self">黑马程序员</a> <br/>
<a href="http://www.itheima.com" target="_blank"><img src="../img/itheima.png" width="150px" height="50px"/></a>
</body>
</html>

效果图:

img

表单标签

基本介绍

form 表示表单,是用来收集用户输入信息并向 Web 服务器提交的一个容器

1
2
3
<form >
//表单元素
</form>
属性名 作用
action 处理此表单信息的Web服务器的URL地址
method 提交此表单信息到Web服务器的方式,可能的值有get和post,默认为get
autocomplete 自动补全,指示表单元素是否能够拥有一个默认值,配合input标签使用

get与post区别:

  • post:指的是 HTTP POST 方法;表单数据会包含在表单体内然后发送给服务器。
  • get:指的是 HTTP GET 方法;表单数据会附加在 action 属性的URI中,并以 ‘?’ 作为分隔符,然后这样得到的 URI 再发送给服务器。
地址栏可见 数据安全 数据大小
GET 可见 不安全 有限制(取决于浏览器)
POST 不可见 相对安全 无限制

表单元素

标签名 作用 备注
label 表单元素的说明,配合表单元素使用 for属性值为相关表单元素id属性值
input 表单中输入控件,多种输入类型,用于接受来自用户数据 type属性值决定输入类型
button 页面中可点击的按钮,可以配合表单进行提交 type属性值决定按钮类型
select 表单的控件,下拉选项菜单 与option配合实用
optgroup option的分组标签 与option配合实用
option select的子标签,表示一个选项
textarea 表示多行纯文本编辑控件
fieldset 用来对表单中的控制元素进行分组(也包括 label 元素)
legend 用于表示它的fieldset内容的标题。 fieldset 的子元素

按键控件

button标签:表示按钮

  • type属性:表示按钮类型,submit值为提交按钮。
属性值 作用 备注
button 无行为按钮,用于结合JavaScript实现自定义动态效果 同 ``
submit 提交按钮,用于提交表单数据到服务器。 同 ``
reset 重置按钮,用于将表单中内容恢复为默认值。 同`/>

输入控件

基本介绍
  • label标签:表单的说明。

    • for属性值:匹配input标签的id属性值
  • input标签:输入控件。

    属性:

    • type:表示输入类型,text值为普通文本框
    • id:表示标签唯一标识
    • name:表示标签名称,提交服务器的标识
    • value:表示标签的默认数据值
    • placeholder:默认的提示信息,仅适用于当type 属性为text, search, tel, url or email时;
    • required:是否必须为该元素填充值,当type属性是hidden,image或者button类型时不可使用
    • readonly:是否只读,可以让用户不修改这个输入框的值,就使用value属性设置默认值
    • disabled:是否可用,如果某个输入框有disabled那么它的数据不能提交到服务器通常是使用在有的页面中,让一些按钮不能点击
    • autocomplete:自动补全,规定表单或输入字段是否应该自动完成。当自动完成开启,浏览器会基于用户之前的输入值自动填写值。可以设置指定的字段为off,关闭自动补全
1
2
3
4
5
6
7
8
9
10
<body>
<form action="#" method="get" autocomplete="off">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" value="" placeholder=" 请在此处输入用户名" required/>
<button type="submit">提交</button>
<button type="reset">重置</button>
<button type="button">按钮</button>
</form>
</body>
</html>

效果图:

用户名: 提交 重置 按钮

n-v属性
属性名 作用
name 的名字,在提交整个表单数据时,可以用于区分属于不同的值
value 这个``元素当前的值,允许用户通过页面输入

使用方式:以name属性值作为键,value属性值作为值,构成键值对提交到服务器,多个键值对浏览器使用&进行分隔。

img

type属性
属性值 作用 备注
text 单行文本字段
password 单行文本字段,值被遮盖
email 用于编辑 e-mail 的字段,可以对e-mail地址进行简单校验
radio 单选按钮。 1. 在同一个”单选按钮组“中,所有单选按钮的 name 属性使用同一个值;一个单选按钮组中是,同一时间只有一个单选按钮可以被选择。 2. 必须使用 value 属性定义此控件被提交时的值。 3. 使用checked 必须指示控件是否缺省被选择。
checkbox 复选框。 1. 必须使用 value 属性定义此控件被提交时的值。 2. 使用 checked 属性指示控件是否被选择。 3. 选中多个值时,所有的值会构成一个数组而提交到Web服务器
date HTML5 用于输入日期的控件 年,月,日,不包括时间
time HTML5 用于输入时间的控件 不含时区
datetime-local HTML5 用于输入日期时间的控件 不包含时区
number HTML5 用于输入浮点数的控件
range HTML5 用于输入不精确值控件 max-规定最大值min-规定最小值 step-规定步进值 value-规定默认值
search HTML5 用于输入搜索字符串的单行文本字段 可以点击x清除内容
tel HTML5 用于输入电话号码的控件
url HTML5 用于编辑URL的字段 可以校验URL地址格式
file 此控件可以让用户选择文件,用于文件上传。 使用 accept 属性可以定义控件可以选择的文件类型。
hidden 此控件用户在页面上不可见,但它的值会被提交到服务器,用于传递隐藏值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>type属性演示</title>
</head>
<body>
<form action="#" method="get" autocomplete="off">
<label for="username">用户名:</label>
<input type="text" id="username" name="username"/> <br/>

<label for="password">密码:</label>
<input type="password" id="password" name="password"/> <br/>

<label for="email">邮箱:</label>
<input type="email" id="email" name="email"/> <br/>

<label for="gender">性别:</label>
<input type="radio" id="gender" name="gender" value="men"/>
<input type="radio" name="gender" value="women"/>
<input type="radio" name="gender" value="other"/>其他<br/>

<label for="hobby">爱好:</label>
<input type="checkbox" id="hobby" name="hobby" value="music" checked/>音乐
<input type="checkbox" name="hobby" value="game"/>游戏 <br/>

<label for="birthday">生日:</label>
<input type="date" id="birthday" name="birthday"/> <br/>

<label for="time">当前时间:</label>
<input type="time" id="time" name="time"/> <br/>

<label for="insert">注册时间:</label>
<input type="datetime-local" id="insert" name="insert"/> <br/>

<label for="age">年龄:</label>
<input type="number" id="age" name="age"/> <br/>

<label for="range">心情值(1~10):</label>
<input type="range" id="range" name="range" min="1" max="10" step="1"/> <br/>

<label for="search">可全部清除文本:</label>
<input type="search" id="search" name="search"/> <br/>

<label for="tel">电话:</label>
<input type="tel" id="tel" name="tel"/> <br/>

<label for="url">个人网站:</label>
<input type="url" id="url" name="url"/> <br/>

<label for="file">文件上传:</label>
<input type="file" id="file" name="file"/> <br/>

<label for="hidden">隐藏信息:</label>
<input type="hidden" id="hidden" name="hidden" value="itheima"/> <br/>

<button type="submit">提交</button>
<button type="reset">重置</button>
</form>
</body>
</html>

img

选择控件

下拉列表标签
密码:
爱好:学习 游戏

1
2
3
4
5

- 反射方式:

表单``标签的name属性取值,必须和实体类中定义的属性名称一致

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取请求正文的映射关系 Map map = req.getParameterMap(); //2.封装学生对象 Student stu = new Student(); //2.1遍历集合 for(String name : map.keySet()) { String[] value = map.get(name); try { //2.2获取Student对象的属性描述器 //参数一:指定获取xxx属性的描述器 //参数二:指定字节码文件 PropertyDescriptor pd = new PropertyDescriptor(name,stu.getClass()); //2.3获取对应的setXxx方法 Method writeMethod = pd.getWriteMethod(); //2.4执行方法 if(value.length > 1) { writeMethod.invoke(stu,(Object)value); }else { writeMethod.invoke(stu,value); } } catch (Exception e) { e.printStackTrace(); } } //3.输出对象 System.out.println(stu); }
1
2
3
4
5



- commons-beanutils封装

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取所有的数据 Map map = req.getParameterMap(); //2.封装学生对象 Student stu = new Student(); try { BeanUtils.populate(stu,map); } catch (Exception e) { e.printStackTrace(); } //3.输出对象 System.out.println(stu);

}

1
2
3
4
5
6
7
8
9





#### 流获取数据

`ServletInputStream getInputStream()` : 获取请求字节输入流对象 `BufferedReader getReader()` : 获取请求缓冲字符输入流对象

@WebServlet(“/servletDemo07”)
public class ServletDemo07 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//字符流(必须是post方式)
/BufferedReader br = req.getReader();
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
/
//br.close();
//字节流
ServletInputStream is = req.getInputStream();
byte[] arr = new byte[1024];
int len;
while((len = is.read(arr)) != -1) {
System.out.println(new String(arr,0,len));
}
//is.close();
}

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

}

1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40





### 请求域

#### 请求域

request 域:可以在一次请求范围内进行共享数据

| 方法 | 作用 |
| -------------------------------------------- | ---------------------------- |
| void setAttribute(String name, Object value) | 向请求域对象中存储数据 |
| Object getAttribute(String name) | 通过名称获取请求域对象的数据 |
| void removeAttribute(String name) | 通过名称移除请求域对象的数据 |





#### 请求转发

请求转发:客户端的一次请求到达后,需要借助其他 Servlet 来实现功能,进行请求转发。特点:

- 浏览器地址栏不变
- 域对象中的数据不丢失
- 负责转发的 Servlet 转发前后响应正文会丢失
- 由转发目的地来响应客户端

HttpServletRequest 类方法:

- `RequestDispatcher getRequestDispatcher(String path)` : 获取任务调度对象

RequestDispatcher 类方法:

- `void forward(ServletRequest request, ServletResponse response)` : 实现转发,将请求从 Servlet 转发到服务器上的另一个资源(Servlet,JSP 文件或 HTML 文件)

过程:浏览器访问 http://localhost:8080/request/servletDemo09,/servletDemo10也会执行

@WebServlet("/servletDemo09") public class ServletDemo09 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置共享数据 req.setAttribute("encoding","gbk"); //获取请求调度对象 RequestDispatcher rd = req.getRequestDispatcher("/servletDemo10"); //实现转发功能 rd.forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
1

@WebServlet("/servletDemo10") public class ServletDemo10 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取共享数据 Object encoding = req.getAttribute("encoding"); System.out.println(encoding);//gbk
    System.out.println("servletDemo10执行了...");
}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25





#### 请求包含

请求包含:合并其他的 Servlet 中的功能一起响应给客户端。特点:

- 浏览器地址栏不变
- 域对象中的数据不丢失
- 被包含的 Servlet 响应头会丢失

请求转发的注意事项:负责转发的 Servlet,转发前后的响应正文丢失,由转发目的地来响应浏览器

请求包含的注意事项:被包含者的响应消息头丢失,因为它被包含者包含起来了

HttpServletRequest 类方法:

- `RequestDispatcher getRequestDispatcher(String path)` : 获取任务调度对象

RequestDispatcher 类方法:

- `void include(ServletRequest request, ServletResponse response)` : 实现包含。包括响应中资源的内容(servlet,JSP页面,HTML文件)。

@WebServlet(“/servletDemo11”)
public class ServletDemo11 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(“servletDemo11执行了…”);//执行了
//获取请求调度对象
RequestDispatcher rd = req.getRequestDispatcher(“/servletDemo12”);
//实现包含功能
rd.include(req,resp);
}

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

}


@WebServlet(“/servletDemo12”)
public class ServletDemo12 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(“servletDemo12执行了…”);//输出了
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

1
2
3
4
5
6
7
8
9
10
11





### 乱码问题

请求体

- POST:`void setCharacterEncoding(String env)`:设置请求体的编码

@WebServlet(“/servletDemo08”)
public class ServletDemo08 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码格式
req.setCharacterEncoding(“UTF-8”);

      String username = req.getParameter("username");
      System.out.println(username);
  }

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

- GET:Tomcat8.5 版本及以后,Tomcat 服务器已经帮我们解决







## Response

### 响应对象

响应,服务器把请求的处理结果告知客户端

响应对象:在 JavaEE 工程中,用于发送响应的对象

- 协议无关的对象标准是:ServletResponse 接口
- 协议相关的对象标准是:HttpServletResponse 接口

Response 的作用:

- 操作响应的三部分(行, 头, 体)

- 请求重定向

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Response%E5%93%8D%E5%BA%94%E7%B1%BB%E8%A7%86%E5%9B%BE.png)



### 操作响应行

| 方法 | 说明 |
| ---------------------- | --------------------------------------------- |
| int getStatus() | Gets the current status code of this response |
| void setStatus(int sc) | Sets the status code for this response |

状态码:(HTTP-->相应部分)

| 状态码 | 说明 |
| :----: | :--------: |
| 1xx | 消息 |
| 2xx | 成功 |
| 3xx | 重定向 |
| 4xx | 客户端错误 |
| 5xx | 服务器错误 |





### 操作响应体

#### 字节流响应

响应体对应**乱码问题**

项目中常用的编码格式是UTF-8,而浏览器默认使用的编码是gbk。导致乱码!

解决方式: 一:修改浏览器的编码格式(不推荐,不能让用户做修改的动作) 二:通过输出流写出一个标签:<meta http-equiv='content-type'content='text/html;charset=UTF-8'> 三:指定响应头信息:response.setHeader("Content-Type","text/html;charset=UTF-8") 四:response.setContentType("text/html;charset=UTF-8")

常用API: `ServletOutputStream getOutputStream()` : 获取响应字节输出流对象 `void setContenType("text/html;charset=UTF-8")` : 设置响应内容类型,解决中文乱码问题

@WebServlet(“/servletDemo01”)
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置响应内容类型
resp.setContentType(“text/html;charset=UTF-8”);
//2.通过响应对象获取字节输出流对象
ServletOutputStream sos = resp.getOutputStream();
//3.定义消息
String str = “你好”;
//4.通过字节流输出对象
sos.write(str.getBytes(“UTF-8”));
}

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

}

1
2
3
4
5
6
7
8
9
10
11





#### 字符流响应

response得到的字符流和字节流互斥,只能选其一,response获取的流不用关闭,由服务器关闭即可。

常用API: `PrintWriter getWriter()` : 获取响应字节输出流对象,可以发送标签 `void setContenType("text/html;charset=UTF-8")` : 设置响应内容类型,解决中文乱码问题

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String str = “你好”;
//解决中文乱码
resp.setContentType(“text/html;charset=UTF-8”);
//获取字符流对象
PrintWriter pw = resp.getWriter();
pw.write(str);
}

1
2
3
4
5
6
7
8
9





#### 响应图片

响应图片到浏览器

@WebServlet(“/servletDemo03”)
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.通过文件的相对路径来获取文件的绝对路径
String realPath = getServletContext().getRealPath(“/img/hm.png”);
//E:\Project\JavaEE\out\artifacts\Response_war_exploded\img\hm.png
System.out.println(realPath);
//2.创建字节输入流对象,关联图片路径
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));

    //3.通过响应对象获取字节输出流对象
    ServletOutputStream sos = resp.getOutputStream();

    //4.循环读写
    byte[] arr = new byte[1024];
    int len;
    while((len = bis.read(arr)) != -1) {
        sos.write(arr,0,len);
    }
}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38







### 操作响应头

#### 常用方法

响应头: 是服务器指示浏览器去做什么

| 方法 | 说明 |
| ------------------------------------------ | ------------------------------------ |
| String getHeader(String name) | 获取指定响应头的内容 |
| Collection<String> getHeaders(String name) | 获取指定响应头的多个值 |
| Collection<String> getHeaderNames() | 获取所有响应头名称的枚举 |
| void setHeader(String name, String value) | 设置响应头 |
| void setDateHeader(String name, long date) | 设置具有给定名称和日期值的响应消息头 |
| void sendRedirect(String location) | 设置重定向 |

setHeader常用响应头:

- Expires:设置缓存时间
- Refresh:定时跳转
- Location:重定向地址
- Content-Disposition: 告诉浏览器下载
- Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)





#### 控制缓存

缓存:对于不经常变化的数据,我们可以设置合理的缓存时间,防止浏览器频繁的请求服务器。

@WebServlet(“/servletDemo04”)
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String news = “设置缓存时间”;
//设置缓存时间,缓存一小时
resp.setDateHeader(“Expires”,System.currentTimeMillis()+16060*1000L);
//设置编码格式
resp.setContentType(“text/html;charset=UTF-8”);
//写出数据
resp.getWriter().write(news);
System.out.println(“aaa”);//只输出一次,不能刷新,必须从网址直接进入
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Response%E8%AE%BE%E7%BD%AE%E7%BC%93%E5%AD%98%E6%97%B6%E9%97%B4.png)





#### 定时刷新

定时刷新:过了指定时间后,页面进行自动跳转

格式:`setHeader("Refresh", "3;URL=https://www.baidu.com"");` Refresh设置的时间单位是秒,如果刷新到其他地址,需要在时间后面拼接上地址

@WebServlet(“/servletDemo05”)
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String news = “您的用户名或密码错误,3秒后自动跳转到登录页面…”;
//设置编码格式
resp.setContentType(“text/html;charset=UTF-8”);
//写出数据
resp.getWriter().write(news);

    //设置响应消息头定时刷新
    resp.setHeader("Refresh","3;URL=/response/login.html");
}

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

}

1
2
3
4
5
6
7





#### 下载文件

@WebServlet(“/servletDemo06”)
public class ServletDemo06 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.创建字节输入流对象,关联读取的文件
String realPath = getServletContext().getRealPath(“/img/hm.png”);//绝对路径
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(realPath));

    //2.设置响应头支持的类型  应用支持的类型为字节流
    /*
        Content-Type 消息头名称   支持的类型
        application/octet-stream   消息头参数  应用类型为字节流
     */
    resp.setHeader("Content-Type","application/octet-stream");

    //3.设置响应头以下载方式打开  以附件形式处理内容
    /*
        Content-Disposition  消息头名称  处理的形式
        attachment;filename=  消息头参数  附件形式进行处理
     */
    resp.setHeader("Content-Disposition","attachment;filename=" + System.currentTimeMillis() + ".png");

    //4.获取字节输出流对象
    ServletOutputStream sos = resp.getOutputStream();

    //5.循环读写文件
    byte[] arr = new byte[1024];
    int len;
    while((len = bis.read(arr)) != -1) {
        sos.write(arr,0,len);
    }

    //6.释放资源
    bis.close();
}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28





#### 重定向

##### 实现重定向

请求重定向:客户端的一次请求到达后,需要借助其他 Servlet 来实现功能。特点:

1. 重定向两次请求
2. 重定向的地址栏路径改变
3. **重定向的路径写绝对路径**(带域名 /ip 地址,如果是同一个项目,可以省略域名 /ip 地址)
4. 重定向的路径可以是项目内部的,也可以是项目以外的(百度)
5. 重定向不能重定向到 WEB-INF 下的资源
6. 把数据存到 request 域里面,重定向不可用

实现方式:

- 方式一:
1. 设置响应状态码:`resp.setStatus(302)`
2. 设置重定向的路径(响应到哪里,通过响应头 location 来指定)
- `response.setHeader("Location","http://www.baidu.com");`
- `response.setHeader("Location","/response/servletDemo08);`
- 方式二:
- `resp.sendRedirect("重定向的路径");`

@WebServlet(“/servletDemo07”)
public class ServletDemo07 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求域数据
req.setAttribute(“username”,“zhangsan”);

    //设置重定向
    resp.sendRedirect(req.getContextPath() + "/servletDemo07");
	// resp.sendRedirect("https://www.baidu.com");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    doGet(req,resp);
}

}

1

@WebServlet(“/servletDemo08”)
public class ServletDemo08 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(“servletDemo08执行了…”);
Object username = req.getAttribute(“username”);
System.out.println(username);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43





##### 重定向和转发

请求重定向跳转的特点:

1. 重定向是由**浏览器发起**的,在这个过程中浏览器会发起**两次请求**
2. 重定向可以跳转到任意服务器的资源,但是**无法跳转到WEB-INF中的资源**
3. 重定向不能和请求域对象共享数据,数据会丢失
4. 重定向浏览器的地址栏中的地址会变成跳转到的路径

请求转发跳转的特点:

1. 请求转发是由**服务器发起**的,在这个过程中浏览器只会发起**一次请求**
2. 请求转发只能跳转到本项目的资源,但是**可以跳转到WEB-INF中的资源**
3. 请求转发可以和请求域对象共享数据,数据不会丢失
4. 请求转发浏览器地址栏不变

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/%E9%87%8D%E5%AE%9A%E5%90%91%E5%92%8C%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%E5%AF%B9%E6%AF%94%E5%9B%BE.jpg)





### 路径问题

**完整URL地址:**

1. 协议:http://
2. 服务器主机地址:127.0.0.1 or localhost
3. 服务器端口号:8080
4. 项目的虚拟路径(部署路径):/response
5. 具体的项目上资源路径 /login.html or Demo 的Servlet映射路径



**相对路径:**

不以"/"开头的路径写法,它是以目标路径相对当前文件的路径,其中".."表示上一级目录。

hello world....

访问ServletDemo05
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103



**绝对路径:**

绝对路径就是以"/"开头的路径写法,项目部署的路径





## Cookie

### 会话技术

**会话**:浏览器和服务器之间的多次请求和响应

浏览器和服务器可能产生多次的请求和响应,从浏览器访问服务器开始,到访问服务器结束(关闭浏览器、到了过期时间),这期间产生的多次请求和响应加在一起称为浏览器和服务器之间的一次对话

作用:保存用户各自的数据(以浏览器为单位),在多次请求间实现数据共享

**常用的会话管理技术**

- Cookie:客户端会话管理技术,用户浏览的信息以键值对(key=value)的形式保存在浏览器上。如果没有关闭浏览器,再次访问服务器,会把 cookie 带到服务端,服务端就可以做相应的处理

- Session:服务端会话管理技术。当客户端第一次请求 session 对象时,服务器为每一个浏览器开辟一块内存空间,并将通过特殊算法算出一个 session 的 ID,用来标识该 session 对象。由于内存空间是每一个浏览器独享的,所有用户在访问的时候,可以把信息保存在 session 对象中,同时服务器会把 sessionId 写到 cookie 中,再次访问的时候,浏览器会把 cookie(sessionId) 带过来,找到对应的 session 对象即可

tomcat 生成的 sessionID 叫做 jsessionID

两者区别:

- Cookie 存储在客户端中,而 Session 存储在服务器上,相对来说 Session 安全性更高。如果要在 Cookie 中存储一些敏感信息,不要直接写入 Cookie,应该将 Cookie 信息加密然后使用到的时候再去服务器端解密
- Cookie 一般用来保存用户信息,在 Cookie 中保存已经登录过得用户信息,下次访问网站的时候就不需要重新登录,因为用户登录的时候可以存放一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写),所以登录一次网站后访问网站其他页面不需要重新登录
- Session 通过服务端记录用户的状态,服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户
- Cookie 只能存储 ASCII 码,而 Session 可以存储任何类型的数据



参考文章:https://blog.csdn.net/weixin_43625577/article/details/92393581





### 基本介绍

Cookie:客户端会话管理技术,把要共享的数据保存到了客户端(也就是浏览器端)。每次请求时,把会话信息带到服务器,从而实现多次请求的数据共享。

作用:保存客户浏览器访问网站的相关内容(需要客户端不禁用 Cookie),从而在每次访问同一个内容时,先从本地缓存获取,使资源共享,提高效率。

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Cookie%E7%B1%BB%E8%AE%B2%E8%A7%A3.png)





### 基本使用

#### 常用API

- **Cookie属性:**

| 属性名称 | 属性作用 | 是否重要 |
| -------- | ------------------------ | -------- |
| name | cookie的名称 | 必要属性 |
| value | cookie的值(不能是中文) | 必要属性 |
| path | cookie的路径 | 重要 |
| domain | cookie的域名 | 重要 |
| maxAge | cookie的生存时间 | 重要 |
| version | cookie的版本号 | 不重要 |
| comment | cookie的说明 | 不重要 |

注意:Cookie 有大小,个数限制。每个网站最多只能存20个 Cookie,且大小不能超过 4kb。同时所有网站的 Cookie 总数不超过300个。

- **Cookie类API:**

- `Cookie(String name, String value)` : 构造方法创建 Cookie 对象
- Cookie 属性对应的 set 和 get 方法,name 属性被 final 修饰,没有 set 方法

- HttpServletResponse 类 API:

- `void addCookie(Cookie cookie)`:向客户端添加 Cookie,Adds cookie to the response

- HttpServletRequest类API:

- `Cookie[] getCookies()`:获取所有的 Cookie 对象,client sent with this request





#### 有效期

如果不设置过期时间,表示这个 Cookie 生命周期为浏览器会话期间,只要关闭浏览器窗口 Cookie 就消失,这种生命期为浏览会话期的 Cookie 被称为会话 Cookie,会话 Cookie 一般不保存在硬盘上而是保存在内存里。

如果设置过期时间,浏览器就会把 Cookie 保存到硬盘上,关闭后再次打开浏览器,这些 Cookie 依然有效直到超过设定的过期时间。存储在硬盘上的 Cookie 可以在**不同的浏览器进程间共享**,比如两个 IE 窗口,而对于保存在内存的 Cookie,不同的浏览器有不同的处理方式

设置 Cookie 存活时间 API:`void setMaxAge(int expiry)`

- -1:默认,代表 Cookie 数据存到浏览器关闭(保存在浏览器文件中)
- 0:代表删除 Cookie,如果要删除 Cookie 要确保**路径一致**
- 正整数:以秒为单位保存数据有有效时间(把缓存数据保存到磁盘中)

@WebServlet("/servletDemo01") public class ServletDemo01 extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.通过响应对象写出提示信息 resp.setContentType("text/html;charset=UTF-8"); PrintWriter pw = resp.getWriter(); pw.write("欢迎访问本网站,您的最后访问时间为:
");
    //2.创建Cookie对象,用于记录最后访问时间
    Cookie cookie = new Cookie("time",System.currentTimeMillis()+"");

    //3.设置最大存活时间
    cookie.setMaxAge(3600);
    //cookie.setMaxAge(0);    // 立即清除

    //4.将cookie对象添加到客户端
    resp.addCookie(cookie);

    //5.获取cookie
    Cookie[] cookies = req.getCookies();
    for(Cookie c : cookies) {
        if("time".equals(c.getName())) {
            //6.获取cookie对象中的value,进行写出
            String value = c.getValue();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            pw.write(sdf.format(Long.parseLong(value)));
        }
    }
}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98





#### 有效路径

`setPath(String url)` : Cookie 设置有效路径

有效路径作用 :

1. 保证不会携带别的网站/项目里面的 Cookie 到我们自己的项目
2. 路径不一样,Cookie 的 key 可以相同
3. 保证自己的项目可以合理的利用自己项目的 Cookie

判断路径是否携带 Cookie:请求资源 URI.startWith(cookie的path),返回 true 就带

| 访问URL | URI部分 | Cookie的Path | 是否携带Cookie | 能否取到Cookie |
| ------------------------------------------------------------ | -------------------------- | ------------ | -------------- | -------------- |
| [servletDemo02](http://localhost:8080/servlet/servletDemo02) | /servlet/servletDemo02 | /servlet/ || 能取到 |
| [servletDemo03](http://localhost:8080/servlet/servletDemo03) | /servlet/servletDemo03 | /servlet/ || 能取到 |
| [servletDemo04](http://localhost:8080/servlet/aaa/servletDemo03) | /servlet/aaa/servletDemo04 | /servlet/ || 能取到 |
| [servletDemo05](http://localhost:8080/bbb/servletDemo03) | /bbb/servletDemo04 | /servlet/ | 不带 | 不能取到 |

只有当访问资源的 url 包含此 cookie 的有效 path 的时候,才会携带这个 cookie

想要当前项目下的 Servlet 可以使用该 cookie,一般设置:`cookie.setPath(request.getContextPath())`





#### 安全性

如果 Cookie 中设置了 HttpOnly 属性,通过 js 脚本将无法读取到 cookie 信息,这样能有效的防止 XSS 攻击,窃取 cookie 内容,这样就增加了安全性,即便是这样,也不要将重要信息存入cookie。

XSS 全称 Cross SiteScript,跨站脚本攻击,是Web程序中常见的漏洞,XSS 属于被动式且用于客户端的攻击方式,所以容易被忽略其危害性。其原理是攻击者向有 XSS 漏洞的网站中输入(传入)恶意的 HTML 代码,当其它用户浏览该网站时,这段HTML代码会自动执行,从而达到攻击的目的。如盗取用户 Cookie、破坏页面结构、重定向到其它网站等。





## Session

### 基本介绍

Session:服务器端会话管理技术,本质也是采用客户端会话管理技术,不过在客户端保存的是一个特殊标识,共享的数据保存到了服务器的内存对象中。每次请求时,会将特殊标识带到服务器端,根据标识来找到对应的内存空间,从而实现数据共享。简单说它就是一个服务端会话对象,用于存储用户的会话数据

Session 域(会话域)对象是 Servlet 规范中四大域对象之一,并且它也是用于实现数据共享的

| 域对象 | 功能 | 创建 | 销毁 | 使用场景 |
| -------------- | ------ | ------------ | ----------------------------------------- | ------------------------------------------------------------ |
| ServletContext | 应用域 | 服务器启动 | 服务器关闭 | 在整个应用之间实现数据共享<br />(记录网站访问次数,聊天室) |
| ServletRequest | 请求域 | 请求到来 | 响应了这个请求 | 在当前请求或者请求转发之间实现数据共享 |
| HttpSession | 会话域 | getSession() | session过期,调用invalidate(),服务器关闭 | 在当前会话范围中实现数据共享,可以在多次请求中实现数据共享。<br />(验证码校验, 保存用户登录状态等) |





### 基本使用

#### 获取会话

HttpServletRequest类获取Session:

| 方法 | 说明 |
| ------------------------------------- | ----------------------------------------- |
| HttpSession getSession() | 获取HttpSession对象 |
| HttpSession getSession(boolean creat) | 获取HttpSession对象,未获取到是否自动创建 |

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Session%E8%8E%B7%E5%8F%96%E7%9A%84%E4%B8%A4%E4%B8%AA%E6%96%B9%E6%B3%95.png)





#### 常用API

| 方法 | 说明 |
| -------------------------------------------- | -------------------------------- |
| void setAttribute(String name, Object value) | 设置会话域中的数据 |
| Object getAttribute(String name) | 获取指定名称的会话域数据 |
| Enumeration<String> getAttributeNames() | 获取所有会话域所有属性的名称 |
| void removeAttribute(String name) | 移除会话域中指定名称的数据 |
| String getId() | 获取唯一标识名称,Jsessionid的值 |
| void invalidate() | 立即失效session |





#### 实现会话

通过第一个Servlet设置共享的数据用户名,并在第二个Servlet获取到

项目执行完以后,去浏览器抓包,Request Headers 中的 Cookie JSESSIONID的值是一样的

@WebServlet(“/servletDemo01”)
public class ServletDemo01 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求的用户名
String username = req.getParameter(“username”);
//2.获取HttpSession的对象
HttpSession session = req.getSession();
System.out.println(session);
System.out.println(session.getId());
//3.将用户名信息添加到共享数据中
session.setAttribute(“username”,username);
}

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

}

1

@WebServlet(“/servletDemo02”)
public class ServletDemo02 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取HttpSession对象
HttpSession session = req.getSession();
//2.获取共享数据
Object username = session.getAttribute(“username”);
//3.将数据响应给浏览器
resp.getWriter().write(username+“”);
}

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

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37





#### 生命周期

Session 的创建:一个常见的错误是以为 Session 在有客户端访问时就被创建,事实是直到某 server 端程序(如 Servlet)调用 `HttpServletRequest.getSession(true)` 这样的语句时才会被创建

Session 在以下情况会被删除:

- 程序调用 HttpSession.invalidate()
- 距离上一次收到客户端发送的 session id 时间间隔超过了 session 的最大有效时间
- 服务器进程被停止

注意事项:

- 客户端只保存 sessionID 到 cookie 中,而不会保存 session
- 关闭浏览器只会使存储在客户端浏览器内存中的 cookie 失效,不会使服务器端的 session 对象失效,同样也不会使已经保存到硬盘上的持久化cookie消失

打开两个浏览器窗口访问应用程序会使用的是不同的session,通常 session cookie 是不能跨窗口使用,当新开了一个浏览器窗口进入相同页面时,系统会赋予一个新的 session id,实现跨窗口信息共享:

- 先把 session id 保存在 persistent cookie 中(通过设置session的最大有效时间)
- 在新窗口中读出来,就可以得到上一个窗口的 session id,这样通过 session cookie 和 persistent cookie 的结合就可以实现跨窗口的会话跟踪





### 会话问题

#### 禁用Cookie

浏览器禁用Cookie解决办法:

- 方式一:通过提示信息告知用户

@WebServlet(“/servletDemo03”)
public class ServletDemo03 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取HttpSession对象
HttpSession session = req.getSession(false);
System.out.println(session);
if(session == null) {
resp.setContentType(“text/html;charset=UTF-8”);
resp.getWriter().write(“为了不影响正常的使用,请不要禁用浏览器的Cookie~”);
}
}

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

}

1
2
3

- 方式二:访问时拼接 jsessionid 标识,通过 encodeURL() 方法**重写地址**

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
//实现url重写 相当于在地址栏后面拼接了一个jsessionid
resp.getWriter().write(“go servletDemo03”);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53





#### 钝化活化

Session 存放在服务器端的内存中,可以做持久化管理。

钝化:序列化,持久态。把长时间不用,但还不到过期时间的 HttpSession 进行序列化写到磁盘上。

活化:相反的状态

何时钝化:

- 当访问量很大时,服务器会根据getLastAccessTime来进行排序,对长时间不用,但是还没到过期时间的HttpSession进行序列化(持久化)
- 当服务器进行重启的时候,为了保持客户HttpSession中的数据,也要对HttpSession进行序列化(持久化)

注意:

- HttpSession的持久化由服务器来负责管理,我们不用关心
- 只有实现了序列化接口的类才能被序列化







## JSP

### JSP概述

JSP(Java Server Page):是一种动态网页技术标准。(页面技术)

JSP是基于Java语言的,它的本质就是Servlet,一个特殊的Servlet。

JSP部署在服务器上,可以处理客户端发送的请求,并根据请求内容动态的生成HTML、XML或其他格式文档的Web网页,然后响应给客户端。

| 类别 | 适用场景 |
| ---------- | ------------------------------------------------------------ |
| HTML | 开发静态资源,不能包含java代码,无法添加动态数据。 |
| CSS | 美化页面 |
| JavaScript | 给网页添加动态效果 |
| Servlet | 编写java代码,实现后台功能处理,但是很不方便,开发效率低。 |
| JSP | 包括了显示页面技术,同时具备Servlet输出动态资源的能力。但是不适合作为控制器来用。 |



### 执行原理

- 新建JavaEE工程,编写index.jsp文件

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>

JSP的入门 这是第一个JSP页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37



- 执行过程:

客户端提交请求——Tomcat服务器解析请求地址——找到JSP页面——Tomcat将JSP页面翻译成Servlet的java文件——将翻译好的.java文件编译成.class文件——返回到客户浏览器上

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/JSP%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B.png)

- 溯源,打开JSP翻译后的Java文件

`public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase`,`public abstract class HttpJspBase extends HttpServlet implements HttpJspPage`,HttpJspBase是个抽象类继承HttpServlet,所以JSP本质上继承HttpServlet

在文件中找到了输出页面的代码,本质都是用out.write()输出的JSP语句

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Jsp%E7%9A%84%E6%9C%AC%E8%B4%A8%E8%AF%B4%E6%98%8E.png)



- 总结: JSP它是一个特殊的Servlet,主要是用于展示动态数据。它展示的方式是用流把数据输出出来,而我们在使用JSP时,涉及HTML的部分,都与HTML的用法一致,这部分称为jsp中的模板元素,决定了页面的外观。





### JSP语法

- JSP注释:

| 注释类型 | 方法 | 作用 |
| -------- | ---------------- | ------------------------------------------------------------ |
| JSP注释 | <%--注释内容--%> | 被jsp注释的部分不会被翻译成.java文件,不会在浏览器上显示 |
| HTML注释 | <!--HTML注释--> | 在Jsp中可以使用html的注释,但是只能注释html元素<br />被html注释部分会参与翻译,并且会在浏览器上显示 |
| Java注释 | //; /* */ | |

- Java代码块

<% 此处写java代码 %> <%--由tomcat负责翻译,翻译之后是service方法的成员变量--%>
1
2
3

- JSP表达式

<%=表达式%> <%--翻译成Service()方法里面的内容,相当于调用out.print()--%>
1
2
3

- JSP声明

<%! 声明的变量或方法 %> <%--翻译成Servlet类里面的内容--%>
1
2
3
4
5



- 语法示例:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> jsp语法 <%--1. 这是注释--%>
  <%--
      2.java代码块
      System.out.println("Hello JSP"); 普通输出语句,输出在控制台!!
      out.println("Hello JSP");out是JspWriter对象,输出在页面上
  --%>
  <%
      System.out.println("Hello JSP");
      out.println("Hello JSP<br>");
      String str = "hello<br>";
      out.println(str);
  %>

  <%--
      3.jsp表达式,相当于 out.println("Hello");
  --%>
  <%="Hello<br>"%>

  <%--
      4.jsp中的声明(变量或方法)
      如果加!  代表的是声明的是成员变量
      如果不加!  代表的是声明的是局部变量,页面显示abc
  --%>
  <%! String s = "abc";%>
  <% String s = "def";%>
  <%=s%>
  
  <%! public void getSum(){}%>
1

控制台输出:Hello JSP 页面输出: Hello JSP hello Hello def
1
2
3
4
5
6
7
8
9





### JSP指令

- **page指令:**

<%@ page 属性名=属性值 属性名=属性值... %>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

| 属性名 | 作用 |
| ------------ | ------------------------------------------------------------ |
| contentType | 设置响应正文支持的MIME类型和编码格式:contentType="text/html;charset=UTF-8" |
| language | 告知引擎,脚本使用的语言,默认为Java |
| errorPage | 当前页面出现异常后跳转的页面 |
| isErrorPage | 是否抓住异常。值为true页面中就能使用exception对象,打印异常信息。默认值false |
| import | 导入哪些包(类)<%@ page import="java.util.ArrayList" %> |
| session | 是否创建HttpSession对象,默认是true |
| buffer | 设定JspWriter用s输出jsp内容的缓存大小。默认8kb |
| pageEncoding | 翻译jsp时所用的编码格式,pageEncoding="UTF-8"相当于用UTF-8读取JSP |
| isELIgnored | 是否忽略EL表达式,默认值是false |

Note:当使用全局错误页面,就无须配置errorPage实现跳转错误页面,而是由服务器负责跳转到错误页面

- 配置全局错误页面:web.xml

java.lang.Exception /error.jsp 404 /404.html
1
2
3
4
5



- **include指令:**包含其他页面

<%@include file="被包含的页面" %>
1
2
3
4
5
6
7

属性:file,以/开头,就代表当前应用



- **taglib指令:**引入外部标签库

<%taglib uri="标签库的地址" prefix="前缀名称"%>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

html标签和jsp标签不用引入





### 隐式对象

#### 九大隐式对象

隐式对象:在jsp中可以不声明就直接使用的对象。它只存在于jsp中,因为java类中的变量必须要先声明再使用。 jsp中的隐式对象也并不是未声明,它是在翻译成.java文件时声明的,所以我们在jsp中可以直接使用。

| 隐式对象名称 | 类型 | 备注 |
| ------------ | -------------------------------------- | ----------------------------- |
| request | javax.servlet.http.HttpServletRequest | |
| response | javax.servlet.http.HttpServletResponse | |
| session | javax.servlet.http.HttpSession | Page指令可以控制开关 |
| application | javax.servlet.ServletContext | |
| page | Java.lang.Object | 当前jsp对应的servlet引用实例 |
| config | javax.servlet.ServletConfig | |
| exception | java.lang.Throwable | page指令有开关 |
| out | javax.servlet.jsp.JspWriter | 字符输出流,相当于printwriter |
| pageContext | javax.servlet.jsp.PageContext | 很重要,页面域 |



#### PageContext

- PageContext对象特点:

- PageContextd对象是JSP独有的对象,Servlet中没有
- PageContextd对象是一个**页面域(作用范围)对象**,还可以操作其他三个域对象中的属性
- PageContextd对象**可以获取其他八个隐式对象**
- PageContextd对象是一个局部变量,它的生命周期随着JSP的创建而诞生,随着JSP的结束而消失。每个JSP页面都有一个独立的PageContext

- PageContext方法如下,页面域操作的方法定义在了PageContext的父类JspContext中

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/PageContext%E6%96%B9%E6%B3%95%E8%AF%A6%E8%A7%A3.png)







### 四大域对象

| 域对象名称 | 范围 | 级别 | 备注 |
| -------------- | -------- | ------------------------ | ---------------------------------------- |
| PageContext | 页面范围 | 最小,只能在当前页面用 | 因范围太小,开发中用的很少 |
| ServletRequest | 请求范围 | 一次请求或当期请求转发用 | 当请求转发之后,再次转发时请求域丢失 |
| HttpSession | 会话范围 | 多次请求数据共享时使用 | 多次请求共享数据,但不同的客户端不能共享 |
| ServletContext | 应用范围 | 最大,整个应用都可以使用 | 尽量少用,如果对数据有修改需要做同步处理 |





### MVC模型

M : model, 通常用于封装数据,封装的是数据模型 V : view,通常用于展示数据。动态展示用jsp页面,静态数据展示用html C : controller,通常用于处理请求和响应,一般指的是Servlet

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/MVC%E6%A8%A1%E5%9E%8B.png)





## EL

### EL概述

EL表达式:Expression Language,意为表达式语言。它是Servlet规范中的一部分,是JSP2.0规范加入的内容。

EL表达式作用:在JSP页面中获取数据,让JSP脱离java代码块和JSP表达式

EL表达式格式: `${表达式内容}`

EL表达式特点:

- 有明确的**返回值**
- 把内容输出到**页面**
- **只能在四大域对象中获取数据**,不在四大域对象中的数据取不到。





### EL用法

#### 多种类型

EL表达式可以获取不同类型数据,前提是数据放入四大域对象。

<%@ page import="bean.Student" %> <%@ page import="java.util.ArrayList" %> <%@ page import="java.util.HashMap" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> EL表达式获取不同类型数据 <%--1.获取基本数据类型--%> <% pageContext.setAttribute("num",10); %> 基本数据类型:${num}
<%--2.获取自定义对象类型--%>
<%
    Student stu = new Student("张三",23);
    pageContext.setAttribute("stu",stu);
%>
自定义对象:${stu} <br>
<%--stu.name 实现原理 getName()--%>
学生姓名:${stu.name} <br>
学生年龄:${stu.age} <br>

<%--3.获取数组类型--%>
<%
    String[] arr = {"hello","world"};
    pageContext.setAttribute("arr",arr);
%>
数组:${arr}  <br>
0索引元素:${arr[0]} <br>
1索引元素:${arr[1]} <br>

<%--4.获取List集合--%>
<%
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    pageContext.setAttribute("list",list);
%>
List集合:${list} <br>
0索引元素:${list[0]} <br>

<%--5.获取Map集合--%>
<%
    HashMap<String,Student> map = new HashMap<>();
    map.put("hm01",new Student("张三",23));
    map.put("hm02",new Student("李四",24));
    pageContext.setAttribute("map",map);
%>
Map集合:${map}  <br>
第一个学生对象:${map.hm01}  <br>
第一个学生对象的姓名:${map.hm01.name}

<–页面输出效果
基本数据类型:10
自定义对象:bean.Student@5f8da92c (地址)
学生姓名:张三
学生年龄:23
数组:[Ljava.lang.String;@4b3bd520
0索引元素:hello
1索引元素:world
List集合:[aaa, bbb]
0索引元素:aaa
Map集合:{hm01=bean.Student@4768d250, hm02=bean.Student@67f237d9}
第一个学生对象:bean.Student@4768d250
第一个学生对象的姓名:张三
–>

1
2
3
4
5
6
7
8
9
10
11
12
13





#### 异常问题

EL表达式的注意事项:

1. EL表达式没有空指针异常
2. EL表达式没有数组下标越界
3. EL表达式没有字符串拼接

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>

EL表达式的注意事项 第一个:没有空指针异常
<% String str = null; request.setAttribute("testNull",str); %> str:${testNull}
第二个:没有数组下标越界
<% String[] strs = new String[]{"a","b","c"}; request.setAttribute("strs",strs); %> 取第一个元素:${strs[0]}
取第六个元素:${strs[5]}

第三个:没有字符串拼接
<%--${strs[0]+strs[1]}--%> 拼接:${strs[0]}+${strs[1]} <%--注意拼接--%>

<–页面输出效果
第一个:没有空指针异常
str:
第二个:没有数组下标越界
取第一个元素:a
取第六个元素:
第三个:没有字符串拼接
拼接:a+b
–>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28





#### 运算符

EL表达式中运算符:

- 关系运算符:![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/EL%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%85%B3%E7%B3%BB%E8%BF%90%E7%AE%97%E7%AC%A6.png)

- 逻辑运算符:

| 逻辑运算符 | 说明 |
| ---------- | ---- |
| && 或 and | 交集 |
| \|\| 或 or | 并集 |
| ! 或 not ||



- 其他运算符

| 运算符 | 作用 |
| ------------------------ | ------------------------------------------------------------ |
| empty | 1. 判断对象是否为null<br />2. 判断字符串是否为空字符串<br />3. 判断容器元素是否为0 |
| 条件 ? 表达式1 : 表达式2 | 三元运算符,条件?真:假 |

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>

EL表达式运算符 <%--empty--%> <% String str1 = null; String str2 = ""; int[] arr = {}; %> ${empty str1}
${empty str2}
${empty arr}
<%--三元运算符。获取性别的数据,在对应的按钮上进行勾选--%>
<% pageContext.setAttribute("gender","women"); %>
<input type="radio" name="gender" value="men" ${gender=="men"?"checked":""}>男
<input type="radio" name="gender" value="women" ${gender=="women"?"checked":""}>女
1
2
3
4
5
6
7
8
9
10
11

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/EL%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%BF%90%E7%AE%97%E7%AC%A6%E6%95%88%E6%9E%9C%E5%9B%BE.png)





#### 四大域数据

EL表达式只能从从四大域中获取数据,调用的就是`findAttribute(name,value);`方法,根据名称由小到大在域对象中查找,找到就返回,找不到就什么都不显示。

<%@ page contentType="text/html;charset=UTF-8" language="java" %> EL表达式使用细节 <%--获取四大域对象中的数据--%> <% //pageContext.setAttribute("username","zhangsan"); request.setAttribute("username","zhangsan"); //session.setAttribute("username","zhangsan"); //application.setAttribute("username","zhangsan"); %> ${username}
<%--获取JSP中其他八个隐式对象  获取虚拟目录名称--%>
<%= request.getContextPath()%>
${pageContext.request.contextPath}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25





### EL隐式对象

#### EL表达式隐式对象

EL表达式也为我们提供隐式对象,可以让我们不声明直接来使用,需要注意的是,它和JSP的隐式对象不是同一种事物。

| EL中的隐式对象 | 类型 | 对应JSP隐式对象 | 备注 |
| ---------------- | ----------------------------- | --------------- | --------------------------------------- |
| PageContext | Javax.serlvet.jsp.PageContext | PageContext | 完全一样 |
| ApplicationScope | Java.util.Map | 没有 | 应用层范围 |
| SessionScope | Java.util.Map | 没有 | 会话范围 |
| RequestScope | Java.util.Map | 没有 | 请求范围 |
| PageScope | Java.util.Map | 没有 | 页面层范围 |
| Header | Java.util.Map | 没有 | 请求消息头key,值是value(一个) |
| HeaderValues | Java.util.Map | 没有 | 请求消息头key,值是数组(一个头多个值) |
| Param | Java.util.Map | 没有 | 请求参数key,值是value(一个) |
| ParamValues | Java.util.Map | 没有 | 请求参数key,值是数组(一个名称多个值) |
| InitParam | Java.util.Map | 没有 | 全局参数,key是参数名称,value是参数值 |
| Cookie | Java.util.Map | 没有 | Key是cookie的名称,value是cookie对象 |

<%@ page contentType="text/html;charset=UTF-8" language="java" %> EL表达式11个隐式对象 <%--pageContext对象 可以获取其他三个域对象和JSP中八个隐式对象--%> ${pageContext.request.contextPath}
<%--applicationScope sessionScope requestScope pageScope 操作四大域对象中的数据--%>
<% request.setAttribute("username","zhangsan"); %>
${username} <br>
${requestScope.username} <br>

<%--header headerValues  获取请求头数据--%>
${header["connection"]} <br>
${headerValues["connection"][0]} <br>

<%--param paramValues 获取请求参数数据--%>
${param.username} <br>
${paramValues.hobby[0]} <br>
${paramValues.hobby[1]} <br>

<%--initParam 获取全局配置参数--%>
${initParam["pname"]}  <br>

<%--cookie 获取cookie信息--%>
${cookie}  <br> <%--获取Map集合--%>
${cookie.JSESSIONID}  <br> <%--获取map集合中第二个元素--%>
${cookie.JSESSIONID.name}  <br> <%--获取cookie对象的名称--%>
${cookie.JSESSIONID.value} <%--获取cookie对象的值--%>
<--页面显示 /el zhangsan zhangsan keep-alive keep-alive

bbb
{JSESSIONID=javax.servlet.http.Cookie@435c8431, Idea-5a5d203e=javax.servlet.http.Cookie@46be0b58, Idea-be3279e7=javax.servlet.http.Cookie@4ef6e8e8}
javax.servlet.http.Cookie@435c8431
JSESSIONID
E481B2A845A448AD88A71FD43611FF02
–>

1
2
3

在web.xml配置全局参数

<web-app ******>


pname
bbb

1
2
3
4
5
6
7
8
9





#### 获取JSP隐式对象

通过获取页面域对象,获取其他JSP八个隐式对象

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>

EL表达式使用细节 <%--获取虚拟目录名称--%> <%= request.getContextPath()%> ${pageContext.request.contextPath} <--页面显示 /el /el -->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31







### JSTL

JSTL:Java Server Pages Standarded Tag Library,JSP中标准标签库。

作用:提供给开发人员一个标准的标签库,开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。

| 组成 | 作用 | 说明 |
| --------- | ---------- | ------------------------------ |
| Core | 核心标签库 | 通用逻辑处理 |
| Fmt | 国际化有关 | 需要不同地域显示不同语言时使用 |
| Functions | EL函数 | EL表达式可以使用的方法 |
| SQL | 操作数据库 | |
| XML | 操作XML | |

使用:添加jar包,通过taglib导入,prefix属性表示程序调用标签使用的引用名

| 标签名称 | 功能分类 | 分类 | 作用 |
| -------- | -------- | ---------- | ---------------- |
| `` | 流程控制 | 核心标签库 | 用于判断 |
| ` ,,` | 流程控制 | 核心标签库 | 用于多个条件判断 |
| `` | 迭代操作 | 核心标签库 | 用于循环遍历 |

- 流程控制

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 流程控制 <%--向域对象中添加成绩数据--%> ${pageContext.setAttribute("score","T")}
  <%--对成绩进行判断--%>
  <c:if test="${score eq 'A'}">
      优秀
  </c:if>

  <%--对成绩进行多条件判断--%>
  <c:choose>
      <c:when test="${score eq 'A'}">优秀</c:when>
      <c:when test="${score eq 'B'}">良好</c:when>
      <c:when test="${score eq 'C'}">及格</c:when>
      <c:when test="${score eq 'D'}">较差</c:when>
      <c:otherwise>成绩非法</c:otherwise>
  </c:choose>
1
2
3
4
5
6
7
8
9
10
11
12

- 迭代操作 c:forEach:用来遍历集合,属性:

| 属性 | 作用 |
| --------- | ------------------------------------------------------------ |
| items | 指定要遍历的集合,它可以是用EL表达式取出来的元素 |
| var | 把当前遍历的元素放入指定的page域中。var的值是key,遍历的元素是value<br />注意:var不支持EL表达式,只能是字符串常量 |
| begin | 开始遍历的索引 |
| end | 结束遍历的索引 |
| step | 步长,i+=step |
| varStatus | 它是一个计数器对象,有两个属性,一个是用于记录索引,一个是用于计数。索引是从0开始,计数是从1开始 |

<%@ page import="java.util.ArrayList" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 循环 <%--向域对象中添加集合--%> <% ArrayList list = new ArrayList<>(); list.add("aa"); list.add("bb"); list.add("cc"); list.add("dd"); pageContext.setAttribute("list",list); %> <%--遍历集合--%> ${str}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37





## Filter

### 过滤器

Filter:过滤器,是 JavaWeb 三大组件之一,另外两个是 Servlet 和 Listener

工作流程:在程序访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与去请求资源相关联,如果有过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源,如果没有就直接请求资源,响应同理

作用:过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等





### 相关类

#### Filter

Filter是一个接口,如果想实现过滤器的功能,必须实现该接口

- 核心方法

| 方法 | 说明 |
| ------------------------------------------------------------ | ------------------------ |
| void init(FilterConfig filterConfig) | 初始化,开启过滤器 |
| void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 对请求资源和响应资源过滤 |
| void destroy() | 销毁过滤器 |

- 配置方式

注解方式

@WebFilter("/*") ()内填拦截路径,/*代表全部路径
1
2
3

配置文件

filterDemo01 filter.FilterDemo01 filterDemo01 /*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44





#### FilterChain

- FilterChain 是一个接口,代表过滤器对象。由Servlet容器提供实现类对象,直接使用即可。

- 过滤器可以定义多个,就会组成过滤器链

- 核心方法:`void doFilter(ServletRequest request, ServletResponse response)` 用来放行方法

如果有多个过滤器,在第一个过滤器中调用下一个过滤器,以此类推,直到到达最终访问资源。 如果只有一个过滤器,放行时就会直接到达最终访问资源。



#### FilterConfig

FilterConfig 是一个接口,代表过滤器的配置对象,可以加载一些初始化参数

| 方法 | 作用 |
| ------------------------------------------- | -------------------------------------------- |
| String getFilterName() | 获取过滤器对象名称 |
| String getInitParameter(String name) | 获取指定名称的初始化参数的值,不存在返回null |
| Enumeration<String> getInitParameterNames() | 获取所有参数的名称 |
| ServletContext getServletContext() | 获取应用上下文对象 |







### Filter使用

#### 设置页面编码

请求先被过滤器拦截进行相关操作

过滤器放行之后执行完目标资源,仍会回到过滤器中

- Filter 代码:

@WebFilter("/*") public class FilterDemo01 implements Filter{ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo01拦截到请求..."); //处理乱码 servletResponse.setContentType("text/html;charset=UTF-8"); //过滤器放行 filterChain.doFilter(servletRequest,servletResponse); System.out.println("filterDemo1放行之后,又回到了doFilter方法"); } }
1
2
3

- Servlet 代码:

@WebServlet("/servletDemo01") public class ServletDemo01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servletDemo01执行了..."); resp.getWriter().write("servletDemo01执行了..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
1
2
3

- 控制台输出:

filterDemo01拦截到请求... servletDemo01执行了... filterDemo1放行之后,又回到了doFilter方法
1
2
3
4
5
6
7
8
9
10
11





#### 多过滤器顺序

多个过滤器使用的顺序,取决于过滤器映射的顺序。

- 两个 Filter 代码:

public class FilterDemo01 implements Filter{ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo01执行了..."); filterChain.doFilter(servletRequest,servletResponse); } } public class FilterDemo02 implements Filter{ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo02执行了..."); filterChain.doFilter(servletRequest,servletResponse); } }
1
2
3
4
5

- Servlet代码:`System.out.println("servletDemo02执行了...");`

- web.xml配置:

filterDemo01 filter.FilterDemo01 filterDemo01 /* filterDemo02 filter.FilterDemo02 filterDemo02 /*
1
2
3

- 控制台输出:

filterDemo01执行了 filterDemo02执行了 servletDemo02执行了...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21



在过滤器的配置中,有过滤器的声明和过滤器的映射两部分,到底是声明决定顺序,还是映射决定顺序呢?

答案是:``的配置前后顺序决定过滤器的调用顺序,也就是由映射配置顺序决定。





#### Filter生命周期

**创建:**当应用加载时实例化对象并执行init()初始化方法

**服务:**对象提供服务的过程,执行doFilter()方法

**销毁**:当应用卸载时或服务器停止时对象销毁,执行destroy()方法

- Filter代码:

@WebFilter("/*") public class FilterDemo03 implements Filter{ /* 初始化方法 */ @Override public void init(FilterConfig filterConfig) { System.out.println("对象初始化成功了..."); } /* 提供服务方法 */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo03执行了..."); //过滤器放行 filterChain.doFilter(servletRequest,servletResponse); } /* 对象销毁方法,关闭Tomcat服务器 */ @Override public void destroy() { System.out.println("对象销毁了..."); } }
1
2
3
4
5

- Servlet 代码:`System.out.println("servletDemo03执行了...");`

- 控制台输出:

对象初始化成功了... filterDemo03执行了... servletDemo03执行了... 对象销毁了
1
2
3
4
5
6
7
8
9
10
11





#### FilterConfig使用

Filter初始化函数init的参数是FilterConfig 对象

- Filter代码:

public class FilterDemo04 implements Filter{
//初始化方法
  @Override
  public void init(FilterConfig filterConfig) {
      System.out.println("对象初始化成功了...");

      //获取过滤器名称
      String filterName = filterConfig.getFilterName();
      System.out.println(filterName);

      //根据name获取value
      String username = filterConfig.getInitParameter("username");
      System.out.println(username);
  }
  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
      System.out.println("filterDemo04执行了...");
      filterChain.doFilter(servletRequest,servletResponse);
  }
  @Override
  public void destroy() {}

}

1
2
3

- web.xml配置

filterDemo04 filter.FilterDemo04 username zhangsan filterDemo04 /*
1
2
3

- 控制台输出:

对象初始化成功了... filterDemo04 zhangsan
1
2
3
4
5
6
7
8
9
10
11
12
13





### Filter案例

在访问html,js,image时,不需要每次都重新发送请求读取资源,就可以通过设置响应消息头的方式,设置缓存时间。但是如果每个Servlet都编写相同的代码,显然不符合我们统一调用和维护的理念。

静态资源设置缓存时间:html设置为1小时,js设置为2小时,css设置为3小时

- 配置过滤器

StaticResourceNeedCacheFilter filter.StaticResourceNeedCacheFilter html 3 js 4 css 5 StaticResourceNeedCacheFilter *.html StaticResourceNeedCacheFilter *.js StaticResourceNeedCacheFilter *.css
1
2
3

- 编写过滤器

public class StaticResourceNeedCacheFilter implements Filter { private FilterConfig filterConfig;//获取初始化参数 @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; }
  @Override
  public void doFilter(ServletRequest req, ServletResponse res,
                       FilterChain chain) throws IOException, ServletException {
      //1.把doFilter的请求和响应对象转换成跟http协议有关的对象
      HttpServletRequest  request;
      HttpServletResponse response;
      try {
          request = (HttpServletRequest) req;
          response = (HttpServletResponse) res;
      } catch (ClassCastException e) {
          throw new ServletException("non-HTTP request or response");
      }
      //2.获取请求资源URI
      String uri = request.getRequestURI();
      //3.得到请求资源到底是什么类型
      String extend = uri.substring(uri.lastIndexOf(".")+1);//我们只需要判断它是不是html,css,js。其他的不管
      //4.判断到底是什么类型的资源
      long time = 60*60*1000;
      if("html".equals(extend)){
          //html 缓存1小时
          String html = filterConfig.getInitParameter("html");
          time = time*Long.parseLong(html);
      }else if("js".equals(extend)){
          //js 缓存2小时
          String js = filterConfig.getInitParameter("js");
          time = time*Long.parseLong(js);
      }else if("css".equals(extend)){
          //css 缓存3小时
          String css = filterConfig.getInitParameter("css");
          time = time*Long.parseLong(css);

      }
      //5.设置响应消息头
      response.setDateHeader("Expires", System.currentTimeMillis()+time);
      //6.放行
      chain.doFilter(request, response);
  }
  
  @Override
  public void destroy() {}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15







### 拦截行为

Filter过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调用的全局错误页面。默认情况下过滤器是不参与过滤的,需要配置web.xml

开启功能后,当访问页面发生相关行为后,会执行过滤器的操作

五种拦截行为:

FilterDemo5 filter.FilterDemo5 true FilterDemo5 /error.jsp REQUEST ERROR FORWARD INCLUDE ASYNC
1
2
3

- web.xml:

FilterDemo5 filter.FilterDemo5 true FilterDemo5 /error.jsp ERROR
1
2
3

- ServletDemo03:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servletDemo03执行了..."); int i = 1/ 0; }
1
2
3

- FilterDemo05:

public class FilterDemo05 implements Filter{ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filterDemo05执行了..."); //放行 filterChain.doFilter(servletRequest,servletResponse); } }
1
2
3
4
5

- 访问URLhttp://localhost:8080/filter/servletDemo03

- 控制台输出(注意输出顺序):

servletDemo03执行了... filterDemo05执行了...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146





### 对比Servlet

| 方法/类型 | Servlet | Filter | 备注 |
| -------------------------------------------------- | --------------------------------- | --------------------------------------------- | ------------------------------------------------------------ |
| 初始化 方法 | void init(ServletConfig); | void init(FilterConfig); | 几乎一样,都是在web.xml中配置参数,用该对象的方法可以获取到。 |
| 提供服务方法 | void service(request,response); | void dofilter(request,response,FilterChain) | Filter比Servlet多了一个FilterChain,它不仅能完成Servlet的功能,而且还可以决定程序是否能继续执行。所以过滤器比Servlet更为强大。 在Struts2中,核心控制器就是一个过滤器。 |
| 销毁方法 | void destroy(); | void destroy(); | 方法/类型 |









## Listener

### 观察者设计者

所有的监听器都是基于观察者设计模式的。

观察者模式通常由以下三部分组成:

- 事件源:触发事件的对象。
- 事件:触发的动作,里面封装了事件源。
- 监听器:当事件源触发事件后,可以完成的功能。一般是一个接口,由使用者来实现。(此处的思想还涉及了一个策略模式)





### 监听器分类

在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听。

Servlet规范中共计8个监听器,**监听器都是以接口形式提供**,具体功能需要我们自己完成

#### 监听对象

- ServletContextListener:用于监听ServletContext对象的创建和销毁

| 方法 | 作用 |
| ------------------------------------------------ | -------------------- |
| void contextInitialized(ServletContextEvent sce) | 对象创建时执行该方法 |
| void contextDestroyed(ServletContextEvent sce) | 对象销毁时执行该方法 |

参数ServletContextEvent 代表事件对象,事件对象中封装了事件源ServletContext,真正的事件指的是创建或者销毁ServletContext对象的操作

- HttpSessionListener:用于监听HttpSession对象的创建和销毁

| 方法 | 作用 |
| ------------------------------------------ | :------------------- |
| void sessionCreated(HttpSessionEvent se) | 对象创建时执行该方法 |
| void sessionDestroyed(HttpSessionEvent se) | 对象销毁时执行该方法 |

参数HttpSessionEvent 代表事件对象,事件对象中封装了事件源HttpSession,真正的事件指的是创建或者销毁HttpSession对象的操作

- ServletRequestListener:用于监听ServletRequest对象的创建和销毁

| 方法 | 作用 |
| ------------------------------------------------ | :------------------- |
| void requestInitialized(ServletRequestEvent sre) | 对象创建时执行该方法 |
| void requestDestroyed(ServletRequestEvent sre) | 对象销毁时执行该方法 |

参数ServletRequestEvent 代表事件对象,事件对象中封装了事件源ServletRequest,真正的事件指的是创建或者销毁ServletRequest对象的操作





#### 监听域对象属性

- ServletContextAttributeListener:用于监听ServletContext应用域中属性的变化

| 方法 | 作用 |
| ---------------------------------------------------------- | ------------------------ |
| void attributeAdded(ServletContextAttributeEvent event) | 域中添加属性时执行该方法 |
| void attributeRemoved(ServletContextAttributeEvent event) | 域中移除属性时执行该方法 |
| void attributeReplaced(ServletContextAttributeEvent event) | 域中替换属性时执行该方法 |

参数ServletContextAttributeEvent 代表事件对象,事件对象中封装了事件源ServletContext,真正的事件指的是添加、移除、替换应用域中属性的操作

- HttpSessionAttributeListener:用于监听HttpSession会话域中属性的变化

| 方法 | 作用 |
| ----------------------------------------------------- | ------------------------ |
| void attributeAdded(HttpSessionBindingEvent event) | 域中添加属性时执行该方法 |
| void attributeRemoved(HttpSessionBindingEvent event) | 域中移除属性时执行该方法 |
| void attributeReplaced(HttpSessionBindingEvent event) | 域中替换属性时执行该方法 |

参数HttpSessionBindingEvent 代表事件对象,事件对象中封装了事件源HttpSession,真正的事件指的是添加、移除、替换应用域中属性的操作

- ServletRequestAttributeListener:用于监听ServletRequest请求域中属性的变化

| 方法 | 作用 |
| --------------------------------------------------------- | ------------------------ |
| void attributeAdded(ServletRequestAttributeEvent srae) | 域中添加属性时执行该方法 |
| void attributeRemoved(ServletRequestAttributeEvent srae) | 域中移除属性时执行该方法 |
| void attributeReplaced(ServletRequestAttributeEvent srae) | 域中替换属性时执行该方法 |

参数ServletRequestAttributeEvent 代表事件对象,事件对象中封装了事件源ServletRequest,真正的事件指的是添加、移除、替换应用域中属性的操作

- 页面域对象没有监听器





#### 感知型监听器

监听会话相关的感知型监听器,和会话域相关的两个感知型监听器是无需配置(注解)的,可以直接编写代码

- HttpSessionBindingListener:用于感知对象和会话域绑定的监听器

| 方法 | 作用 |
| ------------------------------------------------ | ------------------------------------ |
| void valueBound(HttpSessionBindingEvent event) | 数据添加到会话域中(绑定)时执行该方法 |
| void valueUnbound(HttpSessionBindingEvent event) | 数据从会话域中移除(解绑)时执行该方法 |

参数HttpSessionBindingEvent 代表事件对象,事件对象中封装了事件源HttpSession,真正的事件指的是添加、移除、替换应用域中属性的操作

- HttpSessionActivationListener:用于感知会话域中对象和钝化和活化的监听器

| 方法 | 作用 |
| ---------------------------------------------- | ---------------------------- |
| void sessionWillPassivate(HttpSessionEvent se) | 会话域中数据钝化时执行该方法 |
| void sessionDidActivate(HttpSessionEvent se) | 会话域中数据活化时执行该方法 |





### 监听器使用

#### ServletContextListener

ServletContext对象的创建和销毁的监听器

注解方式:

@WebListener public class ServletContextListenerDemo implements ServletContextListener { //创建时执行此方法 @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("监听到对象的创建....");//启动服务器就创建
    ServletContext servletContext = sce.getServletContext();
    System.out.println(servletContext);
}
//销毁时执行的方法
@Override
public void contextDestroyed(ServletContextEvent sce) {
    System.out.println("监听到对象的销毁...");//关闭服务器就销毁
}

}

1
2
3

配置web.xml

listener.ServletContextAttributeListenerDemo
1
2
3
4
5
6
7
8
9





#### ServletContextAttributeListener

应用域对象中的属性变化的监听器

public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener{ /* 向应用域对象中添加属性时执行此方法 */ @Override public void attributeAdded(ServletContextAttributeEvent scae) { System.out.println("监听到了属性的添加...");
    //获取应用域对象
    ServletContext servletContext = scae.getServletContext();
    //获取属性
    Object value = servletContext.getAttribute("username");
    System.out.println(value);//zhangsan 
}

/*
    向应用域对象中替换属性时执行此方法
 */
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
    System.out.println("监听到了属性的替换...");

    //获取应用域对象
    ServletContext servletContext = scae.getServletContext();
    //获取属性
    Object value = servletContext.getAttribute("username");
    System.out.println(value);//lisi
}

/*
    向应用域对象中移除属性时执行此方法
 */
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
    System.out.println("监听到了属性的移除...");

    //获取应用域对象
    ServletContext servletContext = scae.getServletContext();
    //获取属性
    Object value = servletContext.getAttribute("username");
    System.out.println(value);//null
}

}

1

public class ServletContextListenerDemo implements ServletContextListener{
//ServletContext对象创建的时候执行此方法
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(“监听到了对象的创建…”);
//获取对象
ServletContext servletContext = sce.getServletContext();

    //添加属性
    servletContext.setAttribute("username","zhangsan");

    //替换属性
    servletContext.setAttribute("username","lisi");

    //移除属性
    servletContext.removeAttribute("username");
}

//ServletContext对象销毁的时候执行此方法
@Override
public void contextDestroyed(ServletContextEvent sce) {
    System.out.println("监听到了对象的销毁...");
}

}

1
2
3

控制台输出:

监听到了对象的创建…
监听到了属性的添加…
zhangsan
监听到了属性的替换
lisi
监听到属性的移除
null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37











# JS

## 概述

JavaScript 是一种客户端脚本语言。运行在客户端浏览器中,每一个浏览器都具备解析 JavaScript 的引擎。

脚本语言:不需要编译,就可以被浏览器直接解析执行了。

作用:增强用户和 HTML 页面的交互过程,让页面产生动态效果,增强用户的体验。

组成部分:ECMAScript、DOM、BOM

开发环境搭建:安装Node.js,是JavaScript运行环境





## 语法

### 引入

引入HTML文件

- 内部方式:<script>标签

JS快速入门
1
2
3
4
5

- 外部方式

- 创建js文件:my.js

alert("Hello");//js语句
1
2
3

- 在html中引用外部js文件

1
2
3
4
5
6
7
8
9





### 注释

- 单行注释

// 注释的内容
1
2
3

- 多行注释

/* 注释的内容 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25



### 输入输出

- 输入框:prompt(“提示内容”);

- 弹出警告框:alert(“提示内容”);

- 控制台输出:console.log(“显示内容”);

- 页面内容输出:document.write(“显示内容”);

注:`document.write(" ")`换行,通常输出数据后跟br标签





### 变量常量

JavaScript 属于弱类型的语言,定义变量时不区分具体的数据类型

- 定义局部变量:let 变量名 = 值;

let name = "张三"; let age = 23; document.write(name + "," + age +"
");
1
2
3

- 定义全局变量:变量名 =;

{ l2 = "bb"; } document.write(l2 + "
");
1
2
3

- 定义常量:const 常量名 =; 常量不能被重新赋值

const PI = 3.1415926; //PI = 3.15; document.write(PI);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18





### 数据类型

| 数据类型 | 说明 |
| --------- | ---------------------------- |
| boolean | 布尔类型,true或false |
| null | 声明null值的特殊关键字 |
| undefined | 代表变量未定义 |
| number | 整数或浮点数 |
| string | 字符串 |
| bigint | 大整数,例如:let num = 10n; |

**typeof 用于判断变量的数据类型**

let age = 18; document.write(typeof(age)); // number
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63





### 运算符

- 算术运算符

| 算术运算符 | 说明 |
| ---------- | -------- |
| + | 加法运算 |
| - | 减法运算 |
| * | 乘法运算 |
| / | 除法运算 |
| % | 取余数 |
| ++ | 自增 |
| -- | 自减 |

- 赋值运算符

| 赋值运算符 | 说明 |
| ---------- | -------- |
| = | 加法运算 |
| += | 减法运算 |
| -= | 乘法运算 |
| *= | 除法运算 |
| /= | 取余数 |
| %= | 自增 |

- 比较运算符

| 比较运算符 | 说明 |
| ---------- | ------------------------ |
| == | 判断值是否相等 |
| === | 判断数据类型和值是否相等 |
| > | 大于 |
| >= | 大于等于 |
| < | 小于 |
| <= | 小于等于 |
| != | 不等于 |

- 逻辑运算符

| 逻辑运算符 | 说明 |
| ---------- | ------------------ |
| && | 逻辑与,并且的功能 |
| \|\| | 逻辑或,或者的功能 |
| ! | 取反 |

- **三元运算符**

- 三元运算符格式:(比较表达式) ? 表达式1 : 表达式2;
- 格式说明: 如果比较表达式为true,则取表达式1 如果比较表达式为false,则取表达式2





### 流程控制

- **if语句**

let month = 3; if(month >= 3 && month <= 5) { document.write("春季"); }else if(month >= 6 && month <= 8) { document.write("夏季"); }else if(month == 12 || month == 1 || month == 2) { document.write("冬季"); }else { document.write("月份有误"); }

document.write(“
”);

1
2
3

- **switch语句**

switch(sex){
case 1:
document.write(“男性”);
break;
case 2:
document.write(“女性”);
break;
default:
document.write(“性别有误”);
break;
}

1
2
3

- **for循环**

for(let i = 1; i <= 5; i++) {
document.write(i + “
”);
}

1
2
3

- **while循环**

let n = 6;
while(n <= 10) {
document.write(n + “
”);
n++;
}

1
2
3
4
5
6
7
8
9
10
11





### 数组

数组的使用和 java 中的数组基本一致,在JavaScript 中的数组更加灵活,数据类型和长度都没有限制

- 定义格式

let 数组名 = [元素1,元素2,…];

1
2
3
4
5

- 索引范围:从 0 开始,最大到数组长度-1

- 数组长度:数组名.length

let arr = [10,20,30];
document.write(arr+“
”)// 直接输出:10,20,30
for(let i = 0; i < arr.length; i++) {
document.write(arr[i] + “
”);
}

1
2
3
4
5

- 数组高级运算符:...

- 数组赋值

let arr2 = [...arr];
1
2
3

- 合并数组

let arr3 = [40,50,60]; let arr4 = [...arr2 , ...arr3];
1
2
3

- 字符串转数组

let arr5 = [..."JavaScript"];
1
2
3
4
5
6
7
8
9
10
11





### 函数

函数类似于 java 中的方法,可以将一些代码进行抽取,达到复用的效果

- 定义格式:

function 方法名(参数列表) {
方法体;
return 返回值;
}

1
2
3

- 调用:

let 变量 = 方法名();
方法名();

1
2
3

- 可变参数:

function 方法名(… 参数名) {
方法体;
return 返回值;
}

1
2
3

- 匿名函数

function(参数列表) {
方法体;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35







## DOM

### DOM介绍

DOM(Document Object Model):文档对象模型。

将 HTML 文档的各个组成部分,封装为对象。借助这些对象,可以对 HTML 文档进行增删改查的动态操作。

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/DOM%E4%BB%8B%E7%BB%8D.png)







### 元素获取

Element元素的获取操作:document接口方法

| 方法 | 说明 |
| ----------------------------------- | ------------------------------------- |
| getElementById(id属性值) | 根据id属性值获取元素对象 |
| getElementsByTagName(标签名称) | 根据标签名称获取元素对象,返回数组 |
| getElementsByClassName(class属性值) | 根据class属性值获取元素对象,返回数组 |
| getElementsByName(name属性值) | 根据name属性值获取元素对象,返回数组 |
| 子元素对象.parentElement属性 | 获取当前元素的父元素 |

div1
div2
div3
div4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17





### 元素增删改

Element元素的增删改操作:

| 方法 | 说明 |
| ---------------------------- | -------------------------- |
| createElement(标签名) | 创建一个新的标签元素 |
| appendChild(子元素) | 将指定子元素添加到父元素中 |
| removeChild(子元素) | 用父元素删除指定子元素 |
| replaceChild(新元素, 旧元素) | 用新元素替换子元素 |
| createTextNode(数据) | 创建文本元素 |

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17





### 属性操作

Attribute属性的操作:

| 方法 | 说明 |
| ---------------------------- | ------------------------ |
| setAttribute(属性名, 属性值) | 设置属性 |
| getAttribute(属性名) | 根据属性名获取属性值 |
| removeAttribute(属性名) | 根据属性名移除指定的属性 |
| 元素名.style属性 | 为元素添加样式 |
| 元素名.className属性 | 为元素添加指定样式 |

.aColor{ color: blue; }/*获取写在
1
2
3
4
5
6
7
8
9
10
11





### 条件渲染

v-if:条件性的渲染某元素,判定为真时渲染,否则不渲染 v-else:条件性的渲染 v-else-if:条件性的渲染

v-show:根据条件展示某元素,区别在于切换的是display属性的值

div1
div2
div3
div4
1
2
3
4
5
6
7
8
9





### 列表渲染

v-for:列表渲染,遍历容器的元素或者对象的属性

1
2
3
4
5
6
7
8
9





### 事件绑定

v-on:为 HTML 标签绑定事件,有简写方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15





### 表单绑定

- **表单绑定** v-model:在表单元素上创建双向数据绑定

- **双向数据绑定** 更新data数据,页面中的数据也会更新;更新页面数据,data数据也会更新

- **MVVM模型(ModelViewViewModel):是MVC模式的改进版** 在前端页面中,JS对象表示Model,页面表示View,两者做到了最大限度的分离。 将Model和View关联起来的就是ViewModel,它是桥梁。 ViewModel负责把Model的数据同步到View显示出来,还负责把View修改的数据同步回Model。

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/MVVM%E6%A8%A1%E5%9E%8B.png)

姓名:
年龄:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24





## Element

Element:网站快速成型工具,是饿了么公司前端开发团队提供的一套基于Vue的网站组件库,使用Element前提必须要有Vue

组件:组成网页的部件,例如超链接、按钮、图片、表格等等

- Element官网:https://element.eleme.cn/#/zh-CN

- 开发步骤:

1. 下载 Element 核心库
2. 引入 Element 样式文件
3. 引入 Vue 核心 js 文件
4. 引入 Element 核心 js 文件
5. 编写按钮标签
6. 通过 Vue 核心对象加载元素

- 代码实现

快速入门
默认按钮 主要按钮 成功按钮 信息按钮 警告按钮 危险按钮
朴素按钮 主要按钮 成功按钮 信息按钮 警告按钮 危险按钮
圆角按钮 主要按钮 成功按钮 信息按钮 警告按钮 危险按钮
1
2
3
4
5
6
7
8
9
10
11
12
13







## 自定义

对组件的封装

- 定义格式

Vue.component(组件名称, { props:组件的属性, data: 组件的数据函数, template: 组件解析的标签模板 })
1
2
3

- 代码实现

我的按钮
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

- 效果



我的按钮







## 生命周期

- 生命周期

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Vue%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.png)

- 生命周期八个阶段

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Vue%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E7%9A%84%E5%85%AB%E4%B8%AA%E9%98%B6%E6%AE%B5.png)





## 异步操作

在Vue中发送异步请求,本质上还是AJAX,使用axios这个插件来简化操作

- 使用步骤: 1.引入axios核心js文件 2.调用axios对象的方法来发起异步请求 3.调用axios对象的方法来处理响应的数据

- axios常用方法:

| 方法 | 作用 |
| ------------------------------------ | ------------------------------------------------ |
| get(请求的资源路径与请求的参数) | 发起GET方式请求 |
| post(请求的资源路径**,** 请求的参数) | 发起POST方式请求 |
| then(response) | 请求成功后的回调函数,通过response获取响应的数据 |
| catch(error) | 请求失败后的回调函数,通过error获取错误信息 |

- 代码实现

Servlet类:

@WebServlet("/testServlet") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp){ //设置请求响应编码 req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8");
      //获取请求参数
      String name = req.getParameter("name");
      System.out.println(name);

      //响应客户端
      resp.getWriter().write("请求成功");
  }
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp){
      doGet(req, resp);
  }

}

1
2
3

HTML文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55













# Nginx

## 安装软件

Nginx 是一个高性能的 HTTP 和[反向代理 ](https://baike.baidu.com/item/反向代理/7793488)Web 服务器,同时也提供了 IMAP/POP3/SMTP 服务

Nginx 两个最核心的功能:高性能的静态 Web 服务器,反向代理

- 安装指令:sudo apt-get install nginx
- 查看版本:nginx -v
- 系统指令:systemctl / service start/restart/stop/status nginx

配置文件安装目录:/etc/nginx

日志文件:/var/log/nginx





## 配置文件

nginx.conf 文件时 Nginx 的主配置文件

![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6conf.jpg)

- main 部分 ![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6main%E9%83%A8%E5%88%86.jpg)

- events 部分 ![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6events%E9%83%A8%E5%88%86.jpg)

- server 部分 ![img](https://seazean.oss-cn-beijing.aliyuncs.com/img/Web/Nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6server%E9%83%A8%E5%88%86.jpg)

root 设置的路径会拼接上 location 的路径,然后去最终路径寻找对应的文件





## 发布项目

1. 创建一个 toutiao 目录

cd /home mkdir toutiao
1
2
3
4
5
6
7

2. 将项目上传到 toutiao 目录

3. 解压项目 unzip web.zip

4. 编辑 Nginx 配置文件 nginx.conf

server { listen 80; server_name localhost; location / { root /home/seazean/toutiao; index index.html index.htm; } } ```
  1. 重启 Nginx 服务:systemctl restart nginx

  2. 浏览器打开网址:http://127.0.0.1:80

反向代理

无法访问 Google,可以配置一个代理服务器,发送请求到代理服务器,代理服务器经过转发,再将请求转发给 Google,返回结果之后,再次转发给用户,这个叫做正向代理,正向代理对于用户来说,是有感知的

正向代理(forward proxy):是一个位于客户端和目标服务器之间的代理服务器,为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端,正向代理,其实是"代理服务器"代理了当前"客户端",去和"目标服务器"进行交互

作用:

  • 突破访问限制:通过代理服务器,可以突破自身 IP 访问限制,访问国外网站,教育网等
  • 提高访问速度:代理服务器都设置一个较大的硬盘缓冲区,会将部分请求的响应保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度
  • 隐藏客户端真实 IP:隐藏自己的 IP,免受攻击

img

反向代理(reverse proxy):是指以代理服务器来接受 Internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器,反向代理,其实是"代理服务器"代理了"目标服务器",去和当前"客户端"进行交互

作用:

  • 隐藏服务器真实 IP:使用反向代理,可以对客户端隐藏服务器的 IP 地址
  • 负载均衡:根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上
  • 提高访问速度:反向代理服务器可以对于静态内容及短时间内有大量访问请求的动态内容提供缓存服务
  • 提供安全保障:反向代理服务器可以作为应用层防火墙,为网站提供对基于 Web 的攻击行为(例如 DoS/DDoS)的防护,更容易排查恶意软件等

img

区别:

  • 正向代理其实是客户端的代理,帮助客户端访问其无法访问的服务器资源;反向代理则是服务器的代理,帮助服务器做负载均衡,安全防护等
  • 正向代理一般是客户端架设的,比如在自己的机器上安装一个代理软件;反向代理一般是服务器架设的,比如在自己的机器集群中部署一个反向代理服务器
  • 正向代理中,服务器不知道真正的客户端到底是谁,以为访问自己的就是真实的客户端;反向代理中,客户端不知道真正的服务器是谁,以为自己访问的就是真实的服务器
  • 正向代理和反向代理的作用和目的不同。正向代理主要是用来解决访问限制问题;而反向代理则是提供负载均衡、安全防护等作用;二者均能提高访问速度