1. JavaScript
1.1 JavaScript简介
1.1.1 什么是JavaScript(了解)
全称叫做JavaScript,简称叫做JS (跟java没啥关系,可能语法有些相似)
由NetScape(网景)公司提供,是一门专门嵌入在浏览器中执行的脚本语言
LiveScript----->(改名) JavaScript
JS运行在浏览器中,负责实现网页中的动画效果或者是实现表单校验等功能(比如密码输入是否正确)
js写错没有提示.
学习前端可以看:W3Cschoole这个网址。
一个后端工程师必须会js.
1.1.2 JS特点和优势(了解)
1、特点:
(1)JS是一门直译式的语言(边解释边执行,没有编译的过程)
java–> 编写时 xx.java —>编译成 xx.class --> 运行
js —> 编写时 html,编写时 js文件,直接运行, 没有编译过程。
(2)JS是一门基于对象的语言(JS中没有类的概念,也没有编译的过程)
JS中是有对象的(内置对象、自定义对象)
(3)JS是一门弱类型的语言(Java:强类型) (弱类型:定义变量的时候不用指定其类型)
在java中: 变量一旦声明, 就属于固定的数据类型, 不能被改变
String s = "abc";
int n = 100;
在JS中: 变量是不区分类型的, 可以指向任意的数据类型
var s = 100;//number(数值类型)
s = "abc";//String(字符串类型)
s = true;//boolean(布尔类型)
s = []; //数组类型
s = function(){} //function(函数类型)
2、优势:(了解)
(1)JS具有良好的交互性 (用户体验更好)
(2)JS具有一定的安全性(只能在浏览器内部运行,不能访问浏览器以外的资源)
(3)JS具有跨平台性(JS 浏览器) ,即:有浏览器的地方就能运行JS。
解释:
JS语言是跨平台的,是因为有浏览器,但浏览器不跨平台。
Java语言是跨平台的,是因为有虚拟机,但虚拟主机不跨平台,比如Linux和windows的jvm的版本不一样 。
1.1.3 在HTML书写JS的方式(三种)
方式一:在script标签内部可以书写JS代码:
在head或者body标签内部可以添加一个script标签,在script标签内部可以直接书写JS代码! 缺点是只能用在同于个网页。而css只能在head标签里面。
<!-- 方式1: 在script标签内部直接书写JS代码 -->
<script>
//声明一个变量str1, 将一个字符串值赋值给str1
var str1 = "引入JS的第一种方式...";
//document是表示当前整个网页的对象,将str1的内容输出到网页上显示 (document: 文件)
document.write( str1 );
</script>
//注意 var不赋值是undefined类型,具体是什么看你赋值的类型(未定义的)
方式二:通过script标签引入外部的JS文件
在head或body标签内部,可以通过script标签引入外部的JS文件。例如:
如何创建一个JS文件: 2种方式
1.new–File,后缀名改为.js
2.new—other—javeScript----javeScript SourceFile—创建.js后缀的文件.
注意1:如果同时引入jquery函数类库和引入自己写的js文件,需要把jquery放在前面。
<!--方式2 通过script标签可以引入外部的JS文件
src 根路径 -->
<script src="./demo.js"></script>
<!--./代表当前文件所在目录, ./可以省略
../代表当前文件所在目录的父目录, ../不能省略
也可以写绝对路径,写相对路径是因为把js文件复制到了项目中。
好处是将来复制项目连js文件也复制过去了,不用在更改js文件路径。-->
注意2:
(1)在引入js文件的script标签内部不要书写JS代码,例如:
<script src="demo.js">
alert( 111 ); //这里的代码不会执行,所以不要写东西
</script>
(2)不要将引入JS文件的script标签自闭,因为可能会导致文件引入失败,如下:
浏览器加载网页执行顺序:从上到下从左到右
html文件:
<script src="demo.js" />
.js文件:
//声明一个变量str2,并将字符串赋值给str2
var str2 ="引入JS的第二种方式";
document.write(str2); //将str2字符串的内容输出到字符串显示
方式三
:也可以直接在元素上绑定点击事件,在事件执行的方法中写JS代码
onclick: 鼠标点击事件,里面写的是一个方法。
<!--方式3 直接在元素上书写JS代码:
onclick属性用于给当前元素绑定点击事件:点击元素就会触发事件,执行相应函数 (onclick:点击鼠标)
alert()方法是个警告框,如果传入的是字符串,外面是双引号,里面只能是单引号。
-->
<input type="button" value="点我~" onclick="alert('叫你点你还真敢点啊!!!')"/>
<!--console.log() 把传入的内容输出到浏览器的控制台. F12开发这工具---console-->
<input type="button" value="别点我" onclick="console.log( new Date() )"/>
1.2 JavaScript语法
1.2.1 注释格式
JS的注释符号和Java的注释符号相同,如下:
// 单行注释内容
/* 多行注释内容 */
js也是严格区分大小写。
//js字符串可以使用单引号也可以使用双引号
1.2.2 数据类型
1、基本数据类型(5种)
(1)数值类型(number) 只有一种浮点型
在JS中,所有的数值在底层都是浮点型,但是在处理和显示的过程中会自动的和整型进行转换。
var n=4;
例如:2.4+3.6=6//为6不是6.0
特殊值:Infinity(无穷大) / -Infinity(负无穷大) / NaN(非数字)
(2)字符串类型(string)
在JS中,字符串类型属于基本数据类型,字符串常量可以使用单引号或者使用双引号引起来。例如:
var s1 = "Hello JS";
var s2 = 'Hello JS';
另外,JS中字符串类型有对应的包装对象(String),在需要时会自动的和包装对象进行转换。
var s1 = "Hello JS"; //基本数据类型, string
console.log( typeof s1 ); //string typeof返回表达式的类型
var s2 = new String("Hello JS"); //复杂数据类型, object
console.log( typeof s2 ); //object 注意o 是小写 返回数据的类型
//不管是基本数据类型s1, 还是对象类型s2, 都可以当作对象来用
console.log( s1.valueOf() ); //s1是基本数据类型, 会转成对象, 调用valueOf函数
console.log( s2.valueOf() );
字符串详解
/*1.引号和转义字符的使用。*/
//1).正常字符串我们使用 单引号,或者双引号包裹
//2).转义字符的使用 \
\` 结果: `
例: console.log("a\`");//输出结果:a`
\n 结果: 换行
例: 略
\t 结果:tab制表符
例: 略
\u4e2d 结果为:中 (unicode字符:\u####)
例:console.log("\u4e2d");//中
\x41 结果为:中 (Ascll字符)
例:console.log("\x41");//中
/*2.字符串拼接。*/
1)普通字符串
var name="早上"+",你好";
console.log(name);//早上,你好
2)模板字符串 tab上面 esc下面
var name=`早上,你好`;
console.log(name);//早上,你好
/*3.字符串长度。*/
var str="adafaf";
console.log(str.length);//6
/*4.js字符串可以直接通过下标取值,java的不可以java是char可以. 字符串的不可变性*/
var str="adafaf";
console.log(str[0]);//a
同样字符串底层也是final修饰的char类型的数组,一旦创建长度固定且不能改变。
/*5,大小写转换 注意为方法不是属性*/
var str="adafaf";
console.log(str.toUpperCase());//转换为大写
console.log(str.toLowerCase());//转换为小写
/*5,根据元素获取下标*/
var str="adafaf";
console.log(str.indexOf("d"));//1
/*6,根据元素下标截取字符串 含头不含尾*/
var str="adafaf";
console.log(str.substring(1,3));//da
console.log(str.substring(1));//dafaf从下标为1的字符串的截取到最后
(3)布尔类型(boolean)
布尔类型的值有两个,分别为true和false。
console.log(12*23>256 ?"YES":"NO");
var b1=true;
(4)undefined类型(了解)
undefined类型的值只有一个,就是undefined,表示变量未定义(但不是指变量没有声明)。
是指声明了变量,但没有为变量赋值,该变量的值默认就是undefined。
/* 1.undefined类型 */ (未定义的)
var x;
alert( x ); //undefined
alert( y ); //抛异常 (没有声明)
(5)null类型(了解)
null类型的值也只有一个,就是null,表示空值。
可以作为函数的返回值,表示函数返回的是一个空的对象。
注意:null和undefined类型的变量是不能调用函数或属性的,会抛异常!
2、复杂数据类型
主要指对象(JS的内置对象、自定义的对象、函数、数组)
内置:即 ,自带的不用自己new可以直接使用。 js中除了5种基本类型都叫对象.
1.2.3 变量声明
JS中是通过var
关键字声明变量,声明的变量是不区分类型,可以指向任意的数据。例如:
声明时不区分类型,根据你赋的值区分类型。
var x = 100;//数值
x = "abc";//字符串
x = true;//boolean
x = [];//数组
x = function(){}//函数
x = new Object(); //对象
x = {}; //对象,是对上面写法的简写
另外,JS中多次声明同名的变量不会出现语法错误,例如:
在js里多次声明同名的变量,第二次声明不会生效,用的是覆盖的值。
每句话要加上分号,不加js会帮你断句加上,但有可能不准确。
一般:变量,方法,以()结尾的加上分号,以{}结尾的不需要加上分号,类似于java。
/* 2.变量的定义 */
var s = "Hello"; // var s; s="Hello";
var s = 123; // var s; s=123; 第二次声明变量x没有生效
alert( s ); //123 会把前面的值覆盖
JS是严格区分大小写的!
js每句话以分号结尾,不写会帮你加上,但最好还是写上以防出现错误。
1.2.4 js的变量作用域
在js中,var定义变量实际上是有作用域的。
//1.假设在函数中声明,则在函数体外不可以使用。(非带用:可以"闭包"进行解决)
function qj(){
var x=1;
x=x+1;
}
x=x+2;//会报错: Uncaught ReferenceError: x is not defined
//2.如果2个函数使用了相同的变量名,只要在函数内部,就不会冲突。
function qi(){
var x=1;
x= x=1;
}
function qi2(){
var x="A";
x= x=1;
}
//3.内部函数可以访问外部函数的成员,反之则不行。
function qj(){
var x=1;
function qj2(){
var y=x=1;//2
}
var z=y+1;//Uncaught ReferenceError: y is not defined
}
//4.假设内部函数变量和外部函数的变量,重名!
function qi(){
var x=1;
function qj2(){
var x='X';
console.log('inner'+x);//outer1
}
console.log('outer'+x);//innerA
qj2();
}
qj();
/*假设在js函数中,函数查找变量从自身函数开始,有‘内’向外查找。
假设外部存在同名的函数变量,则内部函数会屏蔽外部函数的变量。*/
//5.提升变量的作用域
function qj(){
var x="x"+y;
console.log(x);
var y="y";
}
/*结果为:x undefined,说明:js执行引擎,自动提升了y的声明,
但是不会提升变量y的赋值。(即会把变量的声明自动放到前面,赋值正常位置)*/
//6.变量声明的规范
/*所以js的变量声明的规范是:所有的变量定义都放在函数的头部,不要乱放,便于代码的维护。
js创建之初就存在的特性。*/
funxtion qj(){
var x=1;
y=x=1,
z,i,a;//underfined
//之后随意使用。
}
//7.全局函数
x=1;
function f(){
console.log(x);
}
f();
console.log(x);
//8.全局对象Window(又叫浏览器对象)
var x='xxx';
alert(x);//window可省略。
alert(window.x);//默认所有的全局变量,都会自动绑定在window对象下;
//9.alert()函数本身也是一个window变量
var x='xxx';
window.alert(x);
var old_alert=window.alert;
//ola_alert(x);
window.alert=function(){
}
//发现alert失效了
window.alert(123);
//恢复
window.alert=ols_alert;
window.alert(456);
//说明js实际上只有一个全局作用域,任何变量(函数也可以视为变量),
// 假设没有在函数作用域范围内找到,就会向外查找,如果在其全局作用域都没有找到,报错:RefrenceError
//10.规范:由于所有的全局变量都会绑定到我们的window上。如果不同的js文件,
// 使用了相同的全局变量,冲突--->如何能够减少冲突???
// 定义唯一全局变量。
var KuangApp ={};
// 定义全局变量
KuangApp.name='kuangshen';
kuangApp.add=function(a,b){
return a+b;
}
/*即:把自己的代码全部放在自己定义的唯一空间名字中,降低全局命名冲突的问题。
jquery底层就是这样干的。*/
//11.全局变量的定义方式:
//1)通过var关键字实现,在方法外声明是全局,在方法内是局部。
var test = 5; //全局变量
function a(){
var cc=3; //局部变量
alert(test);
}
function b(){
alert(test);
}
//2)没有使用var,直接给标识符test赋值,不管是方法内还是方法外都是全局变量
test = 5;//全局变量
function a()
{
aa=3; //全局变量
alert(test);
}
//3)使用window全局对象来声明,全局对象的属性对应也是全局变量
window.test;
window.test = 5;
//12.局部变量let
function aaa(){
for(var i=o;i<100;i++){
console.log(i);
}
console.log(i+1);//101 问题? i出了这个作用域还可以使用显然不合适。
}
//解决:ES6新语法用let代替var解决局部变量冲突问题。
function aaa(){
for(let i=o;i<100;i++){
console.log(i);
}
console.log(i+1);//Uncaught ReferenceError: o is not defined
}
//建议都用let定义局部变量,但是很多人还是用var.
//13.const常量。
//在ES6之前定义常量的写法:变量名字字母全部为大写。
var AAA='ccc';
AAA='qqq';//任然能改变这个常量值。
console.log(AAA);
//ES6之后
const AAA='ccc';
AAA='qqq';//会报错,不能修改常量值。
console.log(AAA);
1.2.5 JS运算符
JS和Java中的运算符大致相同,例如:
算术运算符: +,-,*,/,%,++,--
赋值运算符: =,+=,-=,*=,/=,%=
比较运算符: ==,!=,>,>=,<,<=
位运算符: & , |
逻辑运算符: && ,|| ( false && 表达式, true || 表达式 )
前置逻辑运算符: ! (not)
三元运算符: 表达式 ? 表达式 : 表达式
......
//js中==和===的区别
== //类型不同,值相同,也会判断为true
=== //绝对等于(类型相同值相同,结果为true)推荐使用===
1.2.6 js常用的输出方式
1、alert("要输出的内容");
->在浏览器中弹出一个对话框,然后把要输出的内容展示出来
->alert都是把要输出的内容首先转换为字符串然后在输出的
2、document.write("要输出的内容");
->直接的在页面中展示输出的内容
3、console.log("要输出的内容");
->在控制台输出内容
1.2.7 JS语句(if,suitch,for,while,do while)
JS中的语句和Java中的语句也大致相同
1、if分支结构
if分支结构用于基于不同的条件来执行不同的动作。语法结构如下:
if (条件 1){
当条件 1 为 true 时执行的代码
}else if (条件 2){
当条件 2 为 true 时执行的代码
}else{
当条件 1 和 条件 2 都不为 true 时执行的代码
}
2、switch语句
使用 switch 语句来选择要执行的多个代码块之一。语法结构如下:
switch(n){
case 1:
执行代码块 1
break;
case 2:
执行代码块 2
break;
...
default:
与 case 1 和 case 2 不同时执行的代码
}
执行原理:首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个case 的值做比较。如果存在匹配,则与该 case 关联的代码块会被执行。请使用 break来阻止代码自动地向下一个 case 运行。
3.1、for循环语句 – 循环代码块一定的次数
for 循环的语法结构如下: js中 没有 增强for循环
for (语句 1; 语句 2; 语句 3){
被执行的代码块
}
3.2 遍历数组
//es5.1特性。
var age=[21,23,12,77,34,67,11,45];
//1.使用js提供的forEach函数进行循环。还可以用箭头函数简写这种方式,省略function
age.forEach(function (value){
console.log(value);//21,23,12,77,34,67,11,45
})
//2.使用for循环语句进行循环
for(var i=0;i<age.length;i++){
console.log(age[i]);//结果相同
}
//3.for...in(不推荐)
//for(var index in object){}
for(var num in age){
if(age.hasOwnProperty(num)){
console.log(age[num]);
}
}
4、while循环 – 在指定条件为真时循环执行代码块
JS中while循环也分为while和do/while循环,下面为while循环语法结构:
while (条件){
需要执行的代码
}
do {
需要执行的代码
}while
while 循环会在指定条件为真时循环执行代码块。
案例1:if分支案例: 接收用户输入的成绩,判断成绩所属的等级
80~100(包括80,也包括100) 优秀
60~80(包括60,但不包括80) 中等
0~60(包括0,但不包括60) 不及格
其他值 输入有误
代码实现如下:
prompt( 参数1, 参数2 )函数:在页面上弹出一个消息输入框,接收的参数1是在弹框中显示的提示内容,用户输入的内容会作为函数的返回值直接返回。
参数2, 是输入框中的默认值, 可以修改.也可以只写一个参数
<script>
/* 案例1:if分支案例: 接收用户输入的成绩,判断成绩所属的等级
80~100(包括80,也包括100) 优秀
60~80(包括60,但不包括80) 中等
0~60(包括0,但不包括60) 不及格
其他值 输入有误
---------------------------------------------
通过prompt函数可以允许用户在页面上输入内容,并返回用户的输入
但返回值是字符串类型,在需要时,可以自动的进行数据类型的转换 若什么也不输出,这接受的是0
解释:这个prompt函数类似与alert,会在页面上弹出一个框,里面的内容是框里的提示内容,他有返回值是String类型拉接受弹窗中输入的值。 如果输入的是数值类型会转化为对应的数值字符串,再给数值比会自动在进行转换为数值进行比较。如果什么也不输入,会转化为空字符串,空字符串会转化为0在进行比较。
*/
/*
var score = prompt("请输入您的成绩:");
console.log( typeof score );
document.write( score +"<br/>" );
if( score>=80 && score<=100 ){
document.write("您的成绩属于: 优秀!");//输出到网页上
}else if( score>=60 && score<80 ){
document.write("您的成绩属于: 中等!");
}else if( score>=0 && score<60){
document.write("您的成绩属于: 不及格!");
}else{
document.write("您的成绩不合法,请重新输入!");
} */
案例2:switch语句案例—实现一个简易的计算器:
可以接收用户输入的两个数值和一个运算符(+、-、*、/),根据运算符号的不同,对两个数值执行不同的运算。
代码实现如下:
var str = prompt("请输入数值1、运算符、数值2,中间用空格分隔:");
document.write("<hr/>"+str); // "10 + 5"
//对当前这个str字符串根据空格进行切割,切割后所有的子字符串会作为数组返回
var strArr = str.split(" "); // ["10","+","5"]
var num1 = strArr[0]-0; // "10"只能在js用, -是运算符只能用于数值运算,所以会自动转
var opt = strArr[1]; // "+"
var num2 = parseFloat( strArr[2] ); // "5"只有parseInt 和parseFloat.这个不会有精度丢失.
switch( opt ){
case "+":
document.write("两个数值的和为:" + (num1 + num2) ); // 因为+是拼接符所以要先把返回的字符串转为数值类型
break;
case "-":
document.write("两个数值的差为:"+ (num1 - num2) );
break;
case "*":
document.write("两个数值的乘积为:"+ (num1 * num2) );
break;
case "/":
document.write("两个数值的商为:"+ (num1 / num2) );
break;
default:
document.write("您输入的运算符不合法,请重新输入!");
} */
案例3:for循环语句案例
遍历1~100之间的所有整数,求1~100之间所有整数的和,并输出到控制台;
代码实现如下:
/* 案例3:for循环语句案例
遍历1~100之间的所有整数,求1~100之间所有整数的和,并输出到控制台; */
var sum = 0;
for(var i=1;i<=100;i++){
// sum = sum+i;
sum += i;
}
document.write("1~100之间所有整数的和为:"+sum);
document.write("<hr/>")
案例4:while循环语句案例
遍历下面数组中的元素,将元素输出到控制台。
var arr = [123, "abc", false, new Object() ]; //java中是大括号。
代码实现如下:
var arr = [ 123, "abc", false, new Object() ];*/
var arr = [ 123, "abc", false, new Object() ];
var index = 0; //作为数组的下标
var len = arr.length; //获取数组长度
//声明数组的长度写在外面是因为,若写在里面的话每循环一次调用一次,浪费时间。一次可能时间少,但要是许多人访问就会节约大量的时间。
while( index < len ){
document.write( arr[index] +" ");
index++;
}
document.write("<hr/>");
1.2.8 JS数组
Array 对象用于在单个的变量中存储多个值。
JS数组的声明方式一:
var arr=( ); 没有这种写法
var arr={ }; 对象的声明方式
var arr=[ ]; 数组的声明方式
var arr=/xx/; 如果里面有内容的话是正则表达式的声明方式
//声明一个空数组,长度为零
var arr1 = [];
//声明一个数组,并为数组设置初始值
var arr2 = ["Hello", 111, false, new Object() ];
arr[0]=1 //通过下标取值和赋值
JS数组的声明方式二:
//声明一个空数组,长度为零
var arr3 = new Array();
//声明一个数组,并为数组设置初始值
var arr4 = new Array("Hello", 111, false, new Object());
数组中的细节问题:
(1)JS中的数组可以存储任意类型的数据
(2)JS中的数组长度是可以被任意改变的
var arr1 = [];
console.log("此处数组的长度为: "+arr1.length ); // 0
arr1.length = 5;
console.log("此处数组的长度为: "+arr1.length ); // 5
arr1[9] = "a";
console.log("此处数组的长度为: "+arr1.length ); // 10
arr1[99] = "b";
console.log("此处数组的长度为: "+arr1.length ); // 100
数组的方法
//数组里面的只可以直接输出
var str=[1,2,3,4,5,6];
console.log(str);//[1, 2, 3, 4, 5, 6]
//1.长度,注意这个长度可以赋值
console.log(str.length);//6
//注意:假如给arr.length赋值,数组大小就会发生变化,如果赋值太小,元素就会丢失。如果赋值太大多的用empty表示。
str.length=10;
console.log(str);//[1, 2, 3, 4, 5, 6, empty × 4]
str.length=2;
console.log(str);//[1, 2]
//2.indexof,通过元素获取下标索引
str.indexof(2)
//3.slice() 截取Array的一部分,返回一个新数组,类似于String中的substring含头不含尾。
str.slice(2)
//4.push(),pop()
str.push("a","b") //压入到数组尾部。
str.pop() //弹窗尾部的一个元素。不传值。
//5.unshift(),shift()
unshift:压入到头部
shift:弹出头部的一个元素。
//6.排序sort()
["B","C","A"]
arr.sort()
["A","B","C"]
//7.元素反转 reverse()
["A","B","C"]
arr.sort()
["C","B","A"]
//8.concat() 拼接数组
["A","B","C"]
arr.concat([1,2,3])
["A","B","C",1,2,3]
["A","B","C"] //输出原来的
注意:concat()并没有修改数组,只是会返回一个新数组。
//9.连接符 join
//打印拼接数组,使用特定的字符串连接
["C","B","A"]
arr.join('-')
"C-B-A"
//10.多维数组
arr=[[1,2],[3,4],["5","6"]];
arr[1][1]
4
1.2.9 JS函数(匿名函数)
函数就是一个具有功能的代码块, 可以反复调用
函数就是包裹在花括号中的代码块,前面使用了关键词 function。
js函数它是弱类型语言没有重载概念,它和参数的类型个数无关。js中所有的方法名都可以看成是一个变量名,所以只要方法名相同(和里面有没有参数无关)就会发生重写(覆盖)。js中的覆盖自己理解是整个方法的覆盖原有的方法,所以区分js中的方法只能是根据方法名来进行区分。
JS中声明函数的方式为: 里面的参数不写参数类型,只需要些参数的名字。
注意:js里面的函数名不能用关键字:如删除不能用delete,否则不起作用。
function 函数名称([参数列表]){
函数体
}
function fn1(name,age){
alert(name+", "+age);
return name;
}
调用: fn1( "刘沛霞", 35 );
//一旦执行到return代表函数结束,返回结果!
//如果没有执行return,函数执行完也会返回结果,结果就是undefined;
或者: 注意这种方法名是在前面写的。
var 变量名/函数名 = function([参数列表]){
函数体
}
例如:
var fn2 = function (name,addr){
alert(name+", "+addr);
}
调用函数 fn2( "张慎政", "河南商丘" );
调用函数都一样:
//函数名称([参数列表]);
//js中的参数问题:
js可以传递任意一个参数,也可以不传递参数。
//1.参数进来是否存在问题?假设不存在参数如何规避。
var x='aa';
if(typeof x!=='number'){ //如果x不是数字类型则抛出异常。
throws 'Not a Number';
}
//2.参数多个问题?arguments是js免费赠送的关键字。它代表传递进来的所有参数,是一个数组。(即,源码里面定义的参数也以输出来)
var abs=function(x){
console.log("x=>"+x);
for(var i=0;i<arguments.length;i++){
console.log(arguments[i]);
}
if(x>0){//绝对值函数。
return x;
}else{
return -x;
}
}
//3.arguments包含所有的参数,我们有时候想要使用多余的参数来进行附加操作。需要排除已有参数。
以前的写法:
if(arguments.length>2){
for(var i=2;i<arguments.length;i++){
}
}
现在的写法;
ES6的新特性,获取以经定义的参数之外的所有参数...
function aaa(a,b,...rest){
console.log("a=>"+a);
console.log("b=>"+b);
console.log(rest);
}
//注意:rest只能写在最后面,必须用...标识。
js中的匿名函数:匿名函数就是没有实际名字的函数,只能调用一次。 如:
//声明一个匿名函数,并调用
//解释:用括号把函数包裹并且在最后加上一个括号调用可以传参数
(function(name,addr){
console.log(name+":"+addr+"...");
})("刘德华","中国香港");
扩展:js中可以把函数当做一个参数传递给另外一个函数。
//声明一个fn函数,并接受一个"函数类型"的参数.
function fn(myFunction){
console.log(“fn函数执行了...);
myFunction("张飞","河北");//把接过来的函数调用一下
}
//声明一个fn2函数,并接受name和age
function fn2(name,age){
console.log(“fn2函数执行了...);
console.log(name+":"+age);
}
//调用fn函数,并将fn2作为参数传给fn函数。
fn( fn2 );
1.2.10 js对象
对象是大括号,数组是中括号。
每个属性之间使用逗号隔开,最后一个不需要添加。
里面是若干键值对.
js中的所有键都是字符串,值可以是任意对象。
//1.语法: 还有几种方式。
var 对象名={
属性名: 属性值,
属性名: 属性值,
属性名: 属性值
}
var person={
name:"shuai",
age:3,
tages:['js','java','web','...']
}
//2.使用一个不存在的对象属性不会报错!
person.haha
undefined
//3.调用对象的值
person.name // shuai
person.age //3
//4.对象赋值
person.name ="你好";
//5.动态的删减属性,java不可以。
delete person.name
true
person //输出对象里面的值
//6.动态的添加,直接给新的属性添加值即可
personson.haha="haha"
"haha"
person
//7.判断属性值是否在这个对象中! xxx in xxx!
'age' in person
true
//继承
'toString' in person
true
//8.判断一个属性是否是这个对象自身拥有的 hasownProperty
person.hasownProperty('toString')
false
person.hasownProperty('age')
false
1.2.11 js对象里面的方法
方法就是把函数放在对象里面,对象只有2改东西:属性和方法。
var kuangshen={
name:'王珂',
birth:2000,
//方法
age:function (){ //注意没有方法名
//今年-出生的年
var now =new Date().getFullYear();
return now-this.bitrh;
}
}
//属性
kuangshen.name
//方法,一定要带()
kuangshen.age()
this.代表什么?拆开上面的代码看看
function getAge(){
var now=new Date().getFullYear();
return now-this.bitrh;
}
var kuangshen={
name:'王珂',
birth:2000,
//方法
age:getAge
}
//kuangshen.age() ok
//getAge() NaN window
this是无法指向的,是默认只想调用他的那个对象。
在js中可以通过apply控制this的指向
function getAge(){
var now=new Date().getFullYear();
return now-this.bitrh;
}
var kuangshen={
name:'王珂',
birth:2000,
//方法
age:getAge
}
getAge.apply(kuangshen,[]);//this 指向了kuangshen,参数为空。
1.2.12 js里面的特殊对象
标准对象
typeof 123 //typeof 判断参数的类型
"number"
typeof '123'
"string"
typeof true
"boolean"
typeof NaN
"number"
typeof []
"object"
typeof {}
"object"
typeof Math.abs
"functionr"
typeof underfined
"underfined"
内部对象(data,json)
1.data对象
//1.Date
var now=new Date();
console.log(now)//VM238:2 Fri May 21 2021 12:51:27 GMT+0800 (中国标准时间)
now.getFullYear();//年
now.getMonth();//月
now.getDate();//日
now.geyDay();//星期几
now.getHours();//时
now.getMinutes();//分
now.getSeconds();//秒
//时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
now.getTime();//时间戳 全世界统一 1070 1.1 0:00:00 毫秒数
console.log(new Date(1621572687140));//时间戳转化为时间(里面的值为:now.getTime())
转换
now =new Date(1621572687140)
Fri May 21 2021 12:51:27 GMT+0800 (中国标准时间)
//转换为本地时间,也可以用东八区的方法
now.toLocaleString//注意,调用是一个方法,不是一个属性
ƒ toLocaleString() { [native code] }
now.toLocaleString()
"2021/5/21下午12:51:27"
//转化为 世界时
now.toGMTString()
"Fri, 21 May 2021 04:51:27 GMT"
2.json对象
json是什么:
早期,所有数据传输习惯使用XML文件!
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在js中一切皆对象,任何js支持的类型都可以用json来表示:number,String…
格式:
对象和map都用{}
数组和list都用[]
所有的键值对都是key:value
json字符串和json对象的转化。
//json对象:单引号或双引号都行
var user={
"name":"wangke",
"age":3,
"sex":"男"
}
//json对象{"name":"qinjiang","age":3,"sex":"男"}转化为json字符串
//一般用于操作json中的数据时候,需要json字符串
var jsonUser =JSON.stringify(user);//'{"name":"qinjiang","age":3,"sex":"男"}'
//json字符串转化为json对象,参数为json 字符串
//一般用于在客户端和服务器之间进行数据交互时,使用json字符串。
var obg =JSON.parse('{"name":"qinjiang","age":3,"sex":"男"}');
很多人搞不清楚,json字符串 、json对象、js对象三者的区别。
var json='{'a':'hello','b':'hellob'}';//json字符串
var json = {'a':'hello','b':'hellob'};//json对象
var obj={a:'hello',b:'hellob'};//js对象
1.2.13 js变量函数和属性方法的区别
var age=20;//变量
function fb(){ //函数
}
var aa={
age:30, //属性
fn:function(){ //方法(直接赋值给它,第二种声明方法的方式。)
}
}
总结:
1.变量和属性作用形同,他们都是用来储存数据的。
变量 :单独声明并赋值 使用的时候直接写变量名 单独存在。
属性 :在对象里面不需要声明的 使用的时候必须是 对象.属性。
2.函数和方法的相同点 都是实现某种功能 做某件事
函数是单独声明 并且调用的 函数名() 单独存在的
方法在对象里面 调用的时候 对象.方法()
1.2.14 js的Map和Set
Es6的新语法
//需求:现在想要查询学生的成绩,学生的名字。
Map:
var names=["tom","jack","rose"];
var scores=[100,90,80];
这种方式需要多个数组进行查询,熟读非常慢。
//改进:
var map=new map([['tom,100'],['jack',90],['haha,80']]);
var name=map.get('tom')//通过key获取value
map.set('admin',123456);//新增或修改
map.delete("tom");//删除
Set:无序不可重复
var set =new Set([3,1,1,1,23]);//去重
set.add(2);//添加
set.delete(1);//删除
console.log(set.has(3));//是否包含
1.2.15 js的iterator
//通过for of实现迭代器, for in不行
//1.可以迭代数组
var arr=[3,4,5];
for (var x of arr){
console.log(x);
}
//2.可以迭代Map集合
var map=new Map([["tom",100],["jack",90],["haha",80]]);
for(let x of map){
console.log(x);
}
//3.可以迭代Set集合
var set =new Set(5,6,7);
for(let x of map){
console.log(x);
}
1.2.16 严格检查模式说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--
前提是IDEA 需要设置支持ES6的语法
'use strict'严格检查模式,预防js的随意性导致产生的一些问题,必须写在第一行,
建议写所以的js代码第一行都加上这句话。
局部变量建议建议使用 let去定义
常量的定义用 const
全局变量用var -->
<script>
'use strict';
//默认全局变量:i=1;
let i = 1;
//在ES6中 局部变量建议用let
</script>
</body>
</html>
总结:像这样i=1这样的代码js可以写,并且可以正确输出,但是如果引入了很多的js文件,
里面的js定义都要这个名字为i的变量,则会后面的覆盖前面的,显然不对,解决:加上这个
'use strict',并设置js版本为es6,则会帮你自动检查,再这样写就会报错不能输出了。
1.2.17 面向对象编程
原型对象
js,java,c#…面向对象;js有些区别!
类:模板,原型对象
对象:具体的事例
在js中这个对象需要换下思维方式。
原型: Es6之前继承的写法。
var Student={
name:"wangke",
age:3,
run:function(){
console.log(this.name+"run...");
}
};
var xiaoming={
name:"xiaoming"
};
//原型对象
xiaoming._proto_=Student;
var Bird={
fly:function(){
console.log(this.name+"fly...");
}
}
//小明的原型是 Student
xiaoming._poroto=Bird
即:把小明当做子类继承父类Student.子类就可以用父类的方法了。
function Student(name){
this.name=name;
}
//给student新增一个方法
Student.prototype.hello=function(){
alert('hello');
}
class对象
class继承 (ES6)
1.定义一个类,属性,方法
//ES6 之后=============
// 定义一个学生的类
class Student{
constructor(name){
this.name = name;
}
hello(){
alert('hello')
}
}
var xiaoming = new Student("xiaoming");
var xiaohong = new XiaoStudent("xiaohong",1);
xiaoming.hello()
2.继承
//ES6 之后=============
// 定义一个学生的类
class Student{
constructor(name){
this.name = name;
}
hello(){
alert('hello')
}
}
class XiaoStudent extends Student{
constructor(name,grade){
super(name);
this.grade = grade;
}
myGrade(){
alert('我是一名小学生')
}
}
var xiaoming = new Student("xiaoming");
var xiaohong = new XiaoStudent("xiaohong",1);
本质:查看对象原型
原型链
_prop_:
1.2.18 操作BOM对象(重点)
浏览器介绍:
js和浏览器关系?
js诞生就是为了能够让它在浏览器中运行!
BOM:浏览器对象模型。
1.IE 6~11
2.Chrome
3.Safari
4.FireFox
5.Opera
三方浏览器:
qq浏览器
360浏览器。
window介绍:(重点)
window代表浏览器窗口。
window.alert(1) //警告框
undefined
window.innerHeight
700
window.innerWidth
150
window.outerHeight
819
window.outerWidth
1555
//可以根据你打开的浏览器窗口改变值。
Navigator:
//Navigator,封装了浏览器的信息
window.navigator.appName
"Netscape" //浏览器的名字
navigator.appVersion
"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
navigator.userAgent
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
navigator.platform
"Win32"
//大对数时候,我们不会使用Navigator对象,因为会被任伟修改!不建议使用这些属性来判断和编写代码。
screen:
//代表屏幕的尺寸
screen.width
1536 px
screen.height
864 px
location(重点)
//location代表当前页面的URL信息
host: "www.baidu.com"
hostname: "www.baidu.com"
protocol: "https:"
reload: ƒ reload()//刷新网页
location.assign('https://blog.kuangstudy.com/')
document(重要)
//document代表当前的页面,HTML DOM文档树
//1.获取网页标题
document.title
"百度一下,你就知道"
document.title='aaa' //aaa
//2.获取具体的文档树节点
<dl id="app">
<dt>Java</dt>
<dd>JavaSE</dd>
<dd>JavaEE</dd>
</dl>
<script>
//返回值是一个对象
var dl = document.getElementById('app');
</script>
//3.获取cookie 百度为例子
document.cookie
"BIDUPSID=BCD0DD182F7217AAC52916C027F801D6; PSTM=1610891488; BD_UPN=12314753; MCITY=-268%3A; BAIDUID=65FFF5AC4BBD3B7839BB19908E91EDC1:FG=1; BAIDUID_BFESS=65FFF5AC4BBD3B7839BB19908E91EDC1:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; Hm_lvt_aec699bb6442ba076c8981c6dc490771=1619429257,1621489701; BD_HOME=1; H_PS_PSSID=33838_34044_31253_33848_33773_33607_26350; delPer=0; BD_CK_SAM=1; ZD_ENTRY=baidu; COOKIE_SESSION=13091_0_9_9_60_62_0_0_0_9_59_0_13081_0_3_0_1621586860_0_1621586857%7C9%2325424_50_1617369622%7C9; PSINO=1; rsv_jmp_slow=1621587991745; H_PS_645EC=ed99IvVBlDpfu1heiqMVKMPw0wG7YGT4AILE9Vre3XX1%2By5mFgkBe0x%2FU6U; BDSVRTM=0; BA_HECTOR=2h8025048h80842g9h1gaf1k70r"
//4.劫持cookie原理
<script src="aa.js"></script>
<!--恶意人员:获取你的cookie上传到他的服务器-->
//服务器端可以是这cookie:httpOnly阻值。
//5.history 代表浏览器记录
history.back()//后退
history.forward();//前进
1.2.19 综合练习
(自己完成)声明一个函数fn,在函数中实现:遍历指定的两个数值(例如1和100)之间的整数,将是3的倍数的数值存入到一个数组中,并将数组返回。
1、声明fn函数
//声明一个fn函数,接收2个参数
function fn(x,y){
//声明一个数组,用于储存是3的倍数的数值
var arr = [];
//循环x到y之间的所有整数
for(var i=x,j=0;i<y;i++){
//判断i(当前正在遍历的整数)是否为3的倍数
if(i%3==0){
arr[j] = i; //如果是,则将i存入arr数组中
j++; //自增
}
}
return arr; //返回arr数组
}
2、调用fn函数, 获取1~100之间是3的倍数的数值组成的数组
var arr = fn(1,100);
3、遍历数组中的元素, 输出在网页上(提示: document.write(“输出的内容”) )
for(var i=0;i<arr.length;i++){
document.write(arr[i]+" ");
}
1.3 DOM操作详解
DOM: Document Object Model,文档对象模型,其实就是JS专门为访问html元素提供的一套API。
核心: 浏览器网页就是一个DOM树形结构。
-
获取: 获取DOM节点
-
更新:更新DOM节点
-
删除:删除一个DOM节点
-
添加:添加一个DOM节点
要操作一个DOM节点,就必须先获得这个DOM节点。
1.3.1 获取DOM节点
一下都是js原生代码比较长,将来都用jquery简写。
<body>
<div id="father">
<h1>标题一</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
//对应 css 选择器 返回值是一个js对象
var h1 = document.getElementsByTagName('h1');//根据标签获取
var p1 = document.getElementById('p1');//根据id获取
var p2 = document.getElementsByClassName('p2');//根据类
var father = document.getElementById('father');
var childrens = father.children; //获取父节点下的所有子节点
// father.firstChild 获取父节点下的第一个子节点
// father.lastChild 获取父节点下的最后一个子节点
</script>
1.3.2 更新DOM节点(innerHTML,css)
<body>
<div id="id1">
</div>
<script>
var id1 = document.getElementById('id1');//先拿到节点
id1.innerText = 'abc'
</script>
</body>
操作文本
//插入或修改文本的值(原先有值为修改,没有为插入)
id1.innerText='123'
//加粗并插入123. 2则的区别:innerHTML可以解析HTML文本标签。
id1.innerHTML='<strong>123</strong>'
js动态操作css
id1.style.color='red'; //设置样式为红色
id1.style.fonSize='20px'//设置字体大小
1.3.3 删除节点
步骤:先获取父节点,在通过父节点删除自己:
<div id="father">
<h1>标题一</h1>
<p id="p1">p1</p>
<p id="p1">p1</p>
</div>
<script>
var self=document.getElementById('p1');
var father=self.parentElement;
father.removeChild(selef)
//删除是一个动态的过程
father.removeChild(father.children[0])
father.removeChild(father.children[0])
father.removeChild(father.children[0])
</script>
注意:删除多个节点是,children是时刻变化的,删出节点时候一定要注意。
1.3.4 插入(添加)DOM节点
我们获得了某个DOM节点,假设这个DOM节点是空的,我们通过innerHTML就可以增加一个元素了,但是这个DOM节点已经存在元素了,我们就不能这么干了!会产生覆盖。
步骤:先获取父节点,在把子节点添加到父节点里面。
1.把已存在的节点追加到已存在的节点里面(默认追加到最后一行)
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js = document.getElementById('js');//子
var list = document.getElementById('list');//父
list.appendChild(js);//追加到后面(参数是子类对象)
</script>
2.创建一个新的标签,实现插入
<script>
var js = document.getElementById('js');//已存在的节点
var list = document.getElementById('list');//追加到后面
//通过一个新的标签,实现插入
var newP=document.createElement('p');//创建一个p标签
//写法1:
newP.id='newP';//向这个标签添加id=newP的属性
//写法2:万能写法,k写属性名 v写属性值。
//newP.setAttribute('id','newP')
newP.innerText='Hello,kuangshen';//向这个标签添加文本内容。
list.appendChild(newP);//追加到后面
//创建script标签
var myScript=document.createElement('script');
myScript.setAttribute('type','text/javascript')
//创建一个style标签
var myStyle=document.createElement('style');//创建一个style标签
myStyle.setAttribute('type','text/css');
myStyle.innerHTML='body{background-color:chartreuse;}';//设置标签内容
document.getElementsByTageName('head')[0].appendChild(myStyle);
</script>
3.把已存在的节点追加到已存在的节点前面
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var ee = document.getElementById('ee');
var js = document.getElementById('js');
var list = document.getElementById('list');
//父节点(简介包含也行) 新节点 目标节点
list.insertBefore(js,ee);
</script>
1.3.5 操作表单
表单是什么: form 本身也是一个DOM树
1.文本框
2.下拉框
3.单选框
4.多选框
…
表单的目的:提交信息
<form action="#">
<p>
<span>用户名:</span> <input type="text" id="username" required>
</p>
<!--多选框的值,就是定义好的value -->
<p>
<span>性别:</span>
<input type="radio" name="sex" value="man" id="boy"> 男
<input type="radio" name="sex" value="women" id="girl"> 女
</p>
<input type="submit">
</form>
<script>
var input_text = document.getElementById('username');
var boy_radio = document.getElementById('boy');
var girl_radio = document.getElementById('girl');
// 得到输入框的值
input_text.value
// 修改输入框的值
input_text.value = '123'
// 对于单选框,多选框等等固定的值,boy_radio.value只能取到当前的值
boy_radio.checked; //查看返回的结果,是否为true,如果为true,则被选中~
girl_radio.checked = true; //赋值
</script>
1.3.6 提交表单(加密处理md5)
<!--
表单绑定提交事件
οnsubmit= 绑定一个提交检测的函数, true, false
将这个结果返回给表单,使用 onsubmit 接收!
οnsubmit="return aaa()"
-->
<form action="https://www.baidu.com/" method="post" onsubmit="return aaa()">
<p>
<span>用户名:</span> <input type="text" id="username" name="username">
</p>
<p>
<button type="submit">提交</button>
<span>密码:</span> <input type="password" id="input-password">
</p>
<input type="hidden" id="md5-password" name="password">
<!--绑定事件 onclick 被点击-->
</form>
<script>
function aaa() {
alert(1);
var uname = document.getElementById('username');
var pwd = document.getElementById('input-password');
var md5pwd = document.getElementById('md5-password');
// pwd.value = md5(pwd.value);
md5pwd.value = md5(pwd.value);
// 可以校验判断表单内容,true就是通过提交,false,阻止提交
return true;
}
</script>
1.4 案例
1.4.1 案例:电灯开关
点击电灯可以实现开/关灯,代码实现如下:
注意:js中可以用一个对象表示一个标签,我们可以通过对象的属性表示标签的属性。
//思路:通过点击事件执行js方法,在这个函数中获取这个标签当做对象,通过这个对象获取对应的属性,在通过if判断更改这个用于控制切换图片的属性值即可。
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>电灯开关案例</title>
<style>
body{padding:20px;font-size:20px;}
#div1{width:30%;border:1px solid red;padding:5px;margin-bottom:20px;}
</style>
<!-- 引入jquery的js库 这个地方没用到jquery注释掉了
<script src="js/jquery-1.8.3.min.js"></script> -->
<script>
/** 练习:点击按钮,开灯或关灯 */
var flag = "off"; //flag用于标记灯的状态,off表示灯目前是关闭状态,on表示灯是打开状态
function changeImg(){
//1.获取表示img元素的js对象 // oImg ==> <img id="img1" src="imgs/off.gif"/>
var oImg = document.getElementById("img1");
//2.判断灯的状态,根据状态选择开灯或关灯
if( flag == "off" ){ //表示灯为关闭状态,需要改为打开状态
oImg.src = "imgs/on.gif"; //打开灯
flag = "on"; //由于上面已经将灯打开,所以更新flag的状态为on
}else{ //表示灯为打开状态,需要改为关闭状态
oImg.src = "imgs/off.gif"; //关闭灯
flag = "off"; //由于上面已经将灯关闭,所以更新flag的状态为off
}
}
</script>
</head>
<body>
<!-- onclick用于为按钮绑定点击事件,当点击按钮时,就会触发点击事件,执行changeImg函数 -->
<input type="button" value="开/关灯"
onclick="changeImg()" /> <br/><br/>
<img id="img1" src="imgs/off.gif"/>
</body>
</html>
1.4.2 案例:增删改元素(元素的DOM操作)
点击网页中的按钮对html元素进行操作
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>元素的增删改查</title>
<!-- 加入样式表 -->
<style type="text/css">
div { border:#0099FF 2px solid;height:60px;width:350px;margin:20px 10px;padding:5px 7px;line-height:60px;font-size:26px;text-align:center;}
#div_1{ background-color:#d400ff; }
#div_2{ background-color:#FF3399; }
#div_3{ background-color:#00FF00; }
#div_4{ background-color:#FFFF66; }
#info{ width:250px;height:90px;font-size:22px;padding:5px;resize:none;}
input{font-size:18px;}
</style>
<!-- 引入jquery的js库
<script src="js/jquery-1.8.3.min.js"></script> -->
<script type="text/javascript">
/** 练习1、添加元素:添加一个div元素到body中 */
function addNode(){
//1.创建一个div元素,并给div添加内容,参数是元素名称
var oDiv = document.createElement("div"); //<div></div>
oDiv.innerHTML = "Hello,我是新来的div~~"; //<div>Hello,我是新来的div~~</div> 向这个div标签里面添加内容。
//2.获取当前网页中的body元素(document上提供了直接获取body元素的属性)
var oBody = document.body; // 如果位置发生改变怎么找它的父类
//3.通过父元素调用方法,添加子元素(因为元素只创建出来没有和当前网页建立联系,所以不会再当前网页显示,想要显示就需要建立联系。比如放在body标签里面。)
oBody.appendChild( oDiv );
}
/** 练习2、删除元素: 删除id为div_2的元素 */
//parentNode
function deleteNode(){
//1.获取要删除的元素
var oDiv2 = document.getElementById("div_2");
//2.获取要删除元素的父元素( parentNode获取当前元素的父元素 )
//var oBody = document.body;没有用body是因为放在别的地方不一定是body.
var oParent = oDiv2.parentNode;//这个同样获取父级元素。
//3.通过父元素调用方法,删除子元素
oParent.removeChild( oDiv2 );
}
/** 练习3、更新元素内容:将div_3的内容更新为当前时间 */
function updateNode(){
//1.获取id为div_3的元素
var oDiv3 = document.getElementById("div_3");
//2.获取表示当前时间的字符串 Local是外国的时间格式
var dateStr = new Date().toLocaleString();
//3.将div_3元素的内容更新为当前时间字符串
oDiv3.innerHTML = dateStr;
}
//练习4.删除所有的div元素
function deleteAll(){
//获取所有的div元素,返回所有的div元素数组
var divArr=document.getElementsByTagName("div");
//便利div元素的父元素,并通过父元素删除当前元素
var len =divArr.length;//获取并记录数组的长度,这样的好处是,数组长度固定,再删除长度也不会变化
//便利div元素组成的数组
for(var i=0;i<len;i++){
//获取当前元素的父元素,并通过父元素删除当前元素
divArr[0].parentNode.removeChild( divArr[0] );
}
}
</script>
</head>
<body>
<input type="button" onclick="addNode()"
value="创建一个div添加到body中"/>
<input type="button" onclick="deleteNode()"
value="删除id为div_2的元素"/>
<input type="button" onclick="updateNode()"
value="将div_3的内容更新为当前时间"/><hr/>
<input type="button" onclick="deleteAll()"
value="删除所有的div元素"/><hr/>
<div id="div_1">
div_1
</div>
<div id="div_2">
div_2
</div>
<div id="div_3">
div_3
</div>
<div id="div_4">
div_4
</div>
</body>
</html>
1.4.3 案例:网页换肤
3个.css文件 换肤的css文件 省略没写。
<html>
<head>
<meta charset="utf-8"/>
<title>网页换肤</title>
<style type="text/css">
body{font-size:18px;font-family:"微软雅黑";}
hr{border:1px solid yellow;}
a{font-size:17px;font-weight:500;}
a:hover {color:#0099FF;}
h2,#change-font{text-align:center;}
#newstext{padding:10px;margin:0 auto;letter-spacing:2px;}
/* 预先定一些选择器 */
.min{
font-size:16px;
}
.middle{
font-size:18px;
}
.max{
font-size:20px;
}
.super-max{
font-size:24px;
}
</style>
<!-- 引入外部的CSS文件 -->
<link rel="stylesheet" href="" id="link"/>
<!-- 引入jquery的js库
<script src="js/jquery-1.8.3.min.js"></script> -->
<script type="text/javascript">
/** 练习1:执行下面的函数,切换字体大小 */
function resize(size){
//获取id为newstext的元素(div)
var oDiv = document.getElementById("newstext");
//将接收到的class值,赋值给上面获取到的div元素
//由于class是js中的保留字,因此为元素设置class属性不能直接点class(.class),而是通过className
oDiv.className = size;
}
//定义数组,存放不同的皮肤(css文件的路径)
var arr = ["css/red.css","css/green.css","css/blue.css","css/yellow.css"];
var index = 0;
/** 练习2:执行下面的函数,为页面切换不同的皮肤 */
function changeStyle(){
//1.获取link标签(返回是一个js对象,这个对象表示link标签)
var oLink = document.getElementById("link");
//2.修改link标签的href属性值,指向一个css文件的路径
//oLink.href = arr[index];
oLink.setAttribute("href", arr[index]);
index++;
//3.判断index的值是否大于或等于数组长度
if( index == arr.length ){
index = 0;
}
}
</script>
</head>
<body>
<h2>达内时代科技集团简介</h2>
<div id="change-font">
<!-- 当为a标签的href属性赋值为 "javascript:void(0)"时,可以阻止超链接跳转:因为超链接默认的有一些样式,不用再额外设置样式了
这里面的方法的参数是 选择器即class的值。
执行流程:浏览器加载网页---点击网页中的超链接---执行里面的方法把class变为对应的参数即选择器变了----选择器变了对应的css样式即字号也变了。
-->
<a href="javascript:void(0)"
onclick="resize('min')">小字体</a>
<a href="javascript:void(0)"
onclick="resize('middle')">中字体</a>
<a href="javascript:void(0)"
onclick="resize('max')">大字体</a>
<a href="javascript:void(0)"
onclick="resize('super-max')">超大字体</a>
<a href="javascript:void(0)"
onclick="changeStyle()">换肤</a>
</div>
<hr/>
<div id="newstext" class="middle">
<p>
达内时代科技集团有限公司,是中国高端IT培训的领先品牌,致力于培养面向互联网、电信和金融领域的Java、C++、C#、.Net、软件测试、嵌入式、PHP、android等方面的中高端软件人才。
</p>
<p>
达内创办于2002年,专注IT职业教育17年,2014年在美国纳斯达克上市公司。目前,已开设24大课程方向,在全国70多个城市建立了330家培训中心,真正实现“一地学习,全国就业”。高薪聘请总监级名师全职授课,术业有专攻,名师出高徒。实施“因材施教,分级培优”教学方案,让每一位学员都成才,让强者更强。采用“先学习,就业后付款”的模式,已帮助80万名学员成功就业。
</p>
<p>
达内优秀的教学效果和行业领先的经营模式赢得了社会各界的广泛赞誉和好评,荣获了各界权威机构的颁奖:达内成为业界唯一的一家2006、2007、2008、2009连续4年入选德勤评选的 “中国高科技高成长50强公司”、“亚太地区高科技高成长500强公司”,获得首届中国留学人才归国创业“腾飞”奖、中关村管理委员会指定的“软件人才培养示范基地”、被《计算机世界》评选的“就业服务杰出贡献奖”、被《中国计算机报》评选的“最具影响力培训机构奖”、被搜狐评为“中国十大教育集团”、被腾讯评为“中国大学生心目中最具影响力的IT品牌”。
有实力、有信誉,要培训,就选上市公司!
</p>
</div>
<hr/>
</body>
</html>
1.4.4 总结:JS增删改元素
document.createElement( 元素名称 )
– 根据元素名称创建指定名称的元素,返回的是表示新创建元素的js对象
parent.appendChild( child )
– 通过父元素添加子元素,其中parent表示父元素,child表示子元素
parent.removeChild( child )
– 通过父元素删除子元素,其中parent表示父元素,child表示子元素
element.innerHTML
– 获取当前元素的html内容(从开始标签到结束标签之间的所有内容),还可以设置当前元素的html内容(如果元素内部有内容,将会覆盖原有内容)
<div id="div1">
这是一个div元素...
<span>这是一个span元素</span>
</div>
//获取div元素
var oDiv1 = document.getElementById("div1");
oDiv1.innerHTML;//获取div元素的内容
2. jQuery
2.1 jQuery简介
2.1.1 什么是jQuery(了解)
jQuery: JavaScript Query JS查询
jQuery是一门轻量的、免费开源的JS函数库(就是JS的简单框架)
jQuery可以极大的简化JS代码
jQuery的核心思想:“写的更少,但做的更多”
注意:alt +/ 如过提示 No Default Proposals: 没有默认的提示
官网:jquery.com
轻量的:是指一个技术或框架对代码或程序的侵入程度是比较低的。或者说代码对该技术依赖程度越低。这个技术越轻,对该技术的依赖程度越高,这个技术越重。 技术越轻量越好,但是现在jquery也变得重了.
jQuery本质就是一个包含了很多函数的JS文件,如果要在某一个HTML中使用这个JS文件中的函数,就必须得将JS文件引入到HTML中(想使用jQuery,就得引入jQuery的函数库文件,就是一个JS文件)
2.1.2 jQuery的优势(了解)
(1) 可以极大的简化JS代码
(2) 可以像CSS选择器一样获取html元素
css中获取所有的div,给div添加样式:
div{ css属性... }
jQuery中获取所有div,给div添加边框样式:
$=jquery 相当于是调用一个函数,里面传的是参数
$("div").css("border", "2px solid red");
JS获取id为div1的元素:
document.getElementById("div1") 返回值是一个对象。
jQuery获取id为div1的元素:
$("#div1")或者jquery("#div1")
(3) 可以通过修改css属性控制页面的效果
(4) 可以兼容常用的浏览器
比如: JS中的innerText属性、removeNode()函数、replaceNode( )函数 这些函数在某些浏览器中是无法使用的。//IE能用,火狐不能用
为了解决这些兼容问题: 功能和上面一样
jQuery中提供了相应的函数( text函数、remove函数、replaceWith函数 )
常用浏览器:谷歌浏览器、火狐浏览器、苹果浏览器、欧朋浏览器等
2.1.3 jQuery公式
//选择器 事件
$(selector).action()
2.1.4 jQuery引入(顺序问题)
jQuery的函数库文件就是一个普通的JS文件,引入jQuery和引入JS文件的方式一样。
注意:一般是把这个jquery文件放在项目中而不是放在磁盘中,在引入。 因为写在磁盘里写绝对路径,将来拷贝项目路径就没用了没有这个文件,除非你连文件也复制。而放在项目中拷贝项目,连里面的文件也复制过来了,比较方便。这个文件笔记中有。
第二阶段----day06—day10------day06.07—jquery_example—js
大的是压缩之前的:学习或项目还没有发布的时候。 小的是压缩后的:项目发布,好处:用户访问页面加载小的js,减少流量的消耗。
解释: js是个目录,目录下的这个js文件jquery-1.8.3.js 。这个地方写的是相对路径 ./可以省略。也可以写绝对路径(写相对路径是因为把文件复制到了项目里。)
<!-- 在使用jQuery之前,必须先引入jQuery的函数库文件 -->
<script src="js/jquery-1.8.3.js"></script>
<script>
//jquery == $
jQuery(function(){
//在浏览器加载完整个网页后会执行
document.write("jquery引入成功了!");
});
</script>
在引入jQuery函数库文件时,如果文件引入路径错误,则会导致文件引入失败,如下图:
2.1.5 文档就绪事件函数(顺序问题)
<head>
<meta charset="UTF-8">
<!-- 在使用jQuery之前,必须先引入jQuery的函数库文件 -->
<script src="js/jquery-1.8.3.js"></script>
<script>
//1.获取id为demo的h1元素
var h1 = document.getElementById( "demo" );
//2.获取h1元素中的内容( innerHTML )
alert( h1.innerHTML );
</script>
</head>
<body>
<h1 id="demo">jQuery的引入示例...</h1>
</body>
问题描述:上面的代码在执行时,会报一个错误:
原因描述:在执行获取id为demo的元素时, h1元素还没有被浏览器加载到,所以获取不到h1元素。
浏览器重上到下顺序执行。
解决方式一:(需要挪代码)
将script标签移到body内部,也就是h1元素的后面
这样浏览器在加载时,会先加载h1元素,再执行获取h1元素的代码,由于在获取h1元素之前,h1元素已经被浏览器加载过了,所以后面再获取就能够获取到!
代码示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- 路径解释:先找html文件的当前目录,在一步一步找文件名加个/, 推荐压缩后的文件jquery.项目上线后,因为内存占用更少 -->
<script src="./jquery_example/js/jquery-1.8.3.js"> </script> <!-- 建议写在head里面 ,文件建议写在目录里,将来传项目时,文件也复制过去了-->
</head>
<body>
<h1 id="demo">大家好我是渣渣辉!</h1>
<script >
//案例:通过js获取id为demo的元素内容
//1.获取id为demo的元素
var oH1 = document.getElementById("demo");//但是这个地方没有获取h1元素,因为浏览器按顺序执行,下面的内容还没有执行.解决办法,把加载放在元素的后面
//2.获取demo元素的内容并输出到控制台,innerHTML获取标签的内容.
console.log(oH1.innerHTML);
</script> -->
</body>
</html>
解决方式二:(不需要挪代码)
通常用在获取函数上.
将获取元素的代码放在文档就绪事件函数中,文档就绪事件函数会在浏览器加载完所有的html元素后(也就是加载完最后一个html元素时)立即执行。
由于当前网页中的所有元素都被加载了,h1元素肯定也被加载了,此时再获取h1元素就一定能获取到。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="./jquery_example/js/jquery-1.8.3.js"></script>
<script >
/*或则通过文档就绪事件函数:浏览器加载完所有内容后会立即执行,这个方法是浏览器自动调用*/
//js提供的文档就绪事件函数 可以理解为固定写法
/* window.οnlοad= function(){
//案例:通过js获取id为demo的元素内容
//1.获取id为demo的元素
var oH1 = document.getElementById("demo");//但是这个地方没有获取h1元素,因为浏览器按顺序执行,下面的内容还没有执行.解决办法,把加载放在元素的后面
//2.获取demo元素的内容并输出到控制台
console.log(oH1.innerHTML);
} */
//jQuery提供的文档就绪事件函数,没有引入jquery就用js,引入后用哪个就行
//理解: $();相当与调用一个函数 里面写一个匿名函数 function(){}
语法: $(function(){
代码....
});
示例:
$(function(){
//案例:通过js获取id为demo的元素内容
//1.获取id为demo的元素
var oH1 = document.getElementById("demo");
//2.获取demo元素的内容并输出到控制台
console.log(oH1.innerHTML);
});
</script>
</head>
<body>
<h1 id="demo">大家好我是渣渣辉!</h1>
</body>
</html>
解决方式三:
将获取元素的代码放在一个自定义的函数中,并将该函数绑定在h1元素的点击事件上,当我们点击h1元素时会执行自定义的函数,函数执行时才获取h1元素,此时就能够获取到h1元素。
说明:点击事件执行顺序是,页面加载完成后才能点击按钮执行点击事件,仍然是先加载网页在执行js代码。3种方式最终实现的效果都是先加载网页在执行js代码。
<head>
<meta charset="UTF-8">
<!-- 在使用jQuery之前,必须先引入jQuery的函数库文件 -->
<script src="js/jquery-1.8.3.js"></script> //2个script一个写引入jquery,一个写代码
<script>
function fn1(){
//1.获取id为demo的h1元素
var h1 = document.getElementById( "demo" );
//2.获取h1元素中的内容( innerHTML )
alert( h1.innerHTML );
}
</script>
</head>
<body>
<h1 id="demo" onclick="fn1()">jQuery的引入示例...</h1>
</body>
总结:什么时候该使用文档就绪事件函数?
如果在获取元素时,获取元素的代码执行的时机,比元素本身加载的时间还要早,如果元素还没有加载就获取,必然是获取不到的。 可以将获取元素的代码放在文档就绪事件函数中,等浏览器加载完整个网页后,文档就绪事件函数才会执行,此时所有的元素都被加载了,再获取任何元素都能获取到!
jQuery提供的文档就绪事件函数(简写形式):
<script>
$(function(){ //没有方法名
//在浏览器加载完整个html网页后立即执行
});
</script>
其完整写法为:
<script>
$(document).ready(function(){
//在浏览器加载完整个html网页后立即执行
});
</script>
JS也为我们提供了文档就绪事件函数,其写法为:
<script>
window.onload = function(){
//在浏览器加载完整个html网页后立即执行
}
</script>
2.2 jQuery选择器(重点)
对应css选择器
2.2.1 基本选择器
jquery中的选择器:$() 里面写一个字符串的参数,单引号双引号都可以, 里面的写法类似js,返回值是一个jquery对象。
(1)元素名选择器
$("div") -- 选中所有的div元素
$("span") -- 选中所有的span元素
(2)class/类选择器
$(".s1") -- 选中所有class值为s1的元素(class值为s1的元素可能是任何元素)
$("span.s1") -- 选中所有class值为s1的span元素
(3)id选择器
$("#one") -- 选中id为one的元素
(4)多元素选择器
$("div,span,.s1,#one") -- 选中所有的div元素,以及所有的span元素,以及所有class值为s1的元素,以及id为one的元素
2.2.2 层级选择器
$("div span") -- 选中所有div内部的所有span元素
$("#one span") -- 选中id为one的元素内部的所有span元素
$("#two+span") -- 选中id为two的元素后面紧邻的span兄弟元素
$("#two").next("span") -- 选中id为two的元素后面紧邻的span兄弟元素
$("#two").prev("span") -- 选中id为two的元素前面紧邻的span兄弟元素
$("#two~span") -- 选中id为two的元素后面所有的span兄弟元素
$("#two").nextAll("span") -- 选中id为two的元素后面所有的span兄弟元素
$("#two").prevAll("span") -- 选中id为two的元素前面所有的span兄弟元素
$("#two").siblings("span") -- 选中id为two的元素前、后所有的span兄弟元素
2.2.3 基本过滤选择器
(1) 选中第一个div元素
$("div:first")
$("div:eq(0)")
$("div").eq(0)
(2) 选中最后一个div元素
$("div:last")
$("div:eq(-1)")
$("div").eq(-1)
(3) 选中第n+1个div元素(n从零开始)
$("div:eq(n)")
$("div").eq(n)
2.2.4 其它选择器
$(":input") -- 匹配所有的表单项元数(可以是input、select、option、textarea等元素。)
$(":checkbox") -- 匹配所有的复选框,等价于$("input[type='checkbox']")。
$(":checked") -- 可以匹配所有被选中的单选框或复选框,以及被选中的option选项。
$("input:checked") -- 表示匹配所有被选中的单选框或复选框。
2.2.5 选择器的练习:
<!DOCTYPE>
<html>
<head>
<meta charset="utf-8"/>
<title>选择器练习</title>
<style type="text/css">
body{ font-family:"微软雅黑"; font-size:20px;padding-bottom:300px;}
input{font-size:18px;margin-top:10px;}
div,span{width:300px;border:1px solid #000;padding-left:10px;background:#bed4ef;;}
span{display:block;}
body>div,body>span{height:100px;margin:10px 0px 0px 20px;display:inline-block;vertical-align:middle;}
#one{width:300px;height:185px;}
div>span,div>div{width:250px;height:35px;margin:10px;}
</style>
<!-- 引入jquery函数库文件 -->
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
/* 文档就绪事件函数(即在浏览器加载完最后一个html元素后立即执行) */
$(function() {
/* -------一、基本选择器练习------- */
/* 1、选中id为b1的按钮,为b1按钮绑定点击事件,点击b1按钮:改变所有 div 元素的背景色为 #FD5551 */
//解释: 这是动态绑定,为元素b1绑定点击事件,只要点击这个b1按钮就会执行click里面的方法function
$("#b1").click(function(){
//在选择器选中的元素被点击后,立即执行当前function,直接在标签上写死了,这是动态绑定 jquery的方式。
//选中所有的div元素,并给所有div设置背景颜色(css函数)
/* $("div").css("background","#FD5551"); //元素名没有# 点击事件就是点击后才会执行的语句
//设置别的css属性 有几个属性设置调几次css方法 第一种:
$("div").css("border","2px solid blue");
$("div").css("color","yellow"); */
//第二种一次性写完 {}里面写key--vey结构
$("div").css({
"background":"#FD5551",
"border":"2px solid blue",
"color":"yellow"
});
});
/* document.getElementById("b1").οnclick=function(){
这是js的方式 注意这个里面没有#
} */
/* 2、选中id为b2的按钮,为b2按钮绑定点击事件,点击b2按钮:改变 id 为 one 的元素的背景色为 #91BF2F */
$("#b2").click(function(){
$("#one").css("background","#91BF2F");
});
/* 3、选中id为b3的按钮,为b3按钮绑定点击事件,点击b3按钮:
改变 class 为 mini 的所有元素的背景色为 #EE82EE */
$("#b3").click(function(){
$(".mini").css("background","#EE82EE");
});
/* ---------二、层级选择器------- */
/* 4、选中id为b4的按钮,为b4按钮绑定点击事件,点击b4按钮:改变 div 内所有 span 的背景色为 #DC21D2 */
$("#b4").click(function(){
$("div span").css("background","#DC21D2"); //选中div 中的所有span元素
});
/* 5、选中id为b5的按钮,为b5按钮绑定点击事件,点击b5按钮:改变 id为two 元素的下一个相邻的 div元素 的背景色为 #2CADAA */
$("#b5").click(function(){
//选中id为two的元素的下一个相邻的div兄弟元素(必须为前后关系)
//$("#two+div").css("background","#2CADAA"); //选中div 中的所有span元素
//和它功能相似的还有一组函数
$("#two").next("div").css("background","#2CADAA");
//选中id为two的元素的上一个相邻的div兄弟元素
$("#two").prev("div").css("background","#2CADAA"); //previous:先前的
});
/* 6、选中id为b6的按钮,为b6按钮绑定点击事件,点击b6按钮:改变 id为two 元素的后面所有的div兄弟元素 的背景色为 #ECD822 */
$("#b6").click(function(){
//$("#two").nextAll(); //选中id为two的元素后面的所有兄弟元素
$("#two").nextAll("div").css("background","#ECD822");//选中id为two的元素后面的所有div兄弟元素
$("#two").prevAll("div").css("background","#ECD822");//选中id为two的元素前面的所有div兄弟元素
});
/* 7、选中id为b7的按钮,为b7按钮绑定点击事件,点击b7按钮:改变 id为two 元素的前、后所有的div兄弟元素 的背景色为 #EE0077 */
$("#b7").click(function(){
$("#two").siblings("div").css("background"," #EE0077"); //等价于,nextAll + prevAll
});
/* ---------三、基本过滤选择器------- */
/* 8、选中id为b8的按钮,为b8按钮绑定点击事件,点击b8按钮:改变第一个以及最后一个 div 元素的背景色为 #0074E8 */
$("#b8").click(function(){ //绑定点击事件
//选中所有div中的第一个div元素
// $("div").eq(0).css("background"," #0074E8");
//第一个元素特殊,还有2种方法
// $("div:first").css("background"," green");
//或则
$("div:eq(0)").css("background"," #0074E8");
//选中div中的最后一个div元素 3种写法 类似于一个时钟 -1永远代表最后一个 下标是从0开始。
// $("div:last").css("background"," red");
//$("div:eq(-1)").css("background"," #0074E8");
$("div").eq(-1).css("background"," #0074E8");
});
/* 9、选中id为b9的按钮,为b9按钮绑定点击事件,点击b9按钮:改变第4个 div 元素的背景色为 #D917C6 */
$("#b9").click(function(){
$("div:eq(3)").css("background"," #D917C6");
});
});
</script>
</head>
<body>
基本选择器→:
<!-- 按钮,id为b1 -->
<input type="button" id="b1" value="b1,改变所有 div 元素的背景色为 #FA8072" />
<!-- 按钮,id为b2 -->
<input type="button" id="b2" value="b2,改变 id 为 one 的元素的背景色为 #9ACD32"/>
<!-- 按钮,id为b3 -->
<input type="button" id="b3" value="b3,改变 class 为 mini 的所有元素的背景色为 #EE82EE"/>
<hr/>
层级选择器→:
<!-- 按钮,id为b4 -->
<input type="button" id="b4" value="b4,改变 div 内所有 span 的背景色为 #7CFC00"/>
<!-- 按钮,id为b5 -->
<input type="button" id="b5" value="b5,改变 id为two 元素的下一个相邻的 div元素 的背景色为 #48D1CC"/>
<!-- 按钮,id为b6 -->
<input type="button" id="b6" value="b6,改变 id为two 元素的后面所有的div兄弟元素 的背景色为 #D2FA7E"/>
<!-- 按钮,id为b7 -->
<input type="button" id="b7" value="b7,改变 id为two 元素的前、后所有的div兄弟元素 的背景色为 #FF69B4"/>
<hr/>
基本过滤选择器→:
<!-- 按钮,id为b8 -->
<input type="button" id="b8" value="b8,改变第一个/最后一个 div 元素的背景色为 #1E90FF"/>
<!-- 按钮,id为b9 -->
<input type="button" id="b9" value="b9,改变第4个 div 元素的背景色为 #EA3AD8"/>
<h3>点击按钮查看效果...</h3>
<div id="one">
这是一个div1
<div class="one01">这是一个div11</div>
<span class="mini">这是一个span,class为mini</span>
<span class="mini">这是一个span,class为mini</span>
</div>
<div>这是一个div2
<input type="button" value="按钮1"/>
<input type="button" value="按钮2"/>
</div>
<div id="two">这是一个div3,id是two
<span>这是一个span</span>
</div>
<div>这是一个div4</div>
<div>这是一个div5</div>
<span class="mini">这是一个span,class为mini</span>
<div>这是一个div6</div>
<span class="mini01">这是一个span,class为mini01</span>
<span class="mini">这是一个span,class为mini</span>
</body>
</html>
2.3 综合案例 (append方法)
2.3.1 创建表格元素
测试:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>创建表格</title>
<style type="text/css">
/* 为表格定义CSS样式 */
body{padding-left:15px;font-size:20px;}
table{ border:1px solid #0099FF; width:70%; border-collapse:collapse; }
table td{ border:#0099FF 1px solid; padding:10px 20px 3px 1px; }
input[type='text']{width:150px;height:20px;vertical-align:text-bottom;text-indent:5px;font-size:20px;}
input[type='button']{font-size:20px;}
</style>
<!-- 引入jquery函数库文件 -->
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
/** 练习1:创建单行单列的表格 */
function createTable1(){
//1.创建一个table元素,返回一个jQuery对象
//$tab前的$在这里只是为了标识这是一个jquery对象,没有别的含义
var $tab = $("<table></table>");
//2.创建一个tr元素
var $tr = $("<tr></tr>");
//3.创建一个td元素(为td设置内容)
var $td = $("<td>Hello,我是TD!</td>");
//4.将td元素添加到tr内部
$tr.append( $td );
//5.将tr元素添加到table内部
$tab.append( $tr )
//6.将table添加到body元素内部(body已存在,直接获取即可!)
$("body").append( $tab );
//$("body").append("<table><tr><td>Hello,我是TD~~~</td></tr></table>");
}
/** 练习2:创建单行6列的表格 */
/** 练习2:创建5行6列的表格 */
function createTable2(){
//1.创建一个table元素,返回一个jQuery对象
//$tab前的$在这里只是为了标识这是一个jquery对象,没有别的含义
var $tab = $("<table></table>");
for(var j=0;j<5;j++){ //控制行数,循环几次,就创建几行
//2.创建一个tr元素
var $tr = $("<tr></tr>");
for(var i=0;i<6;i++){ //控制列数,循环几次,就创建几列
//3.创建一个td元素(为td设置内容)
var $td = $("<td>Hello,我是TD!</td>");
//4.将td元素添加到tr内部
$tr.append( $td );
}
//5.将tr元素添加到table内部
$tab.append( $tr )
}
//6.将table添加到body元素内部(body已存在,直接获取即可!)
$("body").append( $tab );
}
/** 练习3:创建指定行和列的表格 */
function createTable3(){
//(js方式获取)获取用户输入的行数、和列数, value用于设置或获取表单项元素的value值 获取输入框里面的值,这个value跟input标签上有没有value属性没有关系,因为在浏览器内部它会给这个元素所表示的对象上面的value属性,他会把输入框的值赋值给这个对象上的value.
//var rows = document.getElementById("rows").value;
//var cols = document.getElementById("cols").value;
//(jquery方式获取)获取用户输入的行数、和列数,val()函数用于设置或获取表单项元素的value值
var rows = $("#rows").val();
var cols = $("#cols").val();
//1.创建一个table元素,返回一个jQuery对象
//$tab前的$在这里只是为了标识这是一个jquery对象,没有别的含义
var $tab = $("<table></table>");
for(var j=0;j<rows;j++){ //控制行数,循环几次,就创建几行
//2.创建一个tr元素
var $tr = $("<tr></tr>");
for(var i=0;i<cols;i++){ //控制列数,循环几次,就创建几列
//3.创建一个td元素(为td设置内容)
var $td = $("<td>Hello,我是TD!</td>");
//4.将td元素添加到tr内部
$tr.append( $td );
}
//5.将tr元素添加到table内部
$tab.append( $tr )
}
//6.将table添加到body元素内部(body已存在,直接获取即可!)
$("body").append( $tab );
}
</script>
</head>
<body>
<!-- 练习1:点击下列按钮创建单行单列表格 -->
<input type="button" value="创建单行单列表格" onclick="createTable1()" /><br/><br/>
<!-- 练习2:点击下列按钮创建5行6列表格 -->
<input type="button" value="创建表格(5行6列)" onclick="createTable2()" /><br/><br/>
<!-- 练习3:点击下列按钮创建指定行、指定列的表格 -->
<input type="button" value="创建表格(输入行数和列数)" onclick="createTable3()" /><br/>
行数:<input type="text" id="rows"/><br/>
列数:<input type="text" id="cols"/><br/><br/>
<!-- 将创建的表格添加到body内部(追加到最后) --><hr/>
</body>
</html>
2.3.2 仿QQ好友列表
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>仿QQ好友分组</title>
<style type="text/css">
table{border:#09f 1px solid;width:100px;border-collapse:collapse;margin:15px 10px;margin:20px 20px;}
table td{border:#06f 1px solid;background-color:#6f5f3e;text-align:center;padding:5px 0;}
table td div{background-color:#ff9;text-align:left;line-height:28px;padding-left:14px;text-indent:padding-left:20px;}
table td span{color:#fff;font-size:19px;width:100%;border:none;display:block;cursor:pointer;}
table td a:hover{color:#0c0}
</style>
<!--引入jquery的js库-->
<script src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
/** 通过jQuery实现仿QQ列表好友列表
thisobj(js对象)就是当前被点击的分组名(即被点击的span元素)
js对象不能调用jQuery的函数: js对象 --转化为-->jQuery对象 :
$(js对象) --返回-> jQuery对象
*/
function openDiv(thisobj){
/* 将其他三个分组关闭(隐藏其他三个分组内的div)
* 通过当前被点击的span,找到当前span的所有祖先元素中的tr元素,再通过
* tr找到其他三个tr兄弟元素,再通过这三个tr元素找内部的div元素 隐藏的过程用0.1秒来完成这个动作。 */
$(thisobj).parents("tr").siblings("tr").find("div").hide(100);
//获取被点击分组(被点击的span)相邻的div元素
$(thisobj).next("div").slideToggle(100); //100毫秒
}
</script>
</head>
<body>
<table>
<tr>
<td>
<span onclick="openDiv(this)">君王好友</span>
<div style="display:none">
秦始皇<br />
刘邦<br />
李世民<br />
康熙<br />
</div>
</td>
</tr>
<tr>
<td>
<span onclick="openDiv(this)">三国好友</span>
<div style="display:none">
刘备<br />
关羽<br />
张飞<br />
赵云<br />
</div>
</td>
</tr>
<tr>
<td>
<span onclick="openDiv(this)">美女好友</span>
<div style="display:none">
西施<br />
貂蝉<br />
杨贵妃<br />
王昭君<br />
</div>
</td>
</tr>
<tr>
<td>
<span onclick="openDiv(this)">IT好友</span>
<div style="display:none">
王海涛<br />
马云<br />
李开复<br />
俞敏洪<br />
</div>
</td>
</tr>
</table>
</body>
</html>
2.3.3 模拟员工信息管理系统
练习1:添加员工信息
<!DOCTYPE HTML>
<html>
<head>
<title>模拟员工信息管理系统</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style type="text/css">
body{font-family: "微软雅黑"}
h2, h4{ text-align: center; }
div#box1, div#box2 {text-align:center;}
hr{margin: 20px 0;}
table{margin: 0 auto;width:70%;text-align: center;border-collapse:collapse;}
td, th{padding: 7px; width:20%;}
th{background-color: #DCDCDC;}
input[type='text']{width:130px;}
</style>
<!--引入jquery的js库-->
<script src="js/jquery-1.8.3.js"></script>
<script type="text/javascript">
/* --- 添加一个新员工 --- */
function addEmp(){
//1.获取要添加的员工信息(id,name,email,salary)
var id = $("#box1 input[name='id']").val();
var name = $("#box1 input[name='name']").val();
var email = $("#box1 input[name='email']").val();
var salary = $("#box1 input[name='salary']").val();
//2.校验员工信息
//2.1.添加的员工信息不能为空, trim() 用于去除字符串前后的空格
if( id.trim()=="" || name.trim()=="" || email.trim()=="" || salary.trim()=="" ){
alert("添加的员工信息不能为空!");
return;//结束程序,停止添加操作!
}
//2.2.添加的员工id不能重复
/* 获取table中的所有的tr元素,遍历每一个tr元素,通过当前tr找到内部第二个td单元格的内容
(该内容就是当前这个员工的id),拿着用户输入的id和当前员工的id进行比较,如果相等,就停止
程序,如果不相等,就接着执行下一次循环。 其中的this表示每次遍历的tr元素*/
var flag = "id不存在"; //假设id是不存在的!
$("table tr").each(function(){
//通过当前tr找到内部第二个td单元格的内容(就是当前员工的id)
var tempId = $(this).find("td").eq(1).text();
//拿着用户输入的id和当前员工的id进行比较
if(id == tempId){
alert("添加的员工id已存在,添加失败!");
flag = "id已存在";
}
});
if( flag == "id已存在" ){
return;
}
//3.将员工信息作为一行(tr)添加到表格中
//创建一个tr元素
var $tr = $("<tr></tr>");
//创建5个td元素,为td元素添加内容,并将td添加到tr中
$tr.append("<td><input type='checkbox'/></td>");
$tr.append("<td>"+id+"</td>");
$tr.append("<td>"+name+"</td>");
$tr.append("<td>"+email+"</td>");
$tr.append("<td>"+salary+"</td>");
//将tr元素添加到table中
$("table").append( $tr );
}
/* --- 删除选中的员工 ---
$(":checked") -- 获取被选中的单选框、复选框、option选项
获取所有复选框: $("input[type='checkbox']")
获取所有被选中的复选框: $("input[type='checkbox']:checked")
:not(seletor) -- 表示选中除selector以外的其他元素
$("tr:not(.header)") -- 选中除了class为header以外的tr元素
*/
function delEmp(){
//1.获取被选中的复选框所在的tr元素,并将tr元素直接删除
//$("input[type='checkbox']:checked").parents("tr:not(.header)").remove();
$("input[type='checkbox']:checked").parent("td").parent("tr").remove();
}
/* 点击全选设置 员工所在的行全选或者全不选
实现思路: 点击全选复选框之后,如果全选复选框[选中了],则将所有复选框都选中
点击全选复选框,如果全选复选框[取消选中了],则将所有复选框都取消选中
prop()函数:
$ele.prop(attrName) -- 获取当前元素某一个属性的值,attrName就是属性名
$ele.prop(attrName,attrValue) -- 为当前元素的某一个属性赋值,
attrName是属性名,attrValue是属性值 */
function checkAll(){
//1.获取全选复选框在点击之后的状态值(选中了 or 取消选中了),即获取复选框checked属性的值
// checked属性的值: true表示复选框(包括单选框)被选中了,false表示没有被选中
var isCheck = $("#all").prop("checked");
//2.将全选复选框的状态值设置给所有的复选框
$("input[type='checkbox']").prop("checked", isCheck);
}
/* --- 修改指定id的员工 (自己完成)--- */
function updEmp(){
//1.获取修改后的员工信息(id,name,email,salary)
//2.校验数据
//2.1.修改后的员工信息不能为空
//2.2.如果输入的员工id存在,则执行修改,否则提示id不存在,修改失败!
}
</script>
</head>
<body>
<h2>添加新员工</h2>
<div id="box1">
<!-- $("#box1 input[name='id']") -->
ID:<input type="text" name="id"/>
姓名:<input type="text" name="name"/>
邮箱:<input type="text" name="email"/>
工资:<input type="text" name="salary"/>
<input type="button" onclick="addEmp()" id="add" value="添加新员工"/>
</div>
<hr/>
<table border="1">
<tr class="header">
<th>
<!-- 全选复选框,点击全选复选框,触发点击事件,执行checkAll函数-->
<input type="checkbox" onclick="checkAll()" id="all"/>
</th>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>工资</th>
</tr>
<tr>
<td>
<input type="checkbox"/>
</td>
<td>1</td>
<td>宋江</td>
<td>sj@163.com</td>
<td>12000</td>
</tr>
<tr>
<td>
<input type="checkbox"/>
</td>
<td>2</td>
<td>武松</td>
<td>ws@163.com</td>
<td>10500</td>
</tr>
<tr>
<td>
<input type="checkbox"/>
</td>
<td>3</td>
<td>孙二娘</td>
<td>sen@163.com</td>
<td>11000</td>
</tr>
</table>
<h4><a href="javascript:void(0)" onclick="delEmp()" id="del">删除选中员工</a></h2>
<hr/>
<div id="box2">
ID:<input type="text" name="id"/>
姓名:<input type="text" name="name"/>
邮箱:<input type="text" name="email"/>
工资:<input type="text" name="salary"/>
<input type="button" onclick="updEmp()" id="upd" value="根据ID修改员工信息"/>
</div>
</body>
</html>
2.4 jQuery总结
2.4.1 html元素操作 (创建,增,删,改)
注意:用jQuery的对象调用方法不能用js提供的方法。
1、创建元素
$("<div></div>") -- 创建一个div元素,返回的是一个jQuery对象,表示创建的div元素
$("<div>xxxx</div>") -- 创建一个包含内容的div元素,返回的是一个jQuery对象,表示创建的div元素
2、添加子元素
//创建好后再添加
$parent.append( $child ) -- 父元素调用方法添加子元素
//直接创建的同时添加元素
$("body").append( "<div>我是新来的...</div>" ); -- 往body元素内部追加一个div子元素
3、删除元素
remove():
$("div").remove() -- 删除所有的div元素,底层还是一个一个删.
对象.empty():
清空元素的所有后代元素,将对象的后代元素全部清空,但是保留当前对象以及其属性节点.
JS删除所有div元素:
//获取所有的div元素(返回的是所有div组成的数组)
var divArr = document.getElementsByTagName("div"); //div数组
//遍历div数组,依次删除每一个div元素
var len = divArr.length;
for(var i=0;i<len;i++){
//通过当前元素的父元素删除当前元素(始终删除第一个)
divArr[0].parentNode.removeChild( divArr[0] );
}
4、替换元素
$("div").replaceWith("<p>我是来替换的…</p>")
2.4.2 html元素的内容和值的操作
<div>
这是一个div11元素
<span>这是一个span元素</span>
这是一个div1111元素
</div>
<input type="text" name="user"/>
1、html()函数 (类似于js中的innerHTML属性)
– 用于获取或设置元素的内容,比如为div、span、p、h1~h6、table、tr、td、form等元素设置内容。即包裹在开始和结束标签里面的内容,如果通过选择器匹配了多个元素,只能获取第一个元素的内容或者如果通过选择器匹配了多个元素,则会给所有的元素设置内容。因为匹配返回值只有一个而设置没有返回值可以设置所有的内容即便有标签也可以(这个标签会被解析对应的格式)。
//可以设置标签+文本
$("div").html() -- 获取所有div中的第一个div的内容(假如有第一个div)
$("div").html("xxxx") -- 为所有div设置内容
2、text()函数 (类似于js中的innerText属性,innerText在部分浏览器中不兼容)
– 用于获取或设置元素的所有文本内容,即获取元素的所有内容(只获取文本,不获取标签,如果包含标签则会当成文本显示出来而不会解析成对应的样式。),如果通过选择器匹配了多个元素,可以将所有元素内部的文本都返回,text函数还可以为元素的设置文本内容(只能设置文本内容)。
只能设置文本内容
$("div").text() -- 获取所有div中的所有文本内容
$("div").text("xxxx") -- 为所有div设置文本内容
3、val()函数 (类似于js中的value属性)
– 获取或设置表单项元素的表单(input/select/option/textarea)
即:即输入框框里面的值。
//js为value属性。
$("input").val() -- 获取所有input元素中的第一个input元素的value值
$("input").val(值) -- 为所有的input元素设置value值,值写在括号里面。
2.4.3 元素属性和css属性操作
<input type="text" name="username" id="inp"/>
1、prop()函数 – 用于获取或设置元素的属性值
在jQuery1.6版本之后才有这个函数(这能获取固有属性:这个标签上自带的属性),1.6之前版本的jQuery可以使用attr()函数(这个属性是自定义属性或者固有属性)
$("input[type='checkbox']").prop("checked")
// 获取input复选框的选中状态, 返回true表示复选框为选中状态,返回false表示复选框为取消选中状态
$("input[type='checkbox']").prop("checked", true)
// 设置所匹配的复选框元素为选中状态
$("#inp").prop("name"); //获取id为inp元素的name属性值, 返回useranme
$("#inp").prop("name","user"); //为id为inp的元素设置name属性值, name属性值就会变成user
2、css()函数 – 用于获取或设置元素的css属性值
$("#div1").css("width") -- 获取id为div1元素的宽度
$("#div1").css("width","200px") -- 设置id为div1元素的宽度为200px
$("#div1").css({
"width" : "200px",
"height" : "150px",
"border" : "5px solid red",
"background" : "pink"
}); // 为id为div1的元素设置宽度为200px、高度为150px、边框以及背景颜色等样式
2.4.4 其它函数
遍历函数(each)
1、each() 函数
$(selector).each(function( index,element ){})
// each()函数可以遍历$(selector)选择器选中的所有元素(即每次从选择器选中的元素中获取一个元素,并执行function 函数)
// function中的index -- 表示遍历的元素的下标
// function中的element -- 表示当前正在遍历的元素(也可以通过this获取)
示例:
$("table tr").each(function(){
//从当前行中获取第二个单元格的内容(当前行的id值)
var tempId = $(this).find("td").eq(1).html();
//拿着用户输入的id 和 每一行中的id值进行比较
if( id == tempId ){
alert("添加失败,id已存在!");
flag = true; //id存在,更新flag的值,true表示已存在!
}
});
显示隐藏(show()/hide())
2、show()/hide() 函数
为什么要设置元素隐藏在网页上不显示,是为了以后更好的显示.
比如:百度上的登陆框,是点击之后才显示,不点击平常是隐藏的.
show() – 设置元素由隐藏变为显示
$("div").show() -- 设置所有的div元素为显示
等价于:
$("div").css("display", "block");
hide() – 设置元素由显示变为隐藏
$("div").hide() -- 设置所有的div元素为隐藏
等价于:
$("div").css("display", "none")
元素显示状态(toggle()/slideToggle())
3、toggle()/slideToggle()
toggle() – 切换元素的显示状态, 如果元素是显示的, 则切换为隐藏, 否则切换为显示
slidToggle() –切换元素的显示状态, 如果元素是显示的, 则切换为隐藏,否则切换为显示,切换为显示为下拉状态,隐藏为收缩状态。
区别:切换效果不一样,toggle()是由一个点慢慢变大缩小而slidToggle() 是由一条线慢慢变大缩小。
获取当前元素的父和子元素(parent()/parents()/find())
4.parent()/parents()/find()
parent()-- 获取当前元素的父元素,类似于js中的parentNode属性。
parents()-- 获取当前元素的所有祖先元素。(即当前元素的所有上级元素,一般是body标签里面的元素。)
find() --获取当前元素内部指定的后代元素。如:
$("div").find("span") -- 获取所有div元素内部的span元素。
或者
$("div span") -- 获取所有div元素内部的span元素。
2.4.5 鼠标事件
//onClick:鼠标点击事件,多用在某个对象控制的范围内的鼠标点击
//onblur:当前元素失去焦点时触发的事件 [鼠标与键盘的触发均可]
//onfocus:当某个元素获得焦点时触发的事件
//.......
<input type="text" name="name" id="nameId" onblur="doCheck()" onfocus="doClear()" onClick="onClick()">
2.5 扩展内容有
2.5.1 为元素绑定点击事件
以点击事件为例,为元素绑定点击事件的方式为:
方式1(js版): 这种是写死在按钮里面
<script>
function fn(){
alert("input按钮被点击了...");
}
</script>
<body>
<input onclick="fn()" type="button" value="点我~!" />
</body>
方式2(js版): 动态绑定js版
<script>
window.onload = function(){
//获取id为btn的元素
var btn = document.getElementById("btn");
btn.onclick = function(){
alert("input按钮被点击了...");
}
//以上是分开写还可以直接写 注意js这种写法没有#,有#是jquery的写法
document.getElementById("btn").onclick=function(){
alert("input按钮点击了..."); //alert是个方法,里面传的是字符串(单引双引号都行),点击按钮执行点击事件函数会在浏览器页面出现一个警告框,框中的内容就是这个传的字符串
}
}
</script>
<body>
<input id="btn" type="button" value="点我~!" />
</body>
方式3(jQuery版):动态绑定jquery版
<script>
$(function(){
//当点击btn按钮时,触发点击事件执行其中的函数
$("#btn").click( function(){
alert("input按钮被点击了...");
});
});
</script>
<body>
<input id="btn" type="button" value="点我~!" />
</body>
2.5.2 js对象和jQuery对象的互相转换
即: 用$() 把js对象包起来 里面没有双引号
jquery对象是一个集合. js对象只能表示一个元素.
通过JS的方式获取元素,返回的是JS对象,JS对象只能调用JS的属性或函数
通过jQuery选择器获取元素,返回的是jQuery对象(结构像一个集合),jQuery对象只能调用jQuery的属性或函数。
如果现有JS对象,但我们需要调用jQuery的属性或函数,可以将JS对象转成jQuery对象;
如果现有jQuery对象,但我们需要调用JS的属性或函数,可以将jQuery对象转成JS对象;
3 tomcat、HTTP
3.1 服务器概述
3.1.1 什么是服务器?
服务器:分为服务器硬件 和 服务器软件。在硬件服务器(计算机)上安装了服务器软件,才可以对外提供服务。
比如:让其他的计算机来访问当前服务器,为其他的计算机提供服务。
(1) 服务器硬件:是指在互联网上具有独立IP地址的计算机,比如我们自己用的计算机也可以作为服务器使用。
(2) 服务器软件:就是一个计算机程序,比如MySQL服务器软件,tomcat服务器软件。服务器软件分为很多类型,比如:ftp服务器,数据库服务器,web服务器软件,邮件服务器等。
3.1.2 什么是Web服务器?
(1) web服务器是指驻留在互联网上的某种类型的计算机程序。当浏览器访问服务器,请求服务器上的文件时,服务器将会处理该请求,并将请求的文件响应给浏览器,并会附带一些信息告诉浏览器如何查看该文件(即文件的类型),即专门接受客户端的请求并根据请求作出回应。
(2) web服务器是可以向 “发出请求的浏览器提供文档” 的程序,比如在访问百度时,其实就是在访问百度的服务器。
解释:
服务端,是为客户端服务的。服务的内容诸如向客户端提供资源,保存客户端数据。是实现游戏特色化的重要途径,也是最直接可以通过游戏表现出来的技术。
客户端,或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务端互相配合运行。
一般来说,客户端就是我们使用的电脑(包括我们使用的浏览器IE,Firefox);服务器端就是存放网页与数据库数据的服务器。
如果说你玩《魔兽世界》,电脑上装的“魔兽程序”就是客户端程序,你连接的“服务器”就是是服务器端程序。
请求,响应:比如2个人之间的对话,我给你说一句话,另一个人在回复。
tomcat就是一个web服务器软件,是由apache组织提供的一款服务器软件,特点:小巧灵活,免费开源,简单易用。
3.2 tomcat下载、安装、启动、配置
3.2.1 下载tomcat服务器
下载地址:http://tomcat.apache.org/
tomcat有很多版本,有解压版 和 安装版,还分windows (还分为32位和64位版)和linux版,根据自己的需求,选择对应的版本下载。
第一个:windows系统的解压版
第二个:linux或苹果系统
第三个,第四个:直接下第一个就行
第五个:windows的安装版
tomcat服务器运行需要jdk的支持(tomcat是由java语言开发的),版本对应为:
tomcat5 需要jdk4以上支持
tomcat6 需要jdk5以上支持
tomcat7 需要jdk6以上支持
tomcat8 需要jdk7以上支持
3.2.2 安装、启动tomcat服务器
1、安装tomcat服务器
绿色版解压之后就可以使用(原则:安装的路径中不要包含中文和空格)
解压后还需要配置JAVA_HOME环境变量,该变量指向jdk的根目录,指定tomcat启动时使用哪一个位置的jdk。
2、启动tomcat服务器
如何配置JAVA_HOME环境变量:
变量名: JAVA_HOME
变量值: C:\Program Files\Java\jdk1.8.0_45
注意:变量值指向JDK的根目录(不是bin目录),变量值的后面也不要加分号;
2、启动tomcat服务器
启动、关闭tomcat服务器:在网页上输入,localhost:8080回车出现一只猫说明启动成功,
如果显示无法访问此网站,可能是服务器没开或者端口写错了。
localhost:8080 指访问当前电脑上监听8080的服务器,8080就是Tomcat.(因为一台主机上可能有很多服务器,不同的服务器端口号不同)
通过 [tomcat根目录]/bin/startup.bat
可以启动tomcat服务器;如果闪跳一下说明java_Home环境变量没有配置,或配置没有生效。
通过 [tomcat根目录]/bin/shutdown.bat
可以关闭tomcat服务器;
访问测试服务器:
在tomcat服务器启动后,服务器会默认监听8080端口,可以通过如下地址访问tomcat服务器的主页: (localhost是主机名:相当于银行的地址,端口号:8080,相当于办理业务的窗口号.
localhost: 本机的端口名
http://localhost:8080 这个地址就相当于访问到了本机的tomact服务器,的webapps目录.
3.2.3 修改tomcat默认端口
tomcat服务器在启动时,默认监听的端口是8080,这意味着,我们在访问tomcat服务器时,需要在主机名(localhost)或者IP地址(127.0.0.1)等后面加上端口。这样非常不方便。
可以将8080
端口改为80
端口,因为80端口非常特殊,可以省略不写(只有80端口可以省略,其他端口在访问时必须得加上)
修改方法:找到 [tomcat安装目录]/conf/server.xml 文件并打开该文件,将文件中的 69 行的 <Connector>
标签上的 port 属性的值改为 80即可。
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
改完后,保存文件,重新启动服务器(只有在服务器启动时,才会重新加载server.xml文件)再次启动的服务器就会监听新的端口。
扩展问题:端口占用问题:
在启动tomcat服务器时,可能会遇到端口占用问题,如下图:
原因分析: 因为一个端口只能被一个进程(程序)所占用
情况一:可能是之前的tomcat服务器没有完全关闭,仍然在占用8080(或80)端口,导致服务器再次启动时,启动失败。(就是开第二次服务器之前的服务器没有关闭端口,还在占用)
点 x 关闭窗口可能会没有完全关闭(大部分都是关的掉),一个服务器只能占用一个端口。
解决方式:运行shutdown.bat文件,将tomcat按照正常流程再关闭一次即可。再次启动服务器,如果成功,则说明问题已解决,否则看情况二。
情况二:可能是其他程序占用了8080(或80)端口,导致服务器启动失败。(比较少)
解决方式:打开一个cmd窗口,通过 netstat -ano 命令查看当前系统中活动的进程,找到8080(或80)端口对应的进程编号(PID),根据进程编号将进程结束即可!
netstat: 命令,网络.
netstat -ano
协议 本地地址 外部地址 状态 PID
TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 6520
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 448
...
//6520正在占用8080端口,然后在通过下面的命令释放端口。
taskkill /f /pid 6520
3.3 tomcat目录结构
tomcat目录结构介绍
tomcat服务器安装根目录下有很多子目录,这些目录的作用是:
bin:用于存放tomcat服务器中批处理文件(即:用于输入命令的文件)的目录(xx.bat/xx.sh)
conf:用于存放tomcat服务器中的配置文件的目录(其中server.xml文件是tomcat服务器中非常重要的一个文件。)这个server文件相当于汽车的发动机
lib:用于存放tomcat服务器运行时所依赖的jar包。
logs:用于存放tomcat服务器运行时产生的日志文件(启动tomcat服务器时会打印很多日志信息,这些日志信息还会以文件形式保存到logs目录下)
temp:用于存放tomcat服务器产生的临时文件,tomcat会自己清理,可以忽略该目录
webapps:是localhost【虚拟主机】默认管理的目录,将开发好的【web应用】程序放在webapps目录下,就可以通过浏览器访问localhost主机中的Web资源文件了。
可以简单的理解为:webapps目录就是web资源(html、css、js、图片、jsp等)的存放目录,将web资源文件放在该目录下,就可以通过浏览器来访问。
在eclipse中的右键--open with---web Brower是在本地打开,别人不能访问。而放在这个目录下就相当于把文件发布到服务器中,而别人浏览器访问服务器,服务器返回一个文件进而进行访问。
work:用于存放tomcat服务器产生的工作文件(JSP翻译后的Servlet文件会放在work目录下;session对象序列化后产生的文件也会放在work目录下;)
3.4 虚拟主机和Web应用
总结: 站点:网站
(1)虚拟主机就是tomcat服务器中配置的一个站点(tomact服务器可以配置多个站点,浏览器访问时不能区分比如,百度,新浪是不是在同一个服务器上运行的,他也不关心,他关心的是能不能访问时返回比如一个百度页面),在tomcat服务器中默认提供了一个localhost虚拟主机,这个主机的发布目录是webapps目录:
这个文件在: 148行
这样意味着,将Web应用放在webapps目录下,就表示发布到了localhost虚拟主机中。
(2)Web应用就是一个存放了很多Web资源(html、css、js、jsp、servlet、图片等)的目录,将Web应用发布到虚拟主机中,就可以通过浏览器来访问Web应用中的这些资源文件了。
注意:webapps不能直接存放资源,而是存放在一个目录下即web应用,在把目录在webapps下。
如:
解释: localhost:8080 ----先访问tomoact服务器 (因为把资源发布到了服务器上所以先访问服务器.)
abc-----在访问tomoact服务器下的web应用.
regist.html----访问web资源应用下的具体web资源文件.
3.5 localhost和127.010.1:
在计算机网络中,localhost(意为“本地主机”,指“这台计算机”)是给回路网络接口(loopback)的一个标准主机名,相对应的IP地址为127.0.0.1(IPv4)和[::1](IPv6)。
localhost 指你所在的计算机本身。
在windows系统它成了127.0.0.1的别名 ,在Unix系统下,查看网卡配置会发现作为本地回环的方式,一定程度上使用localhost比127.0.0.1要快一些。
在Hosts文件中,localhost指向的IP是127.0.0.1这个关系是可以修改的。
3.6 web应用
3.6.1 web应用的目录结构
news(目录,web应用) 这个目录下分为2类。
|-- 其它目录, 放在news根目录或者其他目录中的资源文件,浏览器可以直接访问
|-- WEB-INF目录, 放在这个目录下的资源文件是受保护的,浏览器不能直接访问(不是不能访问,是不能直接访问) ,这个目录下一般又包含2个目录,和一个文件。 (这个文件比较复杂,在课前资料有,通过eclipse创建时会自动创建)
|-- classes目录, 用于存放编译后的class文件
|-- lib目录, 用于存放web应用所依赖的jar包
|-- web.xml文件, 用于存放和web应用相关的一些配置(配置Servlet、配置主页、配置session的超时时间等) 这个文件使用eclipse建一个web项目时,会自动生成.
其中news就是一个目录, 同时也是一个web应用程序, 其中可以包含很多的资源文件。
3.6.2 部署web应用到虚拟主机中
直接将Web应用的目录拷贝到虚拟主机所管理的目录下,就发布到了虚拟主机中
例如:将news目录拷贝webapps目录下,由于webapps目录是localhost主机默认管理的目录,所以就相当于将news应用发布到 了localhost主机中。(即:localhost:8080相当于写了webapps目录) 把文件发布到服务器上,服务器会随时检查.在控制台可以随时看到变化.(发送到服务器,解除发布)
目录结构: webapps目录—是tomact服务器下的目录,并且这个目录是localhost虚拟主机默认管理的目录.
web应用是webapp下的目录,里面管理的是web资源文件.
主机名----web应用----web资源文件.
通过如下路径规则就可以访问localhost主机下的news应用下的资源文件:
http://localhost:端口/news/xxx
3.7扩展内容(了解)
哔哩哔哩视频链接:https://www.bilibili.com/video/BV1Hg4y1B7dr
访问tomcat服务器主页:http://localhost
访问news/hello.html:http://localhost/news/hello.html
能否将访问 news/hello.html 的路径缩短一些(比如只通过主机名就可以访问news/hello.html这个网页)
3.7.1 配置WEB应用的主页
如果没有将 hello.html 配置为当前Web应用的主页,在访问 hello.html 时的路径为:
http://localhost/news/hello.html
如果将 hello.html 配置为当前Web应用的主页,再次访问 hello.html 时的路径为:
http://localhost/news
在上的路径中,/hello.html 这个路径可以加,也可以省略。
注意:配置完成后可以写也可以不写.
将 hello.html 配置为当前应用的主页,方式为:找到 [当前Web应用]/WEB-INF/web.xml文件并打开,在web.xml文件的根标签内部添加如下配置:
<?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_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>/hello.html</welcome-file>
<welcome-file>/hello1.html</welcome-file>
<welcome-file>/hello2.html</welcome-file>
</welcome-file-list>
</web-app>
配置完后,需要重启服务器,配置才会生效。
3.7.2 配置缺省的(默认的)WEB应用
上面已经将news/hello.html配置为news应用的主页,访问hello.html时路径为:http://localhost/news/
如果不将 news 应用配置为默认的Web应用,在访问 news 下的 hello.html(主页)时的访问路径为:
http://localhost/news/
如果将 news 应用配置为缺省的(默认的)Web应用,在访问 hello.html(主页)时的路径就变成了:
注意:配置为缺省的 这个应用名就不能再写了. 而配置的web应用主页配置完成后,也可以写也可以不写.
http://localhost/
如何将 news 配置为缺省的(默认的)Web应用(缺省Web应用只能有一个)?:
将Web应用的名字改为一个大写的ROOT,当前Web应用就是一个缺省的Web应用,再访问这个Web应用下的资源文件时,访问的路径中就可以不用写Web应用的名称了。
3.7.3 打war包
war包和jar包都是java程序中的一种压缩包格式.
如果开发一个Java基础工程,可以将其中编译后的class文件和相关的配置文件打成一个jar包。
如果开发一个web工程,可以将一个web工程中的所有文件和目录打成一个war包,这样做的好处有:
(1) 将web应用打成一个war包,传输起来更加方便,而且文件体积会变小。
(2) 将war包发布到服务器中,服务器能识别war包格式,会自动将war包解压发布!
打war包的方法是:
进入到web应用的目录下,将Web应用目录下的所有子目录和文件全部选中,右键压缩成一个 xxx.zip 包,再把 xxx.zip 改为 xxx.war即可!! 之后把这个war包放在webapps目录下.
需要注意的是,如果有以下问题,可能会导致war不会自动解压:
(1) 在将Web应用打成一个压缩包时,没有打成一个 xxx.zip,而是使用 rar格式或者其他格式,会导致自动解压失败!
(2) 打成的war包的名字 和 已发布的web应用的名字不能冲突,会导致自动解压失败!
(3) war包中包含的目录名和文件名是中文的,也会导致自动解压失败!
3.8 HTTP协议概述
3.8.1 什么是HTTP协议?
HTTP协议是用于规定浏览器和服务器之间的通信方式/规则
主要规定了浏览器给服务器发送的请求信息的格式
以及规定了服务器给浏览器发送响应信息的格式 (比如2个不同国家的人说话语言不同, 加一个规则用同种语言进行交流, 这就是HTTP协议.)
HTTP协议在工作时所遵循的基本原则:
(1)一次请求,只对应一次响应 10次请求,10次响应
(2)请求只能由浏览器发起,服务器只能被动的等待请求,根据请求作出回应。
3.9 HTTP协议详解
IE浏览器的插件:HttpWatch,可以监听浏览器和服务器通信的内容。(比如 :公安局可以监听2个人之间的对话)
现在的浏览器,比如谷歌或火狐会自带这个功能,不需要在装这个插件。
在浏览器上的网页 F12 打开开发者工具—Network(网络)—在地址栏输入地址访问后(确定键)-----可以看到请求和相应的内容.
点击这个请求响应文件 但是这个格式比较乱,请求和响应混合在一起了看着不方便
需要安装一个插件—收费,没有发到笔记中.
3.9.1 HTTP请求
1、请求行
GET /news/hello.html HTTP/1.1
(1)GET:表示请求方式,在HTTP协议中一共定义了7种提交方式,但是我们只用GET和POST。
(2)/news/hello.html:请求资源路径,表示浏览器请求的是哪一个Web应用以及哪一个web资源文件。
(3)HTTP/1.1:请求所遵循的协议和版本。
2、若干请求头 (请求报头)
请求头都是Key-Value结构,例如:
Host:localhost -- 通知服务器,浏览器要请求的是哪一台虚拟主机。
Accept:text/html, appliaction/xhtml+xml,... -- 通知服务器,浏览器能接收的响应数据类型。 比如:html格式的网页. 浏览器就是一个html的网页.
...
(之间有一个空白行,用于分隔请求头和请求实体)
3、请求实体内容
如果请求方式为 GET 提交,请求实体是没有内容的!
如果请求方式为 POST 提交,并且请求中携带了数据,请求实体中才会有内容!
3.9.2 HTTP响应
content type 表示响应的内容类型 content:内容
响应实体的内容: 出现乱码是因为插件问题, 响应时已经解析好了,其实没有乱码问题.
浏览器发送的请求是html文件,服务器相应的实体内容就是一个网页.
1、状态/响应行
HTTP/1.1 200 OK ok8.5开始可以省略,200对应的是Ok,其他的不一定是
(1)HTTP/1.1:表示响应所遵循的协议和版本
(2)200:状态码,三位的数字,表示服务器对请求处理的结果。
200: 表示请求处理成功
302: 表示请求重定向(即需要再进一步请求才可以获取到相应的资源) 比如向一个人借钱,这个人没有,告诉你另一个人要,你向另一个人去借钱。
304/307: 表示通知浏览器使用缓存的文件
404: 表示浏览器请求的资源不存在(浏览器的问题, 请求路径错误)
500: 表示服务器在处理请求的过程中抛出了异常。 (服务器只是一个运行的环境,真正处理请求的是servlet程序,而servlet就是一个java程序,java程序肯定会抛出异常)
(3)OK:描述短语(可以忽略),也表示服务器对请求处理的结果,和状态码表示的结果一致。
200说明请求已经成功了,ok有说明
200:OK
404:Not Found
500: Internal Server Error
...
2、若干响应头:也是key-value格式
Content-Type: 表示服务器响应的数据类型,text/html, image/*...
Content-Length: 表示服务器响应数据的长度, 例如: 384 /字节
Set-Cookie: 和cookie技术相关的一个头, 后面会提到。
...
3、响应实体内容
响应实体就是浏览器所请求文件的内容。例如:浏览器向服务器请求一个hello.html文件,服务器会找到hello.html文件,将文件的内容作为响应实体发送给浏览器。
3.9.3 内容补充
1、问题1:请求方式什么时候是GET提交?什么时候是POST提交?
只有当使用表单(form),并且在表单上明确的通过method指定提交方式为POST时,请求方式才是POST提交,其他方式都是GET提交(AJAX除外,它可以随意指定)
思考:判断以下请求方式是GET还是POST?
(1)<form action="#"></form> -- GET提交
(2)<form action="#" method="GET"></form> -- GET提交
(3)<form action="#" method="POST"></form> -- POST提交
(4)点击超链接访问服务器,例如:
<a href="http://www.baidu.com">百度一下</a> -- GET提交
(5)直接在浏览器的地址栏中书写URL地址访问服务器 -- GET提交
2、问题2:GET提交和POST提交有什么区别?
主要区别体现在请求参数传输过程的不相同
GET提交:
URL地址: 在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位符),它是WWW的统一资源定位标志,就是指网络地址。 可认为由4部分组成:协议、主机、端口、路径
比如:http://localhost:8080/news/html http后面跟的是// ,路径资源是/分割.
其中网址的协议信息,网页常用两种:http:// 和 https:// 在网页浏览过程中显示这部分内容没有意义,因为 Chrome 会为 https 协议的网址提供更醒目的状态标识(位于地址栏左端)。
而在复制地址时,Chrome 会在文本前自动添补协议信息。
请求参数:比如 提交表单的用户名,密码.
- 将数据通过问号拼接在地址栏URL地址的后面,相对非常不安全。
- 将数据拼接在地址栏URL地址的后面,数据量是有限制的,通常不能超过1KB或者4KB。
POST提交:
- POST提交是通过请求实体将数据提交给服务器,不会显示在地址栏上,因此相对更加安全。
- POST提交通过请求实体提交数据,数据量理论上是没有限制的。
3、总结:
大部分我们用的还是get 提交,post提交还需要写表单等太过麻烦,我们一般也不需要提交数据.
- 如果只是单纯做一个跳转(如,从百度跳转到淘宝),请求中没有数据,尽量使用GET提交。
- 如果在请求中有数据,但数据量不大,并且数据没有隐私性,也尽量使用GET提交。
- 如果在请求中有数据,数据量比较大或者数据较为隐私,此时推荐使用POST提交。
3.10 将Tomcat整合到Eclipse中
整合的目的:将Tomcat服务器整合到Eclipse工具中,可以通过Eclipse启动、关闭tomcat服务器,更重要的是,可以非常方便的将在Eclipse中创建的Web项目发布到Tomcat服务器中运行。
后面框架springboot会有内嵌的Tmocat,这里不用纠结.
哔哩哔哩视频链接:https://www.bilibili.com/video/BV1wz411z73V
3.10.1 方式一:在window偏好设置中配置Tomcat
1、点击Window --> Preferences(偏好设置):
2、在偏好设置窗口中点击 Server --> Runtime Environments --> add:
server (服务器) runtime:运行时间
3、在弹出的窗口中选择 --> Apache --> Apache Tomcat v8.5,需要注意的是,这里得根据自己安装的tomcat版本进行选择,比如我安装是8.5版本的tomcat,所以这里选择Apache Tomcat v8.5。
如果没有没有8.5说明eclipse的版本低,可以升级eclipse版本或者降低Tomact版本。
4、在下面的窗口中配置tomcat服务器的安装根目录,可以直接把路径复制到第二个输入框中;也可以点击后面的 Browse按钮在文件管理器中选择tomcat服务器安装根目录。
最后点击finish即可完成将Tomcat整合到Eclipse中的配置。
Apply and close:应用并关闭 ( apply申请,应用)
3.10.2 方式二:在创建Web项目时配置Tomcat
1、如果在创建Web项目时,Target runtime选项中没有配置可选的服务器,可以点击右面的选项进行配置
点击后进入下一步操作。
2、在弹出的窗口中选择 --> Apache --> Apache Tomcat v8.5,需要注意的是,这里得根据自己安装的tomcat版本进行选择,比如我安装是8.5版本的tomcat,所以这里选择Apache Tomcat v8.5。
3、在下面的窗口中配置tomcat服务器的安装根目录,可以直接把路径复制到第二个输入框中;也可以点击后面的 Browse按钮在文件管理器中选择tomcat服务器安装根目录。
最后点击finish即可完成将Tomcat整合到Eclipse中的配置。
4、上一步完成后,回到Web项目创建的视图窗口,再查看"Target runtime"选项,如下:
3.10.3 将整合到Eclipse中的tomcat从Eclipse中删除
如果要将整合到Eclipse中的tomcat从Eclipse删除:点击Windows --> Preferences --> Server --> Runtime Environments,选中要删除的服务器,点击右侧的删除按钮即可删除,最后点击Apply and Close保存设置即可! edit:编辑, 可以更改服务器的位置。
3.10.4 在Eclipse中创建Server及移除Server
上面讲解了如何将Tomcat整合到Eclipse中,整合之后,需要在Eclipse中创建一个Server(服务器)才可以进行启动tomcat、关闭tomcat等操作。
1、Eclipse中找到Servers窗口:
2、如果没有可以到Window --> Show View --> Other中搜索"servers",如下图:
3、在Server窗口中点击“No servers are available…”链接:
4、在弹出的窗口中,保持默认配置,直接点击完成
如果弹出的窗口中默认的服务器不是tomcat,则说明在此之前没有将Tomcat整合到Eclipse中。
5、在上一步点完成后,Eclipses左侧会多出一个Servers项目,Servers窗口中会出现创建的Server(比如:Tmoact v8.5 Server at localhost [Stopped,Republish]),也就是tomcat服务器。
server服务器和servers项目是配套使用的,这个项目放的是服务器的配置文件.
注意:①处的Servers项目不能关闭(close),更不能删除(delete)
如果将来服务器出错的话,想从新创建一个服务器. 2个都要删除.
选中服务器-----右键delete. servers----右键delete----勾选框表示从硬盘上彻底删除
6、在创建完Server后,双击tomcat,可以修改Tomcat服务器配置
(1)将Server Locations中的选项切换为第二个选项
(2)将Deploy Path右侧的输入框中的内容改为webapps。ctrl+s保存配置即可
以上配置是为了保证在Eclipse中发布Web应用到tomcat服务器中时,可以将项目发布到tomcat服务器的webapps目录下。
如果不配置,会导致tomcat服务器中webapps下的Web应用无法访问。因为整合之后通过eclipse启动服务器它会更改webapps的发布目录,这个发布目录就没用了.
7、如果要移除添加的Server,需要同时删除①处的Servers项目(右键delete,要彻底从硬盘上删除),以及删除②处的tomcat服务器(右键delete)
3.10.5 tomcat右键选项介绍
a) Start:用于启动tomcat服务器,如果已启动,则显示 ReStart,作用是重启服务器
b) Stop:用于停止服务器 或者点击红色按钮
c) Add and Remove:将Web应用部署到tomcat服务器中,或者移除服务器中部署的Web应用
也可以 在发布到服务器的文件上右键一个一个的 remove移除.( 移除发布到文件上的文件,一般c ,d配合使用.)
d) Clean:作用是将发布到Eclipse自己的webapps目录中的项目删除再重新部署
e) Clean Tomcat Work Directory:作用是将在tomcat运行过程中存入work目录的文件删除
3.10.6 tomcat启动失败常见原因
问题1:tomcat服务器启动失败-1
如果在启动服务器时,服务器启动失败,并弹出窗口显示如下异常信息:
根据上面的描述信息,可以看出是8005、8080、8009端口被同时占用了,此时只有一种可能,就是之前已经启动了tomcat或者之前开启的tomcat没有完全关闭导致的。
解决方式:到tomcat安装目录找到bin目录中的shutdown.bat文件,双击运行将服务器关闭,再到Eclipse中启动服务器即可!
问题2:tomcat服务器启动失败-2
如果在启动服务器时,服务器启动失败,并弹出窗口显示如下异常信息:
解决方法:
(1) 可以先将服务器中所有的Web应用移除(在服务器上右键,Add and Remove–>Remove All–>Finish)
(2) 再分别执行服务器右键选项中的clean和Clean Tomcat Work Directory
(3)再次启动服务器,如果启动没有报错,则说明tomcat服务器本身没有问题,再将要运行的项目发布到tomcat中,再次启动服务器,观察是否有错误。如果有则说明是项目本身的问题。
(4)如果移除了所有的Web应用,启动tomcat服务器报错,则说明tomcat本身就有问题,可以将tomcat服务器重新配置一次到Eclipse中(将tomcat和Server项目删除,再点击链接重新创建Server)
4 Servlet
4.1 Servlet概述
4.1.1 什么是Servlet?
servlet(小服务程序)
Servlet是由SUN公司提供的一门动态Web资源开发技术 (web: 网络)
静态Web资源:不同的人,在不同的条件下访问后看到的是相同的效果,
这样的资源叫做静态Web资源(html、css、js等 静态资源的开发技术)
( 而不是根据是否有动画效果)
动态Web资源:在不同的访问条件下看到的是不同的效果,这样的资源叫做动态Web资源
(Servlet、jsp、.NET、PHP等 动态资源的开发技术) 比如访问不同人的购物车 念dao NET
Servlet本质上是一段Java程序,和之前的Java程序不同的是Servlet程序无法独立运行,没有main函数需要将Servlet程序放在服务器中(比如tomcat服务器),由服务器调用才可以执行。
Servlet: 服务器端的Java程序.
Servlet是运行在服务器端的Java程序,其作用是什么?
其作用是对服务器接收过来的请求进行处理(也就是服务器接收请求,servlet处理请求)
Servlet的生命周期:
1、初始化阶段,Servlet容器会创建一个Servlet实例并调用【init()】方法;
2、处理客户端请求阶段,每收到一个客户端请求,服务器就会产生一个新的线程去处理;
3、终止阶段,调用destroy方法终止。
jsp:能写一段java代码的HTML 右边是个数据库
4.2 开发Servlet程序
4.2.1 开发Servlet程序的步骤
第一步: 写一个类,实现一个Servlet接口或者继承Servlet接口的子类(GenericServlet/HttpServlet),并实现其中的方法
Servlet接口
|-- GenericServlet类(抽象类)
|-- HttpServlet类 一般用的这个
第二步: 在web应用的web.xml文件中配置Servlet程序对外访问的路径。
因为servlet编译后的程序放在class目录下,而class目录是放在web-inf目录,而web-INF目录不能直接访问,需要在web.xml文件进行配置路径。 默认是/+类名.
Eclipse在创建一个Servlet时,会在web.xml文件中生成Servlet配置,所以不需要我们手动配置。
4.2.2 使用Eclipse创建Web项目
以上是Web项目在工程视图(Project)和包视图(package)下结构,推荐使用包视图!
工程视图比较混乱,上面的也不用,推荐包视图,结构更清晰。
wibdow–show view—other—package Explorer
1、创建一个Web工程: 在左侧窗口中, 点击鼠标右键 —> New —>
Dynamic Web Project。 动态项目中可以有静态资源也可以有动态资源
即: 静态项目可以开发静态资源,动态项既可以开发静态也可以开发动态.
2、接着会弹出如下窗口:
注意:
双击打开web,xml文件 点击source进入编辑状态,有可能会误报错误。j
解决:选中web.xml文件–右键Validate(校验)
(1) 3.0版本不会创建web.xml文件,
并且创建Servlet时也不会在web.xml文件中生成Servlet相关的配置信息, 记得改为2.5。
(2) Target runtime选项中如果没有可选的服务器,可点击右侧的"New
Runtime…"进行配置。
详细操作步骤在《5.2配置Target runtime(Web项目运行环境)》
3、Eclipse中创建的Web工程的目录结构:
(1) day09: 工程名称/项目名称
(2) src: 源码目录, 创建的java源文件、配置文件(properties、xml文件等)都可以放在src源码目录下
(3) build/classes: 编译文件的输出目录, src源码目录中的文件编译后会输出到classes目录下。
其中的classes目录在发布时会放在WEB-INF目录下,随着项目一起发布到服务器中
(4) WebContent: 就是Web应用的目录,其中可以存放 html、css、js、jsp、图片以及编译后的class文件、jar包、web.xml文件等. 将来发布项目到服务器,其实就是将WebContent中的所有内容一起发布到服务器中。
(5) WebContent/WEB-INF/lib: 用于存放当前项目所依赖的jar包。比如要访问mysql数据库,需要导入mysql驱动包,直接将jar包拷贝到lib目录下即可!(也不用再去做 build path --> add to build path)
4.2.3 使用Eclipse创建Servlet
1、选中项目中的src目录,鼠标右键 —> New —> Servlet
因为:servlet本质是java程序,而java文件放在 src这个源码目录下.
2、在弹出的窗口中,根据提示填写内容:
3、点击finish即可完成Servlet创建过程, 创建好的Servlet如下:
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,IOException{
//获取一个字符输出流,用于向浏览器发送数据 alt shift+l 在()后面,接受方法返回值的快捷键
PrintWriter out = response.getWriter();
//因为默认编码是iso8859-1,所以输出中文数据会变成问号
out.write( "Hello Servlet.."+new Date() );
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
第一行是序列化的id,这里不用序列化,但删除后会报一个警告,所以不用删。
通过Eclipse创建Servlet,默认继承HttpServlet。由于HttpServlet也是Servlet接口的子类,让HelloServlet继承HttpServlet,相当于间接实现了Servlet接口。
继承HttpServlet类,默认会覆盖doGet方法和doPost方法,两个方法的作用为:
浏览器发送请求,服务器调的是service方法,它是继承的HttpServlet方法,service内部会对请求方式进行判断,如果是get提交就调用get方法,如果是post提交就调用post方法。
注意:servlet 不一定有get和post方法。但一定有service方法
doGet方法:当浏览器发送请求的方式为GET提交时, 将会调用doGet方法来处理请求
doPost方法:当浏览器发送请求的方式为POST提交时,将会调用doPost方法来处理请求
提示:如果当GET提交和POST提交处理代码相同时,可以将代码写在其中一个方法里(例如写在doGet中),并在另外一个方法(例如doPost)中调这个方法。这样一来,不管是GET提交还是POST提交,最终doGet方法都会执行,都会对请求进行处理!! 这样写可以少写代码.
package com.tedu;
import java.io.IOException;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/* 当浏览器访问当前Servlet,如果请求方式为GET提交,就会执行doGet方法对请求进行处理 */
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//处理请求
System.out.println("SecondServlet.doGet()...");
//获取能向浏览器响应数据的输出流
response.getWriter().write( "SecondServlet.."+ new Date() );
}
/* 当浏览器访问当前Servlet,如果请求方式为POST提交,就会执行doPost方法对请求进行处理
* 为什么要在doPost中调用doGet: 如果GET提交和POST提交处理方式相同(也就是处理GET请求和POST请求的
* 代码是完全相同的),为了避免代码的冗余,可以在doPost方法中调用doGet,然后将处理请求的代码都放在
* doGet方法中,这样,无论是GET提交还是POST提交,doGet方法一定会执行! */
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
4.2.4 Servlet在web.xml中的配置
在通过Eclipse创建Servlet时,会自动在web.xml文件中进行Servlet相关信息的配置
(注意:如果是复制Servlet类文件,但配置信息不会跟着复制,需要自己手动添加配置,否则复制的Servlet将无法访问!)如果F2把Servlet的类名更改,Web.xml文件里的全称限定类名需要手动更改类名,下面的访问路径改不改都行。下面的路径改名可以欺骗别人的路径,但实际上还是这个类名的路径。
在浏览器中出现带包名的路径,说明没有对应的配置信息。
//至少这8行
<servlet>
<servlet-name>HelloServlet</servlet-name> //这2个上下name名字需要一致。名字叫啥都一样,一样说明是同一个组.
<!-- 此处配置的类的全限定类名,是为了将来能让服务器通过这个全类名获取
SecondServlet类的字节码对象,再通过字节码对象创建该类的实例.-->
<servlet-class>com.tedu.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<!--此处配置的是当前Servlet的访问路径,浏览器可以通过这个路径来访问服务器内部的SecondServlet,由服务器去调用这个Servlet 默认的是 : / + 类名-->
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
关于上面的配置信息:
a) Eclipse每创建一个Servlet,就会在web.xml文件中添加两个标签:<servlet>和<servlet-mapping>标签(可以将这两个标签看成一个组的标签)
b)<servlet>和<servlet-mapping>标签内都会有一个<servlet-name>标签,标签的内容可以更改,但要求更改后的这两个<servlet-name>标签的内容也必须一致。
c) <servlet-class>标签用于配置Servlet类的全限定类名(即包名+类名)
需要注意:如果在创建Servlet后修改了Servlet类的名称,这个地方也要一起更改,否则将会出现"ClassNotFoundException" 即类找不到异常 404 ,而下面的访问路径改不改都行,改的话相当于伪装一下路径,但实际上还是访问的这个文件路径.
d)<url-pattern>标签用于配置浏览器以什么路径访问当前Servlet(即Servlet对外访问的路径),默认的路径是:/+类名
例如:上面为HelloServlet配置的<url-pattern>为 /HelloServlet
,因此我们在浏览器中的访问路径则为:
http://主机名:端口号/项目访问路径/HelloServlet
4.2.5 运行Servlet程序、访问测试
总结运行方式:
test: 选中方法名右键—test util
java项目—右键—run as—java application
servlet----右键—run as — run on server
在创建项目时如果误删了库: 程序肯定会报错.
如果删的是Apache Tomact v8.5(tomact服务器的运行环境):在项目上右键(包视图)—Bulid Path — AddLibraries–Server Runtime—next—选中服务器—finish
如果误删了jdk(jdk的基础核心类库),在项目上右键(包视图)—Bulid Path — AddLibraries—jre … ----Alternate JRE或者默认的jre库。
上面的是自带的jdk最好不要用。
1、访问Servlet方式一:
若是第一次运行,需要先创建tomcat服务器,即在Servers窗口中点击链接可创建一个tomcat服务器,且只需创建一次即可!
(1)发布项目到服务器:在服务器上右键 --> 点击 "add and remove" 将当前web项目发布到服务器中,并点击完成。
(2)启动tomcat服务器:在服务器上右键 Start 即可启动服务器
(3)通过浏览器访问Servlet:打开本地浏览器,通过路径访问,即可访问Servlet程序
注意: 比如: 这个day09这个项目反而在 它里面的WEB-INF目录下,而WEB_INF这个目录下的资源不能直接访问.
这个文件里的路径不能直接访问,不像html,图片,js可以根据他所存放的路径直接访问。servlet访问跟它存放的位置是每有关系的,建一个servlet会在xml文件多一行配置信息对外访问的路径,默认是类名,但有没生成的情况,这需要自己编译。在浏览器中填写 标签中的路径,区分大小写。 标签内容:参考 ( 4.24 Servlet在web.xml中的配置)
servlet文件的对外的访问路径格式即: 主机名_端口 + 项目名称_ 类名/
http://localhost:端口/项目名称/HelloServlet类名
浏览器访问的路径:不能看左边建项目eclipse的结构,而是看发布到tomact服务器的目录
2、访问Servlet方式二: 不用自己写路径也不用自己发布。顶上面3步。
在eclipse左边的项目中servlet的目录上 或者 在这个servlet的文件内容上右键----run as …
(1) 在运行的Servlet上点击右键 –-> “Run As” —> “1 Run on Server”
(2) 在弹出的窗口中,直接点击完成即可!!!
(3) 运行结果如下:
或者打开浏览器,复制上图中的路径:
http://localhost:8080/Hello/HelloServlet,粘贴到浏览器的地址栏中,回车访问:
4.2.6 Eclipse如何发布一个Web应用
第一种:
第一步,发布到服务器: 在服务器上右键(就那个server)—Add and Remove.(窗口左边表示可发布的目录,双击发布到右边,在右边双击移除发布)—finish 服务器下面可以展开看到项目。
也可以在项目上右键进行移除。
第二步,启动服务器:
第三步,访问servlet: servlet发布后的目录在web-inf目录不能直接访问,用的是在web.xml文件中的配置的路径. 默认是 / +项目名.
第二种: 在servlet内部或则在最左侧项目目录中的这个servlet文件上----右键—Run As—Run on Server
点完之后会弹出一个框—选择一个服务器(接下来它会帮你把项目发送到服务器,在启动服务器,在打开浏览器去访问servlet)
即:这种方式一步顶第一种方式三步,更简单.
项目是如何发布到服务器的:
可以理解为: 把整个项目的webcontent目录发布到服务器webapps目录下 ,在把webcontent改为项目名 ,接着在把 build中的 classes目录也放到web-inf目录下.(class目录存放的是编译后的class文件)
左边建的动态web项目的build并不显示这个 classes文件,在工作空间里有.
怎么快数找工作空间:项目上右键-------show in —System Explorer—会直接到工作空间的目录.
META_INF:META-INF目录实际上就是描述jar文件中的信息的一个目录,我们不用关心
当通过eclipse将day09项目发布到服务器中,是直接将day09拷贝到服务器中对应的目录下吗?
发布的过程如下?
4.2.7 Eclipse默认发布Web应用的位置
Tomcat服务器中默认只有一台虚拟主机,叫做localhost主机
而localhost主机发布web应用的位置是webapps。
将day09发布到localhost主机中,但为什么day09项目没有在webapps目录下?
--------------------------------------------------------------------------------------------------------
默认情况下,发布一个Web应用到localhost主机中,只需要将Web应用的目录拷贝到webapps目录下即可完成发布!
而将Eclipse和Tomcat整合之后,2种,发布的路径默认被改成了:
[工作空间]\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps
如何修改Eclipse默认发布Web应用的目录位置:
(1)关闭服务器,将服务器中的所有应用移除
(2)在服务器上右键 --> clean
(3)双击tomcat服务器,在弹出窗口中找到 Server location, 选择第二个选项
并将下方的Deploy Path改为: webapps 改完后,Ctrl+s保存配置即可!!
参考:在Eclipse中创建Server及移除Server 笔记目录下有
4.3 Servlet调用过程 ???
通过浏览器访问服务器中的一个Servlet程序,这个Servlet程序是如何执行的?又是如何被调用的?
localhost/Hello/HelloServlet
参考<<Servlet调用过程图>> 现在的笔记\第二阶段\课前资料+讲义(day06-day10)\day09.10-servlet核心\图片
这个servlet实例是单例的(即servlet在服务器里只有一个对象),这个对象是浏览器发请求第一次访问servlet时,服务器发现还没有 实例就会通过类的全限定类名通过反射来创建这个实例,然后用到这实例的方法如 service方法处理请求.
4.4 扩展内容
4.4.1 添加Servlet模版
通过Eclipse可以直接创建一个Servlet类,这相比通过记事本等文本编辑工具创建Servlet,可以节省配置Servlet的时间,提高了我们的开发效率。
但是通过Eclipse生成的Servlet类中包含了许多我们不需要的注释和默认实现代码,这些每次都删除也非常占用时间。
接下来可以通过添加模版代码的形式,来生成Servlet的内容,以便于提高我们的开发效率。
1、先创建一个Servlet,将其中的内容修改为自己期望的模版格式,并复制其中的内容,例如:
package ${enclosing_package};
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;
/**
* author: bjzhangsz@tedu.cn
* datetime: ${date} ${time} 会用当前日期时间进行替换,创建类的时间和日期。
*/
public class ${primary_type_name} extends HttpServlet {
//这一行没啥用,但不加回报一个警告.
private static final long serialVersionUID = 1L;
//当浏览器访问当前Servelet,如果请请求方式为GET提交,就会执行doGet方法对请求进行处理
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置文本的类型 和编码格式,因为它默认的是 iso8859-1
response.setContentType("text/html;charset=utf-8");
//获取一个字符输出流,用于向浏览器发送数据
PrintWriter out = response.getWriter();
}
/*当浏览器访问当前Servelet,如果请请求方式为POST提交,就会执行doPost方法对请求进行处理
*为什么要在doPost中调用doPost:如果GET提交和Post提交处理方式相同(也就是处理GET请求和 *Post请求的代码是完全相同的)为了避免代码的 ,可以在dopost方法中调用doGet,然后将处理
*请求的代码都放在doGet方法中,这样,无论是GET提交还是POST提交,doGet方法一定会执行.
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
2、点击菜单栏中的window --> Preferences:
3、在出现的窗口左侧依次点击:Java --> Editor --> templates
–>(在右边的窗口中) 点击New… :
4、在出现的新窗口中填写如下内容:
5、替换包路径和类名(作用是在新建Servlet生成的Servlet模版中使用当前类的包路径和类型)
光标停留在此处: alt+ /
效果如下:
效果如下:
6、点击OK保存,创建新的Servlet文件,测试:
将Servlet中的所有内容全选删除,并输入"servlet",接着按 “Alt+ /”
提示即可生成自己想要的Servlet模版内容!
效果如下:
4.4.2 Servlet3.0的特性
上面使用的是Servlet2.5版本,其实JavaEE5.0规范的子规范,要求运行环境最低是JDK5.0,tomcat5.0。
而Servlet3.0规范是JavaEE6.0的子规范,其要求运行环境最低是JDK6.0,tomcat7.0。若要使用Servlet3.0规范,则需要在创建动态Web项目时就要指定。具体用法是,在Eclipse中创建动态Web工程时,指定创建的“动态Web模块版本”为3.0或以上版本,此时创建的Web工程中默认是没有web.xml文件的。**
思考:如果没有web.xml文件,那么如何配置Servlet的访问路径呢?
通过在servlet类上加个注解的方式进行配置Servlet访问路径。下面来几个Servlet3.0的示例。
1、在3.0以上版本的动态Web项目中创建一个Servlet,如下:
@WebServlet(value="/HelloServlet") value可以省略。
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write( "Hello Servlet3.0.."+new Date() );
}
}
其中@WebServlet("/HelloServlet")
这个注解的作用就是配置当前Servlet的访问路径为/HelloServlet
,完善doGet方法中的代码,直接运行Servlet。
可以在浏览器中看到如下效果:
2、@WebServlet注解中可以配置多个访问路径
在@WebServlet注解中配置的访问路径,其实前面省略了value
属性,完整写法为:
@WebServlet(value="/HelloServlet")
,只不过value可以省略
由于在源码中value
属性其本质是一个字符串数组,因此可以为value属性赋值为一个数组直接量。例如:@WebServlet(value={})
将HelloServlet类上的注解改为如下形式:
@WebServlet(value={"/HelloServlet", "/hello01", "/hello02"})
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write( "Hello Servlet3.0.."+new Date() );
}
}
在浏览器中运行效果为:
3、可以将value属性替换为urlPattern属性,效果一样
@WebServlet(urlPatterns={"/HelloServlet", "/hello01", "/hello02"})
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.write( "Hello Servlet3.0.."+new Date() );
}
}
在浏览器中运行效果为:
4.5 request和response介绍
request对象 response对象
service(request ,response){
//通过request获取请求相关信息
//通过response向浏览器发送响应数据
}
注意:servlet类里,doget 和dopost方法可以有也可以没有,而service方法是必定有的,不写是因为使用父类的 service方法
request是代表HTTP请求信息的对象,response是代表HTTP响应信息的对象。
当浏览器发请求访问服务器中的某一个Servlet时,服务器将会调用Servlet中的service方法来处理请求。在调用service方法之前会创建出request和response对象。
其中request对象中封装了浏览器发送给服务器的请求信息(请求行、请求头、请求实体等),response对象中将会封装服务器要发送给浏览器的响应信息(状态行、响应头、响应实体),在service方法执行完后,服务器再将response中的数据取出,按照HTTP协议的格式发送给浏览器。
(不直接把响应的数据 响应给浏览器而是放在 response对象中,因为直接发送响应的格式不对,也可能有多个请求.)
每次浏览器访问服务器,服务器在调用service方法处理请求之前都会创建request和response对象。(即,服务器每次处理请求都会创建request和response对象)
在请求处理完,响应结束时,服务器会销毁request和response对象。
4.6 request对象
4.6.1 获取请求参数
问题1:什么是请求参数?
所谓的请求参数,就是浏览器发送给服务器的请求中携带的数据(不区分请求方式),例如:通过表单向服务器提交的用户名、密码等,或者在超链接后面通过问号提交的数据,都是请求参数。 (get提交可以用表单,和URL地址的方式,post提交可以用form表单等)
http://localhost/day10/TestParam?user=zhangsan&pwd=123&like=篮球&like=足球
问号前的是URL地址,问号后面是请求参数,参数名可以重复。用&连接
问题2:如何获取请求参数?
(1)request.getParameter(String paramName) Parameter:参数
-- 根据请求参数的名字获取对应的参数值,返回值是一个字符串;
-- 如果一个参数有多个值,该方法只会返回第一个值。
-- 如果获取的是一个不存在的参数,返回值为null
(2)request.getParameterValues(String paramName) values:值
-- 根据请求参数的名字获取该名字对应的所有参数值组成的数组,返回值是一个字符串数组,其中包含了这个参数名对应的所有参数值
-- 如果获取的是一个不存在的参数,返回值为null
代码示例:
//1.获取请求参数中的用户名(user)
String user = request.getParameter("user");
System.out.println( "user="+user );
//2.获取请求参数中的爱好(like)
String[] like = request.getParameterValues( "like" );
System.out.println( "like="+Arrays.toString( like ) );
//直接打印的是地址,调用Arrays方法输出里面的属性值.
问题3:如何解决获取请求参数时的中文乱码问题?
servlet文件中写中文的乱码问题, 这个事请求参数中的乱码问题.
在获取中文的请求参数时,可能会出现乱码问题(和请求方式、tomcat服务器版本有关),具体可以分为以下三种情况:
(1)如果请求是GET提交,并且tomcat是8.0及以后的版本,GET提交的中文参数,在获取时不会出现乱码问题!(8.0以后的tomcat包括8.0在获取GET提交的中文参数时,已经处理中文乱码问题。)
思考为什么post提交都会有乱码问题?
因为post提交接受的不仅仅是一个文本(文本可以用utf-8直接接收,可能是一个文件,图片,音频转成2进制不能看。
(2)如果请求是POST提交,不管是哪个版本的tomcat服务器,在获取中文参数时,都会出现乱码问题。因为tomcat底层在接收POST提交的参数时,默认会使用iso8859-1编码接收,而这个编码中没有中文字符,所以在接收中文参数时,一定会出现中文乱码问题!
解决方法是:通知服务器在接收POST提交的参数时,使用utf-8编码来接收!
request.setCharacterEncoding("utf-8");
注意:这行代码不会影响GET提交,只对POST提交有效!
这行代码要放在任何获取参数的代码之前执行!
(3)如果请求是GET提交,并且tomcat是7.0及以前的版本,GET提交的中文参数,在获取时会出现乱码问题!
解决方法:在[tomcat安装目录]/ conf/server.xml文件的(修改端口的)Connector标签上,添加一个 URIEncoding=“utf-8” 属性,如下:
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="utf-8" />
同时在[Eclipse]/Servers/[当前tomcat服务器对应的配置目录]/server.xml文件中,在Connector标签上,添加一个 URIEncoding=“utf-8” 属性,同上! 因为它有可能用的是安装Tomact自带的xml文件,改一个仍有肯能是错的,所以2个都改保证正确.
4.6.2 实现请求转发
请求转发是服务器内部
资源的一种跳转方式,即当浏览器发送请求访问服务器中的某一个资源(A)时,该资源将请求转交给另外一个资源(B)进行处理并且由资源B做出响应的过程,就叫做请求转发。
请求转发和重定向都是资源的跳转方式,但是跳转的过程有所不同。
请求转发的特点:
(1)转发是一次请求,一次响应
(2)请求转发前后,浏览器的地址栏地址不会发生变化。(浏览器--访问--> A --转发--> B,地址栏地址始终指向A的地址) 相当于你向我借钱,我没有,我告诉刘老师,刘老师把钱出了。但你不知道,在你看来是浏览器给你的钱还以为是我给你的钱。 服务器的跳转,浏览器看不到,所以地址不会变。
(3)请求转发前后的request对象是同一个(转发前在A中的request和转发到B后,B中的request对象和A中的request对象是同一个。基于这一点,可以通过request从A带数据到B)
(4)请求转发前后的两个资源必须属于同一个Web应用,否则将无法进行转发。(A--转发-->B,A和B必须属于同一个Web应用!) request: 请求
请求转发实现: get方法中的参数请求的对象和响应的对象.
//Dispatcher: 调度员
request.getRequestDispatcher(url地址/转发到资源的地址).forward(req, res);
代码示例:
/* 将请求转发给BServlet
* http://localhost:8080/day10/AServlet
* http://localhost:8080/day10/BServlet
* 在A里面写B的相对路径,把A的请求转发给B
* 如和在转发到不同的web应用:http://localhost:8080/day09/BServlet,
不可能实现。
*/
request.getRequestDispatcher("index.jsp").forward(request, response);
4.6.3 作为域对象使用
以前没用框架用servlet+jsp+javabin进行开发,通常用转发+request对象上的map集合从servlet传数据到jsp.
用框架后在传数据时从controller传数据到jsp也是用request对象上的map+请求转发.
这个request上的 map集合通常又叫域对象.
注意域对象的范围是一次请求,2次请求传数据就不行了.(因为请求转发是一次请求,域对象是同一个,所以,只有保证request是同一个数据才能传过去)
如果是2次请求(重定向),与对象是一次请求结束后销毁里面携带的参数当然也跟着销毁.而创建的新的域对象没有这个参数也就不能携带数据.
那么如何在多次请求中携带数据? 用session
总结: request域对象用在一次请求中,而session用在多次请求中.
request在实现转发时,通过request.setAttribute方法和request.getAttribute方法带数据到目的地时,就是通过request对象中的map集合带数据,这个request对象上的map集合以及request对象所在的范围即称之为是一个域对象。
如果一个对象具备可以被访问的范围,通过这个对象上的map集合可以在整个范围内实现数据的共享。这样的对象就叫做域对象。// pageContext request session application (4个域对象,第一个第四个不怎么用现在) Attribute:属性
在request对象上提供了往域对象(map)中存数据的方法以及取数据的方法:
request.setAttribute(String attrName, Object attrValue);
-- 往request域中存入一个域属性,属性名(key)只能是字符串,属性值(value)可以是任意类型(object)。
//将数据存入到request的map集合(request域对象)中
request.setAttribute( "name", "尼古拉斯赵四" );
request.getAttribute(String attrName);
-- 根据属性名(key)获取对应的属性值(value)。返回的是一个Object类型,想用string类型接收就需要强转。
//将request的map集合(request域)中的数据取出来
String name = (String)request.getAttribute( "name" );
System.out.println("name="+name);
request域对象所具备的三大特征:
生命周期:在服务器调用Servlet程序的service方法之前,会创建代表请求的request对象,在请求处理完,响应结束时,会销毁request对象。
作用范围:在一次请求范围内,都可以获取到同一个request对象。
主要功能:和请求转发配合使用,从Servlet带数据到JSP(带数据到目的地)
参数 属性
扩展内容: request对象的getParameter和getAttribute方法有什么区别?
- getParameter()方法是用于获取(从浏览器发送过来的)请求参数的,请求参数不能设置,只能是浏览器发送给服务器,在服务器端再通过getParameter方法获取请求中的参数(只有get方法没有set方法)
- getAttribute()方法是用于从request域中获取域属性时用的,域属性得先存入到域中(即得先通过setAttribute方法将数据存入request域中),再通过getAttribute()方法从域中获取。(这个是先存在取,而请求参数是取)
4.7 response对象
response是代表HTTP响应信息的对象。
4.7.1 向客户端发送数据
PrintWriter out = response.getWriter();
由于服务器在通过response获取的流发送数据时,默认使用iso8859-1编码,而这个编码中没有中文字符,所以在通过response获取的流发送中文数据时,会出现乱码问题。
解决方法是:在响应数据之前,通知服务器使用utf-8发送数据。 response :响应
/* 通知服务器在响应数据时,使用utf-8编码
* 也能通知浏览器使用utf-8接收服务器发送的数据 */
response.setContentType( "text/html;charset=utf-8" );
PrintWriter out = response.getWriter();
out.write( "你好" );
4.7.2 实现重定向
在浏览器上—F12开发者工具----network() 网络,可以查看多少个请求.
当浏览器向服务器发请求访问某一个资源A,资源A在响应时通知浏览器需要再进一步请求才能获取到对应的资源,浏览器再次发请求访问服务器中的资源B,最终由资源B响应浏览器要获取的资源,这个过程叫做重定向。
也就是说: 浏览器发送请求给 服务器A,服务器在返回一个请求给浏览器通知浏览器访问服务器B.浏览器再根据这个响应访问浏览器B. 但是这个之间是没有间隔的速度很快,即看起来像浏览器发送请求到服务器,由服务器B响应。其实中间是先发送到服务器A的。
重定向的特点:
(1)重定向是两次请求、两次响应
(2)重定向前后,浏览器的地址栏地址会发生变化。(因为两次请求都是通过浏览器发起,浏览器知道这个跳转的过程,因此地址栏地址会变化)
你向我借钱,我没有,我告诉你刘老师有,你去找刘老师借钱,刘老师在把钱借给你。
(3)重定向前后的request对象不是同一个(因为重定向是两次请求,服务器会根据两次请求创建两个不同的request对象,request对象不是同一个,也就不能在重定向时通过request带数据到目的地。)
(4)重定向前后的两个资源可以是来自不同的web应用也可以是同一个web应用,甚至可以是来自不同的服务器。(进行跳转的两个资源之间没有限制)
实现代码:
response.sendRedirect(所重定向到资源的URL地址);
代码示例:
写在doget方法里
/* 测试1: 同一个应用内部的资源跳转, 从/day10/Hello01重定向到 /day10/Hello02
* http://localhost:8080/day10/Hello01
* http://localhost:8080/day10/Hello02 */
response.sendRedirect("Hello02"); //相对路径
//response.sendRedirect("http://localhost:8080/day10/Hello02"); //绝对路径
/* 测试2: 不同Web应用内部的资源跳转, 从day10/Hello01重定向到 /day09/HelloServlet
* http://localhost:8080/day10/Hello01
* http://localhost:8080/day09/HelloServlet */
//response.sendRedirect( "../day09/HelloServlet" ); //相对路径
//response.sendRedirect( "http://localhost:8080/day09/HelloServlet" ); //绝对路径
/* 测试3: 不同的服务器内部资源的跳转, 从day10/Hello01重定向到 百度/tmooc首页
* http://localhost:8080/day10/Hello01
* http://www.baidu.com */ 主机名不一样不要写相对路径,用绝对路径,协议也要写对,不然会当成相对路径
//response.sendRedirect( "http://www.baidu.com" ); //绝对路径
out.write( "Hello01响应成功了..." ); //由于重定向跳转时没有时间间隔,所以浏览器上看不到这个响应
总结-1:请求转发(forward)和重定向(redirect)的区别?
(1)请求转发是一次请求,一次响应; 而重定向是两次请求两次响应
(2)请求转发前后地址栏地址不会发生变化; 而重定向前后地址栏地址会发生变化
(3)请求转发前后的request对象是同一个,可以配合request域对象带数据到目的地; 而重定向前后的request对象不是同一个, 不能结合request域对象在重定向前后带数据.
(4)请求转发要求两个资源必须属于同一个Web应用; 而进行重定向的两个资源可以是同一个Web应用,也可以不是同一个Web应用,甚至可以是来自于不同的主机或服务器.
总结-2:什么时候用请求转发(forward)?什么时候用重定向(redirect)?
(1)如果希望跳转前后地址栏地址不会发生变化, 只能使用转发; 如果希望跳转前后地址栏地址会发生变化, 只能使用重定向
(2)如果希望在跳转前后, 能够通过request对象带数据到目的地, 只能使用转发
(3)如果仅仅是做一个跳转,没有其他要求,此时推荐使用转发(转发是一次请求,一次响应,可以减少访问服务器的次数,降低服务器的压力)