HTML全称:Hyper Text Markup Language(超文本标记语言)
超文本:超出文本范围内的内容,声音,图片,视频,falsh动画。。。。
标记:标签,如果你想告诉浏览器对于某些特殊的字段显示出特定的效果,那么你就需要使用预先定义好效果的标签来标记你所需要显示特殊效果的文本
语言:脚本语言,他的作用对象不是操作系统,而是浏览器,如果你想让浏览器显示一些内容,那么你就需要用html语言来告诉浏览器
xml:可扩展标记语言
我们学习html就是学习预先定义好效果的那些的标签
超文本标记语言是标准通用标记语言(SGML)下的一个应用,也是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分。
HTML是一门用户创建网页文档的标记语言,网页文件本身是一种文本文件,通过在文本文件中添加标记符。
HTML可以告诉浏览器如何显示其中的内容(如:文字如何处理,画面如何安排,图片如何显示、包括音频、视频等等如何播放)。
简单一句话:HTML是一门用来创建网页的标记语言。
HTML特点
其主要特点如下:
1 简易性:超文本标记语言版本升级采用超集方式,从而更加灵活方便。
2 可扩展性:超文本标记语言采取子类元素的方式,为系统扩展带来保证。
3 平台无关性:超文本标记语言可以使用在广泛的平台上,这也是万维网(www)盛行的另一个原因。
4 通用性:HTML是网络的通用语言,一种简单、通用的标记语言。
HTML的发展
超文本标记语言(第一版)——在1993年6月作为互联网工程工作小组(IETF)工作草案发布(并非标准)
HTML 2.0——1995年11月作为RFC 1866发布,在RFC 2854于2000年6月发布之后被宣布已经过时
HTML 3.2——1997年1月14日,W3C推荐标准
HTML 4.0——1997年12月18日,W3C推荐标准
HTML 4.01(微小改进)——1999年12月24日,W3C推荐标准
W3C : XHTML1.0 -> XHTML1.1 -> XHTML2.0
WHATWG:HTML 5
HTML 5——2014年10月29日,W3C推荐标准
HTML基本结构
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">meta>
<title>第一页面title>
head>
<body>
页面内容
body>
html>
注释 快捷键是 Ctrl+/
<meta charset ="UTF-8"> //这些在网页上不显示,源代码可看到
<meta name = "keywords" content = "西部开源">
<title>我的网页title>
生成一对标签 快捷键是 写一个标签后 +tab键
1.HTML页面包含头部head和主体body
2.HTML标签通常是成对出现的,有开始就有结束,这样的标签称为成对标签、没有结束标签称为空标签。
3.HTML通常都有属性,格式:属性名=“属性值”(多个属性之间空格隔开)
4.HTML标签不区分大小写,建议小写
5.文件名后缀为.html或.htm
<html><html>:根标签
<head>:头标签
<title>title>:页面的标题
head>
<body>body>:主体标签:网页内容
1.注释标签:
2.换行标签:<br/>
3.段落标签:<p>文本文字p>
特点:段与段之间有行高
属性:align对齐方式 (left:左对齐 center:居中 right:右对齐)
4.水平线标签:<hr/>
属性:
width:水平线的长度(两种:第一种:像素表示;第二种,百分比表示) size: 水平线的粗细 (像素表示,例如:10px)
color:水平线的颜色
align:水平线的对齐方式(left:左对齐 center:居中 right:右对齐)
<h1>h1>—-<h6>h6>
随着数字增大文字逐渐变小,字体是加粗的,内置字号,默认占据一行;
字体样式
粗体:<strong>i like itstrong>
斜体:<em>i like item>
:块级标签,独占一行,换行
:行级标签,所有内容都在同一行
作用: :主要是结合css页面分块布局
:进行友好提示信息
1.2.5.1 无序列表
ul (unorder list)
无序列表标签:
属性:type :三个值,分别为
circle(空心圆) ,disc(默认,实心圆),square(黑色方块)
列表项:
示例如下:
无序列表
- 苹果
- 香蕉
- 橘子
1.2.5.2 有序列表
ol(order list)
有序列表标签:
属性:type:1、A、a、I、i(数字、字母、罗马数字)
列表项:
示例如下:
有序列表
- 苹果
- 香蕉
- 橘子
1.2.5.3 定义列表
dl (defination list) 定义列表
dt (defination title) 定义标题
dd (defination description) 定义描述
定义列表
- 苹果
- 苹果是一种水果,富含维生素C,美容养颜,吃了长寿....
1.2.5.4 列表嵌套
<ul>
<li>咖啡li>
<li>茶
<ul>
<li>红茶li>
<li>绿茶
<ul>
<li>中国茶li>
<li>非洲茶li>
ul>
li>
ul>
li>
<li>牛奶li>
ul>
独立标签
属性:
src:图片地址: 相对路径 (同一个网站) 绝对路径 (不同网站)
width:宽度
height:高度
border:边框
align:对齐方式,代表图片与相邻的文本的相当位置(有三个属性值:top middle bottom)
alt:图片的文字说明
title:图片的悬停显示
超链接可以是文本,也可以是一幅图像,您可以点击这些内容来跳转到新的文档或者当前文档中的某个部分。
文本或图片
属性:
href:跳转页面的地址(跳转到外网需要添加协议)
target:_self(自己) _blank(新页面,之前页面存在) _parent _top 默认_self
_search相等于给页面起一个名字,如果再次打开时,如果页面存在,则不再打开新的页面。可以是任意名字。
name:名称,锚点(回到锚点: 顶部,底部,中间),在访问锚点的书写格式:#name的值
表格由
标签来定义。每个表格均有若干行(由 标签定义),每行被分割为若干单元格(由标签定义)。数据单元格可以包含文本、图片、列表、段落、表单、水平线、表格等等。 |
(table,tr,td)
<table border="1" bordercolor="red" cellspacing="0" align="center" width="200" height="100">
<tr>
<td>学号td>
<td>姓名td>
tr>
<tr>
<td>1td>
<td>aatd>
tr>
table>
(th)
<table border="1" bordercolor="red" cellspacing="0" align="center">
<caption>学生表caption>
<tr>
<th>学号th>
<th>姓名th>
tr>
<tr>
<td>1td>
<td>aatd>
tr>
table>
colspan 属性
<table border="1" bordercolor="red" cellspacing="0" align="center">
<tr>
<td colspan="4" align="center">学生表td>
tr>
<tr>
<td>学号td>
<td>姓名td>
<td colspan="2">各科成绩td>
tr>
<tr>
<td>1td>
<td>aatd>
<td>80td>
<td>90td>
tr>
table>
rowspan属性
<table border="1" bordercolor="red" cellspacing="0" align="center">
<tr>
<td colspan="4" align="center">学生表td>
tr>
<tr>
<td>学号td>
<td>姓名td>
<td>语文成绩td>
<td>数学成绩td>
tr>
<tr>
<td rowspan="2">1td>
<td rowspan="2">aatd>
<td>80td>
<td>90td>
tr>
<tr>
<td>80td>
<td>90td>
tr>
table>
定义粗体文本。
定义大号字。
定义着重文字。
定义斜体字。
定义小号字。
定义加重语气。
定义下标字。
定义上标字。
定义下划线。
定义删除字。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书网title>
head>
<body>
<table width="100%">
<tr>
<td>千锋教育-稀有的坚持面授的品质的大型IT培训td>
<td align="right">好程序员训练营 扣丁学堂 联系我们 加入收藏td>
tr>
<tr>
<td><img src="pic\new_logo.png">td>
<td align="right"><img src="pic\nav_r_ico.png">td>
tr>
table>
<hr/>
<p align="center">
<span> 首页 span><span> 课程培训 span><span> 教学保障 span>
<span> 免费视频 span><span> 公开课 span><span> 企业合作 span>
<span> 免就业喜报 span><span> 学员天地 span><span> 关于千锋 span>
<span> 学员论坛 span>
p>
<hr/>
<p align="right">
首页>课程培训>JavaEE列表 p>
<h1>课程培训h1>
<h3>共计xxxx中课程体系h3>
<hr/>
<img src="pic\综合案例素材\001.png" width="100%" />
<table width="100%">
<tr>
<td>
<img src="pic\综合案例素材\002.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\003.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\004.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\005.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\006.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
tr>
<tr>
<td>
<img src="pic\综合案例素材\007.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\008.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\009.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\010.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
<td>
<img src="pic\综合案例素材\011.png">
<p align="center">售价:XXXp>
<p align="center">书名:XXXXp>
td>
tr>
table>
<img src="pic\综合案例素材\012.png" width="100%">
body>
html>
HTML表单用于收集不同类型的用户输入
常用属性:action:表示动作,值为服务器的地址,把表单的数据提交到该地址上处理
method:请求方式:get 和post
enctype:表示是表单提交的类型
默认值:application/x-www-form-urlencoded 普通表单
multipart/form-data 多部分表单(一般用于文件上传)
text/plain 普通文本
get:
1.数据存在地址栏中,请求参数都在地址后拼接 path?name="张三"&password="123456"
2.不安全
3.效率高
4.get请求大小有限制,不同浏览器有不同,但是大约是2KB
使用情况:一般情况用于查询数据。
post:
1.地址栏没有数据:请求参数单独处理。
2.安全可靠
3.效率低
4.post请求大小理论上无限。
使用情况:一般用于插入修改等操作
type: 以下为type可能要取的值:
1.1 text 文本框 输入内容
1.2 password 密码框 密文或者掩码
1.3 radio 表示是单选,name必须一致;value:提交给服务器的数据
表示同一组中只能选中一个( checked ="checked" 表示选中)
1.4 checkbox 表示多选 ,name必须一致,
表示同一组中可以选多个,返回值是个数组( checked ="checked" 表示选中)
1.5 file :表示上传控件
以上具有输入性质的必须要有name属性,初始开始写value表示是默认值(以后获取输入框的内容要根据name来取)
以下按钮不具有输入性质,不需要name属性,但是按钮上的文字提示使用value属性
1.6 submit 提交
1.7 reset 重置
1.9 image 图片提交按钮
1.10 button 普通按钮
1.11 hidden 表示隐藏域,该框的内容服务器需要,但是不想让用户知道(不想清楚的显示在界面上)
1.12 email 表示邮箱格式的数据
name属性:表单元素名字,只有name属性才能提交给服务器。
value属性:提交给服务器的数据
placeholder:提示信息
(下拉列表)
<select name="city">
<option value="北京">北京option>
<option value="上海" selected="selected">上海option>
<option value="广州">广州option>
<option value="杭州">杭州option>
select>
(文本域)
需要指定输入的区域位置大小
效果图代码如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Documenttitle>
head>
<body>
<form action="#" method="get" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="id" value="1">
用户名:<input type="text" name="username1"><br/>
密码:<input type="password" name="password"><br/>
性别:男:<input type="radio" name="sex" value="1">
女:<input type="radio" name="sex" value="0"><br/>
爱好:足球:<input type="checkbox" name="habbit" value="football">
篮球:<input type="checkbox" name="habbit" value="basketball">
sing:<input type="checkbox" name="habbit" value="sing" checked="checked">
dance:<input type="checkbox" name="habbit" value="dance">
<br/>
邮箱:<input type="email" name="email" >
生日:<input type="date" name="birthday"><br/>
地址:<select name="address">
<option value="3401">合肥option>
<option>南京option>
<option selected="selected">北京option>
<option>上海option>
select>
<br/>
照片:<input type="file" name="photo"><br/>
自我介绍:<textarea name="introduce" cols="30" rows="10">textarea>
textarea><br/>
<input type="image" src="img\sub.jpg">
<input type="reset" value="重置">
form>
body>
html>
通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。每份HTML文档称为一个框架,并且每个框架都独立于其他的框架。
使用框架的缺点:
开发人员必须同时跟踪更多的HTML文档
很难打印整张页面
1.5.1 frameset
框架结构标签,把body删掉,使用framset代替body
框架结构标签(
实例1
<frameset rows="20%,*">
<frame name="frame1" src="top.html">
<frame name="frame2" src="bottom.html" />
frameset>
实例2
<frameset cols="20%,*">
<frame name="frame1" src="left.html" />
<frame name="frame2" src="right.html" />
frameset>
1.5.2 frame
框架标签
frame 标签定义了放置在每个框架中的 HTML 文档。
1.5.3 基本的注意事项
1. 不能将 标签与 标签同时使用
2. 假如一个框架有可见边框,用户可以拖动边框来改变它的大小。为了避免这种情况发生,可以在 标签中加入:noresize="noresize
3 frameset的属性 frameborder="1|0|yes|no" 表示是否有边框 border="1" 表示边框的粗细 bordercolor表示边框颜色
1.5.4 效果图及源代码示例
源代码示例:
top.html
HTML的框架标签
left.html
千锋官网
JAVA官网
JAVA在线
right.html
Title
正文内容
content.html
<frameset rows="200,*" border="10px" bordercolor="yellow">
<frame src="top.html" scrolling="yes" noresize="noresize" />
<frameset cols="200,*">
<frame src="left.html" scrolling="yes" noresize="noresize" />
<frame src="right.html" name="content" scrolling="yes" />
frameset>
frameset>
1.6.1 其它标签
< 小于号
> 大于号
& 与字符
" 引号
® 己注册
© 版权
™ 商标
空格
效果图如下:
1.html就是超文本标记语言,他所有的标签都是和浏览器定义好了
2.a标签,页面跳转的标签,他会主动将href的值放在地址栏,他的请求方式是get
3.table:表格标签,tr td th
4.表单标签:form,他的每一个元素,每一个属性的取值都要去试
CSS :层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。
多个样式可以层层覆盖叠加,如果不同的css样式对同一html标签进行修饰,样式有冲突的,应用优先级高的,不冲突的样式规则共同作用。
结构层:HTML:他是用来将内容显示在网页
样式层:CSS:用来控制内容如何显示?,在哪里显示?
行为层:JavaScript:内容添加一些动态效果
CSS作用:
1. 修饰美化html网页。
2. 外部样式表可以提高代码复用性从而提高工作效率。
3. html内容与样式表现分离,便于后期维护。
1 丰富的样式定义
CSS提供了丰富的文档样式外观,以及设置文本和背景属性的能力;允许为任何元素创建边框,以及元素边框与其他元素间的距离,以及元素边框与元素内容间的距离;允许随意改变文本的大小写方式、修饰方式以及其他页面效果。
2 易于使用和修改
CSS可以将样式定义在HTML元素的style属性中,也可以将其定义在HTML文档的header部分,也可以将样式声明在一个专门的CSS文件中,以供HTML页面引用。总之,CSS样式表可以将所有的样式声明统一存放,进行统一管理。
另外,可以将相同样式的元素进行归类,使用同一个样式进行定义,也可以将某个样式应用到所有同名的HTML标签中,也可以将一个CSS样式指定到某个页面元素中。如果要修改样式,我们只需要在样式列表中找到相应的样式声明进行修改。
3 多页面应用
CSS样式表可以单独存放在一个CSS文件中,这样我们就可以在多个页面中使用同一个CSS样式表。CSS样式表理论上不属于任何页面文件,在任何页面文件中都可以将其引用。这样就可以实现多个页面风格的统一。
4 层叠
简单的说,层叠就是对一个元素多次设置同一个样式,这将使用最后一次设置的属性值。例如对一个站点中的多个页面使用了同一套CSS样式表,而某些页面中的某些元素想使用其他样式,就可以针对这些样式单独定义一个样式表应用到页面中。这些后来定义的样式将对前面的样式设置进行重写,在浏览器中看到的将是最后面设置的样式效果。
5 页面压缩
在使用HTML定义页面效果的网站中,往往需要大量或重复的表格和font元素形成各种规格的文字样式,这样做的后果就是会产生大量的HTML标签,从而使页面文件的大小增加。而将样式的声明单独放到CSS样式表中,可以大大的减小页面的体积,这样在加载页面时使用的时间也会大大的减少。另外,CSS样式表的复用更大程序的缩减了页面的体积,减少下载的时间
CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明.
1. 选择器通常是您需要改变样式的 HTML 元素。
2. 每条声明由一个属性和一个值组成。
基础语法:选择器{属性:值;属性:值…… }
提示:请使用花括号来包围声明。
CSS书写方式有两种:
第一种:选择器、每个声明各占一行
第二种:选择器声明都在一行
2.注意事项:
a.如果值为若干单词,则要给值加引号;font-family: "黑体","华文彩云","微软雅黑","arial";
b.多个声明之间使用分号;分开;
c.css对大小不敏感,如果涉及到与html文档一起使用时,class与id名称对大小写敏感
d.css注释/*...*/
把CSS样式嵌入到html标签当中,类似属性的用法,示例如下:
This is my HTML page.
好处:可以单独设置某个元素样式,缺点:不利于样式重用,代码耦合度太高
在head标签中使用style标签引入css,示例如下:
好处:可以控制页面中多个元素样式,缺点:只能一个页面使用
将css样式抽成一个单独文件,谁用谁就引用,好处:多个页面可以同时使用。
示例如下:
单独文件div.css:
内容示例:div{color:green;font-size:50px}
引用语句写在head标签内部,
链接式:
rel:代表当前页面与href所指定文档的关系
type:文件类型,告诉浏览器使用css解析器去解析
href:css文件地址
导入式:
该内容放在head标签中
备注:link和@import区别:
1.link所有浏览器都支持,@import某些版本低的IE不支持
2.@import是等待html加载完成才加载,link解析到这个语句,就加载
3.@import不支持js动态修改
优先级:内联样式>内部样式>外部样式,就近原则。
注意:内部样式和外部样式的位置
主要用于选择需要添加样式的html元素
在head中使用style标签引入在其中声明标签选择器:
html标签{属性:属性值},
具体示例如下:
给需要修改样式的html元素添加id属性标识,在head中使用style标签引入在其中声明id选择器: #id值{属性:属性值}
具体示例如下:
创建id选择器:id不能有重复
hello,everyone!
hello,everyone!
hello,everyone!
根据id选择器进行html文件修饰
给需要修改样式的html元素添加class属性标识,在head中使用style标签引入在其中声明class选择器: .class名{属性:属性值},具体示例如下:
创建class选择器:
hello,everyone!
hello,everyone!
hello,everyone!
根据id选择器进行html文件修饰
备注:以上基本选择器的优先级从高到低:id >class >标签
根据元素的属性及属性值来选择元素。在head中使用style标签引入其中声明,
格式为:html标签[属性='属性值']{css属性:css属性值;}
或者html标签[属性]{css属性:css属性值;},
具体示例如下:
body内容:
head中书写:
主要是针对a标签
语法:
静止状态 a:link{css属性}
悬浮状态 a:hover{css属性}
触发状态 a:active{css属性}
完成状态 a:visited{css属性}
具体示例如下:
点我吧
父级选择器,子级选择器….,具体示例如下:
后代选择器
div p{…} 表示div中的p标签,所有的p,后代
div span{…} 表示div中的span标签,包括所有的span,后代
子代选择器
div>span{…} 表示 div中有一个span, span是子代
相邻兄弟 +
通用兄弟 ~
<div id="div1">
<div class="div11">
<span>span1-1span>
div>
<div class="div12">
<span>span1-2span>
div>
div>
<div class="div2">
<div id="div22">
<span>span2-1span>
div>
<div id="div23">
<span>span2-2span>
div>
div>
<style type="text/css">
#div1 .div11{color:red;}
#div1 .div12{color:purple;}
.div2 #div22{color:green;}
.div2 #div23{color:blue;}
style>
文字属性
1>.font-size:设置字体大小
2>.font-family:设置文字的字体,常见的值为 :黑体,宋体,楷体等
3>.font-style:规定斜体字,常见的值:
normal - 文本正常显示
italic - 文本斜体显示 字体斜体
oblique - 文本倾斜显示 变形斜体
4>.font-weight 属性设置文本的粗细。关键字 100 ~ 900 为字体指定了 9 级加粗度。
100 对应最细的字体变形,900 对应最粗的字体变形。
数字 400 等价于 normal,而 700 等价于 bold。
备注:
斜体(italic)是对每个字母的结构有一些小改动,来反映变化的外观。
倾斜(oblique)文本则是正常竖直文本的一个倾斜版本。
通常情况下,italic 和 oblique 文本在 web 浏览器中看上去完全一样
简写:
font: italic bold 30px "幼圆","黑体"; /*style weight size family swsf*/
文本属性
1>.color:设置文本颜色
2>.text-indent:缩进元素中文本的首行,取值类型如下:
1》text-indent:5em;表示此段落第一行缩进5个字符的宽度
2》text-indent:20%:表示此段落第一行缩进父容器宽度的百分之二十
3>.text-decoration:
none:会关闭原本应用到一个元素上的所有装饰
underline: 添加下划线
overline:在文本的顶端画一个上划线
line-through:在文本中间画一个贯穿线
blink:让文本闪烁(无效果)
4>.text-align:一个元素中的文本行互相之间的对齐方式,值有left(左对齐)、right(右对齐) 和 center(居中)
5>.word-spacing: 字符之间的间隔
6>.letter-spacing: 单词或者字母之间的间隔
7>.line-height:设置行高 line-height:25px;
1>.background-color:设置背景颜色,默认透明
2>.background-image:url("图片路径"):设置背景图片
3>.background-repeat:repeat-y:只在垂直方向都平铺
repeat-x:只在水平方向都平铺
repeat:在水平垂直方向都平铺
no-repeat:任何方向都不平铺
4>.background-position: 改变图像在背景中的位置。top、bottom、left、right 和 center
5>/指定图片和滚动条之间的关系
fixed:背景固定在窗口上,和滚动条无关
scroll:随着滚动条滚动而滚动
background-attachment: scroll;
/*简写 没有顺序*/
background: red center no-repeat url(img/003.jpg);
list-style-type:decimal;改变列表的标志类型
list-style-image: url("images/dog.gif");用图像表示标志
list-style-position: inside;确定标志出现在列表项内容之外还是内容内部
简写
list-style: decimal url(img/001.png) inside;
去掉样式:
list-style:none;
list-style-type:none;
width:设置元素的宽度
height:设置元素的高度
显示属性(display)
display: none 不显示
block:块级显示
inline:行级显示
inline-block:行级块
轮廓(outline)
绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。常用属性:
outline-style:solid(实线)/dotted(虚线)/dashed(虚线,虚线的每段较长)/double(框为空心);设置轮廓的样outline-color:red;设置轮廓的颜色
outline-width:10px设置轮廓的宽度
浮动(float)的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在标准文档流中,所以文档的普通流中的块框表现得就像浮动框不存在一样。
请看下图,当把框 1 向右浮动时,它脱离文档流并且向右移动,直到它的右边缘碰到包含框的右边缘:
再请看下图,当框 1 向左浮动时,它脱离文档流并且向左移动,直到它的左边缘碰到包含框的左边缘。因为它不再处于文档流中,所以它不占据空间,实际上覆盖住了框 2,使框 2 从视图中消失。
如果把所有三个框都向左移动,那么框 1 向左浮动直到碰到包含框,另外两个框向左浮动直到碰到前一个浮动框。
如下图所示,如果包含框太窄,无法容纳水平排列的三个浮动元素,那么其它浮动块向下移动,直到有足够的空间。如果浮动元素的高度不同,那么当它们向下移动时可能被其它浮动元素“卡住”:
clear 属性
规定元素的哪一侧不允许其他浮动元素。
可能的值
值 | 描述 |
---|---|
left | 在左侧不允许浮动元素。 |
right | 在右侧不允许浮动元素。 |
both | 在左右两侧均不允许浮动元素。 |
none | 默认值。允许浮动元素出现在两侧。 |
inherit | 规定应该从父元素继承 clear 属性的值。 |
postion: relative| absolute| fixed
相对于原来的位置偏移某个距离。元素仍保持其未定位前的形状,它原本所占的空间仍保留。
示例代码:
<html>
<head>
<style type="text/css">
h2.pos_left {
position: relative;
left: -20px
}
h2.pos_right {
position: relative;
left: 20px
}
style>
head>
<body>
<h2>这是位于正常位置的标题h2>
<h2 class="pos_left">这个标题相对于其正常位置向左移动h2>
<h2 class="pos_right">这个标题相对于其正常位置向右移动h2>
<p>相对定位会按照元素的原始位置对该元素进行移动。p>
<p>样式 "left:-20px" 从元素的原始左侧位置减去 20 像素。p>
<p>样式 "left:20px" 向元素的原始左侧位置增加 20 像素。p>
body>
html>
元素框从文档流完全删除,并相对于其包含块定位。包含块可能是文档中的另一个元素或者是视窗本身。元素原先在正常文档流中所占的空间会关闭,就好像元素原来不存在一样。元素定位后生成一个块级框,而不论原来它在正常流中生成何种类型的框。
绝对定位的元素的位置相对于最近的已定位祖先元素,如果元素没有已定位的祖先元素,那么它的位置相对于视窗本身。
<html>
<head>
<meta charset="utf-8" />
<style type="text/css">
h2.pos_abs {
position: absolute;
left: 100px;
top: 150px
}
style>
head>
<body>
<h2 class="pos_abs">这是带有绝对定位的标题h2>
<p>通过绝对定位,元素可以放置到页面上的任何位置。下面的标题距离页面左侧 100px,距离页面顶部 150px。p>
body>
html>
元素框的表现类似于将 position 设置为 absolute,不过其位置相对于视窗本身。
示例如下(网站左下角和右下角广告):
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title>
<style>
#left {
width: 200px;
height: 200px;
background-color: red;
position: fixed;
left: 0;
bottom: 0;
}
#right {
width: 200px;
height: 200px;
background-color: green;
position: fixed;
right: 0;
bottom: 0;
}
#middle{
width: 200px;
height: 200px;
background-color: blue;
position: fixed;
left: 0;
bottom: 50%;
}
style>
head>
<body>
<div id="left">
div>
<div id="right">
div>
<div id="middle">
div>
body>
html>
border-style:边框样式,值有以下情况:
solid:实线
double:空心线
dashed:虚线组成的边框
dotted:圆点组成的边框
border-color:边框颜色
border-width:边框宽度
简写
border: 1px solid red;
margin:外间距,边框和边框外层的元素的距离
margin:四个方向的距离(top right bottom left)
margin-top:
margin-bottom:
margin-left:
margin-right:
padding:内间距,元素内容和边框之间的距离((top right bottom left))
padding-left:
padding-right:
padding-top:
padding-bottom:
盒子模型的实际的宽度:width+2*(padding+border+margin)
盒子模型的实际的高度:height+2*(padding+border+margin)
ie6以下
width+2*(border+margin)
圆角属性
示例: border-radius: 25px;
用于向方框添加阴影
示例:box-shadow: 10px 10px 5px #888888;
属性规定背景图片的尺寸
<body style="text-align: center;
background:url(img/1.png);
background-size: 200px 300px;
background-repeat: no-repeat;">
body>
为指定元素使用多个背景图像
可向文本应用阴影。
示例:text-shadow: 5px 5px 5px #ffff00;
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>综合练习title>
<style type="text/css">
body {
font-size: 12px;
}
#main {
width: 1000px;
margin: 0 auto;
}
#top {
width: 980px;
height: 200px;
padding-left: 10px;
padding-right: 10px;
margin: 0 auto;
/* background-color: #87CEEB;*/
}
a {
color: black;
text-decoration: none;
}
a:hover {
color: #333;
text-decoration: underline;
}
#a1 {
color: #F65626;
}
#searchtext{
width: 500px;
border-radius: 10px;
border: 1px solid #888888;
height: 25px;
vertical-align: top;
}
#searchbtn{
background-color: #FF8C00;
border-radius: 10px;
height: 28px;
width: 100px;
display: inline-block;
vertical-align: top;
line-height: 28px;
text-align: center;
}
.price{
text-align: center;
color: #F65626;
}
style>
head>
<body>
<div id="top">
<div style="background-color: #aaa; height: 35px; border-radius: 10px; line-height: 35px;">
<div style="float: left; text-indent: 2em;">
<a href="#" id="a1">亲,请登录a>
<a href="#">免费注册a>
<a href="#">手机狂淘宝a>
div>
<div style="float: right; margin-right: 10px;">
<a href="#" id="a1">淘宝网首页a>
<a href="#">我的淘宝a>
<a href="#">购物车a>
<a href="#">收藏夹a>
<a href="#">商品分类a>
<a href="#">卖家中心a>
<a href="#">联系客服a>
<a href="#">网站导航a>
div>
div>
<div style="overflow: hidden;">
<div style="float: left;">
<img src="img/logo.bmp" />
div>
<div style="float: left; padding-top: 30px;">
<input id="searchtext" type="text" name="keyword" /> <div id="searchbtn">搜索div><br/>
客厅灯 冲锋衣 床底 沙发垫 电脑桌 鞋柜
div>
div>
<div style="background-color: #aaa; height: 35px; border-radius: 10px; line-height: 35px; text-indent: 4em;">
客厅灯 冲锋衣 床底 沙发垫 电脑桌 鞋柜
div>
<div style="margin-top: 10px; overflow: hidden;">
<div style="float: left;">
<input type="text" name="price1" style="border-radius: 5px;" />---<input type="text" name="price2" style="border-radius: 5px;" />
div>
<div style="float: right;">
<input type="checkbox" name="" value="包邮" />包邮<input type="checkbox" name="" value="包邮" />包邮 <input type="checkbox" name="" value="包邮" />包邮
div>
div>
div>
<div id="main">
<table width="100%" id="tab">
<tr>
<td>
<div style="text-align: center;">
<img src="img/002.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/003.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/004.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/005.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/006.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
tr>
<tr>
<td>
<div style="text-align: center;">
<img src="img/007.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/008.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/009.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/010.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
<td>
<div style="text-align: center;">
<img src="img/011.png" width="180"/>
div>
<div class="price">
¥40 包邮
div>
<div style="text-align: center;">
世界上最好的商品
div>
<div style="color: #888888; text-align: center;">
专营店
div>
<div style="color: #888888; text-align: right;">
如实描述
div>
td>
tr>
table>
div>
body>
html>
特点: 必须在客户端安装特定软件
优点: 图形效果显示较好(如:3D游戏)
缺点: 服务器的软件和功能进行升级,客户端也必须升级,不利于维护
常见的C/S程序:QQ和微信
特点:无需安装客户端,任何浏览器都可以直接访问
优点: 涉及到功能升级,只需要升级服务器端
缺点: 图形显示效果不如C/S架构
*需要通过HTTP协议访问
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用[服务器],在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选,目前Tomcat最新版本为**9.0。**最稳定的版本是8.0
原来我们想和浏览器交互,需要手写服务器代码进行交互,开发复杂,而且太偏底层,不适合企业级开发
tomcat就是将原来的手写服务器代码进行封装,他转变了一个思想,原来是写代码将工程变成服务器可以供网络资源访问。而tomcat是将服务器代码进行封装,然后将工程放到服务器中,所以tomcat服务器,他又名tomcat容器。
Tomcat压缩版,安装特别方便,只需要右键解压即可!
Tomcat服务器的安装
**注意:**不建议将服务器软件放在磁盘层次很多的文件夹中!
不建议放在中文路径下!
tomcat安装需要配置JAVA_HOME环境变量
第一次启动服务器建议使用命名行打开,因为可以提示错误信息!
1、bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个exe文件:tomcat9.exe、tomcat9w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要JDK的配置,shutdawn.bat用来停止Tomcat;
2、conf:这是一个非常非常重要的目录,这个目录下有四个最为重要的文件:
server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等;
tomcatusers.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面了;
web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗口才对。MIME就是用来说明文档的内容是什么类型的!
context.xml:对所有应用的统一配置,通常我们不会去配置它。
3、lib:Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的Jar包放到这个目录下;
4、logs:这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。
5、temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除!
6、webapps:存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。
7、work:运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。
8、LICENSE:许可证。
9、NOTICE:说明文件。
注意
当你在浏览器地址栏输入localhost:8080的时候,等同于输入localhost:8080/,/所代表的的意思就根路劲,就是webapps,所以遇到了404,一定是单词写错了!!!!!
解压压缩包,找到/bin/startup.bat ,双击启动即可
测试
打开浏览器!输入 http://localhost:8080
Tomcat其他配置:
1 修改端口号
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
2如何把资源放在tomcat中访问
(1)再webapps中建立文件夹:myweb
在其下创建WEB-INF文件夹,用于存放项目核心内容
*创建classes ,存放.class文件
*创建lib ,存放jar文件
*创建web.xml 项目配置文件(到ROOT项目下的WEB-INF复制即可)
(2)把网页hello.html复制到myweb文件夹中,与WEB-INF在同级目录
(3)访问http://localhost:8080/myweb/hello.html
Servlet 是Java Server Applet的简称,称为小服务器程序,用Java编写的服务器端程序,主要功能交互式地浏览和修改数据,生成动态Web内容。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet编程需要使用到javax.servlet 和 javax.servlet.http两个包下面的类和接口,在所有的类和接口中,javax.servlet.Servlet 接口最为重要。所有的servlet程序都必须实现该接口或者继承实现了该接口的类。javax.servlet.ServletConfig;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
javax.servlet.http.HttpSession;
javax.servlet.http.Cookie;
在src创建package
选中刚刚创建的包,右键–>New–>Servlet
第一个Servlet代码如下:
/**
*第一个Servlet程序
*/
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see 构造函数
*/
public HelloServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see 处理Get请求
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 响应内容到浏览器
response.getWriter().print("Hello Word");;
}
/**
* @see 处理Post请求
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
需要在web.xml中配置
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.qf.controller.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>//与上面name一样
<url-pattern>/myweb</url-pattern>
</servlet-mapping>
//通过浏览器url地址输入/myweb找到myServlet 代表着中的myServlet,而myServlet描述的是com.qf.controller.MyServlet,所以能访问到MyServlet
如果访问到MyServlet中的MyServlet.class文件,就得
<url-pattern>/myweb/MyServlet</url-pattern>
<url-pattern>配置的内容就是浏览器地址栏输入的URL中项目名资源的内容
发布右键–>Run As–>Run On Server
浏览器输入网址访问:http://localhost:8080/项目名称/HelloServlet
HTTP Status 404 资源找不到
解决方法:查看Tomcat的webapps目录下找到当前项目在WEB-INF下的classes内能否找到刚刚的class文件
如果有,重新启动Tomcat
如果没有,在Eclipse中选择Project-->clean让Eclipse清空缓存并重新构建项目,再次运行
idea中,把out目录的内容删除,然后重新运行。
1.4.1 什么是HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。
HTTP协议的主要特点如下:
1.支持客户端/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
1.4.2 Http协议的通信
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
1、 建立TCP连接
在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更低层协议的连接。因此,首先要建立TCP连接,一般TCP连接的端口号是80
2、 浏览器向Web服务器发送请求命令
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令
例如:GET /sample/hello.html HTTP/1.1
3、 浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4、 Web服务器应答
客户机向服务器发出请求后,服务器会客户机回送应答,
HTTP/1.1 200 OK
应答的第一部分是协议的版本号和应答状态码
5、 Web服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6、 Web服务器向浏览器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
7、 Web服务器关闭TCP连接
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽
1.4.3 请求和响应数据格式
HTTP请求报文
当浏览器向Web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),HTTP请求信息由4部分组成:
1 请求行 请求方法/地址 URI协议/版本
2 请求头(Request Header)
3 空行
4 请求正文
下面是一个HTTP请求的例子:
POST/hello HTTP/1.1
//浏览器告诉服务器我能接收的信息
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost:8080
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br
username=zhangsan&age=20&add=beijing
1、请求方法 URI 协议/版本
请求的第一行是“方法URL议/版本”:GET/hello HTTP/1.1
以上代码中“GET”代表请求方法,“/hello”表示URI,“HTTP/1.1代表协议和协议的版本。
根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet应用中,最常用的方法是GET和POST。
URL完整地指定了要访问的网络资源,通常只要给出相对于服务器的根目录的相对目录即可,因此总是以“/”开头,最后,协议版本声明了通信过程中使用HTTP的版本。
2、请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language:zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4
Connection:Keep-Alive
Host:localhost
User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept-Encoding:gzip, deflate, br
3 空行
4、请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:
name=zhangsan
HTTP响应报文
HTTP应答与HTTP请求相似,HTTP响应也由4个部分构成,分别是:
1、状态行
2、响应头(Response Header)
3、空行
4、响应正文
HTTP/1.1 200 OK //状态行
Server: nginx
Date: Tue, 31 May 2016 02:09:24 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With,access_token,access-token,content-type,multipart/form-data,application/x-www-form-urlencoded
Access-Control-Allow-Methods: GET,POST,OPTIONS
Content-Length: 49
//正文
网页标题
网页内容
(1)状态行
由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
状态代码:
状态代码由3位数字组成,表示请求是否被理解或被满足。
状态描述:
状态描述给出了关于状态代码的简短的文字描述。
状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。
第一个数字有五种可能的取值:
- 1xx: 指示信息—表示请求已接收,继续处理。
- 2xx: 成功—表示请求已经被成功接收、理解、接受。
- 3xx: 重定向—要完成请求必须进行更进一步的操作。
- 4xx: 客户端错误—请求有语法错误或请求无法实现。
- 5xx: 服务器端错误—服务器未能实现合法的请求。
状态代码 状态描述 说明
200 OK 客户端请求成功
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthonzed 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 Not Found 请求的资源不存在,例如,输入了错误的URL。
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
(2)响应头
响应头可能包括:
Location:
Location响应报头域用于重定向接受者到一个新的位置。例如:客户端所请求的页面已不存在原先的位置,为了让客户端重定向到这个页面新的位置,服务 器端可以发回Location响应报头后使用重定向语句,让客户端去访问新的域名所对应的服务器上的资源。当我们在JSP中使用重定向语句的时候,服务器 端向客户端发回的响应报头中,就会有Location响应报头域。
Server:
Server响应报头域包含了服务器用来处理请求的软件信息。它和User-Agent请求报头域是相对应的,前者发送服务器端软件的信息,后者发送客户 端软件(浏览器)和操作系统的信息。下面是Server响应报头域的一个例子:Server: Apache-Coyote/1.1
WWW-Authenticate:
WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,这个报头域和前面讲到的Authorization请求报头域是 相关的,当客户端收到401响应消息,就要决定是否请求服务器对其进行验证。如果要求服务器对其进行验证,就可以发送一个包含了 Authorization报头域的请求,下面是WWW-Authenticate响应报头域的一个例子:WWW-Authenticate: Basic realm="Basic Auth Test!"
从这个响应报头域,可以知道服务器端对我们所请求的资源采用的是基本验证机制。
Content-Encoding:
Content-Encoding实体报头域被使用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容编码,因而要获得Content- Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding主要用语记录文档的压缩方法,下面是它的一个例子: Content-Encoding: gzip。如果一个实体正文采用了编码方式存储,在使用之前就必须进行解码。
Content-Language:
Content-Language实体报头域描述了资源所用的自然语言。Content-Language允许用户遵照自身的首选语言来识别和区分实体。 如果这个实体内容仅仅打算提供给丹麦的阅读者,那么可以按照如下的方式设置这个实体报头域:Content-Language: da。
如果没有指定Content-Language报头域,那么实体内容将提供给所以语言的阅读者。
Content-Length:
Content-Length实体报头域用于指明正文的长度,以字节方式存储的十进制数字来表示,也就是一个数字字符占一个字节,用其对应的ASCII码存储传输。
要注意的是:这个长度仅仅是表示实体正文的长度,没有包括实体报头的长度。
Content-Type :
Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。例如:
Content-Type: text/html;charset=utf-8
Content-Type: text/html;charset=GBK
Last-Modified :
Last-Modified实体报头域用于指示资源最后的修改日期及时间。
Expires :
Expires实体报头域给出响应过期的日期和时间。通常,代理服务器或浏览器会缓存一些页面。当用户再次访问这些页面时,直接从缓存中加载并显示给用 户,这样缩短了响应的时间,减少服务器的负载。为了让代理服务器或浏览器在一段时间后更新页面,我们可以使用Expires实体报头域指定页面过期的时 间。当用户又一次访问页面时,如果Expires报头域给出的日期和时间比Date普通报头域给出的日期和时间要早(或相同),那么代理服务器或浏览器就 不会再使用缓存的页面而是从服务器上请求更新的页面。不过要注意,即使页面过期了,也并不意味着服务器上的原始资源在此时间之前或之后发生了改变。
Expires实体报头域使用的日期和时间必须是RFC 1123中的日期格式,例如:
Expires: Thu, 15 Sep 2005 16:00:00 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(也包括0)看作已过期。例如,为了让浏览器不要缓存页面,我们也可以利用Expires实体报头 域,设置它的值为0,如下(JSP):response.setDateHeader("Expires",0);
Servlet接口
在ServletAPI中最重要的是Servlet接口,所有Servlet都会直接或间接的与该接口发生联系,或是直接实现该接口,或间接继承自实现了该接口的类。
该接口包括以下五个方法:
init(ServletConfig config)
ServletConfig getServletConfig()
service(ServletRequest req,ServletResponse res)
String getServletInfo()
destroy( )
处理方式:
(1)第一次访问Servlet时,服务器会创建Servlet对象,并调用init方法,再调用service方法
(2)第二次再访问时,Servlet对象已经存在,不再创建,执行service方法
(3)当服务器停止,会释放Servlet,调用destroy方法。
GenericServlet抽象类
GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 servlet,只需重写抽象 service 方法即可。
HttpServlet类
是继承GenericServlet的基础上进一步的扩展。
提供将要被子类化以创建适用于 Web 站点的 HTTP servlet 的抽象类。HttpServlet 的子类至少必须重写一个方法,该方法通常是以下这些方法之一:
doGet,如果 servlet 支持 HTTP GET 请求
doPost,用于 HTTP POST 请求
doPut,用于 HTTP PUT 请求
doDelete,用于 HTTP DELETE 请求
init 和 destroy,用于管理 servlet 的生命周期内保存的资源
getServletInfo,servlet 使用它提供有关其自身的信息
Servlet的第一种创建方式:继承HttpServlet(常用的)
/**
* Servlet implementation class HelloServlet
* 演示Servlet的第一种创建方式,继承HttpServlet.也是开发中推荐的
*
*/
@WebServlet("/hs1")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**重写doGet
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("我是Servlet创建的第一种方式");
}
/**重写doPost
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
Servlet创建的第二种方式:实现接口Servlet
/**
* Servlet创建的第二种方式:实现接口Servlet
* */
@WebServlet("/hs2")
public class HelloServlet2 implements Servlet{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("OK");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().println("我是第二种创建方式");
}
}
第一种注解式配置 Servlet3.0及以后 :(常用)
package com.qf.controller;
/**
* Servlet implementation class MyServlet
*/
/*@WebServlet(urlPatterns={"/bbb","/ccc"},loadOnStartup=2,
initParams={@WebInitParam(name="username",value="lisi"),
@WebInitParam(name="password",value="123")})*/
@WebServlet("/bbb")
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MyServlet() {
super();
// TODO Auto-generated constructor stub
System.out.println("myServlet初始化啦");
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("开始写业务逻辑了");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
System.out.println(config.getInitParameter("username"));
}
}
使用注解方式:
注解类@ WebServlet
value: 配置url路径
urlPatterns:配置url路径 ,和value作用一样,不能同时使用
loadOnStartup:配置Servlet的创建的时机, 如果是 0 或者正数启动程序时则就创建,如果是负数,则访问时创建。
initParams:配置Servlet的初始化参数
第二种web.xml配置 Servlet所有版本都支持:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的web.xml配置
*/
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
response.getWriter().print("OK");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(req, resp);
}
}
web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>Web_Day11display-name>
<servlet>
<servlet-name>hello2servlet-name>
<servlet-class>com.qf.web.servlet.HelloServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>hello2servlet-name>
<url-pattern>/hello2url-pattern>
servlet-mapping>
<welcome-file-list>
<welcome-file>login.htmlwelcome-file>
welcome-file-list>
web-app>
容器在进行url-pattern配置的时候是遵循一定的匹配原则的
url-pattern定义匹配规则,取值说明:
精确匹配 /具体的名称 只有url路径是具体的名称的时候才会触发Servlet
后缀匹配 *.xxx 只要是以xxx结尾的就匹配触发Servlet
通配符匹配 /* 匹配所有请求,包含服务器的所有资源
通配符匹配 / 匹配所有请求,包含服务器的所有资源,不包括.jsp
load-on-startup (加载的时机)
1元素标记容器是否应该在web应用程序启动的时候就加载这个servlet。
2它的值必须是一个整数,表示servlet被加载的先后顺序。
3如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时再加载。
4如果值为正整数或者0时,表示容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。(值为0最先被加载)
两种不冲突
name
张三
1 init-param元素用来定义Servlet启动的参数,可以定义多个
2 param-name表示参数名称
3 param-value表示参数值
2.4.1 什么是生命周期
生命周期也就是生命历程,就像人都是从怀胎-->出生-->婴儿-->儿童-->少年-->成年-->中年-->老年-->死亡
2.4.2 生命周期的四个阶段
阶段一、实例化(调用构造方法)
实例化阶段是Servlet生命周期中的第一步,由Servlet容器调用Servlet的构造器创建一个具体的Servlet对象的过程。而这个创建的时机可以是在容器收到针对这个组件的请求之后,即用了才创建;也可以在容器启动之后立刻创建实例,而不管此时Servlet是否使用的上。使用如下代码可以设置Servlet是否在服务器启动时就执行创建
1
注意:只执行一次
阶段二、初始化(init方法)
Servlet在被加载实例化之后,必须要初始化它。在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。ServletConfig对象由Servlet引擎负责创建,从中可以读取到事先在web.xml文件中通过节点配置的多个name-value名值对。ServletConfig对象还可以让Servlet接受一个ServletContext对象。
一般情况下,init方法不需要编写,因GenericServlet已经提供了init方法的实现,并且提供了getServletConfig方法来获得ServletConfig对象。
注:init方法只被执行一次
init方法在实例化之后执行,并且也和1 有关系
阶段三、就绪/服务
Servlet被初始化以后就处于能够响应请求的就绪状态。每个对Servlet的请求由一个ServletRequest对象代表,Servlet给客户端的响应由一个ServletResponse对象代表。当客户端有一个请求时,容器就会将请求与响应对象转给Servlet,以参数的形式传给service方法。service方法由javax.servlet.Servlet定义,由具体的Servlet实现
HttpServlet将service方法拆分了。doGet和doPost
可执行多次
阶段四、销毁
Servlet容器在销毁Servlet对象时会调用destroy方法来释放资源。通常情况下Servlet容器停止或者重新启动都会引起销毁Servlet对象的动作,但除此之外,Servlet容器也有自身管理Servlet对象的准则,整个生命周期并不需要人为进行干预
注意:destroy方法只执行一次
Servlet代码如下:
/**
* Servlet implementation class LifeServlet
* 演示Servlet的生命周期:
* 1、实例化
* 2、init:初始化
* 3、service:服务
* 4、destory:销毁
*/
@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LifeServlet() {
super();
System.out.println("1、完成了实例化");
// TODO Auto-generated constructor stub
}
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
super.init();
System.out.println("2、完成了初始化");
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("3、就绪中");
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
System.out.println("4、销毁了");
}
}
html页面:
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页面title>
head>
<body>
<h1>欢迎你h1>
<div>
<form action="HelloServlet">
<label>姓名:label><input name="name"><br/>
<label>年龄:label><input name="age"><br/>
<input type="submit" value="提交">
form>
div>
body>
html>
Servlet代码:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的获取请求参数
*
*/
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单提交的姓名
String name=request.getParameter("name");
//获取年龄
String age=request.getParameter("age");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:姓名:"+name+"---->年龄:"+age);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
默认的请求方式是GET请求
GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连
GET提交的数据大小有限制(因为浏览器对URL的长度有限制)64kb
GET方式提交数据是明文传递,数据量小,不安全,效率高
对应的Servlet的方法是doGet
POST方法是把提交的数据放在HTTP包的Body中
POST方法提交的数据没有限制
POST提交的数据是密文传递数据,数据量大,相对安全
效率相对没有GET高
对应的Servlet的方法是doPost
对应的Servlet的方法是doPost
String getParameter(String name) //根据表单组件名称获取提交数据
void setCharaterEncoding(String charset) //指定每个请求的编码
例:
get的情况:
html页面中
<form action="/WebProject_war_exploded/rs" method="get">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="注册"/>
</form>
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取用户请求发送的数据
String username = req.getParameter("username");
String password = req.getParameter("password");
}
post的情况:
<form action="/WebProject_war_exploded/rs" method="post">
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="注册"/>
</form>
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//所以要对request请求对象设置统一的编码
req.setCharacterEncoding("utf-8");
//获取用户请求发送的数据,如果不设置编码方式,输入中文会乱码
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("提交的数据为"+username+"\t"+password);
}
方法名称 | 作用 |
---|---|
setStatus(int code) | 设置响应状态码:200 成功 302 临时重定向 304 处理缓存 404 Not Found没有找到资源,500 服务器错误 |
setHeader(name,value) | 设置响应信息头 |
setCharacterEncoding(String) | 设置服务端响应内容编码格式 |
setContentType(String) | 设置响应文件类型、响应式的编码格式 |
getWriter() | 获取字符输出流 |
getOutputStream() | 获取字节输出流 |
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//0、所以要对request请求对象设置统一的编码
req.setCharacterEncoding("utf-8");
//1、获取用户请求发送的数据,如果不设置编码方式,输入中文会乱码
String username = req.getParameter("username");
String password = req.getParameter("password");
//System.out.println("提交的数据为"+username+"\t"+password);
//2、响应数据给客户端
//两种编码方式,第一种(不推荐)
resp.setCharacterEncoding("UTF-8");//设置服务端的编码格式
resp.setHeader("Context-Type", "text/html;charset=utf-8");
//第二种(推荐)同时设置 服务端编码格式 和 客户端响应扥件类型及响应时的编码格式
resp.setContentType("text/html;charset=UTF-8");
PrintWriter printWriter = resp.getWriter(); //生成引用可用快捷键resp.getWriter().var
//printWriter.println("success!");
printWriter.println("注册成功!"); //如果不设置编码格式,此时会显示乱码的
}
2.7.1 为什么表单中会产生中文乱码
产生乱码,就是因为服务器和客户端沟通的编码不一致造成的,因此解决的办法是:在客户端和服务器之间设置一个统一的编码,之后就按照此编码进行数据的传输和接收
2.7.2 GET中文乱码
在Tomcat7及以下
客户端以UTF-8的编码传输数据到服务器端,而服务器端的request对象使用的是ISO8859-1这个字符编码来接收数据,服务器和客户端沟通的编码不一致因此才会产生中文乱码的。解决办法:在接收到数据后,先获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题。
String name=request.getParameter("name");
name=new String(name.getBytes("ISO8859-1"),"UTF-8");
Tomcat8的版本中GET基本就不会乱码了,因为服务器对url的编码格式可以进行自动转换
2.7.3 POST乱码
由于客户端是以UTF-8字符编码将表单数据传输到服务器端的,因此服务器也需要设置以UTF-8字符编码进行接收,要想完成此操作,服务器可以直接使用从ServletRequest接口继承而来的"setCharacterEncoding(charset)"方法进行统一的编码设置。
解决POST中文乱码代码如下:
/**
* Servlet implementation class HelloServlet
* 演示Servlet的GET请求,中文乱码的问题
*
*/
@WebServlet("/GETServlet")
public class GetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求参数的编码格式--对GET无效
request.setCharacterEncoding("UTF-8");
//获取表单提交的信息
String name=request.getParameter("msg");
//服务端输出打印
System.out.println(request.getRemoteAddr()+"发来信息:"+msg);
}
}
解决乱码的万金油
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
2.9.1 线程安全问题
因为每次请求都会创建一个线程,如果多人同时请求,那么就会存在多个线程操作同一个Servlet对象,那么如果在对应的方法中操作了成员变量,就有可能产生线程安全的问题。
2.9.2 如何保证线程安全
1、synchronized
将存在线程安全问题的代码放到同步代码块中
2、实现SingleThreadModel接口
servlet实现singleThreadModel接口后,每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端请求的效率太低,所以已经淘汰。
3、尽可能只使用局部变量
作为后台开发人员,我们大多时候都在接收处理用户请求,给予用户响应,为了方便操作,服务器软件将请求和响应封装成了request和response,我们今天就讲解两个对象的操作!
页面跳转:在前端实现资源跳转,在后台服务器实现资源跳转
前端实现跳转:a标签的href,form表单的action
Java Web服务端控制页面跳转主要有两种:重定向和转发
案例中业务逻辑和显示结果都放在同一个Servlet里,会产生设计问题
不利于单一职能原则,各司其职的思想
不利于后期的维护
例如:
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//1、收参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//2、调用业务逻辑
AdminService adminService = new AdminServiceImpl();
Admin admin = adminService.login(username, password);
//3、处理结果
PrintWriter printWriter = resp.getWriter();
if (admin!=null){
//响应成功页面
printWriter.println("");
printWriter.println("");
printWriter.println("");
printWriter.println("结果页面 ");
printWriter.println("");
printWriter.println("");
printWriter.println("登录成功
");
printWriter.println("");
printWriter.println("");
}else {
//响应失败页面
printWriter.println("");
printWriter.println("");
printWriter.println("");
printWriter.println("结果页面 ");
printWriter.println("");
printWriter.println("");
printWriter.println("登录失败
");
printWriter.println("");
printWriter.println("");
}
}
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
因此要将业务逻辑和显示结果分离
并且要实现跳转
在ShowAllAdminController中doGet中写
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//只负责调用业务逻辑功能
AdminService adminService = new AdminServiceImpl();
List<Admin> adminList =adminService.showAllAdmin();
//request作用域存储数据
req.setAttribute("admins", adminList); //键值对,admins存的是adminList集合
//通过转发 跳转到显示结果servlet
req.getRequestDispatcher("/showalljsp").forward(req, resp);
}
在ShowAllAdminJSP中doGet中写
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
List<Admin> adminList= (List)req.getAttribute("admins");//拿到的admin键存的object类型对象,可以强转成list
//后面接页面
PrintWriter printWriter = resp.getWriter();
if (adminList!=null) {...}
}
重定向就是通过各种方法将网络请求重新定个方向转到其它位置。
实现原理:
客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器--》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。
特点:
特点:
1,重定向是客户端行为。
2,重定向是浏览器做了至少两次的访问请求。
3,重定向浏览器地址改变。
4,重定向两次跳转之间传输的信息会丢失(request范围),所以会使用session作用域。
5,重定向可以指向任何的资源,包括当前应用程序中的其他资源,同一个站点上的其他应用程序中的资源,其他站点的资源。注意:传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录
html页面:
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面title>
head>
<body>
<div>
<form action="/day12web1/login" method="post">
<label>账号:label><input name="un"/><br/>
<label>密码:label><input type="password" name="pw"/><br/>
<input type="submit" value="登录"/>
form>
div>
<h5><a href="register.html">还没账号请注册a>h5>
body>
html>
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>网站首页title>
head>
<body>
欢迎进入xxx管理系统............
body>
html>
Servlet代码:
/**
* Servlet implementation class LoginServlet
* 实现登录信息操作
*/
@WebServlet(value="/login",initParams={@WebInitParam(name="version",value="v10")})
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
super.init(config);
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
//获取表单提交的用户名
String username=request.getParameter("un");
//获取密码
String password=request.getParameter("pw");
//服务端输出打印
System.out.println("POST:用户名:"+username+"---->密码:"+password);
//重定向.可以跳转到指定的页面
response.sendRedirect("index.html");
}
}
总结:
重定向是浏览器行为,虽然可以实现资源跳转,但是浏览器发了两次请求,地址栏发生改变,生成两个request对象,不能实现值共享,如果要传值,只能通过url的拼接
Servlet除了支持重定向之外还支持请求转发
当我们在做资源跳转设计到需要携带大量数据,用重定向就不合适了
原理:
客户浏览器发送http请求----》web服务器接受此请求--》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户。在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。
特点:
1,转发是服务器行为
2,转发是浏览器只做了一次访问请求
3,转发浏览器地址不变
4,转发两次跳转之间传输的信息不会丢失,所以可以通过request作用域进行数据的传递
5,转发只能将请求转发给同一个WEB应用中的组件
注意:如果创建RequestDispatcher 对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。
代码见1.0
总结:
转发是服务器行为,浏览只发送一次请求,地址栏不会发生改变,资源跳转的过程中可以实现值共享,并且还可以传任意类型的复杂数据
什么时候用转发?什么时候用重定向?
只要是服务端发生资源跳转,都可以用。你只需要思考要不要带值跳转,如果带单个值(id/username),推荐使用重定向用url拼接。如果需要传递复杂数据类型的值,使用转发
路径分类 :
绝对路径: 用在不同网站之间的跳转,比如:http://www.baidu.com/aaa/1.jpg
**相对路径:**用在同一个网站中, aaa/1.jpg,仅限静态资源,如果页面比较多,并且使用框架,会出现混乱。
根路径:根指定就是主机名(服务器) /day12web1/loginservlet (/ 表示 http://localhost:8080/)
/day12web1/loginservlet 如果在浏览器中使用 / 表示 http://localhost:8080/
/listservlet 如果是在服务器中使用 / 表示 /day12web1
在Servlet中可以使用的内置对象主要有:request、response、application、session、out(PrintWriter)。
定义辅助 servlet 将响应发送到客户端的对象。servlet 容器创建 ServletResponse 对象,并将它作为参数传递给 servlet 的 service 方法。 要发送 MIME 正文响应中的二进制数据,请使用 getOutputStream 返回的 ServletOutputStream。要发送字符数据,请使用 getWriter 返回的 PrintWriter 对象。
扩展 ServletResponse 接口以提供特定于 HTTP 的发送响应功能。例如,该接口拥有访问 HTTP 头和 cookie 的方法。 客户端向服务器发起的都是HTTP协议操作,所以我们大部分使用HttpServletResponse对象作为直接操作对象!
方法名称 | 作用 |
---|---|
setStatus(int code) | 设置响应状态码:200 成功 302 临时重定向 304 处理缓存 404 Not Found没有找到资源,500 服务器错误 |
setHeader(name,value) | 设置响应信息头 |
setCharacterEncoding(String); | 设置编码格式 |
setContentType(String) | 设置返回数据mimetype |
getWriter() | 获取字符输出流 |
getOutputStream() | 获取字节输出流 |
方案1
response.setCharacterEncoding("utf-8");
设置tomcat编码格式
<html>
<head>
<meta charset="utf-8">
<title>xxx</title>
</head>
<body>编写返回的文本内容</body>
</html>
设置浏览器解析文本内容格式
可以解决返回字符串乱码问题,但是需要将返回的字符串封装到html代码中.操作繁琐!
方案2
response.setHeader("Content-type","text/html;charset=UTF-8")
方案按相对简单,通过设置响应头告知浏览器解析字符串的编码格式!
方案3(推荐)
response.setContentType("text/html;charset=UTF-8")
利用setContentType这种综合性的写法解决问题!此方法也是开发中常用的方法!方便!
用户下载服务器图片
package com.qf.controller;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.coyote.http11.filters.BufferedInputFilter;
@WebServlet("/img")
public class ImgServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 下载图片?
// 1.需要找到服务器中图片的位置
// 2.使用io流将它读成二进制
// 3.使用写的流,将二进制写到响应中
// 4.浏览器会自动解读响应,完成下载
// 获取项目根路径的绝对路径
String realPath = req.getServletContext().getRealPath("/");
System.out.println(realPath);
String path = realPath + "\\img\\girl.jpg";
File f = new File(path);
System.out.println();
System.out.println(f.getName());
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(f));
// 设置响应头,通过响应头来告诉浏览器,我给你的二进制是用来下载的
// content-disposition", "attachment;filename="+f.getName()
// 下载用的 attachment下载: filename下载文件的名字
resp.setHeader("content-disposition", "attachment;filename=aaa.jpg");
//根据文件名字的后缀名获取类型
String mimetype = getServletContext().getMimeType(f.getName());
resp.setContentType(mimetype); //下载文件的类型
ServletOutputStream out = resp.getOutputStream();
int a = 0;
while ((a = bin.read()) != -1) {
//print:直接向页面输出
out.write(a);
}
bin.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(req, resp);
}
}
页面中添加验证码
public class CodeServlet extends HttpServlet {
/**
* The doGet method of the servlet.
* This method is called when a form has its tag value method equals to get
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置生成规则
/**
* width:验证码的宽度 px 像素
* height: px
* codeCount:生成验证码有几个数
* lineCount:有几根线
*/
ValidateCode code = new ValidateCode(200, 50, 6, 20);
//2.获取生成的验证码的字符串值
System.out.println(code.getCode()); //获取正确值
//3.响应写回验证图片
code.write(response.getOutputStream());
}
}
DOCTYPE html>
<html>
<head>
<title>login.htmltitle>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
head>
<body>
<form action="/Day11_Response1/servlet/LoginServlet" method="post">
<input type="text" name="username" placeholder="请输入账号!" />
<input type="submit" value="登录"/>
form>
<img src="/Day11_Response1/servlet/CodeServlet" alt="验证码" title="验证码"/>
body>
html>
定义将客户端请求信息提供给某个 servlet 的对象。servlet 容器创建ServletRequest 对象,并将该对象作为参数传递给该 servlet 的service方法。
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
*小结:*同响应相同,客户端请求协议都是基于HTTP所以我们选用HttpServletRequest来操作用户发送过来的请求的数据!
URL :Uniform Resource Location (统一资源定位符) 网址
URI :Uniform Resource Identifier (统一资源标识符) URI包含URL
美国总统:—》特朗普 URI
他二大爷:—》特朗普
美国白宫10号楼99号房间–> 特朗普的地址
//获取请求路径相关参数
**
getRequestURL方法返回客户端发出请求时的完整URL。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
getMethod得到客户机请求方式
//获取请求头信息
getHead(name)方法
getHeaders(String name)方法
getHeaderNames方法
//获取请求正文参数
**getParameter(name)方法 只能传String类型数据
**getParameterValues(String name)方法
getParameterNames方法
getParameterMap方法 //做框架用,非常实用
getInputStream方法 获取输入流
//1.测试获取请求行数据的方法和请求头的方法
//1.获取请求行的方法
//获取请求方式
String method = request.getMethod();
//获取请求的url
String url = request.getRequestURL()+"";
//获取uri
String uri = request.getRequestURI();
//获取请求的参数 get
String query = request.getQueryString();
//获取请求人的ip
String ip = request.getRemoteAddr();
//获取请求的主机名
String host = request.getRemoteHost();
System.out.println(method+" url:"+url+" uri:"+
uri+" query:"+query+" ip:"+ip+" host:"+host);
//获取请求信息
//全部输出
//post fix
String header = request.getHeader("user-agent");
if (header.contains("firefox")) {
System.out.println("这是火狐浏览器");
}
//获取所有请求的names
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = (String) headerNames.nextElement();
//根据name获取keys
Enumeration<String> headers = request.getHeaders(name);
while (headers.hasMoreElements()) {
String key = (String) headers.nextElement();
System.out.println(name+"--->"+key);
}
}
将数据封装到实体类上
创建一个对应的实体类!
实体类要变量命名和变量类型都有相应的要求,要求变量名跟提交参数的key相同,变量跟参数类型形同!
public class User {
private String username;
private String password;
private String sex;
private String [] hobby;
//getter/setter
}
String username = req.getParameter("username");
String password=req.getParameter("password");
String gender=req.getParameter("gender");
String[] hobby = req.getParameterValues("hobby");
User user=new User(username,password,gender,hobby);
System.out.println(user.toString());
Map<String, String[]> map = request.getParameterMap();
try {
Class<?> c1 = Class.forName("com.qf.model.User");
Constructor<?> constructor = c1.getConstructor();
Object obj = constructor.newInstance();
//得到所有set方法
Method[] ms = c1.getMethods();
for (int i = 0; i < ms.length; i++) {
if(ms[i].getName().startsWith("set")){//setUsername
String oldName = ms[i].getName().substring(3);//Username
char[] oldArray = oldName.toCharArray();//[U,s,e,r,n,a,m,e]
char a=(char) (oldArray[0]+32);//U==>u
oldArray[0]=a;//==>[u,s,e,r,n,a,m,e]
String newName=new String(oldArray);//username
String[] strings = map.get(newName);
if(strings.length==1){
ms[i].invoke(obj, strings[0]);
}else{
ms[i].invoke(obj, (Object)strings);
}
}
}
System.out.println(obj.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
1.导入beanutils对应jar包、logging日志、commons-collections-3.2.1.jar
2.映射
Map<String, String[]> map = request.getParameterMap();
User u=new User();
BeanUtils.populate(u, map);
BeanUtils.populate(bean2, request.getParameterMap());
System.out.println(bean2);
HTTP协议是无状态的,不能保存每次提交的信息,即当服务器返回与请求相对应的应答之后,这次事务的所有信息就丢掉了。
如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系。
对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就成问题了。
WEB应用中的会话(多次交互)是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程。
WEB应用的会话状态是指WEB服务器与浏览器在会话过程中产生的状态信息,借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
状态管理是: 将浏览器与web服务器之间多次交互当作一个整体来处理,并且将多次交互所涉及的数据(即状态)保存下来。
客户端状态管理技术:将状态保存在客户端。代表性的是Cookie技术。
服务器状态管理技术:将状态保存在服务器端。代表性的是session技术(服务器传递sessionID时需要使用Cookie的方式)。
Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一小段数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。
一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这个Cookie回传给WEB服务器。
WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB
//服务端创建Cookie
Cookie ck=new Cookie("code", code);
ck.setPath("/WebProject_war_exploded");//设置Cookie的路径ck.setPath("//WebProject_war_exploded/get");//如果是这样只有项目路径get能访问到
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0失效;<0内存存储,默认-1
ck.setMaxAge(60*60); //Cookie存在3600秒
//让浏览器添加Cookie,将Cookie响应给客户端
response.addCookie(ck);
chrome浏览器查看cookie信息:chrome://settings/content/cookies
//获取所有的Cookie
Cookie[] cks=request.getCookies();
//遍历Cookie
for(Cookie ck:cks){
//检索出自己的Cookie
if(ck.getName().equals("code"))
{
//记录Cookie的值
code=ck.getValue();
break;
}
}
只需要保证Cookie的名和路径一致即可修改
更改cookie的name和有效路径会新建cookie,而更改cookie值、有效期会覆盖原有cookie
//创建Cookie
Cookie ck=new Cookie("code", code2);
ck.setPath("/WebProject_war_exploded");//设置Cookie的路径
ck.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒;=0失效;<0内存存储
response.addCookie(ck);//让浏览器添加Cookie
ck.setMaxAge(-1);设置生成时间,默认-1
取值说明:
>0有效期,单位秒
=0失效
<0内存存储
中文和英文字符不同,中文属于Unicode字符,在内存中占用4个字符,而英文属于ASCII字符,内存中只占2个字节。
Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会出现乱码。
编码可使用java.net.URLEncoder类的encode(String str,String encoding)方法,解码使用java.net.URLDecoder类的decode(String str,String encoding)方法
代码如下:
保存:Servlet类
// 使用中文的 Cookie. name 与 value 都使用 UTF-8 编码.
Cookie cookie = new Cookie(
URLEncoder.encode("姓名", "UTF-8"),
URLEncoder.encode("老邢", "UTF-8"));
// 发送到客户端
response.addCookie(cookie);
读取:Servlet读取
if(request.getCookies() != null){
for(Cookie cc : request.getCookies()){
String cookieName = URLDecoder.decode(cc.getName(), "UTF-8");
String cookieValue = URLDecoder.decode(cc.getValue(), "UTF-8");
out.println(cookieName + "=");
out.println(cookieValue + ";
");
}
}
else{
out.println("Cookie 已经写入客户端. 请刷新页面. ");
}
cookie 一般都是由于用户访问页面而被创建的,可是并不是只有在创建 cookie 的页面才可以访问这个cookie。在默认情况下,出于安全方面的考虑,只有与创建 cookie 的页面处于同一个目录或在创建cookie页面的子目录下的网页才可以访问。那么此时如果希望其父级或者整个网页都能够使用cookie,就需要进行路径的设置。
cookie.setPath("/");
自动发送原则
浏览器在发送请求之前,首先会根据请求url中的域名在cookie列表中找所有与当前域名一样的cookie,然后再根据指定的路径进行匹配,如果当前请求在域匹配的基础上,还与路径匹配那么就会将所有匹配的cookie发送给服务器。
通过Cookie的setPath方法设置路径
优点:
可配置到期规则:Cookie 可以在浏览器会话结束时到期,或者可以在客户端计算机上无限期存在,这取决于客户端的到期规则,不需要任何服务器资源,Cookie 存储在客户端并在发送后由服务器读取。
简单性:Cookie 是一种基于文本的轻量结构,包含简单的键值对。
数据持久性:虽然客户端计算机上 Cookie 的持续时间取决于客户端上的 Cookie 过期处理和用户干预,Cookie 通常是客户端上持续时间最长的数据保留形式
缺点:
大小受到限制:大多数浏览器对 Cookie 的大小有 4096 字节的限制,尽管在当今新的浏览器和客户端设备版本中,支持 8192 字节的 Cookie 大小已愈发常见。
用户配置为禁用:有些用户禁用了浏览器或客户端设备接收 Cookie 的能力,因此限制了这一功能。
潜在的安全风险:Cookie 可能会被篡改。用户可能会操纵其计算机上的 Cookie,这意味着会对安全性造成潜在风险或者导致依赖于Cookie 的应用程序失败。
Session用于跟踪客户的状态。Session指的是在一段时间内,单个客户与Web服务器的一连串相关的交互过程。
在一个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。
服务器会为每一次会话分配一个Session对象
同一个浏览器发起的多次请求同属于一次会话(Session)
首次使用到Session时,服务器会自动创建Session,并创建Cookie存储SessionId发送回客户端
注意:session是由服务端创建的
使用:
Session作用域:拥有存储数据的空间,作用范围是一次会话有效
一次会话是使用同一浏览器发送的多次请求。一旦浏览器关闭,则结束会话
可以将数据存入Session中,在一次会话的任意位置进行获取
可传递任何数据(基本数据类型、对象、集合、数组)
第一次浏览器发送请求给服务器,如果需要从请求中拿到session对象,那么他回去找请求中有没有cookie叫做jsessionId,由于是第一次请求,是没有cookie的。此时服务器会在内存开辟一个空间,用来存session对象,并且将该空间的内存地址经过加密后一jsessionId为键存储在cookie中,并且将这个cookie交给浏览器保存
同一个浏览器第n次发送请求到服务器,由于浏览器的自动发送cookie原则,会将一个存了jsessionId的cookie自动发送到服务器中,服务器回去解读请求中的cookie,通过jsessionId的键名拿到内存地址,从而将这一次请求和内存地址所对应的session绑定上
所以只要是cookie还没失效,同一台浏览器去访问服务器的所有请求,绑定的是同一个session对象,所以这个session对象中的值是可以被所有请求共享的,从而解决状态的持久化
//获取Session对象
HttpSession session=request.getSession();
System.out.println( "Id:"+session.getId());//唯一标记,
System.out.println("getLastAccessedTime:"+session.getLastAccessedTime());//最后一次访问时间,毫秒
System.out.println("getMaxInactiveInterval:"+session.getMaxInactiveInterval());//获取最大的空闲时间,单位秒
System.out.println("getCreationTime:"+session.getCreationTime());//获取Session的创建,单位毫秒
使用HttpSession的setAttribute(属性名,Object)方法
HttpSession session=request.getSession();
session,setAttribute("key",value);//以键值对形式存储在session作用域中
//与request作用域一样的用法(请求转发)
使用HttpSession的invalidate方法
HttpSession session=request.getSession();
session.removeAttribute("key"); //通过键移除session作用域中的值
request是一次请求有效,请求改变则request改变
session是一次会话有效,浏览器改变,则session改变
开始: 第一次使用到Session的请求产生,则创建Session
结束:
浏览器关闭,则失效;
Session超时,则失效;
session.setMaxInactiveInterval(seconds);//设置最大有效时间(秒)
手工销毁,则失效
session.invalidate();//登录退出、注销
HttpSession的最后一程访问时间和当前时间的差距大于了指定的最大空闲时间,这时服务器就会销毁Session对象。默认的空闲时间为30分钟。
1 使用HttpSession的session.setMaxInactiveInterval(20*60);设置,单位秒
2 在web.xml中配置 ,单位分钟 或者用webservlet注解
20
1、超过了设置的超时时间
2、主动调用了invalidate方法
3、服务器主动或异常关闭
注意:浏览器关闭并不会让Session失效
如果浏览器禁用Cookie,session还能用吗?
答:不能,但有其他的解决方案
服务器在默认情况下,会使用Cookie的方式将sessionID发送给浏览器,如果用户禁止Cookie,则sessionID不会被浏览器保存,此时,服务器可以使用如URL重写这样的方式来发送sessionID.
使用Session区分每个用户的方式:
1、使用Cookie
2、作为隐藏域嵌入HTML表单中,附加在主体的URL中,通常作为指向其他应用程序页面的链接,即URL重写。
浏览器在访问服务器上的某个地址时,不再使用原来的那个地址,而是使用经过改写的地址(即,在原来的地址后面加上了sessionID)
如果是链接地址和表单提交,使用
response.encodeURL(String url)生成重写后的URL
如果是重定向,使用
response.encodeRedirectURL(String url)生成重写的URL
登录的html页面:
login.html
Insert title here
登录的Servlet:
@WebServlet(name = "LoginMgrController", value = "/loginMgr")
public class LoginMgrController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、处理乱码 2、收参 3、调用业务方法 4、处理结果,流程跳转
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String username =request.getParameter("username");
String password =request.getParameter("password");
ManagerService managerService = new ManagerServiceImpl();
Manager mgr = managerService.login(username, password);
if (mgr!=null){
//登录成功,将管理员信息存储在Session里
HttpSession session = request.getSession();
session.setAttribute("mgr", mgr);
response.sendRedirect("/WebProject_war_exploded/showallcontroller");
}else {
//登录失败
response.sendRedirect("/WebProject_war_exploded/loginMgr.html");
}
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
@WebServlet(value = "/showallcontroller")
public class ShowAllAdminController extends HttpsServlet {
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过HttpSession完成权限控制,这样登录过了的才显示,没登录的就进行登录(防止非法访问)
HttpSession session = req.getSession();
Manager mgr = (Manager)session.getAttribute("mgr");
if (mgr!=null){
//只负责调用业务逻辑功能
AdminService adminService = new AdminServiceImpl();
List adminList =adminService.showAllAdmin();
//request作用域存储数据
req.setAttribute("admins", adminList); //键值对,admins存的是adminList集合
//通过转发 跳转到显示结果servlet
req.getRequestDispatcher("/showalljsp").forward(req, resp);
}else {
resp.sendRedirect("/WebProject_war_exploded/loginMgr.html");
}
}
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注销登录的Servlet:
package com.qf.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LogoutServlet
*/
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LogoutServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//清空session
session.invalidate();
//重定向到login。html
response.sendRedirect("login.html");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
生成验证码:
package com.qf.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import cn.dsna.util.images.ValidateCode;
/**
* Servlet implementation class CodeController
*/
@WebServlet("/code")
public class CodeController extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public CodeController() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* width:验证码的宽度
* height:验证码图片的告诉
* codeCount:验证码的个数
* lineCount:干扰线
*/
ValidateCode vc=new ValidateCode(200, 50, 5, 20);
String code = vc.getCode();
HttpSession session = request.getSession();
session.setAttribute("code", code);
System.out.println("生成的随机验证码是:"+code);
vc.write(response.getOutputStream());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
总结:
在之前的学习中,request和session是servlet一个对象,他们都可以调用set/getAttrbute();,所以有一种说法,他们也是一个容器对象。但是request容器的作用范围是资源转发的过程中,两个资源之间可以实现数据共享
sesssion这个容器他的作用范围是同一个用户的一次会话(多个请求之间)
有一个容器比session的作用范围还要大,他的作用范围是服务器打开和关闭的过程中,所有的用户可以共享
ServletContext: Servlet上下文,代表当前整个应用程序。全局对象,也拥有作用域,对应一个Tomcat中的Web应用
ServletContext:Servlet上下文。
当WEB服务器启动时,会为每一个WEB应用程序(webapps下的每个目录就是一个应用程序)创建一块共享的存储区域
ServletContext也叫做“公共区域”,也就是同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。
ServletContext在WEB服务器启动时创建,服务器关闭时销毁。
方式一:GenericServlet提供了getServletContext()方法。(推荐)
ServletContext servletContext = this.getServletContext();
方式二:ServletConfig提供了getServletContext()方法。
方式三:HttpSession提供了getServletContext()方法。
HttpSession session = request.getSession();
ServletContext servletContext2 = session.getServletContext();
方式四:HttpServletRequest提供了getServletContext()方法。(推荐)
ServletContext servletContext1 = request.getServletContext();
作用:
1、获取真实路径
获取当前项目的发布路径
request.getServletContext().getRealPath("/");
2、获取容器的附加信息
System.out.println(request.getServletContext().getServerInfo());
获取项目上下文路径(应用程序名称)
System.out.println(request.getServletContext().getContextPath());
System.out.println(request.getContextPath());
3、全局容器
//设置信息到全局容器中
request.getServletContext().setAttribute("msg", "共享信息");
//获取数据
System.out.println(request.getServletContext().getAttribute("msg"));
//移除数据
request.getServletContext().removeAttribute("msg");
特点:
唯一性: 一个应用对应一个servlet上下文。
一直存在: 只要容器不关闭或者应用不卸载,servlet上下文就一直存在。
web.xml文件配置servletContext参数
appname
xxx管理系统
appversion
2.0
//获取servlet上下文参数
String appname=application.getInitParameter("appname");
String appversion=application.getInitParameter("appversion");
System.out.println(appname+"..."+appversion);
package com.pzy.counter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "CounterController",value = "/counterController")
public class CounterController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取ServletContext对象
ServletContext servletContext = request.getServletContext();
//2、获取计数器
Integer counter =(Integer)servletContext.getAttribute("counter");
if (counter == null){
counter = 1;
servletContext.setAttribute("counter", counter);
}else {
counter++;
servletContext.setAttribute("counter", counter);
}
System.out.println("被访问了:"+counter+"次");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
1 Cookie:客户端状态管理,保存一小段信息,第一次访问时服务器,服务器cookie响应给浏览器,下次再访问服务器时,把cookie回传给服务器,服务器收到cookie。
Cookie cookie=new Cookie("xxx","141241232");
cookie.setMaxAge(); 默认-1 保存在内存中, 0 表示失效 正数 过期时间 单位是秒
cookie.setPath();设置有效路径,默认 /项目名 cookie.setPath("/)
response.addCookie(cookie);
2 session:服务器端状态管理,是一个map集合,session使用sessionid区别,服务器会把SessionId作为cookie的值发送给浏览器,浏览器再次访问服务器时,服务器读取到cookie(sessionid)。
保存登录信息,购物车
HttpSession session=request.getSession();
在以往的Servlet中,有冗余的代码,多个Servle需要进行编写
概念
过滤器(Filter)是处于 客户端与服务器目标资源之间的一道过滤技术。
作用
执行地位在Servlet之前,客户端发送请求时,会先经过Filter,再到达目标Servlet中;响应时,会根据执行流程再次反向执行Filter
可以解决多个Servlet共性代码的冗余问题(例如:乱码处理、登录验证)
Servlet API中提供了一个Filter接口,开发人员编写了一个Java类实现了这个接口即可。
这个Java类称之为过滤器(Filter)
实现过程:
编写Java类实现Filter接口
在doFilter方法中编写拦截逻辑
设置拦截路径
package com.pzy.filter;
@WebServlet(name = "TargetServlet", value = "/t")
public class TargetServlet extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("--target");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
package com.pzy.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(value = "/t")
public class MyFilter implements Filter {
@Override
public void init (FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截了");
//让请求继续
filterChain.doFilter(servletRequest, servletResponse);
//响应拦截
System.out.println("拦截结束");
}
@Override
public void destroy ( ) {
}
}
注解配置
@WebFilter(value = "/过滤目标资源")
xml配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dv8U3Zym-1652089994453)(C:\Users\DELL\Desktop\笔记图片库\第二阶段\过滤器xml配置.png)]
拦截路径
精确拦截匹配 /index.jsp /myservlet1
后缀拦截匹配 *.jsp *.html *.jpg
通配符拦截匹配 /* 表示拦截所有,注意过滤器不能使用/匹配
/aaa/bbb/*允许
客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就成为一条过滤器链
每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则Web服务器会检查FilterChain对象中是否还有filter。如果有,则调用第二个Filter,如果没有则调用目标资源
package com.pzy.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(value = "/*")
public class EncodingFilter implements Filter {
@Override
public void init (FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//统一处理请求和响应的乱码
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset = utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy ( ) {
}
}
package com.pzy.servletProject.filter;
import com.pzy.servlet.HttpsServlet;
import com.pzy.servletProject.entity.Manager;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(value = "/showallcontroller")
public class CheckFilter implements Filter {
@Override
public void init (FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//权限验证,验证管理员是否登录!
//得到session需要HttpServlet 那就要向下转型,拆箱
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session =request.getSession();
Manager mgr =(Manager)session.getAttribute("mgr");
if (mgr!=null){
//登陆过,放过去
filterChain.doFilter(request, response);
}else {
response.sendRedirect(request.getContextPath()+"/loginMgr.html");
}
}
@Override
public void destroy ( ) {
}
}
使用两张表,EMP员工信息表,EmpManager管理员表
创建数据库、数据表
CREATE DATABASE EMS;
CREATE TABLE EMP(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
salary DOUBLE NOT NULL,
age INT NOT NULL
)CHARSET= utf8;
CREATE TABLE EmpManager(
username VARCHAR(20) PRIMARY KEY,
password VARCHAR(20) NOT NULL
)CHARSET=utf8;
INSERT INTO emp(name,salary,age) VALUES('tom',8000,20);
INSERT INTO emp(name,salary,age) VALUES('jerry',10000,20);
INSERT INTO emp(name,salary,age) VALUES('fpz',18000,22);
INSERT INTO empmanager(username,PASSWORD) VALUES('root','root');
创建Web项目
导入相关jar包,到web下WEB-INF中的lib中
数据库连接配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ems?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
/*数据库连接池的相关配置
初始容量给 10 个
最大的连接数量为 20
最小空闲连接 为 5个
超时:3000*/
initialSize=10
maxActive=20
minIdle=5
maxWait=3000
com.pzy,ems.utils 存放数据库连接工具类
com.pzy,ems.entity 实体类
com.pzy,ems.dao 数据访问层
com.pzy,ems.service 业务逻辑层
com.pzy,ems.controller 调用业务逻辑的Servlet
com.pzy,ems.jsp 显示页面的Servlet
com.pzy,ems.dao.impl 数据访问层实现类
com.pzy,ems.service.impl 业务逻辑层实现类
DbUtils
package com.pzy.ems.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DbUtils {
private static DruidDataSource ds; //数据库连接池
private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>(); //控制事物,用Connection来存储
static {
Properties properties = new Properties(); //创建一个Properties集合
InputStream inputStream = DbUtils.class.getResourceAsStream("/database.properties");
try {
properties.load(inputStream); //把文件加载进来
ds =(DruidDataSource) DruidDataSourceFactory.createDataSource(properties); //把配置文件给进去
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection connection = THREAD_LOCAL.get();
try {
if (connection == null){
connection = ds.getConnection();
THREAD_LOCAL.set(connection);
}
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
public static void begin(){
Connection connection = null;
try {
connection = getConnection();
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void commit(){
Connection connection = null;
try {
connection = getConnection();
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeAll(connection,null,null);
}
}
public static void rollback(){
Connection connection = null;
try {
connection = getConnection();
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeAll(connection,null,null);
}
}
//释放资源的方法
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet){
try {
if (resultSet != null){
resultSet.close();
}
if (statement != null){
statement.close();
}
if (connection != null){
connection.close();
THREAD_LOCAL.remove();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
EmpManager(管理员实体类)
package com.pzy.ems.entity;
public class EmpManager {
private String username;
private String password;
public EmpManager ( ) {
}
public EmpManager (String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername ( ) {
return username;
}
public void setUsername (String username) {
this.username = username;
}
public String getPassword ( ) {
return password;
}
public void setPassword (String password) {
this.password = password;
}
@Override
public String toString ( ) {
return super.toString();
}
}
Emp(员工实体类)
package com.pzy.ems.entity;
public class Emp {
private int id;
private String name;
private double salary;
private int age;
public Emp ( ) {
}
public Emp (int id, String name, double salary, int age) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
}
public int getId ( ) {
return id;
}
public void setId (int id) {
this.id = id;
}
public String getName ( ) {
return name;
}
public void setName (String name) {
this.name = name;
}
public double getSalary ( ) {
return salary;
}
public void setSalary (double salary) {
this.salary = salary;
}
public int getAge ( ) {
return age;
}
public void setAge (int age) {
this.age = age;
}
}
EmpManagerDao
package com.pzy.ems.dao;
import com.pzy.ems.entity.EmpManager;
public interface EmpManagerDao {
//登录功能,要完成查询方法
public EmpManager select(String username);
}
EmpDao
package com.pzy.ems.dao;
import com.pzy.ems.entity.Emp;
import java.util.List;
public interface EmpDao {
//查询所有员工
public List<Emp> selectAll();
//删除
public int delete(int id);
//修改
public int update (Emp emp);
//查询单个员工
public Emp select(int id);
}
EmpManagerDaoImpl
package com.pzy.ems.dao.impl;
import com.pzy.ems.dao.EmpManagerDao;
import com.pzy.ems.entity.EmpManager;
import com.pzy.ems.utils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
public class EmpManagerDaoImpl implements EmpManagerDao {
//用QueryRunner 来执行sql语句
private QueryRunner queryRunner = new QueryRunner();
@Override
public EmpManager select (String username) {
try {
EmpManager empManager = queryRunner.query(DbUtils.getConnection(), "select * from empmanager where username =?;", new BeanHandler<EmpManager>(EmpManager.class), username);
return empManager;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
EmpDaoImpl
package com.pzy.ems.dao.impl;
import com.pzy.ems.dao.EmpDao;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.entity.EmpManager;
import com.pzy.ems.utils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;
public class EmpDaoImpl implements EmpDao {
//用QueryRunner 来执行sql语句
private QueryRunner queryRunner = new QueryRunner();
@Override
public List<Emp> selectAll(){
try {
List<Emp> emps = queryRunner.query(DbUtils.getConnection(), "select * from emp;", new BeanListHandler<Emp>(Emp.class));
return emps;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public int delete (int id) {
try {
int result = queryRunner.update(DbUtils.getConnection(), "delete from emp where id = ?;", id);
return result;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int update (Emp emp) {
try {
int result = queryRunner.update(DbUtils.getConnection(), "update emp set name=?,salary=?,age=? where id = ?", emp.getName(), emp.getSalary(), emp.getAge(), emp.getId());
return result;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public Emp select (int id) {
try {
Emp emp = queryRunner.query(DbUtils.getConnection(), "select * from emp where id =?;", new BeanHandler<Emp>(Emp.class), id);
return emp;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
EmpManagerService
package com.pzy.ems.service;
import com.pzy.ems.entity.EmpManager;
public interface EmpManagerService {
//登录方法
public EmpManager login(String username);
}
EmpService
package com.pzy.ems.service;
import com.pzy.ems.entity.Emp;
import java.util.List;
public interface EmpService {
//显示所有员工
public List<Emp> showAllEmp();
//删除员工
public int removeEmp(int id);
//修改员工信息
public int modify (Emp emp);
//显示单个用户信息
public Emp showEmp(int id);
}
EmpManagerServiceImpl
package com.pzy.ems.service.impl;
import com.pzy.ems.dao.EmpManagerDao;
import com.pzy.ems.dao.impl.EmpManagerDaoImpl;
import com.pzy.ems.entity.EmpManager;
import com.pzy.ems.service.EmpManagerService;
import com.pzy.ems.utils.DbUtils;
public class EmpManagerServiceImpl implements EmpManagerService {
//需要使用到EmpManagerDao对象
private EmpManagerDao empManagerDao = new EmpManagerDaoImpl();
@Override
public EmpManager login (String username,String password) {
EmpManager empManager = null;
try {
DbUtils.begin();
EmpManager temp = empManagerDao.select(username);
if (temp!=null){
if (temp.getPassword().equals(password)){
empManager = temp;
}
}
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return empManager;
}
}
EmpServiceImpl
package com.pzy.ems.service.impl;
import com.pzy.ems.dao.EmpDao;
import com.pzy.ems.dao.impl.EmpDaoImpl;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.service.EmpService;
import com.pzy.ems.utils.DbUtils;
import java.util.ArrayList;
import java.util.List;
public class EmpServiceImpl implements EmpService {
private EmpDao empDao = new EmpDaoImpl();
@Override
public List<Emp> showAllEmp ( ) {
List<Emp> emps =new ArrayList<>();
try {
DbUtils.begin();
List<Emp> temps = empDao.selectAll();
if (temps!=null){
emps = temps;
}
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return emps;
}
@Override
public int removeEmp (int id) {
int result = 0;
try {
DbUtils.begin();
result = empDao.delete(id);
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return result;
}
@Override
public int modify (Emp emp) {
int result = 0;
try {
DbUtils.begin();
result = empDao.update(emp);
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return result;
}
@Override
public Emp showEmp (int id) {
Emp emp = null;
try {
DbUtils.begin();
emp = empDao.select(id);
DbUtils.commit();
} catch (Exception e) {
DbUtils.rollback();
e.printStackTrace();
}
return emp;
}
}
EmpManagerLoginController
package com.pzy.ems.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(value = "/manager/EmpManagerLoginController")
public class EmpManagerLoginController extends HttpServlet {
@Override
protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、收参
String username = req.getParameter("username");
String password = req.getParameter("password");
String inputVcode = req.getParameter("inputVcode");
//2、写完CreateCodeController后 回来校验验证码
String codes = (String) req.getSession().getAttribute("codes");
if (!inputVcode.isEmpty() && inputVcode.equalsIgnoreCase(codes)){
//调用业务逻辑实现登录
EmpManagerService empManagerService = new EmpManagerServiceImpl();
EmpManager empManager = empManagerService.login(username, password);
if (empManager!=null){
//登录成功
//存储在session作用域中
HttpSession session = req.getSession();
session.setAttribute("empManager", empManager);
//跳转到查询所有的controller
resp.sendRedirect(req.getContextPath()+"/manager/safe/showAllEmpController");
}else {
resp.sendRedirect(req.getContextPath()+"/login.html");
}
}else {
//验证码输入错误,跳转到登录页面
resp.sendRedirect(req.getContextPath()+"/login.html");
}
}
}
CreateCodeController
package com.pzy.ems.controller;
import cn.dsna.util.images.ValidateCode;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(name = "CreateCodeController",value = "/createCode")
public class CreateCodeController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ValidateCode validateCode = new ValidateCode(200, 30, 4, 10);
String codes = validateCode.getCode();
HttpSession session = request.getSession();
session.setAttribute("codes", codes);
//响应给客户端
validateCode.write(response.getOutputStream());
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ShowAllEmpController
package com.pzy.ems.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//把所有用到权限验证的资源放到manager下的safe,也为了后续的删除修改做准备
@WebServlet(name = "ShowAllEmpController" ,value = "/manager/safe/showAllEmpController")
public class ShowAllEmpController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//把权限验证的代码放在filter层中,直接业务逻辑的调用 ,把所有用到权限验证的资源放到manager下的safe
EmpService empService = new EmpServiceImpl();
List<Emp> emps = empService.showAllEmp();
request.setAttribute("emps", emps);
request.getRequestDispatcher("/manager/safe/showAllEmpJSP").forward(request, response);
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
RemoveEmpController
package com.pzy.ems.controller;
import com.pzy.ems.service.EmpService;
import com.pzy.ems.service.impl.EmpServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "RemoveEmpController" ,value = "/manager/safe/removeEmpController")
public class RemoveEmpController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer id = Integer.valueOf(request.getParameter("id"));
EmpService empService = new EmpServiceImpl();
empService.removeEmp(id);
//然后重新加载显示页面
response.sendRedirect(request.getContextPath()+"/manager/safe/showAllEmpController");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ShowEmpController
package com.pzy.ems.controller;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.service.EmpService;
import com.pzy.ems.service.impl.EmpServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//负责拿到id查询到员工的最新信息, 运用的业务逻辑要在dao层写select方法
@WebServlet(name = "ShowEmpController", value = "/manager/safe/showEmpController")
public class ShowEmpController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer id = Integer.valueOf(request.getParameter("id"));
EmpService empService = new EmpServiceImpl();
Emp emp = empService.showEmp(id);
//需要把上面的得到数据放到修改页面中
request.setAttribute("emp", emp);
request.getRequestDispatcher("/manager/safe/showUpdateEmpInfoJSP").forward(request, response);
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
UpdateEmpController
package com.pzy.ems.controller;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.service.EmpService;
import com.pzy.ems.service.impl.EmpServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "UpdateEmpController" , value = "/manager/safe/updateEmpController")
public class UpdateEmpController extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、收参
Integer id = Integer.valueOf(request.getParameter("id"));
String name = request.getParameter("name");
Double salary = Double.valueOf(request.getParameter("salary"));
Integer age = Integer.valueOf(request.getParameter("age"));
Emp emp = new Emp(id, name, salary, age);
EmpService empService = new EmpServiceImpl();
empService.modify(emp);
response.sendRedirect(request.getContextPath()+"/manager/safe/showAllEmpController");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
CheckFilter
package com.pzy.ems.filter;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.entity.EmpManager;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(value = "/manager/safe/*")
public class CheckFilter implements Filter {
@Override
public void init (FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//向下转型
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession();
EmpManager empManager = (EmpManager)session.getAttribute("empManager");
if (empManager!=null) {
//登录过
filterChain.doFilter(request, response);
}else{
response.sendRedirect(request.getContextPath()+"/login.html");
}
}
@Override
public void destroy ( ) {
}
}
EncodingFilter
package com.pzy.ems.filter;
import com.sun.org.apache.regexp.internal.RE;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
//过滤manager下的所有资源
@WebFilter(value = "/manager/*")
public class EncodingFilter implements Filter {
@Override
public void init (FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy ( ) {
}
}
ShowAllEmpJSP
package com.pzy.ems.jsp;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.entity.EmpManager;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@WebServlet(name = "ShowAllEmpJSP" , value = "/manager/safe/showAllEmpJSP")
public class ShowAllEmpJSP extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取集合数据、管理员信息
List<Emp> emps = (List<Emp>) request.getAttribute("emps");
HttpSession session = request.getSession();
EmpManager empManager = (EmpManager) session.getAttribute("empManager");
PrintWriter printWriter = response.getWriter();
printWriter.println("");
printWriter.println("");
printWriter.println("");
printWriter.println("查询所有员工页面 ");
printWriter.println("");
printWriter.println("");
printWriter.println("欢迎你,管理员:"
+ empManager.getUsername()+"");
printWriter.println("");
printWriter.println("");
printWriter.println("编号 ");
printWriter.println("姓名 ");
printWriter.println("工资 ");
printWriter.println("年龄 ");
printWriter.println("操作 ");
printWriter.println(" ");
for (Emp emp : emps) {
printWriter.println("");
printWriter.println("" + emp.getId()+" ");
printWriter.println("" + emp.getName()+" ");
printWriter.println("" + emp.getSalary()+ " ");
printWriter.println("" + emp.getAge()+" ");
printWriter.println("删除 ");
printWriter.println("+request.getContextPath()+"/manager/safe/showEmpController?id="+emp.getId()+">修改 ");
printWriter.println(" ");
}
printWriter.println("");
printWriter.println("");
printWriter.println("");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ShowUpdateEmpInfoJSP
package com.pzy.ems.jsp;
import com.pzy.ems.entity.Emp;
import com.pzy.ems.entity.EmpManager;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "ShowUpdateEmpInfoJSP" , value = "/manager/safe/showUpdateEmpInfoJSP")
public class ShowUpdateEmpInfoJSP extends HttpServlet {
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Emp emp = (Emp)request.getAttribute("emp");
HttpSession session = request.getSession();
EmpManager empManager = (EmpManager) session.getAttribute("empManager");
PrintWriter printWriter = response.getWriter();
printWriter.println("");
printWriter.println("");
printWriter.println("");
printWriter.println("修改员工信息页面 ");
printWriter.println("");
printWriter.println("");
printWriter.println("欢迎你,管理员:"
+ empManager.getUsername()+"");
printWriter.println(");
printWriter.println(" 编号:");//value放的是默认数据
printWriter.println(" 姓名:");
printWriter.println(" 工资:");
printWriter.println(" 年龄:");
printWriter.println(" ");
printWriter.println(");
printWriter.println("");
printWriter.println("");
}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
登录页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>管理员登录title>
head>
<body>
<form action="/EMS/manager/EmpManagerLoginController" method="post">
<h1>管理员登录h1>
用户名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
验证码:<input type="text" name="inputVcode"/><img src="/EMS/createCode"><br/>
<input type="submit" value="登录"/>
form>
body>
html>
流程说明
查询所有员工信息
如果非法访问,从showAllEmpController的路径下访问,会通过过滤器过滤到登录页面,然后进入到我们的showAllEmpController,在这里面调用业务逻辑查询到我们的数据在集合emps中,把它放到request作用域中然后请求转发到showAllEmpJSP,然后向客户端打印一个页面,显示所有员工数据
修改操作
修改的时候为了防止安全问题(两个管理员都在一定时间内改了某个数据),那就应该在每次修改过后就做一次查询
你可能感兴趣的:(笔记,java)