JavaWeb

cccs7 Lv5

Java Web

HTML

Hyper Text Markup Language (超文本标记语言) 简写: HTML
HTML 通过标签来标记要显示的网页中的各个部分。 网页文件本身是一种文本文件,
通过在文本文件中添加标记符, 可以告诉浏览器如何显示其中的内容(如: 文字如何处理, 画
面如何安排, 图片如何显示等)

HTML 的书写规范


1
2
3
4
5
6
7
8
9
10
<!DOCTYPEhtml>
<html lang="en"> <!-- 表示整个 html 页面的开始 -->
<head> <!-- 头信息 -->
<meta charset="UTF-8">
<title>标题</title> <!-- 标题 -->
</head>
<body> <!-- body 是页面的主体内容 -->
页面主体内容
</body>
</html> <!-- 表示整个 html 页面的结束 -->

HTML 标签介绍


标签的格式

<标签名>封装的数据</标签名>

注意事项

  • 标签名大小写不敏感
  • 标签拥有自己的属性
    • 基本属性 :bgcolor="red" 可以修改简单的样式效果
    • 事件属性 :onclick="alert('你好');" 可以直接设置事件响应后的代码
  • 标签又分为单标签和双标签
    • 单标签格式 : <标签名/> <br/> <hr/>
    • 双标签格式 :<标签名>...封装的数据...</标签名>

标签的语法

  • 标签不能嵌套
    • 正确:<div><span>早安, 尚硅谷</span></div>
    • 错误:<div><span>早安, 尚硅谷</div></span>
  • 标签必须正确关闭
    • 有文本内容的标签
      • 正确:<div>早安, 尚硅谷</div>
      • 错误: <div>早安, 尚硅谷
    • 没有文本内容的标签
      • 正确:<br />
      • 错误:<br>
  • 属性必须有值,属性值必须加 “ “
    • 正确:<font color="blue">早安, 尚硅谷</font>
    • 错误:<font color=blue>早安, 尚硅谷</font>
    • 错误:<font color>早安, 尚硅谷</font>
  • 注释不能嵌套

HTML 代码不是很严谨。有时候标签不闭合也不会报错

常用标签介绍


文档: w3cschool.CHM

front 标签

需求1:在网页上显示我是字体标签,并修改字体为 宋体,颜色为红色

1
2
3
4
5
6
7
8
9
10
<body>
<!-- 字体标签
需求 1: 在网页上显示 我是字体标签 , 并修改字体为 宋体, 颜色为红色。
font 标签是字体标签,它可以用来修改文本的字体,颜色,大小(尺寸)
color 属性修改颜色
face 属性修改字体
size 属性修改文本大小
-->
<font color="red" face="宋体" size="7">我是字体标签</font>
</body>

特殊字符


需求1:把 <br /> 换行标签变成文本 转换成字符显示在页面上

常用特殊字符表

image-20220804153301887

其他特殊字符表

image-20220804153342186
1
2
3
4
5
6
7
8
9
10
11
12
<body>
<!-- 特殊字符
需求 1: 把 <br> 换行标签 变成文本 转换成字符显示在页面上
常用的特殊字符:
< ===>>>> &lt;
> ===>>>> &gt;
空格 ===>>>> &nbsp;
-->
我是&lt;br&gt;标签<br/>
国哥好
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</body>

标题标签


标题标签是 h1 到 h6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<!-- 标题标签
需求 1: 演示标题 1 到 标题 6 的.

h1 - h6 都是标题标签
h1 最大
h6 最小
align 属性是对齐属性
left 左对齐(默认)
center 剧中
right 右对齐
-->
<h1 align="left">标题 1</h1>
<h2 align="center">标题 2</h2>
<h3 align="right">标题 3</h3>
<h4>标题 4</h4>
<h5>标题 5</h5>
<h6>标题 6</h6>
<h7>标题 7</h7>
</body>

超链接


在网页中所有点击之后可以跳转的内容都是超链接

普通的超链接

1
2
3
4
5
6
7
8
9
10
11
12
<body>
<!--
a 标签是 超链接
href 属性设置连接的地址
target 属性设置哪个目标进行跳转
_self 表示当前页面(默认值)
_blank 表示打开新页面来进行跳转
-->
<a href="http://localhost:8080">百度</a><br/>
<a href="http://localhost:8080" target="_self">百度_self</a><br/>
<a href="http://localhost:8080" target="_blank">百度_blank</a><br/>
</body>

列表标签


无序列表、有序列表

无序列表

需求1:使用无序, 列表方式, 把东北 F4, 赵四, 刘能, 小沈阳, 宋小宝, 展示出来

1
2
3
4
5
6
7
8
9
10
11
12
13
<body>
<!--需求 1: 使用无序, 列表方式, 把东北 F4, 赵四, 刘能, 小沈阳, 宋小宝, 展示出来
ul 是无序列表
type 属性可以修改列表项前面的符号
li 是列表项
-->
<ul type="none">
<li>赵四</li>
<li>刘能</li>
<li>小沈阳</li>
<li>宋小宝</li>
</ul>
</body>

img 标签


img 标签可以在 html 页面上显示图片

需求1:使用 img 标签显示一张美女的照片。 并修改宽高, 和边框属性

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
    <body>
<!--需求 1: 使用 img 标签显示一张美女的照片。 并修改宽高, 和边框属性
img 标签是图片标签,用来显示图片
src 属性可以设置图片的路径
width 属性设置图片的宽度
height 属性设置图片的高度
border 属性设置图片边框大小
alt 属性设置当指定路径找不到图片时,用来代替显示的文本内容

在 JavaSE 中路径也分为相对路径和绝对路径.
相对路径:从工程名开始算
绝对路径:盘符:/目录/文件名

在 web 中路径分为相对路径和绝对路径两种
相对路径:
. 表示当前文件所在的目录
.. 表示当前文件所在的上一级目录
文件名 表示当前文件所在目录的文件,相当于 ./文件名 ./ 可以省略
绝对路径:
正确格式是: http://ip:port/工程名/资源路径
错误格式是: 盘符:/目录/文件名
-->
<img src="1.jpg" width="200" height="260" border="1" alt="美女找不到"/>
<img src="../2.jpg" width="200" height="260" />
<img src="../imgs/3.jpg" width="200" height="260" />
<img src="../imgs/4.jpg" width="200" height="260" />
<img src="../imgs/5.jpg" width="200" height="260" />
<img src="../imgs/6.jpg" width="200" height="260" />
</body>

表格标签


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
<body>
<!--
需求 1: 做一个 带表头的 , 三行, 三列的表格, 并显示边框
需求 2: 修改表格的宽度, 高度, 表格的对齐方式, 单元格间距。

table 标签是表格标签
border 设置表格标签
width 设置表格宽度
height 设置表格高度
align 设置表格相对于页面的对齐方式cellspacing 设置单元格间距
tr 是行标签
th 是表头标签
td 是单元格标签
align 设置单元格文本对齐方式
b 是加粗标签
-->
<table align="center" border="1" width="300" height="300" cellspacing="0">
<tr>
<th>1.1</th>
<th>1.2</th>
<th>1.3</th>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
<td>2.3</td>
</tr>
<tr>
<td>3.1</td>
<td>3.2</td>
<td>3.3</td>
</tr>
</table>
</body>

表格的跨行跨列

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
<body>
<!-- 需求 1:
新建一个五行, 五列的表格,
第一行, 第一列的单元格要跨两列,
第二行第一列的单元格跨两行,
第四行第四列的单元格跨两行两列。

colspan 属性设置跨列
rowspan 属性设置跨行
-->
<table width="500" height="500" cellspacing="0" border="1">
<tr>
<td colspan="2">1.1</td>
<td>1.3</td>
<td>1.4</td>
<td>1.5</td>
</tr>
<tr>
<td rowspan="2">2.1</td>
<td>2.2</td>
<td>2.3</td>
<td>2.4</td>
<td>2.5</td>
</tr>
<tr>
<td>3.2</td>
<td>3.3</td>
<td>3.4</td>
<td>3.5</td>
</tr>
<tr>
<td>4.1</td>
<td>4.2</td>
<td>4.3</td>
<td colspan="2" rowspan="2">4.4</td>
</tr>
<tr>
<td>5.1</td>
<td>5.2</td>
<td>5.3</td>
</tr>
</table>
</body>

iframe 框架


ifarme 标签它可以在一个 html 页面上,打开一个小窗口,去加载一个单独的页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
我是一个单独的完整的页面
<br/><br/>
<!--ifarme 标签可以在页面上开辟一个小区域显示一个单独的页面
ifarme 和 a 标签组合使用的步骤:
1 在 iframe 标签中使用 name 属性定义一个名称
2 在 a 标签的 target 属性上设置 iframe 的 name 的属性值
-->
<iframe src="3.标题标签.html" width="500" height="400" name="abc"></iframe>
<br/>
<ul>
<li><a href="0-标签语法.html" target="abc">0-标签语法.html</a></li>
<li><a href="1.font 标签.html" target="abc">1.font 标签.html</a></li>
<li><a href="2.特殊字符.html" target="abc">2.特殊字符.html</a></li>
</ul>
</body>

表单标签


表单就是 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
<body>
<!--需求
1:创建一个个人信息注册的表单界面。 包含用户名, 密码, 确认密码。 性别(单选) , 兴趣爱好(多选) , 国籍(下拉列表) 。
隐藏域, 自我评价(多行文本域) 。 重置, 提交。 -->

<!--
form 标签就是表单
input type=text 是文件输入框 value 设置默认显示内容
input type=password 是密码输入框 value 设置默认显示内容
input type=radio 是单选框 name 属性可以对其进行分组 checked="checked"表示默认选中input type=checkbox 是复选框 checked="checked"表示默认选中
input type=reset 是重置按钮 value 属性修改按钮上的文本
input type=submit 是提交按钮 value 属性修改按钮上的文本
input type=button 是按钮 value 属性修改按钮上的文本
input type=file 是文件上传域
input type=hidden 是隐藏域 当我们要发送某些信息, 而这些信息, 不需要用户参与, 就可以使用隐藏域(提交的
时候同时发送给服务器)
select 标签是下拉列表框
option 标签是下拉列表框中的选项 selected="selected"设置默认选中
textarea 表示多行文本输入框 (起始标签和结束标签中的内容是默认值)
rows 属性设置可以显示几行的高度
cols 属性设置每行可以显示几个字符宽度
-->
<form>
用户名称: <input type="text" value="默认值"/><br/>
用户密码: <input type="password" value="abc"/><br/>
确认密码: <input type="password" value="abc"/><br/>
性别: <input type="radio" name="sex"/><input type="radio" name="sex" checked="checked" /><br/>
兴趣爱好: <input type="checkbox" checked="checked" />Java<input type="checkbox" />JavaScript<input
type="checkbox" />C++<br/>
国籍: <select>
<option>--请选择国籍--</option>
<option selected="selected">中国</option>
<option>美国</option>
<option>小日本</option>
</select><br/>
自我评价: <textarea rows="10" cols="20">我才是默认值</textarea><br/>
<input type="reset" value="abc" />
<input type="submit"/>
</form>
</body>

表单的格式化

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
<form>
<h1 align="center">用户注册</h1>
<table align="center">
<tr>
<td> 用户名称: </td>
<td>
<input type="text" value="默认值"/>
</td>
</tr>
<tr>
<td> 用户密码: </td>
<td><input type="password" value="abc"/></td>
</tr>
<tr>
<td>确认密码: </td>
<td><input type="password" value="abc"/></td>
</tr>
<tr>
<td>性别: </td>
<td>
<input type="radio" name="sex"/>
<input type="radio" name="sex" checked="checked" />
</td>
</tr>
<tr>
<td> 兴趣爱好: </td>
<td>
<input type="checkbox" checked="checked" />Java
<input type="checkbox" />JavaScript
<input type="checkbox" />C++
</td>
</tr>
<tr>
<td>国籍: </td>
<td>
<select>
<option>--请选择国籍--</option>
<option selected="selected">中国</option>
<option>美国</option>
<option>小日本</option>
</select>
</td>
</tr>
<tr>
<td>自我评价: </td>
<td><textarea rows="10" cols="20">我才是默认值</textarea></td>
</tr>
<tr>
<td><input type="reset" /></td>
<td align="center"><input type="submit"/></td>
</tr>
</table>
</form>
</body>

表单提交的细节

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
<body>
<!--
form 标签是表单标签
action 属性设置提交的服务器地址
method 属性设置提交的方式 GET(默认值)或 POST

表单提交的时候, 数据没有发送给服务器的三种情况:
1、 表单项没有 name 属性值
2、 单选、 复选(下拉列表中的 option 标签) 都需要添加 value 属性, 以便发送给服务器
3、 表单项不在提交的 form 标签中

GET 请求的特点是:
1、 浏览器地址栏中的地址是: action 属性[+?+请求参数]
请求参数的格式是: name=value&name=value
2、 不安全
3、 它有数据长度的限制

POST 请求的特点是:
1、 浏览器地址栏中只有 action 属性值
2、 相对于 GET 请求要安全
3、 理论上没有数据长度的限制
-->
<form action="http://localhost:8080" method="post">
<input type="hidden" name="action" value="login" />
<h1 align="center">用户注册</h1>
<table align="center">
<tr>
<td> 用户名称: </td>
<td>
<input type="text" name="username" value="默认值"/>
</td>
</tr>
<tr>
<td> 用户密码: </td>
<td><input type="password" name="password" value="abc"/></td>
</tr>
<tr>
<td>性别: </td>
<td>
<input type="radio" name="sex" value="boy"/>
<input type="radio" name="sex" checked="checked" value="girl" />
</td>
</tr>
<tr>
<td> 兴趣爱好: </td>
<td>
<input name="hobby" type="checkbox" checked="checked" value="java"/>Java
<input name="hobby" type="checkbox" value="js"/>JavaScript
<input name="hobby" type="checkbox" value="cpp"/>C++
</td>
</tr>
<tr>
<td>国籍: </td>
<td>
<select name="country">
<option value="none">--请选择国籍--</option>
<option value="cn" selected="selected">中国</option>
<option value="usa">美国</option>
<option value="jp">小日本</option>
</select>
</td>
</tr>
<tr>
<td>自我评价: </td>
<td><textarea name="desc" rows="10" cols="20">我才是默认值</textarea></td>
</tr>
<tr>
<td><input type="reset" /></td>
<td align="center"><input type="submit"/></td>
</tr>
</table>
</form>
</body>

其他标签


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
<!--需求 1: div、 span、 p 标签的演示

div 标签 默认独占一行
span 标签 它的长度是封装数据的长度
p 段落标签 默认会在段落的上方或下方各空出一行来(如果已有就不再空)
-->

<div>div 标签 1</div>
<div>div 标签 2</div>
<span>span 标签 1</span>
<span>span 标签 2</span>
<p>p 段落标签 1</p>
<p>p 段落标签 2</p>
</body>

CSS

CSS 是层叠样式表单。是用于(增强)控制网页样式并允许将样式信息与网页内容分离的一种标记性语言

CSS语法规则


1
2
3
p{ /* 选择器 */
font-size:80px; /* 属性:值*/
}

选择器:浏览器根据“选择器” 决定受 CSS 样式影响的 HTML 元素(标签) 。

属性:是你要改变的样式名, 并且每个属性都有一个值。 属性和值被冒号分开, 并
由花括号包围, 这样就组成了一个完整的样式声明(declaration) , 例如: p {color: blue}

多个声明:如果要定义不止一个声明, 则需要用分号将每个声明分开。 虽然最后一条声明的
最后可以不加分号(但尽量在每条声明的末尾都加上分号)

注:一般每行只描述一个属性

CSS 注释:/* 注释内容 */

CSS 和 HTML 的结合方式


第一种

在标签的 style 属性上设置 “ key : value value;” ,修改标签样式

需求一:分别定义两个 div、 span 标签, 分别修改每个 div 标签的样式为: 边框 1 个像素, 实线, 红色。

1
2
3
4
5
6
7
8
<div>
div 标签1
</div>
<div>
div 标签2
</div>
<span>span 标签1</span>
<span>span 标签2</span>

问题:这种方式的缺点

  • 如果标签多了,样式多了,代码量非常庞大
  • 可读性非常差
  • CSS 代码没有复用性可言

第二种

在head标签中,使用 style 标签来定义各种自己需要的 css 样式

格式如下

1
2
3
xxx{
Key:value value;
}

问题:缺点?

  • 只能在同一页面内复用代码,不能在多个页面中复用 css 代码
  • 维护起来不方便,实际的项目中会有成千上万的页面,要到每个页面中去修改,工作量太大了
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
<!--
* @Date: 2022-09-19 10:26:00
* @FilePath: \src\javaweb\css_\css和html的结合方式\2.html
* @Description: css 和 html的结合方式 2
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
div{
border : 1px solid red;
}
span{
border: 1px solid red;
}
</style>
</head>
<body>
<div>div标签1</div>
<div>div标签2</div>
<span>span标签1</span>
<span>span标签2</span>
</body>
</html>

第三种

把 css 样式写成一个单独的 css 文件,再通过 link 标签引入即可复用

使用 html 的 <link rel="stylesheet" type="text/css" href="./styles.css"/>标签 导入css 样式文件

css 文件内容

1
2
3
4
5
6
div{
border: 1px solid yellow;
}
span{
border: 1px solid red;
}

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
<!--
* @Date: 2022-09-19 10:38:10
* @FilePath: \src\javaweb\css_\css和html的结合方式\3.html
* @Description: css 和html的结合方式 3
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 使用 link 标签专门引入 css 样式代码-->
<link rel="stylesheet" type="text/css" href="1.css"/>
</head>
<body>
<div>div标签</div>
<div>div标签</div>
<span>span标签</span>
<span>span标签</span>
</body>
</html>

CSS 选择器


标签名选择器

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
<!--
* @Date: 2022-09-20 09:08:07
* @FilePath: \src\javaweb\css_\标签名选择器.html
* @Description: 标签名选择器
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>标签名选择器</title>
<style type="text/css">
div{
border: 1px solid yellow;
color: blue;
font-size: 30px;
}
span{
border: 5px dashed blue;
color: yellow;
font-size: 20px;
}
</style>
</head>
<body>
<div>div标签</div>
<div>div标签</div>
<span>span标签</span>
<span>span标签</span>
</body>
</html>

id 选择器

1
2
3
#id 属性值{
属性: 值;
}

id选择器,可以让我们通过id 属性选择器的去使用这个样式

代码示例

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
<!--
* @Date: 2022-09-20 09:18:57
* @FilePath: \src\javaweb\css_\id选择器.html
* @Description: id 选择器
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>id 选择器</title>
<style type="text/css">
#id001{
color: red;
font-size: 30px;
border: 1px yellow solid;
}

#id002{
color: green;
font-size: 30px;
border: 1px yellow solid;
}
</style>
</head>
<body>
<div id="id001">div 标签1</div>
<div id="id002">div 标签2</div>
</body>
</html>

class 选择器

1
2
3
.class 属性值{
属性: 值;
}

.class 类型选择器,可以通过 class 属性有效的选择性地区使用这个样式

代码示例

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
<!--
* @Date: 2022-09-20 18:49:28
* @FilePath: \src\javaweb\css_\class选择器.html
* @Description:
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> class 选择器</title>
<style type="text/css">
.class001{
color: black;
font-size: 30px;
border: 1px solid white;
}

.class002{
color:aqua;
font-size: 24px;
border: 1px solid black;
}
</style>
</head>
<body>
<div class="class001">div标签</div>
<div class="class002">div标签</div>
</body>
</html>

组合选择器

组合选择器的格式是:

1
2
3
选择器1,选择器2,选择器n{
属性: 值;
}

组合选择器可以让多个选择器共用一个 css 样式代码

代码示例

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
<!--
* @Date: 2022-09-20 19:01:59
* @FilePath: \src\javaweb\css_\组合选择器.html
* @Description:
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组合选择器</title>
<style type="text/css">
.class01,id01{
color:aqua;
font-size:30px;
border:2px solid black;
}
</style>
</head>
<body>
<div id="id001">div 标签</div>
<div class="class01">div 标签2</div>
</body>
</html>

常用样式


字体颜色

color: red;

颜色可以写颜色名如:black,blue,red,green

颜色也可以写 rgb 值和十六进制表示值:如 rgb(255,0,0),#00F6DE,如果写十六进制值必须加 #

宽度

width: 19px;

宽度可以写像素值: 19px;

也可以写百分比值: 20% ;

高度

height: 20px;

高度可以写像素值: 19px;

也可以写百分比值:20%

背景颜色

background-color: #0F2D4C

字体样式

color: #FF0000; 字体颜色红色

font-size: 20px; 字体大小

特例

红色1像素实线边框: boder: 1px red solid;

DIV 居中: margin-left:auto; margin-right:auto;

文本居中:text-align:center;

超链接去下划线:text-decoration:none;

表格细线:

1
2
3
4
5
6
7
8
table{
border:1px solid black;
border-collapse:collpase;
}

td,th{
border:1px solid black;
}

列表去除修饰:

1
2
3
ul{
list-style:none;
}

代码示例

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
<!--
* @Date: 2022-09-21 09:54:54
* @FilePath: \src\javaweb\css_\css常用样式.html
* @Description: css 常用样式
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>css 常用样式</title>
<style type="text/css">

div{
color: red;
border: 1px solid black;
width: 300px;
height: 300px;
background-color: green;
font-size: 30px;
margin-left: auto;
margin-right: auto;
text-align: center;
}

table{
border: 1px solid red;
border-collapse: collapse;
}

td{
border: 1px solid black;
}

a{
text-decoration: none;
}

ul{
list-style: none;
}
</style>
</head>
<body>
<ul>
<li>111111</li>
<li>111111</li>
<li>111111</li>
<li>111111</li>
</ul>
<table>
<tr>
<td>1.1</td>
<td>1.2</td>
</tr>
</table>
<a href="http://www.baidu.com">百度</a>
<div>div标签</div>
</body>
</html>

JavaScript

JavaScript 语言诞生主要是为了完成页面的数据验证。因此他运行在客户端,需要浏览器来解析执行 JavaScript 代码。

JavaScprit 是弱类型,Java 是强类型

JavaScript 介绍


特点

  • 交互性:他可以做的就是信息的动态交互
  • 安全性:不允许直接访问本地硬盘
  • 跨平台性:只要是可以解释 JS 的浏览器都可以执行,和平台无关

JavaScript 和 HTML 代码结合的方式


第一种

只需要在 head 标签中,或者在 body 标签中,使用 script 标签来书写 JavaScript 代码

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--
* @Date: 2022-09-21 10:24:50
* @FilePath: \src\javaweb\javascript\js和html结合的方式\第一种.html
* @Description:
*
* Copyright (c) 2022 by CSQ Cs7eric@outlook.com, All Rights Reserved.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>js和html 结合的方式</title>
<script type="text/javascript">
// alert 是 js 中提供的一个警告框函数
// 他可以接受任何类型的 参数,这个参数就是警告框的提示信息
alert("Hello javascript!");
</script>
</head>
<body>

</body>
</html>

第二种

使用 script 标签引入单独的 JavaScript 文件

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>第二种 js h5 结合方式</title>
<!--
现在需要使用 Script 引入外部的 js 文件来执行
src 属性专门用来引入 js 文件路径(可以是相对路径,也可以是绝对路径)

script 标签可以用来定义 js 代码,也可以用来引入 js 文件
但是,两个功能二选一,不能同时使用两个功能
-->
<script type="text/javascript"src="1.js"></script>
</head>
<body>

</body>
</html>

变量


变量是可以存放某些值的内存的命名

JavaScript 的变量类型

  • 数值类型

    ​ number

  • 字符串类型

    ​ string

  • 对象类型

    ​ object

  • 布尔类型

    ​ boolean

  • 函数类型

    ​ function

JavaScript 里特殊的值

  • undefined

    未定义,所有 js 变量未赋予初始值的时候,默认值都是 undefined

  • null

    空值

  • NaN

    全称是:Not a Number 非数字。非数值

JavaScript 定义变量格式

var 变量名;

var 变量名 = 值 ;

代码示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>变量</title>
<script type="text/javascript">
var i;
alert(i);
i = 12;
// typeof() 是 js 中 提供的一个函数
alert(typeof(i)); // number
i = "abc";
// 他可以取变量的数据类型返回
// alert(typeof(i)); // string

var a = 12;
var b = "abc";

alert(a * b); //NaN 是非数字,非数值
</script>
</head>
<body>

</body>
</html>

alert() 弹窗,经常用于确保用户可以得到某些信息,当警告框出现后,用户需要点击确定按钮才可以继续进行操作

typeof() 是 JavaScript 中提供的一个函数:操作符返回一个字符串,表示未经计算的操作数的类型。

关系(比较)运算

等于: == 等于是简单的做字面值的比较

全等于: === 除了做字面值的比较,还会比较两个变量的数据类型

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>关系运算</title>
<script type="text/javascript">
var a = 10;
var b = "10";

alert(a == b); // true
alert(a === b); // false
</script>
</head>
<body>

</body>
</html>

逻辑运算

且运算: &&

或运算: ||

取反运算: !

在 JavaScript 语言中,所有的变量,都可以作为一个 boolean 类型的变量去使用。

**0、null、undefined、“”(空串)都认为是 false; **

且运算
  • 第一种: 当表达式全为真的时候。 返回最后一个表达式的值。
  • 第二种: 当表达式中, 有一个为假的时候。 返回第一个为假的表达式的值
或运算
  • 第一种情况: 当表达式全为假时, 返回最后一个表达式的值
  • 第二种情况: 只要有一个表达式为真。 就会把回第一个为真的表达式的值

并且 && 与运算 和 ||或运算 有短路。
短路就是说, 当这个&&或||运算有结果了之后 。 后面的表达式不再执行

数组


数组的定义方式

js 中数组的定义:

1
2
var arrayName = []; // 空数组
var arrayName = [1,'abc,true']; // 定义数组同时赋值元素

代码示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数组定义</title>
<script type="text/javascript">

var arr = [true,1];
alert(arr.length);

arr[0] = 12;
alert(arr[0]);
alert(arr.length);

// js 中的数组,只要我们通过数组下标赋值,那么最大的下标值,就会自动给数组做扩容操作

arr[2] = "abc";
alert(arr.length);

alert(arr[1]);

// 数组的遍历
for(var i = 0;i < arr.length;++i){
alert(arr[i])
}
</script>
</head>
<body>

</body>
</html>

函数


函数的两种定义方式

function 关键字定义

格式如下

1
2
3
function funcName(){
//函数体
}

在 JavaScript 中,如何定义带有返回值的函数:只需要在函数体中直接使用 return 语句返回值即可。

代码示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数定义的方式</title>
<script type="text/javascript">

// 定义一个无参函数
function fun(){
alert("调用了 无参函数 fun()");
}

//fun();

// 定义有参函数
function fun2(a,b){
alert("有参函数 fun2() 被调用了 a=>" + a + ",b=>" +b);
}
//fun2(12,"abc");

// 定义带有返回值的函数
function sum(num1,num2){
var result = num1 + num2;
return result;
}
alert(sum(100,50));
</script>
</head>
<body>

</body>
</html>
var 定义

var 函数名 = 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
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>函数定义</title>
<script type="text/javascript">
var fun = function(){
alert("无参函数");
}

//fun();

var fun2 = function(a,b){
alert("a:" + a + "b:" + b );
}
fun2(1,2);

var fun3 = function(a,b){
return a + b;
}
alert(fun3(12,43));
</script>
</head>
<body>

</body>
</html>

函数的 arguments 隐形参数

就是在 function 函数中不需要定义,但却可以直接用来获取所有参数的变量,称之为 隐形参数,(与 Java 中 的可变长参数一样)

public void fun (Object ...args)

可变长参数其实是一个数组

那么 js 中的隐形参数跟 Java 的可变参数一样,类似操作数组

JS 中的自定义对象

Object 形式的自定义对象

对象的定义:

​ var 变量名 = new Object(); // 对象实例(空对象)

​ 变量名.属性名 = 值; // 定义一个属性

​ 变量名.函数名 = function(){} // 定义一个函数

对象的访问:

​ 变量名.属性/函数名();

{}形式的自定义对象

对象的定义:

1
2
3
4
5
var 变量名 = {
属性名: 值,
属性名: 值,
函数名: function(){}
};

对象的访问:

​ 变量名.属性/函数名();

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{}形式的自定义对象</title>
<script type="text/javascript">
var obj = {
name : "csq",
age : 18,
fun : function(){
alert("name=" + this.name + "age" + this.age);
}
};
obj.fun();
</script>
</head>
<body>

</body>
</html>

事件


什么是事件,事件是电脑输入设备与页面进行交互的响应。我们称之为事件

事件的注册

事件的注册又分为静态注册和动态注册两种

什么是事件的注册? 其实就是告诉浏览器,当事件响应后要执行哪些操作代码,叫事件注册或事件绑定

静态注册

通过 HTML 标签的事件属性直接赋予事件响应后 的代码,这种方式我们叫 静态注册

动态注册

是指先通过js 代码得到标签的 dom 对象,然后再 通过 dom 对象.事件名 = function(){} 这种形式赋予事件响应后的代码,叫动态注册

动态注册基本步骤
  1. 获取标签对象
  2. 标签对象.事件名 = function(){}

常用的事件

  • onload 加载完成事件

    页面加载完成之后,常用于做页面 js 代码的初始化操作

  • onclick 单击事件

    常用于按钮的点击响应操作

  • onblur 失去焦点事件

    常用于输入法失去交点后验证其输入内容是否合法

  • onchange 内容发生改变事件

    常用于下拉列表和输入框内容发生更改之后操作

  • onsubmit 表单提交操作

    常用于表单提交前,验证所有的表单项是否合法

onload 加载完成事件

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>onload 加载完成事件</title>
<script type="text/javascript">
// onload 事件的方法
function onload() {
alert("静态注册 onload 事件");
}
window.onload = function() {
alert("动态注册的 onload事件")
}
window.onload();
</script>
</head>
<body>

</body>
</html>
onclick 单击事件

代码示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>onclick 单击事件</title>
<script type="text/javascript">
function onclickFun(){
alert("静态注册 onclick事件");
}

//动态注册 onclick 事件
window.onload = function (){
//1. 获取标签对象
/*
document 是 JavaScript 语言提供的一个对象(文档)<br/>
get 获取
Element 元素(就是标签)
By 通过... 由... 经...
Id ID属性

getElementById 通过 id 属性获取标签对象
*/

var btnObj = document.getElementById("btn01");
alert(btnObj);

// 2. 通过标签事件.事件名 = function(){}
btnObj.onclick = function(){
alert("动态注册的 onclick 事件");
}
}
</script>
</head>
<body>
<!--
静态注册 onclick 事件 -->
<button onclick="onclickFun();">按钮1</button>
<button id="btn01">按钮2</button>
</body>
</html>
onblur 失去焦点事件

代码示例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>onblur失去焦点事件</title>
<script type="text/javascript">

//静态注册失去焦点事件
function onblurFun(){
//console 是控制台对象,是由 JavaScript 语言提供,专门用来向浏览器的控制器打印输出,用于测试使用
//log() 是打印的方法
console.log("静态注册失去焦点事件")
}

// 动态注册 onblur 事件
window.onload = function(){
// 1. 获取标签对象
let passwordObj = document.getElementById("password");
//alert(passwordObj);
passwordObj.onblur = function(){
console.log("动态注册失去焦点事件");
}
}
</script>
</head>
<body>
用户名:<input type="text" onblur="onblurFun();"><br/>
密码:<input id="password" type="text"><br/>
</body>
</html>
oncharge 内容发生改变事件
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>onchange内容发生改变时间</title>
<script type="text/javascript">
function onchangeFun(){
alert("内容已经发生改变")
}

window.onload = function(){
// 1. 获取标签对象
var selObj = document.getElementById("sel01");
alert(selObj);

// 2. 通过标签对象.事件名 = function(){}
selObj.onchange = function(){
alert("内容已经更改2");
}
}
</script>
</head>
<body>
请选择:
<!-- 静态注册 oncharge 事件-->
<select onchange="onchangeFun();">
<option>1</option>
<option>2</option>
<option>3</option>
</select>

请选择2:
<select onchange="onchangeFun();">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
</body>
</html>
onsubmit 表单提交事件
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
// 静态注册表单提交事务
function onsubmitFun(){
// 要验证所有表单项是否合法,
// 如果,有一个不合法就阻止表单提交
alert("静态注册表单提交事件---发现不合法")
return false;
}

window.onload = function(){
// 1. 获取标签对象
var formObj = document.getElementById("form01");

//2. 通过标签对象.事件名 = function(){}
formObj.onsubmit = function(){
// 要验证所有表单项是否合法
// 如果,有一个不合法就阻止表单提交
alert("动态注册表单提交事件---发现不合法");
return false;
}
}
</script>
</head>
<body>
<!-- false 可以阻止 表单提交-->
<form action="http://localhost:8080" method="get" onsubmit="onsubmitFun();">
<input type="submit" value="静态注册"/>
</form>
<form action="http://localhost:8080" id="form01">
<input type="submit" value="动态注册"/>
</form>
</body>
</html>

DOM 模型


DOM 全程就是 Document Object Model 文档对象模型

换句话说,就是把文档中的标签,属性,文本,转换成对象来管理,

Document 对象

Document 对象的理解
  • Document 他管理了所有的 HTML 文档内容
  • document 他是一种树结构的文档,有层级关系
  • 他让我们把所有的标签都对象化
  • 我们可以通过 document 访问所有的标签对象
html 标签对象化
1
2
3
4
5
<body>
<div id="div01">
div01
</div>
</body>

模拟对象化

1
2
3
4
5
6
7
class Dom{
private String id;
private String tagName;
private Dom parentNOde;
private List<Dom> children;
private String innerHTML;
}

Document 对象中的方法介绍

document.getElementById(elementId)

通过标签的 id 属性查找标签对象,elementId 是标签的 id 属性值

示例代码
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
/*
需求:当用户点击了校验按钮,要获取输出框中的内容,然后验证其是否合法
验证的规则是:必须由字母、数字和下划线组成,并且长度是 5 - 12 位
*/
function onclickFun(){

//1.我们要操作一个标签时,一定要先获取这个标签对象
let usernameObj = document.getElementById("username");
// [object HTMLInputElement] 他就是dom 对象
let usernameText = usernameObj.value;
// 如何验证 字符串符合某个规则,需要使用正则表达式技术
let patt = /^\w{5,12}$/;

/*
test() 方法用于测试某个字符串,是不是匹配我的规则
匹配就返回 true,不匹配就返回 false
*/

let usernameSpanObj = document.getElementById("usernameSpan");
// innerHTML 表示起始标签和结束标签中的内容
// innerHTML 这个属性可读,可写
usernameSpanObj.innerHTML ="innerHTML";

if(patt.test(usernameText)){
usernameSpanObj.innerHTML = "right";
} else {
usernameSpanObj.innerHTML="wrong";
}
}

</script>
</head>
<body>
用户名: <input type="text" id="username" value="csq"/>
<span id="usernameSpan" style="color:red;"></span>
<button onclick="onclickFun()">校验</button>
</body>
</html>
document.getElementsByName(elementName)

通过标签的 name 属性 查找标签的 dom 对象,elementName 标签的 name 属性值

示例代码
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">

function checkAll(){
/**
* 让所有复选框都选中
* document.getElementsByName(); 是根据指定的 name 属性查询返回多个标签对象集合
* 这个集合的操作和数组一样
* 集合中每个元素都是 dom 对象
* 这个集合中的元素顺序是他们在 HTML 页面中从上到下的顺序
*/
let hobbies = document.getElementsByName("hobby");
// checked 表示复选框的选中状态,如果选中就是 true ,不选中就是 false
// checked 这个属性可读,可写
for(let i = 0;i < hobbies.length;++i){
hobbies[i].checked = true;
}
}

//全不选
function checkNo(){

let hobbies = document.getElementsByName("hobby");
//checked 表示复选框的选中状态。如果选中是 true,不选中是false
// checked 这个属性可读,可写
for(let i = 0;i < hobbies.length;++i){
hobbies[i].checked = false;
}
}

//反选
function checkReverse(){

let hobbies = document.getElementsByName("hobby");

for(let i = 0;i < hobbies.length;++i){
hobbies[i].checked = !hobbies[i].checked;
}
}
</script>
</head>
<body>
兴趣爱好:
<input type="checkbox" name="hobby" value="cpp" checked="checked">C++
<input type="checkbox" name="hobby" value="java">Java
<input type="checkbox" name="hobby" value="js">JavaScript
<button onclick="checkAll()">全选</button>
<button onclick="checkNo()">全不选</button>
<button onclick="checkReverse()">反选</button>
</body>
</html>
document.getElementsByTagName(tagName)

通过标签名查找标签 dom 对象,tagName 是标签名

示例代码
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
//全选
function checkAll() {
/**
* document.getElementsByTagName("input");
* 是按照指定标签名来进行查询并返回集合
* 这个集合的操作和数组一样
* 集合中都是 dom 对象
* 集合中元素顺序 是他们在 html 页面中从上到下的顺序
*/

let inputs = document.getElementsByTagName("input");

for(let i = 0;i < inputs.length;++i){
inputs[i].checked = true;
}
}
</script>

</head>
<body>
兴趣爱好:
<input type="checkbox" value="cpp" checked="checked">C++
<input type="checkbox" value="java">Java
<input type="checkbox" value="js">JavaScript
<br/>
<button onclick="checkAll()">全选</button>
</body>
</html>
document.createElement(tagName)

方法,通过给定的标签名,创建一个标签对象。tagName 是要创建的标签名

示例代码
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
window.onload = function(){
//现在需要我们还用 js 代码来创建 html 标签,并显示在页面上
// 标签的内容就是: <div> csq </div>
let divObj = document.createElement("div");// 在内存中 <div></div>

let textNodeObj = document.createTextNode("csq");// 有一个文本节点对象 #csq

divObj.appendChild(textNodeObj);

//divObj.innerHTML = "csq" // <div> csq</div> 但 还只是在内存中
//添加子元素
document.body.appendChild(divObj);
}
</script>
</head>
<body>

</body>
</html>

注:

document 对象的是哪个查询方法,如果有 id 属性,优先使用 getElementById 方法来进行查询,如果没有 id 属性,则优先使用 getElementsByName 方法来进行查询,如果id 属性 和 name 属性都没有最后再按标签名查 getElementsByTagName

以上三个方法,一定要在页面加载完成之后执行,才能查询到标签对象

节点的常用属性和方法

节点就是标签对象

方法

通过具体的节点调用

getElementsByName()

方法,获取当前节点的指定标签名的孩子节点

appendChild(oChildNode)

方法,可以添加一个子节点,oChildNode 是要添加的孩子节点

属性
childNodes

属性,获取当前节点的所有子节点

firstChild

属性,获取当前节点的第一个节点

lastChild

属性,获取当前节点的最后一个节点

parentNode

属性,获取当前节点的父节点

nextSibling

属性,获取当前节点的下一个节点

previousSibling

属性,获取当前节点的上一个节点

className

用于获取或设置标签的 class 属性值

innerHTML

属性,表示获取/设置起始标签和结束标签中的内容

innerText

属性,表示获取/设置起始标签和结束标签中的文本

DOM 查询练习

代码示例
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
147
148
149
150
151
152
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
window.onload = function(){
//1.查询 #bj 节点
document.getElementById("btn01").onclick = function(){
let bjObj = document.getElementById("bj");
alert(bjObj.innerHTML);
}


//2. 查找所有 li 节点

let btn02Ele = document.getElementById("btn02");
btn02Ele.onclick = function(){
let lis = document.getElementsByTagName("li");
alert(lis.length);
}


//3. 查找 name = gender 的所有节点

let btn03Ele = document.getElementById("btn03");
btn03Ele.onclick = function(){
let genders = document.getElementsByName("gender");
alert(genders.length);
}

//4. 查找 #city 下的所有 li 节点
let btn04Ele = document.getElementById("btn04");
btn04Ele.onclick = function(){
let lis = document.getElementById("city").getElementsByTagName("li");
alert(lis.length);
}

//5. 返回 #city 的所有子节点
let btn05Ele = document.getElementById("btn05");
btn05Ele.onclick = function(){
let childLength = document.getElementById("city").childNodes.length;
alert(childLength);
}

//6. 返回 #phone 的第一个子节点
let btn06Ele = document.getElementById("btn06");
btn06Ele.onclick = function(){
let firstChild = document.getElementById("phone").firstChild;
alert(firstChild.innerHTML);
}

//7. 返回 #bj 的父节点
let btn07Ele = document.getElementById("btn07");
btn07Ele.onclick = function(){
let parentNode = document.getElementById("bj").parentNode;
alert(parentNode.innerHTML);
}

//8. 返回 #android 的前一个兄弟节点
let btn08Ele = document.getElementById("btn08");
btn08Ele.onclick = function(){
let previousSibling = document.getElementById("android").previousSibling;
alert(previousSibling.innerHTML);
}

//9. 读取 #username 的value 值
let btn09Ele = document.getElementById("btn09");
btn09Ele.onclick = function(){
let value = document.getElementById("username").value;
alert(value);
}

//10. 设置 #username 的 value 属性值
let btn10Ele = document.getElementById("btn10");
btn10Ele.onclick = function(){
document.getElementById("username").value = "csq";
alert(document.getElementById("username").value);
}

//11. 返回 #bj 的文本值
let btn11Ele = document.getElementById("btn11");
btn11Ele.onclick = function(){
let innerText = document.getElementById("bj").innerText;
alert(innerText);
}
}
</script>
</head>
<body>
<div id="inner">
<p>
你喜欢哪个城市?
</p>

<ul id="city">
<li id="bj">北京</li>
<li>上海</li>
<li>南京</li>
<li>首尔</li>
</ul>

<br>
<br>

<p>
你喜欢哪款游戏?
</p>

<ul id="game">
<li id="lol">LOL</li>
<li>永劫无间</li>
<li>王者荣耀</li>
</ul>

<br />
<br />

<p>
你手机操作系统是?
</p>

<ul id="phone"><li>IOS</li><li id="android">Android</li></ul>
</div>

<div class="inner">
gender:
<input type="radio" name="gender" value="male"/>
Male
<input type="radio" name="gender" value="female"/>
Female
<br>
<br>
name:
<input type="text" name="name" id="username" value="abcde"/>
</div>

<div id="btnlist">
<div><button id="btn01">查找#bj节点</button></div>
<div><button id="btn02">查找所有li 节点</button></div>
<div><button id="btn03">查找 name = gender 的所有节点</button></div>
<div><button id="btn04">查找#city 下所有 li 节点</button></div>
<div><button id="btn05">返回#city 的所有子节点</button></div>
<div><button id="btn06">返回#phone 的第一个子节点</button></div>
<div><button id="btn07">返回#bj 的父节点</button></div>
<div><button id="btn08">返回#android 的前一个兄弟节点</button></div>
<div><button id="btn09">返回#username 的 value 属性值</button></div>
<div><button id="btn10">设置#username 的 value 属性值</button></div>
<div><button id="btn11">返回#bj 的文本值</button></div>
</div>
</body>
</html>

jQuery

jQuery 介绍


什么是jQuery

jQuery 是 JavaScript 和 查询(Query),是辅助 JavaScript 开发的 js 类库

jQuery 核心思想

核心思想就是 write less,do more,所以他实现了很多浏览器的兼容问题

jQuery 好处

jQuery 是免费、开源的,jQuery 的语法设计可以使开发更加便捷,例如操作文档对象、选择 DOM 对象、制作动画特效、事件处理、使用 Ajax 以及其他功能

常见问题

  1. 使用 jQuery 一定要引入 jQuery 库吗

    是,必须引入

  2. jQuery 中的 $ 是什么

    是一个函数

  3. 怎么为 按钮添加点击响应函数

    1. 使用 jQuery 查询标签对象
    2. 使用标签对象.click(function(){});

jQuery 核心函数


$ 是 jQuery 的核心函数,能完成 jQuery 的很多功能。$()就是 调用 $ 这个函数

  • 传入参数为 [函数] 时:

    表示页面加载完成之后。相当于 window.onclick = function(){}

  • 传入参数为 [HTML 字符串] 时:

    会对我们创建这个 HTML 标签对象

  • 传入参数为 [选择器字符串]时:

    • $("#id属性值"); id选择器,根据 id 查询标签对象

    • $("标签名"); 标签名选择器,根据指定的标签名查询标签对象

    • $(".class 属性值"); 类型选择器,可以根据 class 属性查询标签对象

  • 传入参数为 [DOM 对象] 时:

    会把这个 DOM 对象转换为 jQuery 对象

jQuery对象和dom 对象区分


jQuery对象、dom 对象

Dom对象
  • 通过 getElementById() 查询出来的标签对象是 Dom 对象
  • 通过 getElementsByName() 查询出来的标签对象是 Dom 对象
  • 通过 getElementsByTagName() 查询出来的是 Dom 对象
  • 通过 createElement() 方法创建出来的对象,是 Dom 对象

Dom 对象 alert 出来的效果是:[object HTML 标签名 Element]

jQuery 对象
  • 通过 jQuery 提供的 API 创建的对象,是jQuery 对象
  • 通过 jQuery 包装的 Dom 对象,是 jQuery 对象
  • 通过 jQuery 提供的 API 查询到的对象,也是 jQuery 对象

jQuery 对象 alert 出来的效果:[object Object]

jQuery 对象本质

jQuery 对象是 dom 对象的数组 + jQuery 提供的一系列功能函数

jQuery对象和dom对象使用区别

  • jQuery对象不能使用 DOM 对象的属性和方法
  • DOM 对象也不能使用 jQuery 对象的属性和方法

jQuery对象和 dom 对象互转

  • dom 对象转化为 jQuery 对象
    1. 先有 dom 对象
    2. $(dom 对象) 就可以转换成为 jQuery 对象
  • jQuery 对象转化为 dom 对象
    1. 先有 jQuery 对象
    2. jQuery 对象[下标] 取出相应的 dom 对象

jQuery 选择器


基本选择器

  • #ID 选择器

    根据 id 查找标签对象

  • .class 选择器

    根据 class 查找标签对象

  • element 选择器

    根据标签名选择标签对象

  • * 选择器

    表示任意的、所有的元素

  • selector 1,selector 2 组合选择器

    合并选择器1,选择器2 的结果并返回

p.myClass 表示 标签名必须是 p 标签,而且class 类型必须是 myClass 类型

层级选择器、

  • ancestor descendant 后代选择器

    在给定的祖先元素下匹配的所有的后代元素

  • parent > child 子元素选择器

    在给定的父元素下 匹配 所有的 子元素

  • prev + next 相邻元素选择器

    匹配所有紧接在 prev 元素后的 next 元素

  • prev ~ siblings 之后的兄弟元素选择器

    匹配 prev 元素之后的 所有 siblings 元素

过滤选择器

基本过滤器
  • first

    获取第一个元素

  • last

    获取最后一个元素

  • not(selector)

    去除所有与 给定选择器匹配的元素

  • even

    匹配所有索引值为 偶数 的元素,从 0 开始计数

  • odd

    匹配所有索引值为 奇数 的元素,从 0 开始计数

  • eq(index)

    匹配一个给定索引值的元素

  • gt(index)

    匹配所有大于给定索引值的元素

  • lt(index)

    匹配所有小于给定索引值的元素

  • header

    匹配如 h1,h2,h3 之类的标题元素

  • animated

    匹配所有正在执行动画效果的元素

内容过滤器
  • contains(text)

    匹配包含给定文本的元素

  • empty

    匹配所有不包含子元素或者文本的空元素

  • parent

    匹配含有子元素或者文本的元素

  • has(selector)

    匹配含有选择器所匹配的元素的元素

属性过滤器
  • [attribute]

    匹配包含给定属性的元素

  • [attribute = value]

    匹配给定的属性是某个特征值的元素

  • [attribute != value]

    匹配所有不含有指定的属性,或者属性不等于特征值的元素

  • [attribute ^= value]

    匹配给定的属性是以某些值开始的元素

  • [attribute $= value]

    匹配给定的属性是以某些值结尾的元素

  • [attribute *= value]

    匹配给定的属性是以包含某些值得元素

  • [attrSel1][attrSel2][attrSelN]

    复合属性选择器,需要同时满足多个条件时使用

表单过滤器
  • input

    匹配所有 input ,textarea.select 和 button 元素

  • text

    匹配所有文本输入框

  • password

    匹配所有的密码输入框

  • radio

    匹配所有的单选框

  • checkbox

    匹配所有的复选框

  • submit

    匹配所以的提交按钮

  • image

    匹配所有的 img 标签

  • reset

    匹配所有的重置按钮

  • button

    匹配所有的 input type = butoon

  • file

    匹配所有 input type = file 文件上传

  • hidden

    匹配所有不可见元素 display:none 或 input type = hidden

表单对象属性过滤器
  • enabled

    匹配所有可用元素

  • disabled

    匹配所有不可用元素

  • checked

    匹配所有选中的单选、复选和下拉列表中选中的 option 标签对象

  • selected

    匹配所有选中的 option

jQuery 元素筛选


eq()

获取给定索引的元素
功能跟eq()一样

first()

获取第一个元素
功能跟:first一样

last()

获取最后一个元素
功能跟last一样

filter(exp)

留下匹配的元素

is(exp)

判断是否匹配给定的选择器,只要有一个匹配就返回,tue

has(exp)

返回包含有匹配选择器的元素的元素功能跟:has一样

not(exp)

删除匹配选择器的元素
功能跟:not一样

children(exp)

返回匹配给定选择器的子元素
功能跟parent>:child一样

find(exp)

返回匹配给定选择器的后代元素
功能跟ancestor descendant一样

next()

返回当前元素的下一个兄弟元素
功能跟prev+next功能一样

nextAll()

返回当前元素后面所有的兄弟元素
功能跟prev~siblings功能一样

nextUntil()

返回当前元素到指定匹配的元素为止的后面元素

parent()

返回父元素

prev(exp)

返回当前元素的上一个兄弟元素

prevAll()

返回当前元素前面所有的兄弟元素

prevUnit(exp)

返回当前元素到指定匹配的元素为止的前面元素

siblings(exp)

返回所有兄弟元素

add()

把add匹配的选择器的元素添加到当前jquery对象中

jQuery 的属性操作


html()

他可以设置和获取起始标签和结束标签中的内容,跟dom 属性 innerHTML 一样

text()

他可以设置和获取起始标签和结束标签中的文本,跟 dom 属性 innerText 一样

val()

他可以设置和获取 表单项 的value 属性值,跟 dom 属性 value 一样

代码示例
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
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">

$(function () {
/*
// 批量操作单选
$(":radio").val(["radio2"]);
// 批量操作筛选框的选中状态
$(":checkbox").val(["checkbox3","checkbox2"]);
// 批量操作多选的下拉框选中状态
$("#multiple").val(["mul2","mul3","mul4"]);
// 操作单选的下拉框选中状态
$("#single").val(["sin2"]);
*/
$("#multiple,#single,:radio,:checkbox").val(["radio2","checkbox1","checkbox3","mul1","mul4","sin3"]);
});

</script>
</head>
<body>
<body>
单选:
<input name="radio" type="radio" value="radio1" />radio1
<input name="radio" type="radio" value="radio2" />radio2
<br/>
多选:
<input name="checkbox" type="checkbox" value="checkbox1" />checkbox1
<input name="checkbox" type="checkbox" value="checkbox2" />checkbox2
<input name="checkbox" type="checkbox" value="checkbox3" />checkbox3
<br/>

下拉多选 :
<select id="multiple" multiple="multiple" size="4">
<option value="mul1">mul1</option>
<option value="mul2">mul2</option>
<option value="mul3">mul3</option>
<option value="mul4">mul4</option>
</select>
<br/>

下拉单选 :
<select id="single">
<option value="sin1">sin1</option>
<option value="sin2">sin2</option>
<option value="sin3">sin3</option>
</select>
</body>
</body>
</html>

attr()

可以设置和获取属性的值,不推荐操作 checked

不推荐操作 checked、readOnly、selected、disabled 等

attr()方法还可以操作 非标准属性。比如自定义属性:abc,csq

prop()

可以设置和获取属性的值

只推荐操作 checked、readOnly、selected、disabled 等

代码示例
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
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">

$(function () {
//attr
// alert( $(":checkbox:first").attr("name") ); // 获取
// $(":checkbox:first").attr("name","abc") ; // 设置

// $(":checkbox").prop("checked",false );// 官方觉得返回undefined是一个错误

// $(":checkbox:first").attr("abc","abcValue");
// alert( $(":checkbox:first").attr("abc") );

// $("<h1>标题</h1>").prependTo( $("div") );
// $("<h1>标题</h1>").insertAfter("div");

// $("<h1>标题</h1>").insertBefore( $("div") );

// $("<h1>标题</h1>").replaceWith("div");

// $("div").replaceWith( $("<h1>标题</h1>") );

// $("<h1>标题</h1>").replaceAll( "div" );


$("div").empty();

});


</script>
</head>
<body>
<body>
<br/>
多选:
<input name="checkbox" type="checkbox" checked="checked" value="checkbox1" />checkbox1
<input name="checkbox" type="checkbox" value="checkbox2" />checkbox2
<br/><br/>
<div>1234</div>
<div>1234</div>
</body>
</body>
</html>

jQuery 练习


全选、全不选、反选

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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="../../script/jquery-1.7.2.js"></script>
<script type="text/javascript">

$(document).ready(function(){

// 给全选绑定事件
$("#checkedAllBtn").click(function(){
$(":checkbox").prop("checked",true);
});

//给全不选绑定单击事件
$("#checkedNoBtn").click(function(){
$(":checkbox").prop("checked",false);
});

//给反选绑定单击事件
$("#checkedRevBtn").click(function(){
//查询全部球类的复选框
$(":checkbox[name='items']").each(function(){
//each遍历的 function 函数中,有一个this 对象,这个this 对象是当前遍历到的 dom 对象
this.checked = !this.checked;
});

//要检查是否满选
//获取总球数
let allCount = $(":checkbox[name='items']").length;
//获取选中球数
let selectedCount = $(":checkbox[name='items']:checked").length;
if(allCount === selectedCount){
$("#checkedAllBox").prop("checked", true);
} else {
$("#checkedAllBox").prop("checked", allCount === selectedCount);
}
});

// 给提交按钮绑定单击事件
$("#sendBtn").click(function () {
$(":checkbox[name='items']:checked").each(function(){
alert(this.value);
});
});

// 给全选/全不选 绑定单击事件
$("#checkedAllBox").click(function(){

//
//$(":checked[name='items']").prop("checked",true);
$(":checkbox[name='items']").prop("checked",this.checked);
});

//给所有球类绑定单击事件
$(":checkbox[name='items']").click(function (){

//检查是否满选

//获取总球数
let allCount = $(":checkbox[name='items']").length;
//获取选中球数
let selectedCount = $(":checkbox[name='items']:checked").length;
if(allCount === selectedCount){
$("#checkedAllBox").prop("checked", true);
} else {
$("#checkedAllBox").prop("checked", allCount === selectedCount);
}
});

});

</script>
</head>
<body>

<form method="post" action="">

你爱好的运动是?<input type="checkbox" id="checkedAllBox" />全选/全不选

<br />
<input type="checkbox" name="items" value="足球" />足球
<input type="checkbox" name="items" value="篮球" />篮球
<input type="checkbox" name="items" value="羽毛球" />羽毛球
<input type="checkbox" name="items" value="乒乓球" />乒乓球
<br />
<input type="button" id="checkedAllBtn" value="全 选" />
<input type="button" id="checkedNoBtn" value="全不选" />
<input type="button" id="checkedRevBtn" value="反 选" />
<input type="button" id="sendBtn" value="提 交" />
</form>

</body>
</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
56
57
58
59
60
61
62
63
64
65
66
67
68
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
select {
width: 100px;
height: 140px;
}

div {
width: 130px;
float: left;
text-align: center;
}
</style>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">
// 页面加载完成
$(function () {
// 第一个按钮 【选中添加到右边】
$("button:eq(0)").click(function () {
$("select:eq(0) option:selected").appendTo($("select:eq(1)"));
});
// 第二个按钮 【全部添加到右边】
$("button:eq(1)").click(function () {
$("select:eq(0) option").appendTo($("select:eq(1)"));
});

// 第三个按钮 【选中删除到左边】
$("button:eq(2)").click(function () {
$("select:eq(1) option:selected").appendTo($("select:eq(0)"));
});

// 第四个按钮 【全部删除到左边】
$("button:eq(3)").click(function () {
$("select:eq(1) option").appendTo($("select:eq(0)"));
});
});
</script>
</head>
<body>

<div id="left">
<select multiple="multiple" name="sel01">
<option value="opt01">选项1</option>
<option value="opt02">选项2</option>
<option value="opt03">选项3</option>
<option value="opt04">选项4</option>
<option value="opt05">选项5</option>
<option value="opt06">选项6</option>
<option value="opt07">选项7</option>
<option value="opt08">选项8</option>
</select>

<button>选中添加到右边</button>
<button>全部添加到右边</button>
</div>
<div id="rigth">
<select multiple="multiple" name="sel02">
</select>
<button>选中删除到左边</button>
<button>全部删除到左边</button>
</div>

</body>
</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
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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Untitled Document</title>
<link rel="stylesheet" type="text/css" href="styleB/css.css" />
<script type="text/javascript" src="../../script/jquery-1.7.2.js"></script>
<script type="text/javascript">

$(function(){

// 定义删除函数
let deleteFun = function(){

//在事件响应的 function () 函数中,有一个 this 对象,这个 this 对象是当前正在响应事件的dom 对象
let $trObj = $(this).parent().parent();

let name = $trObj.find("td:first").text();

/**
* confirm 是JavaScript语言提供的一个确认提示框函数。你给它传什么,它就提示什么<br/>
* 当用户点击了确定,就返回true。当用户点击了取消,就返回false
*/
if(confirm("你确定要删除 " + name + "吗")){
$trObj.remove();
}
// return false 可以组织元素的默认行为
return false;
}

// 给【Submit】按钮绑定单击事件
$("#addEmpButton").click(function(){
// 获取输入框,姓名,邮箱,工资的内容
let name = $("#empName").val();
let email = $("#email").val();
let salary = $("#salary").val();

// 创建一个行标签对象,添加到显示数据的表格中
let $trObj = $("<tr>" +
"<td>" + name + "</td>" +
"<td>" + email + "</td>" +
"<td>" + salary + "</td>" +
"<td><a href=\"deleteEmp?id=002\">Delete</a></td>" +
"</tr>");
// 添加到显示数据的表格中
$trObj.appendTo($("#employeeTable"));
// 给添加的行的a标签绑上事件
$trObj.find("a").click(deleteFun);
});

//给a绑定事件
$("a").click(deleteFun);

});



</script>
</head>
<body>

<table id="employeeTable">
<tr>
<th>Name</th>
<th>Email</th>
<th>Salary</th>
<th>&nbsp;</th>
</tr>
<tr>
<td>Tom</td>
<td>tom@tom.com</td>
<td>5000</td>
<td><a href="deleteEmp?id=001">Delete</a></td>
</tr>
<tr>
<td>Jerry</td>
<td>jerry@sohu.com</td>
<td>8000</td>
<td><a href="deleteEmp?id=002">Delete</a></td>
</tr>
<tr>
<td>Bob</td>
<td>bob@tom.com</td>
<td>10000</td>
<td><a href="deleteEmp?id=003">Delete</a></td>
</tr>
</table>

<div id="formDiv">

<h4>添加新员工</h4>

<table>
<tr>
<td class="word">name: </td>
<td class="inp">
<input type="text" name="empName" id="empName" />
</td>
</tr>
<tr>
<td class="word">email: </td>
<td class="inp">
<input type="text" name="email" id="email" />
</td>
</tr>
<tr>
<td class="word">salary: </td>
<td class="inp">
<input type="text" name="salary" id="salary" />
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button id="addEmpButton" value="abc">
Submit
</button>
</td>
</tr>
</table>

</div>

</body>
</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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body {
text-align: center;
}
#small {
margin-top: 150px;
}
#showBig {
position: absolute;
display: none;
}
</style>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function(){
$("#small").bind("mouseover mouseout mousemove",function(event){
if(event.type == "mouseover"){
$("#showBig").show();
} else if(event.type == "mousemove"){
console.log(event);
$("#showBig").offset({
left:event.pageX + 10,
top:event.pageY + 10
});
} else if(event.type == "mouseout"){
$("#showBig").hide();
}
});
});
</script>
</head>
<body>

<img id="small" src="img/small.jpg" />

<div id="showBig">
<img src="img/big.jpg">
</div>

</body>
</html>

dom 的增删改


内部插入

appendTo()

a.appendTo(b)

把a 插入到 b 子元素末尾,称为最后一个元素

prependTo()

a.preepend(b)

把 a 插到 b 所有子元素前面,成为第一个元素

外部插入

insertAfter()

a.insertAfter(b)

得到 ba

insertBefore()

a.insertBefore(b)

得到 ab

替换

replaceWith()

a.replaceWith(b)

用 b 替换 a

replaceAll()

a.replacerAll(b)

用 a 替换掉所有的 b

删除

remove()

a.remove();

删除 a 标签

empty()

a.empty();

清空 a 标签里的内容

CSS 样式操作


addClass()

添加样式

removeClass()

删除样式

toggleClass()

有就删除,没有就添加

offSet()

获取和设置元素的坐标

jQuery 动画


基本动画

show()

将隐藏的元素显示

hide()

将可见的元素隐藏

toggle()

可见就隐藏,不可见就显示

以上动画方法都可以添加参数

  • 第一个参数就是动画 执行的时长,以毫秒为单位
  • 第二个参数就是动画的回调参数(动画完成之后自动调用的函数)

淡入淡出动画

fadeIn()

淡入(慢慢可见)

fadeOut()

淡出(慢慢消失)

fadeTo()

在指定的时长内慢慢的将透明度修改到指定的值。 0:透明 1:完成可见 0.5:半透明

fadeToggle()

淡入/淡出 切换

动画练习

品牌展示

需求:
1.点击按钮的时候, 隐藏和显示卡西欧之后的品牌。
2.当显示全部内容的时候, 按钮文本为“显示精简品牌”
然后, 小三角形向上。 所有品牌产品为默认颜色。
3.当只显示精简品牌的时候, 要隐藏卡西欧之后的品牌, 按钮文本为“显示全部品牌”
然后小三形向下。 并且把 佳能, 尼康的品牌颜色改为红色(给 li 标签添加 promoted 样式即可)

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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>品牌展示练习</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}

body {
font-size: 12px;
text-align: center;
}

a {
color: #04D;
text-decoration: none;
}

a:hover {
color: #F50;
text-decoration: underline;
}

.SubCategoryBox {
width: 600px;
margin: 0 auto;
text-align: center;
margin-top: 40px;
}

.SubCategoryBox ul {
list-style: none;
}

.SubCategoryBox ul li {
display: block;
float: left;
width: 200px;
line-height: 20px;
}

.showmore , .showless{
clear: both;
text-align: center;
padding-top: 10px;
}

.showmore a , .showless a{
display: block;
width: 120px;
margin: 0 auto;
line-height: 24px;
border: 1px solid #AAA;
}

.showmore a span {
padding-left: 15px;
background: url(img/down.gif) no-repeat 0 0;
}

.showless a span {
padding-left: 15px;
background: url(img/up.gif) no-repeat 0 0;
}

.promoted a {
color: #F50;
}
</style>
<script type="text/javascript" src="script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function() {
//基本初始状态
$("li:gt(5):not(:last)").hide();

//给功能的按钮绑定单击事件
$("div div a").click(function(){

//让某些品牌显示或隐藏
$("li:gt(5):not(:last)").toggle();
//判断 品牌,是否当前可见
if($("li:gt(5):not(:last)").is(":hidden")){
//品牌隐藏的状态: 1显示全部品牌 == 角标向下 showmore
$("div div a span").text("显示全部品牌");

$("div div").removeClass();
$("div div").addClass("showmore");

//去掉高亮
$("li:contains('索尼')").removeClass("promoted");
} else {
//品牌可见的状态 : 2 显示精简品牌 == 角标向上 showless
$("div div a span").text("显示精简品牌");

$("div div").removeClass();
$("div div").addClass("showless");

//加高亮
$("li:contains('索尼')").addClass("promoted");
}
return false;
});

});
</script>
</head>
<body>
<div class="SubCategoryBox">
<ul>
<li><a href="#">佳能</a><i>(30440) </i></li>
<li><a href="#">索尼</a><i>(27220) </i></li>
<li><a href="#">三星</a><i>(20808) </i></li>
<li><a href="#">尼康</a><i>(17821) </i></li>
<li><a href="#">松下</a><i>(12289) </i></li>
<li><a href="#">卡西欧</a><i>(8242) </i></li>
<li><a href="#">富士</a><i>(14894) </i></li>
<li><a href="#">柯达</a><i>(9520) </i></li>
<li><a href="#">宾得</a><i>(2195) </i></li>
<li><a href="#">理光</a><i>(4114) </i></li>
<li><a href="#">奥林巴斯</a><i>(12205) </i></li>
<li><a href="#">明基</a><i>(1466) </i></li>
<li><a href="#">爱国者</a><i>(3091) </i></li>
<li><a href="#">其它品牌相机</a><i>(7275) </i></li>
</ul>
<div class="showmore">
<a href="more.html"><span>显示全部品牌</span></a>
</div>
</div>
</body>
</html>


jQuery 事件操作


$function(){};window.onload(){} 区别

什么时候触发
  1. jQuery 的页面加载完成之后是浏览器的内核解析完页面的标签创建好 dom 对象之后就会马上执行
  2. 原生 js 的页面加载完成之后,除了要等浏览器内核解析完标签创建好 dom 对象,还要等标签显示时需要的内容加载完成
触发的顺序
  1. jQuery 页面加载完成之后先执行
  2. 原生 js 的页面加载完成之后
执行的次数
  1. 原生 js 的页面加载完成之后,只会执行最后一次的赋值函数
  2. jQuery 的页面加载完成之后是全部把注册的 function 函数,依次顺序执行

jQuery 其他事件处理方法

click()

他可以绑定单击事件,以及触发单击事件

mouseover()

鼠标移入事件

mouseout()

鼠标移除事件

bind()

可以给元素一次性绑定一个或多个事件

one()

使用上跟 bind() 一样。但是one ()绑定的事件只会响应一次

unbind()

跟 bind() 相反的操作,解除事件的绑定

live()

也是用来绑定事件,他可以用来绑定选择器匹配的所有元素的事件。哪怕这个元素是后面动态创建出来的也有效

事件的冒泡

事件的冒泡是指,父子元素同时监听同一个元素,当触发子元素的时候,同一个事件也被传递到了父元素的事件里去响应

如何阻止事件冒泡

在子元素事件函数体中,return false; 可以阻止事件的冒泡传递

JavaScript 事件对象


事件对象,是封装有触发的事件信息的一个 js 对象

我们重点关心的是 怎么拿到这个 js 事件对象,以及使用

获取 JavaScript 事件对象

在给元素绑定事件对象的时候,在事件的 function(event) 参数列表中添加一个参数,这个参数名,我们习惯取名为 event ,这个event 就是 JavaScript 传递参数事件处理函数的事件对象

JavaScript 获取事件对象
1
2
3
4
5
window.onload = function(){
document.getElementById("areaDiv").onclick() = function(event){
console.log(event);
}
}
jQuery 获取事件对象
1
2
3
4
5
$(function(){
$("#areaDiv").click(function(event){
console.log(event);
});
});
bind 对多个事件绑定同一个函数
1
2
3
4
5
6
7
$("area").bind("mouseover mouseout",function(event){
if(event.type == "mouseover"){
console.log("鼠标移入");
} else if(event.type == "mouseout"){
console.log("鼠标移出");
}
});

XML

xml 是可扩展的标记性语言

xml 的作用


  • 用来保存数据,而且这些数据有自我描述性
  • 他还可以作为项目或者模块的配置文件
  • 还可以作为网络传输数据的格式(现在 json 为主)

xml 语法


文档声明

1
2
<?xml version="1.0" encoding="UTF-8"?> <!-- xml 声明-->
<!-- version 是版本的意思 encoding 是编码的意思-->

<?xml 要连在一起写,要不会报错

属性
  • version - 版本号
  • encoding - xml 文件编码
  • standalone=”yes/no” - 表示这个 xml 文件是否是独立的 xml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8" ?>
<!--
<?xml version="1.0" encoding="UTF-8 ?>
以上内容就是 xml 文件的声明
version="1.0" version 表示 xml的版本
encoding="UTF-8 encoding 表示文件本身的编码
-->
<books> <!-- books 表示多个图书信息-->
<book sn="SN122323232"> <!-- 表示 一个图书信息 sn 表示图书序列号-->
<name>时间简史</name> <!-- name 表示书名-->
<author>霍金</author> <!-- author 表示作者-->
<price>100</price> <!-- price 表示价格 -->
</book>
<book sn="SN3244324234">
<name>java从入门到放弃</name>
<author>ss</author>
<price>100</price>
</book>
</books>

xml 注释

HTML 和 xml 注释一样

<!-- 注释 -->

元素(标签)

什么是 xml 元素

xml 元素是从(且包括)开始标签直到(且包括)结束标签的部分

元素可包含其他元素、文本或者两者的混合物。元素也可以拥有属性

xml 命名规则
  1. 名称可以包含字母、数字以及其他的字符
  2. 名称不能以数字或者标点符号开始
  3. 名称不能包含空格
xml 中的元素(标签)也分成单标签和双标签
  • 单标签

    格式:<标签名 属性="值" 属性="值".../>

  • 双标签

    格式:<标签名 属性="值" 属性="值" ...> 文本数据或子标签 </标签名>

xml 属性

xml 的标签属性 和 html 的标签属性是非常相似的,属性可以提供元素的额外信息

在标签上可以书写属性

​ 一个标签可以书写多个属性。每个属性的值必须使用 引号 引起来 。 规则和标签的书写规则一致

XML 元素可以在开始标签中包含属性,类似 HTML

属性(Attribute) 提供关于元素的额外信息

xml 语法规则

  • 所有 xml 元素都必须有关闭标签(也就是闭合)

  • XML 标签对大小写敏感

  • xml 必须正确地嵌套

  • xml 文档必须有根元素

    根元素就是顶级元素,没有父标签的元素叫做顶级元素,根元素是没有父标签的顶级元素,而且是唯一一个才行

  • xml 的属性值必须加 引号

  • xml 中的特殊字符

    • > 特殊字符:&gt;
    • < 特殊字符:&lt;
  • 文本区域(CDATA区)

    CDATA 语法可以告诉 xml 解析器,我 CDATA 里的文本内容,只是纯文本内容,不需要 xml 语法解析

    CDATA 格式:

    <![CDATA[这里可以把你输入的字符原样提示,不会解析 xml]]>

xml 解析技术


xml 可扩展的标记语言

不管是 html 还是 xml 文件 他们都是标记型文档,都可以使用 w3c 组织指定的 dom 技术来解析

xml 文档对象模型定义访问和操作 XML 文档的标准方法

DOM 将 xml 文档作为一个树形结构,而树叶被定义为节点

document 对象表示的是整个文档(可以是 HTML 文档,也可以是 xml 文档)

dom4j 解析技术


由于 dom4j 不是 sun 公司的技术,而属于第三方公司的技术,我们需要使用 dom4j 就需要 dom4j 官网下载 dom4j 的 jar 包

Dom4j 类库的使用

dom4j 编程步骤
  1. 先加载 xml 文件创建 Document 对象
  2. 通过 Document 对象拿到 根元素
  3. 通过 根元素.elements(“标签名”); 可以返回一个集合,这个集合里放着,所有你指定的标签名的元素对象
  4. 找到你想要修改、删除的子元素,进行相应的操作
  5. 保存到硬盘上
步骤
  1. 先创建 SAXReader 对象,这个对象,用于读取 xml 文件,并创建 document
  2. 通过 document 对象,拿到 xml 的根元素对象
  3. 通过根元素对象,获取所有的 book 标签对象
  4. 遍历每个 book 标签对象,然后获取到 book 标签对象内的每一个元素,再通过 getText() 方法拿到起始标签和结束标签之间的文本内容
代码示例
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
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;

import java.util.List;

/**
* @author C77eric
* @version 1.0
*/
public class dom4jTest {
/**
* dom4j 获取 Document 对象
*/
@Test
public void getDocument() throws Exception {

//要创建一个 Document 对象,需要我们先创建一个 SAXReader 对象
SAXReader reader = new SAXReader();
// 这个对象 用于读取 xml 文件,然后返回一个 Document
Document document = reader.read("src/books.xml");
//打印到控制台,看看是否创建成功
System.out.println(document);
}

@Test
public void readXML() throws Exception {
/*
需要分四步操作:
1.通过创建 SAXReader 对象,来读取 xml 文件,获取 document 对象
2.通过 document 对象,拿到 XML 的根元素对象
3.通过根元素对象,获取所有的 book 标签对象
4.遍历每个 book 标签对象,然后获取到 book 标签对象内的每一个元素,
再通过 getText() 方法拿到起始标签和结束标签之间的文本内容
*/
// 1. 通过创建 SAXReader 对象,来读取 xml 文件。获取document 对象
SAXReader reader = new SAXReader();
Document document = reader.read("src/books.xml");

//2. 通过 document 对象,拿到 xml 的根元素对象
Element root = document.getRootElement();
//打印测试
// Element.asXML() 它将当前元素转换为 String 对象
// root.asXML();
// System.out.println(root);

//3. 通过根元素对象,获取所有的 book 标签对象
//Element.elements("标签名") 可以拿到当前元素下的指定的子元素的集合
List<Element> books = root.elements("book");

//4. 遍历每个book 标签对象,然后获取到 book 标签对象内的每一个元素
for(Element book : books) {

//拿到 book 下面的 name 对象
Element nameElement = book.element("name");
// 拿到book 下面的 price 对象
Element priceElement = book.element("price");
//拿到 book 下面的 author 对象
Element authorElement = book.element("author");

//再通过 getText() 方法拿到起始标签和结束标签之间的文本内容
System.out.println("书名:" + nameElement.getText() + " 价格:" + priceElement.getText() + " 作者:" + authorElement.getText());
}
}

}

Tomcat

JavaWeb 的概念


什么是 JavaWeb

javaweb 是指所有通过 Java 语言编写可以通过浏览器访问的程序的总称,叫 Javaweb

JavaWeb 是基于请求和响应来开发的

什么是请求

请求是指客户端给服务器发送数据,叫请求 request

什么是响应

响应是指服务器给客户端回传数据,叫响应 response

请求和响应的关系

请求和响应是成对出现的,有请求就有响应

Web 资源的分类


web 资源按实现的技术和呈现的效果的不同,又分为静态资源和动态资源两种

  • 静态资源

    HTML、css、js、txt、mp4视频、jpg图片

  • 动态资源

    jsp页面、servlet 程序

常用的 Web 服务器


  • Tomcat:Apache 组织提供的一种 Web 服务器, 提供对 jsp 和 Servlet 的支持。 它是一种轻量级的 javaWeb 容器(服务
    器) , 也是当前应用最广的 JavaWeb 服务器(免费)

  • Jboss: 是一个遵从 JavaEE 规范的、 开放源代码的、 纯 Java 的 EJB 服务器, 它支持所有的 JavaEE 规范(免费)

  • GlassFish: 由 Oracle 公司开发的一款 JavaWeb 服务器, 是一款强健的商业服务器, 达到产品级质量(应用很少)

  • Resin: 是 CAUCHO 公司的产品, 是一个非常流行的服务器, 对 servlet 和 JSP 提供了良好的支持,
    性能也比较优良, resin 自身采用 JAVA 语言开发(收费, 应用比较多)

  • WebLogic: 是 Oracle 公司的产品, 是目前应用最广泛的 Web 服务器, 支持 JavaEE 规范,
    而且不断的完善以适应新的开发要求, 适合大型项目(收费, 用的不多, 适合大公司)

Tomcat 服务器和 Servlet 版本的对应关系


当前企业常用的版本 7.* 8.*

Tomcat版本 Servlet/JSP版本 JavaEE版本 运行环境
4.1 2.3/1.2 1.3 JDK 1.3
5.0 2.4/2.0 1.4 JDK 1.4
5.5/6.0 2.5/2.1 5.0 JDK 5.0
7.0 3.0/2.2 6.0 JDK 6.0
8.0 3.1/2.3 7.0 JDK 7.0

Servlet 程序从 2.5 版本就是现在世面使用最多的版本(xml 配置)

到了Servlet 3.0 之后,就是注解版本的 Servlet 使用

Tomcat 的使用


Servlet

Servlet 技术


什么是 Servlet

  1. Servlet 就是 JavaEE 规范之一。规范就是接口
  2. Servlet 就是 JavaWeb 三大组件之一。三大组件分别是
    • Servlet 程序
    • Filter 过滤器
    • Listener 监听器
  3. Servlet 是运行在服务器上的一个 Java 小程序,他可以接收客户端发送来的请求,并响应数据给客户端

手动实现 Servlet 程序

  1. 编写一个类去实现 Servlet 接口
  2. 实现 service 方法,处理请求,并相应数据
  3. 到 web.xml 中去配置 Servlet 程序的访问地址
Servlet 程序代码
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
package com.csqservlet.servlet_;

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

/**
* @author C77eric
* @version 1.0
*/
public class helloServlet_ implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {

}

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

/**
* service 方法是专门用来处理请求和响应的
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("helloServlet 被访问了");
}

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

@Override
public void destroy() {

}
}




<!-- servlet 标签给 Tomcat 服务器配置 servlet 程序 -->
<servlet>
<!-- servlet-name 标签 :给servlet程序起一个别名 (一般是类名)-->
<servlet-name>helloServlet_</servlet-name>
<!-- servlet-class 标签: 是 servlet 程序的全类名 -->
<servlet-class>com.csqservlet.servlet_.helloServlet_</servlet-class>
</servlet>

<!-- servlet-mapping 标签:给 servlet 程序配置访问地址-->
<servlet-mapping>
<!-- servlet-name 标签:告诉服务器,我当前配置的地址 给哪个 servlet 程序使用-->
<servlet-name>helloServlet_</servlet-name>
<!-- url-pattern 标签:配置访问地址
/ 斜杠在服务器解析的时候,表示地址为 http://ip:port/工程路径
/hello 表示地址为:http://ip:port/工程路径/hello
-->
<url-pattern>/abc</url-pattern>
</servlet-mapping>

url 地址到 servlet 程序的访问

image-20221027111329959

Servlet 的生命周期

  1. 执行 servlet 构造器方法
  2. 执行 init 初始化方法
  3. 执行 service 方法
  4. 执行 destroy 销毁方法

第一、二步是在第一次访问的时候创建 servlet 程序会调用

第三步每次访问都会调用

第四步在 web 工程停止的时候调用

代码示例
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
package com.cs7eric.servlet;

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

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet implements Servlet {

public HelloServlet() {
System.out.println("HelloServlet 的构造器");
}

@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("HelloServlet 的init 方法");
}

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

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service 被访问了!!");
}

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

@Override
public void destroy() {

}
}

get 和 post 请求的分发请求

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
package com.cs7eric.servlet;

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

@WebServlet(name = "helloServlet", value = "/hello-servlet")
public class HelloServlet implements Servlet {

public HelloServlet() {
System.out.println("HelloServlet 的构造器");
}

@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("HelloServlet 的init 方法");
}

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

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 service == Hello Servlet 被访问了");
// 类型转换(因为他有 getMethod() 方法)
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

//获取请求的方式
String method = httpServletRequest.getMethod();
if("GET".equals(method)){
doGet();
} else if("POST".equals(method)){
doPost();
}
System.out.println("service 被访问了!!");
}

/**
* 做 get 请求的操作
*/
public void doGet(){
System.out.println("get 请求");
System.out.println( "get 请求");
}

/**
* 做 post 请求的操作
*/
public void doPost(){
System.out.println("doPost请求");
System.out.println("doPost请求");
}


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

@Override
public void destroy() {

}
}

通过继承 HttpServlet 实现Servlet 程序

一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序

  1. 编写一个类去继承 HttpServlet 类
  2. 根据业务需要重写 doGet 或 doPost 方法
  3. 到 web.xml 中的 配置 servlet 程序的访问地址
servlet 类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.cs7eric.servlet;
/**
* @author C77eric
* @version 1.0
*/

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

public class HelloServlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get 请求");
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post 请求");
}
}

web.xml 配置代码
1
2
3
4
5
6
7
8
<servlet>
<servlet-name>HelloServlet3</servlet-name>
<servlet-class>com.cs7eric.servlet.HelloServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet3</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>

Servlet 类 的继承体系

image-20221027121409037

ServletConfig 类


ServletConfig 类从类名上看,就知道是 Servlet 程序的配置信息类

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

Servlet程序默认是第一次访问的时候创建的,ServletConfig 是每个 Servlet程序创建时,就创建一个对应的 ServletConfig 对于旋风

ServletConfig 类的三大作用

  1. 可以获取Servlet 程序的别名 servlet-name 的值
  2. 获取初始化参数 init-parm
  3. 获取 ServletContext 对象
web.xml 中的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- servlet 标签给 Tomcat 服务器配置 servlet 程序 -->
<servlet>
<!-- servlet-name 标签 :给servlet程序起一个别名 (一般是类名)-->
<servlet-name>HelloServlet</servlet-name>
<!-- servlet-class 标签: 是 servlet 程序的全类名 -->
<servlet-class>com.cs7eric.servlet.HelloServlet</servlet-class>
<!-- init-param 是初始化参数 -->
<init-param>
<!-- param-name 是参数名 -->
<param-name>username</param-name>
<!-- param-value 是参数值 -->
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</servlet>
Servlet 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
System.out.println("HelloServlet 的init 方法");
System.out.println("----------------------------------");
//1.可以获取 Servlet 程序的别名 servlet-name 的值
System.out.println("HelloServlet 程序的别名:" + servletConfig.getServletName());
//2.获取初始化参数 init-param
System.out.println("初始化参数 username 的值:" + servletConfig.getInitParameter("username"));
System.out.println("初始化参数 url 的值:" + servletConfig.getInitParameter("url"));
//3.获取 ServletContext 对象
System.out.println(servletConfig.getServletContext());
}

ServletContext 类


什么是 ServletContext

  1. ServletContext 是一个接口,他表示 Servlet 上下文对象
  2. 一个 web 工程,只有一个 ServletContext 对象实例
  3. ServletContext 对象是一个域对象
  4. ServletContext 是在 web 工程部署启动的时候创建,在 web 工程停止的时候销毁

什么是域对象

域对象,是可以像 Map 一样存取数据的对象,叫做域对象

这里的域指的是 存取数据的操作范围,整个 web 工程

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

ServletContext 类的四个作用

  1. 获取 web.xml 中配置的上下文参数 context-param
  2. 获取当前的工程路径,格式:/工程路径
  3. 获取工程部署后在服务器硬盘上的绝对路径
  4. 像 Map 一样存取数据
获取参数
Servlet 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取 web.xml 中配置的上下文参数 context-param
javax.servlet.ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
System.out.println("context-param 参数 username 的值是:" + username);
System.out.println("context-param 参数 password 的值是:" + context.getInitParameter("password"));

//2.获取当前的工程路径,格式:/工程路径
System.out.println("当前工程路径:" + context.getContextPath());

//3.获取工程部署后在服务器硬盘上的绝对路径
/*
/ 斜杠被服务器解析地址为 http://ip:port/工程名 映射到 IDEA 代码的 web 目录 <br/>
*/
System.out.println("工程部署的路径是:" + context.getRealPath("/"));
System.out.println("工程 css 目录的绝对路径是" + context.getRealPath("/css"));
System.out.println("工程下 img 目录下 1.png的绝对路径:" + context.getRealPath("/imgs/1.png"));

}
web.xml 文件
1
2
3
4
5
6
7
8
9
<!-- context-param 是上下文参数(它属于整个 web 工程) -->
<context-param>
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
像 Map 一样存取数据
ServletContext3 代码
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
package com.cs7eric.servlet; /**
* @author C77eric
* @version 1.0
*/

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

public class ServletContext3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取 ServletContext 对象
ServletContext context = getServletContext();
System.out.println(context);
System.out.println("保存之前的值:context1 获取 key1 的值是:" + context.getAttribute("key1"));

context.setAttribute("key1","value1");

System.out.println("context1 获取域数据 key1 的值是" + context.getAttribute("key1"));

}

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

}
}

ServletContext2 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.cs7eric.servlet; /**
* @author C77eric
* @version 1.0
*/

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

public class ServletContext2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println(context);
System.out.println("Context2 中获取域数据 key1的值是:" + context.getAttribute("key1"));
}

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

}
}

HTTP 协议


什么是 HTTP 协议

什么是协议

协议是指双方,或者多方,相互约定好,大家都需要遵守的规则,叫协议

HTTP 协议

客户端与服务器之间通信时,发送的数据,需要遵守的规则,叫 HTTP 协议。

HTTP 协议中的数据又叫 报文

请求的 HTTP 协议格式

客户端给服务器发送数据叫请求

服务器给客户端发送数据叫响应

请求又分为 GET 请求和 POST 请求两种

GET 请求
  1. 请求行
    • 请求的方式 GET
    • 请求的资源路径 [+ ? + 请求参数]
    • 请求的协议的版本号 HTTP/1.1
  2. 请求头
    • key :value 组成 不同的键值对,表示不同的含义

image-20221027163010124

POST 请求
  1. 请求行

    • 请求的方式 POST
    • 请求的资源路径 [ + ? + 请求参数]
    • 请求的协议版本号 HTTP/1.1
  2. 请求头

    • key : value 不同的请求头,有不同的含义

      空行

  3. 请求体 就是发送给服务器的数据

uTools_1666859645499

常用请求头的说明
  • Accept:表示客户端可以接收的数据类型
  • Accept-Languege : 表示客户端可以接收的语言类型
  • User-Agent : 表示客户端浏览器的信息
  • Host :表示请求时的 服务器的 ip 和端口号
GET / POST 请求
GET 请求
  1. form 标签 method=get
  2. a 标签
  3. link 标签引入 css
  4. Script 标签 引入 js 文件
  5. img 标签引入图片
  6. iframe 引入 HTML 页面
  7. 在浏览器地址栏中输入地址后敲回车
POST 请求
  1. form 标签 method=post

响应的 HTTP 协议格式

  1. 响应行

    • 响应的协议和版本号
    • 响应状态码
    • 响应状态描述符
  2. 响应头

    • key : value 不同的响应头,有其不同含义

      空行

  3. 响应体 就是回传给客户端的数据

uTools_1666871966924

常用的响应码

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

MIME 类型说明

MIME是 HTTP 协议中的数据类型

全称是: Multipurpose Internet Mail Extensions 多功能 Internet 邮件扩充服务。MIME 类型的格式是 ” 大类型/小类型“,并与某一种文件的扩展名相对应

常见的MIME 类型
文件 MIME 类型
超文本标记语言文本 .html, .htm text/html
普通文本 .txt text/plain
RTF 文本 .rtf application/rtf
GIF 图形 .gif image/gif
JPEG 图形 .jpeg, .jpg image/jpeg
au 声音文件 .au audio/basic
MIDI 音乐文件 mid,.midi audio/midi audio/x-midi
RealAudio 音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG 文件 .mpg,.mpeg video/mpeg
AVI 文件 .avi video/x-msvideo
GZIP 文件 .gz application/x-gzip
TAR 文件 .tar application/x-tar

HttpServletRequest 类


HttpServletRequest 类的作用

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

HttpServletRequest 的常用方法

  1. getRequestURI()

    ​ 获取请求的资源路径

  2. getRequestURL()

    ​ 获取请求的统一资源定位符(绝对路径)

  3. getRomoteHost()

    ​ 获取客户端的 IP 地址

  4. getHeader()

    ​ 获取请求头

  5. getParameter()

    ​ 获取请求的参数

  6. getParameterValues()

    ​ 获取请求的参数(多个值的时候使用)

  7. getMethodA()

    ​ 获取请求的方式 GET 或者 POST

  8. setAttribute(key,value)

    ​ 设置域数据

  9. getAttribute(key)

    ​ 获取域数据

  10. getRequestDispatcher()

    ​ 获取请求转发对象

常用 API 代码示例
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
package com.cs7eric.servlet2; /**
* @author C77eric
* @version 1.0
*/

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

public class RequestAPIServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.getRequestURI() 获取请求的资源路径
System.out.println("URI:" + request.getRequestURI());

//2.getRequestURL() 获取请求的统一资源路径定位符(绝对路径))
System.out.println("URL:" + request.getRequestURL());

//3.getRemoteHost 获取客户端的 IP 地址
/*
在IDEA 中,使用 localhost 访问时,得到的客户端 IP 地址是 :127.0.0.1 <br/>
在IDEA 中,使用 127.0.0.1 访问时,得到的客户端 IP 地址是: 127.0.0.1 <br/>
在IDEA 中,使用真实 IP 访问时,得到的客户端 IP 地址是 : 真实的客户端 IP 地址 <br/>
*/
System.out.println("客户端地址:" + request.getRemoteHost());

//4.getHeader 获取表头
System.out.println("请求头 User-agent:" + request.getHeader("User-agent"));

//5.getMethod() 获取请求的方式 GET 、POST
System.out.println("请求的方式:" + request.getMethod());

}

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

}
}

如何获取请求参数

GET
java 代码
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
package com.cs7eric.servlet2; /**
* @author C77eric
* @version 1.0
*/

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

public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbies = request.getParameterValues("hobby");

System.out.println("用户名:" + username);
System.out.println("密码:" + password);
System.out.println("兴趣爱好" + Arrays.asList(hobbies));
}

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

}
}

html 页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8088/servlet2_war/parameterServlet" method="get">
用户名:<input type="text" name="username"><br/>
密码: <input type="password" name="password"><br/>
兴趣爱好: <input type="checkbox" name="hobby" value="cpp"> C++
<input type="checkbox" name="hobby" value="java"> Java
<input type="checkbox" name="hobby" value="js">JS
<input type="submit">
</form>
</body>
</html>
doGet 请求的中文乱码解决
1
2
3
4
5
6
//获取请求参数
String username = request.getParameter("username");

//1. 先以 iso8859-1 进行编码
//2. 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"),"UTF-8");
POST
html 页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8088/servlet2_war/parameterServlet" method="get">
用户名:<input type="text" name="username"><br/>
密码: <input type="password" name="password"><br/>
兴趣爱好: <input type="checkbox" name="hobby" value="cpp"> C++
<input type="checkbox" name="hobby" value="java"> Java
<input type="checkbox" name="hobby" value="js">JS
<input type="submit">
</form>
</body>
</html>
POST 请求的中文乱码解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求体的字符集为 UTF-8 ,从而解决 post 请求的中文乱码问题
request.setCharacterEncoding("UTF-8");
System.out.println("--------------- doPost---------------");

//获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbies = request.getParameterValues("hobby");

System.out.println("用户名:" + username);
System.out.println("密码:" + password);
System.out.println("兴趣爱好" + Arrays.asList(hobbies));

}

请求转发

服务器收到请求后,从一个资源跳转到另一个资源的操作叫做请求转发

uTools_1666881583448
Servlet1 代码
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
package com.cs7eric.servlet2; /**
* @author C77eric
* @version 1.0
*/

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

public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求的参数(办事的材料)查看
String username = request.getParameter("username");
System.out.println("在 Servlet1 (柜台 1) 中查看参数(材料) :" + username );

//给材料盖一个章,并传递到 Servlet2 (柜台2) 中去查看
request.setAttribute("key1","柜台一的章");

//问路:Servlet 2 (柜台2) 怎么走
/**
* 请求转发必须以斜杠打头, / 斜杠表示地址为: http://ip:port/工程名/
* 映射到 IDEA 的 web 目录
*/
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");

// 走向Servlet 2(柜台2)
requestDispatcher.forward(request,response);
}

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

}
}

Servlet 2 代码
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
package com.cs7eric.servlet2; /**
* @author C77eric
* @version 1.0
*/

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

public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求的参数(办事的材料)查看
String username = request.getParameter("username");
System.out.println("在 Servlet 2 (柜台2) 中查看材料" + username);

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

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

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

}
}

base 标签

base 标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转

uTools_1666944718121
c.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- base 标签设置页面相对路径工作时参照的地址
href 属性就是参数的地址值
-->
<base href="http://localhost:8088/servlet2_war/a/b/">
</head>
<body>
这是 a 下的 b 下的 c.html 页面<br/>
<a href="../../index.jsp">跳回首页</a><br/>
</body>
</html>

Web 中的相对路径和绝对路径

在JavaWeb 中,路径分为相对路径和绝对路径两种

在实际开发中,路径都使用绝对路径,而不简单的使用相对路径

  1. 绝对路径
  2. base + 相对

web 中 / 斜杠的不同意义

在 web 中 / 斜杠是一种绝对路径

/ 斜杠 如果被浏览器解析,得到的地址是 : http://ip:port/

<a href="/"> 斜杠 <a/>

/ 斜杠如果被服务器解析,得到的地址是 :http://ip:port/工程路径

  1. <url-pattern>/servlet<url-pattern/>
  2. servletContext.getReallPath("/");
  3. request.getRequestDispatcher("/");

特殊情况: response.sendRediect("/"); 将斜杠发送给服务器解析。得到 http://ip:port/

HttpServletResponse 类


HttpServletResponse 类的作用

HttpServletResponse 类 和 HttpServletRequest 类一样,每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所以响应信息

如果我们需要设置返回客户端的信息,都可以通过 HttpServletResponse 对象来进行设置

两个输出流的说明

  • 字节流 getOutputStream(); 常用于下载(传递二进制数据)
  • 字符流 getWriter(); 常用于回传字符串(常用)

两个流同时只能使用一个

使用了字节流,就不能再使用字符流,反之亦然,否则就会报错

如何往客户端回传数据

要求:往客户端回传 字符串 数据

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
package com.cs7eric.servlet2; /**
* @author C77eric
* @version 1.0
*/

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

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

//要求往客户端回传 字符串数据
PrintWriter writer = response.getWriter();
writer.write("response's context");
}

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

}
}

响应的乱码解决

方案一(不推荐使用)
1
2
3
4
//设置服务器服务器 UTF-8
response.setCharacterEncoding("UTF-8");
//通过响应头,设置浏览器也使用 UTF-8 字符集
response.setHeader("Context-Type","text/html;charset=UTF-8");
方案二(推荐)
1
2
3
//他会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头
//此方法一定要在获取流对象之前调用才有效
response.setContentType("text/html;charset=UTF-8");

请求重定向

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

uTools_1666949298035
请求重定向的第一种方案
1
2
3
4
//设置响应状态码 302 ,表示重定向(已搬迁)
response.setStatus(302);
//设置响应头,说明新的地址在哪里
response.setHeader("Location","http://localhost:8088");
请求重定向的第二种方案(推荐使用)
1
response.sendRedirect("http://loacalhost:8088");

JSP

为什么学习 JSP 技术


什么是 JSP

JSP (全称 Java Server Pages)是由 Sun 公司专门为了解决动态生成 HTML 文档的技术

Servlet 程序输出 HTML 页面

在学习 jsp 技术之前,如果我们要往 客户端 输出一个 页面,我们可以使用Servlet 程序来实现。

但是通过 Servlet 程序 输出简单的 HTML 页面都非常不方便,如果我们要输出一个复杂页面的时候,就更加的困难,而且不利于页面的维护和调试,所以 SUN 公司推出一种叫做 jsp 的 动态页面技术帮助我们实现对页面的输出繁琐工作

jsp 页面的访问千万不能像 HTML 一样。托到浏览器 中。只能通过浏览器访问 Tomcat 服务器再访问 jsp 页面

如何访问 jsp 文件

jsp 页面和 HTML 页面一样,都是存放在 web 目录下,访问也跟 HTML 一样

比如: 在 web 目录下有如下的文件

web 目录

​ a.html 页面 访问地址就是 ——————–》 http://ip:port/工程路径/a.html

​ b.jsp 页面 访问地址就是———————-》 http://ip:port/工程路径/b.jsp

jsp 的本质

jsp 页面本质上是一个 Servlet 程序

当我们第一次访问 jsp 页面的时候。Tomcat 服务器会帮我们把 jsp 页面翻译成为一个 Java 源文件,并且对它编译成为 .class 字节码程序。当我们 打开 Java 源文件不难发现其里面的内容是

我们跟踪源代码发现,HttpJspBase 类。它直接继承了 HttpServlet 类,也就是说,jsp 翻译出来的 Java 类,它间接继承了 HttpServlet 类,也就是说,翻译出来的是一个 Servlet 程序

总结:通过翻译的 Java 源代码,我们就可以得到结果: jsp 就是 Servlet 程序

观察 翻译出来的 Servlet 源码,不难发现。其底层实现,也是通过 输出流。把 HTML 页面 数据回传给客户端

JSP 语法


jsp 头部的 page 指令

jsp 的 page 指令可以修改 jsp 页面中一些重要的属性或者 行为

1
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
  • language 属性 表示 jsp 翻译后是什么语言文件。暂时只支持 Java
  • contextType 属性 表示 jsp 返回的数据类型是什么,也是 源码中的 response.setContextType() 参数值
  • pageEncoding 属性 表示当前 jsp 页面文件本身的字符集
  • import 属性 跟Java 源码一样,用于导包、导类
out 输出流使用
  • autoFlash 属性 设置当 out 输出流缓冲区满了之后,是否自动刷新缓冲区。默认值为 true;
  • buffer 属性 设置 out 缓冲区的大小,默认是 8kb

缓冲区溢出错误

java.io.IOException:Error:JSP Buffer overflow

  • errorPage 属性 设置当 jsp 页面运行出错,自动跳转去的错误页面路径

errorPage 表示 错误后自动跳转的路径,这个路径一般都是以斜杠打头,他表示请求地址为 http://ip:port/工程路径/

映射到 代码的 web 目录

  • isErrorPage 属性 设置当前jsp 页面是否是错误信息页面,默认是 false,如果是 true,可以获取异常信息
  • session 属性 设置访问当前 jsp 页面,是否会创建 HttpSession 对象。默认是 true
  • extends 属性 设置 jsp 翻译出来的 Java 类默认继承谁、

jsp 中常用的脚本

声明脚本(极少使用)

声明脚本的格式是<% 声明 Java 代码%>

作用:可以给 翻译出来的 Java 类 定义属性和方法甚至是 静态代码块,内部类等

代码示例
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
<%-- 1. 声明类属性 --%>
<%!
private Integer id;
private String name;
private String phone;
private static Map<Integer,String> map;
%>

<%-- 2. 声明 static 静态代码块 --%>
<%!
static{
map = new HashMap<Integer,String>();
map.put(1,"csq");
map.put(2,"cym");
map.put(3,"rbb");
}
%>

<%-- 3. 声明类方法 --%>
<%!
public int add(){
return 1;
}
%>

<%-- 4. 声明内部类 --%>
<%!
public static class A{
private Integer id = 0;
private String abc = "abc";
}
%>
表达式脚本(常用)

表达式脚本的格式是 :<%= 表达式 %>

表达式脚本的作用是:在 jsp 页面上输出数据

表达式脚本的特点
  1. 所有的表达式脚本都会被翻译到 _jspService() 中
  2. 表达式脚本都会被翻译成为 out.print() 输出到页面上
  3. 由于表达式脚本翻译的内容都在 _jspService() 方法中,所有 jspService() 方法中的对象都可以直接使用
  4. 表达式脚本中的表达式 不能以分好结束
1
2
3
4
5
<%=12 %> <br>
<%=12.12 %> <br>
<%="我是字符串" %> <br>
<%=map%> <br>
<%=request.getParameter("username")%>
代码脚本

代码脚本的格式是:

1
2
3
<%
java 语句
%>

代码脚本的作用是:可以在 jsp 页面中,编写我们自己需要的功能(写的是 Java语句)

代码脚本的特点
  1. 代码脚本翻译之后都在 jspService() 方法中
  2. 代码脚本由于被翻译到 _jspService() 方法中,所以在方法中的现有对象都可以直接使用
  3. 还可以由多个 代码脚本组合完成一个完整的 Java语句
  4. 代码脚本还可以和表达式脚本一起使用,在 jsp页面上输出数据

jsp 中 的三个注释

HTML 注释

<!-- 这是 HTML 注释 -->

HTML 注释会被翻译到 Java 源代码中,在 _jspService() 方法中,以 out.print() 输出到客户端

Java 注释
1
2
3
4
5
// 单行注释

/*
多行注释
*/

Java 注释会被翻译到 Java 源码中

jsp 注释

<%-- 这是 jsp 注释--%>

jsp 注释可以注掉,jsp 页面中的所有代码

jsp 九大内置对象


jsp 中的内置对象,是指 Tomcat 在翻译 jsp 页面成为 Servlet 源码之后,内部提供的 九大对象,叫 内置对象

  • request 请求对象
  • response 响应对象
  • pageContext jsp 的上下文对象
  • session 会话对象
  • application ServletContext 对象
  • config ServletConfig 对象
  • out jsp 输出流对象
  • page 指向当前 jsp 的对象
  • exception 异常对象

jsp 四大域对象


四个域对象分别是

  • pageContext (PageContextImpl 类) 当前 jsp 页面范围内有效
  • request ( HttpServletRequest 类) 一次请求内有效
  • session (HttpSession 类) 一次会话范围内有效(打开浏览器访问服务器,知道关闭浏览器)
  • application (ServletContext 类) 整个web 工程范围内都有效(只要 web 工程不停止,数据都在)

域是可以像 Map 一样存取数据的对象,四个域对象功能一样,不同的是 他们对数据的存取翻译

pageContext —> request —> session —> application

jsp out 输出和 response.getWriter


response 中表示响应,我们经常用于设置返回 客户端的内容(输出)

out 也是给用户输出使用的

out和getWriter

当jsp 页面中所有代码执行完成之后会做一下两个操作

  1. 执行 out.flush() 操作,会把 out 缓冲区中的数据追加写入到 response 缓冲区 末尾
  2. 会执行 response 的刷新操作,把全部数据写给客户端

由于 jsp 翻译之后,底层源码都是使用 out 来进行输出,所以一般情况下,我们在jsp 页面中统一使用 out 来进行输出。避免扰乱页面输出内容的顺序

  • out.write() 输出 字符串没有问题

  • out.print() 输出 任意数据都没有问题(都转换成为字符串后调用的 write 输出

深入源码,浅出结论 : 在 jsp 页面中,可以统一使用 out.print() 来进行输出

jsp 常用标签


静态包含

1
<%@ include file="" %>

就是静态包含

file 属性指定你要包含的 jsp 页面的路径

地址中的 第一个 斜杠 / 表示 http://ip:port/工程路径/ 映射到代码的 web 目录

静态包含的特点
  1. 静态包含 不会翻译被包含的 jsp 页面
  2. 静态包含其实是把 被包含的 jsp 页面的代码 拷贝 到包含的位置 执行输出

jsp 动态包含

1
<jsp:include page=""></jsp:include>

这是 动态包含

page 属性是指定你要包含的 jsp 页面的 路径

动态包含也可以像动态包含一样。把被包含的内容执行输出到包含位置

动态包含的特点
  1. 动态包含会把包含的 jsp 页面也翻译成为 Java 代码

  2. 动态包含底层代码使用如下代码去掉用被包含的 jsp 页面 执行输出

    JspRnutimeLibrary.include(request,response,"/include/footer.jsp",out,false);

  3. 动态包含,还可以传递参数

    1
    2
    3
    4
    <jsp:include page="/include/footer.jsp">
    <jsp:param name="username" value="bbj"/>
    <jsp:param name="password" value="root"/>
    </jsp:include>
动态包含的底层原理

动态绑定底层原理

jsp 标签-转发

1
<jsp:forward page=""></jsp:forward>

这是请求转发标签,它的功能就是请求转发

page 属性设置请求转发的路径

练习


jsp 输出一个表格,里面有十个 学生信息

searchStudentServlet 程序

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
package com.cs7eric.jsp.servlet;

import com.cs7eric.jsp.pojo.Student;

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.ArrayList;
import java.util.List;

public class searchStudentServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求的参数
//发 SQL 语句 查询学生信息
//使用 for 循环生成查询到的数据做模拟
List<Student> list = new ArrayList<Student>();
for (int i = 0; i < 10; i++) {
int t = i + 1;
list.add(new Student(t,"name"+t,"phone"+t,t+18));
}

//保存查询到的结果(学生信息)到 request
request.setAttribute("list",list);
//请求转发到 showStudent.jsp 页面中
request.getRequestDispatcher("showStudent.jsp").forward(request, response);
}

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

}
}

showStudent.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
38
39
40
41
42
43
44
45
46
47
48
49
<%@ page import="com.cs7eric.jsp.pojo.Student" %>
<%@ page import="java.util.List" %><%--
Created by IntelliJ IDEA.
User: CSQ-PC
Date: 2022/11/3
Time: 20:20
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
table{
border:1px blue solid;
width:600px;
border-collapse:collapse;
}

td,th{
border:1px blue solid;
}
</style>
</head>
<body>
<%
List<Student> stuList = (List<Student>) request.getAttribute("list");
%>
<table>
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>电话</td>
<td>操作</td>
</tr>
<%for(Student student : stuList){%>
<tr>
<td><%=student.getId() %>></td>
<td><%=student.getName() %></td>
<td><%=student.getAge()%>></td>
<td><%=student.getPhone()%>></td>
<td>删除、修改</td>
</tr>
<%}%>
</table>
</body>
</html>

Listenser 监听器


  1. Listener 监听器是 JavaWeb 的 三大组件之一。Java 的三大组件分别是:Servlet 程序、Fliter 过滤器、Listener 监听器
  2. Listener它是 JavaEE 的规范,就是 接口
  3. 监听器的作用是:监听某种事物的变化。然后通过回调函数,反馈给客户(程序)去做一些相应的处理

ServletContextListener 监听器

ServletContextListener 它可以监听ServletContext 对象的创建和销毁

ServletContext 对象在 web 工程启动的时候创建,在 web 工程停止的时候 销毁

监听到 创建和销毁之后都会分别调用 ServletContextListener 监听器的方法去反馈

两个方法分别是:

Listener.java
1
2
3
4
5
6
7
8
9
10
11
12
public class Listener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
/* This method is called when the servlet context is initialized(when the Web application is deployed). */
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
/* This method is called when the servlet Context is undeployed or Application Server shuts down. */
}
}
web.xml 配置
1
2
3
<listener>
<listener-class>com.cs7eric.jsp.listener.Listener</listener-class>
</listener>

EL 表达式

EL 表达式介绍


EL 表达式的全称是 Expression Language 。是 表达式语言

EL 表达式介绍

EL表达式主要是代替 jsp 页面中的表达式脚本在 jsp 页面中进行数据的输出

因为 EL 表达式在输出数据的时候,要 比 jsp 的表达式脚本简洁很多

1
2
3
4
5
6
<%
request.setAttribute("key","值");
%>
表达式脚本输出的key 值是:
<%=request.getAttribute("key")==null?"":request.getAttribute("key")%> <br>
EL 表达式输出key 的值是 :${key}

EL 表达式格式

1
${表达式}

EL 表达式在输出 null 值得时候,输出的是空串。jsp 表达式脚本输出 null 值的 时候,输出的是 null 字符串

EL 表达式搜索域数据的顺序


EL 表达式主要实在 jsp 页面中输出数据

主要是输出域对象中的数据

当四个域中都有相同的 key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去搜索,找到就输出

1
2
3
4
5
6
7
8
9
10
<body>
<%
//往四个域中都保存了相同的key 的值
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
pageContext.setAttribute("key","pageContext");
%>
${ key }
</body>

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
<body>
<%
Person person = new Person();
person.setName("cs7eric");
person.setPhones(new String[]{"123","456","789"});

List<String> cities = new ArrayList<String>();
cities.add("北京");
cities.add("南京");
person.setCities(cities);

Map<String,Object> map = new HashMap<String,Object>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
person.setMap(map);

pageContext.setAttribute("person",person);
%>
输出 person:${person} <br>
输出 person 的 name 属性: ${person.name} <br>
输出person 的phones 属性: ${person.phones[2]} <br>
输出person 的cities集合中元素值 :${person.cities} <br>
输出person 的LIst 集合中个别元素值 :${person.cities[2]}
输出person 的Map 集合:${person.map} <br>
输出person 的Map 集合个别元素值:${person.map.key3} <br>
输出 person 的 age 属性: ${person.age} <br>

</body>

EL 表达式-运算


语法:

1
${运算表达式}

关系运算

关系运算符 说 明 范 例 结果
== 或 eq 等于 ${ 5 == 5 } 或 ${ 5 eq 5 } true
!= 或 ne 不等于 ${ 5 !=5 } 或 ${ 5 ne 5 } false
< 或 lt 小于 ${ 3 < 5 } 或 ${ 3 lt 5 } true
> 或 gt 大于 ${ 2 > 10 } 或 ${ 2 gt 10 } false
<= 或 le 小于等于 ${ 5 <= 12 } 或 ${ 5 le 12 } true
>= 或 ge 大于等于 ${ 3 >= 5 } 或 ${ 3 ge 5 } false

逻辑运算

逻辑运算符 说 明 范 例 结果
&& 或 and 与运算 ${ 12 == 12 && 12 < 11 } 或 ${ 12 == 12 and 12 < 11 } false
|| 或 or 或运算 ${ 12 == 12 || 12 < 11 } 或 ${ 12 == 12 or 12 < 11 } true
! 或 not 取反运算 ${ !true } 或 ${not true } false

算数运算

算数运算符 说 明 范 例 结果
+ 加法 ${ 12 + 18 } 30
- 减法 ${ 18 - 8 } 10
* 乘法 ${ 12 * 12 } 144
/ 或 div 除法 ${ 144 / 12 }
% 或 mod 取模 ${ 144 % 10 }
empty 运算

empty 运算可以判断一个数据是否为空,如果为空,则输出 true,不空 则为 false

以下几种情况为空

  1. 值为 null 值 的时候,为空
  2. 值为空串的时候,为空
  3. 值是 Object 类型数组,长度为 0 的时候
  4. list 集合,元素个数为 0
  5. map 集合,元素个数为 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<body>
<%
//1.值为 null 值 的时候,为空
request.setAttribute("emptyNull",null);
//2. 值为空串的时候
request.setAttribute("emptyStr","");
//3. 值是 Object 数组,长度为 0的时候
request.setAttribute("emptyArr",new Object[]{});
//4. list 集合,元素个数为 0
List<Object> list = new ArrayList<>();
request.setAttribute("emptyList",list);
//5. map 集合,元素个数为0
Map<String,Object> map = new HashMap<String,Object>();
request.setAttribute("emptyMap",map);

%>

${empty emptyNull} <br>
${empty emptyStr} <br>
${empty emptyArr} <br>
${empty emptyList} <br>
${empty emptyMap} <br>
</body>
三元运算

表达式 1? 表达式 2: 表达式 3
如果表达式 1 的值为真, 返回表达式 2 的值, 如果表达式 1 的值为假, 返回表达式 3 的值。

” . “ 点运算 和 [] 中括号运算符

.点运算, 可以输出 Bean 对象中某个属性的值。
[]中括号运算, 可以输出有序集合中某个元素的值。
并且[]中括号运算, 还可以输出 map 集合中 key 里含有特殊字符的 key 的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<%
Map<String,Object> map = new HashMap<String, Object>();
map.put("a.a.a", "aaaValue");
map.put("b+b+b", "bbbValue");
map.put("c-c-c", "cccValue");
request.setAttribute("map", map);
%>

${ map['a.a.a'] } <br>
${ map["b+b+b"] } <br>
${ map['c-c-c'] } <br>

</body>

EL 表达式的 11 个隐含对象


EL 表达式中 11 个隐含对象,是 EL表达式中自己定义的,可以直接使用

变量 类型 作用
pageContext PageContextImpl 他可以获取 jsp 中的九大内置对象
pageScope Map<String,Object> 他可以获取 pageContext 域中的数据
requestScope Map<String,Object> 他可以获取 request 域中的数据
sessionScope Map<String,Object> 它可以获取 session 域中的数据
applicationScope Map<String,Object> 它可以获取 ServletContext 域中的数据
param Map<String,Object> 他可以获取请求参数的值
paramValues Map<String,Object[]> 他可以获取请求参数的值,获取多个值的时候使用
header Map<String,Object> 他可以获取请求头的信息
headerValues Map<String,Object[]> 他可以获取请求头的信息,他可以获取多个值的情况
cookie Map<String,Cookie> 他可以获取当前请求的 cookie 信息
initParam Map<String,String> 他可以获取在 web.xml 中配置的 上下文参数

EL 获取四个特定域中的属性

  • pageScope ————– pageContext 域
  • requestScope ————– request 域
  • sessionScope ————– session 域
  • application ————– ServletContext 域
pageContext 对象的使用
  1. 协议
  2. 服务器 ip
  3. 服务器端口
  4. 获取工程路径
  5. 获取请求方法
  6. 获取客户端 IP 地址
  7. 获取 会话 的 ID 编号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<body>
<%--
request.getScheme() 它可以获取请求的协议
request.getServerName() 获取请求的服务器 ip 或域名
request.getServerPort() 获取请求的服务器端口号
getContextPath() 获取当前工程路径
request.getMethod() 获取请求的方式(GET 或 POST)
request.getRemoteHost() 获取客户端的 ip 地址
session.getId() 获取会话的唯一标识
--%>
<%
pageContext.setAttribute("req",request);
%>
<%=request.getScheme() %> <br>

1. 协议 :${req.scheme} <br>
2. 服务器 ip: ${req.serverName} <br>
3. 服务器端口: ${req.serverPort} <br>
4. **获取工程路径**: ${req.contextPath} <br>
5. 获取请求方法: ${req.method} <br>
6. 获取客户端 IP 地址 ${req.remoteHost} <br>
7. 获取 会话 的 ID 编号 ${pageContext.session.id} <br>

</body>
EL 表达式其他隐含对象的使用
  • param
  • paramValues
1
2
3
4
5
6
7
8
9
<body>
输出请求参数 username 的值:${param.username} <br>
输出请求参数 password 的值:${param.password} <br>

输出请求参数 username 的值:${paramValues.username[0]} <br>
输出请求参数 hobby 的值:${paramValues.hobby[0]} <br>
输出请求参数 hobby 的值:${paramValues.hobby[1]} <br>

</body>
  • header
  • headerValues
1
2
3
输出 请求头【User-Agent】的值:${header['User-Agent']} <br>
输出 请求头【Connection】的值:${header.Connection} <br>
输出 请求头【User-Agent】的值:${headerValues['User-Agent'][0]} <br>
  • cookie
1
2
输出 &lt; Context-param &gt; username 的值:${initParam.username} <br>
输出 &lt; Context-param &gt; url 的值: ${initParam.url} <br>

JSTL 标签库

JSTL 标签库 全称是 JSP Standard Tag Library ,JSP 标准标签库。是一个不断完善的开源的 JSP 标签库

EL 表达式只要是为了 替换 jsp 中的表达式脚本,而标签库则是为了 替换代码脚本。这样使得整个 jsp 页面变得简洁

JSTL 组成


JSTL 由五个功能不同的标签库组成

功能范围 URI 前缀
核心标签库–重点 http://java.sun.com/jsp/jstl/core c
格式化 http://java.sun.com/jsp/jstl/fmt fmt
函数 http://java.sun.com/jsp/jstl/functions fn
数据库(不使用) http://java.sun.com/jsp/jstl/sql sql
XML(不使用) http://java.sun.com/jsp/jstl/xml x

在 jsp 标签库中使用 taglib 指令引入标签库

1
2
3
4
5
6
7
8
9
10
CORE 标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
XML 标签库
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
FMT 标签库
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
SQL 标签库
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
FUNCTIONS 标签库
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

JSTL 标签库的使用步骤


  1. 先导入 jstl 标签库的 jar 包
    1. taglibs-standard-impl-1.2.1.jar
    2. taglibs-standard-spec-1.2.1.jar
  2. 使用 taglib 指令引入标签库

core 核心库使用


<c:set/>

set 标签可以往域中保存数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%--
<c:set />
作用:set 标签可以往域中保存数据

域对象.setAttribute()
scope 属性设置保存到哪个域
page 表示 pageContext 域
request 表示 Request 域
session 表示 Session 域
application 表示 ServletContext 域

var 属性设置 key 是多少
value 属性设置值
--%>
保存之前:${sessionScope.abc} <br>
<c:set scope="session" var="abc" value="sessionValue"/>
保存之后:${sessionScope.abc} <br>

<c:if />

if标签 用来做 if 判断

1
2
3
4
5
6
7
8
9
10
11
<%-- 
<c:if/>
if 标签用来做 if 判断
test 属性 表示判断的条件(用 EL 表达式输出)
--%>
<c:if test="${12 == 12}">
<h1>12 等于 12</h1>
</c:if>
<c:if test="${12 != 12}">
<h2>不等于</h2>
</c:if>

<c:choose><c:when><c:otherwise>

多路判断。跟 switch…case…default 非常相近

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
<%--
iii.<c:choose> <c:when> <c:otherwise>标签
作用: 多路判断。 跟 switch ... case .... default 非常接近
choose 标签开始选择判断
when 标签表示每一种判断情况
test 属性表示当前这种判断情况的值
otherwise 标签表示剩下的情况

<c:choose> <c:when> <c:otherwise>标签使用时需要注意的点:
1、 标签里不能使用 html 注释, 要使用 jsp 注释
2、 when 标签的父标签一定要是 choose 标签
--%>
<%
request.setAttribute("height",180);
%>
<c:choose>
<c:when test="${requestScope.height > 190}">
<h1>小巨人</h1>
</c:when>
<c:when test="${requestScope.height > 180}">
<h1>很高</h1>
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${requestScope.height >160}">
<h1>大于160</h1>
</c:when>
<c:otherwise>
其他小于160
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>

<c:foreach/>

遍历输出使用

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
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="com.cs7eric.el_jstl.pojo.Person" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cs7eric.el_jstl.pojo.Student" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: CSQ-PC
Date: 2022/11/4
Time: 15:00
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<style>
table{
border:1px blue solid;
width:600px;
border-collapse:collapse;
}

td,th{
border:1px blue solid;
}
</style>
</head>
<body>
<%--1.遍历 110, 输出
begin 属性设置开始的索引
end 属性设置结束的索引
var 属性表示循环的变量(也是当前正在遍历到的数据)
for (int i = 1; i < 10; i++)
--%>
<table border="1">
<c:forEach begin="1" end="10" var="i">
<tr>
<td>第${i} 行</td>
</tr>
</c:forEach>
</table>


------------------------------------- <br>
<%
request.setAttribute("arr",new String[]{"123","234","456"});
%>
<c:forEach items="${requestScope.arr}" var="item">
${item} <br>
</c:forEach>
--------------------------------------- <br>
<%
Map<String,String> map = new HashMap<String,String>();
map.put("1","11");
map.put("2","12");
map.put("3","13");
request.setAttribute("map",map);
%>

<c:forEach items="${requestScope.map}" var="entry">
<h1>${entry.key} == ${entry.value}</h1>
</c:forEach>

------------------------------------------------------ <br>
<%
List<Student> stuList = new ArrayList<Student>();
for (int i = 0; i < 10; i++) {
stuList.add(new Student(i,18+i,"name"+i,"110"+i));
}
request.setAttribute("stuList",stuList);
%>
<table>
<tr>
<th>id</th>
<th>年龄</th>
<th>名字</th>
<th>电话</th>
<th>操作</th>
</tr>
<c:forEach begin="1" end="10" varStatus="status" items="${requestScope.stuList}" var="stu">
<tr>
<td>${stu.id}</td>
<td>${stu.age}</td>
<td>${stu.name}</td>
<td>${stu.phone}</td>
<td>${status.index}</td>
</tr>
</c:forEach>
</table>

</body>
</html>

文件的上传与下载

文件的上传和下载,是非常常见的功能,很多的系统中,或者软件中都经常使用文件的上传和下载

文件的上传


文件上传的介绍

  1. 要有一个 form 标签,method=post 请求
  2. form 标签的 encType 属性值必须为 multipart/form-data 值
  3. 在 form 标签中使用 input type=file 添加上传的文件
  4. 编写服务器代码(Servlet 程序) 接受,处理上传的数据

encType=multipart/form-data 表示提交的数据,以多段(每一个表单项一个数据段) 的形式进行拼接,然后以二进制流的形式发送服务器

文件上传,HTTP 协议的说明

image-20221117131328465

commons-fileupload.jar 常用 API 说明

commons-fileipload.jar 需要依赖 commons-io.jar 这个包,所以两个包都要引入

引入以下两个 jar 包

  • commons-fileupload.jar
  • commons-io.jar
ServletFileUpload 类

用于解析上传的数据

FileItem类

表示每一个表单项

boolean ServletFileUpload.isMutipartContent(HttpServletRequest rquest)

判断当前上传的数据格式是否是多段的格式

public List <FileItem > parseRequest(HttpServletRequest request)

解析上传的数据

boolean FileItem.isFormField()

判断当前这个表单项,是否是普通的表单项。还是上传的文件类型

  • true:表示普通类型的表单项
  • false:表示上传的文件类型
String FileItem.getFieldName()

获取表单项的 name 属性值

String FileItem.getString()

获取当前表单项的值

String FileItem.getName()

获取上传的文件名

void FileItem.write(File)

将上传的文件 写到参数 file 所指向所写硬盘位置

文件上传操作

上传文件的表单 upload.jsp
1
2
3
4
5
<form action="Http://localhost:8088/file/uploadServlet" method="post" encType="multipart/form-data">
用户名:<input type="text" name="username"/> <br>
头像 :<input type="file" name="photo"> <br>
<input type="submit" value="上传">
</form>
Servlet 程序 uploadServlet.java
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
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("文件上传过来了");
// ServletInputStream inputStream = request.getInputStream();
// byte[] buffer = new byte[1024000] ;
// int read = inputStream.read(buffer);
// System.out.println(new String(buffer,0,read));


//1. 先判断上传的数据是否是多段数据(只有是多段的数据,才是文件上传的)
if(ServletFileUpload.isMultipartContent(request)){
//创建 FileItemFactory 工厂实现类
FileItemFactory fileItemFactory = new DiskFileItemFactory();
//创建用于解析上传数据的工具类 ServletFileUpload 类
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
servletFileUpload.setHeaderEncoding("UTF-8");

try {
//解析上传的数据,得到每一个表单项 FileItem
List<FileItem> list = servletFileUpload.parseRequest(request);
//循环判断,每一个表单项,是普通文件还是上传的文件
for(FileItem fileItem : list){
if(fileItem.isFormField()){
//普通表单项
System.out.println("表单项的 name 属性值:" + fileItem.getFieldName());
//解决 UTF-8 乱码问题
System.out.println("表单项的 value 值:" + fileItem.getString("UTF-8"));
} else {
//上传的文件
System.out.println("表单的 name 属性值:" + fileItem.getFieldName());
System.out.println("上传的文件名:" + fileItem.getName());

fileItem.write(new File("e:\\" + fileItem.getName()));
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

文件下载


常用 API 说明

  • response.getOutputStream()
  • servletContext.getResourceAsStream()
  • servletContext.getMimeType()
  • response.getContentType()

response.setHeader(“Content-Disposition”,”attachment;fileName=1.jpg);

这个响应头告诉浏览器,这是需要下载的,而 **attachment **表示附件,也就是下载的一个文件, fileName=后面 表示下载的文件名

完成上面的两个步骤,下载文件是没问题了,但是如果我们要下载的文件 是中文名的话,下载无法显示出正确的中文名

原因是 在响应头中,不能包含有中文字符,只能包含 ASCII 码

文件下载示例

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
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


//1.获取要下载的内容
String downloadFileName = "abc.png";

String str = "attachment;fileName" + URLEncoder.encode(downloadFileName,"UTF-8");
response.setHeader("Content-Disposition",str);

//2. 读取要下载的内容(通过 ServletContext 对象可以读取)
ServletContext servletContext = getServletContext();

//3. 获取要下载的文件类型
String mimeType = servletContext.getMimeType("/file/" + downloadFileName);

//4. 在回传之前,通过响应头告诉客户端返回的数据类型
response.setContentType(mimeType);

//5. 告诉客户端收到的数据是用于下载使用还是使用响应头
/*
Content-Disposition 响应头,表示收到的数据怎么处理
attachment 表示附件,表示下载使用
filename 表示指定下载的文件名
*/
System.out.println(downloadFileName);

//response.setHeader("Content-Disposition", "attachment; filename" + downloadFileName);

/**
* 斜杠 被服务器解析为 http:ip:port/工程名/ 映射到 web 目录
*/
InputStream resourceStream = servletContext.getResourceAsStream("/file/" + downloadFileName);

//获取响应的输出流
OutputStream outputStream = response.getOutputStream();

//把下载的文件内容回传给客户端
//读取输入流中的全部的数据,复制给输出流,输出给客户端
IOUtils.copy(resourceStream,outputStream);
}

Cookie 是服务器通知客户端保存键值对的一种技术,客户端有了 Cookie 后,每次请求都发送给服务器,每个Cookie的大小不能超过 4kb

Cookie的创建

1
2
3
4
5
6
7
8
9
10
11
12
protected void createCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建 Cookie 对象
Cookie cookie = new Cookie("key1", "value1");
//通知客户端保存 Cookie
resp.addCookie(cookie);
//创建 Cookie对象
Cookie cookie1 = new Cookie("key2", "value2");
//通知客户端保存 Cookie
resp.addCookie(cookie1);

resp.getWriter().write("Cookie 创建成功");
}

服务器获取 Cookie,只需要一行代码\

TODO 图片

Cookie 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void getCookies(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Cookie[] cookies = req.getCookies();

for(Cookie cookie : cookies){
//getName 方法返回 Cookie 的 key
//getValue 方法返回 Cookie的 value
resp.getWriter().write("Cookie[" + cookie.getName() + "=" + cookie.getValue() + "]<br/>");

Cookie iWantCookie = CookieUtils.findCookie("key1",cookies);
if(iWantCookie != null){
resp.getWriter().write("找到了需要的Cookie");
}
}
方案一
  1. 先创建一个要修改的同名(指的就是 key) 的Cookie 对象
  2. 在构造器,同时赋予 新的 Cookie 值
  3. 调用 response.addCookie(Cookie)
1
2
Cookie cookie = new Cookie("key1","value1");
response.addCookie(cookie);
方案二
  1. 先查找到需要修改的 Cookie 对象
  2. 调用 setValue() 方法赋予新的 Cookie 值
  3. 调用 response.addCookie() 通知客户端保存修改
1
2
3
4
5
6
7
8
//先查找到需要修改的 Cookie 对象
Cookie cookie = CookieUtils.findCookie("key2",req.getCookies());
if(cookie != null){
//调用 setValue() 方法赋予新的 cookie 值
cookie.setValue("newValue2");
//通知客户端保存
response.addCookie(cookie);
}

F12 - Application

Cookie的生命控制指的是 如何管理 Cookie 什么时候被销毁

setMaxAge()
  • 正数:表示在指定的秒数后会过期
  • 负数:表示浏览器一关,Cookie 就会删除(默认值是 - 1)
  • 0:表示马上删除
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
/**
* 设置存活1个小时的Cooie
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void life3600(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

Cookie cookie = new Cookie("life3600", "life3600");
cookie.setMaxAge(60 * 60); // 设置Cookie一小时之后被删除。无效
resp.addCookie(cookie);
resp.getWriter().write("已经创建了一个存活一小时的Cookie");

}

/**
* 马上删除一个Cookie
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 先找到你要删除的Cookie对象
Cookie cookie = CookieUtils.findCookie("key4", req.getCookies());
if (cookie != null) {
// 调用setMaxAge(0);
cookie.setMaxAge(0); // 表示马上删除,都不需要等待浏览器关闭
// 调用response.addCookie(cookie);
resp.addCookie(cookie);

resp.getWriter().write("key4的Cookie已经被删除");
}

}

Cookie 的 path 属性 可以有效的过滤哪些 Cookie 可以发送给服务器,哪些不发

path 属性 是通过请求的地址来进行有效的过滤

CookieA path=/工程路径/

CookieB path=/工程路径/abc

请求地址如下

免用户名登录

login.jsp 页面
1
2
3
4
5
<form action="http://localhost:8088/cookie_session/loginServlet" method="get">
<input type="text" name="username" value="${cookie.username.value}"> <br>
<input type="password" name="password">
<input type="submit" value="登录">
</form>
LoginServlet.java 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if("cs7eric".equals(username) && "C020611.".equals(password)){
Cookie cookie = new Cookie("username",username);
cookie.setMaxAge(60 * 60 * 24 * 7);
response.addCookie(cookie);
System.out.println("Success");
} else {
System.out.println("Failed");
}

}

Session 会话


什么是 Session 会话

  1. Session 就是一个接口(HttpSession)
  2. Session 就是会话,它是用来维护一个客户端和服务器之间关联的一种技术
  3. 每个客户端都有自己的一个 Session 会话
  4. Session 会话中,我们经常用来保存用户登录之后的信息

如何创建 Session 和获取(ID号是否为新)

如何创建和获取— 他们的 API 是一样的

request.getSession()

  • 第一次调用是:创建 Session 会话
  • 之后调用都是:获取前面创建好的 Session 会话对象

isNew(); 判断是不是刚创建的(新的)

  • true:表示刚创建
  • false:表示获取之前创建

每个会话都会有一个身份证号,也就是 ID 值。而且这个ID 值是唯一的

getId()

获得Seesion 会话 的 ID 值

Session 域数据的存取

1
2
3
4
5
6
7
8
9
10
protected void setAttribute(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.getSession().setAttribute("key1","value1");
resp.getWriter().write("已经往 Session 保存了数据");
}

protected void getAttribute(HttpServletRequest req, HttpServletResponse resp) throws IOException {

Object attribute = req.getSession().getAttribute("key1");
resp.getWriter().write("从 Session 域中取出的数据是" + attribute);
}

Session 生命周期控制

public void setMaxInactiveInterval(int interval)

设置 Session 的超时时间(以秒为单位),超过指定的时长。Session就会被销毁

  • 值为整数的时候,设定Session 的超时时长
  • 负数表示永不超时(极少使用)
public int getMaxInactiveInterval()

获取 Session 超时的时间

public void invalidate()

让当前 Session 会话马上超时无效

Session 默认的超时时长是 30 分钟

因为在 Tomcat服务器的配置文件 web.xml 中默认有以下的配置,它就代表了当前 Tomcat 服务器下所有的 Session超时配置默认时长为 :30分钟

1
2
3
<session-config>
<session-timeout>30</session-timeout>
</session-config>

如果说,你希望你的 web 工程,默认的 Session 的超时时长为其他时间,你可以在你自己的 web.xml 配置文件中做以上的配置,就可以修改你的 web 工程所有的 Session 的 默认时长

如果你想只修改个别 Session 的超时时长,就可以使用上面的 API setMaxInactiveInterval(int interval)

Session 超时的概念介绍

Session超时

浏览器和 Session 之间关联的技术内幕

Session技术,底层其实是基于 Cookie 技术来实现的

浏览器和Session的关联内幕

Fliter 过滤器

Fliter 过滤器是 JavaWeb 的三大组件之一。三大组件分别是 Servlet 程序、Listener 监听器、Fliter 过滤器

Fliter 简介


  1. Fliter 过滤器是 JavaWeb 的三大组件之一。三大组件分别是 Servlet 程序、Listener 监听器、Fliter 过滤器
  2. Fliter 过滤器它是 JavaEE 的规范,也就是接口
  3. Fliter 过滤器它的作用是:拦截请求,过滤响应

应用场景

  1. 权限检查
  2. 日记操作
  3. 事务管理
  4. ….

初体验

要求: 在你的 web 工程下, 有一个 admin 目录。 这个 admin 目录下的所有资源(html 页面、 jpg 图片、 jsp 文件、 等等) 都必
须是用户登录之后才允许访问。

思考: 根据之前我们学过内容。 我们知道, 用户登录之后都会把用户登录的信息保存到 Session 域中。 所以要检查用户是否
登录, 可以判断 Session 中否包含有用户登录的信息即可

Fliter 工作流程

fliter代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
//如果 等于 null ,说明还没有登录
if(user == null){
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
} else {
//让程序继续往下访问用户的目标资源
chain.doFilter(request, response);
}


}
web.xml 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--  filter 标签用于配置一个  filter 标签 -->
<filter>
<!-- 给 filter 起一个别名 -->
<filter-name>AdminFilter</filter-name>
<!-- 配置 filter 的全类名 -->
<filter-class>com.cs7eric.filter_.AdminFilter</filter-class>
</filter>
<!-- 配置 filter 过滤器的拦截路径 -->
<filter-mapping>
<!-- 表示当前的拦截路径给哪个 filter 用 -->
<filter-name>AdminFilter</filter-name>
<!-- 配置拦截路径

/ 表示请求地址为 http://ip:port/工程路径/ 映射到 IDEA 的 web 目录
/admin/* 表示请求地址为 http://ip:port/工程路径/admin/*
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>

filter 过滤器的使用步骤

  1. 编写一个类去实现 Filter 接口
  2. 实现过滤方法 doFilter()
  3. 到 web.xml 中去配置 filter 的拦截路径

Filter 的生命周期


Filter 的生命周期包含几个方法

  1. 构造方法

  2. init 初始化方法

    1,2 在 web 工程启动的时候执行(Filter 已经创建)

  3. doFilter()过滤方法

    第三步,每次拦截到请求,会执行

  4. destory 销毁方法

    第四步,停止 web 工程的时候,就会执行(停止 web 工程,也会销毁 Filter 过滤器)

FilterConfig 类


FilterConfig 类 见名知意,他是 Filter 过滤器的配置文件类

Tomcat 每次创建 Filter 的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息

FilterConfig 类的作用

获取 Filter 过滤器的配置内容

  1. 获取 Filter 的名称 filter-name 的内容
  2. 获取 在 Filter中 配置的 init-param 初始化参数
  3. 获取 ServletContext 对象
Java 代码
1
2
3
4
5
6
7
8
9
10
11
public void init(FilterConfig config) throws ServletException {

System.out.println("Filter 的init初始化");
//获取 Filter 名称 filter-name 的值
System.out.println("filter-name:" + config.getFilterName());
//获取 在 web.xml 中配置的 init-param 初始化参数
System.out.println("init-param username:" + config.getInitParameter("username"));
System.out.println("init-param url:" + config.getInitParameter("url"));
//获取 ServletContext 对象
System.out.println(config.getServletContext());
}

FilterChain 过滤器链


Filter 过滤器

Chain 链,链条

FilterChain 就是过滤器链(多个过滤器如何一起工作)

FilterChain

多个Filter 过滤器执行的特点

  1. 所有 Filter 和 目标资源默认都执行在同一个线程中
  2. 多个 Filter 共同执行的时候,他们都是使用 同一个 Request 对象

FilterChain.doFilter () 方法的作用

  1. 执行下一个 filter 过滤器(如果有 Filter)
  2. 执行目标资源 (没有 Filter )

在多个 Filter 过滤器执行的时候,他们执行的顺序是由他们在 web.xml 中 从上到下 配置的顺序决定

Filter 的拦截路径


精确匹配

1
<url-pattern>/target.jsp</url-pattern>

以上配置的路径,表示请求地址必须为 http://ip:port/工程路径/target.jsp

目录匹配

1
<url-pattern>/admin/*</url-pattern>

以上的配置路径,表示请求地址必须为 :http://ip:port/工程路径/admin/*

后缀名匹配

1
<url-pattern>*.html</url-pattern>

以上的配置路径,表示请求地址必须以.html 结尾 才会被拦截

Fliter 过滤器只关心请求的地址会不会被拦截,不关心请求的资源是否存在

ThreadLoacal

ThreadLocal 的作用


可以解决多线程的数据安全问题

它可以给当前线程关联一个数据(可以是普通变量、对象、数组、集合)

ThreadLocal 的特点


  1. ThreadLoacal 可以为当前线程关联一个数据(他可以像map 一样存取数据,key 为当前线程)
  2. 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个 ThreadLocal 对象实例
  3. 每个 ThreadLocal 对象实例定义的时候,一般都是 static 类型
  4. ThreadLocal 中保存数据,在线程销毁后,会由 JVM 虚拟自动释放
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
public class OrderService {

public void createOrder(){
String name = Thread.currentThread().getName();
System.out.println("OrderService 当前线程[" + name + "]中保存的数据是: " +
ThreadLocalTest.threadLocal.get());
new OrderDao().saveOrder();
}
}


public class OrderDao {

public void saveOrder(){
String name = Thread.currentThread().getName();
System.out.println("OrderDao 当前线程[" + name + "]中保存的数据是: " +
ThreadLocalTest.threadLocal.get());
}
}

public class ThreadLocalTest {

// public static Map<String,Object> data = new Hashtable<String,Object>();
public static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
private static Random random = new Random();

public static class Task implements Runnable {

@Override
public void run() {

// 在 Run 方法中, 随机生成一个变量(线程要关联的数据) , 然后以当前线程名为 key 保存到 map 中
Integer i = random.nextInt(1000);

// 获取当前线程名
String name = Thread.currentThread().getName();
System.out.println("线程["+name+"]生成的随机数是: " + i);

// data.put(name,i);
threadLocal.set(i);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new OrderService().createOrder();

// 在 Run 方法结束之前, 以当前线程名获取出数据并打印。 查看是否可以取出操作
// Object o = data.get(name);
Object o = threadLocal.get();
System.out.println("在线程["+name+"]快结束时取出关联的数据是: " + o);
}
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++){
new Thread(new Task()).start();
}
}
}

使用 Filter 和 ThreadLocal 组合管理事务


使用 ThreadLocal 来确保 所有 dao 操作都在一个 Connection 连接对象中完成

jdbc数据库事务管理

JDBCUtils 工具类的修改

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
private static DruidDataSource dataSource;
private static ThreadLocal<Connection> conns = new ThreadLocal<Connection>();
static {
try {
Properties properties = new Properties();
//读取 druid.properties 配置文件
InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//从流中加载数据
properties.load(inputStream);
//创造数据库连接池
dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接池中的链接
* @return 如果返回 null,说明获取连接失败 有值就是获取成功
*/
public static Connection getConnection(){

Connection conn = conns.get();
if(conn == null){
try {
conn = dataSource.getConnection(); //从数据库连接池获取连接
conns.set(conn); //保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}

return conn;

}


/**
* 提交事务,并关闭释放链接
*/
public static void commitAndClose(){
Connection connection = conns.get();
if (connection != null){

try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//一定要执行 remove 操作,否则就会出错(因为 Tomcat 服务器底层用了 线程池技术)
conns.remove();;
}


public static void rollbackAndClose(){
Connection connection = conns.get();
if(connection != null){
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

conns.remove();
}

BaseDAO 修改

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
public abstract class BaseDAO{

//使用 DbUtils 操作数据库
private QueryRunner queryRinner = new QueryRunner();

/**
* update 用来执行 Insert/Delete/Update 语句
* @return 如果返回 - 1,说明执行失败,返回其他表示影响的行数
*/
public int update(String sql,Object ...params){

Connection conn = JDBCUtils.getConnection();
try {
return queryRinner.update(conn,sql,params);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

/**
* 查询返回一个 JavaBean 的 SQL 语句
* @param type 返回的对象类型
* @param sql 执行的 SQL 语句
* @param params SQL 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> T queryForOne(Class<T> type,String sql,Object ...params){
Connection conn = JDBCUtils.getConnection();
try {
return queryRinner.query(conn,sql,new BeanHandler<T>(type),params);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}


/**
* 查询返回多个 JavaBean 的 SQL 语句
* @param type 返回的对象类型
* @param sql 执行的 SQL 语句
* @param params SQL 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> List<T> queryForList(Class<T> type, String sql, Object ...params){
Connection conn = JDBCUtils.getConnection();
try {
return queryRinner.query(conn,sql,new BeanListHandler<T>(type),params);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

/**
* 执行返回一行一列的 SQL 语句
* @param sql 执行的 SQL 语句
* @param params SQL语句中对应的参数
* @return
*/
public Object getForSingleValue(String sql,Object...params){
Connection conn = JDBCUtils.getConnection();
try {
return queryRinner.query(conn, sql, new ScalarHandler(), params);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

使用 Filter 过滤器统一给所有的 Service 方法加上 try-catch,来进行实现的管理

原理分析图

实现原理图ThreadLocal

按上面的分析示意,那么就可以使用一个 Filter 一次性,统一地给所有的 XxxService.xxx() 方法都统一加上 try-catch() 来实现事务的管理

Filter 代码
1
2
3
4
5
6
7
8
9
10
11
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

try {
chain.doFilter(request, response);
JDBCUtils.commitAndClose();
} catch (Exception e) {
JDBCUtils.rollbackAndClose();
e.printStackTrace();
}
}
web.xml 配置
1
2
3
4
5
6
7
8
<filter>
<filter-name>TransactionFilter</filter-name>
<filter-class>com.cs7eric.book.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TransactionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
把 BaseServlet 中的一场抛给 Filter 过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决 post 请求中文乱码
//一定要在获取请求参数之前调用才有效
request.setCharacterEncoding("UTF-8");

String action = request.getParameter("action");

try {

//获取 action 业务鉴别字符串,获取相应的业务方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);

//调用 目标业务 方法
method.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();

//把异常抛给 Filter 过滤器
throw new RuntimeException(e);
}
}

错误信息页面

将所有异常都交给 Tomcat,让 Tomcat 展示友好的错误信息页面

在 web.xml 中我们可以通过错误信息页面配置来进行管理

1
2
3
4
5
6
7
8
<!--    错误页面信息配置-->
<error-page>
<!-- error-code 是错误类型 -->
<error-code>500</error-code>
<!-- location 标签表示,要跳转去的页面路径 -->
<location>/pages/error/error500.jsp</location>
</error-page>
</web-app>

JSON

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写。有同时也易于机器解析和生成。JSON 采用完全独立于语言的文本格式,而且很多语言都提供了对 json 的支持(包括 C,C++,C#,Java,JavaScript,Perl,Python等),这样就使得 JSON 成为理想的数据交换格式

json 是一种轻量级的数据交换格式

轻量级指的是跟 xml 相比

数据交换指的是客户端和服务器之间业务数据的传递格式

JSON 在 JavaScript 中的使用


JSON的定义

json 是由键值对组成,并且由花括号(大括号)包围,每个键由引号引起来,键和值之间使用冒号进行分割

JSON 定义实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var jsonObj = {
"key1":12,
"key2":"abc",
"key3":true,
"key4":[11,"arr",false],
"key5":{
"key5_1" : 551,
"key5_2" : "key5_2_value"
},
"key6":[{
"key6_1_1":6611,
"key6_1_2":"key6_1_2_value"
},{
"key6_2_1":6621,
"key6_2_2":"key6_2_2_value"
}]
};

JSON 的访问

JSON 本身是一个对象

JSON 中的 key 我们可以理解为是对象中 的一个属性

JSON 中的 key 访问就跟访问对象的属性一样:JSON对象.key

JSON 访问实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
alert(typeof(jsonObj));// object json 就是一个对象
alert(jsonObj.key1); //12
alert(jsonObj.key2); // abc
alert(jsonObj.key3); // true
alert(jsonObj.key4);// 得到数组[11,"arr",false]

// json 中 数组值的遍历
for(var i = 0; i < jsonObj.key4.length; i++) {
alert(jsonObj.key4[i]);
}
alert(jsonObj.key5.key5_1);//551
alert(jsonObj.key5.key5_2);//key5_2_value
alert( jsonObj.key6 );// 得到 json 数组
// 取出来每一个元素都是 json 对象
var jsonItem = jsonObj.key6[0];
// alert( jsonItem.key6_1_1 ); //6611
alert( jsonItem.key6_1_2 ); //key6_1_2_value

JSON 的两个常用方法

JSON 的存在有两种形式

  • 对象的形式存在,我们叫他 JSON 对象

    JSON.stringify() 把 json 对象转换为 json 字符串

    一般我们要操作 JSON 中的数据的时候,需要 JSON 对象的格式

  • 字符串的形式存在 ,我们叫他 JSON 字符串

    JSON.parse() 把 json 字符串转换为 JSON 对象

    一般我们要在客户端和服务器之间进行数据交换的时候,使用 JSON 字符串

示例代码
1
2
3
4
5
6
7
// 把 json 对象转换成为 json 字符串
var jsonObjString = JSON.stringify(jsonObj); // 特别像 Java 中对象的 toString
alert(jsonObjString)
// 把 json 字符串。 转换成为 json 对象
var jsonObj2 = JSON.parse(jsonObjString);
alert(jsonObj2.key1);// 12
alert(jsonObj2.key2);// abc

JSON 在 Java 中的应用


JavaBean 和 JSON 互转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void test1(){
Person person = new Person(1,"国哥好帅!");
// 创建 Gson 对象实例
Gson gson = new Gson();
// toJson 方法可以把 java 对象转换成为 json 字符串
String personJsonString = gson.toJson(person);
System.out.println(personJsonString);
// fromJson 把 json 字符串转换回 Java 对象
// 第一个参数是 json 字符串
// 第二个参数是转换回去的 Java 对象类型
Person person1 = gson.fromJson(personJsonString, Person.class);
System.out.println(person1);
}

List 和 JSON 互转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1.2.2、 List 和 json 的互转
@Test
public void test2() {
List<Person> personList = new ArrayList<>();

personList.add(new Person(1, "国哥"));
personList.add(new Person(2, "康师傅"));

Gson gson = new Gson();

// 把 List 转换为 json 字符串
String personListJsonString = gson.toJson(personList);
System.out.println(personListJsonString);

List<Person> list = gson.fromJson(personListJsonString, new PersonListType().getType());
System.out.println(list);
Person person = list.get(0);
System.out.println(person);
}

map 和 JSON 互转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void test3(){
Map<Integer,Person> personMap = new HashMap<>();

personMap.put(1, new Person(1, "国哥好帅"));
personMap.put(2, new Person(2, "康师傅也好帅"));

Gson gson = new Gson();
// 把 map 集合转换成为 json 字符串
String personMapJsonString = gson.toJson(personMap);
System.out.println(personMapJsonString);

// Map<Integer,Person> personMap2 = gson.fromJson(personMapJsonString, new
PersonMapType().getType());
Map<Integer,Person> personMap2 = gson.fromJson(personMapJsonString, new
TypeToken<HashMap<Integer,Person>>(){}.getType());

System.out.println(personMap2);
Person p = personMap2.get(1);
System.out.println(p);
}

AJAX 请求

AJAX 即 Asynchronous JavaScript And XML(异步 JavaScript 和 XML),是指一种创建交互式 网页应用的网页开发技术

AJAX 介绍


ajax 是一种 浏览器 通过 js 异步发起请求,局部更新页面的技术

Ajax 请求的局部更新,浏览器地址不会发生变化

局部更新不会舍弃原来页面的内容

原生 AJAX 请求的示例


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
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
// 在这里使用javaScript语言发起Ajax请求,访问服务器AjaxServlet中javaScriptAjax
function ajaxRequest() {
// 1、我们首先要创建XMLHttpRequest
var xmlhttprequest = new XMLHttpRequest();
// 2、调用open方法设置请求参数
xmlhttprequest.open("GET","http://localhost:8080/16_json_ajax_i18n/ajaxServlet?action=javaScriptAjax",true);
// 4、在send方法前绑定onreadystatechange事件,处理请求完成后的操作。
xmlhttprequest.onreadystatechange = function(){
if (xmlhttprequest.readyState == 4 && xmlhttprequest.status == 200) {
alert("收到服务器返回的数据:" + xmlhttprequest.responseText);
var jsonObj = JSON.parse(xmlhttprequest.responseText);
// 把响应的数据显示在页面上
document.getElementById("div01").innerHTML = "编号:" + jsonObj.id + " , 姓名:" + jsonObj.name;
}
}
// 3、调用send方法发送请求
xmlhttprequest.send();


alert("我是最后一行的代码");

}
</script>
</head>
<body>
<!-- <a href="http://localhost:8080/16_json_ajax_i18n/ajaxServlet?action=javaScriptAjax">非Ajax</a>-->
<button onclick="ajaxRequest()">ajax request</button>
<button onclick="ajaxRequest()">ajax request</button>
<button onclick="ajaxRequest()">ajax request</button>
<button onclick="ajaxRequest()">ajax request</button>
<button onclick="ajaxRequest()">ajax request</button>
<div id="div01">
</div>
<table border="1">
<tr>
<td>1.1</td>
<td>1.2</td>
</tr>
<tr>
<td>2.1</td>
<td>2.2</td>
</tr>
</table>
</body>
</html>

jQuery 中的 AJAX 请求


$.ajax 方法

  • url 表示请求的地址
  • type 表示请求的类型 GET 或 POST 请求
  • data 表示发送给服务器的数据
    • name=value&name=value
    • {key:value}
  • success 请求成功 ,响应的回调函数
  • dataType 响应的数据类型
    • text 表示纯文本
    • xml 表示 xml 数据
    • json 表示 json 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(function(){
// ajax请求
$("#ajaxBtn").click(function(){
$.ajax({
url:"http://localhost:8080/16_json_ajax_i18n/ajaxServlet",
// data:"action=jQueryAjax",
data:{action:"jQueryAjax"},
type:"GET",
success:function (data) {
// alert("服务器返回的数据是:" + data);
// var jsonObj = JSON.parse(data);
$("#msg").html(" ajax 编号:" + data.id + " , 姓名:" + data.name);
},
dataType : "json"
});
});

$.get 方法 和 $.post 方法

  • url 请求的 url 地址
  • data 发送的数据
  • callback 成功的回调函数
  • type 返回的数据类型
1
2
3
4
5
6
7
8
// ajax--get请求
$("#getBtn").click(function(){

$.get("http://localhost:8080/16_json_ajax_i18n/ajaxServlet","action=jQueryGet",function (data) {
$("#msg").html(" get 编号:" + data.id + " , 姓名:" + data.name);
},"json");

});
1
2
3
4
5
6
7
8
// ajax--post请求
$("#postBtn").click(function(){
// post请求
$.post("http://localhost:8080/16_json_ajax_i18n/ajaxServlet","action=jQueryPost",function (data) {
$("#msg").html(" post 编号:" + data.id + " , 姓名:" + data.name);
},"json");

});

$.getJSON 方法

  • url 请求的地址
  • data 发送给服务器的数据
  • callback 成功的回调函数
1
2
3
4
5
6
// ajax--getJson请求
$("#getJSONBtn").click(function(){
$.getJSON("http://localhost:8080/16_json_ajax_i18n/ajaxServlet","action=jQueryGetJSON",function (data) {
$("#msg").html(" getJSON 编号:" + data.id + " , 姓名:" + data.name);
});
});

serialize() 表单序列化

serialize() 可以把表单中所有表单项的内容都获取到,并以 name=value&name=value 的形式进行拼接

1
2
3
4
5
6
7
// ajax请求
$("#submit").click(function(){
// 把参数序列化
$.getJSON("http://localhost:8080/16_json_ajax_i18n/ajaxServlet","action=jQuerySerialize&" + $("#form01").serialize(),function (data) {
$("#msg").html(" Serialize 编号:" + data.id + " , 姓名:" + data.name);
});
});

i18n 国际化

  • 国际化(Internationalization) 指的是同一个网站可以支持多种不同的语言, 以方便不同国家, 不同语种的用户访问。
  • 关于国际化我们想到的最简单的方案就是为不同的国家创建不同的网站, 比如苹果公司, 他的英文官网是:
    http://www.apple.com 而中国官网是 http://www.apple.com/cn
  • 苹果公司这种方案并不适合全部公司, 而我们希望相同的一个网站, 而不同人访问的时候可以根据用户所在的区域显示
    不同的语言文字, 而网站的布局样式等不发生改变。
  • 于是就有了我们说的国际化, 国际化总的来说就是同一个网站不同国家的人来访问可以显示出不同的语言。 但实际上这
    种需求并不强烈, 一般真的有国际化需求的公司, 主流采用的依然是苹果公司的那种方案, 为不同的国家创建不同的页
    面。 所以国际化的内容我们了解一下即可。
  • 国际化的英文 Internationalization, 但是由于拼写过长, 老外想了一个简单的写法叫做 I18N, 代表的是 Internationalization
    这个单词, 以 I 开头, 以 N 结尾, 而中间是 18 个字母, 所以简写为 I18N。 以后我们说 I18N 和国际化是一个意思。
  • Title: JavaWeb
  • Author: cccs7
  • Created at: 2022-09-02 00:00:00
  • Updated at: 2023-06-29 23:12:36
  • Link: https://blog.cccs7.icu/2022/09/02/JavaWeb/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments
On this page
JavaWeb