第一章 EMMET语法
1. syntax 快捷键介绍
Child : >相当于创建子标签
nav>ul>li
<nav><ul><li></li></ul></nav>
Subling : +
相当于创建平级标签
div+p+bq
<div></div><p></p><blockquote></blockquote>
Climb-up : ^
相当于创建了与父标签同级的标签
div+div>p>span+em^bq
<div></div><div><p><sapn><em></em></sapn></p><blockquote></blockquote></div>
div+div>p>span+em^^bq
<div></div><div><p><sapn><em></em></sapn></p> </div><blockquote></blockquote>
Group: ()
div>(header>ul>li*2>a)+footer>p
<div><header><ul><li></li><li></li></ul></header><footer><p></p></footer></div>
(div>dl>(dt+dd))+footer>p
<div><dl><dt></dt><dd></dd></dl></div><footer><p></p></footer>
Item number: $
*ul>li.item$2
<ul><li class="item1"></li><li class="item2"></li></ul>
<!--h$[title=item$]{Header $}*3--><h1 title="item1">Header 1</h1><h2 title="item2">Header 2</h2><h3 title="item3">Header 3</h3>
*ul>li.item$$$2
<ul><li class="item001"></li><li class="item002"></li></ul>
*ul>li.item$@-2
<!--倒序的--><ul><li class="item2"></li><li class="item1"></li></ul>
ul>li.item$@3*2
<!--从三开始数两个数--><ul><li class="item3"></li><li class="item4"></li></ul>
ID and Class attributes
#header
<div id=“#header”></div>
.title
<div class="title"></div>
form#search.wide
<form id="#search" class="wide"></form>
p.class1.class2.class3
<p class="class1 class2 class3"></p>
Custom attributes
p[title=“Hi”]
<p title="Hi"></p>
td[rowspan=2 colspan=3 title]
<td rowspan="2" colspan="3" title=""></td>
[a=‘value1’ b=“value2”]
<div a="value1" b="value2"></div>
Text
a{Click me}
<a href=""> Cilck me</a>
p>{Click }+a{here}+{to continue}
<p>Click <a href="">here</a> to continue</p>
第二章 HTML简介
浏览器内核
1. 注释
<!--此为html的注释书写方式html文件以.html和.htm为后缀,全文不区分大小写具有较高的容错性,浏览器具有一个标签解析器和脚本解析器,从上往下解析用户书写的html页面,如果出现严重的错误,则无法显示相应的结构和样式在html页面上主要存在以下三种结构(html)页面上有什么 一个人身高 体型 素颜样式(css html*) 页面有的这个东西是什么样子的 打扮化妆以后的样子动作(js) 页面上能够具有什么操作 这个人的谈吐举止在1996年css出现之前html也能够渲染页面样式,之后样式被css取代以下第一句为DTD信息,规定了整个页面使用的是第几版的html规范,可以使用哪些标签,哪些标签不能使用,此处使用的是html5,从第五版开始,dtd不再发生改变,如果不书写DTD,则默认使用4.01版本-->
2.根标签
的根标签,在html和xml中都有且仅有一个根标签,嵌套在最外层lang属性可选,用来描述当前页面是何种语言的网页en为英文网页,此处比对我们的操作系统的地区,如果不一致,则google翻译提示是否进行翻译3. 一级子元素
1. head
head:一级子元素,也可以称之为html标签的子元素,用来设置
页面的头信息,例如标签,编码,引入的js css等
注意书写规范为,子标签必须在父标签向右一个制表符
meta
meta:此标签可以设置页面的编码,关键字,描述等;此处为设置编码,如果不指明编码则可能会导致页面的乱码
title
用来设置页面的标题,支持中文
2.footer
addressh5新增标签,表示页脚,用来放置作者信息 网站版权 法律合作信息等
用来存地址等信息
4.其他元素
headersectionh5新增标签,表示页眉,一般放置页面的标题,搜索栏导航栏等元素
formh5新增标签,表示整个页面中主体部分,放置完整的文章等
label表单元素,此元素可以通过嵌套在内部的各种表单项元素以键值对的形式收集用户填写的信息,例如用户名 密码 等等;当表单提交时,最终将信息提交到action设置的目的地
action:属性表示表单提交到的目的地
method:提交表单的方式,存在get和post两种方式
input用来设置表单项外的文本,for属性对应表单项中的id属性
5. HTML部分标签列表
因为有Typroa支持部分的HTML标签,因此部分显示不出来的标签会在前边加上空格,让大纲显示该标签以下仅仅是个人学习是学到的标签及标签内的部分属性,全部标签请移步W3C/tags/tag_doctype.aspHTML注释<!--这是一段注释,注释不会再浏览器中显示-->
<!DOCTYPE>
DTD信息规定了整个页面使用的是第几版的html规范,可以使用哪些标签,哪些标签不能使用,此处使用的是html5,从第五版开始,DTD不再发生改变,如果不书写DTD,则默认使用4.01版本
< a>
超链接< address>
用来书写地址等信息< body>
页面的正文,所有的结构样式都写在body元素中< br>换行
< center>
包含的内容强制居中,建议使用CSS代替< div>
div: 此元素相当于一个容器,div元素结束后自动换行最外层的 div一般设置一个id=“container”,表示容器< footer>
html5新增标签,表示页脚,通常用来放置作者信息,网站版权,法律合作信息等< form>
表单元素,通过巧挑在内部的各种表单元素以键值对的形式手机用户填写的信息,例如用户名,密码等
表单提交时 GET 和 POST两种提交方式的不同
GET :get 提交表单的速度较快。安全性低,通过浏览器的地址栏进行传输
格式:目的地 ?key=value&key2=value2&keyN=valueN
最多传递256个字符,不支持中文仅仅支持字符串
如果使用链接提交则肯定为GET
POST :post 提交速度慢,安全性高,不通过浏览器的地址栏传递,无法从地址栏发现用户书写的内容,通过消息体传递值,格式与get一致,同样不支持中文,但是没有大小限制,如果进行上传操作必须使用post,链接提交无法使用post,必须用get
< h1> - < h6>
标题,h1字体最大,h6最小,和typora的大纲标题一个样< head>
用来设置页面的头部信息,例如标签,编码,引入等可以包含的标签有 ,,< header>
html5新增的标签表示页眉,一般放置页面的标题,搜索框导航栏等< hr>
分割线,一般是一条线可以设置宽度的颜色width有设置像素值和百分比两种形式,建议用css代替< html>
html的根标签,在html和xml中都有且只有一个根标签,嵌套在最外层< label>
用来设置表单项外的文本,for属性对象表单项中的id属性< input>
< meter>
进度条兼容性较差< option>
下拉框的选项,selected选项代表默认选中需要个标签配合使用< select>
下拉框,需要个标签配合使用<label for="locationid">归属地</label><select name="location" id="locationid"><option value="huibei">湖北</option><option value="sichuan">四川</option></select>
< textarea>
多行文本输入框6.特殊字符
第三章 XML
1. XML规范
xml的API开发文档与HTML文档一致头信息之前不能书写任何字符全文小写,无容错性在HTML中,首行为一个DTD信息,这个DTD规范了全文为那种版本的html,可以使用那些标签,出现多少次,不能使使用哪些标签,如果不写则默认4.01DTDxml默认不存在DTD,如果用户不写DTD,则全文无DTD,标签可以随意书写,支持中文2. XML标签
1. CDATA[]
<![CDATA[ 在嵌套在此格式之后,用户书写的空格,换行,特殊字符 都可以被正确的识别,不需要转义字符进行转义 CDATA一般嵌套SQL语句,当封装SQL语句时, 如果空格换行特殊字符不能正确识别,则可能会出现错误 ]]>
<我是根元素><student id="et001" name="elena"><hobby>购物</hobby><hobby>跑步</hobby><location>济南</location><info>来自济南的elena非常喜欢购物和跑步><'"&</info></student><student id="et002" name="penny"><hobby>睡觉</hobby><hobby>吃饭</hobby><location>青岛</location><info><![CDATA[来自青岛的penny非常喜欢吃饭><'"&> < ' " &]]></info></student></我是根元素>
2. 内部DTD
2.1 元素<!ELEMENT>
将DTD文件和xml文件书写在一些,用来约束全文可以使用哪些标签,不能使用那些标签]>
*:表示此元素可以出现任意多个,也可以不出现
如果元素后面没有书写任何标识符,则表示元素只能书写一次,也不能不出现
元素,元素,元素:注意这里严格区分先后顺序,必须按照逗号的分割排列元素
(元素1|元素2|元素N):枚举写法,表示其中任选其一
?:可以出现0个或者1个
+:至少一个上不封顶
(#PCDATA):表示元素中可以书写任意字符串,不再嵌套子元素
ANY:元素中可以是任意字符串,也可以再有子元素
(#PCDATA|元素名)*:表示元素中可以是任意字符串,也可以再次嵌套
特定元素,也可以两者同时存在
EMPTY:表示空元素,元素中不能存在子元素,也没有字符串
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE 学生信息[<!ELEMENT 学生信息 (student*)><!ELEMENT student (name,age,(location|home),hobby*,gf?,teacher+,job*,criminal)><!ELEMENT name (#PCDATA)><!ELEMENT age (#PCDATA)><!ELEMENT location (#PCDATA)><!ELEMENT home (#PCDATA)><!ELEMENT hobby ANY><!ELEMENT gf (#PCDATA)><!ELEMENT teacher (#PCDATA)><!ELEMENT job (#PCDATA|secondJob)*><!ELEMENT secondJob (#PCDATA)><!ELEMENT criminal EMPTY>]><学生信息><student><name>elena</name><age>23</age><location>济南</location><hobby>游戏</hobby><hobby>购物</hobby><gf>damon</gf><teacher>aleric</teacher><teacher>tom</teacher><job>软件工程师<secondJob>特工</secondJob></job><criminal /></student></学生信息>
2.1 属性<!ATTLIST>
使用内部DTD来约束元素的属性
<!ATTLIST 依附元素名 属性名 属性值类型 默认值类型>
ID:表示这个属性全文唯一,不能重复,不能以数字开头
CDATA:表示属性值可以是任意字符串
(数据1|数据2|数据N):表示默认值任选其一
#REQUIRED:表示默认值必须书写不能不写
#IMPLIED:表示默认值爱写不写
#FIXED:属性值固定,为后面的默认值,不得更改,存在浏览器差异性
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE 学生信息 [<!ELEMENT 学生信息 (student*)><!ELEMENT student (name,age)><!ATTLIST student sid ID #REQUIRED><!ATTLIST student home CDATA #IMPLIED><!ATTLIST student salary (10k|12k|14k) "12k"><!ATTLIST student job CDATA #FIXED "软件工程师"><!ELEMENT name (#PCDATA)><!ELEMENT age (#PCDATA)>]><学生信息><student sid="et001" home="济南" salary="12k"job="软件工程师"><name>elena</name><age>23</age></student></学生信息>
3. 外部DTD
拓展名为.dtd,是一个独立的文件,不需要书写<!DOCTYPE>标签<?xml version="1.0" encoding="utf-8" ?><!ELEMENT student (name,age)><!ELEMENT name (#PCDATA)><!ATTLIST name id ID #REQUIRED><!ELEMENT age (#PCDATA)>
引入DTD存在以下两种方式
本地方式:网络方式:
<?xml version="1.0" encoding="UTF-8" ?><!--本地方式导入DTD文件--><!DOCTYPE student SYSTEM "outterDTD4.dtd"><student><name id="et001">penny</name><age>23</age></student>
第四章 CSS
1. CSS简介
CSS(Cascading style Sheet) 层叠样式表CSS注释与java多行注释一样都为 /**/1. 三种引入css的方式
内嵌式直接将css代码写在head标签内,是一种优缺点都不是很明显的书写方式,在 style 标签内只能书写 css 代码,不能写html标签
<style>*{margin:0;}</style>
外链式
通过 link 标签引入一个独立的css文件到本页面,rel表示引入的是一个样式表,href表示引入的css文件路径,这种方式被普遍使用
<link rel="stylesheet" href="./css/style.css">
行内式
在标签内直接书写css,这种方式严重违背了解耦结构和样式的原则; 将结构和样式再次耦合在一起,但是由于其优先级极高,所以使用较多
<div style="background-color:red"></div>
三种引入方式的优先级行内式 > 外链式和内嵌式谁放在后边,就会覆盖之前出现冲突的样式
2. CSS继承性和层叠性
继承性层叠性在 CSS中,没有任何冲突的前提下,字标签会完全继承父标签的所有css渲染设置,如果存在冲突则以字标签为准。继承特性
当多种基本选择器出现冲突时,浏览器渲染的优先级情况:
id选择器>类别选择器>标记选择器
注意以上优先级与顺序无关,如果存在行内式,则一切以行内式为准
2. CSS选择器
css选择器写的越详细越好基本选择器当多种基本选择器出现冲突时,浏览器渲染的优先级情况
id选择器>类别选择器>标记选择器
注意以上优先级与顺序无关。如果存在行内式,则一切以行内式为准
/*标记选择器*/tagName{使用标签名作为选择元素的依据,一般极少单独使用,非常容易引起误操作}p{color:red;}
类选择器
/*类选择器*/.className{根据.class属性值精确选取元素,class全文不唯一,可以随意使用}.test{color:red;}
id选择器
/*id选择器*/#idName{使用#id值来拿去元素,id全文唯一不可以出现重复}
交集选择器
/*由一个标签后边紧跟类别或者#id,必须同时满足两个条件才可以成功选取*/tagName.className{}tagName#idName{}
并集选择器
/*有多个基本或者符合选择器用都好隔开,只要返祖其中任意一个就可以成功选取*/sel1,sel2,sel3,selN{}
后代选择器
在 CSS中,没有任何冲突的前提下,字标签会完全继承父标签的所有css渲染设置,如果存在冲突则以字标签为准。继承特性
sel1 sel2 sel3 sel4{根据左祖先右后代的继承原则,可以精确的拿取具有层级关系的子元素,没有个数限制}
全选选择器
*{拿取页面的全部元素}
其他选择器
3. CSS常见元素类型
块元素(block)内联元素(inline)eg: div p h1-h6 ul li img*
这些元素结束之后自带换行,易航智能存在一个元素 ,无法横向排列,设置这写盒子的盒子模型有效,文本对齐方式无效
空元素(empty)eg:a label sapn img*
这些元素结束之后没有换行,一行可以存在多个,从左往右排列,设置这些元素的盒子模型很多参数无效,设置文本对齐方式无效
img(inline-block内联块元素)
是一种内联元素(不换行),但是具备所有块元素的特性,可以设置盒子模型等*
eg: br hr meta
这种元素一般用来设置参数或者特定的结构或者样式
通过设置display属性可以用来修改元素的类型
4. 盒子模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bhe7b6Lm-1595911803055)(D:\Study\Yitu\前端\盒子模型.png)]
1.标准文本流
在css中所有的元素在没有设置任何定位 浮动等参数的前提下,从上到下一次排列的顺序称之为标准文本流,由于大部分的元素都是块元素,所以基本上所有的元素易航智能存在一个从上往下排列
**在制作页面的时候,一般先写好html呈现标准文本流的状态,然后统一书写css,而不是html和css同时书写 **
2.盒子模型
在css中将所有的元素看作是一个具有四个边框的盒子,这些盒子按照标准文本流的形态从上往下排列,盒子的四个边框分别为外边距margin 内边距padding 边框border,通过设置border属性可以显示元素的边框
border
border:边框类型 边框粗细 边框颜色
solid单实线 double双实线 dotted点状线
margin
margin有四个属性margin-top,margin-right,margin-bottom,margin-left
/*margin的简略写法*//*--四个参数--margin: 上 右 下 左;--三个参数--margin: 上 (右下) 左;--两个参数--margin: (上下) (右左);--一个参数--margin: (上右下左);*//*最简单的网页居中方法*/margin:0 auto;
padding
padding同样遵循上述的简略写法;
不同的浏览器都设置了元素边框之间存在默认的缝隙
为了统一距离一般都要设置 *{margin:0;padding:0;}
5. 背景图和浮动
1. 背景图
/*设置背景图*/backgroud-image:url("");/*只允许从左往右排列一次*/background-repeat:repeat-x;/*设置背景图位置*/background-position:bottom;/*去除立标的标记*/ul{list-style-type:none;}
2. 浮动
块元素在不设置情况下会自动占满父元素的宽度
默认块元素会占满父元素的宽度,设置浮动之后按照设置的浮动方向进行缩小,缩小到内部的内容宽度为准,之后漂浮在页面上,原来的位置被后边的元素占据
/*左右浮动*/float:left;/*设置元素不受到其他元素浮动的影响*/clear:left;/*不受左浮动影响*/clear:right;/*不受右浮动影响*/clear:both;/*不受两侧浮动影响*/
6. 定位
1. 相对定位
元素根据原先所在位置的左上角进行定位,定位之后元素依然保持原来的类型,原来的位置也依旧被占用。偏移量 top 和 bottom 只能写一个。left 和 right 也只能写一个
/*设置为相对定位*/position:relative;/*向下偏移量300像素 距离顶部300px*/top:300px;/*向右偏移量300像素 距离左端300px*/left:300px;
2.绝对定位
元素根据其距离最近的定位过的父元素的左上角进行定位,如果元素的祖先元素都没有被定位过,则根据body也就是浏览器的左上角进行定位(这样可能会出现问题)
元素定位之后,不再保留原先的类型,不在沾满一行,漂浮在页面上,原有的位置被之后的元素占据,每对偏移量同样只能书写一个
position:absolute;top:300px;left:300px;
7.布局
1. 圣杯布局
在html4.01等之前的版本中html并没有专门的布局元素而是统一使用div进行布局
html5出现了布局元素,通常是采用圣杯布局包含header(页眉),nav(导航栏),section(网页的主体),aside(侧边栏),footer(页脚),article(放置完整的文章)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YN0Co1Tp-1595911803059)(D:\Study\Yitu\前端\css\CssDayOfficial\attachment\html5布局.jpg)]
常用属性
2. FLex布局
采用lex布局的元素,被称为Flex容器(Flex container),简称容器,子元素自动成为容器成员,成为Flex项目(Flex item),简称项目
容器默认存在两根主轴,水平方向主轴(main axis)垂直方向交叉轴(cross axis)默认项目按照主轴排列
main start/main end : 主轴开始、结束位置cross start/cross start : 交叉轴开始、结束位置main size/cross size :单个项目占据主轴、交叉轴的空间
flex-direction
决定项目的排列方向
flex-wrap
定义换行情况
flex-flow
flex-direction 和 flex-wrap的简写
justify-content
定义项目与在主轴上的对齐方式
align-items
定义在垂直方向上的对齐方式
align-content
定义多条轴线的对齐方式,如果项目只有一根轴线,该属性不起作用,所以必须设置flex-wrap:wrap;
如果不给项目设置高度,但是给容器设置align-content不为stretch时,同一轴线上的项目高度都会变为该轴线上高度最高的项目的高度。
项目属性
order
定义项目排列顺序
item{order:integer;}/*数值越小,排列的越靠前,默认为零,可以使付负数*/
flex-grow
定义项目的放大比例,默认为0,如果空间有剩余,项目也不放大,也可以是小数,按照比例占据剩余空间,数值相同则等分空间,设置为2,则占据值为1的项目空间的2倍
item{flex-grow:<数字>;}
flex-shrink
定义项目缩小比例默认值为1,如果看空间不足则等比例缩小。设置为0,则不进行缩小。如果设置了一个值为0,其他项目都为1,则当空间不足时,该项目不缩小
如果都设置为0,则当空间不足,都不缩小,项目撑破容器溢出
设置为不为0的非负数,则效果等同设置为1
item{flex-shrink:<非负整数>;}
flex-basis
定义在分配多余空间之前,项目占据的主轴空间,如果空间充足,则设置了数值的项目占据设定的空间;如果空间不足,则该项目也会缩小,小于设定值
flex
flex是flex-grow,flex-shrink,flex-basis的简写
align-self
默认为auto,表示继承父元素的align-items属性,可以单独设置align-items属性
第五章 JavaScript
1. JS简介
js => JavaScript页面脚本语言,前段三大基础之一,用来负责页面的动作
相关类库 prototype YUI Dojo Extjs ajax jQuery easyUI等
1.基本数据类型
String ,number,boolean,null,undefined
2.复合数据类型
Array,Object
3.赋值
ES5规范
var i = 3;var j = 1.1;var x = true;var y = 'etoak'/*由于js没有默认值,如果没有声明初始值,则会变成undefined,即未定义类型*/var a;
ES6规范
var赋值存在许多bug,如越级bug等。
ES6新规范中使用let赋值变量const复制常量,同时不书写分号
let i = 3i++/*字符串赋值 " 和 ' 都可以用推荐用'*/let y = 'etoak'const PI = 3.14
2. BOM七对象
在JS中,将浏览器的页面分为七大对象,每个对象存在自己的属性和激发事件BOM是browser object model的缩写,简称浏览器对象模型BOM提供了独立于内容与浏览器窗口进行交互的对象,BOM主要用于管理窗口与窗口之间的通讯,因此这个和新对象是windowBOM和DOM的区别
Document Object Model(文档对象模型),就是把「文档」当做一个「对象」来看待。
Browser Object Model(浏览器对象模型),即把「浏览器」当做一个「对象」来看待。
区别:DOM描述了处理网页内容的方法和接口,BOM描述了与浏览器进行交互的方法和接口。
在 DOM 中,文档中的各个组件(component),可以通过 object.attribute 这种形式来访问。一个 DOM 会有一个根对象,这个对象通常就是 document。而 BOM 除了可以访问文档中的组件之外,还可以访问浏览器的组件,比如问题描述中的 navigator(导航条)、history(历史记录)等等。在这种 「XOM」的模型中,最应该理解的就是 Object Model。Object Model 就表示你可以通过像操作对象一样,来操作这个 X。再解释一下什么是对象(Object)。在编程领域中,对象就是指的一种拥有具体数据(Data)并且具有(并不总是)特定行为(Behavior)的东西。例如,一个人 ,就可以看做一个对象。人的年龄、性别、身高、体重就是上文说的具体「数据」,通常将对象拥有的具体数据称作对象的「属性(Attribute)」;而人吃饭,睡觉,行走等能力,就是上文所说的「行为」,通常,我们把对象的行为称作对象的「方法(Method)」。另外,对象是可以嵌套的,也就是是说,一个对象的属性也可以是对象。上文所说的「像操作对象一样」,最主要就是指访问对象的属性和调用对象的方法。对象的属性可以通过 object.attribute 这种形式来访问,对象的方法可以通过 object.method(arguments) 这种形式来调用。对应到 DOM 中,document 这个根对象就有很多属性,例如 title 就是 document 的一个属性,可以通过 document.title 访问;document 对象也有很多方法,例如 getElementById,可以通过 document.getElementById(nodeId) 调用。
DOM 是 W3C 的标准; [所有浏览器公共遵守的标准]BOM 是 各个浏览器厂商根据 DOM
在各自浏览器上的实现;[表现为不同浏览器定义有差别,实现方式不同]window 是 BOM 对象,而非 js 对象;
3. DOM的使用
/*
* Html
* |
* DOM (文档对象模型:将正文上下文看做一个对象,全部封装在文档节点document中,
* html和xml都只有一个文档节点,也就是html)
* |
* Javascript
*
*Javascript不能直接修改页面的结构和样式
* 而必须通过文档对象模型来修改页面的结构和样式
*
* 浏览器内置两个解析器,一个是标签解析器,一个是脚本解析器,从上往下解析,如果出现解析异常则停止解析
* 通过控制台报错,如果解析无误,则将整个html文档节点封装进document中,全文只有一个文档节点
* 根据这个节点中的结构样式,创建一个文档对象模型格式如下:
*
* document
* |
* html
* |
* |
* ---------------------------------------
* | |
* | |
* head body
* | |
* ---------- ----------------------
* | | | |
* title meta button table
* |
* tr
* |
* td
* Js中的的方法可以对这个模型进行增删查改,修改之后,文档对象模型与页面实际结构和样式
* 不再统一,浏览器根据这个模型重新刷新页面,使之保持一致
* 我们这里去掉了window.onload之后那么浏览器从上往下解析,首先解析到的就是
* let domBtn = document.getElementById(‘btn’)
* 从模型中根据btn这个id拿取元素节点,可是注意window.onload前提被删除了,
* 整个页面还没有解析,模型未被创建,所以根本无法从模型中根据id拿取元素,所以报错
* 那么是不是必须书写window.onload来保证模型创建完整呢?
* 不是必须书写,通常将js脚本书写在页面body闭合标签标签之前,保证最后执行js脚本
* 优先加载html和css 并且保证模型创建完毕
1. JS实例一
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>1)如何绑定一个js函数</title><!--类似css的style标签,在此标签内书写Js脚本--><script>/*onload:激发事件之一,激发事件有很多种,此处表示页面载入无误此处和BOM内置对象一起使用表示当前窗口载入无误,那么执行一个叫做etoak的函数*/window.onload = etoak/*function:固定写法表示是一个函数注意不书写返回值,也不书写void,函数名推荐使用驼峰命名括号内为实参,可选*/function etoak(){//弹出一个对话框/*由于window是全局变量,所以所有的对象都是window的子对象所以window可以省略*/alert('青山一道同云雨,明月何曾是两乡')/*根据id属性值从全文拿取唯一节点(Node)*/let domBtn = document.getElementById('btn')/*onclick:表示单击给拿取的btn节点绑定单击事件,后面可以绑定一个有名的函数,也可以直接绑定一个匿名函数*/domBtn.onclick = function(){/*innerText:属性,拿取节点中嵌套的值,不支持标签*/alert('button元素中的文本是'+domBtn.innerText)}}</script></head><body><button id="btn">点我试试!!</button></body></html>
2.JS原理
HTML》DOM文档对象模型:将正文全文看做一个对象,全部封装在文档节点document中,html和xml都只有一个文档节点,也就是html
JavaScript**不能直接修改**页面的样式和结构而必须通过文档对象模型来修改页面的结构和样式,浏览器内置两个解析器,一个是标签解析器,一个是脚本解析器,从上往下解析,如果出现解析异常则停止解析,通过控制台报错;如果解析无误,则将整个html文档节点封装进document中,全文只有一个文档节点。根据这个节点中的结构样式
Js中的的方法可以对这个模型进行增删查改,修改之后,文档对象模型与页面实际结构和样式不再统一,浏览器根据这个模型重新刷新页面,使之保持一致。我们这里去掉了window.onload之后那么浏览器从上往下解析,首先解析到的就是let domBtn = document.getElementById(‘btn’)从模型中根据btn这个id拿取元素节点,可是注意window.onload前提被删除了,整个页面还没有解析,模型未被创建,所以根本无法从模型中根据id拿取元素,所以报错。
那么是不是必须书写window.onload来保证模型创建完整呢?
不是必须书写,通常将js脚本书写在页面body闭合标签标签之前,保证最后执行js脚本。优先加载html和css 并且保证模型创建完毕。
3.JS实例二
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>2)文档对象模型</title><style>table{width:200px;border-collapse: collapse;}table,tr,td{border:solid 2px red;}</style><script>//窗口加载无误,执行此匿名方法window.onload = function(){//根据id从全文拿取一个元素节点let domBtn = document.getElementById('btn')//当按钮单击时,执行此匿名方法domBtn.onclick = function(){//根据table标签名拿取一个元素节点列表NodeList,这个NodeList封装了所有匹配table的元素//也就是将所有标签名为table的元素,装到一个“数组”中let domTb = document.getElementsByTagName('table')[0]//控制台打印//console.log(domTb)//创建一个tr元素节点<tr></tr>let domTr = document.createElement('tr')/** 修改这个元素的节点,向内部添加文本或者超文本* innerText:向元素节点中添加文本* innerHTML:向元素节点中添加超文本* 添加前:<tr></tr>* 添加后:<tr><td style="color:coral">我是添加的一列</td></tr>* 不管是innerHTML还是innerText如果元素节点中存在节点值不管是文本还是子元素则全部被覆盖*/domTr.innerHTML = '<td style="color:coral">我是添加的一列</td>'/** 将组装好的tr追加到table中作为子元素,不影响原先的子元素** 元素节点.appendChild(子元素)* 元素节点中原先的子元素不受影响,追加到原先子元素之后*/domTb.appendChild(domTr)//通过修改style属性来间接修改页面的样式/** Math:计算内置对象,专门用来进行数学运算* Math.floor():返回小于或者等于一个给定数字的最大整数* Math.random():返回介于 0(包含) ~ 1(不包含)之间的数* */let r = Math.floor(Math.random()*255)let g = Math.floor(Math.random()*255)let b = Math.floor(Math.random()*255)/** 节点.style.样式名 = 样式值* 注意这里的样式名与CSS的样式名书写略有出入,不能出现- 必须 使用驼峰书写格式* css:background-color* js:backgroundColor* font-size ==> fontSize**///domTb.style.backgroundColor = 'rgb('+r+','+g+','+b+')'/*使用ES6提供的模板字符串来避免进行字符串的拼接`${要输出的值}`* */domTb.style.backgroundColor = `rgb(${r},${g},${b})`}}</script></head><body><button id="btn">添加一行</button><table><tr><td>我是默认存在的一列</td></tr></table><script>/** js如果放置在此处,则不需要每次都添加window.onload* 页面的加载顺序应该是* html ==> css ==>js* */</script></body></html>
4.DOM节点
DOM中共有12种节点,最为常用的试以下五种,根据节点的不同NodeType,NodeValue,NodeName三个属性也不同5.节点相关方法及常用选择器
节点相关方法
常用选择器
使用JS打印九九乘法表
<script>let str = ''for(let a = 1;a<=9;a++){for(let b = 1;b<=a;b++){str += `${b}*${a}=${b*a}\t`}str += '<br />'}document.write(str)</script>
4.JS引用
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>5)外部引入js文件</title></head><body><!--onblur:失去焦点此处函数传递的是实参-->测试1: <input type="text" name="test1"onblur="func3('测试',true,100)"/><!-- 引入独立的js文件到本页面,类似css的外链式 --><script src="./script/myjs1.js"></script><!--注意引入js文件的script标签中src表示源,后面是独立js文件的路径script标签要么引入js文件要么直接书写,不允许同时引入和书写js--><script src="./script/myjs2.js"></script></body></html>
5.使用对象字面量和构造方法创建对象
1. 对象字面量
/*对象字面量let 对象名 = {属性名:属性值,属性名:属性值,方法名:function(){}上变得是ES5的写法,简称为钩子函数ES6简化为 方法名(){}}*/let stu = {name:'赵信',age=10,hobby:['吃饭','睡觉','打豆豆'],run(){console.log(`今年${this.age}岁的${this.name}非常喜欢${this.hobby[1]}`)}}
拿取属性值
属性值 = 对象名.属性名
调用方法
对象名.方法名()
删除属性
delete 对象名.属性名/*注意此处删除的是属性,而不是属性的值*/
2. 使用构造方法创建灵活的对象
/*使用构造方法创建灵活的对象function 对象名(args1,args2){this.args1 = args1this.args2 = args2this.方法名 = function(){}}*/function person(name,age,hobby){this.name = namethis.age = agethis.hobby = hobbythis.run = function(){if(age > 18){console.log(`欢迎您回来${this.name}`)}esle{console.log(`年龄在18岁以下,禁止访问本页面`) }}}let oneperson = new person('尚朝晖',20,['游戏','学习'])console.log(`${oneperson.name}\n${oneperson.hobby[0]}`)oneperson.run()
6.数组
1. 如何创建数组
/*括号里的数字是数组的长度*//*JS中所有的length都是属性*/let arr = new Array(4)arr[0] = 100arr[1] = truearr[2] = 'etoak'arr[3] = null
2. 如何遍历数组
for循环遍历for(let i = 0;i < arr.length;i++){console.log(`数组元素值是${ar[i]}`)}
for in循环**[ES5]**
/*for(let key in arr){如果是单值类型集合,那么这个key就是索引值如果是键值对,则是属性名}*/for(let key in arr){console.log(`数组索引值是${key}`) console.log(`数组元素值是${ar[key]}`) }
for of循环**[ES6]**
/*for(let val of arr){这个val就是值}此循环不能用来迭代自己创建的js对象,因为自己创建的对象底层没有迭代器*/for(let val of arr){console.log(`数组元素值是${value}`)}
forEach
/*arr.forEach(function(被遍历的对象,索引值){注意被遍历的对象和索引值位置不能变})*/arr.forEach(function(val.index){console.log(`索引值是${index}`)console.log(`数组元素值是${value}`)})
3. 向数组添加一个元素
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>8)小练习</title><link rel="stylesheet" href="css/mystyle.css"></head><body><div id="container"><fieldset><legend>添加用户</legend><label for="nameid">姓名: <input type="text" name="name" id="nameid"placeholder="请输入姓名" minlength="4" maxlength="8"></label><label for="emailid">邮箱: <input type="text" name="email" id="emailid"placeholder="请输入邮箱"></label><label for="ageid">年龄: <input type="number" max="65" min="18" placeholder="岁" id="ageid"></label><button style="border-radius:18px;background-color:lightblue;">添加用户</button></fieldset><hr><div id="show"></div></div><script>/** 创建一个数组* */const items = [//注意level字段'1'为管理员 '0'为普通用户{id:1,name:'elena',email:'et01@',age:20,level:'0'},{id:2,name:'penny',email:'et02@',age:20,level:'0'},{id:3,name:'matt',email:'et03@',age:30,level:'0'},{id:4,name:'damon',email:'et04@',age:40,level:'0'},{id:5,name:'admin',email:'et05@',age:50,level:'1'},{id:6,name:'stefan',email:'et06@',age:55,level:'0'},{id:7,name:'aleric',email:'et07@',age:30,level:'0'},{id:8,name:'damon',email:'et08@',age:40,level:'0'},{id:9,name:'jack',email:'et09@',age:20,level:'0'}]//向数组中添加一个元素/** 数组.push(追加的元素)** 注意在Js中基本数据类型,在定义const常量之后划分内存地址,不能再次进行任何变动,* 但是在数组,对象中,虽然也划分了内存地址,但是在数组和元素中可以进行任意的增删* */items.push({id:10,name:'boonie',email:'et10@',age:23,level:'0'})onload = ()=>{//显示默认数据show()//拿取button按钮let domBtn = document.getElementsByTagName('button')[0]domBtn.onclick = ()=>{//console.log('~~~~')/** 点击添加按钮之后,表格中多出一行* id:为现有数组的长度+1* name:用户填写数据* age:用户填写数据* email:用户填写数据* level:全都是'0'* */let domInputs = document.getElementsByTagName('input')let name = domInputs[0].valuelet email = domInputs[1].valuelet age = domInputs[2].valuelet item = {id:items.length+1,/** ES6:新特性* 如果属性名和属性值重名,则直接书写即可不需要书写名值对形式* */name,email,age,level:'0'}items.push(item)//添加之后重新遍历数组show()}}//此函数用来拿取数据function show(){let table ='<table id="tb"><thead><tr><th>ID</th><th>姓名</th><th>邮箱</th><th>年龄</th><th>权限</th><th>操作</th></tr></thead><tbody>'items.forEach(item=>{//tis:表示当前行的span元素节点//this.parentNode:表示span的父节点,这里就是td元素节点//this.parentNode.parentNode:表示tr元素节点table +=`<tr><td>${item.id}</td><td>${item.name}</td><td>${item.email}</td><td>${item.age}</td><td>${item.level=='0'?'普通用户':'管理员'}</td><td><span οnclick="del(this.parentNode.parentNode)">删除</span></td></tr>`})table += '</tbody></table>'//将组装好的table放置进div中document.getElementById('show').innerHTML = table}//此函数用来删除数据function del(tr){/** 这里拿取了tbody,之后调用removeChild来删除子元素传递过来的子元素tr* */document.getElementsByTagName('tbody')[0].removeChild(tr)//tr.remove()}</script></body></html>
JS比较
在JS中字符串比较没有equals()方法,一般用不同数量的等号进行比较
ES6新特性,箭头函数
在ES6中,匿名函数可以省略为箭头函数,类似于lambda表达式,匿名函数去掉function,在参数后添加 => 如果之后一个参数,则括号省略
上述forEach可以简略为
arr.forEach(val => console.log(`数组元素值是${value}`))/*如果大括号内直接就是return语句,则大括号省略,return省略*/
7.JS常用20个字符串方法
蓝色的与Java中用法一致,红色为JS新的charAt()
/*返回对应下标的字符*/let str = '01234'alert(str.charAt(0)) //0
charCodeAt()
/*返回对应下边字符的 Unicode 编码*/let str = 'AaBb'alert(str.charCodeAt(0)) //65
concat()
/*拼接字符串,不会改变现有的字符串,返回新的字符串*/let str = 'Hello'let newStr = str.concat('World ','JavaScript')alert(newStr) // HelloWorld JavaScript
fromCharCode
/*从Unicode编码转换成字符*/alert(String.frmCharCode(72,69,76,76,79))//HELLO
indexOf
/*查找指定字符串的第一次出现的下标,如果不存在返回-1*/let str = 'HelloWorld'alert(str.indexOf('l'))//2/*从下边指定下标开始查找的方式,后边的参数是可选的*/alert(str.indexOf('l',3))//3
lastIndexOf
/*查找指定字符串最后一次出现的位置*/let str = 'HelloWorld'console.log(str.lastIndexOf('l'))//8/*指定开始搜索的位置*/console.log(str.lastIndexOf('h',5))//-1
match
/*根据正则表达式在字符串中搜索匹配项,如果没有则返回null或者信息数组*/let intRegex = /[0-9 -()+]+$/let str1 = '999'let str2 = '999 JS Coders'//'999',index:0,input:'999'group:undefinedconsole.log(str1.match(intRegex)) //nullconsole.log(str2.match(intRegex))
replace
/*在字符串中用一些字符替换另外一些字符串,或者替换一个与正则表达式匹配的字符串*/let myString = '999 JavaScript Code'//999 Jqyery Codeconsole.log(myString.replace(/JavaScript/i,'Jquery'))//The Jquery Code console.log(myString.replace(new RegExp('999','gi'),'The'))
search
8. JS函数常见书写方式
直接在标签上绑定<tagName 事件="函数1(实参)"></tagName><script>function 函数1(形参){}</script>
直接在script书写,绑定匿名
<tagName>XXX</tagName><scrript>onload = function(){let arg = 拿去元素节点arg.事件 = function(){}}</scrript>
直接在script中书写,绑定有名函数
<tagName>XXXX</tagName><script>onload = function(){let args = 拿取元素节点args..事件 = 函数名(实参)}function 函数名(形参){}</script>
直接调用函数
<tagName></tagName><script>function 函数名(形参){}函数名(实参)</script>
9.手动轮播图和验证
1.手动轮播图
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>10)简易相册</title><style>body{background-color: black;}div#container{width:830px;height:900px;margin:0 auto;}</style></head><body><div id="container"><table><caption><img src="./image/logo.png"></caption><tr><!--type="image"引入一张图片,这张图片可以点击,如果放置在form表单内,则可以提交表单--><td><input type="image" src="image/left.gif"onclick="change('left')"></td><td><img src="image/1.jpg" id="mypic"></td><td><input type="image" src="image/right.gif"onclick="change('right')"></td></tr></table></div><script>let currentPage = 1function change(flag){//拿取img元素let domImg = document.getElementById('mypic')if(flag=='left'){if(currentPage>1){currentPage--}else{alert('已经是首页了')}}if(flag=='right'){if(currentPage<6){currentPage++}else{alert('已经是末页了')}}domImg.src = `image/${currentPage}.jpg`}</script></body></html>
2. 表单验证
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>11)表单验证</title></head><body><!--对表单项进行验证onsubmit:表单提交时,如果return后面的函数返回false,则表单无法提交否则表单可以提交--><form action="wow10.html" method="get"onsubmit="return checkAll()"><!--1)单行文本输入框要求用户输入在4到8位之间--><label for="nameid">用户姓名:</label><input type="text" name="name" id="nameid" required placeholder="请输入用户姓名"autocomplete="off" onblur="checkName()" /><span id="name_msg"></span><br><label for="passid">用户密码:</label><!--this:书写在哪里就表示本元素--><input type="password" name="pass" id="passid" required placeholder="请输入用户密码"autocomplete="off" onblur="checkPass(this.value)" /><span id="pass_msg"></span><br><input type="submit" value="提交"><input type="reset" value="取消"></form><script>let flagName = falselet flagPass = falsefunction checkName(){//拿取spanlet domSp = document.getElementById('name_msg')//拿取单行文本输入框let domInput = document.getElementById('nameid')if(domInput.value.length<4||domInput.value.length>8){//添加错误提示domSp.innerHTML='<img src="image/wrong.png">用户姓名不能小于4位或者大于8位'//文字设置为红色domSp.style.color = 'red'flagName = falsereturn}domSp.innerHTML='<img src="image/right.png">用户姓名符合要求'domSp.style.color = 'green'flagName = true}function checkPass(d){//拿取spanlet domSp = document.getElementById('pass_msg')if(d.length<4||d.length>8){domSp.innerHTML='<img src="image/wrong.png">用户密码不能小于4位或者大于8位'domSp.style.color = 'red'flagPass = falsereturn}domSp.innerHTML='<img src="image/right.png">用户密码符合要求'domSp.style.color = 'green'flagPass = true}function checkAll(){return flagName&&flagPass}</script></body></html>
ES6新特性
第六章 dom4j
1. 创建lib目录
FIle -> Project Structure -> Modules -> Dependencies
点击 加号 选择1.JARs or directory选择JAR directory
2. 使用Dom4j读取xml文件
创建扫描仪SAXReader sax = new SAXReader();
创建文档对象模型
//这个对象模型就是要读取的文件DOcument doc = sax.read(new File("test.xml"));
获取根元素
Element root = doc.getRootElement();
获取一级子元素并遍历
List<Element> firstList = root.elements();for(Element firstEle : firstList){}
获取每个以及子元素的属性和值
List<Attribute> firstAttrs = firstEle.attribute();for(Attribute firstAtt : firstAttrs){sout(firstAtt.getName());sout(firstAtt.getValue());}
xml文件如下
<?xml version="1.0" encoding="utf-8" ?><root><student id="et01" name="elena"><email>et01@</email><phone>1111111</phone></student><student id="et02" name="stefan"><email>et02@</email><phone>222222</phone></student><student id="et03" name="damon"><email>et03@</email><phone>3333333</phone></student><student id="et04" name="tom"><email>et04@</email><phone>4444444</phone></student></root>
java代码如下
package com.etoak.test;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import java.io.File;import java.util.List;/*** Created by eleven on /3/17.*/public class Readxml {public static void main(String[] args) {try{//1.拿取Xml解析器,类似ScannerSAXReader sax = new SAXReader();/*2.使用SAXReader对象对xml文件进行解析如果解析无误则返回一个文档对象模型,这个文档对象模型与xml完全相同的结构*/Document doc = sax.read(new File("etoak.xml"));//3.拿取根元素Element root = doc.getRootElement();System.out.println("根元素名字是:" + root.getName());//4.拿取任意一个一级子元素List<Element> firstList = root.elements();for (Element firstEle : firstList){System.out.println("一级子元素的元素名是:" + firstEle.getName());//拿取一级子元素的属性List<Attribute> firstAttrList = firstEle.attributes();for(Attribute fisrtAttr : firstAttrList){System.out.println("属性名是:" + fisrtAttr.getName());System.out.println("属性值是:" + fisrtAttr.getValue());}//拿取二级子元素List<Element> secondList = firstEle.elements();for (Element secondEle : secondList) {System.out.println("二级子元素名字是:" + secondEle.getName());System.out.println("二级子元素内嵌套的值是:" + secondEle.getText());}}}catch(Exception e){e.printStackTrace();}}}
3.使用Dom4j创建xml文件
创建文档对象模型//这个对象模型是空的Document doc = DocumentHelper.createDocument();
添加节点
//添加根节点Element root = doc.addElement("root");//添加一级子节点Element one = root.addElement("one");//添加二级子节点Element two = one.addElement("two");//给一级子节点添加属性和值 第一个参数为属性名,第二个为属性值one.addAttribute("id","01");//给二级子元素内赋值two.setText("two");
创建流
OutputStream os = new FileOutStream("test.xml");
规定输出格式
//有缩进,跟自己写的格式一致OutputFormat format = OutputFormat.createPrettyPrint();//规定输出编码format.setEncoding("utf-8");
输出
//第一个参数为要输出文件的路径,第二个为输出的格式XMLWriter xw = new XMLWriter(os,format);//把文档对象模型输出xw.write(doc);//关闭输出xw.close();
package com.etoak.test;import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.OutputFormat;import org.dom4j.io.XMLWriter;import java.io.FileOutputStream;import java.io.OutputStream;public class WriteXml {public static void main(String[] args) {try {/** 使用Java代码利用DOM4j技术来创建一个XML* *///1)创建一个文档对象模型Document doc = DocumentHelper.createDocument();//2)创建一个根元素/** <root>* </root>* */Element root = doc.addElement("root");//3)创建一级子元素/** <root>* <student></student>* </root>* */Element student = root.addElement("student");//给一级子元素添加属性/** <root>* <student id="et001" name="elena"></student>* </root>* */student.addAttribute("id","et001");student.addAttribute("name","elena");//4)创建二级子元素/** <root>* <student id="et001" name="elena">*<email>XXXX</email>*<phone>XXXX</phone>* </student>* </root>** */Element email = student.addElement("email");email.setText("et01@");Element phone = student.addElement("phone");phone.setText("111111");//再次添加一个一级子元素/** <root>* <student id="et001" name="elena">*<email>XXXX</email>*<phone>XXXX</phone>* </student>* <person>XXXX</person>* </root>** */Element person = root.addElement("person");person.setText("我是Person中的值");//设置一个流,参数表示生成的xml叫什么输出到哪里OutputStream os = new FileOutputStream("etoak2.xml");//设置xml的格式//此处设置为标准格式,自带换行,与我们书写习惯相同,否则输出的xml从左往右不换行OutputFormat format = OutputFormat.createPrettyPrint();//设置xml文件的编码format.setEncoding("utf-8");//输出xml文件//括号内传递两个参数,第一个表示输出到哪里叫什么,第二个是格式和编码是什么XMLWriter xw = new XMLWriter(os,format);//根据拼装好的文档对象模型进行输出xw.write(doc);xw.close();} catch (Exception ex) {ex.printStackTrace();}}}
第七章 JDBC
jdbc(Java DataBase Connectivity)
在C语言的Odbc基础上发展而来,是最早的ORM(Object Relation Mapping对象映射关系)工具,可以使用面向对象的Java代码
对关系型数据库进行操作。
ORM工具随着不断的发展衍生出了很多框架那么大部分框架都是在JDBC基础上发展而来,JDBC是几乎所有框架的基础,也是效率最高的ORM工具
JDBC是第一方技术,所有的接口等全部放置在java.sql包中
全手动 JDBC
半自动 myBatis
全自动 Hibernate
1)创建关系表
2)创建实体类
A:一般放置在com.etoak.po包中或者bean包中
B:尽量使用包装类封装字段,字段名对应
C:必须书写空参构造方法,酌情覆盖有参构造方法
D:酌情覆盖toString()
3)创建工厂类
A:工厂类一般放置在com.etoak.factory包中,此类链接数据库
B:加载驱动,只需要加载一次放置在静态初始化块中
C:封装一个方法返回链接
4)书写dao层
A:dao层全部放置在com.etoak.dao包中
B:接口用来设置需要被实现的方法
C:实现类实现接口中的方法
创建数据表
DROP table if EXISTS person;CREATE table person (idINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(10) NOT NULL,pass VARCHAR(10) NOT NULL,age INT,salary DOUBLE,birth DATE);insert INTO person VALUES (null,'elena','12345',20,5000.00,'1990-06-03');insert INTO person VALUES (null,'penny','123465',30,6000.00,'1993-06-13');insert INTO person VALUES (null,'aleric','1234545',40,7000.00,'1992-06-05');insert INTO person VALUES (null,'bonnie','1432345',20,3000.00,'1996-06-03');insert INTO person VALUES (null,'matt','123345',24,15000.00,'1997-06-04');insert INTO person VALUES (null,'damon','123445',23,25000.00,'1992-06-04');insert INTO person VALUES (null,'用户名','1232245',29,5000.00,'1998-07-01');
1. JavaBean实体类
如果一个Java类仅仅封装了属性,没有其他方法,则称之为POJO类或实体类,好像也叫作JavaBean,通常放置在com.xxx.po 或者 com,xxx.bean 包中
这个类中封装的属性必须对用数据库中的字段,必须覆盖空参的构造方法,酌情覆盖全参构造方法,酌情覆盖toString()方法
public class Person{//使用包装类封装字段,必须对应表中的字段private Integer id;private String name;private String pass;private Integer age;private Double salary;private Date birth;/** 必须覆盖空参的构造方法* 覆盖空参构造方法之后可以new空参的对象* Person per = new Person();* */public Person() {}/** 酌情覆盖全参构造方法,这样我们就可以直接new一个带有六个参数的对象* Person per = new Person(XX,XX,XX,XX,XX,XX);* */public Person(Integer id, String name, String pass, Integer age, Double salary, Date birth) {this.id = id;this.name = name;this.pass = pass;this.age = age;this.salary = salary;this.birth = birth;}//各个属性的get和set方法//看需求是否覆盖 toString() 方法}
2. 工厂类
一般放置在**com.xxx.factory包中**1.加载驱动
static{try{Class.forName("com.mysql.jdbc.Driver");}catch(Exception e){e.printStackTrace();}}
2.获取链接
public static Connection getConn(){try{//2.加载链接/** 完全版:* jdbc:mysql://localhost:端口号/database* jdbc:mysql://远程ip地址:端口号/database* 如果数据库在本地,则可以使用简化版:* jbdc:mysql:///database* user:用户名* password:用户密码* */return DriverManager.getConnection("jdbc:mysql:///et1912","root","dream");}catch(Exception e){e.printStackTrace();return null;}}
3.释放资源
public static void close(ResultSet rs, Statement st,Connection con){try {if(rs!=null)rs.close();} catch (Exception ex) {ex.printStackTrace();} finally {try {if(st!=null)st.close();} catch (Exception ex) {ex.printStackTrace();} finally {try {if(con!=null)con.close();} catch (Exception ex) {ex.printStackTrace();}}}}
代码
package com.etoak.factory;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;public class Factory {/** A:加载驱动* 不同的数据库品牌厂商提供了不同的驱动,可以正确识别各种厂商的数据库品牌* 语法等,加载驱动之后,在Java端可以使用相同的Java代码操作不同品牌不同语法的数据库此处使用静态初始化块仅仅加载一次即可* */static{try {//使用反射类加载的方式加载驱动//不同品牌的驱动不同,需要导入数据库厂商提供的jar包Class.forName("com.mysql.jdbc.Driver");} catch (Exception ex) {ex.printStackTrace();}}/** B:获取连接* 连接数据库,通过驱动管理器提供连接地址,用户名和密码可以链接数据库* */public static Connection getCon(){try {/** 注意这里三个参数分别是* url:链接地址* 格式完全版* jdbc:mysql://localhost:8080/数据库名* jdbc:mysql://远程ip地址:8080/数据库名* 如果数据库就在本地,则可以使用简化版* jdbc:mysql:///数据库名* user:用户名* password:密码* */return DriverManager.getConnection("jdbc:mysql:///et1912","root","etoaketoak");} catch (Exception ex) {ex.printStackTrace();return null;}}/** C:释放资源* 释放资源时顺序如下:* 首先关闭结果集,关闭执行器,最后关闭连接* */public static void close(ResultSet rs, Statement st,Connection con){try {if(rs!=null)rs.close();} catch (Exception ex) {ex.printStackTrace();} finally {try {if(st!=null)st.close();} catch (Exception ex) {ex.printStackTrace();} finally {try {if(con!=null)con.close();} catch (Exception ex) {ex.printStackTrace();}}}}}
3.dao持久化层
dao(Data Access Object)数据访问对象通常放置在**com.xxx.dao包下**1. 接口
/** Dao:Data Access Object数据访问对象* 这里的接口一般由项目经理或者一些规范的制定者来执行* 如何实现不关心,仅仅提供了一个规范* DaoIf 是DaoInterface的简写* */public interface PersonDaoIf {//添加一个用户public boolean addPerson(Person per);//根据id删除一个用户public boolean delPersonById(Integer id);//拿取全部用户public List<Person> queryAll();//根据用户名查询public boolean queryName(String name);//根据用户名和密码查询public Person queryPerson(String name,String pass);//修改用户资料public boolean updatePerson(Person per);}
public interface PersonDaoIf2 {//1添加用户public boolean addPerson(Person per);//2根据id删除public boolean delPersonById(Integer id);//3根据name删除public boolean delPersonByName(String name);//4拿取全部public List<Person> queryAll();//5姓名查重public boolean queryName(String name);//6登录查询public Person queryPerson(String name,String pass);//7拿取总记录数public Integer queryCount();//8分页查询public List<Person> queryPage(Integer index,Integer max);//9姓名模糊分页查询public List<Person> queryNameLikePage(String args,Integer index,Integer max);//10条件分页查询public List<Person> queryLikePage(Person per,Integer index,Integer max);//11批量删除public boolean multiDel(String[] args);//12修改public boolean updatePerson(Person per);}
2.接口实现类[Statement]
创建PersonDaoIf接口的实现类PersonDaoImpl右键空白处 **(或者alt + insert)**选择Implements Method,实现接口中的抽象方法public class PersonDaoImpl implements PersonDaoIf{//设置连接Connection conn;//设置执行器Statement st;//结果集ResultSet rs;@Overridepublic boolean addPerson(Person per) {try {//书写sql语句/** java.util.Date无法和字符串直接通过+拼接成sql语句* 可以有以下两种方式* 1)将java.util.Date转换为java.sql.Date,可以直接拼接* 2)将java.util.Date转换为字符串*** */String sql ="insert into person values (null,'"+per.getName()+"','"+per.getPass()+"',"+per.getAge()+","+per.getSalary()+",'"+new SimpleDateFormat("yyyy-MM-dd").format(per.getBirth()) +"')";//获取连接con = Factory.getCon();//拿取执行器st = con.createStatement();//执行器根据sql语句调用方法return st.executeUpdate(sql)==1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {//不管是否执行正常都要释放资源Factory.close(null,st,con);}}}
存在的安全隐患
当传入的是一个恒等的条件表达式的时候,语句相当于查找全表数据可以被SQL注入3.接口实现类[PreparedStatement]
创建类PersonDaoImpl2实现PersonDaoIf2接口PreparedStatement是Statement的子类使用PreparedStatement执行器时,使用 ? 先进行站位,后填充填充日期类型时,需要用**new java.sql.Date(xxx.getDate().getTime())**package com.etoak.dao;import com.etoak.factory.Factory;import com.etoak.po.Person;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.Statement;import java.util.ArrayList;import java.util.List;public class PersonDaoImpl2 implements PersonDaoIf2 {Connection con;Statement st;/** 使用执行器PreparedStatement,它是Statement的子类* */PreparedStatement pst;ResultSet rs;@Overridepublic boolean addPerson(Person per) {try {/** 在使用Statement时,需要我们对sql语句进行拼接,但是在进行拼接时非常的不方便,* 并且安全性较低,容易出现sql注入安全隐患* 使用PreparedStatement则可以使用?作为占位符的形式来组装sql语句,不再需要我们* 进行复杂的sql拼接了** 注意使用?占位,必须填充占位符,因为sql语句中不能再执行时存在?* */String sql = "insert into person values (null,?,?,?,?,?)";con = Factory.getCon();//获取执行器的同时,加载带有?占位符的sql语句pst = con.prepareStatement(sql);//由于存在占位符所以必须填充/** pst.set数据类型(index,要填充的值)* index:表示从左往右?的顺序,注意从1开始* */pst.setString(1,per.getName());pst.setString(2,per.getPass());pst.setInt(3,per.getAge());pst.setDouble(4,per.getSalary());/** java.util.Date和java.sql.Date的区别** 1)java.util.Date是sql.Date的父类* 2)util.Date一般可以设置年月日小时分钟秒* 而sql.Date只能精确到年月日* 3)util.Date不能和字符串直接拼接成sql语句* 而sql.Date可以* 4)通过getTime()进行转换* */pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));return pst.executeUpdate()==1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {//长按ctrl或者command键可以溯源Factory.close(null,pst,con);}}@Overridepublic boolean delPersonById(Integer id) {try {String sql = "delete from person where id = ?";con = Factory.getCon();//获取执行器的同时加载sql语句pst = con.prepareStatement(sql);pst.setInt(1,id);return pst.executeUpdate()==1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {Factory.close(null,pst,con);}}@Overridepublic boolean delPersonByName(String name) {try {String sql = "delete from person where name = ?";con = Factory.getCon();pst = con.prepareStatement(sql);pst.setString(1,name);return pst.executeUpdate()>=1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {Factory.close(null,pst,con);}}@Overridepublic List<Person> queryAll() {try {String sql = "select * from person";con = Factory.getCon();pst = con.prepareStatement(sql);rs = pst.executeQuery();List<Person> list = new ArrayList<>();while(rs.next()){list.add(new Person(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getInt(4),rs.getDouble(5),rs.getDate(6)));}return list;} catch (Exception ex) {ex.printStackTrace();return null;} finally {Factory.close(rs,pst,con);}}@Overridepublic boolean queryName(String name) {try {String sql = "select * from person where name = ?";con = Factory.getCon();pst = con.prepareStatement(sql);pst.setString(1,name);return pst.executeQuery().next();} catch (Exception ex) {ex.printStackTrace();return false;} finally {Factory.close(rs,pst,con);}}@Overridepublic Person queryPerson(String name, String pass) {try {String sql = "select * from person where name = ? and pass = ?";con = Factory.getCon();pst = con.prepareStatement(sql);pst.setString(1,name);pst.setString(2,pass);rs = pst.executeQuery();if(rs.next()){return new Person(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getInt(4),rs.getDouble(5),rs.getDate(6));}return null;} catch (Exception ex) {ex.printStackTrace();return null;} finally {Factory.close(rs,pst,con);}}@Overridepublic Integer queryCount() {try {String sql = "select count(*) from person";con = Factory.getCon();pst = con.prepareStatement(sql);rs = pst.executeQuery();/** 这里的rs返回的是一个两行一列的表格* ------------* ||* | count |* ------------* ||* | 记录数 |* ------------** 指针指向表头,使其下移一行*/rs.next();return rs.getInt(1);} catch (Exception ex) {ex.printStackTrace();return null;} finally {Factory.close(rs,pst,con);}}@Overridepublic List<Person> queryPage(Integer index, Integer max) {try {/** select 字段 from 表 limit x,y;* x:表示起始索引值* y:表示显示几条记录* */String sql = "select * from person limit ?,?";con = Factory.getCon();pst = con.prepareStatement(sql);pst.setInt(1,index);pst.setInt(2,max);rs = pst.executeQuery();List<Person> list = new ArrayList<>();while(rs.next()){list.add(new Person(rs.getInt(1),rs.getString(2),rs.getString(3),rs.getInt(4),rs.getDouble(5),rs.getDate(6)));}return list;} catch (Exception ex) {ex.printStackTrace();return null;} finally {Factory.close(rs,pst,con);}}//根据姓名模糊查询并且分页@Overridepublic List<Person> queryNameLikePage(String args, Integer index, Integer max) {try {String sql = "select * from person where name like ? limit ?,?";con = Factory.getCon();pst = con.prepareStatement(sql);//对左模糊右模糊进行拼接pst.setString(1,"%"+args+"%");pst.setInt(2,index);pst.setInt(3,max);rs = pst.executeQuery();List<Person> list = new ArrayList<>();while(rs.next()){list.add(new Person(rs.getInt("id"),rs.getString("name"),rs.getString("pass"),rs.getInt("age"),rs.getDouble("salary"),rs.getDate("birth")));}return list;} catch (Exception ex) {ex.printStackTrace();return null;} finally {Factory.close(rs,pst,con);}}@Overridepublic List<Person> queryLikePage(Person per, Integer index, Integer max) {return null;}/** 此处传入的是字符串类型的数组,内部封装了所有的id* 根据这些id批量删除,注意不需要考虑id的真实性情况** */@Overridepublic boolean multiDel(String[] args) {try {String sql = "delete from person where id in (";String sum = "";for(int i = 0;i<args.length;i++){sum = args[i]+","+sum;}sum = sum.substring(0,sum.length()-1);sql += sum+")";con = Factory.getCon();st = con.createStatement();/** pst = con.preparedStatement(sql);* pst.executeUpdate()>=1* */return st.executeUpdate(sql)>=1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {Factory.close(null,pst,con);}}@Overridepublic boolean updatePerson(Person per) {try {String sql ="update person set name = ?,pass = ?,age = ?,salary = ?,birth = ? where id = ?";con = Factory.getCon();pst = con.prepareStatement(sql);pst.setString(1,per.getName());pst.setString(2,per.getPass());pst.setInt(3,per.getAge());pst.setDouble(4,per.getSalary());pst.setDate(5,new java.sql.Date(per.getBirth().getTime()));pst.setInt(6,per.getId());return pst.executeUpdate()==1;} catch (Exception ex) {ex.printStackTrace();return false;} finally {Factory.close(null,pst,con);}}}
1.书写套路注意事项
Statement执行器//在实现的方法中,第一步现获取连接conn = Factory.getConn();//第二步,获取执行器st = conn.createStatement();//第三步。书写Sql语句,这里可以先将SQL语句写完整之后在根据是否是字符类型的加双引号String sql = "select * from person";//如果没有返回结果集,则返回执行结果,//此方法返回的是受影响的行数,返回值为intreturn st.executeUpdate(sql) > 0;//如果有返回结果集,则第四步,获得结果集rs = st.executeQuery(sql);//第五步,创建一个新的空集合,给定泛型确保只能存储该类型的对象List<Person> list = new ArrayList<>();//第六步 把结果集中的结果依次添加到空集合中while(rs.next()){list.add(new Person(rs.getInt(1),...));}//第七步,关闭连接Factory.closeConn(rs,st,conn);
PreparedStatement执行器
//1获取连接conn = Factory.getConn();//2.书写sql语句,先使用占位符 ? 来填充String sql = "select * from person where name like ? limit ?,?";//3.获取执行器d的同时把sql语句传入pst = conn.preparedStatement(sql);//4.给占位符传入相应的值,第一个参数代表是sql语句中第几个问号,第二个参数代表传入的值//4.1 模糊查询时拼接字符串pst.setString(1,"%" + per.getName() + "%");//4.2传入其他参数pst.setInt(2,per.getAge());//4.3 Date类型,因为util.Date不能拼接sql语句,所以要转化成sql.Datepst.setDate(3,new java.sql.Date(per.getBirth().getTime()));//5.执行pst.executeQuery();
2. Date注意事项
执行sql语句拼接Date时 java.util.Date无法和字符串直接通过+拼接成sql语句可以有以下两种方式
1)将java.util.Date转换为java.sql.Date,可以直接拼接
2)将java.util.Date转换为字符串
String sql = "insert into person values('"+ new SimpleDateFormat("yyyy-MM-dd").format(Date) +"')"
创建对象把String转换成Date类型时
Person per = new Person(new SimpleDateFormat("yyyy-MM-dd").parse("1999-01-01"));
PreparedStatement传入Date
pst = conn.preparedStatement(sql);pst.setDate(1,new java.sql.Date(per.getBirth().getTime()));
4. 测试
package com.etoak.test;import com.etoak.factory.Factory;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;public class Test {public static void main(String[] args) {try {//调用工厂获取连接,从而链接数据库Connection con = Factory.getCon();/** 如果出现Can not found class com.mysql.jdbc.Driver则是没导包* 或者驱动书写错误* */if(con==null){System.out.println("链接失败!!");return;}System.out.println("链接成功!!");/** 获取连接之后可以获取执行器,执行器用来执行SQL语句* 主要有以下两种执行器* Statement* PreparedStatement* */Statement st = con.createStatement();String dml1 = "insert into person values (null,'测试1','12345',30,2000.00,'2000-03-03')";String dql1 = "select * from person";/** 获取执行器之后可以根据SQL语句类型的不同,调用以下几种方法** 1) boolean execute()* 如果执行DQL语句,则返回true* 如果执行DML语句,则返回false,但是依然可以执行* 此方法使用较少** 2) int executeUpdate()* 如果执行DQL语句,立刻报错* 如果执行DML语句,则返回更改的记录数** 3) ResultSetexecuteQuery()* 如果执行DML语句,立刻报错* 执行DQL语句返回一个结果集ResultSet,通过解析这个结果集,可以拿取封装在里面的值*** 4) int[]executeBatch()* 执行批处理,一次执行多条SQL语句* *///int count = st.executeUpdate(dml1);//System.out.println(count);ResultSet rs = st.executeQuery(sql1);/** 要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格存在表头,永远不为null存在一个 boolean next() 结果集类似一个表格,默认指针指向第一行表头,当我们调用.next()时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false所以我们可以根据.next()方法是否返回true来判断是否存在有效数据* */while(rs.next()){/** 拿取数据:* get数据类型(列数)或者get数据类型(列名)* *//*System.out.println("ID:"+rs.getInt(1)+"\t姓名:"+rs.getString(2)+"\t密码:"+rs.getString(3)+"\t年龄:"+rs.getInt(4)+"\t薪资:"+rs.getDouble(5)+"\t生日:"+rs.getDate(6));*/System.out.println("ID:"+rs.getInt("id")+"\t姓名:"+rs.getString("name")+"\t密码:"+rs.getString("pass")+"\t年龄:"+rs.getInt("age")+"\t薪资:"+rs.getDouble("salary")+"\t生日:"+rs.getDate("birth"));}} catch (Exception ex) {ex.printStackTrace();}}}
1. 注意点
创建执行器 通常有两种Statement , PreparedStatement拿取有效数据要进行解析之前,首先判断是否存在有效数据,如果没有有效数据,则不需要进行任何解析
不要根据ResultSet是否为null,来判断是否存在有效数据,因为ResultSet类似一个表格, 存在表头,永远不为null, 存在一个 boolean next() 结果集类似一个表格,
默认指针指向第一行表头,当我们调用rs .next()时,如果指针可以下移,返回true,如果不存在有效数据了,则指针无法下移一行,返回false所以我们可以根据.next()方法是否返回true来判断是否存在有效数据
rs = st.executeQuery(sql);while(rs.next()){//TODO}
拿取数据 可以通过 get数据类型(列数) 或者 get数据类型(列名)来拿取
Integer id = rs.getInt(1);String name = rs,getString("name");
2.执行器的executeBatch()方法
首先需要关闭mysql的自动提交事务,conn.setAutoCommit(false); 出错时不会提交用 addBatch(sql)方法 把要执行的SQL语句挨个放进执行器中执行方法并提交打开MySQL的自动提交public class TestBatch {public static void main(String[] args) {try {//获取连接Connection con = Factory.getCon();//关闭mysql的自动提交事务con.setAutoCommit(false);//获取执行器Statement st = con.createStatement();//设置要批处理得sql//注意批处理不能执行dql语句String dml1 = "insert into person values (null,'elena','12345',30,5000.00,'1990-03-01')";String dml2 = "insert into person values (null,'damon','33345',20,6000.00,'1993-03-01')";String dml3 = "insert into person values (null,'stefan','53345',17,4000.00,'1992-03-01')";String dml4 = "delete from person where id = 1";//将要执行的sql语句添加进缓存中//这里每条sql语句都类似一个子弹,此处压入弹夹st.addBatch(dml1);st.addBatch(dml2);st.addBatch(dml3);st.addBatch(dml4);//进行批处理操作/** 返回的是一个int类型的数组,内部封装了更改的记录数** */int[] count = st.executeBatch();//提交事务mit();//恢复自动提交con.setAutoCommit(true);for(int i:count){System.out.println("更改的记录数是~~~~》"+i);}} catch (Exception ex) {ex.printStackTrace();}}}
5. 🐴Statement和PreparedStatement的区别
相同点不同点两者都为接口
public interface Statement implements Wrapper
public interface PreparedStatement implements Statement PreparedStatement是Statement的子类
①:Statem只能执行静态语句; PreparedStatement 可以还行IN参数的sql语句,所谓IN参数是指,sql语句可以进行字段等数据的更改
并不是一个固定的语句。
②PreparedStatement存在一个强大缓存区,可以对sql语句
进行预编译,在执行相同的sql语句时,PreparedStatement
将语句加载进缓存区,仅仅编译一次,当第二次执行此语句时
不需要再次进行编译,也就是说相同的sql语句执行多条
仅仅编译一次,PreparedStatement仅对改动数据进行修改
而不再进行编译;
Statement只要语句发生了改变,则必须重新进行编译
③:PreparedStatement支持对sql语句使用?占位符,从而对
sql语句进行字段参数的修改,降低了开发难度,并且从根本上杜绝了
sql注入安全隐患
④如果sql语句不需要多次执行,或者?过多,则效率可能较
Statement低
第八章 DButil
DBUtil是一个轻量级的JDBC框架,封装了原来的方法,并且可以自动释放资源,不需要手动释放资源1. 实例
QueryRunner 执行器,代替了Statement和PreparedStatement,封装了原来的执行器package com.etoak.dao;import com.etoak.factory.Factory;import com.etoak.po.Person;import mons.dbutils.QueryRunner;import mons.dbutils.handlers.BeanHandler;import mons.dbutils.handlers.BeanListHandler;import mons.dbutils.handlers.ScalarHandler;import java.sql.Connection;import java.text.SimpleDateFormat;import java.util.List;public class PersonDaoImpl3 implements PersonDaoIf3 {Connection con;//拿取选择执行器,这个执行器封装了原先的执行器QueryRunner qr = new QueryRunner();//当我们使用DBUtils框架时,不需要手动释放资源了,此框架自动释放@Overridepublic boolean addPerson(Person per) {try {String sql = "insert into person values (null,?,?,?,?,?)";/** 如果执行DML语句** int qr.update(con,sql,填充的占位符)* 返回值是更改的记录数* con:链接* sql:带有占位符或者拼接的sql语句* */return qr.update(Factory.getCon(),sql,per.getName(),per.getPass(),per.getAge(),per.getSalary(),per.getBirth())==1;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic boolean delPersonById(Integer id) {try {String sql = "delete from person where id = ?";con = Factory.getCon();return qr.update(con,sql,id)==1;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic boolean delPersonByName(String name) {try {String sql = "delete from person where name = ?";con = Factory.getCon();return qr.update(con,sql,name)>=1;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic boolean delPersonByAgeAsc(Integer age) {try {String sql = "delete from person where age > ?";con = Factory.getCon();return qr.update(con,sql,age)>=1;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic boolean multiDelById(String[] args) {try {String sql = "delete from person where id in (";String sum = "";for(int i = 0;i<args.length;i++){sum = args[i]+","+sum;}sum = sum.substring(0,sum.length()-1);sql += sum+")";con = Factory.getCon();return qr.update(con,sql)>=1;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic List<Person> queryAll() {try {String sql = "select * from person";con = Factory.getCon();/** 如果执行DQL语句** qr.query(con,sql,new ResultSetHandler(),填充的占位符);* con:链接* sql:拼接或者带有占位符的sql语句* ResultSetHandler():接口 封装了各种形式的结果集,根据返回值不同一般我们调用其* 子接口* 1)返回实体类 new BeanHandler(实体类.class)* 2)返回封装实体类的List new BeanListHandler(实体类.class)* 3)返回count max min avg调用的函数 new ScalarHandler()* */return qr.query(con,sql,new BeanListHandler<Person>(Person.class));} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic boolean queryName(String name) {try {String sql = "select * from person where name = ?";con = Factory.getCon();/** 注意这里不能使用new BeanListHandler()* 因为此接口封装了结果集,存在表头,永远不为空* */return qr.query(con,sql,new BeanHandler<Person>(Person.class),name)!=null;} catch (Exception ex) {ex.printStackTrace();return false;}}@Overridepublic Person queryPerson(String name, String pass) {try {String sql = "select * from person where name = ? and pass = ?";con = Factory.getCon();return qr.query(con,sql,new BeanHandler<Person>(Person.class),name,pass);} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic Integer queryCount() {try {String sql = "select count(*) from person";con = Factory.getCon();return Integer.parseInt(qr.query(con,sql,new ScalarHandler()).toString());} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic List<Person> queryPage(Integer index, Integer max) {try {String sql = "select * from person limit ?,?";con = Factory.getCon();return qr.query(con,sql,new BeanListHandler<Person>(Person.class),index,max);} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic List<Person> queryBirthByPage(String birthBegin, String birthEnd, Integer index, Integer max) {try {String sql = "select * from person where birth between ? and ? limit ?,?";con = Factory.getCon();return qr.query(con,sql,new BeanListHandler<Person>(Person.class),birthBegin,birthEnd,index,max);} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic List<Person> queryNameLikeByPage(String args, Integer index, Integer max) {try {String sql = "select * from person where name like ? limit ?,?";con = Factory.getCon();return qr.query(con,sql,new BeanListHandler<Person>(Person.class),"%"+args+"%",index,max);} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic List<Person> queryByPage(Person per, Integer index, Integer max) {try {/** 姓名 模糊* 密码 模糊* 年龄 准确* 薪资 准确* 生日 准确** 模块化书写* 不管结果如何必须分页,如果用户不填写任何查询条件,则全部拿取* */String sql = "select * from person where 1 = 1 and ";if(per.getName()!=null){sql += "name like '%"+per.getName()+"%' and ";}if(per.getPass()!=null){sql += "pass like '%"+per.getPass()+"%' and ";}if(per.getAge()!=null){sql += "age = "+per.getAge()+" and ";}if(per.getSalary()!=null){sql += "salary = "+per.getSalary()+" and ";}if(per.getBirth()!=null){sql += "birth = '"+new SimpleDateFormat("yyyy-MM-dd").format(per.getBirth()) +"' and ";}sql = sql.substring(0,sql.length()-4);sql += " limit "+index+","+max;return qr.query(Factory.getCon(),sql,new BeanListHandler<Person>(Person.class));} catch (Exception ex) {ex.printStackTrace();return null;}}@Overridepublic boolean updatePerson(Person per) {try {String sql = "update person set name = ?,pass = ?,age = ?,salary = ?,birth = ? where id = ?";con = Factory.getCon();return qr.update(con,sql,per.getName(),per.getPass(),per.getAge(),per.getSalary(),per.getBirth(),per.getId())==1;} catch (Exception ex) {ex.printStackTrace();return false;}}}
2.注意点
1. 执行DML 语句
当执行增,删,改 操作时,使用update()方法,
QueryRunner qr = new Queryunner();public boolean addPerson(Person per){String sql = "insert into person values(null,?,?)";conn = Factory.getCOnn();return qr.update(conn,sql,per.getName(),per.getPass(),);}
2. 执行DQL语句
执行查询数据时,使用query方法
qr.query(conn,sql,new ResultSetHandler(),填充的占位符)
前两个与上边的一样
ResultSetHandler()这个接口封装了各种形势的结果集,根据返回结果不同,调用其子接口,把要获取的实体类的反射传入构造方法中
return qr.query(conn,sql,new BeanHandele<Person>(Person,class),per.getName()) != null;
3. 接口
第九章 servlet
1. Eclipse相关配置
1. 设置为Java视图
点击上放的Window-->show view-->other-->选中Java下边的Package Explorer点击Open
2. 配置Tomcat
同样在 show view中选中 other,搜索Server点击Open
在Server里边会有一个蓝色的连接,双击连接,选中 tomcat8.5
点击next选中自己的tomcat的目录和 JDK 的路径,点击finish
重新在server中双击tomcat 在 Server Locations选中第二个Use
接着把Deploy Path改成 webapps
配置工程,右键tomcat选中add and remove,吧想要的工程添加进去进行了
更改html、CSS、JS等可以不用关闭Tomcat。更改Servlet一定要关闭tomcat
2. 常见HTTP错误
1.404后边存在一个路径
表单的action或者链接的href在提交之后没有被web.xml中的url-pattern拦截到从浏览器地址书写的路径错误,路径格式为http://localhost:8080/工程名/页面文件放置的位置出现问题,在eclipse下的页面资源应该放置在WebContent下没有成功部署2. 404后边没有路径
tomcat开始失败,原因 文件缺失,在安装tomcat之后对tomcat进行增删web.xml解析异常,其中节点值必须以 / 开头 节点值必须对应已经开启了一个tomcat,因为只有一个8080 端口,所以默认情况下只能开一个tomcat3.405
Post提交覆盖doPost,GET提交覆盖doGet,或者method属性拼写错误,注意表单和链接提交默认都是GET,链接无法改动,请求转发跳转前后一致,重定向跳转之后一定是doGet
4.500
出现异常,例如空指针异常等,或者在web.xml中的servlet-class节点中无法找到Servlet实例地址。如果是异常则找第一个自己写的类。
5.常用接口
3.创建Servlet的两种方式
1.继承HttpServlet,并覆盖相应方法
1. 修改web.xml配置文件
首先要打开WEB-INF 中的 web.xml文件
此文件是整个文件中最为重要的一个文件,当打开tomcat时,tomcat会对工作空间中所有的 web.xml进行解析,如果出现解析错误,则tomcat开启失败,只要有一个工程解析错误,就无法工作
<servlet><!-- Step3)此处必须对应servlet-mapping子节点中的servlet-name节点值,如果不匹配,则无法开启tomcat--><servlet-name>suibianxie</servlet-name><!-- Step4)此节点值为Servlet实例的确切路径,最终找到处理用户请求的Servlet实例,长按Ctrl或者Command键可以检查此处正确与否,如果此处为无效地址,则500错误Can not found class 类名 Exception--><servlet-class>com.etoak.servlet.UserLogin</servlet-class></servlet><servlet-mapping><!-- Step2)当拦截成功时,读取此处的节点值,到servlet的子节点servlet-name中读取与之相同的节点值注意如果全文没有与此节点匹配的servlet-name节点值,则tomcat无法开启--><servlet-name>suibianxie</servlet-name><!-- Step1)此处为拦截路径,这里监听 表单或者链接提交的路径,如果拦截失败,则报404错误如果拦截成功则读取servlet-name的节点值此处书写的格式为 /拦截路径--><url-pattern>/userlog</url-pattern></servlet-mapping>
2.书写实现类
package com.etoak.servlet;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.etoak.dao.UserDaoIf;import com.etoak.dao.UserDaoImpl;import com.etoak.po.User;/** 一个普通的Java类只要继承了HttpServlet抽象类,则这个类就可以称之为* Servlet类* * */public class UserLogin extends HttpServlet{/** 此方法专门用来处理post提交的请求* 没有返回值* HttpServletRequest:接口,封装了所有提交过来的请求* HttpServletResponse:接口,封装了所有要发送走的响应* * */@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/** Servlet默认不支持中文,所以我们需要添加中文支持,* 以下两句为软编码,添加中文支持* *///设置响应的编码/** response.setContentType("MIME;charset=编码");* 注意 MIME:是专门用来提示浏览器按照何种语法解析的设置* 此处填写了text/html表示提示浏览器根据html语法进行解析* * MIME存在数十种写法* text/html:根据html语法解析* text/css:根据css语法解析* text/javascript:根据js语法解析* text/plain:被浏览识别为字符串* application/json:根据json语法解析* image/jpeg:被浏览器识别为一张jpeg格式的图片* * 注意!!!此处如果书写错误* 则浏览器提示下载文件* */response.setContentType("text/html;charset=utf-8");//设置请求的编码request.setCharacterEncoding("utf-8");//拿取字符输出流,一般不使用字节流PrintWriter out = response.getWriter();//引入dao层UserDaoIf dao = new UserDaoImpl();//接受页面表单提交过来的用户名和密码/** 注意这里 request.getParameter("这里对应页面name属性值")* * <input type="text" name="对应这里">* */String name = request.getParameter("myname");String pass = request.getParameter("mypass");System.out.println(name+"\t"+pass);//使用JDBC技术调用dao层User u = dao.queryUser(name, pass);if(u!=null) {//普通用户登录if(u.getLevel().equals("0")) {out.println("欢迎您回来"+u.getName());out.print(u.getGender().equals("0")?"女士":"先生");out.println("<hr />");out.println("以下为普通用户页面结构样式...");out.close();return;}//管理员登录if(u.getLevel().equals("1")) {out.println("欢迎您回来管理员"+u.getName()+"<hr />");out.println("<a href='showuser'>查看所有普通用户资料</a>");out.close();return;}//超级管理员登录if(u.getLevel().equals("2")) {out.println("超级管理员"+u.getName()+"您好<hr />");out.println("<a href='showadmin'>查看所有管理员资料</a>");out.close();return;}return;}//动态输出页面// request.getContextPath():拿取/工程名// 此处组合成了一个绝对路径 /工程名/XXXX.htmlout.println("数据库中查无此人,请您先<a href='"+request.getContextPath()+"/reg.html'>注册</a><hr>");out.close();}}
2.创建Servlet
在servlet包下右键新建,选择other搜索servlet,点击open,创建书写Class Name,点击Next,在下方的拦截地址中改为对应的拦截地址,next,专责需要覆盖的方法
4.Servlet注意点
给Servlet添加中文支持
Servlet默认不支持中文,所以我们需要添加中文支持
//设置响应的编码 MIME存在数十种写法,上边写了几种常用的//response.setContentType("MIME;chaeset=编码");//此处书写错误,浏览器会提示下载文件注意response.setContentType("text/html;charset=utf-8");//设置请求编码request.setCharacterEncoding("utf-8");
方法含义
重定向之后不能再次提交请求问题
在下边这种情况下,重定向之后一定要加return
if(u != null){response.sendRedirect(request.getContextPath() + "/showadmin");//return;}response.sendRedirect(request.getContextPath() + "/showlog");
如果在重定向结束之后没有写return语句,会有500异常,Cannoot call sendRedirect() after the response has been committed
5. Servlet两种跳转方式
1.请求转发
浏览器发送请求到Servlet1,Servlet1执行请求转发之后,再讲请求转发到最终目的地Servlet2,由于不再是浏览器亲自发送到到最终目的地,所以浏览器的地址栏显示信息只是跳转前的路径,因为是同义词请求,request范围有效,跳转前是doXXX之后依旧是doXXX
其中一种
request.getRequestDispatcher(“showadmin”).forward(request, response);
第一个参数为要跳转的地址
2.重定向
浏览器发送请求到Servlet1,Servlet1返回相应到浏览器,浏览器重新发送请求到Servlet2,由于不再是一次请求,所以request范围失效。由于是浏览器轻自发出请求,所以浏览器的地址栏会变为最终跳转的路径。跳转之前是doXX之后肯定为doGet
路径书写格式可以固定为绝对路径写法
response.sendRedirect("/工程名/拦截路径");
response.sendRedirect("/工程名/xxx.html");
response.sendRedirect("/工程名/xxx.jsp");
response.sendRedirect(request.getContextPath() + “/showadmin”)
6. Servlet生命周期
package com.etoak.servlet;import java.io.IOException;import java.io.PrintWriter;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;@WebServlet("/testlife")public class TestLife extends HttpServlet {private String code;/** #Servlet的生命周期是怎样的?Servlet是一个单实例多线程的Java程序某一个Servlet ~~~~~~~》 通桑用户 ~~~~~~~》一百多号人 * 构造方法(由于Servlet是单实例多线程的Java程序,仅仅存在一个实例*所以构造方法仅仅执行1次)*|*|*init()(此方法称之为初始化方法,一般用来读取一些资源,拿取配置文件中的数据等等*类似做了一个准备工作,它也仅仅执行一次)*|*|*service(此方法根据请求的多少,执行多次,一个请求对应线程分配出来的一个*service(),这个方法会根据请求的类型调用相应的doGet()或者doPost(),service()*不推荐我们覆盖,如果覆盖会导致效率低下,并且无法再次自动调用doGet或者doPost)*|*|* doGet||doPost(被service方法调用,根据请求是Get还是Post分配相应的doGet和doPost* 没有返回值,专门用来书写业务逻辑,执行多次)* |* |* destroy()(当tomcat关闭时,执行此方法,一般用来释放资源等等,仅仅执行一次)* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* * * 服务器 ======》 蓝石商务中心* 容器(不严谨的理解为tomcat)======》 易途科技401和411* 容器中的工程======》 et1912* 每一个Servlet实例======》 每个同学* 某个Servlet实例======》 通桑* web.xml======》 座次表* 客户端======》 张老师* * */private static final long serialVersionUID = 1L;public TestLife() {System.out.println("我是Servlet的构造方法~~~~~~");}public void init() throws ServletException {System.out.println("我是Servlet的初始化方法init~~~~~~");/** Servlet中四个最常用的接口* * 1)ServletConfig* 封装某个特定Servlet实例的私有信息,书写在哪个Servlet中就只能拿取* 当前这个Servlet自己的参数* * 2)ServletContext* 封装了整个工程中所有Servlet实例共享的参数* * 3)HttpServletRequest* 封装所有提交过来的请求信息* 4)HttpServletResponse* 封装了所有要发送走的响应信息* * * *//** TestLife tl = new TestLife();* ServletConfig config = tl.getServletConfig();* 如果不使用this,则根据以上书写* *///ServletConfig config = this.getServletConfig();/** 使用ServletConfig也可以拿取ServletContext* ServletContext application = config.getServletContext();* *///System.out.println("类名是~~~~》"+config.getServletName());//拿取ServletContextServletContext application = this.getServletContext();System.out.println("工程名是~~~~~》"+application.getContextPath());System.out.println("拿取服务器中web服务器软件中被部署工程的绝对路径~~~~~》"+application.getRealPath("/"));//拿取web.xml中封装的参数System.out.println("封装的全局参数是~~~~~》"+application.getInitParameter("东京奥运会"));//读取配置好的编码类型code = application.getInitParameter("mycode");}public void destroy() {System.out.println("我是Servlet的销毁方法destroy~~~~~~");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset="+code);request.setCharacterEncoding(code);PrintWriter out = response.getWriter();//接受链接提交过来的值String value = request.getParameter("etoak");out.print("我是动态输出的页面,链接传递过来的值是====》"+value);out.close();System.out.println("我是负责业务逻辑的doGet()~~~~~~");}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request,response);}}
第十章 jsp
1. Session
//拿取专门用来封装权限信息的第三范围
HttpSession(中文翻译:会话)
Servlet中两种会话跟踪机制之一,另外一种是Cookie
HttpSession被翻译为会话,用来表示与用户交互的一段时间,HttpSession通过request.getSession()来创建,可以封装权限信息.用来证明用户的身份,从而避免不必要的一些身份验证工作
request.getSession()可以创建一个新的session或者在当前存在session的前提下,直接拿取已经存在的session
默认情况下用户与服务器交互,只可能存在一个session
创建session之后可以在session中封装信息,这个信息只要能证明用户的身份 资格等就统称为权限信息
session被创建之后默认最大不活动周期为1800s,在1800s以内用户封装的权限信息可以在不同的Servlet中拿取
通过
session.setAttribute(String,Object) 来封装信息
通过
session.getAttribute(String),来拿取信息
支持中文
创建之后从1800s开始倒计时,如果没有请求提交,则倒计时一直在消耗,倒计时结束,session销毁
内部的信息无法拿取
当用户再次提交请求时,倒计时重置。所以理论上用户如果一直在操作,则session一直存在
如果用户关闭浏览器,或者调用session.invalidate()则session立刻销毁
造成session失效的三种状况
超过最大不活动周期 默认1800s可以更改,存在40s左右的误差session.invalidate()立刻销毁关闭浏览器
2. jsp指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3FuwY0e-1595911803064)(D:\Study\Yitu\前端\Jsp\JspDaysOfficial\JspDay1\attachment\JSP语法图.jpg)]
1. include指令
使用include指令元素引入一个外部页面到本页,本页称之为主页
而引入的页面称之为辅页
file:表示引入页面的路径
注意 主页引入辅页,但是辅页不能再去引入主页,会导致无穷死循环
<%@ include file="data2.jsp"%>
2.page指令
page 指令元素共有12中写法,有血必须书写,又是否书写不重要3.jsp九个内置对象
1. request对象
客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应。它是HttpServletRequest类的实例
4.EL表达式
1.基本运算
${"3+2"}=${3+2} // 3+2=5${3>2} //true${3>2 ? true:false} //true
2.范围取值
EL表达式的四范围为pageScope,requestScope,sessionScope,applicationScope,当没有一样的键的时候,范围可以省略,当省略时,有多个范围的,省略范围的取值拿取现存范围中范围最小的。
<%pageContext.setAttribute("elena", "elenaPage");request.setAttribute("elena", "elenaRequest");session.setAttribute("elena","elenaSession");application.setAttribute("elena", "elenaApplication");%><!--java代码--><%=pageContext.getAttribute("elena") %><%=request.getAttribute("elena") %><%=session.getAttribute("elena") %><%=application.getAttribute("elena") %><br /><!--El表达式-->${pageScope.elena } <br />${requestScope.elena } <br />${sessionScope.elena } <br />${applicationScope.elena }${elena} //page
3. 判断是否为空
是空返回true,不是返回false
${empty sessionScope.zhangsan}
4. 接收值
接收链接或者表单传递过来的值
接收值(java):<%=request.getParameter("etoak") %><br /><!--param必须写-->接收值(el表达式):${param.etoak}
从web.xml中取值
<h3>从web.xml取值</h3>java取值:<%=application.getInitParameter("罗永浩") %> <br />El:${initParam.罗永浩 }
5. 拿取自定义数据类型的值
可以省略范围直接通过 key.value来取值,有点类似 js
public class Game{private Integer id;private String name;private Integer price;private String seller;//全参构造器和getset方法}
<%Game game = new Game(1,"动物之森",500,"任天堂");request.setAttribute("mygame", game);request.getRequestDispatcher("show4.jsp").forward(request, response);%>
<h3>拿取自定义数据类型中的属性值</h3>使用java:游戏ID<%=((Game)request.getAttribute("mygame")).getId() %>游戏名<%=((Game)request.getAttribute("mygame")).getName() %>游戏售价<%=((Game)request.getAttribute("mygame")).getPrice() %>发行商<%=((Game)request.getAttribute("mygame")).getSeller() %><hr />游戏ID:${requestScope.mygame.id }游戏名:${requestScope.mygame.name}售价:${mygame.price }发行商:${mygame.seller}
6. EL注意点
<% int i = 3%>java:<%=i%> //3EL:${i} //什么都不显示EL是通过键来拿取值的,上边的i是值,想要拿取到i需要添加范围随便写request.setAttribute("i",i);
5. JSTl
全称Jsp Standard Tag Lib ,jsp第二代标签库,需要导入jar包
<!-- 通常用c来表示JSTL--><%@ taglib prefix="c" uri="/jsp/jstl/core" %>
1. 赋值 <c:set>
存在种范围page,request,session,application<c:set var="elena" value="elenaPage" scope="page"></c:set>
2. 取值<c:out>
<c:out value="这里直接通过value输出的值"></c:out><c:out value="<%=str %>"></c:out><c:out value="${pageScope.elena}"></c:out><c:out value="${requestScope.elena}"></c:out><c:out value="${sessionScope.elena}"></c:out><c:out value="${applicationScope.elena}"></c:out><!--不知名范围的拿取现存范围中最小的--><c:out value="${elena}"></c:out> //page<c:out value="${requestScope.elena}" default="删除成功!"></c:out>
3.删除<c:remove>
<c:remove var="elena" scope="request" />
4.循环遍历 <c:forEach>
//<c:forEach>相当于for(Game ge:(List)request.getAttribute("mylist")){//此处pageContext范围是标签固定范围pageContext.setAttribute("suibianxie",ga);}
<%List<Game> list = new ArrayList<Game>();list.add(new Game(1,"动物森友会",530,"任天堂"));list.add(new Game(2,"生化危机3",440,"卡普空"));list.add(new Game(3,"FF7Re",500,"SE"));list.add(new Game(4,"骑马与砍杀2",300,"MB"));list.add(new Game(5,"仁王2",390,"光荣"));list.add(new Game(6,"十三机兵防卫圈",400,"香草社"));request.setAttribute("mylist", list);%>
<c:forEach items="${requestScope.mylist}" var="suibianxie" begin="1" end="3"><tr><td><c:out value="${pageScope.suibianxie.id}"></c:out></td><td><c:out value="${suibianxie.name}"></c:out></td><td><c:out value="${suibianxie.price}"></c:out></td><td><c:out value="${suibianxie.seller}"></c:out></td></tr></c:forEach>
注意:items后边写El表达式一定要写完整,不然会找不到属性,切记切记
5.流程控制<c:choose>
相当于Java中的if else,可以不书写otherwise,但是不能不书写when.
如果互相嵌套,则c:choose必须和c:when在一起
<c:choose><c:when test="${3>10}"><c:out value="输出这里了吗?"></c:out></c:when><c:otherwise><c:out value="最终输出了这里!!!!!"></c:out></c:otherwise></c:choose><c:choose><c:when test="${3>10}"><c:out value="输出这里了吗?"></c:out></c:when><c:otherwise><c:choose><c:when test="${2>1}"><c:out value="最终输出了这里!!!!!~~~~~~"></c:out></c:when></c:choose></c:otherwise></c:choose>
6.Jsp同步分页
所谓分页就是从数据库中拿取一部分的数据
1.分页的类型
假分页一次将所有数据从数据库中取出,用户需要哪几条就显示哪几条
真分页
用户需要哪几条就从数据库中取出哪几条
2. 分页公式
select 字段 from 表 limit x,y## x:起始索引值## y:一共显示条
3. 分页四要素
分页完成后要进行下边的操作
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" import="com.puterDaoIf,com.puterDaoImpl,com.etoak.po.*,java.util.*" %><%@ taglib prefix="c" uri="/jsp/jstl/core" %><!DOCTYPE html><html><head><meta charset="UTF-8"><title>Jsp同步分页</title><style>body{background-color:silver;}div#container{width:900px;margin:0 auto;text-align:center;}table,tr,th,td{border:solid 2px gray;}table{width:100%;text-align:center;border-collapse:collapse;box-shadow:15px 15px 15px silver;}thead{background-color:coral;}tbody{background-color:whitesmoke;color:navy;}input[type=button]{border-radius:15px;width:60px;background-color:pink;}a:hover{cursor:pointer;color:deeppink;text-decoration:underline;}a{color:navy;text-decoration:none;}</style></head><body><%--在对数据库的最基本操作中 增删查改 是基础的四门功课分页:拿取一部分数据~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分页的类型:假分页一次将所有的数据从数据库取出,用户需要哪几条就显示哪几条真分页用户需要哪几条就从数据库中取出哪几条~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分页公式select 字段 from 表 limit x,y;x:表示起始索引值y:表示一共显示几条记录~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分页四要素不管使用何种分页方式,何种技术,只要拿取了以下四个数据,则分页可得1:总记录数dao2:每页记录数自己订3:总页数(总记录数+每页记录数-1)/每页记录数4:当前页默认值是1,随着用户的操作不断的更改,是一个变量~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分页公式结合分页四要素select 字段 from 表 limit (当前页-1)*每页记录数,每页记录数;List<Computer> list = dao.queryPage((当前页-1)*每页记录数,每页记录数);--%><%--<c:choose>判断session范围中是否存在权限信息<c:when test="${!empty u}">--%><%ComputerDaoIf dao = new ComputerDaoImpl();//1:拿取总记录数Integer allRecord = dao.queryCount();//2:设置每页记录数Integer pageRecord = 5;//3:拿取总页数Integer allPage = (allRecord+pageRecord-1)/pageRecord;//4:设置当前页默认值Integer currentPage = 1;//接受表单提交的值String value = request.getParameter("cup");/*第一次打开本页面肯定为null,从上往下执行,表单还未提交*/if(value!=null){currentPage = Integer.parseInt(value);}List<Computer> list = dao.queryPage((currentPage-1)*pageRecord,pageRecord);pageContext.setAttribute("mylist",list);%><div id="container"><table><caption>计算机售价明细</caption><thead><tr><th>ID</th><th>品名</th><th>售价</th><th>生产商</th><th>CPU型号</th><th>GPU型号</th><th>硬盘容量</th><th>内存容量</th><th>产地</th><th>发售时间</th><%--只要不是平民登录--%><c:if test="${u.level!='0'}"><th colspan="3">操作</th></c:if></tr></thead><tbody><c:forEach items="${mylist}" var="co"><tr><td><c:out value="${co.id}"></c:out></td><td><c:out value="${co.name}"></c:out></td><td><c:out value="${co.total}"></c:out></td><td><c:out value="${co.production}"></c:out></td><td><c:out value="${co.cputype}"></c:out></td><td><c:out value="${co.gputype}"></c:out></td><td><c:out value="${co.disktype}"></c:out></td><td><c:out value="${co.ramtype}"></c:out></td><td><c:out value="${co.location}"></c:out></td><td><c:out value="${co.sellertime}"></c:out></td><c:if test="${u.level!='0'}"><td><a href="delcomputer?id=${co.id}&info=fake">假删除</a></td><td><a href="delcomputer?id=${co.id}&info=true">真删除</a></td><td><a href="computer_update.jsp?id=${co.id}">编辑</a></td></c:if></tr></c:forEach></tbody></table><br /><form action="computer_show.jsp"><input type="hidden" name="cup" /><input type="button" value="首页" οnclick="change(1)" <%=currentPage==1?"disabled":"" %> /><input type="button" value="上一页" οnclick="change(<%=currentPage-1 %>)" <%=currentPage==1?"disabled":"" %> /><input type="button" value="下一页" οnclick="change(<%=currentPage+1 %>)"<%=currentPage==allPage?"disabled":"" %> /><input type="button" value="末页" οnclick="change(<%=allPage %>)" <%=currentPage==allPage?"disabled":"" %> /></form><a href="computerquit">用户登出</a><%--1)普通用户只能看到用户登出链接2)管理员可以看到查看全部普通用户资料链接,点击之后跳转到computer_usershow.jsp页面,此页面存在一个表格,内部是所有普通用户资料。实现分页功能,实现真删除,假删除,编辑功能,提升权限(普通用户=》管理员)3)超级管理员可以看到查看全部管理员用户资料链接,点击之后跳转到computer_adminshow.jsp页面,此页面存在一个表格,内部是所有管理员资料。实现分页,假删除,编辑功能,降低权限(管理员=》普通用户)要求:Jsp页面使用EL表达式和JSTL标签,尽量使用Servlet调用dao层(分页页面可以直接在Jsp页面调用dao层)所有页面必须使用权限控制,非登录人员登入直接跳转到登录页dao层谨慎书写,如果之前已经写过,可以不再书写,工厂,实体类等不需要再次书写--%></div><script>/*此处传递过来的形参就是点击按钮之后当前页的值*/function change(cr){/*document.forms:表示拿取全文中所有的表单,由于这里只有一个表单所以添加[0]表示拿取的就是全文中的唯一表单.cup.value=cr表示将隐藏域的值赋值成cr也就是当前页的值*/document.forms[0].cup.value = cr//使用js提交表单document.forms[0].submit()}</script><%-- </c:when> --%><%-- <c:otherwise> --%><%--此处是放置不经过登录直接在浏览器地址栏输入此页面,逃避登录步骤由于没有从session中无法获得权限信息,所以进显示以下内容--%><!-- <p>您还没有登录,请您先登录</p><hr /> --><%-- </c:otherwise> --%><%-- </c:choose> --%></body></html>
7. 过滤器[filter]
Servlet
> Filter在Servlet中可以设置一个或者多个过滤器,这些过滤器起到过滤的作用,在Servlet执行doGet()或者执行doPost()
> 之前过滤器会挡在之前首先执行过滤工作,例如可以设置编码,可以查看权限
> init():在打开tomcat时,整个工程中所有的过滤器全部启动,仅仅执行一次
> doFilter():当拦截的Servlet要执行之前支持过滤器的doFilter(),注意在doFilter()中存在
> 一个chain.doFilter()方法,如果过滤器过滤结束,则支持此方法之后继续执行Servlet实例
> 而如果过滤失败,不支持chain.doFilter()则后面的Servlet不再执行了
> destroy():关闭tomcat时执行
>
> 多个过滤器:
> 打开tomcat时:
> Servlet的init()
> 过滤器1的init()
> 过滤器2的init()
请求发送时:过滤器1的doFilter()执行到chain.doFilter(request,response)时开始执行过滤器2的doFilter()执行到chain.doFilter(request,response)时开始执行Servlet的doGet()||doPost()之后执行过滤器2的chain.doFilter(request,response)之后的代码过滤器1的chain.doFilter(request,response)之后的代码这叫做过滤链过滤器可以配置在web.xml中或者使用Servlet3.0中注解直接配置在Filter类中<filter><filter-name>suibianxie</filter-name><filter-class>监听器的类的地址</filter-class><init-param><param-name>私有参数名</param-name><param-value>私有参数值</param-value></init-param></filter><filter-mapping><filter-name>suibianxie</filter-name><url-pattern>拦截的Servlet或者jsp路径</url-pattern></filter-mapping>
过滤顺序:
如果配置在web.xml中
注意过滤顺序是web.xml中从上到下过滤
注意servlet一定放置在最后
如果使用Servlet3.0注解
官方至今没有提供任何设置顺序的解决方案,API文档中没有任何方法可以设置顺序
非官方提出的说法按照过滤器字符排列顺序,例如
A.java肯定在B.java之前执行
FilterA.java肯定在FilterB.java之前执行
Filter0Etoak.java肯定在Filter1Etoak.java之前执行
未经过官方认定
1. 设置编码的
package com.etoak.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebFilter;import javax.servlet.annotation.WebInitParam;/** urlPatterns="这里表示要拦截的请求"* 注意如果设置为 /* 则表示拦截所有请求* initParams={* @WebInitParam(name="表示这个过滤器的键",value="表示这个过滤器的值"),* @WebInitParam(name="表示这个过滤器的键",value="表示这个过滤器的值"),* }* 在WebInitParam中部署的私有参数只有本类可以拿取* 可以通过以下几种手段拿取* ServletConfig config = this.getServletConfig();* String value = config.getInitParameter("键");* * 或者通过过滤器中的参数FilterConfig来拿取* * */@WebFilter(urlPatterns="/*",initParams={@WebInitParam(name="encode",value="utf-8"),@WebInitParam(name="thisiskey", value="thisisvalue")})//urlPatterns={"/UserManagerServlet","/index.jsp"}public class Filter1Encoding implements Filter {private String code;public void destroy() {System.out.println("编码过滤器的destroy~~~");}/** ServletRequest和ServletResponse是* HttpServletRequest与HttpServletResponse的父接口* * 注意部分方法无法直接调用* 重定向和请求转发无法直接使用,需要通过多态等进行转换* */public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("编码过滤器开始过滤啦!!~~~");request.setCharacterEncoding(code);chain.doFilter(request, response);}//当打开tomcat时直接执行此方法public void init(FilterConfig fConfig) throws ServletException {System.out.println("编码过滤器启动啦!");code = fConfig.getInitParameter("encode");System.out.println(code);}}
2. 设置权限的
package com.etoak.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.etoak.po.User;@WebFilter(urlPatterns= {"/delcomputer","/computerquit","/computerupdate","/computer_show.jsp","/computer_update.jsp"})public class Filter2Authority implements Filter {public void destroy() {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("权限过滤器开始过滤啦!!~~~");HttpServletRequest req = (HttpServletRequest)request;HttpSession session = req.getSession();User u = (User)session.getAttribute("u");if(u==null) {HttpServletResponse res = (HttpServletResponse)response;res.sendRedirect(req.getContextPath()+"/computer_log.jsp");return;}chain.doFilter(request, response);}public void init(FilterConfig fConfig) throws ServletException {System.out.println("权限过滤器启动啦!");}}
3. 注意点
urlPatterns=“这里表示要拦截的请求”注意如果设置为 /* 则表示拦截所有请求initParams={@WebInitParam(name=“表示这个过滤器的键”,value=“表示这个过滤器的值”),@WebInitParam(name=“表示这个过滤器的键”,value=“表示这个过滤器的值”),}在WebInitParam中部署的私有参数只有本类可以拿取可以通过以下几种手段拿取ServletConfig config = this.getServletConfig();String value = config.getInitParameter(“键”);或者通过过滤器中的参数FilterConfig来拿取*/
第十一章 AJAX和JSON
1.AJAX
Asynchronous JavaScript and XML
异步的js和xml
1. 创建异步请求的步骤
创建异步请求
let request//1)此函数用来创建异步请求function create(){//创建一个异步请求/** 这种创建方式是level2版本的创建方式,如果要针对ie6 7 8 等老旧浏览器* 则应该使用level1版本** if(window.XMLHttpRequest){* request = new XMLHttpRequest()* }else{* request = new ActiveXObject("Microsoft.XMLHttp")* }** 同步请求:* HttpServletRequest* ServletRequest* */request = new XMLHttpRequest()}
创建函数用来发送请求
//2)此函数用来给服务器发送请求,一般称之为主函数(非官方)function checkName(value){//A:创建异步请求create()//B:给服务器发送异步请求/** request.open(type,url,async)** url:表示发送异步请求的目的地(拦截地址)* 如果是get,则从此处传递值* 本例:* 'check?key=value&key2=value2'* type:请求类型 post get* async:表示是否使用异步,默认true使用,更改为false则使用同步,当响应返回之前* 浏览器锁死,用户无法进行任何操作* */request.open('post','check',true)//C:如果使用POST则需要书写此句,表示使用字符流进行值的传递,GET自动字符流不需要书写request.setRequestHeader('Content-Type','application/x-www-form-urlencoded')//D:声明回调函数//注意这里函数名可以随意书写,但是没有括号,如果存在括号则表示调用,没有括号表示声明//调用立刻执行,而声名需要前面的条件满足才可以request.onreadystatechange = callback//E:设置传递的参数,注意POST从此处传递值,GET不从此处传值,也必须书写,填写null//request.send('etoak='+value)request.send(`etoak=${value}`)}
书写回调函数接受响应信息
readyState状态
status状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rR6uvpoc-1595911803067)(D:\Study\Yitu\前端\AJAX\AjaxDaysOfficial\attachment\ajax回调函数.jpg)]
//3)回调函数,接受服务器处理完的响应信息function callback(){//首先判断服务器发送数据是否完整if(request.readyState==4){//完整的返回的数据没有报错if(request.status==200){//接受返回的字符串let value = request.responseText//拿取span元素let nodeSpan = document.getElementById('name_msg')//拿取submit表单元素let nodeSub = document.getElementById('sub')if(value=='bingo'){//设置错误提示信息nodeSpan.innerHTML = '<img src="image/wrong.png">用户姓名已经被占用'//设置样式nodeSpan.style.color = 'red'//禁用提交按钮nodeSub.disabled = truereturn;}nodeSpan.innerHTML = '<img src="image/right.png">用户姓名可以使用'nodeSpan.style.color = 'green'nodeSub.disabled = false}}}
@WebServlet("/check")public class CheckName extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/** Ajax支持三种数据的输出* 1)字符串text/plain* 2)xml text/xml* 3)jsonapplication/json* 所以在这里不管怎么书写也不能书写text/html,因为根本不支持html* */response.setContentType("text/plain;charset=utf-8");request.setCharacterEncoding("utf-8");//拿取要输出的字符流PrintWriter out = response.getWriter();//接受提交过来的用户名String name = request.getParameter("etoak");//模拟数据库查询if(name.equalsIgnoreCase("elena")){/** 返回字符串* out.print(要返回的数据)* 只支持 字符串 json xml* 注意不能使用println()否则会自动添加\n* */out.print("bingo");out.close();return;}out.print("suc");out.close();}
注意点
servlet只能书写一下三种MIME标签
给POST请求设置编码Ajax支持三种数据的输出
1)字符串 text/plain
2)xml text/xml
3)json application/json
所以在这里不管怎么书写也不能书写text/html,因为根本不支持html
request.setRequestHeader(‘Content-Type’,‘application/x-www-form-urlencoded’)
如果写错了会有500错误,提示response.send()这里报错,如果这里出错就找设置编码的