第1章 HTML
1.1 HTML基础
1.1.1 网页和网站和HTML
1.1.1.1 网页和网站
网站是指在英特网上根据一定的规则,使用HTML等制作用于展示特定内容的相关网页的集合。
网页是网站的一“页”,通常是HTML格式的文件,它可以通过浏览器来展示。
网页是构成网站的基本元素,它通常由图片、表格、链接、文字、视频等元素组成。通常我们看到的网页是以.htm或.html为后缀的文件,它们都统称为html文件。
1.1.1.2 什么是HTML
HTML是超文本标签语言(Hyper Test Markup Language),它是用来描述网页的一种语言。
标记语言是一套标记标签。
所谓的超文本,有两层含义:
-
它可以加入图片、声音、动画、多媒体等内容(超越了文件限制)
-
它还可以从一个文件跳转到另一个文件,从一个页面跳转到另一个页面(超链接文本)
1.1.1.3 网页的组成
网页是由网页元素组成的,这些元素是用html标签描述出来的,然后通过浏览器解析来展示给用户。
1.1.2 常用的浏览器
网页可以浏览器来展示的,所以我们要了解一下常用的浏览器。
常用的浏览器:
- IE浏览器:
- 火狐浏览器:
- 谷歌浏览器:
- Edge浏览器:
- Safari浏览器:
- Opera浏览器:
建议使用Chrome浏览器。
浏览器内核:
浏览器内核(渲染引擎):负责读取网页中的内容,整理信息,计算网页的显示方式并显示页面。
浏览器 | 内核 | 备注 |
---|---|---|
IE | Trident | IE、猎豹安全、360极速浏览器、百度浏览器 |
firefox | Gecko | 火狐浏览器内核 |
Safari | Webkit | 苹果浏览器内核 |
chrome/Opera | Blink | Chrome/Opera Blink其实是WebKit的分支 |
1.1.3 Web标准
Web标准是由W3C组织和其它一些标准化组织定义的一系列标准的集合。W3C(万维网联盟)是国际最著名的标准化组织。
为什么需要Web标准
浏览器不同,它显示页面或者排版就会有些许的差异,有了Web标准,就可以使得同一个页面在不同的浏览器中显示的效果是一样的。
使用Web标准还有以下优点:
- 让web的发展更广阔
- 让网站易于维护
- 提高页面浏览速度
Web标准的构成:
- 结构
结构用于对网页元素进行排版,类似于人的身体。在网页中就是使用HTML来完成的。
- 表现
表现用于设置网页元素的布局、颜色、大小等外观,类似于人穿的漂亮的衣服。在网页中使用的是css来完成的。
- 行为
行为指的是网页和用户的交互,例如:点击按钮,点击弹出列表框等,类似于人的行为。网页中的动作是由JavaScript来完成的。
Web标准提出的最佳体验方案:
结构、样式、行为相分离,也就是结构写到HTML文件中,表现写到css文件中、行为写到JavaScript文件中。
1.2 HTML标签
1.2.1 HTML语法规范
-
html标签绝大部分是成对出现的,一个是开始标签,另一个是结束标签,结束标签是有一个
/
的,例如:<html> </html>
当然,也有一些特殊的标签,它只有一个标签,我们将这种标签称之为单标签,单标签数量比较少。例如:
<br />
-
标签关系
标签的关系可以分为两大类:包含关系(父子关系)和并列关系(兄弟关系)。
包含关系:
<head> <title> </title> </head>
并列关系:
<head> </head> <body> </body>
1.2.2 HTML基本结构标签
每一个HTML页面都会有一个基本的结构(骨架标签),页面内容是在这些基本标签上书写的。HTML页面有时也称为HTML文档。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<base href="http://localhost:8080/"/>
<title>Document</title>
</head>
<body>
</body>
</html>
-
<!DOCTYPE html>
标签:文档声明标签,作用就是告诉浏览器使用何种HTML版本来显示网页,它一定要写在HTML的第一行。它不是一个HTML标签,他就是一个文档类型声明标签。 -
html标签的lang属性:指定了页面的语言,比如设置为en(English),谷歌浏览器会知道这个页面是英文的,就会提示了要不要翻译成中文。声明为英文也可以在页面中写中文,声明为英文同样也可以在网页中写中文,它只是来给浏览器提供是否翻译的依据,并不是限制了网页中的语言。
html标签的lang属性也可以设置为:
- zh:中文,包括简体和繁体
- zh-cn:中文简体
-
meta标签的charset属性:指定这个HTML页面的编码方式,通常设置为UTF-8,UTF-8也称之为万国码,它几乎包含了世界上绝大多数的语言,不设置可能会导致乱码。
-
base标签:其中的href属性规定了这个页面中的相对路径是以哪个路径为基础。
常用的编辑器(如:vscode)在新建的HTML文档中直接输入!或会提示生成模板标签
1.2.3 开发工具
-
VScode
Vscode插件推荐:
- Chinese:Vscode汉化插件
- Open in Browser:右键在浏览器中打开HTML文件
- Auto Rename Tag:自动重命名配对的HTML/XML标签
- CSS peek:快速查看样式
注意:插件安装后需要重启才能使用
1.2.4 HTML常用标签
1.2.4.1 标签的语义
学习标签是有技巧的,重点是记住每一个标签的语义,也就是知道这个标签是用来干啥的。
1.4.1.2 标题标签
为了使网页中的内容更加的语义化,我们通常会在页面中用到标题标签,HTML提供了6个等级的标题标签,即<h1>-<h6>,h是单词head(头,标题)的缩写。
**标签语义:**作为标题使用,并且从h1到h6重要性依次递减,也就是大小依次递减
特点:
- 加了标题的文字会变大加粗
- 一个标题会独占一行
1.4.1.3 段落标签
p是单词**paragraph(段落)**的缩写。
**标签语义:**可以把HTML文档分割成若干段落
特点:
-
文本在一个段落中会根据浏览器窗口的大小自动换行
-
段落和段落之间保流有空行
1.4.1.4 换行标签
在HTML中,一个段落的文字会从左到有依次排列,直到浏览器窗口的右端,然后才自动换行,如果想要让文本强制换行,可以使用换行标签<br/>
,br是单词break(打断、换行)的缩写。
**标签语义:**强制换行
特点:
- 换行标签是一个单标签
- br标签只是简单的开始新的一行
1.4.1.5 文本格式化标签
如果要在页面中要使用粗体、斜体、下划线、删除线等效果,就需要使用HTML中的文本格式化标签。
文本格式化标签:
语义 | 标签 | 说明 |
---|---|---|
加粗 | <strong></strong> 或者<b></b> | 推荐是用strong |
斜体 | <em></em> 或者<i></i> | 推荐使用em |
删除线 | <del></del> 或者<s></s> | 推荐使用del |
下划线 | <ins></ins> 或者<u></u> | 推荐使用ins |
**标签语义:**突出显示,表明这些内容的重要性
1.4.1.6 div和span标签
<div>
和<span>
是没有语义的,它们就是一个盒子,是用来装内容的。
div是单词division的缩写,表示分割、分区。span是跨度、跨距的意思。
特点:
-
<div>
标签是起到布局作用,但是在一行只能放置一个<div>
标签,它自己会独占一行,可以将<div></div>
标签看做是一个大盒子 -
<span>
标签也是起布局作用,一行可以有多个<span>
标签,可以将<span>
看做是小盒子
1.4.1.7图像标签和路径
<img/>
标签用于在HTML中插入图片。
<img src="图像url"/>
img是单词**image(图片,图像)**的缩写。
src属性是img标签的必须属性,它用于指定图片的路径或链接地址。
图像标签的属性:
属性 | 属性值 | 说明 |
---|---|---|
src | 图片路径 | 必须属性 |
alt | 文本 | 替换文本,图像不能显示时显示的文字 |
title | 文本 | 提示文本,鼠标放在图像上显示的文字 |
width | 像素 | 设置图片的宽度 |
height | 像素 | 设置图片的宽度 |
border | 像素 | 设置图片的边框粗细 |
注意:
图片的src属性路径中尽量不要带中文,建议在项目中创建一个专门用来存放图片的图片文件夹images
图片的高度和宽度可以只设置其中一个,另一个会自动进行比例缩放,从而避免图片失真
属性之间不分先后顺序,标签名与属性、属性和属性之间均以空格分隔
属性采取的是键值对的形式,值要用双引号括起来
1.4.1.8 超链接标签
<a>
标签用于定义超链接,作用是实现从一个页面跳转到另一个页面。
a是单词anchor(锚)的缩写。
<a href="跳转目标" target="目标窗口的弹出方式"></a>
属性 | 作用 |
---|---|
href | 用于指定链接目标的url地址,它是必须属性,当为标签指定href属性时,它就具有了超链接的功能 |
target | 用于指定打开链接页面的方式,其中_self 为默认值,即在当前窗口中打开,_blank 为在新窗口中打开 |
链接的分类
- 外部链接
例如百度首页等外部链接,通常都是以https开头
- 内部链接
网站链接网站内部页面,通常是路径
- 空链接(#)
没有确定的链接目标时就可以使用空链接
- 下载链接
如果href属性的值是一个文件或者压缩包,点击这个链接就会下载这个文件
- 网页元素链接
网页中的各种网页元素,如文本、表格、音频、视频等都可以添加超链接
例如,下面就是为一张图片添加链接,如果点击这个图片,就会在新标签页中打开百度的首页:
<a href="https://www.baidu" target="_blank"> <img src="../start/image.png"/> </a>
- 锚点链接
当我们点击链接,可以快速定位到页面中指定的某个位置,通常用于内容的导航。例如:
<a href="#here">点击</a>
......
<h3 id="here">3级标题</h3>
假如上面的a标签和h3标签中间有许多内容,点击上面的“点击”链接就会将页面定位到h3标签。
1.4.1.9 注释标签和特殊字符
注释标签
注释标签可以让我们在HTML中写注释,注释不会在页面中显示出来。
<!--这是注释-->
HTML注释的快捷键:ctrl+/
特殊字符
更多HTML特殊字符
1.4.1.10 表格标签
表格通常用来展示数据,它可以让数据非常整齐的显示。
<table>
<tr>
<th>用户名</th>
<th>密码</th>
<th>年龄</th>
</tr>
<tr>
<td>小明</td>
<td>123456</td>
<td>12</td>
</tr>
<tr>
<td>小红</td>
<td>123456</td>
<td>13</td>
<tr>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
<table></table>
:表格标签,定义一个表格,其他的表格标签都要写在table标签中<tr></tr>
:表行标签,定义表格中的一行,需要嵌套在table标签中<th></th>
:表头标签,定义表头,即这个表格有多少列,每一列的字段名是什么,表头中的文字会加粗居中显示,需要嵌套在tr标签中<td></td>
:表格数据标签,定义每个单元格中的数据,需要嵌套在tr标签中
表格属性
通常表格的样式都是用css来设置:
属性名 | 属性值 | 描述 |
---|---|---|
align | left,center,right | 设置表格相对于周围元素的对齐方式 |
border | 1或“” | 规定表格单元格是否有边框,默认为“”,表示没有 |
cellpadding | 像素值 | 设置表格单元沿与其内容之间的空白,默认1个像素 |
cellspacing | 像素值 | 设置单元格之间的空白,默认是2像素 |
width | 像素值或百分百 | 设置表格的宽度 |
表格结构标签
由于表格可能很长,为了更好的显示表格和表示表格,可以将表格分为表格头和表格体两大部分。
使用<thead></thead>
标签表示表格的头部区域,<tbody></tbody>
标签表示表格的主体部分,这样可以更好的分清表格的结构。
合并单元格
合并单元格方式:
- 跨行合并:rowspan=“合并单元格的个数”
- 跨列合并:colspan=“合并单元格的个数”
跨行以最上列的单元格为目标单元格,跨列以最左侧单元格为目标单元格,在目标单元格中写合并代码。
合并单元格的步骤:
- 确定是跨行还是跨列合并
- 找到目标单元格,写合并代码
- 删除多余的单元格
1.4.1.11 列表标签
列表可以非常整齐和有序的排列数据,我们将列表分为三大类:
- 无序列表
- 有序列表
- 自定义列表
无序列表
<ul>
<li>无序列表1</li>
<li>无序列表2</li>
<li>无序列表3</li>
</ul>
注意:在无序列表
<ul>
标签中只能放<li>
标签,不能放其他标签或字符串,但是<li>
标签是一个容器,<li>
中可以放其他标签
有序列表
<ol>
<li>有序列表1</li>
<li>有序列表2</li>
<li>有序列表3</li>
</ol>
注意:
<Ol>
标签中只能放<li>
标签
自定义列表
<dl>
<dt>西瓜</dt>
<dd>一种水果</dd>
<dd>水分较多</dd>
<dd>个头比较大</dd>
</dl>
注意:
- dl标签中只能包含dt标签和dd标签
1.4.1.12 表单标签
表单是用来提交用户数据的,常见的有用户登录表单、用户注册表单等。
表单的组成
在HTML中,一个表单通常包含表单域、表单控件(表单元素)、提示信息三部分组成。
表单域
表单域是一个包含表单元素的区域,在HTML中,form标签用于定义表单域。
form标签会把它范围内的表单元素信息提交给服务器。
<form action="提交到的url" method="提交方法" name="表单的名称">
各种表单元素
</form>
form标签的常用属性:
属性 | 属性值 | 作用 |
---|---|---|
action | url地址 | 用于指定接收处理此表单的服务器程序的url地址 |
method | get/post | 用于设置表单数据的提交方式 |
name | 表单的名称 | 用于设置表单的名称,以辨别一个页面中的多个表单域 |
表单控件(表单元素)
表单域中会包含各种表单元素,这些表单元素就是输入框、复选框、按钮等控件。
- input输入表单元素
input标签中有一个必须属性type,type属性值决定了要接收的信息类型,如:文本、复选框、按钮、单选等。
<input type="属性值"/>
常用的input标签中的type属性取值
属性值 | 描述 |
---|---|
button | 定义可点击按钮,用于触发JavaScript |
checkbox | 定义复选框 |
file | 定义输入字段和“浏览”按钮,供文件上传 |
hidden | 定义隐藏的输入字段 |
image | 定义图像形式提交按钮 |
password | 定义密码输入框,输入的密码会被隐藏 |
radio | 定义单选按钮 |
reset | 定义重置按钮,重置按钮会清空表单中的所有数据 |
submit | 定义提交按钮,按钮按下会将表单提交到指定的处理程序 |
text | 定义单行输入字段,用户可以在其中输入文本,默认宽度为20个字符 |
input标签除了type属性外,还有其他属性:
属性 | 属性值 | 描述 |
---|---|---|
name | input标签的名称 | 定义input元素的名称,是提交的数据的键 |
value | 用户输入或程序员设置 | 规定input元素的值 |
checkout | checked | 规定此input元素首次加载时默认被选中 |
maxlength | 正整数 | 规定输入文本的最大字符长度 |
注意:
单选框和复选框中的每一个选项中的input标签要设置相同的name属性值
input标签的value属性和placeholder属性的使用:
value:设置input标签中的值,不建议将它用来在表单中提示用户输入,它会设置input中的值,用户输入前还要将输入框中的值删除。
placeholder:placeholder 属性提供可描述输入字段预期值的提示信息,该提示会在输入字段为空时显示,并会在字段获得焦点时消失。
将表单中某个字段的设置为必填字段:
可以将input标签的required属性设置为“required”来设置该字段为必填字段,如果用户未输入该字段,会提示用户:
<td>用户名:<input name="userName" type="text" placeholder="用户名" required="required"/></td>
<td>密码:<input name="password" type="password" placeholder="密码" required="required"/></td>
label标签
label标签用于绑定一个表单元素,当点击label标签内的文本时,浏览器会自动将焦点(光标)转到或选择相应的表单中的元素。
<label for="sex_man">男</label>
<input type="radio" name="sex" id="sex_man"/>
注意:label标签中的for属性值应该与对应的标签的id属性值相同
- select下拉表单元素
在页面中,如果有许多个选项让用户选择,并且需要节约页面空间,可以使用select标签控件定义下拉列表。
来自:
<select>
<option selected="selected">北京</option>
<option selected="selected">上海</option>
<option>山东</option>
<option>辽宁</option>
<option>广东</option>
<option>天津</option>
</select>
注意:
- select标签中至少包含一对option标签
- 在option标签中定义属性selected的值为selected时,当前项即为默认选中项
- textarea文本域
文本域适用于需要用户输入较多的文字输入,如:自我介绍等,就需要使用textarea。
自我介绍
<textarea rows="3" cols="20">
我来自......
</textarea>
1.4.1.13 查阅文档
1.2.5
第2章 CSS
2.1 css基础
2.1.1 css介绍
css是层叠样式表(Cascading Style Sheels)的简称,有时我们也会将css称之为css样式表或级联样式表。css也是一种标记语言。
css的主要作用就是设置HTML中文本的样式,图片的外形,版面的布局和外观。
2.1.2 css语法规范
css规则由两部分组成,一部分是选择器,另一部分是声明样式。
p {
color: red;
font-size: 20px;
}
2.2 css基础选择器
css选择器的作用是从页面中挑出我们需要的标签。
选择器分为基础选择器和复合选择器。
基础选择器
基础选择器是由单个的选择器构成的。基础选择器包括:标签选择器、类选择器、id选择器和通配符选择器。
标签选择器:
标签选择器是使用标签名来选择标签
p {
color: aliceblue;
font-family: 'Courier New', Courier, monospace;
}
类选择器:
根据类名来筛选标签
.center {
color: pink;
}
id选择器:
将id值为指定的id值的标签选择出来
#para1
{
text-align:center;
color:red;
}
类选择器:
将所有类名为指定类名的标签选择出来
.center {
text-align:center;
}
复合选择器
2.3 css复合选择器
复合选择器是将基本选择器进行组合。
常用的符合选择器包括:后代选择器、子选择器、并集选择器、伪类选择器等。
后代选择器:
ol li {
color: pink;
}
子选择器:
ol > li {
color: pink;
}
并集选择器:
ol, li {
color: pink;
}
伪类选择器:
链接伪类选择器:
a:link 选择所有未被访问过的链接
a:visited 选择所有已经被访问过的链接
a:hover 选择鼠标正位于其上的链接
a:active 选择活动链接(鼠标按下但是未弹起来的链接)
按照lvha的顺序书写
focus伪类选择器:
:focus伪类选择器是用来获取获得焦点的表单元素。
input:fucous {
background-color:yellor;
}
2.4 css文字属性
- font-family
font-family可以用来设置字体的样式
p {
font-family: Arial, "Microsoft YaHei";
}
常用的字体:
字体英文名(提倡) | 字体中文名 |
---|---|
Microsoft YaHei | 微软雅黑 |
Arial | |
- font-size
font-size可以为文字设置大小
/* 标题标签比较特殊,需要指定文字大小 */
body {
font-size: 16px;
}
h2 {
font-size: 18px;
}
- font-weight
font-weight可以设置文字的粗细
#p1 {
font-weight: bold;
}
#p2 {
font-weight: normal;
}
#p3 {
font-weight: 400;
}
#p4 {
font-weight: 700;
}
normal == 400 bold = 700
推荐使用数字来设置字体的粗细
- font-style
font-style可以设置文字的样式
#p1 {
font-style: italic;
}
/* 下面这个最常用 */
em {
font-style: normal;
}
- 文字样式的复合写法
p {
font-style: italic;
font-weight: 700;
font-size: 19px;
font-family: "Microsoft YaHei";
}
/* 字体复合写法规范 */
/* font: font-style font-weight font-size/line-height font-family */
p {
font: italic 700 16px/20px "Microsoft YaHei";
}
注意:font-size 和 font-family 是必须的
2.4 css文本属性
文本属性可定义文本的外观,如:文本的颜色、对齐文本、装饰文本、文本缩进、行间距等。
文本属性 | 含义 | 常用值 |
---|---|---|
color | 文本的颜色 | 颜色的16进制值 |
text-align | 设置元素内文本内容的水平对齐方式 | left(左对齐),center(居中对齐),right(右对齐) |
text-decoration | 可以给文本添加下划线、删除线、上划线等 | none,underline,overline,line-through |
text-indent | 设置文本首行缩进 | 2em,10px,-10px |
line-height | 设置行高 | 25px |
#p1 {
color: #e74040;
}
#h11 {
text-align: center;
}
#p2 {
text-decoration: underline;
}
#link1 {
/* 取消链接自带的下划线 */
text-decoration: none;
}
#p3 {
text-indent: 2em;
line-height: 40px;
}
2.5 css的引入方式
外部样式表
<head>
<link rel="stylesheet" type="text/css" href="mystyle.css">
</head>
内部样式表
<head>
<style>
hr {color:sienna;}
p {margin-left:20px;}
body {background-image:url("images/back40.gif");}
</style>
</head>
内联样式表
谨慎使用
<p style="color:sienna;margin-left:20px">这是一个段落。</p>
样式的优先级
内部样式表 > 内联演示表 > 外部样式表
2.6 Emment语法
使用Emment语法可以快速写Html和css。
Emment语法用来写html文档:
Emment语法 | 作用 |
---|---|
! | 生成HTMl文件的骨架 |
p*3 | 生成3个p标签 |
ul > li | 创建一个ul,让后再这个ul下创建一个li标签 |
div + p | 表示的是兄弟关系 |
.nav | 生成一个class为nav的div标签 |
#banner | 生成一个id为banner的div标签 |
p.one | 生成一个class为one的p标签 |
.demo$*5 | 生成5个div标签,class分别为demo1…demo5 |
div{这是div标签中的内容} | 在div中输入{}中的文本 |
使用Emment语法快速写css:
其实就是使用简写
Emment语法 | 作用 |
---|---|
tac | 快速生成text-align: center |
ti2em | 快速生成text-indent: 2em |
w100 | 快速生成width: 100px |
2.6 css元素的显示模式
块元素 | 行内元素 |
---|---|
<h1>,<p>,<div>,<ul>,<ol>,<li> | <span>,<a>,<strong>,<i> |
独占一行,宽度、高度、外边距以及内边距都可以控制 | 相邻的行内元素显示在一行中,一行显示多个 |
如果不指定宽度,宽度默认为父容器的100% | 高、宽直接设置都是无效的 |
是一个容器元素,其中可以包含块元素和行内元素 | 默认宽度就是它本身内容的宽度 |
文字类元素中不能包含块级元素,例如,在p标签中不能包含div标签 | 行内元素只能收纳文本或者其他行内元素,但a标签中可以包含块级元素 |
行内块元素
有几个特殊的标签,例如<img/>、<input/>、<td>
等标签,它们同时具有块元素和行内元素的特点,说以,它们也被称之为行内块元素。
特点:
- 在一行上可以显示多个行内块元素,但是它们之间会有一点空隙(行内元素特点)
- 默认宽度就是其内容的宽度(行内元素特点)
- 高度、行高、外边距以及内边距都可以控制(块元素特点)
元素显示模式的装换
将行内元素设置为块元素:
a {
display: block;
width: 200px;
height: 300px;
}
将块级元素转化为行内元素:
#div1 {
display: inline;
background-color: #f18f16;
}
将元素装化为行内块元素:
#div2 {
display: inline-block;
background-color: #e72222;;
}
2.7 css的背景
属性 | 作用 | 值 |
---|---|---|
background-color | 背景颜色 | 预定义颜色值、十六进制、RGB |
background-image | 背景图片 | url(图片路径) |
background-repeat | 背景平铺 | repeat/no-repeat/repeat-x/repaet-y |
background-position | 背景位置 | length/postion(x轴、y轴) |
background-attachment | 背景附着 | scroll/fixed |
背景简写 | 书写简单 | 颜色、地址、平铺、滚动、位置 |
背景颜色透明 | 背景颜色透明 | background:rgba(0,0,0,.3) |
2.8 css选择器的优先级
选择器 | 选择器权重 |
---|---|
继承 * | 0、0、0、0 |
元素选择器 | 0、0、0、1 |
类选择器、伪类选择器 | 0、0、1、0 |
ID选择器 | 0、1、0、0 |
行内样式 style=“” | 1、0、0、0 |
!important 重要的 | 无穷大 |
优先级注意事项:
- 权重是由四组数字组成,但是不会进位
- 符合选择器会有权重叠加的问题,需要重新计算权重
2.9 浮动
多个块级元素纵向排列用浮动,多个块级元素横向排列用浮动
img
{
float:right;
}
属性值 | 描述 |
---|---|
none | 元素不浮动(默认) |
left | 元素向左浮动 |
right | 元素向右浮动 |
注意:
- 浮动元素会脱离标准流(脱标)
- 浮动的元素会一行内显示并且元素顶部对齐
- 浮动的元素会具有行内块元素的特性
- 如果一个子元素浮动,其他子元素也应该浮动
- 当前浮动的元素只会影响后面的标准流
- 清除浮动
额外标签法(隔墙法)
在浮动的最后一个标签写一个空标签
.first .second {
float: left;
}
.clear {
clear: both;
}
<div class="box">
<div class="first">第一个div</div>
<div class="second">第二个div</div>
<div class="clear"></div>
</div>
优点:
- 通俗易懂,书写方便
缺点:
- 添加许多无意义的标签,结构比较差
给父亲添加 overflow 属性(溢出隐藏)
.box {
overflow: hidden; // 清除浮动 hidden、auto、scroll
}
<div class="box">
<div class="first">第一个div</div>
<div class="second">第二个div</div>
<div class="clear"></div>
</div>
优点:
- 简洁
缺点:
- 无法显示溢出部分
:after 伪元素法
/*:after伪元素法清除浮动*/
.clearfix::after {
content: "";
display: block;
height: 0px;
clear: both;
visibility: hidden;
}
.clearfix {
/*IE6,7 专有*/
*zoom: 1;
}
<div class="box clearfix"> // 为父类添加清除浮动类
<div class="first">第一个div</div>
<div class="second">第二个div</div>
<div class="clear"></div>
</div>
双伪元素法清除浮动
/*双伪元素法清除浮动*/
.clearfix:before,
.clearfix:after {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}
.clearfix {
*zoom: 1;
}
<div class="box clearfix"> // 为父类添加清除浮动类
<div class="first">第一个div</div>
<div class="second">第二个div</div>
<div class="clear"></div>
</div>
为什么要清除浮动?
- 父级设置高度
- 子盒子浮动了
- 影响下面的布局了
2.10 css书写的顺序
建议遵循如下顺序:
- 布局定位属性:display/positon/float/clear/visibility/overflow(建议display第一个写)
- 自身属性:width/height/margin/padding/border/background
- 文本属性:color/font/text-decoration/text-align/white-space/break-word
- 其他属性(css3):content/cursor/border-radius/box-shadow/text-shadow/background:linear-gradient
2.11 css定位
定位 = 定位模式 + 边偏移
- 定位模式
定位模式决定的定位方式,它通过css的position属性来设置,其值可以分为四个:
值 | 语义 |
---|---|
static | 静态定位 |
relative | 相对定位 |
absolute | 绝对定位 |
fixed | 固定定位 |
- 边偏移
边偏移属性 | 示例 | 描述 |
---|---|---|
top | top: 80px | 顶端偏移量,定义元素相对于其父元素上边线的距离 |
buttom | buttom: 80px | |
left | left: 80px | |
right | right: 80px |
- 静态定位static(了解)
默认定位方式,无定位的意思。
div {
position: static;
}
- 相对定位relative(重要)
相对定位是元素在移动位置的时候,是相对于它原来的位置来说的;
虽然它会离开原来的位置,但是它原来的位置任然继续占有。
.box1 {
position: relative;
top: 100px;
left: 100px;
width: 200px;
height: 200px;
background-color: pink;
}
- 绝对定位absolute(重要)
绝对定位是元素在移动位置的时候,是相对于它的祖先元素来说的。
绝对定位的特点:
- 如果没有祖先元素或者祖先元素没有定位,则以浏览器的文档为准定位。
- 如果祖先元素有定位(相对、绝对、固定),则以最近一级有定位的祖先元素为参考点移动位置
- 决对定位不会占用原来的位置
- 子绝父相
- 子元素要设置为绝对定位,不会占用位置,可以放到父盒子里的任意地方,不会影响其他兄弟盒子
- 父盒子需要加定位限制子盒子在父盒子内显示
- 父盒子布局是,需要占用位置,所以父盒子必须使用相对定位
- 固定定位fixed(重要)
固定定位是元素固定于浏览器可视区的位置,可以在浏览器页面滚动时元素的位置不会改变。
特点:
- 是以浏览器的可视窗口作为参照
- 固定定位不会占用位置
小技巧:
固定定位还可以和版心对齐
.fixed {
position: fixed;
/* 走浏览器宽度的一半 */
left: 50%;
/* 利用margin-left走版心盒子宽度的一半 */
margin-left: 405px;
width: 50px;
height: 150px;
background-color: blue;
}
- 粘性定位
.nav {
/* 在距离浏览器的可视区域顶部大于0之前都是相对定位
小于等于0之后就是粘性定位 */
position: sticky;
top: 0;
width: 800px;
height: 50px;
background-color: pink;
margin: 100px auto;
}
粘性定位的特点:
- 以浏览器的可视窗口为参照点移动元素(固定定位的特点)
- 粘性定位占有原先的位置(相对定位的特点)
- 必须添加top、left、right、bottom其中一个有效
- 定位总结
定位模式 | 是否脱标 | 移动位置 | 是否常用 |
---|---|---|---|
static静态定位 | 否 | 不能使用边偏移 | 很少 |
relative相对定位 | 否(占位置) | 相对于自身位置移动 | 常用 |
absolute绝对定位 | 是(不占有位置) | 带有定位的祖先元素 | 常用 |
fixed固定定位 | 是(不占用位置) | 浏览器可视区 | 常用 |
sticky粘性定位 | 否(占有位置) | 浏览器可视区 | 当前使用较少 |
- 定位的叠放次序
z-index来控制盒子的前后次序(z轴),数值默认是auto,越大,盒子越靠上,如果值相同,后者居上。
注意:只有定位的盒子才有z-index属性
- 定位的扩展
- 如何让一个绝对定位居中?
.div1 {
position: absolute;
left: 50%;
margin-left: -100px;
width: 100px;
height: 100px;
background-color: pink;
}
- 定位的特殊性
行内元素添加绝对或者固定定位,可以直接设置高度和宽度
块级元素添加绝对或固定定位,如果不给定宽度或者高度,默认大小就是内容的大小
-
浮动元素、绝对定位或固定位元素都不会触发外边距合并的问题
-
绝对定位和固定定位会完全压住下面标准流所有内容,而浮动元素不同,只会压住它下面标准流的盒子,但是不会压住下面标准流盒子里面的文字或图片
2.12 元素的显示和隐藏
- display属性
display除了转换元素之外,同时还有显示元素的作用。display隐藏元素后,不再占有原来的位置。将display设置为none就可以将这个元素隐藏起来。
- visiblity属性
将visibility属性设置为hidden,就可以将元素隐藏起来。visibility隐藏元素后,继续保留原有的位置。
- overflow属性
将overflow设置为hidden就不会显示超出边界的内容。将overflow设置为scroll,不管内容有没有溢出,都会有滚动条。将overflow设置为auto,如果内容有超出边界,才会有滚动条。
2.12 css高级技巧
1. 精灵图(sprites)
将网页中的背景小图片合并到一张大图中,就不需要经常请求服务器了。
.box1 {
width: 70px;
height: 82px;
background: url(../images/img2.jpg) no-repeat -349px -123px;
}
2. 字体图标
- 字体图标的下载
icomoon子库 http://icomoon.io
阿里iconfont子库 http://www.iconfont
- 字体图标的引入
把页面下载包中的fonts文件夹发到页面根目录下,在css样式中全局声明字体,也就是复制字体文件夹下stylesheet.css文件中的部分内容到HTML中。
<!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>
/* 字体声明 */
/* 下面是从stylesheet.css中复制的内容 */
/* ---------- */
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?lmqsf9');
src: url('fonts/icomoon.eot?lmqsf9#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?lmqsf9') format('truetype'),
url('fonts/icomoon.woff?lmqsf9') format('woff'),
url('fonts/icomoon.svg?lmqsf9#icomoon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
/* ---------- */
span {
font-family: 'icomoon';
font-size: 30px;
color: red;
}
</style>
</head>
<body>
<span></span> <!-- 打开demo.html,复制对应的图标的方框,该方框就代表该字体图标 -->
</body>
</html>
- 字体图标的追加
将自己之前的selection.json文件导入到网站中,添加新的图标,点击Generator Font生成新的压缩包,替换掉之前的压缩包。
3. css三角
.xiaomi {
position: relative;
margin-top: 10px;
width: 400px;
height: 200px;
background-color: green;
}
.xiaomi span {
position: absolute;
right: -80px;
top: 60px;
width: 0;
height: 0;
/* 兼容低版本浏览器 */
line-height: 0;
font-size: 0;
border: 40px solid transparent;
border-left-color: green;
}
4. css用户界面样式
所谓的用户界面,就是更改一些用户的操作样式,以便提供更好的用户体验。
- 鼠标样式
通过设置cursor属性就可以改变鼠标遇到某个元素是展现的样式。
属性值 | 描述 |
---|---|
default | 小白 默认 |
pointer | 小手 |
move | 移动 |
text | 文本 |
not-allowed | 禁止 |
- 轮廓线outline
将表单的outline属性设置为none或0就可以取消掉默认的边框。
- 文本域禁止拖拽
将resize属性设置为none就可以禁止文本域拖拽。
5. vertical-align属性应用
css的vertical-aline属性通常用来设置图片或者表单(行内元素或行内块元素)和文字垂直对齐。
值 | 描述 |
---|---|
baseline | 默认,元素放置在父元素的基线上 |
top | 把元素的顶端与行中最高元素的顶端对齐 |
middle | 把此元素放置在父元素的中部 |
bottom | 把元素的顶端与行中最低的元素的顶端对齐 |
6. 图片底部的空白缝隙
图片底部会有一个空白缝隙,原因是行内块元素会和文字的基线对齐。
解决方案有两种:
- 给图片添加vertical-align: middle|top|bottom(不使用默认的基线对齐)
- 把图片转化为块级元素
7. 如何将溢出的文字显示为省略号
一般情况下,中文和英文遇到盒子边界都会自动换行;但在连续的字母或数字的情况下,是不会换行的,可以通过如下设置使其自动换行:
div {
/* 设置自动换行 */
word-wrap: break-word;
}
- 单行文本溢出显示为省略号
div {
width: 150px;
height: 80px;
background-color: pink;
margin: 100px auto;
/* 1.强制一行显示 */
white-space: nowrap;
/* 2.溢出部分隐藏 */
overflow: hidden;
/* 3.文字用省略号代替 */
text-overflow: ellipsis;
}
- 多行文本溢出显示为省略号
多行文本溢出省略兼容性较差:
div.box2 {
width: 150px;
height: 45px; /* 将高度设置为合适的高度 */
background-color: pink;
overflow: hidden;
text-overflow: ellipsis;
/* 弹性伸缩盒子模型显示 */
display: -webkit-box;
/* 限制在一个块元素显示的文本的行数 */
-webkit-line-clamp: 2;
/* 设置或检索伸缩盒子对象的子元素的排列方式 */
-webkit-box-orient: vertical;
}
推荐让后端来实现截取定长的文字,然后再后面添加省略号。
- 常见布局技巧
- margin负值的使用
<!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>margin的负值的使用</title>
<style>
li {
list-style: none;
}
ul>li {
float: left;
width: 200px;
height: 300px;
border: 1px solid red;
margin-left: -1px;
}
/* 当鼠标覆盖时,将该元素定位,就会覆盖其他不定位的元素 */
/* ul>li:hover {
position: relative;
border: 1px solid green;
} */
/* 提高元素的层级,就会压住其他元素 */
ul>li:hover {
z-index: 1;
border: 1px solid blue;
}
</style>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
</html>
- 文字围绕浮动元素
浮动产生的原因就时让文字围绕图片环绕,所以,可以将图片和文段放在同一个容器中,并将图片设置为浮动就可以实现图片在左,文字在右的布局。
- 行内块巧妙运用
行内块元素可以在一行上、可以设置大小、元素之间有间隙,且给父元素设置text-align:center就可以使得所有的行内块元素水平居中。
- css三角强化的妙用
<!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>
* {
margin: 0;
padding: 0;
}
.box1 {
width: 0;
height: 0;
border-top: 100px solid transparent;
border-right: 50px solid skyblue;
border-bottom: 0px solid blue;
border-left: 0px solid green;
}
/* 可以简写 */
.box2 {
width: 0;
height: 0;
border-color: transparent red transparent transparent;
border-style: solid;
border-width: 100px 60px 0 0;
}
.price {
width: 160px;
height: 24px;
line-height: 24px;
border: 1px solid red;
margin: 0 auto;
}
.old_price {
position: relative;
float: left;
width: 90px;
height: 100%;
background-color: red;
text-align: center;
color: #fff;
font-weight: 700;
}
.old_price i {
position: absolute;
right: 0;
top: 0;
width: 0;
height: 0;
border-color: transparent white transparent transparent;
border-style: solid;
border-width: 24px 10px 0 0;
}
</style>
</head>
<body>
<div class="box1">
</div>
<div class="box2"></div>
<div class="price">
<span class="old_price">
¥232.34
<i></i>
</span>
<span class="new_price">¥33.34</span>
</div>
</body>
</html>
2.13 css初始化
/* 将所有标签的内外边距清零 */
* {
margin: 0;
padding: 0
}
/* em、i 中的斜体文字不倾斜 */
em,
i {
font-style: normal
}
/* 去掉li中的小圆点 */
li {
list-style: none
}
img {
border: 0; /* 照顾低版本的浏览器,如果图片外边包含了链接会有边框问题 */
/* 取消图片底部有空白缝隙的问题 */
vertical-align: middle
}
/* 当鼠标经过按钮时,鼠标变成小手 */
button {
cursor: pointer
}
/* 去掉链接的颜色和下划线 */
a {
color: #666;
text-decoration: none
}
/* 当鼠标覆盖在链接上是,链接文字变成红色 */
a:hover {
color: #c81623
}
button,
input {
font-family: Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\5B8B\4F53", sans-serif
}
body {
/* css3的属性,让文字显示更加清晰,抗锯齿 */
-webkit-font-smoothing: antialiased;
background-color: #fff;
font: 12px/1.5 Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\5B8B\4F53", sans-serif;
color: #666
}
.hide,
.none {
display: none
}
/* 清除浮动 */
.clearfix:after {
visibility: hidden;
clear: both;
display: block;
content: ".";
height: 0
}
.clearfix {
*zoom: 1
}
第3章 html5、css3提高
3.1 HTML5的新特性
新特性都有兼容性问题。
- HTML5新增的语义化标签
<header>: 头部标签
<nav>: 导航标签
<article>: 内容标签
<section>: 定义文档某个区域
<aside>: 侧边栏标签
<footer>: 尾部标签
注意:
- 语义标签更多使用在移动端,因为在移动端这些语义标签没有兼容性问题
- 在IE9中,需要将这些语义标签转化为块级元素
- HTML新增的多媒体标签
音频:
视频:
视频
video标签常见属性:
属性 | 值 | 描述 |
---|---|---|
autoplay | autoplay | 视频是否自动播放(谷歌浏览器需要添加muted属性来解决自动播放问题) |
controls | controls | 向用户显示播放控件(不同的浏览器播放控件可能不同) |
width | pixels | 设置播放器宽度 |
height | pixels | 设置播放器高度 |
loop | loop | 设置播放完视频是否循环播放视频 |
preload | auto(预先加载视频)、none | 规定是否预加载视频(如果设置了autoplay,就忽略该属性) |
src | url | 视频的url地址 |
poster | poster | 加载等待的画面图片 |
muted | muted | 静音播放 |
mp4格式的视频的兼容性最好,也可以使用多个source标签来提高兼容性:
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
您的浏览器不支持Video标签。
</video>
音频
音频标签和视频标签的使用方法基本一致。
mp3音频的兼容性最好,也可以使用source标签来提高兼容性:
<audio controls>
<source src="horse.ogg" type="audio/ogg">
<source src="horse.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素。
</audio>
注意:
- 谷歌默认将音频自动播放禁止了,可以通过JavaScript来解决
- HTML5新增的input类型
<!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>HTML5新增的input类型</title>
<style></style>
</head>
<body>
<form>
<ul>
<li>邮箱:<input type="email"/></li>
<li>网址:<input type="url"/></li>
<li>日期:<input type="date"/></li>
<li>日期:<input type="time"/></li>
<li>数量:<input type="number" name="" id=""></li>
<li>手机号码:<input type="tel" name="" id=""></li>
<li>搜索<input type="search" name="" id=""></li>
<li>颜色<input type="color" name="" id=""></li>
<li><input type="submit" value="提交"></li>
</ul>
</form>
</body>
</html>
- HTML5中新增的表单属性
属性 | 值 | 说明 |
---|---|---|
required | required | 设置字段是否是必填字段 |
placeholder | 提示文本 | 表单的提示信息,存在默认值将不显示 |
autocomplete | off/on | input标签设置了name属性且正确提交过了,下次就可以提示之前提交过的信息。默认是打开的。 |
autofocus | autofocus | 自动聚焦属性,页面加载完成自动聚焦到指定表单 |
multiple | multiple | 可以多选文件提交 |
3.2 CSS3的新特性
css3也有兼容性问题,在移动端支持优于pc端。
- css3 新增选择器
属性选择器
选择器 | 功能描述 |
---|---|
E[attribute] | 选取带有指定属性的元素 |
E[attribute=value] | 选取带有指定属性和值的元素 |
E[attr^=“val”] | 匹配属性attr的值以指定值"val"开头的每个元素 |
E[attr$=“val”] | 匹配属性attr的值以指定值"val"结尾的元素 |
E[attr*=“val”] | 匹配属性attr的值包含字符串"val"元素 |
注意:类选择器、属性选择器、伪类选择器权重都为10
结构伪类选择器
结构伪类选择器 | 功能 |
---|---|
:root | |
E:nth-child(n) | |
E:nth-child(even) | 选择序号 |
E:nth-child(odd) | 选择序号为奇的子元素 |
E:nth-child(n) | n从0开始以步长为1开始增加,选取所有的子元素(子元素序号从0开始) |
E:nth-child(5n) | 选择序号为0、5、10…的子元素(子元素序号从0开始) |
E:last-child | |
E:fisrt-child | |
E:first-of-type | |
E:last-of-type | |
E:nth-of-type(n) | |
E:nth-last-of-type(n) | |
E:only-child | |
E:only-of-type | |
E:empty | |
注意:
- nth-child会将所有的子元素都排序号,所以 div:nth-child(1) 会将第一个子元素选择出来,然后再判断其是不是div,如果是 div 的话,就执行渲染,否则,不执行渲染。
- div:nth-of-type(1) 会将子元素中的所有div进行排序,然后选中第一个。
伪元素选择器(重点)
伪元素选择器可以帮助我们使用css来创建标签,而不需要使用HTML标签,从而简化HTML结构。
选择符 | 介绍 |
---|---|
::before | 在元素内部的前面插入内容 |
::after | 在元素内部的后面插入内容 |
注意:
- before和after创建一个元素,但是属于行内元素
- 新创建的元素在文档中找不到,所以被称之为伪元素
- before和after选择器必须有content属性
- 为元素选择器和标签选择器一样,权重为1
- css3盒子模型
在之前的盒子模型中,设置好盒子的大小之后,如果在设置padding或border就会撑大盒子。
css3中可以通过box-sizing来指定盒子模型的大小,有两个值:content-box、
border-box。
盒子的大小可以分为两种情况:
- box-sizing: content-box (默认) 盒子大小=width+padding+border
- box-sizing: border-box 盒子的大小=width
注意:
使用box-sizing: border-box 来使得盒子不会被padding和border撑大的前提是padding和border的和不会大于盒子的大小。
- css3的其他特性
css3滤镜
img {
/* 数值越大越模糊 */
filter: blur(3px);
}
img:hover {
filter: blur(0);
}
css3 calc函数
.father {
width: 300px;
height: 200px;
background-color: pink;
}
.son {
width: calc(100% - 50px);
height: calc(100% - 40px);
background-color: yellow;
}
calc函数还可以计算+、-、*、/
- css3过渡(重点)
transition可以实现过渡动画。
transition: 要过渡的属性 花费的时间 运动曲线 何时开始;
属性:可以是宽度、高度、背景颜色、内外边距,也可以是all
花费时间:单位是秒,且秒必须写,如:0.5s
运行曲线:默认是ease(可以省略)
何时开始:单位是秒,且秒必须写,可以设置延迟触发时间,默认是0s
谁做过渡给谁加
第4章 JavaScript
第5章 servlet
前面几章介绍了服务端的知识,接下来就是服务端的知识。
5.1 Tomcat
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML的一个应用页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
5.1.1 Tomcat服务器的下载和安装
- 官网下载压缩包
- 配置好JAVA_HOME这个环境变量
- 解压压缩包
安装完毕后通过两种方法开启Tomcat:
第一种:
开起Tomcat后,在浏览器中输入地址:http://localhost:8080 ,将会出现Tomcat的首页,说明Tomcat启动成功。
第二种:
将Tomcat集成到Eclipse中,
集成到Eclipse中后,就可以通过右键一个web项目,Run ad
--> Run on Server
来将该项目运行在Tomcat服务器中了。
5.1.2 Tomcat的目录结构
下面是Tomcat的安装目录的结构:
bin:包含Tomcat的启动、停止等一些批处理文件
conf:Tomcat的配置文件
lib:Tomcat运行时依赖的jar包
logs:日志信息
temp:Tomcat用来临时存储文件的文件夹
webapps:里面集合了所有的Web项目,每一个文件夹就代表一个Web项目。Tomcat启动默认访问的是root目录。我们发布的web应用也是放在这个文件夹。一般访问一个web项目默认访问的是index.html文件。
work:保存的是tomcat运行时编译好的一些文件
5.2 servlet
Servlet是运行在服务器上的一段小java程序,通过HTTP来接收和响应用户的请求。Servlet是sum公司制定的一套规范,所有的Servlet的实现类都可以称之为Servlet。
在Tomcat6以及之前的版本中:
-
创建servlet的实现类(java类)
-
在servlet中的service方法中写处理代码
下面是servlet类中的方法:
public class selevlet01 implements Servlet{ public selevlet01(){ System.out.println("servlet01 constructor"); } //初始化 @Override public void init(ServletConfig config) throws ServletException { System.out.println("init"); } //获取servlet配置信息 @Override public ServletConfig getServletConfig() { System.out.println("ServletConfig"); return null; } //服务 @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("service"); PrintWriter writer = res.getWriter(); writer.write("service"); } //获取servlet信息 @Override public String getServletInfo() { System.out.println("getServletInfo"); return null; } //销毁 @Override public void destroy() { System.out.println("destroy"); } }
-
在web.xml中配置servlet
<servlet> <servlet-name>selevlet01</servlet-name> <servlet-class>com.jxd.servlet01.selevlet01</servlet-class> </servlet> <servlet-mapping> <servlet-name>selevlet01</servlet-name> <url-pattern>/helloWorld</url-pattern> </servlet-mapping>
servlet-name:给这个servlet起的别名,可以任意取,一般和servlet类的名字相同
**servlet-class:**servlet类的完整名称,可以在eclipse中选择类名后右键
Cope qualified Name
获取**servlet-pattern:**配置这个servlet响应的请求,即在HTML页面中使用的servlet
在之后的Tomcat中:
没有web.xml配置文件,也不需要配置servlet,直接用Eclipse创建Servlet。
5.3 servlet的生命周期
Servlet是运行在servlet的容器(Tomcat)中,Servlet是服务器创建和销毁的。
从servlet的方法中就可以看出servlet的生命周期:
**构造器:**用来创建对象
**init()😗*初始化servlet,接收一个服务器传送过来的ServletConfig类型的变量,它代表当前的servlet的配置信息,它与servlet是一一对应的。
ServletConfig对象的常用方法:
常用方法 | 作用 |
---|---|
config.getServletName() | 获取servlet的别名 |
config.getInitParameter() | 获取Servlet的初始化参数 |
config.getServletContext() | 获取Servlet的上下文信息,也就是当前的web应用,一个web项目中的servlet的ServletContext是一样的 |
ServletContext对象常用的方法:
常用方法 | 作用 |
---|---|
context.getInitParameter( ) | 获取servlet初始化参数中的值 |
context.getContextPath() | 获取项目的虚拟路径 |
context.getRealPath( “资源在web项目下的虚拟路径”) | 获取web项目的实际路径,常用于资源的下载和上传 |
ServletContext作为最大的域对象共享资源,域对象可以用来在不同的web资源中共享数据。
Jsp四大域对象:
-
pageContext
-
request
-
session
-
application
**service():**处理请求
**destory()😗*销毁servlet
**servlet的运行过程:**第一次请求servlet的时候,使用构造器创建一个servlet对象,执行初始化,调用service()方法处理请求,当下一次掉用这个servlet的时候,就直接调用servlet对象的service()方法处理请求。当web应用被卸载或服务器关闭的时候执行destory()方法销毁这个servlet对象。
5.4 HttpServlet
HttpServlet是专门用来处理HTTP请求的,它可以使用Eclipse来自动创建,HttpServlet中包含两个方法:
- doPost():用来处理get请求
- doGet():用来处理post请求
一般在doGet()中调用doPost()。
5.4.1 HttpServletRequest
HttpServletRequest封装了当次的Http请求信息,可以调用这个对象的方法来获取请求中包含的信息。
方法 | 作用 |
---|---|
request.getParameter() | 获取请求参数,是单个的key-value |
request.getParameterValues() | 获取多选框之类的数据 |
request.getRequestDispatcher().forword(request, response) | 转发 |
request.getHeader() | 获取请求头信息 |
request.getHeaders() | 获取请求头中的多个值 |
request.getContextPath() | 获取项目的虚拟路径 |
HttpServletRequest也作为域对象共享数据。
注意:request.getParameter()方法可以获取的参数:
- 表单中提交的
- 在url后面的
对于get请求,它的请求参数是带在url中的,而对于post请求,它的参数是在请求体中的。
5.4.2 HttpServletResponse
HttpServletResponse代表的是当次的响应对象。
HttpServletResponse的常用方法:
方法 | 作用 |
---|---|
response.getWriter().write( “ ”) | 向页面中写入内容 |
response.sendRedirect(“重定向的位置”) | 重定向 |
5.4.3转发和重定向的区别
装发和重定向都是在web应用中页面跳转的重要手段。
重定向 | 转发 | |
---|---|---|
浏览器地址栏 | 变 | 不变 |
请求次数 | 2 | 1 |
使用方式 | response.sendRedirect() | request.getRequestDispatcher().forword(request,response) |
位置 | 浏览器处理(重新访问) | 服务器内部找资源并返回 |
web-inf | 不可以 | 可以 |
共享请求数据域 | 可以共享 | 不可以 |
目标资源 | 当前项目 | 任意位置 |
5.5 乱码
乱码问题都是由于字符集不统一所导致的,因此,要统一字符集。
-
get请求提交中文(参数放在url中)
原因:服务器获取解析url的时候不知道编码规则
修改服务器的配置文件server.xml
解决办法:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8"/>
-
post请求提交中文(参数放在请求体中)
原因:服务器不知道收到的文字的编码方式
解决办法:
request.setCharacterEncoding("utf-8")
-
响应[response.getWriter.write(“中文”)]
原因:浏览器不知道write写入的字符类型
第一种解决办法(推荐):
response.setContentType(“text/html;charset=utf-8”);
第二种:
response.setContentType("text/html"); response.setCharacterEncoding("utf-8");
第三种:
response.addHeader("Content-Type", "text/html;charset=utf-8");
5.6 项目中的路径问题
绝对路径以/开始,/经常代表从根开始。
下面的例子都假设在服务器中有一个名为project1的项目,项目下有一个名为pages的目录,pages目录中有一个名为index.html的文件。
在页面中使用绝对路径:
所有在HTML页面中的绝对路径,/代表的是从服务器的根开始,即http://localhost:8080,因为一个服务器中可能有多个项目,所以要在/后面加上项目名称,下面是链接到index.html文件的链接:
<a href="/project1/pages/index.html">首页</a>
注意:在jsp文件中的include等标签中,由于jsp文件会翻译成Java文件,也就是在服务器上执行,所以/代表的就是当前项目的根目录。
在转发中使用绝对路径:
转发中的/代表的是项目的根目录,下面是一个转发到index.html文件的转发例子:
request.getRequestDispatcher("/pages/a.html").forward(request, response);
在重定向中使用绝对路径:
重定向中的/代表的是服务器的根,下面是重定向到index.html的重定向代码:
response.sendRedirect("/project1/pages/index.html");
该怎么理解呢?页面中的链接和重定向都是浏览器来处理,所以是以服务器的根开始的;而重定向是服务器来处理的,所以是从项目的根开始的。
使用base标签来解决路径问题:
在head标签之中,可以使用base标签:
<head>
<meta http-equiv="Content-Type" content="register/html; charset=UTF-8">
<title>注册</title>
<base href="http://localhost:8080/MonkeyShop/"/>
</head>
<body>
<image src="images/picture1.png"></image>
</body>
使用base标签之后,我们在该页面中的所有的相对路径都是从这个base标签中的href属性指定的url开始的。
例如:上面的image标签的src属性的真实路径是:
http://localhost:8080/MonkeyShop/images/picture1.png
5.7项目发布后的结构
Tomcat发布项目后会将WebContent中的内容和src中的内容发布,src中的所有的.java文件会编译成.class文件并放在WEB-INF文件夹下的classes文件夹中。
下面是某一个项目发布后的结构:
下面是文件夹WEB-INF中的内容:
5.8 动态web工程创建后没有web.xml文件
使用下面如图的方式解决:
第6章 项目的第一阶段
项目架构
- 表示层
HTML页面,Servlet
- 业务逻辑层
Service层:判断用户是否能够登陆等
- 数据库访问层(持久化层)
Dao(Database Access Object)层:所有操作数据库的类
模型层:创建与数据库对应的对象
项目目录结构:
项目流程:
-
用户查看HTML页面,发起请求
-
Servlet层的某个Servlet收到用户请求
-
掉用Servlet层相关的方法来处理
-
Service层可以直接调用Dao层来和数据库沟通
-
Dao层将查询到的数据封装为对象,系统以后就使用对象
开发流程:
需求分析,建立模型
建立登录和注册相关的模型(Bean层)
建立用户表,建立对应的User类,sys_user
建立Dao层,操作数据库
JDBCUtils:用来获取数据库连接
UserDao:用来操作用户表的Dao类
建立Service层
UserService:完成用户的登录注册功能
…
建立Servlet层
LoginServlet,RegisterServlet
界面
修改响应的逻辑
开发详细步骤
# 创建store数据库
CREATE DATABASE store CHAR SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 创建用户表
CREATE TABLE sys_user(
USER_ID INT(11) AUTO_INCREMENT COMMENT '用户ID',
USER_NAME VARCHAR(32) NOT NULL COMMENT '用户名',
USER_PASSWORD VARCHAR(10) NOT NULL COMMENT '密码',
USER_SEX VARCHAR(1) DEFAULT NULL COMMENT '性别',
USER_BIRTHDAY DATE DEFAULT NULL COMMENT '出生日期',
USER_EMAIL VARCHAR(60) NOT NULL COMMENT '邮箱',
USER_MOBILE VARCHAR(11) DEFAULT NULL COMMENT '用户电话',
USER_ADDRESS VARCHAR(200) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (USER_ID)
) COMMENT='用户表' ENGINE=INNODB DEFAULT CHARSET='utf8mb4' COLLATE='utf8mb4_unicode_ci';
对sys_user表做一个映射,即在bean中创建一个User类。
完成JDBCUtils类,使用c3p0.
由于所有的Dao都有部分相同的功能,所以,将这些相同的功能都提取出来,建立BaseDao类,其他的Dao类就可以继承这个类。
BaseDao:
范型,getBean(),getBeanList(),update(),
创建UserDao,面向接口编程,定义一个UseerDao接口,定义UserDao有什么方法,UserDao接口中应该有的方法:
User getUserByUserNameAndPassword(User user)
boolean registUser(User user)
UserService接口:
User login(User user)
boolean register(User user)
第7章 jsp
7.1 jsp基础
Servlet可以控制页面的跳转,html可以展示页面,但是HTML页面中的内容不受Servlet的控制。如过用户在登录的时候密码不正确等原因,可以使用servlet使其跳转到一个登录失败页面,但这并不好。
jsp是能写java代码的HTML,jsp的全称是Java Server Page,jsp的本质是一个Servlet,Servlet能做的事JSP都能做,JSP能够以HTML页面的方式呈现数据,是一个可以嵌入Java代码的HTML,JSP不同于HTML,不能使用浏览器直接打开,而必须运行在服务器中。
jsp的底层文件是一个.java文件,打开这个.java文件后就会发现它其中有和servlet相似的init(),service(),destory()等方法,并且它是继承了HttpServlet。
jsp就是将我们的html代码使用response.getWriter.write()将其写在java代码中。
模板元素
jsp会把模板元素写在out.print()中,比如html代码,script标签。
表达式
格式:
<%= %>
jsp表达式的作用是在页面中输入内容,例如:
<%= new Date()%>
脚本片段
格式:
<% %>
我们可以在脚本片段中写java代码,例如:
<body>
<%
int age = 10;
if (age >= 10){
out.print("大于等于10");
}else{
out.print("小于10");
}
%>
</body>
上面的代码将在页面中输出“大于等于10”。
脚本片段会被原封不动的复制到java文件中,我们可以在jsp文件中书写多个脚本片段,并且可以将脚本片段使用模板元素分隔开来,但是,整个jsp中的脚本片段必须是合法的。
<body>
<%
List<String> str = new ArrayList<String>();
str.add("s1");
str.add("s2");
str.add("s3");
%>
<table>
<%
for(int i=0;i<str.size();i++){
%>
<tr><td>名字</td><td><%=str.get(i) %></td></tr>
<%
}
%>
</table>
</body>
脚本片段都是放在service()方法中的,所以,在service()方法中不能写的代码在jsp脚本片段中也不能写,例如:
final int a=10;
public void test(){
};
jsp声明
语法:
<%! %>
jsp声明中的代码都会写在Service方法之外,它是写在java类的里面。也正是由于它是在Service方法之外的,所以可以在jsp什么中定义方法等。
jsp注释
语法:
<%-- --%>
几种注释的可见性:
jsp原文件 | .java文件 | HTML页面 | |
---|---|---|---|
<%-- --%> | 可见 | 不可见 | 不可见 |
可见 | 可见 | 可见 | |
// | 可见 | 可见 | 不可见 |
jsp指令
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见的输出,而只是告诉引擎如何处理JSP页面中的其余部分。
语法:
<%@ 指令名 属性名=属性值 %>
-
page指令
定义页面如何解析
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
page指令中常见的属性:
属性名 作用 import 导包 pageEncoding 指定页面使用的字符集,也是告诉jsp引擎使用指定的编码方式翻译 contentType 设置响应头 errorPage 指定发生错误转到的页面 isErrorPage 表示当前页面时错误页面 session 默认是true,表示当前页面是否参与会话,是否可以使用session对象 isELIgnored 默认是false,表示是否忽略El模式 info 定义页面的信息,放在getServletInfo()方法中 -
include指令
静态包含
可以把另外一个页面包含到当前页面
<%@include file="/html1.html" %>
-
taglib指令
在页面引入标签库
jsp标签
jsp标签是jsp中内置的标签,每一个标签都有不同的功能,能动态的执行一段代码。
常用的jsp标签:
jsp标签 | 作用 |
---|---|
<jsp:include> | 也是在页面中包含另外一个页面,是动态包含,其中的page属性的值是要包含的页面的路径。动态包含会将要包含的页面进行翻译和编译,适合有数据更新的界面。 |
<jsp:forward> | 转发,其中的page属性的值是要转发的页面的路径。如果不带参数的话,标签中不能包含任何的空格。 |
7.2 jsp九大隐含对象
隐含对象:在<% %>中可以直接使用的对象,可以理解为在Servlet的service()方法中的对象。
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
- pageContext:代表当前页面对象
- session:代表会话对象
- exception:代表捕获的异常对象
- application:代表整个web应用
- config:代表的是servlet的配置信息
- out:可以在页面输出数据的out对象
- page:代表的是当前的jsp对象
- request:代表的是当次请求的详细信息的对象
- response:代表的是当次响应的对象
7.2.1 四大域对象(共享数据):
pageContext
request
session
application
-
pageContext:最小的域对象,通过pageContext.getXXX方法可以获取其他的隐含对象。它还作为域对象共享数据,只能在当前页面共享数据,离开页面就无法共享。
<body> <% //给页面域中设置内容 pageContext.setAttribute("username", "Tom"); %> <%--获取域中的对象 --%> <%=pageContext.getAttribute("username")%> </body>
-
request:能在一个请求对象中共享数据,只要是同一次请求,就可以共享数据。链接是发起另一个请求,不是同一次请求。转发对于浏览器来说只发送了一次请求,转发是同一次请求。
-
session:在同一次会话中共享数据。打开浏览器是一次会话,关闭浏览器是结束当前会话。会话就是和web应用沟通,所以不同的web应用就是不同的会话。不同的浏览器也是不同的会话。
-
application:在同一个web应用中共享数据。服务器停止后就卸载了web应用,再次开启就属于不同的应用。
下面是test5.jsp文件中的内容:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
//给PageContext域中设置内容
pageContext.setAttribute("PageUser", "pageName");
//给request域中设置内容
request.setAttribute("ReqUser", "reqName");
//给session域中设置内容
session.setAttribute("SessUser", "sessName");
//给applocation域中设置内容
application.setAttribute("AppUser", "appName");
%>
<%--获取域中的对象 --%>
<h1>以下是各个域中的数据:</h1>
pageContext: <%=pageContext.getAttribute("PageUser")%><br/>
request: <%=request.getAttribute("ReqUser")%><br/>
session: <%=session.getAttribute("SessUser")%><br/>
application: <%=application.getAttribute("AppUser")%><br/>
<a href="/jsp_test/test55.jsp">链接到test55.jsp</a>
</body>
</html>
下面是test55.jsp中的内容:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%--获取域中的对象 --%>
<h1>test55.jsp 以下是各个域中的数据:</h1>
pageContext: <%=pageContext.getAttribute("PageUser")%><br/>
request: <%=request.getAttribute("ReqUser")%><br/>
session: <%=session.getAttribute("SessUser")%><br/>
application: <%=application.getAttribute("AppUser")%><br/>
</body>
</html>
你可以看看在test55.jsp中可以获取哪些对象,如果将test5.jsp中的链接该为直接转发到test55.jsp,test55.jsp可以获取到哪些对象数据。
四大域对象的比较:
域对象 | 作用范围 | 起始时间 | 结束时间 |
---|---|---|---|
pageContext | 当前jsp页面 | 页面加载 | 离开页面 |
request | 同一次请求 | 收到请求 | 响应 |
session | 同一次会话 | 开始会话 | 结束会话 |
application | 当前web应用 | web应用加载 | web应用卸载 |
7.2.2 五大常规对象:
exception:getMassage( )
config:getServletName( ) getInitParameter( )
out:write( ) flush( )
page:this
response:getWriter().write(" ")
注意:response.getWriter().write()和out.write()都有缓冲区,分别是response的缓冲区和JspWriter缓冲区,最终JspWriter缓冲区中的内容会附加在response缓冲区的后面,导致JspWriter写的内容都会在response写的内容的后面,要想解决这个问题,可以将使用out.flush()方法刷新JspWriter缓冲区中的内容,也就是将JspWriter缓冲区中的内容提交到response缓冲区中。
7.3 el
7.3.1 el的简介和使用
EL(Expression Language)全称是表达式语言,它可以使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
下面是使用jsp表达式和使用el表达式来获取四大域对象中的属性的比较:
<!-- jap脚本片段 pageContent request session application -->
<%
pageContext.setAttribute("pageAttr", "pageValue");
request.setAttribute("requestAttr", "requestValue");
session.setAttribute("sessionAttr", "sessionValue");
application.setAttribute("appAttr","appValue");
%>
<hr/>
<!-- 使用jsp表示式来获取四大域对象中的属性 -->
<br/>
page:<%= pageContext.getAttribute("pageAttr") %><br/>
request:<%= request.getAttribute("requestAttr") %><br/>
session:<%= session.getAttribute("sessionAttr") %><br/>
application:<%= application.getAttribute("appAttr") %><br/>
<hr/>
<!--使用el表达式来获取四大域中的属性 -->
<br/>
<!-- -->
page:${ pageAttr}<br/>
request: ${ requestAttr}<br/>
session:${ sessionAttr}<br/>
application:${ appAttr}<br/>
下面是el表达式的用法:
- 在页面中显示域中的属性值的语法:
${属性名}
- 获取对象中的某个属性
${对象.属性名}
注意:其中的属性名就是对象的getName()中的name
-
el表达式如果直接获取属性域中的属性,直接写属性名,它会从四个域中从小到大找,找到就停止
-
el中的11个隐含对象
隐含对象 类型 说明 pageContext javax.servlet.jsp.PageContext 就是JSP页面上的pageContext pageScope java.util.Map<String,Object> page范围 requestScope java.util.Map<String,Object> request范围 sessionScope java.util.Map<String,Object> Session范围 applicationScope java.util.Map<String,Object> Web应用范围 param java.util.Map<String,String> 对应一个请求参数 paramValues java.util.Map<String,String[]> 对应一组请求参数 header java.util.Map<String,String> 请求头 headerValues java.util.Map<String,String[]> 请求头返回字符数组 cookie java.util.Map<String,Cookie> 获取某个cookie对象 initParam java.util.Map<String,String> 获取应用初始化参数 注意:
- el可以取出上面的11个隐含对象中的属性值,但是不能取出你在页面中(脚本片段)中定义的变量的值
- 用EL输出一个常量的话,字符串要加双引号,不然的话EL会默认把你认为的常量当做一个变量来处理
- 明确EL表达式只能通过内置对象取值,也就是只读操作,EL表达式仅仅是视图上的输出标签罢了
- 如果属性名中包含
-
等特殊字符(例如:User-Agent),el会将它当成减号,为了避免这样,就需要使用[],例如:${requestScope.['user-Name']}
或${requestScope.["user-Name"]}
,它相当于是取Map中的键所对应的值 - el取出域中的属性,如果没有,它会返回一个空,不是null
下面是例子:
<!-- jap脚本片段 pageContent request session application --> <% Student stu = new Student("小hong", 13); pageContext.setAttribute("stu", stu); request.setAttribute("stu-", stu); session.setAttribute("stu", "sessionValue"); application.setAttribute("stu","appValue"); %> <hr/> <!-- 使用jsp表示式来获取四大域对象中的属性 --> <br/> page:<%= ((Student)pageContext.getAttribute("stu")).getName() %><br/> request:<%= request.getAttribute("stu-") %><br/> session:<%= session.getAttribute("stu") %><br/> application:<%= application.getAttribute("stu") %><br/> <hr/> <!--使用el表达式来获取四大域中的属性 --> <br/> <!-- --> page:${ pageScope.stu.name}<br/> request: ${ requestScope['stu-']}<br/> session:${ sessionScope.stu}<br/> application:${ applicationScope.stu}<br/>
pageContext
el中的pageContext相当于jsp中的pageContext,它和jsp中的pageContext的作用一样,可以取出其他域中的对象。
下面是例子:
<!-- 使用el表达式中的pageContext隐含对象来获取其他的隐含对象中的数据 --> ${pageContext.request.scheme }<br/><!-- 相当于下面的jsp --> <%= pageContext.getRequest().getScheme() %>
param
它是el中和HTTP相关的5个隐含对象之一,它对应于jsp中的request.getParamer(“ ”)方法。param中封装了所有的请求参数的key-value键值对。
request.getParamer("userName");
${param.userName}
paramValues
和param一样,当请求携带的信息中的某个属性所对应的值有多个的时候就会使用到它。
header
它是el中和HTTP相关的5个隐含对象之一,对应于request.getHeader(“ ”)方法。
request.getHeader("User-Agent");
${header["User-Agent"]} ${header.Host}
headerValues
和header一样,当请求头中某个属性名所对应的属性值有多个的时候就会使用到它。它获取到的是一个数组 ,可以使用
[索引]
来获取其中的元素。${paramValues.hobby[0]}<br/>${paramValues.hobby[1]}
cookie
它是el中和HTTP相关的5个隐含对象之一,cookie是一个对象,
${cookie.JSESSIONID.name} ${cookie.JSESSIONID.value}
initParam
它是获取Web配置信息的,即web.xml文件中的参数。
假设你已经在Web.xml中配置了属性name和它的属性值:
${initParam.name}
7.3.2 el表达式运算符
- 算数运算
${5+6}
${6-2}
......
- 关系运算
${7>=0}
${6==0}
${6!=0}
......
- 逻辑运算
${true&&false}
......
- empty运算
empty用来判断对象是否为空。
<%
Student stu = new Student("小明", 12);
pageContext.setAttribute("stu", stu);
%>
${empty pageScope.stu}<br/>
下面这些情况下它会判断为空:
- 对象就是null
- 域中不存在这个对象
- 空集合、空字符串、空数组、空字符
注意:
在集合或数组中加入了一个null,这个集合或列表不为空
new一个数组用empty判断是false,因为这个对象被创建出来了
-
三目运算
${5>6 ? "a":"b"}
7.3.3 el补充
- 获取项目的虚拟路径
${pageContext.request.contextPath}
- 使用el表达式拼出base标签中的href属性
<%
pageContext.setAttribute("req",request);
%>
${req.scheme}://${req.serverName}:${req.serverPort }<br/>
<base href="${req.scheme}://${req.serverName}:${req.serverPort }/"/>
- 使用el实现表单回显
<b></b>
<%-- <% String str = (String)request.getAttribute("message"); %> --%>
<%-- <%= str==null ? "公共场所不建议自动登录,以防账号丢失":str%> --%>
${message==null?"公共场所不建议自动登录,以防账号丢失":message}
</div>
<p>
<input type="text" name="us_name" placeholder="用户名 6-10个字符" required="required"
<%-- <%String userName = request.getParameter("us_name"); %> --%>
<%-- value="<%= userName==null ? "": userName %>" --%>
value="${param.us_name}"
/>
</p>
7.4 JSTL
7.4.1 JSTL简介
JSP虽然为我么提供了El表达式,但是,El表达式仅仅具有输出功能,而不能代替页面中的JSP脚本片段。为了解决这个问题,JSP提供了可以自定义标签库(Tag Library)的功能。所谓的标签库就是可以在JSP页面中以类似于HTML标签的形式调用Java中的方法,使用方法和JSP动作标签类似,而为了方便使用,Sun公司定义了一套通用的标签库JSPL(JSP标准标签库),里面定义了很多我们开发中常用的方法,方便我们使用。
根据JSTL标签所提供的功能,可以将其分为5个类别。
- 核心标签
- 格式化标签
- SQL 标签
- XML 标签
- JSTL 函数
由于SQL标签库、XML标签库不常用,所以就不需要学习这两个标签库。
7.4.2 JSTL的使用
- 导入两个jar包:
taglibs-standard-impl-1.2.1
taglibs-standard-spec-1.2.1
-
在jsp中导入标签库
<%@ taglib prefix="c" uri="http://java.sun/jsp/jstl/core"%>
- prefix:定义标签的前缀
- uri:标签库的唯一标识符
7.4.2.1 核心标签库的使用(c标签库)
<c:out>
用于计算一个表达式,并将结果输出到当前页面,功能类似于JSP表达式<%= %>
和El表达式${ }
属性:
属性名 | 取值 | 作用 |
---|---|---|
value | Object | 设置要输出的值 |
default | Object | 当value为null时显示的默认值 |
escaXml | boolean | 是否对特殊字符进行转义,默认是true |
例子:
<%
pageContext.setAttribute("msg", "<h1>message</h1>");
%>
<c:out value="${msg}" default="null" escapeXml="true"></c:out>
你可以将escapeXml的值设置为false再看看有什么不一样。
<c:set>
用于添加或修改域中的属性
属性:
属性名 | 取值 | 作用 |
---|---|---|
value | Object | 要设置的值 |
var | String | 表示域中存放的属性名 |
scope | String | 要设置到的域 |
property | String | 目标对象的属性名 |
target | Object | 目标对象,可以是域中的对象,也可以是页面中的对象 |
使用set标签给域中设置属性的例子:
<c:set var="tip" scope="page" value="tipMassage" ></c:set>
${pageScope.tip}
使用set标签修改对象的某个属性值的例子:
<%
Student stu = new Student("Tom",13);
%>
<c:set property="name" value="apache" target="<%=stu %>" ></c:set>
<%=stu.getName() %>
<c:remove>
用于移除域中的属性
属性名 | 取值 | 作用 |
---|---|---|
scope | String | 目标域, |
var | String | 要移除的属性 |
注意:如果不指定域,会将所有域中的属性都移除
<c:set var="tip" scope="request" value="tipMassage" ></c:set>
未移除之前:${requestScope.tip}<br/>
<c:remove scope="request" var="tip"/>
移除之后:${requestScope.tip}<br/>
<c:if>
实现if功能
属性名 | 取值 | 作用 |
---|---|---|
test | el表达式或jsp代码片段 | 判断条件,如果是true,执行标签体中的内容 |
scope | String | 指定判断结果保存到那个域中 |
var | String | 指定属性名 |
<%
Student stu = new Student("Tom",13);
%>
<c:if test="${stu.name != null }" scope="page" var="flag">
<h1><%=stu.getName() %></h1>
</c:if>
${flag}
<c:choose>,<c:when>,<c:otherwise>
组合
<c:choose>
<c:when test="${23>1}">
<h1>23是大于1的</h1>
</c:when>
<c:when test="${23==1}">
<h1>23等于1</h1>
</c:when>
<c:otherwise>
<h1>23是小于1的</h1>
</c:otherwise>
</c:choose>
<c:forEach>
增强for循环,可以用来遍历一个列表、数组等
属性名 | 取值 | 作用 |
---|---|---|
begin | 指定遍历开始位置 | |
end | 指定遍历结束位置 | |
step | 指定步长 | |
items | 遍历目标 | |
var | 当前条目的变量名 | |
varStatus | 遍历状态 |
例子:
<c:forEach begin="0" end="10" var="num" step="2">
${num}
</c:forEach>
<%
List<Student> list = new ArrayList<Student>();
list.add(new Student("小红",1));
list.add(new Student("小面",2));
list.add(new Student("小跑",3));
list.add(new Student("小号",4));
list.add(new Student("小打",5));
%>
<table>
<tr>
<th>用户名</th>
<th>密码</th>
<tr/>
<c:forEach items="<%=list%>" var="people">
<tr>
<td>${people.name}</td>
<td>${people.age}</td>
</tr>
</c:forEach>
</table>
<c:url>
<c:url>
标签可以用来拼接url字符串:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:url value="https://www.baidu"></c:url>
</body>
</html>
执行后的结果:
上面使用url标签生成的是字符串,如果想要让它变成链接,需要配合html中的a标签使用:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="<c:url value="https://www.baidu"></c:url>">百度</a>
</body>
</html>
执行后的效果如下图,此时的url标签中的url字符串就变成了链接:
url标签更为常用的是配合标签库中的param标签和HTML中的a标签来拼接url:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="
<c:url value="https://www.baidu/s">
<c:param name="wd" value="javaWeb"></c:param>
</c:url>
">百度搜索javaWeb</a>
</body>
</html>
当然,如果将拼接成的字符串保存到域中,就可以实现url的复用:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:url value="https://www.baidu/s" var="baidu_search_javaWeb" scope="page">
<c:param name="wd" value="javaWeb"></c:param>
</c:url>
<a href="${pageScope.baidu_search_javaWeb}">百度搜索javaWeb</a>
</body>
</html>
<c:redirect>
用来重定向,当这个页面一打开,就会直接重定向到指定的页面
<c:if test="${msg}">
<c:redirect url="/error.jsp"></c:redirect>
</c:if>
7.4.2.2 JSTL函数库
函数库中定义了许多常用的函数,这些函数大多都是针对字符串的函数,例如:判断一个字符串中是否包含指定的字符串,判断字符串是否以指定的字符串开头或结尾等。
要使用函数库,需要在jsp中导入JSTL函数库:
<%@taglib prefix="fn" uri="http://java.sun/jsp/jstl/functions" %>
${fn:contains(String, subString)}
判断某个字符串中是否包含指定的字符串,区分大小写
<c:set var="str" value="string"></c:set>
<c:if test="${fn:contains(str,'str')}">
<h2>找到str</h1>
</c:if>
注意:el中不能包含el
${fn:containsIgnoreCase(String, SubString)}
判断某个字符串中是否包含指定的字符串,不区分大小写
<c:set var="str" value="String"></c:set>
<c:if test="${fn:containsIgnoreCase(str,'str')}">
<h2>找到str</h1>
</c:if>
${fn:endsWith()}
和${fn:startsWith()}
分别表示判断字符串是否以指定的字符串结尾或开始
<c:set var="str" value="string"></c:set>
<c:if test="${fn:startsWith(str,'str')}">
<h2>以str开始</h1>
</c:if>
<c:set var="str" value="string"></c:set>
<c:if test="${fn:endsWith(str,'ing')}">
<h2>以ing结尾</h1>
</c:if>
${fn:indexOf()}
返回指定字符串在输入字符串中出现的位置
<c:set var="str" value="string"></c:set>
${fn:indexOf(str,'ing')}
${fu:substring()}
按照提供的开始和结束索引从目标字符串中截取字符串,将截取的字符串返回
<c:set var="str" value="string"></c:set>
${fn:substring(str,0,2)}
注意:不包含结束索引
7.5 自定义标签
JSTL为我们提供了许多标签,但是,有时我们自己需要定义一些标签,这个时候就需要我们自己定义标签。
第一步:创建标签库的描述文件
标签库文件描述文件就是用来描述标签的,下面是remove标签的部分描述内容:
<tag>
<description>
Removes a scoped variable (from a particular scope, if specified).
</description>
<name>remove</name>
<tag-class>org.apache.taglibs.standard.tagmon.core.RemoveTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>
Name of the scoped variable to be removed.
</description>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<description>
Scope for var.
</description>
<name>scope</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
我们编写的标签库描述文件要放在WEB-INF文件夹下。可以直接放在WEB-INF文件夹下,但是,我们通常会在WEB-INF文件夹下新建一个名为tags的文件夹,然后将所有的标签库描述文件放在这个文件夹下。
下面是在Eclipse中创建一个标签描述文件的详细步骤:
在WEB-INF文件夹下新建一个名为tags的文件夹,在这个文件夹下new一个XML File:
输入文件名,要将文件的后缀名更改为tld,再点击“Next”:
选择“Create XML file from an XML schema file”后点击“Next”:
选择“Select XML Catalog entry”,在下面的列表中找到“http://xmlns.jsp./xml/ns/j2ee/web-jsptaglibrary_2_0.xsd
”,选中后点击”Next“:
在”Namespace Information“列表中选中”j2ee”这个条目,点击右边的“Edit”按钮:
在弹出的窗口中将“Prefix”中的内容清空,再点击“OK”:
点击”Finish“按钮完成标签库文件的创建:
第二步:编写标签描述文件
下面是标签文件编写的示例:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun/xml/ns/j2ee" xmlns:xml="http://www.w3/XML/1998/namespace" xmlns:xsi="http://www.w3/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun/xml/ns/j2ee http://xmlns.jcp/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd ">
<!-- 标签库的版本 -->
<tlib-version>0.0</tlib-version>
<!-- 指定当前标签库的标签前缀 -->
<short-name>jxd</short-name>
<!-- 标签库的唯一标识,不能重复 -->
<uri>jxd</uri>
<!-- 定义一个可以使用的标签 -->
<tag>
<!-- 定义标签名 -->
<name>hello</name>
<!-- 定义标签的实现类,必须写全类名 -->
<tag-class>com.jxd.tag.MyTag</tag-class>
<!-- 标签体,描述属于那种标签,有四种取值,常用的是empty,即空标签 -->
<body-content>empty</body-content>
<!-- 定义属性 -->
<attribute>
<!-- 指定属性名 -->
<name>message</name>
<!-- 设置这个属性是否是必须的 -->
<required>true</required>
<!-- 传入的el表达式是否解析 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
第三步:编写标签的实现类,实现doTag()方法
下面是对应于上面的标签描述文件的标签实现类:
注意:编写标签实现类要导入Tomcat的源码
package com.jxd.tag;
import java.io.IOException;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
public class MyTag implements SimpleTag {
private String message;
private PageContext pc;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
System.out.println("接受到的属性值:"+ message);
}
/**
* 执行标签功能
*/
@Override
public void doTag() throws JspException, IOException {
// TODO Auto-generated method stub
System.out.println("doTag-->HelloWord!");
pc.getOut().write("<h1>"+message+"</h1>");
}
/**
* 设置父标签,服务器自动设置
*/
@Override
public void setParent(JspTag parent) {
// TODO Auto-generated method stub
System.out.println("setJspParent-->");
}
/**
* 获取父标签
*/
@Override
public JspTag getParent() {
// TODO Auto-generated method stub
System.out.println("getParent()-->");
return null;
}
/**
* 设置JspContext(pageContext) 服务器自动传入
*/
@Override
public void setJspContext(JspContext pc) {
// TODO Auto-generated method stub
System.out.println("setJspContext-->");
System.out.println(pc);
this.pc = (PageContext) pc;
}
/**
* 设置JspBody标签体内容 服务器自动传入
*/
@Override
public void setJspBody(JspFragment jspBody) {
// TODO Auto-generated method stub
System.out.println("setJspBody-->");
}
}
好了,这个自定义的标签就实现了,它的功能是接收一个名为message的字符串,将这个字符串当做一级标题在页面中展示出来。
下面是在一个jsp页面中使用这个标签的例子:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<%@taglib prefix="jxd" uri="jxd" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jxd:hello message="你好 世界"/>
</body>
</html>
下面是这个jsp的运行结果:
第8章 cookie和session
8.1 cookie
8.1.1 cookie的介绍
8.1.2 cookie的使用
- 创建cookie
Cookie cookie = new Cookie("userName", "Tom");
response.addCookie(cookie);
Cookie cookie2 = new Cookie("pwd", "123456");
response.addCookie(cookie2);
- 获取cookie
将cookie创建并设置在response后,浏览器就会在本地保存这些cookie,并且,这些cookie会在浏览器请求应用时自动添加在request对象中,所以,我们使用request.getCookie()方法获取这些cookie:
protected void getCookie(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
response.getWriter().write("cookie的name值:"+name);
response.getWriter().write("cookie的value值:"+value);
}
}
- 删除cookie
我们可以通过设置cookie的最大存活时间来删除cookie,但是不同的浏览器对于删除cookie的方式是不一样的。
protected void delete(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getName();
if(name.equals("pwd")){
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
}
- 持久化cookie
我们也可以通过将cookie的最大存活时间设置为我们想要它存活的秒数来达到持久化cookie的效果:
protected void persistence(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getName();
if(name.equals("userName")){
cookie.setMaxAge(60*60);
response.addCookie(cookie);
}
}
}
- 设置cookie的路径
cookie创建并保存在浏览器后,默认访问项目下的所有的资源都会携带该cookie,此时,就需要我们为cookie设置路径,指定该cookie只有在访问该路径时才会携带该cookie:
//设置cookie的路径
protected void SetPath(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("MyCookie","CookiePath");
cookie.setPath("/cookie"); //这里的/代表的是服务器的根
response.addCookie(cookie);
}
8.2 session
8.2.1 session
session是在服务器端保存数据的技术,域对象在整个会话期间保存的数据都可以在任意资源都可以取到。
session是四大域对象之一。session在一次请求中共享数据,服务器会为每个不同的会话设置一个独立的不同的session对象,每一个session对象都有一个唯一的ID与之对应,可以通过session.getId()方法来获取一个session的ID。
session通过唯一不重复的JSESSIONID来识别是否是相同的会话。
8.2.2 session的使用
- 获取session
protected void getSession(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
boolean b = session.isNew(); //判断session是不是新创建的
response.getWriter().write("已经获取到session对象"+b);
}
- 设置session域中的键值对
protected void setSession(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("name", "jxd");
}
- 获取session域中的值
- 设置session的存活时间
session默认的存活时间是1800秒,也就是半个小时,在WEB.xml文件中有配置,下面是在web.xml文件中修改session的默认存活时间为30秒:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
下面是通过使用session对象的相关方法来设置session的存活时间:
protected void setSessionTime(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
int maxInactiveInterval = session.getMaxInactiveInterval();
session.setMaxInactiveInterval(60); //将时间设置为负数的话,代表session永不过期
response.getWriter().write(String.valueOf(maxInactiveInterval));
}
- 强制session失效
protected void delSession(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.invalidate();
response.getWriter().write("session已经强制立即失效!");
}
8.2.3 url重写
由于浏览器可以设置不使用cookie,即禁用cookie,这就会导致session完全失效,也就是即使是在同一个会话,每次请求网页获取的都是新的session,这个时候就需要使用url重写。
url重写会检查用户的浏览器是否禁用了cookie,如果用户未禁用cookie,它不会执行任何操作,如果用户禁用了cookie,它就会在请求的url后面加上jsessionid来重写url。
通过在url中带上jsessionid就可以找到之前的session:
http://localhost:8080/Examples/index.html;jsessionid=6F835FA690068D4590A46B6F1651E048
下面是例子:
index.jsp文件中的内容:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
session.setAttribute("sessionAttr", "sessionValue");
%>
<!-- url重写 -->
<%--
<%=
response.encodeRedirectURL(request.getContextPath()+ "/s.jsp")
%>
<a href="/s.jsp">去其他页面查看session中的数据</a>
--%>
<!-- jstl标签库来实现url重写 -->
<!-- value用于指定要重写哪个url -->
<c:url value="/s.jsp"></c:url>
<a href="<c:url value="/s.jsp"></c:url>">使用c:url去其他页面查看session中的数据</a>
</body>
</html>
s.jsp文件中的内容:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>${sessionAttr}</h1>
</body>
</html>
你可以在浏览器中分别查看在不禁用cookie和禁用cookie这两种情况下index.jsp文件中显示的路径。
8.2.4 session的活化和钝化
服务器关闭重新启动,只要服务器没关,还是能获取到session里面的值。只是因为在服务器关闭后,会将session保存进硬盘中,这称之为session的钝化;服务器再次启动时,就会再次加载保存在硬盘中的session,这称之为session的活化。
服务器关闭后,session会保存在项目的目录下的SESSION.ser这个文件中,这个文件是session序列化后的文件;当服务器再次启动后,服务器会将之前序列化的session加载。
但是,需要注意的是,在session中保存的对象如果没有实现serializable接口,在活化钝化后将会丢失该对象。所以,要保证session中保存的对象在session的钝化和活化不会丢失,该对象必须实现序列化接口serializable。
第9章
9.1 表单重复提交问题
产生表单重复提交的情况:
-
成功以后,直接刷新页面(每一次刷新就是重复上一次请求)
-
网络服务器性能或用户网络状况不佳导致处理请求缓慢,用户狂点提交
-
用户提交成功后点击后退,再次提交
解决办法:
解决第一种情况的办法就是使用重定向,用户提交完表单后,重定向到另一个页面中,此时,用户如果再次点击刷新页面,由于用户此时已经处于新的页面,此时点击刷新的作用就是重新请求这个新的页面,而不是重新提交表单。
解决第二种情况的办法就是将提交按钮设置为点击一次以后就不能再次点击了:
window.onload = function(){
var btn = document.getElementById("subId");
btn.onclick = function(){
//使按钮变灰,同时表单也不会提交
this.disabled = true;
//选择目标表单,通过表单对象的submit()方法将表单提交
var form = document.getElementByTagName("form")[0];
form.submit();
}
}
当然,也可以用重定向来解决第二种情况。
第三种方法解决比较困难,重定向也不能解决,因为用户回退到上一步是从浏览器的缓存中读取的。可以采用令牌机制,每次提交表单时带上立牌,服务器检测令牌是否合法,如果令牌合法才将表单中的数据提交到数据库,如果不合法,打回请求或不处理请求。
下面是通过使用token机制来处理用户回退到表单提交页面然后点击提交导致的表单重复提交问题:
login.jsp文件中的内容:
<%@page import="java.util.UUID"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String token = (String) UUID.randomUUID().toString();
session.setAttribute("token", token);
%>
<form action="LoginServlet">
<input name="token" type="hidden" value="<%= token %>"/>
<input name="userName" type="text" />
<input name="submit" type="submit" value="提交"/>
</form>
</body>
</html>
LoginServlet.java文件中的内容:
package com.jxd.Servlet;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String saverToken = (String) request.getSession().getAttribute("token");
//如果用户返回到提交页面,再次提交,将从服务器中的缓存中读取request
String userToken = (String) request.getParameter("token");
if(saverToken.equals(userToken)){
//重定向
request.getRequestDispatcher("/success.html").forward(request, response);
System.out.println("true");
}else{
request.getRequestDispatcher("/reSubmitError.html").forward(request, response);
}
System.out.println("SaverToken: "+saverToken);
System.out.println("useToken: "+userToken);
//将服务器中session域中的token设置为null
request.getSession().setAttribute("token", "null");
}
}
seccuess.html文件中的内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>登录成功!</h1>
</body>
</html>
reSubmitError.html文件中的内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>请不要重复提交!</h1>
</body>
</html>
上面就是使用token机制来避免用户回退到表单提交页面中重复提交表单的问题,这个token机制的原理是:
- 第一次,在表单页面生成一个token,将这个token放入session域和表单提交的隐藏提交信息中,将表单提交时,相应的servlet将检查session中的token和用户表单中携带的token是否相等,第一次它们一定是相等的,就处理请求,并将session中的token设置为字符串null
- 第二次,用户回退到表单提交页面,再次提交时,由于表单中的token隐藏信息还是从缓存中加载出来的,所以表单中的token还是和第一次是一样的,而session中的token已经被修改为了字符串null,所以它们两个肯定不相等,将页面重定向到提示用户不要重复提交表单的页面
9.2 Filter
如果用户登录后,将一些登录后才能看到的网页的地址复制粘贴访问,也可以看见登录后才能看见的网页。我们可以在要登录才能看见的每一个页面中添加一个检测用户是否已经登录的步骤,如果用户没有登录,转发到登录页面,如果用户登录了,才显示页面。但是,这样就太麻烦了,这就相当于在学校的每一个教室门口检查身份,这个时候就需要使用Filter了,它相当于在学习门口检查身份。
Filter是用来执行过滤任务的一个对象,作用于请求一个动态或静态资源,它还作用于来自一个资源的响应。也就是说:Filter是用来过滤请求和响应
Filter可以拦截请求,可以修改请求头,请求内容;Filter也可以拦截来自服务器的响应,可以修改响应头和响应内容。
9.2.1 Filter的创建
-
创建一个Filter接口的实现类
-
在web.xml中配置Filter或使用注解的方式配置Filter
<!-- filter配置信息 --> <!-- 配置filter的类信息 --> <filter> <!-- filter的别名--> <filter-name>Filter1</filter-name> <!-- filter的全类名 --> <filter-class>com.jxd.Filter1</filter-class> </filter> <!-- 配置filter的映射信息 --> <filter-mapping> <filter-name>Filter1</filter-name> <!-- 过滤访问请求 --> <!-- 表示所以访问hello.jsp的请求都要经过这个Filter --> <url-pattern>/hello.jsp</url-pattern> </filter-mapping>
9.2.2 Filter的声明周期
- 服务器一启动,也就是项目一加载进服务器中就会创建Filter对象,然后初始化Filter
- 以后每一次拦截都执行doFilter()方法
- 项目从服务器中移除就会销毁Filter
9.2.3 Filter-urlpatter配置
- 精确匹配
拦截在url-pattern中写的详细路径所对应的资源:
<url-pattern>/a.jsp</url-pattern>
<url-pattern>/page/a.jsp</url-pattern>
- 路径匹配
拦截所有访问路径下的资源
<url-pattern>/page/*</url-pattern>
- 后缀匹配
拦截所有以给定后缀的结尾的资源:
<url-pattern>*.jsp</url-pattern>
注意:如果web.xml中的这些配置有错误,会导致Tomcat不能正常启动!
9.2.4 通过request来拦截部分请求
虽然我们可以利用filter中的配置来拦截我们想要拦截的请求,但这还不够灵活,我们可以利用request来拦截部分请求,将ServletRequest强转为HttpServletRequest后就可以调用更多关于Request的信息的方法。
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String uri = req.getRequestURI();
System.out.println("uri: "+uri);
//拦截page目录下的所有.jsp文件
if(uri.endsWith(".jsp")){
System.out.println("以jsp结尾");
}else {
chain.doFilter(request, response);
}
}
9.2.5 filter放行之前的乱码问题
在请求放行之前,使用response输出内容,内容追加到页面上了,但是页面中的中文都乱码了,但是在放行之后,中文不是乱码。
下面的中文不会乱码:
doFilter()方法中:
chain.doFilter(request, response);
response.getWriter().writer("你好");
在操作response之前放行或设置response的编码就可以解决这个问题。
9.2.6 FilterConfig
filter中的chain就是用来放行请求,如果不执行chain.doFilter(request, response);
就不会放行。
Filter中的init方法接收一个FilterConfig对象,该对象中包含了Filter的配置信息。
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.jxd.filter.filter1</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
下面是FilterConfig对象的常用方法:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//从FilterConfig对象中获取Filter的配置信息
//获取filter的别名
String filterName = filterConfig.getFilterName();
//获取filter的初始化配置信息
String usernameParameter = filterConfig.getInitParameter("username");
//获取servletContext对象(对应于我们的web应用)
ServletContext servletContext = filterConfig.getServletContext();
//获取web初始化参数
servletContext.getInitParameter("name");
}
9.2.7 Filter链
9.2.8 dispatcher配置
为了防止通过页面转发绕过Filter拦截,我们需要在Filter的配置中添加dispatcher这个配置项:
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.jxd.Filter1</filter-class>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-name>/page/*</url-name>
</filter-mapping>
- FORWARE:拦截转发过来的
- INCLUDE:拦截包含的
- REQUEST:拦截直接请求的,这个是默认的
- ERROR:拦截发生错误的,这个错误指的是web.xml中的
<error-page>
和<error-code>
中指定的全局错误,而不是errorPage中指定的页面地址
9.2.9 Filter在web应用中的使用
- 会员用户不过睡眠Servlet,非会员用户就要过Servlet
- 解决中文乱码问题,即每次请求和返回都要设置编码
同步日期:2021.8.13
更多推荐
Java_web笔记: 含html、css、js、servlet、jsp
发布评论