共23793个词 |
---|
129779个字符 |
这些东西不需要花费太多时间去记忆,需要用的时候去自己的笔记中查就是啦。
有些参数,或许真正用的并不多,但我们学习时意识不到,那这样就把他们大都记下来吧,如果真的用到,也可以很方便的找到用法。
建议:
这篇博客是不适合学习啦,对我的作用是作为参考手册来使用。
如果在学习或做一个小项目时发现有些用法忘记了,那么来这里查看应该比方便。
这篇博客,jQuery的篇幅还挺多,其实必要性不大,jQuery的官方文档就挺好。
而Servlet以及后面的一些感觉是有作用的,有一些代码可以贴过来直接用。
2021记:
用jsp和servlet写程序,感觉有些麻烦,写的时候很乱。下一步学Spring,期待它能带给我spring。
文章目录
零、 Maven依赖
常用的几个
mysql
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
DBCP数据库连接池
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.8.0</version>
</dependency>
dbutils
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
c3p0
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
druid
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
BootStrap引入
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
一、H5、CSS、JavaScript查缺补漏
1. HTML
1.1 标签
名称 | 作用 | 备注 |
---|---|---|
<hr/> | 水平线 | |
<br/> | 换行 | |
<h1> | 标题标签 | 位置:align=left center right |
<a> | 超链接 | href 地址 target 新打开窗口= "_self" 当前窗口 "_blank" 新窗口 |
<ul> | 列表 | type 列表项前面的符号 |
<img /> | 图片 | border边框大小 alt当路径找不到图片时,用来代替的文字 |
<table> | 表格 | align 表格相对于界面的位置 cellspacing 间距(=0不是重叠,是相邻) css边框合并: border-collapse: collapse; |
<tr> | 表格 行 | align 一行元素在表格中的位置 |
<td> | 表格 列 | align 某一个元素在表格中的位置 rowspan=“2” 内容跨越两行 colspan=“2” 内容跨越两行 |
<th> | 有设置的列标签 | 相当于align="center"和<b> |
<b> | 加粗 | |
**1.2 字符实体
更全的:传送门
常用的几个:
显示结果 | 描述 | 实体名称 | 实体编号 |
---|---|---|---|
空格 | | ||
< | 小于号 | < | < |
> | 大于号 | > | > |
**1.3 路径
相对路径的点的写法,这个是web的写法
. 当前文件所在的目录
… 当前文件所在的上一级目录
文件名 当前文件所在目录的文件,相当于 ./文件名 而./ 可以省略
**1.4 标签基本属性
- bgcolor – 直接设置背景颜色
- onclick – 直接写javascript的代码 and 调用javascript函数
<body bgcolor="#7fffd4" onclick = "alert('你好');">
你好
<div style = "border: 1px solid red">
123
</div>
</body>
**1.5 iframe
在页面上开辟一个小区域显示一个单独的界面
利用超链接标签,设置显示的区域
iframe设置name属性,a标签的target设置iframe的name
<iframe src="./other/tao.html" width="1000" height="1000" name="if"></iframe>
<br/>
<a href="other/tao.html" target="if">淘宝</a>
<br/>
<a href="other/index.html" target="if">163邮箱</a>
2. CSS
格式:
选择器{
属性: 值;
font-size: 30px;
}
引入css文件:在head中加入link标签
<link rel="stylesheet" type="text/css" href="filename.css" />
选择器
-
标签名选择器
应用于所有的"标签名"
标签名{ 属性: 值; } div{ border: 1px solid red; }
-
id选择器
#id名{ 属性: 值; } #id001{ border: 1px solid red; } 应用: <div id = "id001">我是一个div</div>
-
class选择器
.class名{ 属性: 值; } .class01{ border: 1px solid red; } 应用: <div class = "class01">我是一个div</div>
-
组合选择器
选择器1,选择器2,选择器n{ 属性: 值; } .class01 , #id001{ border: 1px solid red; } 应用: <div id = "id001">我是一个div</div> <div class = "class01">我是一个div</div>
3. JavaScript
引入JS文件:
<script type="text/javascript" src="1.js"></script>
3.1 变量
虽然是弱类型,但是其实内部是有类型的区别的。
- 变量类型:
数值类型: number
字符串类型: string
对象类型: object
布尔类型: boolean
函数类型: function
- 特殊值:
undefined 未定义,所有js变量没有初始值时都是undefined
null 空值
NAN Not a Number 非数字,非数值。(假如数字和字符串运算)
- 查看变量的类型:
var i = 1;
typeof(i);
所有变量,都可以作为一个Boolean类型的变量使用,认为是false的情况: |
---|
0 |
null |
undefined |
“” (空串) |
3.2 关系运算
1、
等于 | == | 简单的做字面值的比较 |
---|---|---|
全等于 | === | 还比较两个变量的数据类型 |
var a = 1;
var b = "1";
alert(a == b); // true
alert(a === b); // false
2、
&&表达式全为真 | 返回最后一个表达式的值 |
---|---|
&&有一个表达式为假 | 返回第一个为假的表达式的值 |
alert(true && "abc"); // abc
alert("abc" && null); // null
3、
||表达式全为假 | 返回最后一个表达式的值 |
---|---|
||只有一个是真 | 返回第一个为真的表达式的值 |
其实&&和||也就是,返回第一个能判断整个运算值的那个表达式
3.3 数组
定义格式:
var 数组名 = [];
var arr = [1,'abc',true];
只要对数组下标进行赋值,那么就会自动给数组做扩容操作。
var arr = ['111'];
alert( arr.length + " " + arr[0]); // 111 1
arr[3] = "123";
alert(arr.length + " " + arr[3]); // 4 123
alert(arr[1]); // undefined
遍历:
var a = ['1', 2, false];
var s = "";
for (var i = 0; i < a.length; i++) {
s += " " + a[i];
}
alert(s); // 1 2 false
3.4 函数
两种定义方法:
function 函数名(参数){ }
function f(a,b){
alert(a + ' ' + b);
return a;
}
形参不需要定义,返回值也不需要
var 函数名 = function(参数){ }
不管是有参无参或者是有返回值,都和第一种没有区别
arguments:
如同数组一样使用即可,他的值是调用时传的值。
function f() {
alert(arguments.length);
// 像数组一样操作
var ans = "";
for (var i = 0; i < arguments.length; i++) {
ans += " " + arguments[i];
}
alert(ans);
}
f(1, 2, 3, 4);
3.5 对象
对象的定义:
1.
var 变量名 = new Object(); // 对象实例(空对象)
变量名.属性 = 值; // 定义一个属性
变量名.函数名 = function(){}; // 定义一个函数
对象的访问:
变量名.属性 / 函数名();
var obj = new Object();
obj.name = "文仔";
obj.age = 18;
obj.f = function () {
alert("name = " + obj.name + " age = " + obj.age);
}
obj.f();
2.
对于定义,也可以:
var 变量名 = {}; // 空对象
var 变量名 = {
属性: 值, // 定义一个属性
属性: 值, // 每个之间加“,” 最后一个不加
函数名: function(){}
};
var obj = {
name: "哥哥",
age: 18,
fun: function () {
alert("name = " + obj.name + " age = " + obj.age);
}
};
obj.fun();
3.6 事件
事件 | 名称 | 备注 |
---|---|---|
onload | 加载完成事件 | 界面加载完成之后,常用于做界面的js代码初始化操作 |
onclick | 单机事件 | 常用于按钮的点击相应操作 |
onblur | 失去焦点事件 | 常用于输入框失去焦点后验证其输入内容是否合法 |
onchange | 内容发生变化操作 | 常用于下拉列表和和输入框内容发生改变后操作 |
onsubmit | 表单提交事件 | 常用于表单提交前,验证所有表单项是否合法 |
1. 事件的注册(绑定)
告诉浏览器,当事件相应后要执行哪一些代码
分为静态注册和动态注册两种;
- 静态注册事件:通过html标签的事件属性直接赋予事件响应后的代码。
- 动态注册事件:先通过js代码得到标签的dom对象,然后再通过dom对象.事件名=function(){}。
动态注册的步骤:
- 获取标签对象
- 标签对象.事件名 = function(){};
2. oncload事件
- 静态
function onloadFun() {
alert("静态注册onload事件");
}
<body onload="onloadFun();"></body>
- 动态
window.onload = function () {
alert("动态注册");
}
2. onclick事件
<script type="text/javascript">
function onclickFun() {
alert("静态注册");
}
window.onload = function () {
// 1. 获取标签对象
var btnobj = document.getElementById("btn02"); // z
// 2. 标签名.事件名 = function(){}
btnobj.onclick = function () {
alert("动态注册");
}
}
</script>
<body>
<button onclick="onclickFun()">按钮1</button>
<button id="btn02">按钮2</button>
</body>
3. onblur事件
不写静态注册了,简洁一些;
静态注册就是在html标签里面调用;
动态就是在window.onload = function () {} 里面声明
window.onload = function () {
var pass = document.getElementById("pass");
var text = document.getElementById("text");
pass.onblur = function (){
alert(pass.value);
}
text.onblur = function (){
alert(text.value);
}
}
<body>
<form>
<input type="text" id="text"/>
<input type="password" id="pass"/>
</form>
</body>
4. onchange事件
window.onload = function () {
var onChangeObj = document.getElementById("select");
onChangeObj.onchange = function () {
alert(onChangeObj.value);
}
}
<body>
<select id="select">
<option>国家</option>
<option>中国</option>
<option>日本</option>
<option>美国</option>
</select>
</body>
5. onsubmit事件
<script type="text/javascript">
<!--静态注册-->
function onsubFun() {
var text = document.getElementById("text");
if (text.value.length < 6) {
alert("不符合规范");
return false;
}
}
window.onload = function () {
var formObj = document.getElementById("form02");
formObj.onsubmit = function () {
var text = document.getElementById("te");
if (text.value.length < 6) {
alert("不符合规范");
return false;
}
}
}
</script>
<body>
<form action="http://www.baidu.com" method="get" onsubmit="return onsubFun()">
<input type="text" name="text" id="text"/>
<input type="submit" value="静态注册"/>
</form>
<br/>
<br/>
<form action="http://www.baidu.com" id="form02">
<input type="text" name="text" id="te"/>
<input type="submit" value="动态注册"/>
</form>
</body>
3.7 DOM 模型
就是把文档中的标签,属性,文本,转换成对象来管理。
DOM对象常用的方法:
方法 | 描述 |
---|---|
close | 关闭用 document.open() 方法打开的输出流,并显示选定的数据。 |
getElementById() | 返回对拥有指定 id 的第一个对象的引用。 |
getElementsByName | 返回带有指定名称的对象集合。 |
getElementsByTagName | 返回带有指定标签名的对象集合。 |
open | 打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。 |
write | 向文档写 HTML 表达式 或 JavaScript 代码。 |
writeln | 等同于 write() 方法,不同的是在每个表达式之后写一个换行符 |
1. 样例:验证用户名
5-12位,且包含下划线、字母、数字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MOMO的网址</title>
<script type="text/javascript">
window.onload = function () {
var btn = document.getElementById("bt");
var text = document.getElementById("text");
btn.onclick = function () {
var userText = text.value;
/*
* test方法用来测试字符串是否符合自己的规则
*/
var patt = /^\w{5,12}$/;
if (patt.test(userText))
alert("提交成功");
else
alert("提交失败");
}
}
</script>
</head>
<body>
<form>
<input id="text" type="text"/>
<input id="bt" type="button" value="校验"/>
</form>
</body>
</html>
2. 正则表达式对象regexp
创建正则表达式对象 :
var patt=new RegExp(pattern表达式,modifiers修饰符);
或更简单的方法
var patt=/pattern/modifiers;
- 修饰符
修饰符用于执行区分大小写和全局匹配:
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 |
m | 执行多行匹配。 |
- 表达式
方括号用于查找某个范围内的字符:
表达式 | 描述 |
---|---|
[abc] | 查找方括号之间的任何字符。 |
[^abc] | 查找任何不在方括号之间的字符。 |
[0-9] | 查找任何从 0 至 9 的数字。 |
[a-z] | 查找任何从小写 a 到小写 z 的字符。 |
[A-Z] | 查找任何从大写 A 到大写 Z 的字符。 |
[A-z] | 查找任何从大写 A 到小写 z 的字符。 |
[adgk] | 查找给定集合内的任何字符。 |
[^adgk] | 查找给定集合外的任何字符。 |
应该都是是否包含以上的条件;
包含 true
不包含 false
- 元字符:
是拥有特殊含义的字符:
元字符 | 描述 |
---|---|
. | 查找单个字符,除了换行和行结束符。 |
\w | 查找数字、字母及下划线。 |
\W | 查找非单词字符。 |
\d | 查找数字。 |
\D | 查找非数字字符。 |
\s | 查找空白字符。 |
\S | 查找非空白字符。 |
\b | 匹配单词边界。 |
\B | 匹配非单词边界。 |
\0 | 查找 NULL 字符。 |
\n | 查找换行符。 |
\f | 查找换页符。 |
\r | 查找回车符。 |
\t | 查找制表符。 |
\v | 查找垂直制表符。 |
\xxx | 查找以八进制数 xxx 规定的字符。 |
\xdd | 查找以十六进制数 dd 规定的字符。 |
\uxxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符。 |
- 量词:
量词 | 描述 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串。 例如,/a+/ 匹配 “candy” 中的 “a”,“caaaaaaandy” 中所有的 “a”。 |
n* | 匹配任何包含零个或多个 n 的字符串。 例如,/bo*/ 匹配 “A ghost booooed” 中的 “boooo”,“A bird warbled” 中的 “b”,但是不匹配 “A goat grunted”。 |
n? | 匹配任何包含零个或一个 n 的字符串。 例如,/e?le?/ 匹配 “angel” 中的 “el”,“angle” 中的 “le”。 |
n{X} | 匹配包含 X 个 n 的序列的字符串。 例如,/a{2}/ 不匹配 “candy,” 中的 “a”,但是匹配 “caandy,” 中的两个 “a”,且匹配 “caaandy.” 中的前两个 “a”。 |
n{X,} | X 是一个正整数。前面的模式 n 连续出现至少 X 次时匹配。 例如,/a{2,}/ 不匹配 “candy” 中的 “a”,但是匹配 “caandy” 和 “caaaaaaandy.” 中所有的 “a”。 |
n{X,Y} | X 和 Y 为正整数。前面的模式 n 连续出现至少 X 次,至多 Y 次时匹配。 例如,/a{1,3}/ 不匹配 “cndy”,匹配 “candy,” 中的 “a”,“caandy,” 中的两个 “a”,匹配 “caaaaaaandy” 中的前面三个 “a”。注意,当匹配 “caaaaaaandy” 时,即使原始字符串拥有更多的 “a”,匹配项也是 “aaa”。 |
n$ | 匹配任何结尾为 n 的字符串。 |
^n | 匹配任何开头为 n 的字符串。 |
?=n | 匹配任何其后紧接指定字符串 n 的字符串。 |
?!n | 匹配任何其后没有紧接指定字符串 n 的字符串。 |
- runoo+b,可以匹配 runoob、runooob、runoooooob 等,+ 号代表前面的字符必须至少出现一次(1次或多次)。
- runoo*b,可以匹配 runob、runoob、runoooooob 等,* 号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次)。
- colou?r 可以匹配 color 或者 colour,? 问号代表前面的字符最多只可以出现一次(0次、或1次)。
判断输入是否符合规范
innerHTML属性 : 标识起始标签和结束标签中的内容 – 可读 – 可写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MOMO的网址</title>
<script type="text/javascript">
window.onload = function () {
var patt = /^\w{5,8}$/;
var usernameObj = document.getElementById("userid");
usernameObj.onblur = function () {
var usernameSpanObj = document.getElementById("useridSpan");
if (patt.test(usernameObj.value) == false) {
usernameSpanObj.innerHTML = "不符合规范";
}else {
usernameSpanObj.innerHTML = "";
}
}
}
</script>
</head>
<body>
<form>
<input type="text" id="userid">
<span id="useridSpan" style="color: red"></span>
</form>
</body>
</html>
后面跟着图片:
<script type="text/javascript">
window.onload = function () {
var patt = /^\w{5,8}$/;
var usernameObj = document.getElementById("userid");
usernameObj.onblur = function () {
var usernameSpanObj = document.getElementById("useridSpan");
if (patt.test(usernameObj.value) == false) {
usernameSpanObj.innerHTML = "<img src=\"https://z3.ax1x.com/2021/07/21/WU66HO.png\" height='25px'>";
} else {
usernameSpanObj.innerHTML = "<img src=\"https://z3.ax1x.com/2021/07/21/WU6yDK.png\" height='25px'>";
}
}
}
</script>
3. 方法:getElementsByName()
返回的是多个,也就 是一个包含多个标签对象的集合
这个集合的操作跟数组一样
集合中每个元素都是dom对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MOMO的网址</title>
<script type="text/javascript">
function checkAll() {
var hobies = document.getElementsByName("hobby");
for (var i = 0; i < hobies.length; i++) {
hobies[i].checked = true;
}
}
function checkNo() {
var hobies = document.getElementsByName("hobby");
for (var i = 0; i < hobies.length; i++) {
hobies[i].checked = false;
}
}
function checkReverse() {
var hobbies = document.getElementsByName("hobby");
for (var i = 0; i < hobbies.length; i++) {
hobbies[i].checked = !hobbies[i].checked;
}
}
</script>
</head>
<body>
<input type="checkbox" name="hobby" value="cpp">C++
<input type="checkbox" name="hobby" value="JS">JS
<input type="checkbox" name="hobby" value="Java">Java
<br/>
<button onclick="checkAll()">全选</button>
<button onclick="checkNo()">全不选</button>
<button onclick="checkReverse()">反选</button>
</body>
</html>
**getElementsByTagName :**按照标签名进行查询,并返回集合。
document查询的方法就是这三个。
<script type="text/javascript">
function checkAll() {
var hobies = document.getElementsByTagName("input");
for (var i = 0; i < hobies.length; i++) {
hobies[i].checked = true;
}
}
function checkNo() {
var hobies = document.getElementsByTagName("input");
for (var i = 0; i < hobies.length; i++) {
hobies[i].checked = false;
}
}
function checkReverse() {
var hobies = document.getElementsByTagName("input");
for (var i = 0; i < hobies.length; i++) {
hobies[i].checked = !hobies[i].checked;
}
}
</script>
3.8 节点的常用属性和方法
节点就是标签对象
1. 方法
通过具体的元素节点调用:
getElementByTagName();
获取当前节点的指定标签名孩子节点
- appendChild
为当前节点添加一个新的子节点,放在最后的子节点后 - cloneNode
返回当前节点的拷贝 - createAttribute
创建新的属性 - createCDATASection
创建包括给定数据的CDATA段 - createComment
创建一个注释节点 - createDocumentFragment
创建DocumentFragment对象 - createElement 创建一个元素节点
- createEntityReference
创建EntityReference对象 - createNode
创建给定类型,名字和命名空间的节点 - createPorcessingInstruction
创建操作指令节点 - createTextNode
创建包括给定数据的文本节点 - getElementsByTagName
返回指定名字的元素集合 - hasChildNodes
返回当前节点是否有子节点 - insertBefore
在指定节点前插入子节点 - Load
导入指定位置的XML文档 - loadXML
导入指定字符串的XML文档 - removeChild
从子结点列表中删除指定的子节点 - replaceChild
从子节点列表中替换指定的子节点 - Save
把XML文件存到指定节点 - selectNodes
对节点进行指定的匹配,并返回匹配节点列表 - selectSingleNode
对节点进行指定的匹配,并返回第一个匹配节点 - transformNode
使用指定的样式表对节点及其后代进行转换 - transformNodeToObject
使用指定的样式表将节点及其后代转换为对象
2. 属性
-
childNodes
获取当前节点的所有子节点列表(只读)
-
Attributes
获取节点的属性列表(只读),即HTML中标签上的属性值
a.attributes[0].value
-
dataType
返回此节点的数据类型 -
Definition
以DTD或XML模式给出的节点的定义(只读) -
Doctype
指定文档类型节点(只读) -
documentElement
返回文档的根元素(可读写) -
firstChild
返回当前节点的第一个子节点(只读) -
Implementation
返回XMLDOMImplementation对象 -
lastChild
返回当前节点最后一个子节点(只读) -
nextSibling
返回当前节点的下一个兄弟节点(只读) -
nodeName
返回节点的名字(只读) -
nodeType
返回节点的类型(只读) -
nodeTypedValue
存储节点值(可读写) -
nodeValue
返回节点的文本(可读写) -
ownerDocument
返回包含此节点的根文档(只读) -
parentNode
返回父节点(只读) -
Parsed
返回此节点及其子节点是否已经被解析(只读) -
Prefix
返回名称空间前缀(只读) -
preserveWhiteSpace
指定是否保留空白(可读写) -
previousSibling
返回此节点的前一个兄弟节点(只读) -
Text
返回此节点及其后代的文本内容(可读写) -
url
返回最近载入的XML文档的URL(只读) -
Xml
返回节点及其后代的XML表示(只读) -
nextSibling
返回相领的节点 -
innerHTML
获取/设置起始标签和结束标签中的内容 -
innerText
获取/设置起始标签和结束标签中的文本
二、PHP
用PHP+JS可以做简单的web程序
PHP连接数据库
JS调用
HTML --》 PHP
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>form提交</title>
<script>
function f1() {
var request = new XMLHttpRequest(); //建立request请求
request.open('post', 'test.php'); //发送对象是boke.php 发送post
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //请求头 默认即可
var name = form1.name.value; //获取文本框内输入的内容
request.send("name=" + name); //发送request请求 请求可以有多个post 格式:key1=value1&key2=value2 php端根据key取出value
//确认接收消息
request.onreadystatechange = function() {
// readyState=4为php收到并返回值 status为返回字段为200火304
if (request.readyState == 4 && (request.status == 200 || request.status == 304)) {
//弹出窗口显示php返回的值
alert(request.responseText);
}
}
}
</script>
</head>
<body>
<form id="form1">
<input type="text" name="name">
<!-- 点击按钮调用js的f1方法-->
<input type="submit" onclick="f1()">
</form>
</body>
</html>
PHP接收
$_POST['name']
1. 读取数据
<?php
$servername = "127.0.0.1";
$username = "root";
$password = "623724";
$dbname = "test_db";
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
$sql = "SELECT col from test";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// 输出数据
while($row = $result->fetch_assoc()) {
echo "col: " . $row["col"]. "<br>";
}
} else {
echo "0 结果";
}
$conn->close();
?>
2. 插入数据
<?php
$servername = "localhost";
$username = "root";
$password = "623724";
$dbname = "test_db";
// 创建连接
$conn = new mysqli($servername, $username, $password, $dbname);
// 检测连接
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
$sql = "INSERT INTO test VALUES ('".$_POST['name']."')";
if ($conn->query($sql) === TRUE) {
echo "新记录插入成功";
} else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
$conn->close();
?>
三、jQuery
就是Javascript和查询(Query)
1. 语法
1.1 杂
- 页面加载完之后:
$(function () {}) ------> window.onload = function () {}
全写:$(document).ready( function () {} )
- HelloWord
<script type="text/javascript">
// 表示页面加载完成之后 相当于 window.onload = function () {}
$(function () {
// 获取Id元素
var $btnObj = $("#btn01");
$btnObj.click(function (){
alert("JQuery单机");
});
});
</script>
-
JQuery核心函数 $()
-
传入参数为 【函数】时
表示页面加载完成之后。相当于 window.onload = function () {}
-
传入参数为 【HTML字符串】时
根据这个字符串创建元素节点对象
<script type="text/javascript"> // 表示页面加载完成之后 相当于 window.onload = function () {} $(function () { // 新加入btn02 $("<button id=\"btn02\">测试按钮02</button>\n").appendTo("body"); // 为新加的btn02设置点击事件 $("#btn02").click(function () { alert("123"); }); }); </script>
-
传入参数为 【选择器字符串】时
- $(“#id属性值”)
- $(“标签名”)
- $(“.class属性值”)
-
传入参数为 【DOM对象】时
会把DOM对象转换成jQuery对象
jQuery对象是dom对象的数组 + jQuery提供的一系列功能函数
-
接4:dom对象和jQuery对象使用的区别
- dom对象的方法jQuery对象是用不了的
- jQuery对象的方法dom对象是用不了的
- 可以将jQuery对象作为数组使用,$jq_name[i] 直接就可以调用
<script type="text/javascript"> $(function () { var $btn = $("#btn01"); // 这样就是一个dom对象了 alert($btn[0].innerText); }); </script>
-
-
Dom对象和jQuery对象互转
- dom --> jQuery
- 先有DOM对象
- $(DOM对象)就可以转换成jQuery对象
- jQuery --> dom
- 先有jQuery对象
- jQuery对象[下标] 取出相应的DOM对象
- dom --> jQuery
-
除了上面三种基本选择器,还有一种是组合选择器
将每一个选择器匹配到的元素合并后一起返回。你可以指定任意多个选择器,并将匹配到的元素合并到一个结果内。
HTML: <div>div</div> <p class="myClass">p class="myClass"</p> <span>span</span> <p class="notMyClass">p class="notMyClass"</p> jQuery: $("div,span,p.myClass") div标签,span标签,p标签的class是myClass的元素 结果: [ <div>div</div>, <p class="myClass">p class="myClass"</p>, <span>span</span> ] 结果的顺序是HTML中的顺序!!!
1.2 jQuery对象的方法
-
css()方法
直接设置css样式 $("#div01").css("background-color", "#bbffaa");
-
attr()方法
修改属性值。
.attr(name, value)
-
val()
可以操作表单项的value属性值。可以设置和获取
1.3 循环
使用each方法:obj.each(套函数);
this就是当前的对象
例子❌:获取当前勾选的多选框
html:
<button id="btn01">确定</button>
<input type="checkbox" name="c" value="1">1
<input type="checkbox" name="c" value="2">2
<input type="checkbox" name="c" value="3">3
<input type="checkbox" name="c" value="4">4
js:
$(function () {
$("#btn01").click(function () {
var $checkboxs = $(":checkbox:checked");
$checkboxs.each(function () {
alert(this.value); // 当前的对象
})
});
});
1.4 确认弹窗
点击“确认”–返回true
点击“取消”–返回false
confirm("你好呀")
2. 选择器
2.1 基本选择器
在1.3中
2.2 层级选择器
-
在给定的祖先元素下匹配所有的后代元素HTML 代码:
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> </fieldset> </form> <input name="none" />
jQuery 代码:
$("form input")
结果:
[ <input name="name" />, <input name="newsletter" /> ]
-
parent > child :在给定的父元素下匹配所有的子元素(低一级)
HTML 代码:
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> // 这个不是子级元素 </fieldset> </form> <input name="none" />
jQuery 代码:
$("form > input")
结果:
[ <input name="name" /> ]
-
prev + next :匹配所有紧接在 prev 元素后的 next 元素 (prev后面的一个元素,成对)
HTML 代码:
<form> <label>Name:</label> <input name="name" /> // 1 <input name="name02" /> // 这个不算 <fieldset> <label>Newsletter:</label> <input name="newsletter" /> // 2 </fieldset> </form> <input name="none" />
jQuery 代码:
$("label + input")
结果:
[ <input name="name" />, <input name="newsletter" /> ]
-
prev ~ siblings :匹配 prev 元素之后的所有 siblings 元素**(同辈的所有)**
HTML 代码:
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> </fieldset> </form> <input name="none" />
jQuery 代码:
$("form ~ input")
结果:
[ <input name="none" /> ]
2.3 过滤选择器
基本过滤选择器
- :first
获取第一个元素
HTML 代码:
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
</ul>
jQuery 代码:
$('li:first');
结果:
[ <li>list item 1</li> ]
- :last()
获取最后个元素
HTML 代码:
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
</ul>
jQuery 代码:
$('li:last')
结果:
[ <li>list item 5</li> ]
-
:not(selector)
去除所有与给定选择器匹配的元素
在jQuery 1.3中,已经支持复杂选择器了(例如:not(div a) 和 :not(div,a))
HTML 代码:
<input name="apple" /> <input name="flower" checked="checked" />
jQuery 代码:
$("input:not(:checked)")
结果:
[ <input name="apple" /> ]
-
:even
先找到所有此标签的元素序列,但是只返回偶数下标的元素(0,2,4…); 也就是第1,3,5个…
HTML 代码:
<table>
<tr><td>Header 1</td></tr>
<tr><td>Value 1</td></tr>
<tr><td>Value 2</td></tr>
</table>
jQuery 代码:
$("tr:even")
结果:
[ <tr><td>Header 1</td></tr>, <tr><td>Value 2</td></tr> ]
-
:odd
奇数下标:用法同even
-
:eq(index)
HTML 代码:
<table>
<tr><td>Header 1</td></tr>
<tr><td>Value 1</td></tr>
<tr><td>Value 2</td></tr>
</table>
jQuery 代码:
$("tr:eq(1)")
结果:
[ <tr><td>Value 1</td></tr> ]
-
:gt(index)
匹配所有大于给定索引值的元素
HTML 代码:
<table> <tr><td>Header 1</td></tr> <tr><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table>
jQuery 代码:
$("tr:gt(0)")
结果:
[ <tr><td>Value 1</td></tr>, <tr><td>Value 2</td></tr> ]
-
:lt(index)
匹配所有小于给定索引值的元素,用法同gt
-
:header
匹配如 h1, h2, h3之类的标题元素
$(":header").css("background", "#EEE");
-
:animated
匹配所有正在执行动画效果的元素
内容过滤器
过滤器 | 作用 | 用法 |
---|---|---|
:contains(text) | 匹配包含给定文本的元素 | $("div:contains('John')") 只要包含’John’的div |
:empty | 匹配所有不包含子元素或者文本的空元素 | $("td:empty") 空的td |
:parent | 匹配含有子元素或者文本的元素 | 就是非空的 |
:has(selector) | 匹配含有选择器所匹配的元素的元素 | $("div:has(p)") 查找包含p标签的div |
属性过滤选择器
过滤器 | 作用 | 用法 |
---|---|---|
[attribute] | 匹配包含给定属性的元素。 | $("div[id]") 有id属性的div |
[attribute=value] | 匹配给定的属性是某个特定值的元素 | $("input[name='newsletter']").attr("checked", true); 查找所有 name 属性是 newsletter 的 input 元素 |
[attribute!=value] | 匹配所有不含有指定的属性,或者属性不等于特定值的元素。 | 同上;注意没有这个属性的也被选中 |
[attribute^=value] | 匹配给定的属性是以某些值开始的元素 | 下面: |
HTML 代码:
<input name="newsletter" />
<input name="milkman" />
<input name="newsboy" />
jQuery 代码:
$("input[name^='news']")
结果:
[ <input name="newsletter" />, <input name="newsboy" /> ]
[attribute$=value] | 匹配给定的属性是以某些值结尾的元素 | 同上 |
---|---|---|
[attribute=value]* | 匹配给定的属性是以包含某些值的元素 | $("input[name*='man']") 查找所有 name 包含 ‘man’ 的 input 元素 |
[selector1][selector2][selectorN] | 复合属性选择器,需要同时满足多个条件时使用。 | $("input[id][name$='man']") 找到所有含有 id 属性,并且它的 name 属性是以 man 结尾的 |
表单过滤器
就是过滤几个表单。
-
:input 匹配所有的input元素
-
:text 匹配type是text的表单元素
-
其他的表单也是这样
-
例子:查找所有文本框
HTML 代码:
<form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery 代码: $(":text") 结果: [ <input type="text" /> ]
-
表单对象属性
-
:enabled
匹配所有可用元素,就是正常元素
$("input:enabled")
-
:disabled
匹配所有不可用元素
HTML 代码:
<form>
<input name="email" disabled="disabled" /> // 通过disabled设置
<input name="id" />
</form>
jQuery 代码:
$("input:disabled")
结果:
[ <input name="email" disabled="disabled" /> ]
-
:checked
匹配所有选中的被选中元素(复选框、单选框等,不包括select中的option)
-
:selected
匹配所有选中的option元素
HTML 代码:
<select> <option value="1">Flowers</option> <option value="2" selected="selected">Gardens</option> <option value="3">Trees</option> </select>
jQuery 代码:
$("select option:selected") 层级选择器 + 过滤选择器
结果:
[ <option value="2" selected="selected">Gardens</option> ]
样例:
html:
<button id="btn01">确定</button>
<select multiple="multiple"> // 可以多选
<option>张崇文</option>
<option selected="selected">齐文欣</option>
<option>爸爸</option>
<option>妈妈</option>
</select>
js:
$(function () {
$("#btn01").click(function () {
$selectes = $("select option:selected");
$selectes.each(function () {
alert(this.innerText);
})
});
});
3. 筛选
-
过滤
-
eq(index|-index)
$("p").eq(1)
,p标签中的第二个
-
first()
-
last()
-
filter(expr|obj|ele|fn)
-
筛选出与指定表达式匹配的元素集合。
这个方法用于缩小匹配的范围。用逗号分隔多个表达式
里面就可以写多个过滤器条件
-
-
is(expr|obj|ele|fn)
- 根据选择器、DOM元素或 jQuery 对象来检测匹配元素集合,如果其中至少有一个元素符合这个给定的表达式就返回true。也可以写一个函数,返回true或false
-
has(expr|ele)
- 返回 含有指定元素 的元素
-
not(expr|ele|fn)
- 删除所匹配选择器的元素
-
-
查找
- children([expr])
- 查询匹配的子元素
- find(expr|obj|ele)
- 匹配的后代的元素
- next([expr])
- 返回当前元素的下一个兄弟元素
- nextall([expr])
- 返回当前元素后面的 所有兄弟元素
- nextUntil([exp|ele][,fil])
- 一个区间:(当前元素, 匹配的元素) 左开右开
- parent([expr])
- 返回父元素
- prev([expr])
- 返回当前元素的上一个兄弟元素
- prevall([expr])
- 返回当前元素的 前面全部的的元素
- prevUntil([exp|ele][,fil])
- (匹配的元素,当前元素)
- siblings([expr])
- 返回所有兄弟元素
- add()
- 将匹配的元素添加到当前的元素集合中,并返回
- children([expr])
4. 属性
4.1 HTML代码/文本/值
不传参数是获取,传递参数是设置
属性 | 作用 | 备注 |
---|---|---|
html() | 设置和获取 起始标签和结束标签中的内容 | 和dom属性 innerHTML 一样 |
text() | 设置和获取 起始标签和结束标签中本文 | 和dom属性 innerText 一样 |
val() | 设置和获取 表单项的value值 | 和dom属性 value 一样 |
val()例子:
html:
<body>
<button id="btn01">确定</button>
<form>
<!-- 单选-->
<input type="radio" value="1" name="1">1
<input type="radio" value="2" name="1">2
<input type="radio" value="3" name="1">3
<br/>
<br/>
<!-- 复选-->
<input type="checkbox" value="4" name="1">4
<input type="checkbox" value="5" name="1">5
<input type="checkbox" value="6" name="1">6
</form>
</body>
js:
$(function () {
$("#btn01").click(function () {
// $(":radio").val(['1']);
// $(":checkbox").val(['4','5']);
// 同时设置多个
$(":radio,:checkbox").val(['1','6', '5']);
});
});
4.2 属性
属性 | 作用 | 备注 |
---|---|---|
attr() | 可以设置和获取属性的值 | 一个参数:获取指定参数的属性值。 两个参数:设置指定参数的属性值 当前参数没有设置的情况下返回undefined(官方认为这是错误的) 不推荐操作:checked、readOnly、selected、disabled |
prop() | 可以设置和获取属性的值 | 当前参数没有设置的情况下返回false 选中的时候返回true 只推荐操作:checked、readOnly、selected、disabled |
HTML:
<body>
<button id="btn01">确定</button>
<input type="text" name="text">
</body>
JS:
$(function () {
$("#btn01").click(function () {
// 获取
alert($(":text").attr("name"));
// 设置
$(":text").attr("name", "changeName");
});
});
<body>
<button id="btn01">确定</button>
<input type="checkbox" checked="checked" >多选
</body>
$(function () {
$("#btn01").click(function () {
$(":checkbox").prop("checked", false);
});
});
5. 增删改操作
5.1 内部插入
方法 | 作用 | 备注 |
---|---|---|
appendTo | 把a插入到b的子元素末尾,成为最后一个子元素 | a.appendTo(b) |
prependTo | 把a插入到b的子元素前面,成为第一个子元素 | a.prependTo(b) |
5.2 外部插入
方法 | 作用 | 备注 |
---|---|---|
insertAfter() | 得到ba | a.insertAfter(b) |
insertBefore() | 得到ab | a.insertBefore(b) |
5.3 替换
方法 | 作用 | 备注 |
---|---|---|
replaceWith() | 用一个b替换掉所有的a | a.replaceWith(b) |
replaceAll() | 用a替换掉b(一个换一个) | a.replaceAll(b) |
5.4 删除
方法 | 作用 | 备注 |
---|---|---|
remove() | 删除a标签 | a.remove() |
empty() | 清空a标签内的内容 | a.empty() |
6. CSS
方法 | 作用 | 备注 |
---|---|---|
addClass | 添加样式 | |
removeClass | 删除样式 | 删除全部获取其中几个 |
toggleClass | 添加/删除样式 | 当前样式,有就添加,没有删除 |
offset | 获取/改变坐标 | |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
var $d = $("div");
// 增加样式
$("#btn01").click(function () {
// 多个样式用空格分开
$d.addClass("redColor border");
});
// 删除样式
$("#btn02").click(function () {
// 不加参数是删除全部的样式
$d.removeClass("redColor");
});
// 删除或者添加样式
$("#btn03").click(function () {
// 有就删除 没有就添加
// 没有参数的时候,看以前的样式,一开始设置为空,再点就还原
$d.toggleClass("blackColor");
});
$("#btn04").click(function () {
console.log($d.offset());
$d.offset({
top: 100,
left: 50
});
console.log($d.offset());
});
});
</script>
<style type="text/css">
div.redColor {
background: red;
}
div.border {
border: yellow 30px solid;
}
div.blackColor {
background: black;
}
</style>
</head>
<body>
<div style="height: 300px; width: 300px">3</div>
<button id="btn01">addClass</button>
<button id="btn02">removeClass</button>
<button id="btn03">toggleClass</button>
<button id="btn04">offset</button>
</body>
</html>
7. 动画操作
以下动画操作都可以添加参数:
- 第一个参数是时长,以毫秒为单位:1000ms=1s。(宽高慢慢变化)
- 第二个参数是动画完成后的回调函数(动画完成后自动调用 的函数);
7.1 基本动画
方法 | 作用 | 备注 |
---|---|---|
show | 隐藏元素显示 | |
hide | 可见元素隐藏 | |
toggle | 可见就隐藏;不可见就显示 |
7.2 淡入淡出动画
方法 | 作用 | 备注 |
---|---|---|
fadeIn | 淡入 | |
fadeOut | 淡出 | |
fadeTo | 在指定时长内将透明度修改到指定的值 | 0透明 0.5半透明 1可见 三个参数:时间、透明度、回调函数 |
fadeTOggle | 淡入/淡出 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
var $d = $("div");
$("#btn01").click(function () {
$d.show();
});
$("#btn02").click(function () {
$d.hide();
});
$("#btn03").click(function () {
$d.toggle(1000, f);
});
$("#btn04").click(function () {
$d.fadeIn();
});
$("#btn05").click(function () {
$d.fadeOut();
});
$("#btn06").click(function () {
$d.fadeIn();
});
$("#btn07").click(function () {
$d.fadeTo(1000, 0.5, function () {
alert("fadeTo完成");
});
});
// 循环
function f() {
$d.toggle(1000, f);
}
});
</script>
<style type="text/css">
</style>
</head>
<body>
<div style="height: 300px; width: 300px; background: antiquewhite; border: aqua 10px solid">3</div>
<button id="btn01">show</button>
<button id="btn02">hide</button>
<button id="btn03">toggle</button>
<button id="btn04">fadeIn</button>
<button id="btn05">fadeOut</button>
<button id="btn06">fadeTo</button>
<button id="btn07">fadeToggle</button>
</body>
</html>
8. 事件操作
页面加载完成之后的区别:
- js原生:页面加载完成之后,除了需要等浏览器内核解析完便签创建好DOM对象,还要等标签显示时需要的内容加载完成。如果是多个,只会执行最后一个。
- jQuery:页面加载完成之后,等浏览器内核解析完便签创建好DOM对象就会马上执行。如果是多个,会依次执行。
方法 | 作用 | 备注 |
---|---|---|
click | 传function函数是绑定事件 不传参数是触发事件 | |
mouseover | 鼠标移入事件 | |
mouseout | 鼠标移出使事件 | |
bind | 可以给元素一次性绑定一个或多个事件 | 多个事件用空格分开 .bind(“click mouseover”, function(){}); |
one | 使用上和bind一样,但是只会相应一次 | 设置的事件,只运行一次 |
unbind | 和bind方法相反:解除事件的绑定 | 可以解除一个或者多个 |
live | 也是用来绑定事件。它可以用来绑定选择器匹配的所有元素的事件。以后创建的(动态创建)也会绑定 | |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
$("h3:eq(0)").bind("click mouseover mouseout", function () {
console.log("这是bind绑定的事件");
});
$("button:eq(0)").click(function () {
$("h3").click();
});
$("h3:eq(1)").one("click mouseover mouseout", function () {
console.log("这是one绑定的事件");
});
$("button:eq(1)").click(function () {
$("h3").unbind("click");
});
$("h2").live("click", function () {
console.log("这是live绑定的事件");
});
// 由于上面设置了live 所以新设置的事件也是有效的
$("button:eq(2)").click(function () {
$("<h2>新的H2</h2>").appendTo( $("h2").first());
});
});
</script>
<style type="text/css">
</style>
</head>
<body>
<h3 style="background: aqua">h3的事件</h3>
<button>触发h3的事件</button>
<h3 style="background: aqua">h3的事件</h3>
<button>移出h3的事件</button>
<br/>
<br/>
<h2>live事件</h2>
<button>新建h2</button>
</body>
</html>
8.1 事件的冒泡
就是在父元素和子元素绑定了相同的事件,如果子元素触发,那么父元素也会触发,这就是冒泡。
可以在子元素中return false;
来组织冒泡的发生。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
$("div").click(function () {
alert("这是div事件");
});
$("span").click(function () {
alert("这是span事件");
// 在子元素中return false; 可以阻止冒泡
return false;
});
});
</script>
<style type="text/css">
</style>
</head>
<body>
<div style="height: 300px; width: 200px; background: antiquewhite">
这是一个div
<br/>
<span>
这是一个span
</span>
</div>
</body>
</html>
8.2 事件对象
事件对象是封装触发的事件信息的一个js对象
获取:在事件的fucntion(event){}参数列表中添加一个参数,参数名习惯取为event
event就是事件对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
// 原生js事件对象
window.onload = function () {
document.getElementById("div01").onclick = function (event) {
console.log(event);
};
}
$(function () {
// jQuery事件对象
$("#div02").click(function (event) {
console.log(event);
});
// 获取事件对象,判断是何种事件
$("#div03").bind("click mouseover", function (event) {
if (event.type == "click")
console.log("鼠标点击事件");
if (event.type == "mouseover")
console.log("鼠标移入事件");
})
});
</script>
<style type="text/css">
</style>
</head>
<body>
<div id="div01" style="height: 300px; width: 200px; background: antiquewhite">
原生js事件对象
</div>
<div id="div02" style="height: 300px; width: 200px; background: darkred">
jQuery事件对象
</div>
<div id="div03" style="height: 300px; width: 200px; background: yellow">
bind事件绑定,然后获取是何种事件触发
</div>
</body>
</html>
样例:图片跟随
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
var $img = $("#img02");
$img.hide();
$("#img01").bind("mouseover mouseout mousemove", function (event) {
if (event.type == "mouseover") {
$img.show();
} else if (event.type == "mouseout") {
$img.hide();
} else if (event.type == "mousemove") {
$img.offset({
left: event.pageX + 3,
top: event.pageY + 3
});
}
});
});
</script>
<style type="text/css">
</style>
</head>
<body>
<img id="img01" src="../imagin/niu.jpg" height="100px">
<div>
<img id="img02" src="../imagin/niu.jpg">
</div>
</body>
</html>
四、XMl
使用dom4j解析xml
package com.bzu;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Test;
import java.util.List;
public class Dom4jTest {
// 1. 读入xml文件
@Test
public void test_1() throws Exception {
// SAXReader输入流,用来读取xml配置文件,生成Document对象
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/books.xml");
System.out.println(document);
}
// 2. 获取标签内容
@Test
public void test_2() throws Exception {
// SAXReader输入流,用来读取xml配置文件,生成Document对象
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/books.xml");
// 得到根节点
Element rootElement = document.getRootElement();
// System.out.println(rootElement);
// 获取book标签(村子啊多个,所以用elements,一个用element)
List<Element> books = rootElement.elements("book");
for (Element book : books) {
// asXML 把标签对象转为标签字符串
// System.out.println(book.asXML());
Element nameElement = book.element("name");
// System.out.println(nameElement.asXML());
// 获取标签内的文本内容
String nameText = nameElement.getText();
// System.out.println(nameText);
// 直接 获取指定标签的文本内容
String price = book.elementText("price");
// System.out.println(price);
// 获取属性值
String sn = book.attributeValue("sn");
// System.out.println(sn);
System.out.println(new book(nameText, sn, price));
}
}
}
五、Tomcat
-
启动
catalina run
-
部署服务器
-
将工程文件放到webapps目录下,直接访问就行
-
工程名不在tomcat文件中,在其他目录下。 在tomcat目录:conf\Catalina\localhost,下创建xml配置文件:
<!-- Context表示一个工程上下文 path表示工程的访问路径:即用户输入的网址路径 后来验证,发现是这个xml文件的名称,即path和xml配置文件名相同即可 docBase表示真实的工程目录 --> <Context path="/test_01" docBase = "D:\EnglishCatalog\phpstudy_pro\WWW" />
-
没有工程名,默认访问ROOT目录
-
-
Idea部署:先将tomcat地址添加到Idea,然后创建时选择Java En…即可
-
idea启动tomcat
-
重新运行时的几个选项
- 工程路径、运行的浏览器、端口号都可以更改
修改热部署:更改的资源,在浏览器刷新就能看到变化
六、Servlet技术
Servlet是运行在Servlet容器中的Java类,它能处理Web客户的HTTP请求,并产生HTTP响应。
HTTP服务器负责静态页面解析,Servlet的请求转交给Servlet容器,Servlet容器会根据映射关系**(web.xml,注解@WebServlet )**调用相应的Servlet,Servlet将处理结果返回给容器,并通过HTTP服Servlet对请求的处理和响应过程可进一步细分为如下几个步骤:
①接收HTTP请求;
②取得请求信息,包括请求头和请求参数数据;
③调用其他Java类方法,完成具体的业务功能;
④实现到其他Web组件的跳转(包括重定向或请求转发);
⑤生成HTTP响应(包括HTML或非HTML响应)。
Servlet API包含两个软件包:
javax.servlet包
javax.servlet.http包
1. Servlet的体系结构
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "Momo", value = "/Momo")
public class Momo extends HttpServlet {
public Momo() {
System.out.println("1. 构造器方法");
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("2. init初始化方法");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
System.out.println("3. service == servlet被访问了");
}
@Override
public void destroy() {
super.destroy();
System.out.println("4. 销毁方法");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get请求");
}
// @Override
// protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("post请求");
//
// }
}
1.1 Servlet接口
1.2 GenericServlet类
定义
public abstract class GenericServlet
extends Object
implements Servlet, ServletConfig, Serializable
GenericServlet类是一个抽象类,是Servlet接口的直接实现,提供了除service()方法之外其他有关Servlet生命周期的方法;
1.3 HttpServlet类
定义
public abstract class HttpServlet extends GenericServlet implements Serializable
HttpServlet指能够处理HTTP请求的Servlet,它在原有Servlet接口上添加了对HTTP协议的处理,它比Servlet接口的功能更为强大。
1.4 Servlet生命周期
Servlet生命周期是指Servlet实例从创建到响应客户请求,直至销毁的过程。
Servlet生命周期可分为四个阶段:加载和实例化、初始化、处理请求、销毁。
- Servlet构造器方法
- init初始化方法
- service方法
- destroy销毁方法
注:1、2步是在第一次访问的时候,创建Servlet程序时调用
第3步每次访问都会调用
第4步在web工程停止时调用
1.5 执行逻辑
2. Servlet的声明配置
2.1 输出到界面
// 不需要重写service方法,因为在HttpServlet中,会直接调用相应的请求方法
// 只需要重写相应的请求方法:doGet doPost
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
// 解决中文乱码
resp.setContentType("text/html;charset=utf-8");
System.out.println("3. 处理请求");
PrintWriter out = resp.getWriter();
out.println("<p>处理请求aa123a</p>");
}
2.1 注解@WebServlet
2.3 xml配置
加载分为懒加载和一般加载:
- 懒加载:访问的时候启动servlet
- 一般加载:启动javaweb程序的时候启动servlet
映射地址:
<servlet-mapping>
<servlet-name>Momo</servlet-name>
映射成hello
<url-pattern>/hello</url-pattern>
</servlet-mapping>
配置缺省访问,如没有映射地址都访问Momo:
<url-pattern>/</url-pattern>
也可以设置多个<servlet-mapping>标签
<!-- servlet标签 给tomcat配置servlet程序 -->
<servlet>
<!-- servlet-name标签 Servlet程序起的一个别名(一般就是类名)-->
<servlet-name>Momo</servlet-name>
<!-- Servlet-clss 是Servlet程序的全类名-->
<servlet-class>cn.bzu.momo.Momo</servlet-class>
启动顺序
<load-on-startup>2</load-on-startup>
</servlet>
<!-- servlet-mapping标签 给servlet配置访问地址 -->
<servlet-mapping>
<!-- servlet-name 告诉服务器当前配置的地址给哪一个Servlet程序使用 -->
<servlet-name>Momo</servlet-name>
<!-- 配置访问地址
/ 斜杠在服务器解析的时候,表示地址为http://ip:port/工程路径
/hello 表示地址为:http://ip:port/工程路径/hello
-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
配置初始化参数:
-
Servlet单独的参数
<servlet> <servlet-name>Momo</servlet-name> <servlet-class>cn.bzu.momo.Momo</servlet-class> // context-param是上下文参数,属于整个web工程 <context-param> <param-name>id</param-name> <param-value>666</param-value> </context-param> </servlet>
-
共享参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
// 配置成公共的参数
<init-param>
<param-name>id</param-name>
<param-value>1934110608</param-value>
</init-param>
</web-app>
3. ServletConfig类
servlet程序的配置信息类。
Servlet程序和ServletConfig对象都是tomcat负责创建,我们负责使用。
Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象。
三大作用:
-
获取servlet程序的别名 servlet-name 的值
-
获取初始化对象 init-param
-
获取ServletContext对象
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// 1. 获取servlet程序的别名 servlet-name 的值
System.out.println("Servlet程序的别名:" + config.getServletName());
// 2. 获取初始化对象 init-param
System.out.println("Servlet参数:" + config.getInitParameter("id"));
// 3. 获取ServletContext对象
System.out.println(config.getServletContext());
}
4. ServletContext类
-
ServletContext是一个接口,表示Servlet上下文
-
一个web工程,只有一个ServletContext对象实例
-
ServletContext是一个域对象
-
可以像Map一样存取数据的对象,叫域对象
-
这里的域对象是指 存取数据的操作范围:整个web工程
-
存数据 取数据 删除 数据 Map put( ) get( ) remove( ) 域对象 setAttribute( ) getAttribute( ) removeAttribute( )
-
-
-
ServletContext在web工程启动时创建。在web工程停止时销毁
作用:
- 获取web.xml中配置的上下文参数context-param
- 获取当前的工程路径,格式:/工程路径
- 获取工程部署后服务器硬盘上的绝对路径
- 像Map一样存取数据
- 获取部署之后的配置文件
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取web.xml中配置的上下文参数context-param
ServletContext context = getServletConfig().getServletContext();
String id = context.getInitParameter("id");
System.out.println("context-param参数的values: \t" + id);
// 2. 获取当前的工程路径,格式:/工程路径
System.out.println("当前工程路径: \t" + context.getContextPath());
// 输出:当前工程路径: /03_Web
// 3. 获取工程部署后服务器硬盘上的绝对路径
/**
* / 斜杠被服务器解析为:http://ip:port/工程名/ 映射到IDEA代码的web目录
*/
System.out.println("工程部署的路径: \t" + context.getRealPath("/"));
System.out.println("工程路径下的index.jsp文件的绝对路径: \t" + context.getRealPath("/index.jsp"));
}
注:
getServletContext()
,也可以直接调用这个方法来获取Context
,为什么? 如果看这个的源码,那么就知道,其实是包装了一下,源码里也是利用Config
获取的的context
4. 用 Attribute
存取数据
用来共享数据,在一个Servlet中存储了数据之后,其它的Servley也可以访问到。但是重启工程,就没有了。
先启动a,后启动b。
@WebServlet(name = "a", value = "/a")
public class a extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
context.setAttribute("name", "MoMo");
System.out.println(context.getAttribute("name"));
}
}
@WebServlet(name = "b", value = "/b")
public class b extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println(context.getAttribute("name"));
}
}
5. Properties
配置文件
将properties
文件放到src
文件夹中,项目部署时会一起备份到一个路径中。
注:如果是maven
,则放在resourse
文件夹
先利用context
获取到properties
文件数据流,令InputStream
接收
然后用Properties
类的load
方法转为Properties
的数据
@WebServlet("/momo")
public class MoMo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
ServletContext context = getServletContext();
// 获取数据流
InputStream is = context.getResourceAsStream("/WEB-INF/classes/student.properties");
Properties properties = new Properties();
// 加载成properties
properties.load(is);
// 输出 na
System.out.println(properties.getProperty("name"));
// 设置一个新数据
properties.setProperty("new", "new");
System.out.println(properties.getProperty("new"));
// 部署之后的地址其实是:
// D:\EnglishCatalog\Code\JavaWeb\JavaWeb01\out\artifacts\Test_war_exploded\WEB-INF\classes\student.properties
// 而 / 代表当前项目的地址;所以:/WEB-INF/classes/student.properties
}
}
在其他类中读取:
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;
public class Test {
public static void main(String[] args) throws SQLException, IOException {
Properties properties = new Properties();
InputStream is = Test.class.getResourceAsStream("/druid.properties");
properties.load(is);
System.out.println(properties.getProperty("maxWait"));
}
}
6. HTTP
6.1 GET请求
-
请求行
-
请求的方式 GET
-
请求的资源路径 [+ ? + 请求参数]
-
请求的协议的版本号 HTTP/1.1
-
-
请求头
key :value 组成 不同的键值对,表示不同的含义
请求行:
GET /ZCW_Shopp/ HTTP/1.1
请求头:
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: Idea-e72cea2b=f3a2b575-dcd1-4828-92ed-5b418c0be762
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Cache-Control: max-age=0
key | 含义 | 说明 |
---|---|---|
Accept | 客户端可以接收的数据类型 | |
Accept-Language | 客户端可以接收的语言类型 | zh_CN 中文中国 en_US 英文美国 |
User-Agent | 浏览器的信息 | |
Accept-Encoding | 客户端可以接收的数据编码(压缩)格式 | |
Host | 请求的服务器ip 和 端口号 | |
Connection | 告诉服务器请求连接如何处理 | Keep-Alive 回传数据之后不要马上关闭连接 Closed 马上关闭 |
6.2 POST请求
-
请求行
-
请求头
key :value 组成 不同的键值对,表示不同的含义
-
请求体 ---->>> 发送给服务器的数据
POST /ZCW_Shopp/UserRegisterServlet HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 65
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/ZCW_Shopp/register.html
Cookie: Idea-e72cea2b=f3a2b575-dcd1-4828-92ed-5b418c0be762
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
name=value&name=value&name=value&name=value
key | 含义 | 说明 |
---|---|---|
Refere | 请求发起时,浏览器地址栏中的地址(数据的来源) | |
Content-Type | 发送数据的类型 | application/x-www-form-urlencoded :表示提交的数据格式是:name=value&name=value,然后对其进行URL编码, URL编码:将非英文内容转换为:%xx%xx multipart/form-data :表示以多段的形式提交数据给服务器 (以流的形式提交,用于上传) |
Content-Length | 请求体的长度 |
6.3 响应的HTTP格式
-
相应行
- 响应的协会和版本号
- 响应的状态码
- 响应状态描述符
-
响应头
key:value
-
响应体 ---->>> 回传给客户端的数据
HTTP/1.1 200
Accept-Ranges: bytes
ETag: W/"2441-1633245284585"
Last-Modified: Sun, 03 Oct 2021 07:14:44 GMT
Content-Type: text/html
Content-Length: 2441
Date: Mon, 04 Oct 2021 07:55:25 GMT
Keep-Alive: timeout=20
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>购物</title>
</head>
<body>
</body>
</html>
key | 含义 |
---|---|
Server | 表示服务器的信息 |
Content-Type | 响应体的数据类型 |
Content-Length | 响应体的长度 |
Date | 请求响应的时间(格林时间) |
响应码 | 含义 |
---|---|
200 | 请求成功 |
302 | 请求重定向 |
404 | 请求已经收到,但是数据不存在 |
500 | 请求已经收到,但是服务器内部错误(代码错误) |
6.4 中文乱码问题
- 请求:
request.setCharacterEncoding("utf-8");
- 响应:
System.out.println(resp.getCharacterEncoding());
得到默认字符集:ISO-8859-1
如果直接:
resp.setCharacterEncoding("UTF-8");
结果仍是乱码,因为这只是设置了服务器的字符集
**指定服务器响应给浏览器的编码**
resp.setHeader("Content-Type", "text/html; charset=utf-8");
直接设置这个就可以了:它会同时设置服务器和客户端都是用utf-8
response.setContentType("text/html;charset=utf-8");
指定服务器响应给浏览器的编码。同时,浏览器也是根据这个参数来对其接收到的数据进行重新编码(或者称为解码)。
7. HttpServletRequest类
每次只要有请求进入Tomcat
服务器Tomcat
服务器就会把请求过来的HTTP协议信息解析好封装到Request
对象中。然后传递到service
、doGet
、doPost
方法中给用户使用。可以通过HTTPServletRequsr
获取所有的请求信息。
方法 | 作用 |
---|---|
request.getRequestURI() | 获取请求的资源路径 |
request.getRequestURL() | 获取请求的统一资源定位符(绝对地址) |
request.getRemoteHost() | 获取客户端的IP 地址 |
request.getHeader(“Referer”) | 获取请求头 |
request.getParameter(“name”) | 获取请求的参数 |
request.getParameterValues(“name”) | 获取请求的参数,会返回String[] |
request.getMethod() | 获取请求的方式 |
setAttribute(key, value) | 设置域数据 |
getAttribute(key) | 获取域数据 |
getRequestDispatchar() | 获取请求转发对象 |
9. 请求转发
将接收的数据由Servlet1
处理完之后,全部转发至Servlet2
Servlet1:
@WebServlet(name = "Servlet1", value = "/Servlet1")
public class Servlet1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
System.out.println("Servlet1处理数据:" + name);
request.setAttribute("key", "value");
// 问路:Servlet2 怎么走
// 请求转发必须以斜杠开头, ”/“ 表示为 http://ip:port/工程名/ 映射之后的路径
RequestDispatcher dispatcher = request.getRequestDispatcher("/tow");
dispatcher.forward(request,response);
}
}
Servlet2:
@WebServlet(value = "/two")
public class Servlet2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("访问到了Servlet2 " + request.getAttribute("key"));
System.out.println("访问到了Servlet2 " + request.getAttribute("key"));
}
}
base标签的作用
如果由index跳转到Servlet,然后Servlet转发自Second.html,然后再点击index的连接,是跳转不过去的,因为再second界面时,浏览器地址栏中的地址仍是Servlet的地址…具体看代码
index:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a href="./a/b/Second.html">Second.html</a> </br>
<a href="http://localhost:8080/Test/Servlet1">Servlet1</a>
</body>
</html>
Second:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Second</title>
// Second.html 中所有的相对路径都参照base路径
// 如果不加base就会出错
<base href="http://localhost:8080/Test/a/b/Second.html">
// 也可以:http://localhost:8080/Test/a/b/
</head>
<body>
// 相对路径,转发时,是根据当前地址栏中的地址
<a href="../../index.html">index</a>
</body>
</html>
Servlet:
@WebServlet(name = "Servlet1", value = "/Servlet1")
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 直接转发到Second.html
request.getRequestDispatcher("/a/b/Second.html").forward(request, response);
}
}
web中 /
的意义
再web中,/ 是一种绝对路径:
/
斜杠如果被浏览器解析,得到的地址是:http://ip:port/
<a href="/"> </a>
-
/
斜杠如果被服务器解析,得到的地址是:http://ip:port/工程路径<url-pattern> /servletName </url-pattern>
servletContext.getRealPath("/")
request.getRequestDispatcher("/")
-
特殊情况
response.sendRediect("/")
----- 把斜杠发送给浏览器解析。得到:http://ip:port
10. HttpServletResponse类
每次只要有请求进入Tomcat
服务器Tomcat
服务器就会创建一个Response对象传递给Servlet程序去使用。HttpServletResponse
表示所有响应的信息。将需要返回给客服端的信息,通过这个类设置。
字节流: getOutputStream()
常用于下载(传递二进制数据)
字符流: getWriter()
常用于回传字符串(常用)
注:两个流同时只能用一个,否则会报错500。
11. 请求重定向
客户端给服务器发送请求,然后服务器告诉客户端去新的地址。
- 浏览器的地址栏会发生变化
- 是两次请求
- 不共享Request域中的数据
- 不能访问WEB-INF下的资源
- 可以访问工程之外的数据
resp.setStatus(302);
resp.setHeader("Location", "http://localhost:8080/Test/Servlet");
或者
response.sendRedirect("http://localhost:8080/Test/Servlet");
七、数据库
1. 数据库连接池 DBCP
1.1 用类创建数据源
BasicDataSource类
public class Test {
public static DataSource ds = null;
static {
BasicDataSource dbs = new BasicDataSource();
dbs.setDriverClassName("com.mysql.cj.jdbc.Driver");
dbs.setUrl("jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC");
dbs.setUsername("root");
dbs.setPassword("root");
dbs.setInitialSize(5);
dbs.setMaxTotal(5);
ds = dbs;
}
public static void main(String[] args) throws SQLException {
Connection conn = ds.getConnection();
DatabaseMetaData metaData = conn.getMetaData();
System.out.println(metaData.getURL() + "\n" +
metaData.getUserName() + "\n" +
metaData.getDriverName());
}
}
1.2 使用配置文件创建数据源
#连接设置
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC
username=root
password=root
#初始化连接
initialSize=5
#最大连接数量
maxTotal=10
#最大空闲连接
maxIdle=10
package Test;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;
public class Test {
public static DataSource ds = null;
static {
Properties prop = new Properties();
try{
InputStream in = new Test().getClass().getClassLoader().getResourceAsStream("dbcpconig.properties");
// 或
// InputStream in =
// Test.class.getClassLoader().getResourceAsStream("dbcpconig.properties");
prop.load(in);
ds = BasicDataSourceFactory.createDataSource(prop);
}catch (Exception e){
throw new ExceptionInInitializerError(e);
}
}
public static void main(String[] args) throws SQLException {
Connection conn = ds.getConnection();
DatabaseMetaData metaData = conn.getMetaData();
System.out.println(metaData.getURL() + "\n" +
metaData.getUserName() + "\n" +
metaData.getDriverName());
}
}
2. 数据库连接池C3P0
1.1 用构造方法创建数据源
ComboPooledDataSource
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.sql.SQLException;
public class Main {
private static DataSource ds = null;
static {
ComboPooledDataSource cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
} catch (PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC");
cpds.setUser("root");
cpds.setPassword("root");
cpds.setMaxPoolSize(30);
cpds.setMinPoolSize(2);
cpds.setInitialPoolSize(10);
cpds.setMaxStatements(180);
ds = cpds;
}
public static void main(String[] args) {
try {
System.out.println(ds.getConnection());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
1.2 使用配置文件创建数据源
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.SQLException;
public class Main {
private static DataSource ds = null;
static {
ComboPooledDataSource cpds = new ComboPooledDataSource("mysql");
ds = cpds;
}
public static void main(String[] args) {
try {
System.out.println(ds.getConnection());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
注意!:在maven项目下,需要放到resources文件夹下
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<!-- 默认配置 -->
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">
jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC
</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="checkoutTimeout">30000</property>
<property name="initialPollSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<!--传入name时,使用这个配置-->
<named-config name="mysql">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</named-config>
</c3p0-config>
3. 阿里数据库连接池Druid
工具类
package utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.util.Properties;
public class DruidUtils {
private static DataSource dataSource;
//加载配置文件只需要加载一次,而静态代码块也是只加载一次的,所以将加载配置文件的代码放在静态代码块中
static {
try {
//Properties加载配置文件
Properties properties = new Properties();
InputStream inputStream = DruidUtils.class.getResourceAsStream("/druid.properties");
properties.load(inputStream);
//创建druid的连接池
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接池
public static DataSource getDataSource() {
return dataSource;
}
}
配置文件
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/momo?useSSL=false&serverTimezone=UTC
username = root
password = root
initialSize=5
maxActive=10
maxWait=3000
4. 连接池使用
例如C3P0
:
主要是传递出去一个DataSource
对象
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
public class C3P0Utils {
private static DataSource ds;
static {
ds = new ComboPooledDataSource();
}
public static DataSource getDataSource(){
return ds;
}
}
用DBUtils
的QueryRunner
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
5. DBUtils
QueryRunner
类- 提供了一个有参构造方法,以
javax.sql.DataSourse
作为参数传递到QueryRunner
的构造方法中,来获取Connection对象。下面是几个常用的操作: query
(String sql, ResultSetHandler rsh, Object… params) --------- 查询操作update
(String sql, Object… params) -------- 插入、更新、删除update
(String sql) --------- 插入、更新、删除
- 提供了一个有参构造方法,以
ResultSetHandler
接口- 用于处理Result结果集,可以将结果集的数据转为不同的形式。提供了几个实现类:
BeanHandler
将结果集的第一行数据封装到一个对应的JavaBean实例中BeanListHandler
将结果集的每一行数据封装到一个对应的JavaBean实例中,并存放到List
里ScalarHandler
将结果集中某一条记录的其中某一列的数据存储成Object
对象
使用 new BeanHandler 还有 new BeanListHandler 时 ,(xxx.class)里面的xxx类
(1)里面的属性要有set方法
(2)类里面如果有带参数的改造方法,必须添加一个没有参数的构造方法
(3)查询语句·sql·里面的参数保证类里面有同名的构造方法;
import java.sql.SQLException;
import java.util.List;
import model.User;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import utils.C3P0Utils;
import utils.DBCP;
public class UserDao {
public boolean isUserNameExist(String username) throws SQLException {
// 数据库连接池用哪个都行
// QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
QueryRunner runner = new QueryRunner(DBCP.getDataSource());
String sql = "select * from user where username=?";
User u = runner.query(sql, new BeanHandler<User>(User.class), username);
if (u == null)
return false;
else
return true;
}
public boolean isEmailExist(String email) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user where email=?";
User u = runner.query(sql, new BeanHandler<User>(User.class), email);
if (u == null)
return false;
else
return true;
}
public List findAll() throws SQLException {
// 创建 QueryRunner对象
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user";
// 调用方法
List list = (List) runner.query(sql, new BeanListHandler<User>(User.class));
return list;
}
public User findByUsernamePassword(String username, String password) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user where username=? and password=?";
return runner.query(sql, new BeanHandler<User>(User.class), username, password);
}
public User findByEmailPassword(String email, String password) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user where email=? and password=?";
return runner.query(sql, new BeanHandler<User>(User.class), email, password);
}
public User findById(int id) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select * from user where id=?";
return runner.query(sql, new BeanHandler<User>(User.class), id);
}
public boolean addUser(User user) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "insert into user(username, email, password, name ,phone, address, isadmin, isvalidate)" +
" values (?,?,?,?,?,?,?,?)";
/**
* 用不用Object都行,可以依次写上
*/
int num = runner.update(sql, new Object[]{user.getUserName(), user.getEmail(), user.getPassword(),
user.getName(), user.getPhone(), user.getAddress(), user.isAdmin(), user.isValidate()});
System.out.println(num);
if (num > 0)
return true;
else
return false;
}
public int findIdByUserName(String username) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select id from user where username = ?";
System.out.println(username);
return (int) runner.query(sql, new ScalarHandler<Object>(), username);
}
public int findIdByEmail(String email) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "select id from user where email = ?";
return runner.query(sql, new ScalarHandler<Integer>(), email);
}
public void updateUserInformation(User user) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "update user set name=? ,phone = ?, address=? where id=?";
runner.update(sql, user.getName(), user.getPhone(), user.getAddress(), user.getId());
}
public void updateUserPassword(User user) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "update user set password=? where id=?";
runner.update(sql, user.getPassword(), user.getId());
}
public void delete(User user) throws SQLException {
QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
String sql = "delete from user where id = ?";
runner.update(sql, user.getId());
}
public static void main(String[] args) throws SQLException {
}
}
八、文件上传和下载
1. 上传
前端的准备
-
需要一个
form
标签,method
=post
,input
类型为file
-
encType
属性必须是multipart/form-data
encType=multipart/form-data
表示提交的数据,以多段(每一个表单项一个数据段)的形式拼接,然后以二进制流的形式发送给服务器
后端:
1.HttpServletRequest提供的方法
- Part
getPart(String name)
:根据名称获取文件上传域 - Collection
getParts()
:获取所有的文件上传域
2.Part中常用的方法
- String
getContentType()
:获取上传文件的文件类型 - long
getSize()
:上传文件的大小 - String
getSubmittedFileName()
:上传文件的原始文件名 - String
getName()
:获取<input name=“upload” …>标签中name属性值 - String
getHeader(String name)
:获取请求头部 - Collection
getHeaderNames()
:获取所有请求头部名称 - InputStream
getInputStream()
:获取上传文件的输入流 - void
write(String path)
:保存文件至服务器
@MultipartConfig注解属性说明
属性 | 类型 | 是否必需 | 说明 |
---|---|---|---|
maxFileSize | long | 否 | |
maxRequestSize | long | 否 | |
fileSizeThreshold | int | 否 | |
location | String | 否 |
FileUtils:几个操作
package utils;
import java.io.File;
import java.util.UUID;
public class FileUtils {
/**
* 目录分离算法 --- 返回一个用于保存文件的目录
*
* @param fileName 文件名称
* @param fileSaveRoot 文件保存的根目录
* @return 文件实际保存的目录
*/
public static String fileSave(String fileName, String fileSaveRoot) {
int hash = fileName.hashCode();
int dir1 = hash & 0xf;
int dir2 = (hash & 0xf0) >> 4;
// File.separator 在Windows的作用相当于 '\', 用 File.separator 保证了在任何系统下不会出错。
String fileSavePath = fileSaveRoot + File.separator + dir1 + File.separator + dir2;
File file = new File(fileSavePath);
if(!file.exists()){
file.mkdirs();
}
return fileSavePath;
}
/**
* 防止提交的文件重名,加上唯一的UUID
*
* @param fileName 原始文件名
* @return 加上UUID的文件名
*/
public static String makeFileName(String fileName) {
return UUID.randomUUID().toString() + "_" + fileName;
}
/**
* @param fileUUIDName 带有UUID的文件名
* @return 去掉 UUID的文件名
*/
public static String extractFileName(String fileUUIDName) {
int index = fileUUIDName.indexOf("_");
return fileUUIDName.substring(index + 1);
}
}
Servlet
// 存放文件的目录
String savePathRoot = getServletContext().getRealPath(
"/WEB-INF/classes/picture");
// 最后把所有的文件名存放list中,方便后面处理
ArrayList<String> list = new ArrayList<String>();
// 直接 接收多个
Collection<Part> parts = request.getParts();
for (Part part : parts) {
// 获取原始文件名
String fileName = part.getSubmittedFileName();
// 如果是空(没有上传),在这里就处理掉
if (fileName == null) {
continue;
}
// 加上UUID
String fileUUIDName = FileUtils.makeFileName(fileName);
// 用目录分类算法 获取存放的目录
String saveDir = FileUtils.fileSave(fileUUIDName, savePathRoot);
list.add(fileUUIDName);
// 最终的路径
String realPath = saveDir + File.separator + fileUUIDName;
// 存储
part.write(realPath);
part.delete();
}
2. 下载
读文件流进Servlet输出流里面进行输出即可
然后再写上头
意的是这边要对文件名进行URL UTF-8编码,不然在浏览器控制台会显示????
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//带UUID的文件名
String fileUUIDName = request.getParameter("fileName");
String fileName = FileUtils.extractFileName(fileUUIDName);
System.out.println(fileName);
String fileRoot = this.getServletContext().getRealPath("/WEB-INF");
//根据文件名找到存储目录
String fileDir = FileUtils.fileSave(fileUUIDName, fileRoot);
// 以idea存放临时文件的目录为基础,的真实目录
String targetFileUrl = fileDir + File.separator + fileUUIDName;
System.out.println(targetFileUrl);
File file = new File(targetFileUrl);
if (!file.exists()) {
System.out.println("目标文件不存在");
return;
}
// 下载的文件名
response.setHeader("content-disposition",
"attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 输出
FileInputStream inputStream = new FileInputStream(file);
ServletOutputStream servletOutputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > 0) {
servletOutputStream.write(buffer, 0, len);
}
inputStream.close();
servletOutputStream.close();
}
九、会话
1. Cookie
Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)
Cookie规范
- Cookie通过请求头和响应头在服务器与客户端之间传输
- Cookie大小上限为4KB
- 一个服务器最多在客户端浏览器上保存20个Cookie
- 一个浏览器最多保存300个Cookie
方法声明 | 功能描述 |
---|---|
Cookie(String name, String value) | 构造方法 |
getName() | 获取Cookie的名称 |
setValue() | 设置Cookie的值 |
getValue() | 获取Cookie的值 |
setPath() | 设置Cookie项的有效目录路径 |
getPath() | 获取Cookie的路径 |
setDomain() | 设置Cookie的有效域 |
setMaxAge() | 设置Cookie在浏览器上保持的时间,以秒为单位 |
getMaxAge() | 获取Cookie在浏览器上保持的秒数 |
setVersion() | 设置Cookie采用的协议版本 |
getVersion() | 获取Cookie采用的协议版本 |
setComment() | 设置Cookie的注解部分 |
getComment() | 获取Cookie的注解 |
setSecure() | 设置Cookie是否使用安全的协议传送 |
getSecure() | 获取Cookie是否使用安全的协议传送 |
详解
-
setMaxAge()
1.
-1 一旦关闭浏览器窗口,cookie就会消失。(默认情况就是-1)2.
正数 表示存活时间,会保存到硬盘上。若60*60,表示cookie对象可存活1小时3.
0 表示cookie被作废。如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。 -
setPath(String uri)
默认情况下:设置的Cookie只对当前路径所属的目录及其子目录有效
若将Cookie在该站点所有目录有效:setPath(“/”)
-
setDomain
设置在某个域名下生效
值必须以
.
开头如:BZU的域为
bzu.cn
,设置setDomain(".bzu.cn")
。那么浏览器在访问当前主机下的资源时,都会将Cookie信息回送给服务器。(属性值不区分大小写) -
如果有中文字符或者其他特殊字符:空格分号…
存储:Cookie cookie = new Cookie("userName", URLEncoder.encode("你好世界", "UTF-8")); 读取:URLDecoder.decode(cookie.getValue(), "UTF-8")
小案例:显示上次访问的时间
public class momo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 获取所有的 Cookie
Cookie[] cookies = request.getCookies();
String lastTime = null;
if (cookies != null)
for (Cookie c : cookies) {
System.out.println(11);
if (c.getName().equals("lastTime")) {
lastTime = URLDecoder.decode(c.getValue());
}
}
if (lastTime == null)
out.println("首次访问");
else
out.println("上次访问时间:" + lastTime);
String currenTime = new SimpleDateFormat("yyyy-MM-dd--hh:mm:ss").format(new Date());
Cookie cookie = new Cookie("lastTime", URLEncoder.encode(currenTime));
cookie.setMaxAge(-1);
response.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
2. Session
session机制采用的是在服务器端保持 HTTP 状态信息的方案。为了加速session的读取和存储,web服务器中会开辟一块内存用来保存服务器端所有的session,每个session都会有一个唯一标识sessionid,根据客户端传过来的jsessionid(cookie中),找到对应的服务器端的session。为了防止服务器端的session过多导致内存溢出,web服务器默认会给每个session设置一个有效期, (30分钟)若有效期内客户端没有访问过该session,服务器就认为该客户端已离线并删除该session。
2.1 保存session的两种方式
-
1)
cookie
中- 通过一个特殊的
cookie
,name
为JSESSIONID
,value为服务器端某个 session的ID,默认的方式。但是当浏览器禁用cookie
后session
就会失效。
- 通过一个特殊的
-
2)
url
重写-
当浏览器Cookie被禁时用。
就是把session的id附加在URL路径的后面。附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。
-
做法:
1、
response.encodeURL(String url)
用于对表单action和超链接的url地址进行重写2、
response.encodeRedirectURL(String url)
用于对sendRedirect方法后的url地址进行重写。这两个方法很智能,若浏览器禁用了cookie,就默认会进行url重写(url中带上sessionid),当用户浏览器没有禁用cookie时,就不在URL后附加sessionid。
其实都是依靠
encodeRedirectURL
, 来获取带有ID的URL,然后对这个URL进行操作
-
2.2 基本原理
当用户发送一个请求到服务器端时,服务器会先检查请求中是否含有sessionid(存在cookie中或者在url中)
1. 如果不存在sessionid(说明是第一次请求),就会为该请求用户创建一个session
对象,并将该session对象的sessionid(放到响应头的set-cookie
中,格式set-cookie:sessionid
,下次再请求时cookie中就会有一个name为jsessionid的cookie,value就是sessionid)响应给客户端。
2. 如果存在sessionid
,就会在服务器端查找是否有该sessionid
对应的session
,如果有就使用,没有就创建一个。
所以说,服务器端的session
和客户端的cookie
是息息相关的,若是没有了cookie,又不做其他处理的话,服务器端的session也没了。
2.3 常用API
getId()方法
:得到sessionid。
invalidate()方法
:让session立刻失效。
getAttribute(String key)
:根据key获取该session中的value。
setAttribute(String key,Object value)
:往session中存放key-value。
removeAttribute(Stringkey)
:根据key删除session中的key-value。
getServletContext()
:得到ServletContext。
setMaxInactiveInterval(long timeout)/getMaxInactiveInterval
:设置/获取session的最大有效时间。
getCreationTime方法
:获取session的创建的时间。
getLastAccessedTime方法
:获取session最后一次访问的时间。
getSession()
:从HttpServletRequest中获取session。
实例
借助Cookie实现
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(true);
String lastTime = (String) session.getAttribute("lastTime");
if (lastTime == null) {
out.println("first");
/**
* 2. 使用请求重定向的方式
* 重定向之后的代码还是会执行的
* 所以session也就有了值
*/
//String url = "/Cookie/SessionServlet?id=" + session.getId();
// String newUrl = response.encodeRedirectURL(url);
// response.sendRedirect(newUrl);
} else
out.println("上次访问时间:" + lastTime
+ "\n" + session.getId());
String currentTime = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss").format(new Date());
session.setAttribute("lastTime", currentTime);
Cookie cookie = new Cookie("JSESSIONID", session.getId());
response.addCookie(cookie);
/**
* 3. URL重写
*/
// String url = "/Cookie/SessionServlet?id=" + session.getId();
// System.out.println(url);
// String newUrl = response.encodeRedirectURL(url);
// /**
// * newUrl是带有sessionID的Url
// * /Cookie/SessionServlet?id=CCFCCE5EC7478CD00F04FF71742510ED
// */
// out.println(newUrl);
// out.println("<a href='" + newUrl + "'>点击跳转 </a>");
}
重写表单action和超链接的url地址
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(true);
String lastTime = (String) session.getAttribute("lastTime");
if (lastTime == null)
out.println("first");
else
out.println("上次访问时间:" + lastTime
+ "\n" + session.getId());
String currentTime = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss").format(new Date());
session.setAttribute("lastTime", currentTime);
String url = "/Cookie/SessionServlet?id=" + session.getId();
System.out.println(url);
String newUrl = response.encodeRedirectURL(url);
/**
* newUrl是带有sessionID的Url
* /Cookie/SessionServlet?id=CCFCCE5EC7478CD00F04FF71742510ED
*/
out.println(newUrl);
out.println("<a href='" + newUrl + "'>点击跳转 </a>");
}
sendRedirect
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(true);
String lastTime = (String) session.getAttribute("lastTime");
if (lastTime == null) {
out.println("first");
/**
* 2. 使用请求重定向的方式
* 重定向之后的代码还是会执行的
* 所以session也就有了值
*/
String url = "/Cookie/SessionServlet?id=" + session.getId();
String newUrl = response.encodeRedirectURL(url);
response.sendRedirect(newUrl);
} else
out.println("上次访问时间:" + lastTime
+ "\n" + session.getId());
String currentTime = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss").format(new Date());
session.setAttribute("lastTime", currentTime);
}
十、JSP
1.jsp基本语法
1.1 脚本元素
JSP脚本
所谓脚本代码(Scriptlet),是指JSP中的代码部分,在这个部分中可以使用几乎任何Java的语法。
<%
if(Calendar.getInstance().get(Calendar.AM_PM) == Calendar.AM){
%>
上午好!
<%
} else {
%>
下午好!
<%
}
%>
JSP表达式
JSP中的表达式可以被看做一种简单的输出形式,需要注意的是,表达式一定要有一个可以输出的值。
<%=(new java.util.Date()).toLocaleString()) %>
JSP声明
JSP中的声明用于声明一个或多个变量和方法,并不输出任何的文本到输出流。在声明元素中声明的变量和方法将在JSP页面初始化时进行初始化。
JSP声明中的变量全局可用
JSP脚本中的变量是在Service中
<%!int i=0;%>
<%!public String f(int i){
if(i<3)
return ("…");
return "";
}
%>
JSP声明变量与普通脚本变量的区别:
声明变量将做为JSP翻译生成的Servlet的属性,所有对该JSP的请求将共享此变量;
普通脚本变量将做为JSP翻译生成的Servlet的_jspService()方法中的局部变量,每个对该JSP的请求将被分配给一个同名的此变量。
<%! int count = 0;
synchronized void setCount() {
count++;
}
%>
<%
String date = new java.util.Date().toLocaleString();
%>
<% setCount(); %>
您是第<%=count %>个访问此页面的人,访问时间是:<%=date%>
1.2 指令元素
JSP指令用来向JSP容器提供编译信息。
指令并不向客户端产生任何输出,所有的指令都只在当前页面中有效。
JSP指令元素包括三种:
page指令
include指令
taglib指令
page
page指令描述了和页面相关的信息,如:导入所需类包、指明输出内容类型、控制Session等。
page指令一般位于JSP页面的开头部分
在一个JSP页面中,page指令可以出现多次,但是在每个page指令中,每一种属性却只能出现一次,重复的属性设置将覆盖掉先前的设置。
<%@page 属性列表 %>
<%@page language="java" contentType="text/html; charset=UTF-8"%>
属性名 | 说明 |
---|---|
language | 设定JSP页面使用的脚本语言,默认为Java,目前只可使用Java语言 |
import | 指定导入的Java软件包或类名列表,若有多个类,中间用逗号隔开 |
isThreadSafe | 指定JSP容器执行JSP程序的模式。有两种模式:一种为默认值true,代表JSP容器会以多线程方式运行JSP页面;另一种模式设定值为false,JSP容器会以单线程方式运行JSP页面。建议采用isThreadSage="true"模式 |
contentType | 指定MIME类型和JSP页面响应时的编码方式,默认为“text/html;charset=ISO8859-1” |
pageEncoding | 指定JSP文件本身的编码方式,例如pageEncoding="UTF-8" |
session | 指定JSP页面中是否使用session 对象,值为“`true |
errorPage | 设定JSP页面发生异常时重新指向的页面URL,指向的页面文件要把isErrorPage设成true |
isErrorPage | 指定此JSP页面是否为处理异常错误的网页,值为“true|false”,默认false |
isELIgnored | 指定JSP页面是否忽略EL 表达式,值为“`true |
buffer | 指定输出流是否需要缓冲,默认值是8kb,与autoFlush一起使用,确定是否自动刷新输出缓冲,如果设成true,则当输出缓冲区满的时候,刷新缓冲区而不是抛出一个异常 |
autoFlush | 如果页面缓冲区满时要自动刷新输出,则设置为true;否则,当页面缓冲区满时要抛出一个异常,则设置为false |
导入包,可以同时导入多个
<%@page import="java.util.*,com.qst.ch05.service.CustomerService"%>
或
<%@page import="java.util.* "%>
<%@page import="com.qst.ch05.service.CustomerService"%>
include
include指令的作用是在页面翻译期间引入另一个文件,被包含的文件可以是JSP、HTML或文本文件。
将被引入的文件的内容放到 引入的位置显示
<%@include file="文件"%>
<%@include file="head.jsp" %>
500错误,不知道为什么
include指令会先将当前JSP和被包含的文件融合到一起形成一个Servlet再进行编译执行;
因此包含文件时,必须保证新合并生成的文件符合JSP语法规则。
例如,当前文件和被包含文件的不能同时定义同名的变量,否则当前文件将不能编译通过,会提示Duplicate local variable错误。
taglib
taglib指令用于指定JSP页面所使用的标签库,通过该指令可以在JSP页面中使用标签库中的标签
<%@taglib uri="标签库URI" prefix="标签前缀"%>
1.3 动作元素
<jsp:include > 动作用于在页面被请求时引入一个文件;
jsp:forward 动作用于把请求转发到另一个页面;
jsp:useBean 动作用于查找或实例化一个JavaBean;
jsp:setProperty 动作用于设置JavaBean的属性;
jsp:getProperty 动作用于输出某个JavaBean的属性。
<jsp:include>
<jsp:include page="urlSpec" flush="true">
<jsp:param name="name" value="value"/>
......
</jsp:include>
可以向引入的界面传入参数
page指定引入文件的地址;
flush="true"表示设定是否自动刷新缓冲区,默认为false,可省略;在页面包含大量数据时,为缩短客户端延迟,可将一部分内容先行输出;
name指定传入包含文件的变量名;
value指定传入包含文件的变量名对应的值。
include指令元素是在翻译阶段就引入所包含的文件,被处理的文件在逻辑和语法上依赖于当前JSP页面,其优点是页面的执行速度快。
include动作元素是在JSP页面运行时才引入包含文件所产生的应答文本,被包含的文件在逻辑和语法上独立于当前JSP页面,其优点是可以使用param子元素更加灵活地处理所需要的文件,缺点是执行速度要慢一些。
<jsp:forward>
jsp:forward用于引导客户端的请求到另一个页面或者另一个Servlet。jsp:forward动作可以包含一个或几个jsp:param子动作,用于向所转向的页面传递参数。
<jsp:forward page="head.jsp">
<jsp:param name="name" value="momo"/>
<jsp:param name="ps" value="132"/>
</jsp:forward>
page指定转发请求的相对地址;
jsp:param中的name指定向转向页面传递的参数名称;
jsp:param中的value指定向转向页面传递的参数名称对应的值;
<jsp:useBean>
jsp:useBean是JSP中一个非常重要的动作,使用这个动作,JSP可以动态使用JavaBean组件来扩充JSP的功能,由于JavaBean在开发上以及jsp:useBean在使用上简单明了,使得JSP与其它动态网页开发技术有了本质的区别。
<jsp:useBean id="name"
class="className" scope="page|request|session|application"/>
id指定该JavaBean实例的变量名,通过id可以访问这个实例;
class指定JavaBean的类名。容器根据class指定的类调用其构造方法来创建这个类的实例;
scope指定JavaBean的作用范围,可以使用page、request、session和application。默认值为page。
type指定JavaBean对象的类型,通常在查找已存在的JavaBean时使用,这时使用type将不会产生新的对象。
注:如果book类不放在一个包内的话,运行报错500
范围
<jsp:useBean id="book" scope="application" class="model.Book">
<jsp:setProperty name="book" property="id" value="1"></jsp:setProperty>
<jsp:setProperty name="book" property="bookName" value="Java Web 应用开发"></jsp:setProperty>
<jsp:setProperty name="book" property="price" value="67.8"></jsp:setProperty>
</jsp:useBean>
name指定JavaBean对象名,与useBean动作中的id相对应;
property指定JavaBean中需要赋值的属性名;
value指定要为属性设置的值;
param指定请求中的参数名(如表单传值或URL传值),并将该参数的值赋给property所指定的属性。
2. 内置对象
对象名称 | 类型 | 功能说明 |
---|---|---|
request | javax.servlet.http.HttpServletRequest | 请求对象,提供客户端HTTP请求数据的访问 |
response | javax.servlet.http.HttpServletResponse | 响应对象,用来向客户端输出响应 |
out | javax.servlet.jsp.JspWriter | 输出对象,提供对输出流的访问 |
session | javax.servlet.http.HttpSession | 会话对象,用来保存服务器与每个客户端会话过程中的信息 |
application | javax.servlet.ServletContext | 应用程序对象,用来保存整个应用环境的信息 |
pageContext | javax.servlet.jsp.PageContext | 页面上下文对象,用于存储当前JSP页面的相关信息 |
config | javax.servlet.ServletConfig | 页面配置对象,JSP页面的配置信息对象 |
page | javax.servlet.jsp.HttpJspPage | 当前JSP页面对象,即this |
exception | java.lang.Throwable | 异常对象,用于处理JSP页面中的错误 |
2.1 上下文
与Context(上下文)有关的内置对象包括session、application和pageContext。其中:
session对象表示浏览器与服务器的会话上下文环境;
application对象表示应用程序上下文环境;
pageContext对象表示当前JSP页面上下文环境。
2.1.1 session
session对象即会话对象,表示浏览器与服务器之间的一次会话。
一次会话的含义是:从客户端浏览器连接服务器开始,在关闭浏览器或主动退出后,会话结束。这个过程可以包含浏览器与服务器之间的多次请求与响应。
void setAttribute(String name, Object value):以名/值对的方式存储session域属性;
Object getAttribute(String name):根据属性名获取属性值;
void invalidate():使session对象失效,释放所有的属性空间。
2.1.1 application
application对象即应用程序上下文对象,表示当前应用程序运行环境,用以获取应用程序上下文环境中的信息。
application对象在容器启动时实例化,在容器关闭时销毁。作用域为整个Web容器的生命周期。
application对象实现了javax.servlet.ServletContext接口,具有ServletContext接口的所有功能。application对象常用方法如下:
void setAttribute(String name,Object value):以名/值对的方式存储application域属性;
Object getAttribute(String name):根据属性名获取属性值;
void removeAttribute(String name):根据属性名从application域中移除属性。
2.1.1 pageContext
pageContext即页面上下文对象,表示当前页面运行环境,用以获取当前JSP页面的相关信息。
pageContext对象作用范围为当前JSP页面。
方法 | 描述 |
---|---|
Object getAttribute(String name, int scope) | 获取范围为scope,名为name的属性对象 |
void setAttribute(String name, Object value, int scope) | 以名/值对的方式存储scope范围域属性 |
void removeAttribute(String name, int scope) | 从scope范围移除名为name的属性 |
Enumeration getAttributeNamesInScope(int scope) | 从scope范围中获取所有属性的名称 |
PAGE_SCOPE
= 1代表page范围;
REQUEST_SCOPE
= 2代表request范围;
SESSION_SCOPE
= 3代表session范围;
APPLICATION_SCOPE
= 4代表application 范围。
对象的生命周期和可访问性称为作用域(scope),在JSP中有四种作用域:页面域、请求域、会话域和应用域。
四种作用域的生命周期和可访问性介绍如下:
页面域(page scope),页面域的生命周期是指页面执行期间。存储在页面域的对象只对于它所在页面是可访问的。
请求域(request scope),请求域的生命周期是指一次请求过程,包括请求被转发(forward)或者被包含(include)的情况。存储在请求域中的对象只有在此次请求过程中才可以被访问。
会话域(session scope),会话域的生命周期是指某个客户端与服务器所连接的时间;客户端在第一次访问服务器时创建会话,在关闭浏览器或主动退出后,会话结束。存储在会话域中的对象在整个会话期间(可能包含多次请求)都可以被访问。
应用域(application scope),应用域的生命周期是指从服务器开始执行服务到服务器关闭为止,是四个作用域中时间最长的。存储在应用域中的对象在整个应用程序运行期间可以被所有JSP和Servlet共享访问,在使用时要特别注意存储数据的大小和安全性,否则可能会造成服务器负载过重和线程安全性问题。
JSP的四种作用域分别对应pageContex、request、session和application四个内置对象。
四个内置对象都通过setAttribute(String name,Object value)方法来存储属性,通过getAttribute(String name)来获取属性,从而实现属性对象在不同作用域的数据分享。
十一、EL表达式
1. 语法
${表达式}
${"hello"} //输出字符串常量
${23.5} //输出浮点数常量
${23+5} //输出算术运算结果
${23>5} //输出关系运算结果
${true||false} //输出逻辑运算结果
${23>5?23:5} //输出条件运算结果
${empty username} //输出empty运算结果
${username} //查找输出变量值
${sessionScope.user.sex} //输出隐含对象中的属性值
${qst:fun(arg)} //输出自定义函数的返回值
EL表达式中的常量包括:布尔常量、整形常量、浮点数常量、字符串常量和NULL常量。
布尔常量,用于区分事物的正反两面,用true或false表示。例如:${true}。
整型常量,与Java中定义的整型常量相同,范围为Long.MIN_VALUE到Long.MAX_VALUE之间。例如:${23E2}。
浮点数常量,与Java中定义的浮点数常量相同,范围为Double.MIN_VALUE到Double.MAX_VALUE之间。例如:${23.5E-2}。
字符串常量,是用单引号或双引号引起来的一连串字符。例如:${“你好!”}。
NULL常量,用于表示引用的对象为空,用null表示,但在EL表达式中并不会输出“null”而是输出空。例如:${null},页面会什么也不输出
EL表达式中的变量不同于JSP表达式从当前页面中定义的变量进行查找,而是由EL引擎调用PageContext.findAttribute(String)方法从JSP四大作用域范围中查找。
例如:${username},表达式将按照page、request、session、application范围的顺序依次查找名为username的属性;假如中途找到,就直接回传,不再继续找下去;假如全部的范围都没有找到,就回传null。
注:在使用EL表达式访问某个变量时,应该指定查找的范围,从而避免在不同作用范围中有同名属性的问题,同时也提高了查询效率。
保留字:
and | or | not | empty | div |
---|---|---|---|---|
mod | instance of | eq | ne | lt |
gt | le | ge | true | false |
null |
2. 隐含对象
与范围有关的隐含对象
隐含对象 | 说明 |
---|---|
pageScope | 用于获得页面作用范围中的属性值,相当于pageContext.getAttribute() |
requestScope | 用于获得请求作用范围中的属性值,相当于request.getAttribute() |
sessionScope | 用于获得会话作用范围中的属性值,相当于session.getAttribute() |
applicationScope | 用于获得应用程序作用范围中的属性值,相当于application.getAttribute() |
与请求参数有关的隐含对象
隐含对象 | 说明 |
---|---|
param | 用于获得请求参数的单个值,相当于request.getParameter() |
paramValues | 用于获得请求参数的一组值,相当于request.getParameterValues() |
其他隐含对象
隐含对象 | 说明 |
---|---|
pageContext | 相当于JSP页面中的pageContext对象,用于获取ServletContext、request、response、session等其它JSP内置对象 |
header | 用于获得HTTP请求头中的单个值,相当于request.getHeader(String name) |
headerValues | 用于获得HTTP请求头中的一组值,相当于request.getHeaders(String name) |
cookie | 用于获得指定的Cookie |
initParam | 用于获得上下文初始参数,相当于application.getInitParameter(String name) |
3. 运算符
算数运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
+ | 加 | ${23+5} | 28 |
- | 减 | ${23-5} | 18 |
* | 乘 | ${23*5} | 115 |
/或div | 除 | ${23/5}或${23div5} | 4.6 |
%或mod | 取余 | ${23%5}或${23mod5} | 3 |
算数运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
==或eq | 等于 | ${23==5}或${23 eq 5} | false |
!=或ne | 不等于 | ${23!=5}或${23 ne 5} | true |
<或lt | 小于 | ${23<5}或${23 lt 5} | false |
>或gt | 大于 | ${23>5}或${23 gt 5} | true |
<=或le | 小于等于 | ${23<=5}或${23 le 5} | false |
>=或ge | 大于等于 | ${23>=5}或${23 ge 5} | true |
算数运算符 | 说明 | 示例 | 结果 |
---|---|---|---|
&& 或 and | 逻辑与 | ${true && true}或${true and true} | true |
|| 或 or | 逻辑或 | ${true || false}或${true or true} | true |
! 或 not | 逻辑非 | ${!true}或${not true} | false |
empty运算符
${empty sessionScope.username}
上述示例有两层含义:
一是表示session对象中是否存在username属性,等同于${sessionScope.usernamenull};
二是表示session对象中username的值是否为“空”,等同于${sessionScope.username""}。
4.自定义函数
${ns:func(a1,a2,...an)}
前缀ns必须匹配包含了函数的标签库的前缀;
func为函数的名称;
a1,a2,…an为函数的参数。
十二、JSTL
1. 导入
<%@taglib prefix="标签库前缀" uri="http://java.sun.com/jsp/jstl/core"%>
prefix属性表示标签库的前缀,可以为任意字符串,通常设置值为“c”,注意避免使用一些保留的关键字,例如:jsp、jspx、java、servlet、sun、sunw等;
uri属性用来指定核心标签库的URI,从而定位标签库描述文件(TLD文件)。
2. jstl函数库分类
标签库 | 前缀名称 | URI | 示例 |
---|---|---|---|
核心标签库 | c | http://java.sun.com/jsp/jstl/core | <c:out> |
I18N标签库 | fmt | http://java.sun.com/jsp/jstl/fmt | fmt:formatDate |
SQL标签库 | sql | http://java.sun.com/jsp/jstl/sql | sql:query |
XML标签库 | x | http://java.sun.com/jsp/jstl/xml | <x:forBach> |
函数标签库 | fn | http://java.sun.com/jsp/jstl/functions | fn:split |
核心标签库中包含实现Web应用的通用操作的标签。例如,输出变量内容的<c:out>标签、用于条件判断的<c:if>标签,用于循环遍历的<c:forEach>标签等。
I18N标签库中包含实现Web应用程序的国际化的标签。例如,设置JSP页面的本地信息、设置JSP页面的时区、使本地敏感的数据(如数值、日期)按照JSP页面中设置的本地格式进行显示等。
SQL标签库中包含用于访问数据库和对数据库中的数据进行操作的标签。例如,从数据源中获得数据库连接、从数据库表中检索数据等。由于在实际开发中,多数应用采用分层开发模式,JSP页面通常仅用作表现层,并不会在JSP页面中直接操作数据库,所以此标签库在分层的较大项目中较少使用,在小型不分层的项目中可以通过SQL标签库实现快速开发。
3. 通用标签
-
<c:out>
-
等同于<%=表达式%>
-
<c:out value="value" [escapeXml="{true|false}"] [default="defaultValue"] /> 您好!<c:out value="${sessionScope.userName}" default="游客"/> <c:out value="<b>没有变成粗体字</b>" escapeXml="true" ></c:out> 输出结果为“<b>没有变成粗体字</b>”。
-
value表示要输出的数据,可以是JSP表达式、EL表达式或静态值;
escapeXml表示是否将>、<、&、'、"等特殊字符进行HTML字符实体转换后再进行输出,默认值为true;
default表示如果value属性的值为null时所输出的默认值。
-
-
<c:set>
-
<c:set var="varName" value="value" [scope="{page|request|session|application}"] /> <c:set var="userName" value="青软实训" scope="session"/>
-
var指定要设置的范围域属性名;
value指定var属性的属性值;
scope指定var属性所属的范围域,默认为page。
-
-
<c:remove>
-
<c:remove var="varName" [scope="{page|request|session|application}"] /> <c:remove var="userName" scope="session" />
-
var属性用于指定要删除的属性名称;
scope属性用于指定要删除的属性所属的范围域。
-
-
<c:catch>
-
<c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常
-
<c:catch [var="varName"]> nested actions </c:catch> <c:catch var="myException"> <%=5/0%> </c:catch> <c:out value="${myException}"/><br> <c:out value="${myException.message}"/> 结果: java.lang.ArithmeticException: / by zero / by zero
-
var属性用于标识捕获的异常对象名称,并将异常对象保存在page域中;
若未指定var属性,则仅捕获异常而不在page域中保存异常对象。
-
4. 条件标签
-
<c:if> 标签
-
用于进行条件判断。
-
<c:if test="condition" [var="varName"] [scope="{page|request|session|application}"] > //condition为true时执行的代码 </c:if> <c:if test="${not empty sessionScope.userName}"> 欢迎您:${sessionScope.userName } </c:if>
-
test用于指定条件表达式,返回boolean类型值;
var用于指定将test属性的执行结果保存到某个范围作用域的属性名称;
scope用于指定将test属性的执行结果保存到哪个范围作用域中。
-
-
<c:choose>标签
-
用于指定多个条件选择,必须与<c:when>和<c:otherwise>标签一起使用
-
<c:choose> //<c:when>和<c:otherwise>子标签 </c:choose> <c:choose> <c:when test="${empty sessionScope.userName}"> 欢迎您:${sessionScope.userName } </c:when> <c:otherwise> 欢迎您:游客 </c:otherwise> </c:choose> if-else if-else结构: <c:set var="score" value="85"></c:set> <c:choose> <c:when test="${score>=90}"> 你的成绩为优秀! </c:when> <c:when test="${score>=80&&score<90}"> 您的成绩为良好! </c:when> <c:when test="${score>60&&score<80}"> 您的成绩为及格! </c:when> <c:otherwise> 对不起,您没有通过考试! </c:otherwise> </c:choose>
-
<c:choose>标签没有属性,它的标签体内容只能有:空白、一个或多个<c:when>、0或多个<c:otherwise>。
-
-
-
<c:when>标签
-
代表<c:choose>标签的一个条件分支,必须以<c:choose>为父标签,且必须在<c:otherwise>标签之前。
-
<c:when test="condition"> //condition为true时,执行的代码 <c:when>
-
-
-
<c:otherwise>标签
-
代表<c:choose>标签中前面所有<c:when>标签条件都不符合的情况下的最后选择。
-
<c:otherwise> //执行的代码 <c:otherwise>
-
-
5. 迭代标签
-
<c:forEach>
-
<c:forEach>标签用于遍历集合或迭代指定的次数。
-
<c:forEach [var="varName"] items="collection" [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"] > //标签体内容 </c:forEach> 【示例】迭代数组对象 <% String arrays[] = new String [5]; arrays[0]="Hello"; arrays[1]=","; arrays[2]="everyone"; arrays[3]="!"; request.setAttribute("arrays",arrays); %> <c:forEach items="${arrays}" var="item" > ${item} </c:forEach> 【示例】迭代集合对象 <% List<Book> list = new ArrayList<Book>(); list.add(new Book("JavaWeb开发与应用")); list.add(new Book("JavaSE开发与应用")); session.setAttribute("bookList", list); %> <c:forEach items="${sessionScope.bookList}" var="book" varStatus="vst"> <p> 序号:${vst.index+1} ,书名:${book.bookName} </p> </c:forEach> 【示例】迭代Map对象 <% Map<String,Book> map=new HashMap<String,Book>(); map.put("JavaWeb", new Book("JavaWeb开发与应用")); map.put("JavaSE", new Book("JavaSE与开发与应用")); request.setAttribute("bookMap", map); %> <c:forEach items="${requestScope.bookMap}" var="mapItem"> <p> ${mapItem.key } : ${mapItem.value.bookName } </p> </c:forEach> 【示例】迭代指定次数 <c:forEach begin="1" end="100" step="1" var="num"> <c:set var="sum" value="${sum+num}"></c:set> </c:forEach> ${sum}
-
var用于指定将当前迭代到的元素保存到page域中的属性名称;
items指定将要迭代的集合对象;
varStatus表示当前被迭代到的对象的状态信息,包括四个属性:index(表示当前迭代成员的索引值)、count(表示当前已迭代成员的数量)、first(表示当前迭代到的成员是否为第一个)、last(表示当前迭代到的成员是否为最后一个);
begin表示遍历的起始索引,值为整数;
end表示遍历的结束索引,值为整数;
step表示迭代的步长,值为整数。
-
-
<c:forTokens>
-
<c:forTokens>标签用于实现类似java.util.StringTokenizer类的迭代功能,按照指定的分隔符对字符串进行迭代。
-
<c:forTokens items="stringOfTokens" delims="delimiters" [var="varName"] [varStatus="varStatusName"] [begin=begin] [end=end] [step=step]> //标签体内容 </c:forTokens> <c:set var="sourceStr" value="a|b|c|d|e" /> <c:forTokens var="str" items="${sourceStr}" delims="|" varStatus="status"> <c:out value="${status.count}"/>.<c:out value="${str}"/> <c:if test="${status.last}"> <p>总共被分为<c:out value="${status.count}"/>段</p> </c:if> </c:forTokens> 结果 1.a 2.b 3.c 4.d 5.e 总共被分为5段
-
其中:
items用于指定将要迭代的字符串;
delims用于指定一个或多个分隔符;
var用于将当前迭代的子字符串保存到page域中的属性名称;
varStatus表示当前被迭代到的对象的状态信息,包括四个属性:index(表示当前迭代成员的索引值)、count(表示当前已迭代成员的数量)、first(表示当前迭代到的成员是否为第一个)、last(表示当前迭代到的成员是否为最后一个);
begin指定从第begin个子字符串开始进行迭代,begin的索引值从0开始编号;
end指定迭代到第begin个字符串,begin的索引值从0开始编号;
step指定迭代的步长,即每次迭代后的迭代因子增量。
-