1-11

===============================================================================================


for(:){
String str="asdga";
for(char s:str){ //char 指的是str的元素的类型
System.out.println(s);
}
int[] arr ={1,2,3,5};
for(int t:arr){//for(int i=0;i<arr.length;i++){}  //int指的是元素的类型
System.out.println(t);
}










for();{}




能.什么要看引用类型
重写看对象
===============================================================================================
置换算法:  a=5;b=3
1,使用中间值;
c=a; //c=5;
a=b; //a=3;
b=c; //b=5;
a=3;b=5;




2不使用中间值
a=a+b //a=8,b=3;
b=a-b; //a=8,b=5;
a=a-b; //a=3;
a=3;b=5;








命名可以用_和$
int $_$ 正确




输入(5+7+“heloo”+5+7 ) 编译为12hello57
因为字符串前面求和,字符串后面为拼接。java规则




1KB = 1024B
1B = 8Bit位




long a = 10000000000000L  一定要加L或l结尾




long a = 10000000000*2*10L 




long b = 10000000000*3*10l 溢出,十亿乘3超过20亿,溢出。溢出*10l
建议:写在第一个数字之后如:10000000000L*3*10;s




long a = 10000*365*24*299792458溢出。
long a = 10000*365*24*299792458L 正常。




System.currentTimeMillis() 返回1970年1月1日00:00到当前的毫秒数




int a = 10000000000  //编译错误(直接量超范围)




int a = 1000000000*10  //溢出(运算时超范围)




dataTypeDemo------------驼封命名法
DateTypeDemo------------帕斯卡命名法(如类名 class DateTypeDemo)








float f1 = 3.14 编译错误。应该写3.14f
默认的浮点型是double




舍入误差:
2进制无法精确表示1/10.即0.1如同十进制的1/3




double a =3.0;
double b =2.9;
println(a-b):  //0.100000000000000009---0.1




double a=6.0;
double b=4.9;
print(a-b);  //1.099999999996---1.1
   0.00000000000000004




财务ERP  --------不能用double
精确运算场合不能使用double和folat
用BigDecimal  如BigInteger一样




int c=2147483647; //int的最大值
c= c+1; //在c本身基础之上增1;
print(c) ;//溢出为-2147483648




double a =3.14159
float b= 3.14159 //错误。需要加F或 f因为浮点型默认都算double












字符char是表现形式,实质是其对应的码int(0-65535之间,也就是unicode的范围,世界通用的定长字符集,所有字符都是16位的)




ASCII:
'A'--65 'a'---97  '0' ----48  '2'-----50
char c1 = 'ab' //错误,只能一个字符
char c2 = 65; //输出A 
char print(2+2); //4
char print(2+'2'); //2+50=52;
char c1 = '   //错误,无结尾
';  //回车也是字符。错误,无开头




回车,tab---------控制字符---------需要转义
'\n' 表示回车
'\r' 表示换行符号
'\\' 反斜杠
'\'' 单引号




----------------------------------------------------
char c = ' '; //正确。空格的unicode码
char c = ''; //错误,必须有字符;
char c2 = '5' //5的码
char c = 97;  //正确,数值必须在0-65535之间。97是a的码
(‘2’+‘2’)   //输出100,‘2‘的码是int类型的,为50;




----------------------------------------------------------------
int a =5;
long b =a;
int c=(int)b; //强制转换,大转小。有可能溢出或丢失精度




-------------------------------------
2规则:
2.1 整数直接量可以直接赋值给byte,short,char,但不能超范围
2.2byte,short,char型变量参与运算时,先一律转为int再运算;
如:
byte b1 =5;
byte b2 =6;
byte b3 = b1+b2; //错误,
byte b3 = (byte)b1 + b2; //错误 转成了int,b2还是int类型
byte b3 = (byte)(b1+b2); //正确;








---------------------------------------
Day03 运算:
% 大除小需要运算,如8/2
但小除大,如2/8. 结果都是小数,不到1,因此商就是0.模则为大的数本身
如2/8的商是0,0乘8等于0,2只能除0,所以模的结果就是2;
5%2  //1,因为商2,余1;
8%2  //0, 商4,余0;
2%8  //2,商0余2;
8.456%2 //0.456.了解即可。








----------------------------------------------------
int a=10;b =20;
int c1 = a++;
int c2 = ++b;
//输出结果:a=11;b=21;c1=10,c2=31




---------------------------------------------------------
逻辑与或非




&& || 两个则表示短路,即前面的判断出结果后面的条件则不计算了
也可以用单个:&  | 则表示无论如何后面的结果都走一遍。




int a=5,b=10,c=5;




boolean b4 = a<b || a++>2;
print(b4); //true;
print(a); //5,发生短路了。即a<b为true,逻辑或中有true则全true,后面的a++>2不走。如果改成单个的 | 则a的输出变成6,因为走了一遍了;




----------------------------------------------------------
!!!!!!!!!!!!!!!!!!!!
常见面试题目:
short s1 =5;
s1= s1+10;  //只要参与运算,一律都算int。编译错误,大的int变成short,必须强转
//修改:s1=(int)(s1+10);
s1+=10;  //正确,因为扩展赋值运算自动强转;








!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!




print(10+20+""+30); //输出字符串3030 前面加法,字符串后面拼接
print(10+20+30+""); //输出字符串60;
print(""+10+20+30); //输出字符串102030;




三目/条件运算符:
1)语法:
boolean?数1:数2;
2)执行过程:
计算boolean的值;如果为true,执行数1,若为false,执行数2;








可以嵌套使用
int a=-3;
String r=a>0 ? "正数" : (a==0 ? "0" : "负数" );
print(r); //结果为负数;








4.break:跳出循环,剩下的次数不执行,只是跳出当前循环
  continue:跳过循环体中剩余语句而进入下一次循环,比如当前判断下面还有语句也不走了




---------------------------------------------------------------------------------
=================================================================================
Day03
分支结构:








满足就干事,不满足就不干事————————if
满足就干事,不满足就干另一件事情——————if else












1)ABCD四个档,只有可能走其中之一
2)若没有最后的else,则abcd 并非必走其中之一
3)若有最后的else,则abcd必走其中之一




int score=45;
if(score>=90){A}
else(score>=80){B}
else(score>=60){C}
else{不及格}




switch...case多条路
优点:效率高/结构清晰
缺点:整数/相等








int num=3;
switch(num){  //byte,short,int,char 只能用整型;
case 1:
System.out.println("显示全部记录");
break;
case 2: //以此为入口;
System.out.println("显示查询");
break; //跳出switch  //break如果不用,则入口即之下的都会执行。
case 3:
System.out.println("显示其他");
break: 
default: //只要上面没匹配就走默认的。可以放在任意位置。
System.out.println("输入错误"); 
break;//default放最上面一定要加break;放下方不需要;
}








5个经典案例:
age年龄判断程序
LeapYear闰年判断程序
Cashier收银程序
ScoreLevel成绩等级判断程序
CommandBySwitch命令解析程序
======================================================================
Day04:
循环结构 while    do...while
循环3要素:




循环结构:
1,while结构: while(判断条件boolean){} //当满足判断条件,即判断条件为true的时候就一直循环,直到false才结束;有可能一次也不执行,就是当判断结果为false的时候。
2,do...while结构  //先执行一次,再判断是否为true,是则继续,false则跳出。
3,for结构








笔记:
1.循环:反复执行一段相同或相似的代码
2.循环三要素:
  1)循环变量的初始化
  2)循环的条件(以循环变量为基础)
  3)循环变量的改变(向着循环的结束变)
  循环变量:在循环过程中所反复改变的那个量
3.循环结构:
  1)while:先判断后执行,有可能一次都不执行
  2)do...while:先执行后判断,至少执行一次
               第1要素与第3要素相同时,首选
  3)for:应用率最高,固定次数循环
4.break:跳出循环
  continue:跳过循环体中剩余语句而进入下一次循环




三要素
1,循环变量的初始化
2,循环的条件(以




接收用户输入
int guess = scan.nextInt();




for(int i=0,j=6;i<=6;i+=2,j-=2)
条件i<=6必须用;不能, 如果多个条件可以用&&




break 常与if用




======================================================================
Day05:
o  -------------char--字符-------- 编码0
char:字符型,2个字节,必须放在单引号中,有且仅有一个
char c1 = '女';
"0"-------------------int/long/----------字符串








System.Arraycopy(src,srcIndex,desti,destIndex,length)
e.g: arr = Arrays.copyOf(arr,arr.length+1);




(
import java.util.Arrays;
Arrays.copyOf(original,newlen) //短截取,长用null或0填充
)








Arrays.sort(arr)




——————————————————————————————————————————————————————




回顾:
1.循环:反复执行一段相同或相似的代码
2.循环三要素:
  1)循环变量的初始化
  2)循环的条件
  3)循环变量的改变
  循环变量:在循环过程中所改变的那个量
3.循环结构:
  1)while:先判断后执行,有可能一次都不执行
  2)do...while:先执行后判断,至少会执行一次
               第1要素与第3要素相同时首选
  3)for:固定次数循环




















笔记:
1.三种循环结构的更佳适用情况:
  1)while:"当..."循环
  2)do...while:"直到..."循环
               第1要素与第3要素相同时首选
  3)for:固定次数循环,应用率最高
2.嵌套循环:
  1)循环中套循环,一般多行多列时使用,外层控制行,内层控制列
  2)执行规则:外层循环走一次,内层循环走所有次
  3)建议:层数越少越好,能用一层就不用两层,能用两层就不用三层
    若需要必须通过三层以上才能实现,说明设计有问题
  4)break只能跳出一层循环
3.程序=算法+数据结构
  1)算法:解决问题的流程/步骤(顺序、分支、循环结构)
  2)数据结构:将数据按照某种特定的结构来保存
             数怎么存
    设计良好的数据结构会导致好的算法
4.数组:
  1)相同数据类型元素的集合
  2)数组也是数据类型(引用类型)
  3)数组的定义:
      int[] arr = new int[4];
  4)数组的初始化:
      int[] arr = new int[3];       //0,0,0
 int[] arr = {1,4,7};          //1,4,7
 int[] arr = new int[]{1,4,7}; //1,4,7
 int[] arr;
 arr = {1,4,7}; //编译错误
      arr = new int[]{1,4,7}; //正确
  5)数组的访问:
    5.1)通过(数组名.length)获取数组的长度
     int[] arr = new int[3];
 System.out.println(arr.length); //3
5.2)通过下标来访问数组中的元素
   从0开始,最大到(数组的长度-1)
 int[] arr = new int[3];
 arr[0] = 100; //给第1个元素赋值为100
 arr[1] = 200;
 arr[2] = 300;
 arr[3] = 400; //数组下标越界异常
 System.out.println(arr[arr.length-1]);
  6)数组的遍历:
      int[] arr = new int[5];
 for(int i=0;i<arr.length;i++){
   arr[i] = 100;
 }
 for(int i=0;i<arr.length;i++){ //正序输出
   System.out.println(arr[i]);
 }
      for(int i=arr.length-1;i>=0;i--){ //倒序输出
   System.out.println(arr[i]);
 }
  7)数组的复制:
      System.arraycopy(a,1,a1,0,4);
 int[] a1 = Arrays.copyOf(a,6);
 a = Arrays.copyOf(a,a.length+1);
  8)数组的排序:
      Arrays.sort(arr); //升序
      冒泡原理:
        1)四个数冒三轮
        2)每一轮都是从第1个元素开始冒
          每一次都是和它的下一个元素比
        3)冒出来的就不带它玩了


















BubbleSort








int[] arr = {23,5,89,1}; //升序




for(int i=0;i<arr.length-1;i++){ //控制轮
  for(int j=0;j<arr.length-1-i;j++){ //控制次
    if(arr[j]>arr[j+1]){ //每次和它的下一个元素比
 int t = arr[j];
 arr[j] = arr[j+1];
 arr[j+1] = t;
}
  }
}
    
arr.length-1-i
i=0 比3次
i=1 比2次
i=2 比1次




第一轮:
  23和5比,换,5,23,89,1
  23和89比,不换
  89和1比,换,5,23,1,89-----------89冒出来了
第二轮:
  5和23比,不换
  23和1比,换,5,1,23,89-----------23冒出来了
第三轮:
  5和1比,换,1,5,23,89------------5冒出来了












不同的数据,不同的排序方式效率是不同的




30万个数据--------------插入排序最快
30万个数据--------------冒泡排序最快
30万个数据--------------快速排序最快












long a = System.currentTimeMillis();
......
long b = System.currentTimeMillis();




System.out.println(b-a); //500








int[] a = {10,20,30,40,50};
int[] b = new int[6]; //0,0,0,0,0,0




for(int i=0;i<a.length;i++){
  b[i] = a[i];
}




b[0] = a[0];
b[1] = a[1];
b[2] = a[2];
b[3] = a[3];
b[4] = a[4];












int[] arr = {2,23,56,4};
找最大值算法:
1.假设第一个数为最大值
    int max = arr[0];
2.遍历剩余元素,用剩余元素与max对比,
  若大于max,则修改max的值为较大的
    for(int i=1;i<arr.length;i++){
 if(arr[i]>max){
   max=arr[i];
 }
}




max=2/23/56








int a = 8; //4个字节




int[] arr = new int[10]; //40个字节








0-----------char的默认值为码0
'0'








ArrayDemo








int[] arr = new int[5];
for(int i=0;i<arr.length;i++){
  arr[i] = 100;
}












for(int i=0;i<arr.length;i++){
  System.out.println(arr[i]);
}








for(int i=arr.length-1;i>=0;i--){
  System.out.println(arr[i]);
}








System.out.println(arr[4]);
System.out.println(arr[3]);
System.out.println(arr[2]);
System.out.println(arr[1]);
System.out.println(arr[0]);








arr[0] = 100;
arr[1] = 100;
arr[2] = 100;
arr[3] = 100;
arr[4] = 100;








int[] arr = new int[3]; //0,0,0
arr[0] = 100; //给arr中第一个元素赋值为100
arr[1] = 200;
arr[2] = 300;
arr[3] = 400; //运行时异常----数组下标越界异常
System.out.println(arr[arr.length-1]); //输出最后一个元素












int a=0;
int b=0;
int c=0;
a=100;
b=200;
c=300;












arr[0]-------代表arr中的第1个元素
arr[1]-------             2
arr[2]-------             3
















//声明布尔型数组b,包含26个元素
//每个元素都是boolean型,默认值为false
boolean[] b = new boolean[26];












//声明浮点型数组d,包含10个元素
//每个元素都是double型,默认值为0.0
double[] d = new double[10];








//声明整型数组a,包含5个元素
//每个元素都是int型,默认值为0
int[] a = new int[5]; //0,0,0,0,0








int   a; //声明整型变量a
int[] a; //声明整型数组变量a
















将1万本书按照图书类别存储------设计数据结构
找java编程思想------------------算法简单








将1万本书按照出版社来存储------设计数据结构
找java编程思想------------------算法不简单












跳出多层循环------这个需求几乎没有




for(int i=1;i<=100;i++){
  for(int j=1;j<=200;j++){
    for(int k=1;k<=300;k++){
      System.out.println("aaa");
 if(){break};
}
  }
}












i=1
  j=1
    k走30次
  j=2
    k走30次
  ...
  j=20




















1*9=9   2*9=18  3*9=27  
















选择循环结构的规则:
1.先看是否是固定次数循环?
  1)固定次数时,选择for循环
  2)不固定次数时,再看要素1与要素3是否相同?
    2.1)相同时,首选do...while
2.1)不同时,首选while








int i = 0;
while(i<10){
  i++;
}
System.out.println(i); //10








int i;
for(i=0;i<10;i++){
}
System.out.println(i); //10




















逻辑思维能力-------------几乎没有
听得懂,就是写不出来----------




——————————————————————————————————————————————————




int [] a= Arrays.copyOf(a,6);
System.arrayscopy(a,0,a1,1,10);
Arrsys.sort(arr); 




System.arrayscopy(a,0,a1,1,10);
Arrsys.sort(arr); 无返回值








int [] a= Arrays.copyOf(a,6); 有返回值












public static int sum(number1,number2) 
//修饰词;方法体;返回值类型;方法名(参数1,参数2)








有参更灵活
double c = Math.random(); //无参 0.0-0.999999999
double d = Math.sqrt(25); //有参








double c = Math.random(0,99); //0.0-9999999 








若方法不需要返回值就用 void
需要返回值 指定类型 int long string boolean或者char,或者引用类型Emp Person等等




方法和方法并列








只有字符数组java的System.out.println()才能直接输出,整型的不行。
System.out.println(arr)




boolean[] flags = new boolean[letters.length]; 默认false












int=0 index=0  false chs[0]='a' flags[0]=true
int=1 index=25 false chs[1]='a' flags[25]=true
int=2 index=0/25/0/25/0/25/1 false chs[2]='b' flags[1]
int=3








循环次数不固定,用while /do while




while(true)








11月二十几号讲:
String str = scan.next();
char[] input = str.toCharArray();




String.equals.(string2)
if ("EXIT".equals(inputStr)){}








基本类型相比较 用==
String 类型相比较用equals  if(str.equals("exit"))




——————————————————————————————————————————————————————
day06 








回顾:
1.适用情况:
  1)while:当...
  2)do...while:直到...
               要素1与要素3相同时首选 
  3)for:固定次数
2.嵌套循环:
    循环中套循环
外层一次,内层所有次
层数越少越好
break跳出一层循环
3.数组:
    相同数据类型元素的集合
是数据类型(引用类型)
int[] arr = new int[4];
    int[] arr = {1,4,6};
int[] arr = new int[]{1,4,6};
    arr[0] = 55;
System.out.println(arr[arr.length-1]);
    for(int i=0;i<arr.length;i++){
 arr[i] = 100;
}
    System.arraycopy(a,0,a1,1,4);
    int[] a1 = Arrays.copyOf(a,6);
a = Arrays.copyOf(a,a.length+1);
Arrays.sort(arr);
冒泡




正课:
1.方法:
  1)封装一段特定的业务逻辑功能
  2)尽可能的独立,一个方法只干一件事
  3)方法可以被反复调用多次
  4)避免代码重复,有利于代码的复用,有利于团队协作开发
2.
3.
4.return的用法:
  1)return 值; //1)结束方法的执行 2)返回结果给调用方法
  2)return;    //1)结束方法的执行




5.猜字符小游戏:












public static void main(String[] args){
  say();
  sayHi("zhangsan");
  int a = getNum(); 输出a的值
  double b = plus(5.5,6.6); 输出b的值
  double c=5.5,d=6.6; 
  double e = plus(c,d); 输出e的值
}
public static void say(){}
public static void sayHi(String name){}
public static int getNum(){
  return 88;
}
public static double plus(double num1,double num2){
  return num1+num2;
}












方法可以嵌套调用








if(){
  break;
}




if(){
  return;
}












MethodDemo








方法可以有参也可以无参,有参使方法更灵活
















System.out.          println("HelloWorld");
System.              arraycopy(a,1,a1,0,4);
Arrays.              sort(arr);
double d = Math.     sqrt(25);
int[] a1 = Arrays.   copyOf(a,6);  //有参数




int a    = scan.     nextInt();
double b = scan.     nextDouble();
double c = Math.     random();     //无参数








double c = Math.random(); //0.0到0.99999999999...
double d = Math.sqrt(25);




假设random()有参:
double a = Math.random(1,1000);
double a = Math.random(0,99);
double a = Math.random(21,60);
double a = Math.random(0,26);
























方法可以有返回值也可以没有返回值
  无返回值----返回值类型写成void
  有返回值----返回值类型写成具体的数据类型




若方法执行完以后,需要方法中的某个数据----有
若不需要方法中的某个数据------------------没有
















System.out.println("HelloWorld");
System.arraycopy(a,1,a1,0,4);
Arrays.sort(arr);             无返回值




int a    = scan.nextInt();
double b = scan.nextDouble();
double c = Math.random();
double d = Math.sqrt(25);
int[] a1 = Arrays.copyOf(a,6);  有返回值












A:干一个业务
B:干一个业务
C:干一个业务












排序10个地方




排序(){
  冒泡6句话
}












System.out.println("HelloWorld");












a(){
  存
}
b(){
  取
}
c(){
  转
}




张三-------调a(),b(),c()
李四-------调a()
王五-------调b()
赵六-------调a(),c()












main(){
  调存----1
  调取----1
  调转----1
}
存(){
  500---调检测密码()
}
取(){
  500---调检测密码()
}
转(){
  1000---调检测密码()
}
检测密码(){
  
}












质数:又称素数,只能被1和它本身整除的数




何时是质数?------------取余所有都不得0
何时不是质数?----------只要有取余为0的








并非一次判断得结果----------------开关








5是质数:
  5%2/3/4-------------------都不得0
7是质数:
  7%2/3/4/5/6---------------都不得0
8不是质数:
  8%2/3/4/5/6/7-------------有取余为0的
9不是质数:
  9%2/3/4/5/6/7/8-----------有取余为0的












100
  %2/3/4/5/..../98/99
  %2/3/4/5/..../49/50
  %2/3/4/5/..../9/10




100%  51/52/53/54/.../98/99
100%  11/12/13/14/.../49/50












Math.sqrt(100)-----10.0




100平方根是10
25平方根是5
81平方根是9








-----------------------------------------------------------------
DAY07 OOP




OOP 本周讲4天,下周讲2天。然后做飞机大战案例3天




前4天,贯穿俄罗斯方块








面向过程也就是面向方法,面向函数




引用类型都需要借助new关键字
STRING
如int[] arr = new int[]
Emp e = new Emp();  //Emp为封装了的类。public class Emp{...}








---------------------------------------------------------------------------
1,找对象————一堆小格子对象
2,抽类——————cell类
3,设计类中成员变量和方法——————
4,创建对象并测试——————




class Cell{ //格子类
形状,颜色,宽 高 ————>图片
行号,列号








int row;//行号
int col //列号




void drop(){ //下落一格
 row++;
}
void moveleft(int n){ //左移
col-=n
}
//想获取行,获取的话需要返回值
int[] getCellInfo(){ //获取行号和列号
 int [] arr = new int[2] //数组太麻烦
}




String getCellInfo(){
return row+","+col
}

cell c = new cell()
类型 引用类型变量 指向 对象




new出来的对象都是放在堆中
基本类型 int = 5 因为没有new,放在栈中
Cell c = new Cell();  c 和保存的在堆中的数据的地址在栈中。如c 0x7797 
而Cell的row=0和col=0在堆中
————————————————————————
引用类型之间画等号:
1,指向同一个对象;如CellTest.java
2,对其中一个引用的修改影响另外一个
基本类型之间画等号:
eg:钥匙 :引用。  房子:对象  配一把钥匙:另一个引用
1,赋值
2,对其中一个变量的修改不影响另一个
eg:身份证复印








---------------------------------------------------------------------------------------
overload 




同一个java文件中可以有多个类,但是只能有一个public
比如:public class a{
public void a(){}}
      class b{ public void b(){} }
跟返回值类型无关。如void say(){} 和int say(){return 1} 不能重载
与参数的名称无关。如void say(){String name} 和 int say(String age){}不能重载




下周整个面向对象结束,下下周讲API ——20161109




————————————————————————————————




凡是加()都是调方法








构造方法:5句话
1,常常用于给成员变量赋初值
2,与类同名 没有返回值。如class Cell{int row;int col; public Cell(int row1,int col1)}
3,在new对象时被自动调用;
4,没有构造方法系统自动给一个无参无内容的构造方法,有了就不给了
5,构造方法可以被重载








----------------------------------------------------------------------------
this;指代当前对象。哪个对象调用就指哪个。只能用在方法中。在访问成员变量之前都有个this
this.成员变量名 ————访问成员变量
this.方法名()————调用方法
this()——————————调用构造方法;








构造方法还是方法,方法可以被重载












---------------------------------------------------------------------------------
成员变量有默认值,一旦new了就有默认值
局部变量没有




--------------------------------------------------------------------------------
向上造型;




//父类型o1,能访问父类的成员;但是T特有的不能访问
Tetromino o1 = new T(1,2); //向上造型;父类型的引用o1指向子类对象T
printWall(o1); //先造型后传值;
//父类型j,能访问父类的成员;下面J的能访问的权限大于上面的Tetromino;
System.out.println("--<<<<<<<<<分割线->>>>>>>>>>>>--------");
J j = new J(6,6);
printWall(j); //传值的同时造型;




_______________________________________________________________________________
继承要符合IT‘S A 的关系,不要为了复用代码而随意继承。如:
class dog(){
String name;
int age;
class student extends dog(){}




______________________________________________________________________________
子类不能继承父类的构造方法,只能被调用。如:
class fu{
fu(){}
fu(int n){}
}
class zi{
zi(){}
}




Zi z = new Zi(6); //错误!子类不能继承父类的构造方法,只能被调用。子类无有参的构造函数
可以改成:
class fu{
fu(){}
fu(int n){}
}
class zi{
zi(){
super(n)
}
}








_________________________________________________________________________________




Override :
使用频率相当高
重写需遵循两同两小一大
两同:
1方法名相同
2参数列表相同
两小:
1,子类返回值类型小于或等于父类的。
1,void时,必须相等
2,基本类型时,必须相等
3,引用类型,小于或等于
如:
//父类大 ,子类小;
class Coo{
Coo say(){}
Doo sayHi(){}
}
class Doo{
Coo say(){}
Doo sayHi(){} //错误。
}
一大:












编译期:.java 到 .class 无对象,只能看引用类型
运行期: jvm运行。.class到.class; 内存中分配了空间给对象。




--------------------------------------------------------------------------------------------------------------




常见面试:override和overload的区别












4种修饰符;
public :本类;同包类;
protected:
private
默认的:




















成员变量:
1,实例变量:存在堆中,new几次就有几份
2,静态变量:存在方法区中,只有一份




实例方法:默认都有this,this接收当前对象。调用实例方法要先new对象
静态方法:无隐式的this,则无对象,无对象则实例变量无法用隐式的this传对象进静态方法。
所以,静态方法一定跟对象无关的,只跟参数有关。
静态方法不能访问非静态成员








静态方法:
Math.random();  //首字母大写可知Math是类名。要调用静态方法只能通过类名.静态方法名的方式
Math.sqrt();
Array.sort();




实例方法:
需要new,如
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();








静态块:
1,由static修饰
2,属于类的代码块,类被加载期间自动执行
因为类只加载一次,无论new多少次对象,所以静态块也只执行一次。
3,何时用:常常用于加载图片等,如游戏的图片,一开始就加载。








final
1,修饰变量 : 变量不能被改变
2,修饰方法 : 不能被重写
3,修饰类 : 意味着不能被继承
final修饰成员变量,只有两种初始化方式
1,声明的同时初始化;
2,在构造方法中初始化;
final修饰局部变量,只要在用之前初始化即可
 class Hoo{
final int a=5;   //1,声明的同时初始化;
final int b;  
Hoo(){
b=6;          //2,构造方法中初始化
}
}








java中默认都可以重写,不想被重写则加final








------------------------------------------------------------------------------------------
static final:常量
1,必须声明的同时初始化
2,常常通过类名点来访问,不能被改变
3,建议:常量名所有的字母必须大写
4,








public class Poo{
public static final int COUNT=5;  //修饰词顺序无所谓
System.out.println(Poo.COUNT);
}
//编译器在编译时将常量直接替换为具体的值
//相当用于System.out.println(5)








-------------------------------------------------------------------------------------------
有方法体{}则不能用抽象
或者: class Shape  
{  //抽象类————不完整
double c;
abstract double area();抽象方法——不完整的。所以类也需要写抽象
}








抽象的类绝对不能new对象。




没写完的方法,就算抽象;如下
class Car{
...
...
void stop();  //不完整的方法,所以需要加上abstract。而又因为方法是abstract,所以类名前面也要加。
}
变成:
abstract class Car{
...
...
abstract void stop(); 
}
抽象类不能被实例化,只能被继承。
new shape //编译错误;
Shape s;//正确。声明了引用类型的引用;




Shape s = new shape();左边正确,因为是shape类型的引用,右边错误,不能new












抽象方法:
1,abstract修饰
2,方法不完整,只有方法的定义,没有方法体








抽象类:
1,由abstract修饰
2,包含抽象方法的类必须是抽象类
3,抽象类不能被实例化;
4,只能作为父类被继承。方法被子类重写;








absract class Shape{ //抽象类————不完整
double c;
abstract doble area (){} //抽象方法————不完整
}




class Square extends Shape{ //重写抽象方法,----变不完整为完整。
double area(){
return 0.0625*c*c;




n
抽象存在的意义
1,封装子类共有的属性和行为,实现代码的复用
2,为所有子类提供一种统一的类型---向上造型
3,可以包含抽象方法,为所有子类提供统一的入口。子类的具体实现不同,但定义是一致的








笔记:
1.访问控制修饰符:
  1)public:公开的,任何类
  2)private:私有的,本类
  3)protected:受保护的,本类、子类、同包类
  4)默认的:什么也不写,本类、同包类
  说明:
    1)类的访问修饰只能是public和默认的
2)类中成员访问修饰如上4种都可以
2.static:静态的
  1)静态变量:
    1.1)由static修饰
1.2)属于类的,存在方法区中,只有一份
1.3)常常通过类名.来访问
1.4)何时用:所有对象的数据都一样时使用
  2)静态方法:
    2.1)由static修饰
2.2)属于类的,存在方法区中,只有一份
2.3)常常通过类名.来访问
2.4)静态方法没有隐式this传递,
        所以静态方法中不能直接访问实例成员
2.5)何时用:方法的操作仅与参数相关而与对象无关
  3)静态块:
    3.1)由static修饰
3.2)属于类的代码块,类被加载期间自动执行
   因为类只被加载一次,所以静态块也只执行一次
3.3)何时用:常常用于加载/初始化静态资源(图片、音频、视频等)
3.final:最终的,单独应用的几率不大
  1)修饰变量:变量不能被改变
  2)修饰方法:方法不能被重写
  3)修饰类  :类不能被继承
4.static final:常量
  1)必须声明的同时初始化
  2)常常通过类名点来访问,不能被改变
  3)建议:常量名所有字母都大写
  4)在编译时被直接替换为具体的值,效率高
5.抽象方法:
  1)由abstract修饰
  2)只有方法的定义,没有具体的实现(连大括号都没有)
6.抽象类:
  1)由abstract修饰
  2)包含抽象方法的类必须是抽象类
    不包含抽象方法的类也可以声明为抽象类---我乐意
  3)抽象类不能被实例化
  4)抽象类是需要被继承的,子类:
    4.1)重写抽象类中的所有抽象方法----建议
4.2)也声明为抽象类----不建议
  5)抽象类的意义:
    5.1)封装子类所共有的属性和行为,实现代码复用
5.2)为所有子类提供一种统一的类型----向上造型
5.3)可以包含抽象方法,为所有子类提供了统一的入口,
   子类的具体实现不同,但定义是一致的
7.接口:
  1)是一个标准、规范----制定方
    遵守了这个标准就能干某件事------API之




---------------------------------------------------------------------------------------------
用static修饰的成员变量是属于对象的数据结构 错
用static修饰的成员变量是属于类
static成员变量存储在堆中
static成员变量存储在方法中




子类的访问权限得大于或等于父类的








抽象方法也是一种数据类型(引用类型),所以可以作为类型数组
---------------------------------------------------------------------------------------------




Day06
===============================================================================================




接口:
只包含常量或者抽象方法。








1.接口:
  1)是一个标准、规范
    遵守这个标准就能干某件事------API之后
  2)接口也是一种数据类型(引用类型)
  3)由interface定义,只能包含常量和抽象方法
  4)接口不能被实例化
  5)接口是需要被实现/继承的,实现类/子类:
      必须重写接口中的所有抽象方法
  6)一个类可以实现多个接口,
    若又继承又实现时,应先继承后实现
  7)接口可以继承接口
2.多态:
3.内部类:
4.面向对象总结:








interface Inter1{
public static final int NUM  5;
public abstract void show();
int COUNT = 6; //默认public static final
void say(); //默认public abstract




int NUMBER; //编译错误,常量必须声明同时初始化
void test(){} //编译错误,   ——————————————————?是因为接口都是抽象的吗?








interface Inter1{
public void show();
public void say();
}
class Aoo implements Inter1{
//子类的访问权限得大于或等于父类的
void show();  //不加public则报错。因为接口默认类public,不写也算public,但是类不写则
//默认为默认修饰,默认修饰符的权限没有public大,只能同类同包。所以实现
//的类中重写的方法必须加上public
void say();
}




正解:
class Aoo implents Inter1{
public void show(){}
public void say(){}
}




接口可以继承接口,而且可以继承多个;
-----------------------------------------------------------------------------------------------------
可以多实现。
interface Inter2{
void test()
}
//必须先继承再实现
class Boo extends Aoo implements Inter1,Inter2








interface Inter1{ void show();}




interface Inter 2 implents Inter2{ void test(); }




class Boo implements Inter2{ 
void show(); //必须也要重写test,因为2继承类1;。
void test();  
}








例子:
Inter2 o2 = new Inter();  //编译错误,接口不能被实现
Inter2 o2 = new Aoo();  //向上造型;
Inter1 o3 = new Aoo();  //向上造型(前提是Inter2实现了Inter1),间接父子




---------------------------------------------------------------------------------------------------




接口和抽象类 的区别;
所有子类共有的,抽到父类中。用继承
部分子类共有的,抽到接口中。




符合既是 也是原则,使用接口




接口是继承的单根性的扩展。




“实现接口”与“继承父类”不同,一个类可以实现多个接口,实现的接口直接用逗号分隔。并且,具体类需要实现这些接口中定义的所有抽象方法; 接口间可以存在继承关系,一个接口可以通过extends关键字继承另外多个接口。子接口继承了父接口中定义的所有方法。




-----------------------------------------------------------------------------------------------------
多态:
点出什么看引用类型,具体行为的实现要看对象




1.同一类型的引用,指向不同的对象时,有不同的实现




向上造型:
父类型的引用指向子类的对象
能造型成的类型:父类+所实现的接口
能点出什么看引用的类型








强制类型转换,成功的条件有2种:
引用所指向的对象,就是该类型;
引用所指向的对象,实现了该接口
不符合那两种条件则转换失败;
发生ClassCastException类型转换异常;
建议使用instanceof判断引用指向的对象是否是该类型




Aoo o1 = new Boo();
Boo o2 = (Boo)o1  //符合条件1
Inter1 o3 = (Inter1)o1; //符合条件2
Coo o4 = (Coo) o1 //ClassCastException类型转换异常;








interface








interface Inter7{}
class Foo{}
class Goo extends Foo implements Inter7{}
class Hoo extends Foo{}




main:
Foo o1=new Goo(); //向上造型
Goo o2=(Goo)o1 //o1所指向的对象Goo就是Goo类型
Inter7 o3=(Inter7)o1 //正确。o1指向的Goo确实实现了Inter7
??????????????/










父类大,子类小;
自动:小到大
强制: 大到小




人 p1 = new 理发师()  //向上造型,自动转
理发师 l = new 人(); //错误













double num = Double.parseDouble(input.next());
double num = scan.nextDouble();








======================================================================================================




内部类,匿名内部类:




类中套类,外面的类成为外部类,里面的类




4.内部类中可以直接访问外部类的成员,包括私有的。




class Aoo{
private int a;
void test(){
Boo o - new Boo();
}
class show(){
System.out.println(a);
System.out.println(Aoo.this.a);
System.out.println(this.a); //编译错误
}}












匿名内部类:
1,想创建一个类的对象,并且对象只创建一次。
此时该类不必命名
2.
3.
4








常见面试题:
问:内部类有独立的.class么?
答:有




接口也会生成一个.class文件
//.java编译都会生成.class








面向对象三大特征:
封装 
1,类:封装的是对象的属性和行为
2,方法:封装的是具体的业务逻辑功能
3,访问控制修饰符:封装的是访问的权限
继承 
1,作用:代码的复用;
2,父类/基类:所有子类所共有的属性和行为
  子类/派生类:子类所特有的属性和行为;
3,子继承父之后哦,子具有:父+子
4,单一继承,多接口实现,传递性/符合is a关系
多态
1,意义:行为的多态,对象的多态
2,向上造型,强制类型转换,instanceof
3,多态的表现形式:
1,重写--根据对象的不同
2,重载--根据参数列表不同而多态,行为的多态。

---------------------------------------------------------------------------------------------------








shootgame
1,找对象 :英雄机,敌人飞机,小蜜蜂,子弹
2,抽类: Hero,Airplane,Bee,Bullet
3,设计类中的成员变量和方法
4,创建类和测试




























敌人飞机————能得分
BOSS飞机————能得分;








蜜蜂————奖励
大黄蜂————奖励




所以用接口
interface enemy{
int getScore();
}
interface Award{
int getType();
}








class FlyingObject{//飞行物
x,y,image,width,height
}
















class Hero extends FlyingObject{//英雄机
life,doubleFile
}




class Airplane extends FlyingObject implements enemy{
int getScore(){return 5;}




}
class BossAirplane extends FlyingObject implements enemy{//BOSS飞机
int getScore(){return 20;}
}




class bee extends FlyingObject implements Award{

}
class bullet extends FlyingObject{




}








shotTest{








void set???(有参)-----------设置;
get(无参)————————
boolean




================================+++++++++++++++++++++++++++++++========================================
ShootGame Test Day2
1,画图,画对象; swing相关 c# java几乎无c端,以B/S为主  飞机大战用浏览器比C端好。
JFrame  JPanel 
2,敌人(敌机+小蜜蜂)入场
3,飞行物(敌机+小蜜蜂+英雄机+子弹)走一步
4,子弹入场












子弹入场;
1创建子弹对象
2将对象添加的到bullets数组中
























敌人对象————————在窗口上产生的
子弹对象————-————英雄机产生的








TimerTask 按住ctrl点




timer.schedule(Aoo){
}




class Aoo extends TimerTask
变成:
timer.schedule(new TimerTask(){})  {
}




paint()方法调用的两种方法:
1.frame.setVisible(paint);
2,repaint();




================================+++++++++++++++++++++++++++====================================
MouseListener()
MouseMotionListener()




侦听器












MouseListener m1 = new MouseListener(){重写5个};
MouseMotionListener mm1 = new MouseMotionListener(){重写2个};




需要重写的太多,其他方法实际都没用上,因此,用Adapter




public abstract class MouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener




MouseAdapter已经实现了MouseListener, MouseWheelListener, MouseMotionListener接口
可以不需要重写全部方法,因为虽然是抽象类,但没有抽象方法;需要哪个方法就用哪个。
MouseAdapter 1 = new MouseAdapter(){};




this.addMouseListener(1)
this.addMouseMotionListener(l);








----------------------------------------------___+++++++++++++++++++++++++++++++++++++++++++++++__
ShootGame day3




1,先判断每个飞行对象达到越界的条件
2,在一个越界方法里统一处理越界的对象,以及对应数组长度的改变,旧与新数组;
3,碰撞。确定子弹达到碰撞的条件,X1 X2 Y1 Y2,以及英雄机如何得分,或得命和火力
4,碰到的即消失,放数组中最后一个,然后缩容
5,定位英雄机碰撞敌机的坐标
6,状态。给run做分支判断。




















1,删除越界的飞行物  
//每个对象都有的,因此在父类。越界检查的方法体不同,因此抽象方法。需要返回越界的结果,因此boolean
飞机:X不变因为都是下落的。只需要判断y。当y超过整个窗口的高度,就算越界了
蜜蜂:因为X已经设定不越界,因此y和飞机一样。
子弹:子弹是直线上升,当y小于窗口的负的高。+,上负,下正;




for(飞行数组的长度遍历)
FlyingObject f = flying[i]
if(f.outOfBounds()){  //越界了,默认true,也就是越界了
从flyings数组中删除----删除30次。数组也要缩容。每删除一个缩一次效率不高。








SO,
int index=0 //也做新数组的下标
FlyingObject[] flyinglives = new  flyingObject[flyings.length]

for(int i=0;i<flyings.length;i++){
FlyingObject f = flyings[i]
if(f.){

















2,子弹和敌人的碰撞 最复杂
飞行对象被子弹射中,只要子弹的x和y都在飞行对象的4个坐标内就算击中;




3,画分和命




4,英雄机和敌人的碰撞




5,画状态;




撞上之后:
1,敌人消失
2,英雄机减少命








class Bullet{
public boolean shoot(FlyingObject obj)








class FlyingObject{
//敌人被子弹撞
public boolean shoot(Bullet obj)




















X1/Y1 X2
-----------------------
]
]
]
]
]
]
]
【】 ]
【】 ]
-------------------------
Y2








撞上之后:
1,玩家得分
英雄机得命或者火力
2,敌人消失;




玩家不操作只要碰到也会产生效果,因此是定时的,而定时的放到action方法里面




所有子弹对所有敌人的碰撞。所有对所有,用遍历;




for(int i i<bullet.length
Bullet b = bullets[i];
for(int j j<flying.length
//每个子弹跟每个敌人
FlyingObject f = [j]
if(f.shotBy(b)) //撞上了
判断撞的是敌人是得分or类型
得分,加分
类型
判断是给命还是火力












CLASS HERO{
//英雄机撞敌人
bollean hit(FlyingObject obj)
this英雄机
obj敌机








//英雄机撞敌人也是定时发生的,不操作也会碰撞;












final关键字修饰成员变量
声明时初始化或在构造方法中进行初始化,不能在其他方法中初始化。
如果初始化后再给其赋值,会编译错误








“实现接口”与“继承父类”不同,一个类可以实现多个接口,实现的接口直接用逗号分隔。并且,具体类需要实现这些接口中定义的所有抽象方法; 接口间可以存在继承关系,一个接口可以通过extends关键字继承另外多个接口。子接口继承了父接口中定义的所




import, class和package的声明顺序:
package, import, class








子类可以重写(覆盖)父类的方法。方法的重写要遵循“两同两小一大”规则,“两同”即方法名相同,形参列表相同;“两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;“一大”指的是子类方法的访问权限应比父类方法的访问范围更大或相等。 在Java语言中,允许多个方法的名称相同,但参数列表不同,称之为方法的重载。




JVM的内存结构有方法区,堆,栈等。其中方法区用于保存类的各种信息;
栈用于存放程序运行过程当中所有的局部变量;
堆一般用于存储使用new关键字创建的对象。 
类属于Java语言中引用类型的一种,不属于JVM的内存结构




static修饰的方法不需要针对某些对象进行操作,其运行结果仅仅与输入的参数有关。调用时直接用类名引用。由于static在调用时没有当前的对象this,因此在static方法中不能对非static成员(当前对象的属性和方法)进行访问,但是非static方法可以访问static成员。








-------------------------------------------------------------------------------------------




double b = Math.sqrt(25); //静态方法




假设sqrt不是静态的:




无论是m1,m2,m3,m4...m100,
  调用sqrt(25)方法,最终结果都一样
----------------sqrt()方法与对象无关,仅与参数相关








Math m1 = new Math();
double a = m1.sqrt(25); //5




Math m2 = new Math();
double b = m2.sqrt(25); //5




Math m3 = new Math();
double c = m3.sqrt(25); //5




Math m4 = new Math();
double d = m4.sqrt(25); //5












class Aoo{
  int a; //实例变量,只能由对象点来访问
  static int b; 
  
  void show(){ //有this
    System.out.println(this.a);
System.out.println(Aoo.b);
  }
  static void test(){ //没有this,意味着没有对象
    System.out.println(a); //编译错误
System.out.println(Aoo.b);
  }
}








——————————————————————————————————————————————————————————
Aoo o = new Aoo();




class Aoo{
  int a;
  void show(){
    int b;
System.out.println(a); //0
System.out.println(b); //编译错误。局部变量必须同时初始化,成员变量可以在第一次调用初始化
  }
}








class Aoo{
  int a;
  void show(int b){
    int c=5;
  }
}




---------------------------------------------————————————————————————————————————
drop()不适合做为静态的,
因为每个对象drop()之后的结果都是不一样的
意味着与对象有关----所以不适合做为静态的
静态方法只跟参数有关
class Cell{
  int row;
  int col;
  void drop(){
    row++;
  }
  void moveLeft(){
  }
  String getCellInfo(){
    
  }
}




————————————————————————————————————————————————————————




无论a1,a2,a3,...a100,
调sort()方法,只要arr一样,结果一定是一样的
说明sort()方法的操作仅与参数有关,而与对象无关




Arrays a1 = new Arrays();
a1.sort(arr);




Arrays a2 = new Arrays();
a2.sort(arr);




Arrays a3 = new Arrays();
a3.sort(arr);
















假设sqrt()不是静态的:




无论m1,m2,m3,...m100,
.sqrt()时,只要参数是25,最终结果一定是5.0
说明,sqrt()方法仅与参数有关,而与对象无关




Math m1 = new Math();
double a = m1.sqrt(25);




Math m2 = new Math();
double b = m2.sqrt(25);




Math m3 = new Math();
double c = m3.sqrt(25);
——————————————————————————————————————————————————————————
静态方法没有隐式this的传递








静态方法没有隐式的this传递,
没有this意味着没有对象,
而实例成员必须对象来访问,




所以静态方法中不能直接访问实例成员








class Aoo{
  int a; //实例变量,对象点来访问
  static int b; //静态变量,类名点来访问




  void show(){ //有this
    System.out.println(this.a);
System.out.println(Aoo.b);
  }
  static void test(){ //没有this
    System.out.println(a); //编译错误。方法内没有a,由于没有this,也就没法使用this.a调用成员实例变量
System.out.println(Aoo.b);
  }
}








————————————————————————————————————————————————————————
2.多态:
  1)多态的意义:
    1.1)同一类型的引用,指向不同的对象时,有不同的实现
   ------行为的多态:cut(),run()...
1.2)同一个对象,被造型为不同的类型时,有不同的功能
   ------对象的多态:我、你、水...
  2)向上造型:
    2.1)父类型的引用指向子类的对象
2.2)能造型成的类型: 父类+所实现的接口
2.3)能点出来什么,看引用的类型
  3)强制类型转换,成功的条件有两种:
    3.1)引用所指向的对象,就是该类型
3.2)引用所指向的对象,实现了该接口
  4)不符合那两种条件则转换失败,发生ClassCastException类型转换异常,
建议在强转之前使用instanceof判断引用指向的对象是否是该类型








————————————————————————————————————————————————————————
设计规则:
1)所有子类共有的属性和行为,抽到父类中
2)所有子类行为都一样,设计为普通方法
  所有子类行为不一样,设计为抽象方法
3)部分子类共有的行为,抽到接口中
  符合既是也是原则时,使用接口
  接口是对继承的单根性的扩展








——————————————————————————————————————————————————————————




类和类--------------继承
接口和接口----------继承
类和接口------------实现




Inter2 o1 = new Inter2(); //编译错误,接口不能被实例化
Inter2 o2 = new Aoo(); //向上造型--造型为直接父类
Inter1 o3 = new Aoo(); //向上造型--造型为间接父类








interface Inter1{
  void show();
}
interface Inter2 extends Inter1{
  void test();
}
class Aoo implements Inter2{
  public void test(){}
  public void show(){}
}




new Inter1(); //编译错误,接口不能被实例化
Inter1 o1; //正确








nterface Inter1{
  public static final int NUM = 5;
  public abstract void show();
  int COUNT = 6; //默认public static final
  void say(); //默认public abstract




  int NUMBER; //编译错误,常量必须声明同时初始化
  void test(){} //编译错误,抽象方法不能有方法体。接口的方法都是抽象的
}




















class 驼鸟 extends 鸟{
  fly(){
    奔跑
  }
  main(){
    鸟 a = new 驼鸟();
a.fly();
  }
}
class 鸟{
  fly(){
    飞翔
  }
}




















































































--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
框架基础:反射


-------------------------------------------------------------------------------------------
正则表达式只关注格式
X{n,m} n可以等于0,但不能留空。最多个数的m可以留空,留空则表示任意多个X
分组:"()"
(abc || def){3}
abcdefabc   三个数为一个整体;


[^abc]除了ab从的任意字符
[a-z&&{^bc]]a到z中除了b和c以外的任意一个字符,其中&&表示“与”关系
[a-z]a到z中的任意一个字符
[a-zA-Z0-9]a到z,A到Z和0到9中任意一个字符




String regex = "\\d"; //[0-9]
String regex = "\\D"; //[^0-9]








^\w{ 8,10 }$ 表示整体字符串只能出现单词字符8-10个。




(+86|0086) 表示这里可以是+86或者0086。








————————————————————————————————————————




"."点儿,在正则表达式中表示任意一个字符。




"\"在正则表达式中是转意字符,当我们需要描述一个已经被正则表达式使用的特殊字符时,我们就可以通过使用"\"将其转变为原本的意思。




"\"在正则表达式中也有一些预定义的特殊内容:




    \d:表示任意一个数字
    \w:表示任意一个单词字符(只能是 数字,字母,下划线)
    \s:表示任意一个空白字符(\t \r \n \f \x0B)
    \D:表示任意一个非数字字符
    \W:表示任意一个非单词字符
    \S:表示任意一个非空白字符




2、"字符集合 []"




"[]"用来描述单一字符,方括号内部可以定义这个字符的内容,也可以描述一个范围。例如:




[abc]:表示该字符只能是a或者b或者c




[123]:表示该字符只能是1或者2或者3




当我们需要描述所有小写字母时,我们可以使用范围 [a-z],表示该字符可以是任意一个小写字母。




同样还可以使用 [0-9] 来表示该字符可以是任意一个数字。




也可以在多个范围内选择。比如,[a-zA-Z0-9_] 表示该字符可以是任意字母,数字以及"下划线"。




3、"*"、"+"、"?"




通常我们需要描述的字符串会有很多重复出现的元素,但又不需要严格限制出现的次数时,我们就可以使用"*","+"这些量词。




例如:邮箱地址,那么在"@"字符前允许出现若干字符作为用户名。这时候我们就可以使用"\w+"来描述这里至少出现一个单词字符了。




    "+":表示内容可以连续出现至少1次以上
    "*":表示内容出现0-若干次
    "?":表示内容出现0-1次




4、{n}、{n,}{n,m}




除了前面讲到的量词外,有时我们也需要要求内容出现的次数有具体要求。比如手机号码。这时我们要求出现的数字就不能是一个模糊的概念了,而必须要求11位。又比如我们要求用户输入密码时,要求密码是6-15位。遇到这类问题是,我们可以使用:




    {n}:表示内容必须出现n次
    {n,m}:表示内容出现n-m次
    {n,}:表示内容出现至少n次




例如,\d{11} 就表示数字只能出现11位,这样就解决了上述的问题。
1.1.2. 分组




通过上面的内容,我们还无法解决类似下面的问题:




在描述电话号码时,前面有区号,区号的形式可以是0086或者+86




那么我们如何在这两个字符串之间选择?




这时我们可以使用分组"()"。() 可以将内容看做一个整体,()中可以使用"|"来表示或关系。例如,(+86|0086) 表示这里可以是+86或者0086。
1.1.3. "^"和"$"




通过在正则表达式的开始添加"^"以及末尾添加"$"来表示一个整体。若不使用它们,那么正则表达式只匹配某个字符串的部分内容是否符合格式规则,但使用它们,则要求字符串必须从头到尾都满足该格式规则。




例如,^\w{ 8,10 }$ 表示整体字符串只能出现单词字符8-10个。








——————————————————————————————————————————




1.2.1. matches方法




matches()方法的参数要求我们传入一个用字符串描述的正则表达式,然后使用该正则表达式描述的字符串格式规则来匹配当前字符串,若满足那么该方法返回true。否则返回false。




例如:




        String emailRegEx =
                 "^[a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9]{2,4}$"; 
        String email = "bjliyi@tarena.com.cn";
        System.out.println(email.matches(emailRegEx));//true




1.2.2. split方法




String[] split(String regex):参数要求传入一个用字符串描述的正则表达式,然后使用该正则表达式描述的字符串规则来匹配当前字符串,并按照满足的部分将字符串拆分。




例如:




        String str = "java,c#,php,javascript"; 
        String[] array = str.split(",");
        //[java,c#,php,javascript]
        System.out.println(Arrays.toString(array));




1.2.3. replaceAll方法




String replaceAll(String regex,String replacement):参数要求传入一个用字符串描述的正则表达式和一个需要替换的字符串,然后使用该正则表达式描述的字符串规则来匹配当前字符串,并将满足的部分替换为需要替换的这个字符串。




例如:




        String str = "abc123bcd45ef6g7890";; 
        str = str.replaceAll("\\d+", "数字");
        System.out.println(str);//abc数字bcd数字ef数字g数字












——————————————————————————————————————————————————————
^[abc]{3}$  java中的字符串中[abc]{3}不带^ $也表示全匹配,其他语言不行。
^必须要abc开头
$必须abc结尾




[]表示可选,没有表示必须
fancq@tedu.cn
jackson,25,男,5000,2008-12-22
[a-zA-z]{1,20},[0-100],["男""女"],[\d],[\d]-[1-12]-[1-31]
[a-zA-Z0-9_]@[a-zA-Z0-9_].([a-zA-Z]) 缺量词




.在表示任意字符,需要.则需要转义字符
[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\.[a-zA-Z]+) +




()表示分组
java中.没有特殊含义,不同与正则表达式。需要再补\








面向对象3:
封装 继承 多态




object类有toString和equals方法,继承了建议重写该方法




==比较的是地址指向的对象是否一致
equals比较的是对象








void dosome(Object obj){}
int i=1;
基本类型不继承于Object,不是对象。因此dosome(i)是报错的
可以定义一个类Integer,该类是继承Object的




基本数据类型不能直接参与面向对象开发,因此需要包装类




更推荐使用valueOf,Integer但只用一个字节保存,127到-127之间,超过比如128则重新开辟一个空间,也就是new
double的话valueOf都是直接new新对象;












String str1 = "123.123";
String str = "123";
//int i1=Integer.parseInt(str1); //编译报错,数值格式异常,int存不下123.123
int i=Integer.parseInt(str);  
'''''''''''''''''''''








//jdk1.5开始类自动装箱。这里实际上已经变成:
int i=Integer.valueOf(123).intValue();编译器自己补充了
int i=Integer.valueOf(123); 
//jdk1.5开始类自动装箱。这里实际上已经变成:
Integer in=Integer.valueOf(123);编译器自己补充了
Integer in =123;




软件:
box2d:模拟物理效果 c语言写的 ->jbox2d
JMonkey Engine




---------------------------------------------------------------------------------------
day03 Collection








/**
 * java.util.Collection
 * 集合
 * 集合和数组一样,用于保存一组元素,但是其提供了用于操作和维护集合元素的相关方法,使用起来更便捷
 * Collection接口定义了所有集合都具备的功能
 * 其派生了两个子接口
 * java.util.List 可重复集且有序
 * java.util.Set不可重复集,大部分实现类是无序的
 * 元素是否重复是依靠元素自身equals比较的结果
 * 
 */




跟之前学的的接口案例一样,不能new 接口,但是可以这样:

接口 引用=new 该接口的实现类 




Collection c = new ArrayList();//是接口,不能new,但是可以new其实现类

/*
* boolean add(E e)
* 将给定元素添加到集合中
* 添加成功则返回true
*/

c.add(1); //数据类型也可以,但是其实是自动装箱了




















/*
 * boolean contains(E e)
 * 该方法会根据给定元素与集合现有元素equals
 * 比较的结果来判定结果是否包含该元素
 * 
 * 如果Point的equals方法注释掉,则调用==方法判断,结果返回的是false————因为都new了对象,因此地址值不同
 */












Calendar calendar = Calendar.getInstance();
/*
* Calendar的实现类都重写类toString,只是直观看不出具体日期

*/
System.out.println(calendar);
/*
* Calendar ->Date
* 使用Calendar提供的方法:
* Date getTime();
* 该方法会将当前Calendar表示的日期以一个Date类型实例返回。
*/




Date date = calendar.getTime();
System.out.println(date);

/*
* Date->Calendar
* Calendar提供的方法:
* void setTime(Date date)
* 该方法可以使当前Calendar表示给定的Date所表示的日期
*/
calendar.setTime(date);
























//设置一个分量值,其他尽量不改变
calendar.set(calendar.DAY_OF_WEEK,Calendar.MONDAY);
System.out.println(calendar.getTime());
——————————————————————————————————————————————————————————————




什么是迭代器呢?
其实就是集合的取出元素的方式




集合的size()跟数组的length不同,集合的是当前的元素个数,长度是不固定的,最大长度也就是int的长度








集合的isEmpty判断的只是是否空元素,而集合是中是存在的,并不是null的。null则是集合不存在




substring(intdexbegin,indexend) 可以中间截取
---------------------------------------------------------------------------------------------------------------
day04 Collection




集合中的常用方法:
add
removeAll
containsAll




集合不能像数组一样用下标获取元素,只能用Iterator迭代器




/*
 * Iterator的三个方法:
* boolean hasNext()
* E next() 返回迭代的下一个元素。
* void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
 */








-----------------------------------------------------------------------------------
/*
 * 在使用迭代器遍历集合的过程中
 * 是不可以通过集合的方法增删元素的。
 */
//c.remove(str);  //这是c也就是Collection的删除方法,错误的!!
/*
 * 迭代器提供的remove方法可以将调用迭代器next方法取出的元素从集合中删除。
 */
it.remove();  //这是迭代器的删除方法,正确的








------------------------------------------------------------------------------------
增强型for循环,也叫新循环,增强循环,for each ,JDK1.5以后推出的一个新特性
仅仅用来遍历集合或数组元素使用




特性都是编译器认可,不是虚拟机认可。
增强for作为一个新特性也是编译器认可的,编译器自动变成了Iterator,因此
增强for循环的判断中删除元素还是不能用集合的方法,还是只能用Iterator的增删方法。然而不能再次调用迭代器,再用迭代器的增删方式,因为for其实已经用了迭代器的方法了。




所以
使用新循环遍历集合元素时不可以通过集合分方法增删元素,因为本质就是迭代器遍历




---------------------------------------------------------------------------------------
泛型:
第一位不能是数字,后面可以。如<T1>可以,<1T>不行,错误




调用泛型类的时候必须是数据类型的不能是基本类型,如
class Point<T>{
private T x;
private T y;
构造方法....
}




class TestPoint{
public static void main(String [] args){
Point <Integer> p1 = new Point <Integer> ();
Point <Double> p2 = new Point <Double> ();
Point <String> p3 = new Point <String> ();
}




}
还可以设置多个类型
class Point<X,Y>{
private X x; //X类型的x
private Y y; //Y类型的y
构造方法....
}




class TestPoint{
public static void main(String [] args){
Point <Integer,Double> p = new Point <Integer,Double> ();
Point <Double,Double> p2 = new Point<Double,Double> ();
Point <String,Integer,> p3 = new Point <String,Integer> ();
}




}




-------------------------------------------------------




泛型的实际原型都是Object,new出来在堆里面就是Object,跟迭代器一样其实质也算编译器实现的,而不是虚拟机认可的




------------------------------------------------------------------------------------
Point <Integer> p1 = new Point<Integer>(1,2);
//编译器检查实际的值是否为Integer
p1.setX(12);
//p1.setX("12"); //编译不通过,不是Integer值

/*
* 编译后的class文件中有强制类型转换
* int x1 =(Integer)p1.getX();  
*/
int x1= p1.getX();
System.out.println("x1:"+x1);
/*
* 可以不指定泛型,不指定则使用原型Object
*/
Point p2 =p1;
p2.setX("一");
String x2 = (String)p2.getX();
System.out.println("x2:"+x2);
//堆内存中的x的类型已经被p2改为类String类型
x1 =  p1.getX(); //类造型异常
System.out.println("x1:"+x1);  //常见面试题:这里输出值是?答:无法走到这一步,上面已经异常了








-----------------------------------------------------------------------------------------












数组和集合类同是容器,有何不同:
数组虽然也可以存储对象,但长度是固定的。而集合长度是可变的
数组中可以存储基本数据类型,集合只能存储对象




集合类的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象









为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同。
这个存储方式称之为:数据结构








集合作为一个容器,应具备哪些功能,如已学的StringBuffer容器
增删改查
___________________________________________________________________________________________




集合框架



--ArrayList 更适合查询
--LinkedList 更适合插入和删除,首尾更快
--Vector
-List
Collection--
-Set
--HashSet
--TreeSet




可以通过下标操作的:get set 重载的remove
调用clear()方法之后再输出




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++




List的set和remove方法均返回被加入或删除的指定位置的元素
List <Integer>list = new ArrayList<Integer>();
subList:




 对子集的操作就是对原来集合该部分元素的操作




集合转数组:--------------------------------->      toArray:
给的数组能用就用,不能用就自己new一个
比如集合只有3个元素,
String[] array= c.toArray(new String[c.size()]);
c.size()是根据集合的长度给出数组长度,如果给多了就为剩下的就为空,如果少了toArray就自己new一个同类型的数组



当数组转换成集合后,对集合的操作就是对数组的操作,比如set后集合变了,数组也一样变了




从数组中转换来的集合是不能添加新元素的
数组转集合:--------------------------------->asList()
//数组转成集合。调用Arrays的第一个方法也就是asList()
List<String> list = Arrays.asList(array);




 * 数组切换为集合
 * 使用数组的工具类Arrays的静态方法asList //静态方法只跟参数有关,也就是只传参即可
 * 需要注意,仅能转换为List集合




/*
 * 向集合中添加元素“five”
 * 数组转换的集合是不可以添加新元素的
 * 因为这会导致数组的扩容,就不能表示原来的数组了。
 * 所以添加元素会抛出不受支持的异常
 */




//创建一个新的的同时把旧的作为传进构造方法中去,但是不能是重复的,否则只会有一个元素。不同对象也可以传进去
/*
 * 所有集合都支持一个可以用Collection作为参数的构造方法。
 * 该构造方法的作用是在创建当前集合的同时包含给定集合中的所有元素
 */








List<String > list1 = new ArrayList<String>(list); 
//将旧的list传进新建的list1中去,这样新的list1就有了旧的list的元素,而且list1也可以增加新的元素




//list1.addAll(list); //将旧集合的元素整体传进新集合,用addAll更多,省事,简单
list1.add("five");
System.out.println(list1);
}




















——————————————————————————————————————————————————
day04 Homework test01
boolean re= c1.remove("two");  //remove(Object o);必须是被删除的元素,而不能是下标

-------------------------------------------------------------------------------------------------------
day05:




List排序:只是对集合的操作
数组的工具类:Arrays 此类包含用来操作数组(比如排序和搜索)的各种方法。此类还包含一个允许将数组作为列表来查看的静态工厂。 包括
静态的方法asList,
静态的sort方法,
静态的toString方法
静态的copyOf方法
静态的equals方法








集合的工具类:Collections 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。




常见面试题:
Collections和Collection的区别是?
colletion是集合的接口,collections是工具类
联想,对于线程池executorService的executor和exetutors也一样,
前者是接口,后者是工具类,有各种方法比如静态的newFixedThreadPool(int nThreads)
——————————————————————————————————————————————
/**
 * 结合排序
 * 使用集合的工具类Collections的静态方法sort
 * 需要注意的是,仅能对List集合排序
 * sort方法会对List集合元素进行自然排序(从小到大)
 * 
 */








哪个类实现了Comparable,泛型写自己就行了
但是用系统的Comparable比较方法具有侵入性
public class Point implements Comparable<Point>{ 
......
@Override
/**
* 该方法的作用是用于判断当前对象this与参数对象o比较大小
* 返回值不关注具体数值,只关注取值范围
* 当返回值>0 : 当前对象大于参数对象
* 当返回值<0 : 当前对象大于参数对象
* 当返回值=0 : 两个对象相等
*/
public int compareTo(Point o) {
//由于x和y是坐标,因此比较到原点的距离
int len = this.x*this.x+this.y*this.y;
int olen = o.x*o.x+o.y*o.y;
return len-olen;
//反过来排序,由大到小。认为谁大就返回谁的值
//return olen-len;
}




}




如对汉字进行排序,具体可看day05----> SortListDemo3类 
list.add("苍老师");
list.add("范老师");
list.add("小泽老师");
String类是final的,因此不能重写。但是Collections的sort提供了重载的方法




sort的重载方法
public static <T> void sort(List<T> list,Comparator<? super T> c)








Comparator相当与第三方,给两个参数,我帮你进行比较
Comparable是自己和别人比




——————————————————————————————————————
队列Queue:FIFO
栈Stack:先进后出,相当于底部堵死的,比如弹夹。有后退功能的时候用,如Windows进入文件夹后后退前进功能。
相当于管道,只能首尾增删
Queue:
boolean offer(E e);将一个对象添加至队尾,如果添加成功则返回
E poll();从队首删除并返回一个元素
E peek();返回队首的元素(但并不删除)




Queue也继承了Collection方法,因此也是集合的一种,Collection的方法也能用
LinkedList继承了Deque,而Deque继承了Queue








不使用迭代器只遍历一遍????




Queue的遍历建议用while,当队列的size大于0则一直把数据poll出




——————————————————————————————————————————

双端队列Deque(继承自Queue)
push入栈
pop出栈
是最常见的方法




LinkedList继承了Deque,而Deque继承了Queue




stack.push("1");
stack.push("2");
stack.push("3");
stack.push("4");
System.out.println(stack);  //push是先进后出,输出是4321
















————————————————————————————————————————————
查询表:




Map查找表,相当于多行两列
贴个标签
如需要查找某人成绩:




key value
语文 98
数学 99
英语 97
物理 96
化学 98




Map的key不可以重复的




/**
 * java.util.Map
 * 查找表,常用的实现类:HashMap(散列表)
 * 
 * Map的每一个元素分为两部分:key , value
 * 其中key在Map中不允许重复(equals判断)
 */












Map重写了toString,输出的数值在{}内,跟字符串一样




——————————————————————————————————————————————————
Map<String,Integer> map = new HashMap<String,Integer>();

map.put("语文",99);
map.put("数学",98);
map.put("英语",97);
map.put("物理",96);
map.put("化学",99);












System.out.println(map);
map的修改Entry只需要继续调用put方法即可,因为map的key不能有重复,有则覆盖,因此修改数据也就是还是用put方法
————————————————————————————————————————————————
Map遍历有3种方式:
1:遍历所有的key,
2:遍历每一组键值对(Entry)
3:遍历所有的value(相对不常用)




————————————————————————————————————————————————
1 * 遍历所有的key
keySet()




    返回此映射中包含的键的 Set 视图。该 set 受映射支持,所以对映射的更改可在此 set 中反映出来,反之亦然。如果对该 set 进行迭代的同时修改了映射(通过迭代器自己的 remove 操作除外),则迭代结果是不确定的。set 支持元素移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作可从映射中移除相应的映射关系。它不支持  add 或 addAll 操作。 








+++++++++++++++++++++++++++++++++++++++++++++++++——————————=++++++++++++++++++++++++++++++++++++++++++++++++




/*
* 遍历所有的key
* Set keySet()
* 将Map中所有的key存入一个Set集合后返回
* 遍历该Set集合等于遍历了所有的key
*/




Set<String> keySet = map.keySet();
for(String key: keySet){
System.out.println("key: "+key);
}








——————————————————————————————————————————————————————
2* 遍历每一组键值对




Entry是Map的内部类,每new一个Entry就相当于有一组键值对




/*
* 遍历每一组键值对
* Map中每一组键值对都是用一个Entry的实例保存的,Entry是Map的内部类
* Set entrySet()
* 该方法会将Map中每组键值对(若干Entry实例)存入一个Set集合后返回
*/




Set<Entry<String ,Integer>> entrySet = map.entrySet();
for(Entry<String,Integer> e : entrySet){
String key =  e.getKey();
Integer value = e.getValue();
System.out.println(key+":"+value);
}








Set的泛型就是Entry,然而Entry自己也有泛型!!如Entry<k,v> 
Map.Entry<K,V> 常用方法,用来获取Entry里面的Key和Value,分别是:
getKey()
getValue()
————————————————————————————————————————————————
3:遍历所有的value(相对不常用)




 values




Collection<V> values()




    返回此映射中包含的值的 Collection 视图。该 collection 受映射支持,所以对映射的更改可在此 collection 中反映出来,反之亦然。如果对该 collection 进行迭代的同时修改了映射(通过迭代器自己的 remove 操作除外),则迭代结果是不确定的。collection 支持元素移除,通过 Iterator.remove、Collection.remove、removeAll、retainAll 和 clear 操作可从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。




    返回:
        此映射中包含的值的 collection 视图
——————————————————————————————————————————————————
/*
* 遍历所有的value
* Collection values()
* 该方法会将所有的value存入一个集合后返回
*/
Collection<Integer> values = map.values();
for(Integer value : values){
System.out.println("value"+value);
}




%…………%……%……%……%……%……%……%……%……%……%……%……%……%……%……%……%……%……








为毛用集合接口Collection????????????????????????????????????????
答:因为
values方法 返回此映射中包含的值的 Collection 视图。所以接收的也当然是Collection啦




map的方法有keySet和entrySet和values方法,第一个和第二个都返回Set视图,当然
其中第一个的keySet返回此映射中包含的键的 Set 视图,而entrySet返回此映射中包含的映射关系的 Set 视图。
最后,values方法 返回此映射中包含的值的 Collection 视图。所以接收的也当然是Collection啦




————————————————————————————————————————————————
散列算法:相当于酒店的前台,根据身份证查询,也就是key。key通过hashcode()计算存放位置,get的时候
调用hashcode查询到指定位置。
缺陷:使用不当,效率也低。应该避免一个空间存多个值,如保证身份证号不同




尽量避免两个hashcode一样
相同的key就是替换value,equals比较的是true就是一样
hashcode一样,key比较的却不是true,也就是身份证号hashcode一样,但不是同一张身份证key。




********************就是Map中尽量避免链表?????????????????????????
理解:链表不是连续存储的,而是位置不固定的,一个元素只链接上一个和下一个,其他是不知道的,找也是根据算法值找数据的。




hashmap存储时不确定具体位置,而是通过算法给出hashcode值,算出存储位置,而获取的时候也是根据hashcode直接获取key从而返回value。




1.2. HashMap
1.2.1. hash表原理




HashMap是Map的一个常用的子类实现。其实使用散列算法实现的。




HashMap内部维护着一个散列数组(就是一个存放元素的数组),我们称其为散列桶,而当我们向HashMap中存入一组键值对时,HashMap首先获取key这个对象的hashcode()方法的返回值,然后使用该值进行一个散列算法,得出一个数字,这个数字就是这组键值对要存入散列数组中的下标位置。




那么得知了下标位置后,HashMap还会查看散列数组当前位置是否包含该元素。(这里要注意的是,散列数组中每个元素并非是直接存储键值对的,而是存入了一个链表,这个链表中的每个节点才是真实保存这组键值对的。)检查是否包含该元素时根据当前要存入的key在当前散列数组对应位置中的链表里是否已经包含这个key,若不包含则将这组键值对存入链表,否则就替换value。




那么在获取元素时,HashMap同样先根据key的hashcode值进行散列算法,找到它在散列数组中的位置,然后遍历该位置的链表,找到该key所对应的value之后返回。




看到这里可能有个疑问,链表中应该只能存入一个元素,那么HashMap是如何将key-value存入链表的某个节点的呢?实际上,HashMap会将每组键值对封装为一个Entry的实例,然后将该实例存入链表。
1.2.2. hashcode方法




HashMap的存取是依赖于key的hashcode方法的返回值的,而hashcode方法实际上是在Object中定义的。其定义如下:




    int hashCode()




重写一个类的hashcode()方法有以下注意事项:




1、若一个类重写了equals方法,那么就应当重写hashcode()方法。




2、若两个对象的equals方法比较为true,那么它们应当具有相同的hashcode值。




3、对于同一个对象而言,在内容没有发生改变的情况下,多次调用hashCode()方法应当总是返回相同的值。




4、对于两个对象equals比较为false的,并不要求其hashcode值一定不同,但是应尽量保证不同,这样可以提高散列表性能。




——————————————————————————————————————————————————————————
1.2.3. 装载因子及HashMap优化




在散列表中有一下名词需要了解:




    Capacity:容量, hash表里bucket(桶)的数量, 也就是散列数组大小.
    Initial capacity:初始容量, 创建hash表的时 初始bucket的数量, 默认构建容量是16个元素. 也可以使用特定容量.
    Size : 大小, 当前散列表中存储数据的数量.
    Load factor:加载因子, 默认值0.75(就是75%), 向散列表增加数据时如果 size/capacity 的值大于Load factor则发生扩容并且重新散列(rehash).




那么当加载因子较小时候散列查找性能会提高, 同时也浪费了散列桶空间容量. 0.75是性能和空间相对平衡结果. 在创建散列表时候指定合理容量, 从而可以减少rehash提高性能。








————————————————————————————————————————————————————————




1.3. 有序Map
1.3.1. LinkedHashMap实现有序的Map




Map 接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是将存放元素的顺序。




需要注意的是,如果在Map中重新存入已有的key,那么key的位置会不会发生改变,只是将value值替换。




————————————————————————————————————————————————————————————




HashMap Hash算法




Map的内部其实就是一个数组,但是比数组快












重写equals的同时也要重写hashcode
具体的重写eclipse可以完成,但是面试中常用
Capacity :容量,hash表里bucket(桶)的数量




hashcode应该是无论调用多少遍都是不变的




hashcode的Initial Capacity容量默认就是16 也就是16个元素
Size 当前散列表中存储数据的数量
load factor 0.75 元素个数不能超过3/4,也就是12个元素,一旦超过就扩容,每次都是翻倍扩容  16->32-->64




Map是根据散列算法算的。哪怕16个空间也有可能一个空间存多个元素
如3*5=15 但是1*15也是15,hashcode算出都是15,结果就存同一个位置了








每次扩容之后之前的都要重新计算hashcode,重新存放位置
如存放75万条数据,最好一次性估算容量
Map<String,Integer> map = new HashMap<String ,Integer>(10000000000); //自定义一百万个元素大小




Map在大数据中常用。根据一次算法告诉你位置。




——————————————————————————————————————————————————




public class SortListDemo3 {




public static void main(String[] args) {
List<String> list = new ArrayList<String>();

list.add("苍老师");
list.add("范老");
list.add("小泽老师");

System.out.println(list);
MyComparator com = new MyComparator();
/*
* 比较大小的规则。

* 该sort方法有个明显的缺点:
* 当我们在使用sort方法排序时,该方法要求集合元素必须实现comparable接口,
* 这就导致sort方法对我们的类有较强的侵入性

*/
//Collections.sort(list,com);


//只用一次的话就用匿名内部类的形式
Collections.sort(list,new Comparator<String>(){
public int compare(String o1,String o2){
return o1.length()-o2.length();
}
});
System.out.println(list);
}




}
/**
 * 提供额外比较器的好处1:不要求元素实现comparable接口(侵入性:也就是代价高昂。
 * 如Point类,只是用sort一句,但是却需要实现comparable接口,然后还要重写个接口,如果将来不需要了,这些代码就没用了) 
 *面向接口开发,而不应该面向类开发。调用者和被调用者的关系完全模块化,涉及到框架,比如Spring框架
 *
 *重载的sort方法有两个好处:
 *1,由于提供了额外的比较器,所以不要求集合元素必须实现Comparable接口,这就没有侵入性
 *2:有些元素自身已经实现了Comparable接口,并且定义了比较规则,但是又不满足这里排序需求,
 *也可以使用额外的比较器来定义比较规则,从而满足排序需求
*/
class MyComparator implements Comparator<String>{
public int compare(String o1,String o2){
return o1.length()-o2.length();
}
}












——————————————————————————————————————————————
day06
file操作




通常写相对当前目录,不写绝对路径




File file = new File("./demo.txt");
Linux只认/,Windows也认,但Windows用\




实际应该:("."+File.separator+"demo.txt");




file获取信息属性的方法:
String getName()
long length()
long lastModified() //获取的是毫秒值,需要用Date转换




boolean canRead()
boolean canWrite()
boolean isHidden()




file不能访问文件内容




file的创建方法:
createNewFile()








file文件删除方法:delete()
目录创建:
File dir = new File("demo");
dir.mkdir()
创建多级目录:
File dir = new File("a/b/c/d/e");
dir.mkdirs()




-————————————————————————————————————————
获取目录下的所有子项需要用用listFiles()方法,并且获取给File类型的数组,通过遍历输出




File dir = new File(".");
if(dir.isDirectory()){
/*
* File[] listFiles()
* 该方法可以获取当前目录下的所有子项

*/

File[] subs = dir.listFiles();
for(File sub : subs){
if(sub.isFile()){
System.out.print("文件: ");
}
else if(sub.isDirectory()){
System.out.print("目录: ");
}
System.out.println(sub.getName());
}




————————————————————————————————————————————
file的过滤:
获取子项的listFile方法里面new 一个过滤方法FileFilter




但是FileFilter是一个接口,只有一个boolean accept方法,需要重写该方法








以下用匿名内部类实现,因为只用一次








File dir = new File(".");




File [] subs = dir.listFiles(new FileFilter(){
//重写FileFilter的boolean accept方法
public boolean accept(File file){
System.out.println("正在过滤:"+file.getName());
//设置过滤规则
//return file.isFile();

//过滤以"."开头的文件。
//return file.getName().startsWith(".");

return file.getName().endsWith("txt");

}
});
//subs存的是经过过滤的的数据,遍历输出
for(File sub: subs){
System.out.println(sub.getName());
}
——————————————————————————————————————————
删除多级目录,day06的test.java,实用案例。








使用递归
当发现每次都要把所有的方法都走一遍,就用递归

public static void delete(File f){
if(f.isDirectory()){
//先将其所有子项删除
File[] subs = f.listFiles();




//自己本身就是delete方法,因此调用自己的delete方法,把子项传进去
for(File sub: subs){
//递归调用,自己的内部调用自己
delete(sub);
}
}f.delete();
}
一定要有条件判断,不能百分之百干,否则就是死循环。
不能进太多层,否则很消耗资源
——————————————————————————————————————————
关于递归的电影:比如,盗梦空间








listFile还有一个重载方法,获取




listFiles(FileFilter filter),其中FileFilter是接口,如果要用也要实现然后重写,跟
comparable与comparator一样。使用匿名内部类




——————————————————————————————————————————————————








/**
 * 1:编写一段代码,不超过20,要求完成从1+2+3一直加到100,并输出最终结果
 * 在代码中不能出现for,while关键字
 * 
 * 
 * 2:有20块钱,买汽水,1块钱一瓶,然后3个瓶盖可以换一瓶汽水,两个空瓶也可以换一瓶汽水,总共能买多少瓶汽水?
 * 20P ->20/2=10P,20P--> 30/3=10P->
 *  
 */
























有20块钱,买汽水,1块钱一瓶,然后3个瓶盖可以换一瓶汽水,两个空瓶也可以换一瓶汽水












    20C->------------>    ->10C
 ->>>10P   |->5P
20P-> 10C-->    ->10E|  
20E-> 10P -> ->5C   |->5C
10E -> 5P-
->5E 












——————————————————————————————————————————————
文件操作RandomAccessFile
















/*
 * RandomAccessFile两个常用的构造方法:
 * RandomAccessFile(File f,String mode)
 * RandomAccessFile(String path,String mode)
 * 
 * mode是创建模式,常用的对应两个字符串:
 * “rw”读写模式,对文件进行读取也可以写入
 * “r” 只读模式,仅对文件进行读取操作
 */




//可以直接提供创建文件,不需要另外File file = new File("raf.dat");
RandomAccessFile raf = new RandomAccessFile("raf.dat","rw");
RandomAccessFile raf = new RandomAccessFile("raf.dat","rw");
/*
 * void write(int d)
 * 向文件中写入一个字节,写的是给定的int值对应的二进制的“低八位“
 *  vvvvvvvv
 * 00000000 00000000 00000000 00000001
 * 不能直接操作
 */
//1写的不是1,而是1的二进制
raf.write(1);
System.out.println("写入完毕");
raf.write(97);
System.out.println("写入完毕");
raf.write(-1); //-1如果只有低8位存进去,也就00000...0000.11111111也就是255.如果存32位4个字节才是-1
System.out.println("写入完毕");
raf.close();




————————————————————————————————————————————




  int read(byte[] b)
          将最多 b.length 个数据字节从此文件读入 byte 数组。
 int read(byte[] b, int off, int len)
          将最多 len 个数据字节从此文件读入 byte 数组




如:
byte[] data = new byte[32]; //现在data数组长度32字节,内容为0




raf.read(data); //通过read方法,现在data已经装了32字节数据。
read(byte[] b);方法返回的是int类型的已经读取数据的数组长度




return String(data,"UTF-8");//返回的data已经是数组长度的数据




——————————————————————————————————




RandomAccessFile  raf = new RandomAccessFile("raf.dat","r");
/*
* 从文件中指针当前位置读取一个字节,并以十进制的int值返回。若返回值是-1,-1是一个字节永远无法
* 表示的数,表示-1需要用到4个字节,32位,前面都是111...     则读取到了文件末尾了
*/








write和read一次只能操作一个字节
int read 一次只能操作一个字节
int read(byte[] d) 尝试最多读取给定数组lenght的字节并存入数组








raf的读的方法:
read
readLine
readInt
readShort
readDouble
readLong
readByte




但是没有readString方法,可以自定义个readString的方法




public static String readString(RandomAccessFile raf , int len) throws IOException{
byte[] data = new byte[len];

raf.read(data);
return new String(data,"UTF-8");
}
















-----------------------------------------------------------------------------------------------------




day07 AM
————————————————————
int max = Integer.MAX_VALUE;
int的长度是4个字节,long是8个字节。然而write只写低8位
/*    vvvvvvvv
 * 01111111 11111111 11111111 11111111
 *  
 * 00000000 00000000 00000000 00000001
 */
因此造成int前面的3的没写入。因此需要通过移位每次把8位写进去。如果是Long型,则需要8次,int的4次,如下:




raf.writeInt




raf.write(max>>>24);
raf.write(max>>>16);
raf.write(max>>>8);
raf.write(max);
/*
* writeInt方法一次性将给定的int值的4个字节全部写出,等同于上面4句,原理是一样的,详见源代码
*/
raf.writeInt(max);

raf.writeLong(123L);
raf.writeDouble(123.123)
















-————————————————————————————————————————————
System.out.println("pos"+raf.getFilePointer());
把指针移回0位置
raf.seek(0)
但是也只读到低8位的值,也就127,而不是int的值。因此需要左移。readInt已经实现了








RandomAccessFile是基于指针的,可以随意的读取指定位置,也是可以返回位置读取




流跟水管一样,一次性读完,需要再读取再重新读取




RandomAccessFile是可以读也可以写,但是raf写入的是二进制。因为写入的值字节流,因此也不需要像高级流那样指定编码
——————————————————————————————————————————————————————




比如获取int和long和double的最大值:








RandomAccessFile raf = new RandomAccessFile("raf.dat","rw");




int maxint = Integer.MAX_VALUE;
long maxlong = Long.MAX_VALUE;
double maxdouble = Double.MAX_VALUE;
raf.writeInt(maxint);
raf.writeLong(maxlong);
raf.writeDouble(maxdouble);
System.out.println("Ding!Write Finished!");
//写完int4个字节和long8个字节后FilePointer实际已经在第九个字节位置了,需要把指针移回0位置读取
raf.seek(0);
System.out.println("MaxInt: "+raf.readInt()); 
System.out.println("MaxLong: "+raf.readLong());
System.out.println("MaxDouble: "+raf.readDouble());








raf如何将用户输入的每一行字符串写入到文件中呢?虽然有readLine方法,但是没有writeLine方法啊?




解决:参考作业day06的Test09
将输入的line字符串调用getBytes()给转成字节流,因为raf的write只能写入int类型
raf.write(line.getBytes());




——————————————————————————————————————————————








day07 PM
——————————————————




输入流:读
输出流: 写
参照物:程序




节点流,低级流:也就是从数据源搬运数据的,必然会有的
处理流,高级流: 处理数据,简化操作的,可选的




IS 所有的输入流的父类,
OS 所有的输出流的父类,
void write(int d) 
void write(byte[] d)








若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。但是有支持添加参数的重载方法:
FileOutputStream(File file, boolean append)
          创建一个向指定 File 对象表示的文件中写入数据的文件输出流。








/**
 * java.io.FileOutputStream
 * 文件输出流
 * 
 * 流根据功能分为:
 * 输入流:输入流是用来读取数据的
 * 输出流:输出流是用来写出数据的
 * 
 * InputStream是所有字节输入流的父类
 * OutputStream是所有字节输出流的父类
 * 
 * 流还分为字节流(低级流)与处理流(高级流)
 * 低级流:数据源明确,真实负责“搬运数据”的流读写一定要有低级流
 * 高级流:不能独立存在,没有意义。它是用来处理其他流的,通过处理其他流来简化我们的读写操作
 * 
 * 文件输出流FileOutputStream是一个低级流,作用是向文件中写出数据
 * 
 */








流要么清空了重写,还有支持追加模式
FileOutputStream fos = new FileOutputStream("fos.txt",true);
多了个true表示追加




/*
 * FileOutputStream支持第二个参数是一个boolean值,该值为true时,为追加操作。
 * 那么通过该流写出的内容会追加到文件末尾,否则就是覆盖写操作,即先将该文件原有数据全部删除,再开始本次流
 * 写入的内容
 * 一个参数的构造方法就是覆盖写操作
 */












————————————————————————————————————————————
FileInputStream fis = new FileInputStream("fos.txt");
byte[] data = new byte[100];
int len = fis.read(data);
String str = new String(data,0,len,"UTF-8");




高级流不仅可以处理低级流,也可以处理其他高级流。高级流的功能是可以叠加的








FileInputStream fis = new FileInputStream("demo.txt);
InputStreamReader isr = new InputStreamReader(fis);//这里可以指定编码
BufferedReader br = new BufferedReader(isr);
















所有高级流都一样,只需要关闭高级流即可,因为其会自动先把下一级的关闭




FileInputStream fis = new FileInputStream ("tts.zip");
FileOutputStream fos = new FileOutputStream("tts2_copy.zip");




BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);




也还是比上面的10k的数组形式的慢,因为只有8192字节。实际也是一次读一组,放到缓冲区先








——————————————————————————————————————————————————————
缓冲输出流的注意事项:
假如输入的字符没装满Buffered的长度,Buffered是先不写的,除非调用flush或者在关流的close之前写出。
用了Buffered,记得要调用flush(),如果频繁调用也会增加写入次数,耗费资源,看需求,是需要及时性还是效率
/*
* flush方法会强制将缓冲流缓冲区中已缓冲的数据一次性写出
*/








——————————————————————————————————————
对象流




只要想往文件写就必须用到低级流




接口有
1,约束的接口——常见的有约束行为,需要重写的
2,签名接口——比如Serializable接口




public class Person implements Serializable{多了个方法,只是方法不需要自己实现




————————————————————————————————————————————————
FileOutputStream fos = new FileOutputStream("person.obj");

ObjectOutputStream oos = new ObjectOutputStream(fos);
/*
* writeObject方法要求写出的对象必须实现序列化接口。否则抛出异常
*/
oos.writeObject(p);
System.out.println("Ding!");
oos.close();




————————————————————————————————————————————
写进的Person.obj文件是二进制的,也比一半字符的大小大,因为需要保存每个字符串的类型等等信息。




————————————————————————————————————————————
OIS:








不是什么都能读成对象
/**
 * java.io.ObjectInputStream
 * 对象输入流,是一个高级流,作用是可以读取一组字节(必须是ObjectOutputStream将一个对象写出的一组字节)
 * 并还原为对象
 * 
 */
————————————————————————————————————————————








FileInputStream fis = new FileInputStream("person.obj");
ObjectInputStream ois = new ObjectInputStream (fis);




//读取出来的也是还原成object对象,需要强转
Person p = (Person)ois.readObject();

System.out.println(p);








__________________________________________________________________________________________________
transient
如果某些信息不需要保存,可以在声明的时候,private修饰的后面加上transient关键字。当然
再次读取也是没有的




/*
 * transient关键字修饰的JAVA 属性在进行对象序列化时会被忽略,将不需要的属性值忽略可以达到对象
 * “瘦身”的目的,减少资源消耗。
 */

private transient List<String> otherInfo;




——————————————————————————————————————————————
/*
* writeObject方法要求写出的对象必须实现序列化接口。否则抛出异常

* 该方法首先是oos将给定对象转换成了一组字节,然后再通过fos将这组字节写入到文件person.obj中
* 这里经历的两个操作都有专业名词:
* 将对象转换为一组字节的过程称之为:对象序列化
* 将字节写入到磁盘的过程称为:持久化

*/
oos.writeObject(p)








DAO 数据访问对象  Data Access Object




——————————————————————————————————————————————
public class Person implements Serializable{








/**
* 根据当前类的属性算出来的一个版本号,版本号也会保存到写入的文件中。
* 只要该了属性都会重新生成版本号,
* 如果和读取的文件的版本号比对不一致了就会抛出无效类异常
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String gender;




版本号不对,反序列一定失败的。
版本号可以自定义的








还原,如果原来有的,现在也有,就还原;如果原来有的,现在没有,比如age改成salary就忽略;
如果原来没有,现在有的,比如文件没有salary,但是现在有,就使用默认值,int的0




* 当一个类实现类serializable接口后,应定义一个常量serialVersionUID,
* 这个是序列化版本号,该值直接决定当前类实例在进行反序列化时的成功与否。
* 当使用ObjectInputStream对一个已经序列化的对象进行反序列化时,会首先检查该对象
* 的版本号与当前类的版本是否一致,不一致则直接反序列化失败。
* 若一致则可以还原。那么若当前类的结构发生了改变,则在进行反序列化时启用兼容模式,即
* 原有的属性现在依然有的则还原,原有属性现在没有了则忽略,现有新的属性则使用默认值

* 若不指定版本号,编译器会在编译当前类时根据当前类结构生成一个版本号,那么当前类结构只要
* 发生改变,版本号一定改变,那么反序列化就一定失败了












_____________---------------------------------------------------------------_________________________
如果父类的返回值类型是基本类型或者void的,子类必须与父类保持一致




字节流:最底层最基本的,binary的
字符




所有写入操作都得转成字节,用getBytes ,要转回字符串用toString
所有的字符流都是高级流








——————————————————————————————————————————————
day08 am  December 1,2016
**
*
*
V




只要是Reader结尾的都是字符流




Read常用方法:
int read()一次都是读一个字符,而不是低八位,返回的int值“低16位”表示的字符
int read(char[] chs)








InputStreamReader




OutputStreamWriter
 void write(char[] cbuf, int off, int len)
          写入字符数组的某一部分。
 void write(int c)
          写入单个字符。
 void write(String str, int off, int len)








————————————————————————————————————————————
大部分只能套字符流,如上,BufferedInputStream套FileInputStream,高级套低级流实现。
















/**
 * 字符流
 * 字符流是以字符为单位进行读写数据的,所以字符流也仅能读写文本数据。字符流都是高级流,本质上字符流读写字符是会自动
 * 与字节进行转换进行读写,所以底层还是要读写字节的
 * 
 * Reader是一个抽象类,所有字符输入流都继承它
 * Writer是一个抽象类,所有字符输出流都继承它
 * 它们规定了所有字符流都应当具备的读写字符的方法
 * 
 * 转换流
 * InputStreamReader:该流是Reader的实现类,很多字符流都只能处理其他字符流,但是低级流都是字节流,所以就需要先将字节流转换为字符流才可以被其他高级流使用,这时候常用转换流进行转换
 * OutputStreamWriter:Writer的实现类,作用是可以将字节输出流转换为字符输出流
 * 
 * 转换流还有一个作用是可以指定读写字符的字符集
 * 
 */
public class OSWDemo {.......












转换流相当于Adapter,比如:不同数据线用适配器的例子








FileInputStream -->  BufferedInputStream -->  BufferedReader




   -->  InputStreamReader -->




BufferedReader in= 
new BufferedReader(new InputStreamReader(System.in));
这句跟视频的代码一样
-————————————————————————————————————
FileInputStream fis = 
new FileInputStream("src"+File.separator+"day08"+File.separator+"BRDemo.java");
InputStreamReader isr = new InputStreamReader(fis);
/*
 * 缓冲字符输入流只能处理其他字符输入流,所以要先用InputStreamReader将字节流转换为字符流
 */
BufferedReader br = new BufferedReader(isr);




/*
 * String readLine()
 * 该方法会连续读取若干字符,直到读取到换行符为止,然后将换行符之前的所有
 * 字符组成一个字符串返回。
 * 注意:
 * 返回的字符串中不含有最后的换行符
 * 当返回值为null时,说明读取到文件末尾
 */
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
















((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))




FileOutputStream -->  BufferedOutputStream -->  BufferedWriter
 ||
 ||
 v
OutputStreamReader
 ||
 ||
 v
PrintWriter
以前只能在getBytes时指定字符集,
OutputStreamWriter支持第二个参数,指定字符集








FileInputStream 只能一个字符一个字符读,或者一次读一个数组
——————————————————————————————————————)))
FileInputStream fis = new FileInputStream("osw.txt");

InputStreamReader isr =new  InputStreamReader(fis,"GBK");


//读回来的是一个字符,需要转成char,构造方法中也支持第二个参数




int d = -1;
while((d=isr.read())!=-1){
System.out.println((char)d);
}
isr.close();








——————————————————————————————————————))))




valueOf()把其他字符转成字符串




————————————————————————————————————————
//FileInputStream 只能一个字符一个字符读,或者一次读一个数组








char[] data = new char[100];
int len = -1;
len = isr.read(data);
String str = String.valueOf(data,0,len);

System.out.println(str);
isr.close();




————————————————————————————————————)))))))
/**
 * 缓冲字符流
 * 特点是可以按行读写字符串
 * 
 * java.io.BufferedWriter是缓冲字符输出流
 * java.io.BufferedReader是具有自动行刷新的缓冲字符输出流,其更常用,而且
 * 内部默认嵌套BufferedWriter作为缓冲
 * 
 */
public class PWDemo1{.......
/*
 * PW提供了方便写文件的构造方法
 * PrintWriter(File file)
 * PrintWriter(String path)
 * 并且上述两个构造方法还支持第二个参数取指定charSet
 */








PrintWriter(File file, String csn)
          创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。




PrintWriter(String fileName, String csn)
          创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。












PrintWriter源代码:
public PrintWriter(OutputStream out, boolean autoFlush) {
        this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
______________________________________________________________________________________________




PrintWriter pw = new PrintWriter("pw.txt");
或者自定字符集:
PrintWriter pw = new PrintWriter("pw.txt",“GBK“);
PrintWriter不需要调用write()方法,只需要pw.println();




一次写一行,写完一句换行继续写下一句




对流做操作不支持第二个参数定义字符集,操作文件才可以,如下
PrintWriter pw = new PrintWriter(fos);




但是可以用OutputStreamWriter osw = OutputStreamWriter(fos,"gbk")
再用PrintWriter pw = new PrintWriter(osw);




————————————————————————————————————————————
//对流做操作不支持第二个参数定义字符集
//PrintWriter pw = new PrintWriter(fos,"gbk");




//但是可以通过另一个高级流转好了字符集再用
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
PrintWriter pw = new PrintWriter(osw);








pw.println("PrintWriter处理其他流");
pw.println("提供的构造方法既可以传入字节流也可以传入字符流");












————————————————————————————————————————————————————
public class Note {








FileOutputStream fos = new FileOutputStream(filename);
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");








/*
* 只要第一个参数是流,就支持第二个参数true,作为自动flush的开关,
* 当然要pw.println(line)而不能是pw.print(line),因为要换行才会flush
*line是用户输入的字符串内容
* 当PrintWriter处理的是一个流时,则支持第二个参数,该参数为boolean,若为true,
* 则具有自动行刷新,即,每次使用println方法写出的字符串后会自动flush
*/
PrintWriter pw = new PrintWriter(osw,true);


System.out.println("请输入内容:");
String line=null;








————————————————————————————————————————————————




InputStreamReader isr = new InputStreamReader(fis);
/*
* 缓冲字符输入流只能处理其他字符输入流,所以要先用InputStreamReader将字节流转换为字符流
*/
BufferedReader br = new BufferedReader(isr);


/*
* String readLine()
* 该方法会连续读取若干字符,直到读取到换行符为止,然后将换行符之前的所有
* 字符组成一个字符串返回。
* 注意:
* 返回的字符串中不含有最后的换行符
* 当返回值为null时,说明读取到文件末尾
*/
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}












————————————————————————————————————————————————




day08 pm
*
*




Exception




所有异常都继承Throwable  Error虚拟机级别的错误




Throwable
直接已知子类:
    Error, Exception 








Exception 相当于自身的问题。
Error大级别状况,非自身能处理




try{可能出异常的代码}




————————————————————————————————————————————————
异常也是一个封装类








一旦try中一行出错了try中下面的就不会执行了




try不出错catch就不会执行




catch可以写多个,捕获异常




为了预防未知的错误,最后应该都抛一个父类异常
catch(Exception e){




}
子类异常在上,父类异常在最后
但要注意继承关系,如果父类的异常Exception放最上面,那子类的其他异常就不会执行了。




————————————————————————————————————————————————————
public class ExceptionDemo3 {




public static void main(String[] args) {
FileOutputStream fos = null;
try{
fos = new FileOutputStream("fos.dat");
fos.write(1);
}
catch(Exception e){
System.out.println("读写出异常鸟");
}
finally{
if(fos!=null){
try{
fos.close();
}
catch(Exception e){
System.out.println("究竟哪里错了??");
}
}
}
System.out.println("Ding");
}




}












————————————————————————————————————————————————————————
符合语法,不符合业务逻辑,抛出异常




不是自己的问题,让执行的下一层处理异常。举例:托人介绍对象。责任制,自己的问题自己处理,不是自己的给谁负责的捕获处理




throws在方法上声明可能会报一些错,举例:“丑话说前边”












只要不是RuntimeException的及其子类,必须处理它
1,自己try catch
2,方法上继续throws




永远不要在main方法throws,不负责任。
















——————————————————————————————————————————————————————
public static void main(String[] args) {
Person p = new Person();
try{
/*
* 当调用一个含有throws声明异常抛出的方法时,编译器要求必须处理该异常
* 处理方式有两种:
* 1,使用try-catch捕获并处理
* 2,在当前方法上继续使用throws声明该异常的抛出
* 不要在main方法上使用throws
*/

p.setAge(10000);
}
catch(Exception e){
System.out.println("年龄非法");
}












————————————————————————————————————————
throw是一个动作,抛异常
throws是一个声明,告知被调用的该方法可能会有异常




区别:throw和throws
前者是动作,抛出,定义在方法内。后者是声明,定义在方法体外








子类继承父类需要重写父类方法,但是如果父类抛了异常呢?




——————————————————————————————————————————————————————
public class ExceptionDemo5 {
public  void dosome() throws IOException,AWTException{

}
}




class Son extends ExceptionDemo5{

// //不再抛出任何异常
// public void dosome(){
//
// }
//
// //只抛出父类方法抛出的部分异常
// public void dosome()throws IOException{
//
// }
// //抛出父类方法抛出异常的子类型异常
// public void dosome()  throws FileNotFoundException{
//
// }
// //不可以抛出额外的异常
// public void dosome() throws SQLException{
//
// }
//
// //不可以抛出父类方法抛出异常的父类型异常
// public void dosome() throws Exception{
//
// }
//




——————————————————————————————————————————————————————
检查异常:如果方法抛异常既不try catch也不throws,少一个编译都不通过
非检查异常:如果是RuntimeException,编译器不报错,但出错也会导致程序中断




RuntimeException是属于常识型异常
RuntimeException的子类:空指针异常,下标越界....








自变量equals(变量)








printStackTrace输出执行堆栈信息,也就是编译运行提示的
catch(Exception e){
e.printStackTrace();




————————————————————————————————————————————
getMessage和getCause实际运用中较少,后者大项目多见




——————————————————————————————————————————
自定义异常,通常不继承RuntimeException,一般继承Exception








静态方法是静态块初始化的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
有native关键值表示是C语言的方法
JNI:JAVA NATIVE INTERFACE 
java本地接口,用来调用c语言




Android也可以用C语言写,苹果也可以。用java调用c的口。用NDK




————————————————————————————————————————————————————————
day09 am
Thread
*
*
*
*
*
并发:微观上走走停停,宏观上都在运行








IO Block通过动作驱动
sleep Block周期性工作,比如飞机大战的30毫秒计时刷新
wait Block




剥夺出让yield








每个线程class都需要继承Thread
//要实现run方法,run方法无参数,具体动作写到run方法里面
class MyThread1 extends Thread{}












run方法会自动被调用的,只需要调用start方法即可




Thread t1 = new Thread();
Thread t2 = new Thread();
/*
 * 启动线程要执行start方法,不能调用run方法,run方法是线程要执行的任务,当线程启动后
 * 一旦被分配cpu时间片会自动执行自己的run方法
 */




t1.start();
t2.start();




————————————————————————————————————————————————
多线程没有先后问题,谁拿到cpu就运行




————————————————————————————————————————————
/**
 * 第一种创建线程的方式有两个不足:
 * 1,由于java是单继承的,所以导致当前类继承了Thread就不能再继承其他类。在实际开发中经常会出现继承冲突
 * 2,由于线程内部重写了run方法并定义了线程的任务,这就导致该线程与其执行的任务有一个必然的耦合关系,不利于线程的重用
 */




/**
 * 第二种创建线程的方式:单独定义线程任务
 * 实现Runnable接口并重写run方法
 */








线程本身就可以实例化








————————————————————————————————————————————————
Runnable r1 = new MyRunnable1();
Runnable r2 = new MyRunnable2();
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
/*
* 线程用于并发执行任务,多个线程运行任务
* 相当于现实生活中多个人各做各的事情

* 线程有几点不可控:
* 线程何时运行,运行多久完全听从线程调度的同一安排
* 1:时间片长短线程不可控
* 2:时间片分配给哪个线程线程也不可控。
* 线程只能被动被分配时间片,不能主动索取
* 线程调度会尽可能均匀地将时间片分配给不同的线程,但是不保证“一人一次”
*/
t1.start();
t2.start();








————————————————————————————————————————————————————




也是用匿名内部类的方式创建




+++++++++++++++++++++++++++++++++++++++++++++++
new Thread(
//相当于new Thread(new ThreadDemo$3).start();
//为何这里用Runnable,不是实现吗?匿名的是Runnable的子类,new的其实是Runnable的一个子类
new Runnable(){ 
public void run(){
for(int i=0;i<1000;i++){
System.out.println("老乡开门,我们不拿一针一线!");
}
}
}
).start();




——————————————————————————————————————————————




线程有一个构造方法,可以指定线程名字,但其实非特别的线程没必要指定名字




/*
* 获取运行main方法的线程
*/
Thread main = Thread.currentThread();
System.out.println("运行main方法的线程是:"+main);

dosome();

Thread t = new Thread("自定义线程"){
public void run(){
Thread t = Thread.currentThread();
System.out.println("自定义线程是:"+t);
dosome();
}
};
t.start();
——————————————————————————————————————————————
day08 PM




Thread提供了获取线程信息的方法:
long getId()
String getName()
int getPriority()
boolean isAlive()
boolean isDaemon() // 测试线程是否处于活动状态。
boolean isInterrupted()




/**
 * 线程优先级
 * 优先级越高,被cpu分配的时间片越多。默认是5,最高10
 * 线程优先级有10个等级,对应的数字是1-10
 * 其中1是最低优先级,10是最高优先级
 * 理论上,优先级越高的线程,大部分情况,并发量大更容易查看获取cpu时间片的次数越多,线程提供了常量对应了区间
 * 范围的最高与最低和默认:
 * Thread.MAX_PRIORITY:最高优先级,对应数字10
 *  Thread.MIN_PRIORITY:最低优先级,对应数字1
 *   Thread.NORM_PRIORITY:默认优先级,对应数字5
 */
————————————————————————————————————————————
/**
 * sleep阻塞
 * 线程提供了一个静态方法:
 * static void sleep(long ms)
 * 该方法可以导致调用该方法的线程进入阻塞状态指定的毫秒,当超时后线程会自动回到Runnable状态等待
 * 分配时间片继续并发运行
 * 通常使用sleep做周期性间隔使用
 */








跳秒。线程在Runnable中等待需要时间,累积刚好达到千毫秒也就是秒的跨越时刚跳过








void setDaemon(boolean)
守护线程的特点是,当进程中只剩下守护线程时,所有守护线程强制终止。








main肯定是前台线程




/**
 * 守护线程,又称为后台线程
 * 当一个进程中的所有前台线程都结束时,进程结束。
 * 那么正在运行的后台线程会被强制结束
 * 默认创建的线程都是前台线程,后台线程需要单独设置。
 * 设置必须在调用start方法之前,调用setDaemon(true)
 */




————————————————————————————————————————————————————
方法执行完毕main最先结束,但是其他方法还在执行




进程结束与否是前台是否还有线程








static void  yield()主动让出时间
暂停当前正在执行的线程对象,并执行其他线程。




——————————————————————————————————————————————————————
join方法。用于等待当前线程结束,该方法声明抛出InterruptedException




同步:有先后顺序的
异步:多个线程各做个的




同步代码块 sychronized关键字








————————————————————————————————————————————————————
想让谁阻塞,比如show要等到download执行完毕才执行,就在局部内部类里面使用download.join();
方法里的变量叫局部变量,方法里面的方法叫做局部内部类
注意:一个方法的局部内部类中要使用这个方法的其他变量,这个变量需要final。
比如这里的download需要final,1.8才可以不加,之前的版本都要加final
join还需要捕获InterruptedException




——————————————————————————————————————————————
/**
 * join方法
 * 线程的join方法可以做到线程同步运行
 * 
 * join方法会将调用该方法的线程置于阻塞状态,直到其等待的线程执行完毕才会解除阻塞继续运行
 * 
 * 同步:有先后顺序的执行代码为同步执行
 * 异步:多线程并发运行通常就是异步执行,各执行各的互相没有牵制
 * 线程同步:指的就是线程运行方式从各执行各的变为有先后顺序的执行
 * 
 */




——————————————————————————————————————————————————




public class ThreadDemo9 {
  //表示图片是否下载完毕
  public static  boolean isFinish = false;
  public static void main(String[] args) {
/*
* 当一个方法中的局部内部类中想引用该方法的其他局部变量,那么该变量必须是final的
* 这是因为jvm虚拟机内存分配问题所导致的,java 8.0之后没有此问题了
*/
final Thread download = new Thread(){
public void run(){
System.out.println("开始下载图片");
for(int i=1;i<=100;i++){
System.out.println("down"+i+"%");
try{
Thread.sleep(50);
}catch(InterruptedException e){
}
}
System.out.println("down:图片下载完毕");
isFinish = true;
}
};
Thread show = new Thread(){
public void run(){
/*
* 先等待download将图片下载完毕再尝试加载
*/
System.out.println("准备显示图片...");
try{
//匿名局部内部类
download.join();
if(!isFinish){
throw new RuntimeException("图片没有加载成功");
}
}catch(InterruptedException e){
e.printStackTrace();
}

System.out.println("show:显示图片完毕");
}
};

download.start();
show.start();












————————————————————————————————————————————————————
线程同步。在调用返回值的过程中将其锁定,用完了其他方法才能使用,防止抢用




synchronized关键字




多个线程并发读写同一个临界资源时候会发生"线程并发安全问题“




常见的临界资源:




    多线程共享实例变量
    多线程共享静态公共变量




若想解决线程安全问题,需要将异步的操作变为同步操作。 何为同步?那么我们来对比看一下什么是同步什么异步。




所谓异步操作是指多线程并发的操作,相当于各干各的。




所谓同步操作是指有先后顺序的操作,相当于你干完我再干。




而java中有一个关键字名为:synchronized,该关键字是同步锁,用于将某段代码变为同步操作,从而解决线程并发安全问题




||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||




巩固:抽象类不能被实例化,只能被继承。
抽象的类绝对不能new对象。
new shape //编译错误;
Shape s;//句柄 正确。声明了引用类型的引用;




new Inter1(); //编译错误,接口不能被实例化
Inter1 o1; //正确




用static修饰的成员变量是属于对象的数据结构 错
用static修饰的成员变量是属于类
static成员变量存储在堆中
static成员变量存储在方法区中




子类的访问权限得大于或等于父类的








抽象方法也是一种数据类型(引用类型),所以可以作为类型数组




多态:
点出什么看引用类型,具体行为的实现要看对象




1.同一类型的引用,指向不同的对象时,有不同的实现




向上造型:
父类型的引用指向子类的对象
能造型成的类型:父类+所实现的接口
能点出什么看引用的类型








强制类型转换,成功的条件有2种:
引用所指向的对象,就是该类型;
引用所指向的对象,实现了该接口
不符合那两种条件则转换失败;
发生ClassCastException类型转换异常;
建议使用instanceof判断引用指向的对象是否是该类型




JVM的内存结构有方法区,堆,栈等。其中方法区用于保存类的各种信息;
栈用于存放程序运行过程当中所有的局部变量;
堆一般用于存储使用new关键字创建的对象。 
类属于Java语言中引用类型的一种,不属于JVM的内存结构








--------------------------------------------------------------------------------------------------------------------------




线程安全API与非线程安全API




之前学习的API中就有设计为线程安全与非线程安全的类:




StringBuffer 是同步的 synchronized append();




StringBuilder 是java1.5后出的,为了提高性能损失安全性  不是同步的 append();




相对而言StringBuffer在处理上稍逊于StringBuilder,但是其是线程安全的。当不存在并发时首选应当使用StringBuilder。




同样的:




Vector 和 Hashtable 是线程安全的而ArrayList 和 HashMap则不是线程安全的。




对于集合而言,Collections提供了几个静态方法,可以将集合或Map转换为线程安全的:




例如:




Collections.synchronizedList() :获取线程安全的List集合




Collections.synchronizedMap():获取线程安全的Map








_______________________________________________________________________________________________________________




???????????????????????????????????????????????????????????????




RandomAccessFile 如何读取Object数据呢?比如day06的test的10,写完emp对象之后如何读取写入的内容??




解答:raf无论读写都是byte类型的。读取需要用到数组,raf调用数组引用,然后赋给长度len
最后new一个字符串用String,从0位置到len接收数组data。输出即可。如下:




RandomAccessFile reademp = new RandomAccessFile(filename,"rw");
byte[] data = new byte[1024];
int len=reademp.read(data);




System.out.println("实际读取到的字节量:"+len);
String str = new String(data,0,len);
System.out.println(str);
















——————————————————————————————————————————————————————
day10 AM




synchronized








————————————————————————————————————————————————————————————
/**
* 当一个方法被sychronized修饰后,该方法称为“同步方法”,即:多个线程不能同时进到方法内部执行代码,这就导致
* 该方法从多线程异步执行变为同步执行,不存在抢的问题,所以解决了并发执行的安全问题

* 在方法上使用synchronized,那么上锁的对象就是当前方法所属对象,即:方法内部看到的this
*/
//加上sychronized关键字则只能有一个线程执行
public synchronized int getBeans (){




————————————————————————————————————————————————————




大括号:排队执行的代码
小括号:同一个类型。this也可以。一个方法的this就是方法的所属对象,就是调用的哪个方法就是哪个对象




class shop{
public void buy(){
try{
Thread t = Thread.currentThread();
System.out.println(t.getName()+" : 正在选衣服...");
Thread.sleep(1000);
/*
* 同步块
* 可以更精确地包含需要多线程同步执行的代码片段,这样可以在保证并发安全的前提下尽可能地提高并发效率。
* 但是需要注意,使用同步块时,指定的同步监视器对象(即圆括号中指定的对象,上锁的对象)必须保证
* 多个需要同步执行的线程看到的是同一个才行
*/
synchronized(this){
System.out.println(t.getName()+" : 正在试衣服");
Thread.sleep(1000);
}
System.out.println(t.getName()+" : 结帐离开");

}catch(Exception e){

}




}




多个线程操作同一个功能时,被操作的就上锁。如多个线程操作同一个集合,则把集合上锁




——————————————————————————————————————————————————————————




推荐写同步块,尽量不写到方法上。








/**
 * 静态方法使用synchronized修饰后,该方法一定具有同步效果
 * 静态方法锁的当前类的类对象,即Class的实例
 * jvm加载每一个类的时候都会实例化一个class类的实例用于描述当前类的信息,并且在jvm内部只有一个class的实例
 * 与当前类对应,锁的就是这个class的实例
 */








——————————————————————————————————————————————————————————
如果一个静态方法用了同步修饰,一定具有同步效果,跟对象没关系,跟类有关。再多new也是同步的。任何时候都是同步的
class Table{public void buy(){..}..}  //buy方法不是静态,这里new两个,同步与否无所谓




final Table table1 = new Table();
final Table table1 = new Table();




——————————————————————————————————————————————————-
如果是静态:




class ...
public static void main(String[] args) {








//Class class1 =  SyncDemo3.class;
//Method m = class1.getMethod("getXXX",null);
//m.invoke(obj,args); //java反射机制。可以不知道方法名,直接getXXX方法,java会操作调用




//final Foo f= new Foo();
//final Foo f2 = new Foo();
Thread t1 = new Thread(){
public void run(){
Foo.dosome();  //静态方法。类名.方法名即可
}
};
Thread t2 = new Thread(){
public void run(){
Foo.dosome(); //可以不new Foo,静态方法。类名.方法名即可
}
};
t1.start();
t2.start();
}
}
class Foo{
public synchronized static void dosome(){
...}}








——————————————————————————————————————————————————————
常见面试题:
同步锁:sync。修饰的方法
互斥锁:也是sync,修饰地方不一样。上锁的方法一样,但是访问的代码不一样。如同喘气和下咽不能同时。




具体看SyncDemo4




死锁:互相等对方先退,僵持状态 如day10 SyncDemo5








——————————————————————————————————————————————————————
day10 PM




——————————————————————————————————————————————




























之前学习的API中就有设计为线程安全与非线程安全的类:




StringBuffer 是同步的 synchronized append();




StringBuilder 不是同步的 append(); java1.5以后加入的,非安全的




相对而言StringBuffer在处理上稍逊于StringBuilder,但是其是线程安全的。当不存在并发时首选应当使用StringBuilder。




Vetor向量 和 Hashtable是同步的 
ArrayList 和 HashMap不是同步的




————————————————————————————————————————————————-----
同样的:








Vector 和 Hashtable 是线程安全的而ArrayList 和 HashMap则不是线程安全的。




对于集合而言,Collections提供了几个静态方法,可以将集合或Map转换为线程安全的:




例如:




Collections.synchronizedList() :获取线程安全的List集合




Collections.synchronizedSet(); HashSet用的就是HashMap
源代码就是这样的:
 public HashSet() {
        map = new HashMap<>();
    }




(((((((((((((注意)))))))))))))))))




所有的集合不与Iterator做互斥。一个线程在查询集合,另一个也在用迭代器增删,不会互斥的,只能自己另外设置方法做互斥
/*
* 就算是线程安全的集合,也不与迭代器的遍历操作互斥。但是迭代器在遍历集合时
* 不能通过集合增删元素否则会抛出异常
* 所以在这种情况下需要自行维护互斥关系
*/
——————————————————————————————————————————————————————————












Collections.synchronizedMap():获取线程安全的Map












//Stack //HashSet就是HashMap
Set<String> set = new HashSet<String> ();
set.add("1");
set.add("2");
set.add("3");
System.out.println(set);
set = Collections.synchronizedSet(set); 需要接收值
System.out.println(set);
//HashSet就是HashMap








——————————————————————————————————————————————————————————
线程越多,cpu轮寻的时间就更长




1.1.2. 使用ExecutorService实现线程池




当一个程序中若创建大量线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切换线程的危险,从而可能导致系统崩溃。为此我们应使用线程池来解决这个问题。




ExecutorService是java提供的用于管理线程池的类。




线程池有两个主要作用:




    控制线程数量
    重用线程




线程池的概念:首先创建一些线程,它们的集合称为线程池,当服务器接受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。




在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务




线程池有以下几种实现策略:




Executors.newCachedThreadPool()




//创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。固定时间内还没有被用就关闭线程




Executors.newFixedThreadPool(int nThreads)




//创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。较常见




Executors.newScheduledThreadPool(int corePoolSize)




//创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。




Executors.newSingleThreadExecutor()




//创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。光杆司令,解决特定问题




可以根据实际需求来使用某种线程池。例如,创建一个有固定线程数量的线程池:








——————————————————————————————————————————————————————
玩游戏的路径算法就是二叉树treeMap








————————————————————————————————————————————————————————————




双缓冲队列BlockingQueue。学过的LinkedList但不是安全的,做项目再单独讲。








网络游戏都是udp,即时性




课堂上不讲udp,只讲tcp,工作中常用tcp
port:
2000以内不要用常用的软件,1000以内是操作系统
0-65535也就是short的最大值
















ServerSocket是被动创建的,只要有客户端连接就创建








——————————————————————————————————————
day11
怎么样才能让大家看得见呢?ServerHandler是内部类
内部类是否可以访问外部类的属性呢?可以




什么时候要把一个方法定义为private,就是不需要给外界知道的








MTA不可以补考 650一门课








——————————————————————————————————————————————————




day12 AM




xml Extensible Markup Language是独立于软件和硬件的信息传输工具
应用于 web 开发的许多方面,常用于简化数据的存储和共享。




简化数据共享
简化数据传输 子系:HTML




通常都用双引号
内部用到双引号时外部使用单引号
<id name='""""' age = "24"> </id>
必须且只能有一个根标签,也就是不被其他元素包含




转意字符:
&lt; 小于
&gt; 大于
&amp;
&apos; 表示单引号
&quot; 表示双引号




CDATA段,里面的所有内容当作一整块文本数据
<![CDATA[ 全部都是文字 <name></name> <age></age>   ]]>




注释:
<!-- 注释注释...                 -->








————————————————!!!!!!!!!!!!!!!!——————————————————




警告:




任何代码注意不要放到while(true)死循环下面,因为会报错:不可到达unreachable




注意注意!








int怎么转字符串??? 任何类型加上空字符串就是字符串啦  直接+" "












valueOf具体用法? 其他类型转字符串除了直接加空字符串外也可以用String.valueOf(被转的类型如int类型)




————————————————!!!!!!!!!!!!!!!!——————————————————








很多情况下都是使用非java官方的,第三方的jar包。经常出现的问题:某某某类找不到,就是因为jar包用了其他jar包,但是
打包发过来没把另一个jar包发过来。








告诉jvm jar包在哪,java会自动处理








maven可以连到apache的中央库,用到了些jar包












如果有下一级则信息写成属性,比如部门下有员工












SAX 也就是SIMPLE API FOR XML 在assemble设备常见。嵌入式。读一个告知一个




DOM 也就是DOCUMENT OBJECT MODEL文档对象模型。当场把xml全部读完。但是慢。所有xml都加载到内存里。如果文件比较大,内存有压力,解析的时间会比较长。java原生api没提供对dom的解析,因此需要导入jar包












阿里云不支持索引,只能在阿里云上搜索jar,下载到本地导入
外网需要去apache官网下载索引,几个g,才能在以后在本机索引,索引到了自动下载








——————————————————————————————————————————————————————————




DAY12 PM








try {

/*
* 使用DOM解析XML的大致步骤:
* 1:创建SAXReader
* 2:使用SAXReader读取要解析的XML文档并返回一个Document对象,
* 该步骤就是DOM解析耗时耗资源的地方,因为要先将XML文档内容全部读取完毕并载入内存
* 3:Document对象表示的就是该XML文档从Document中首先获取根元素
* 4:从根元素中按照XML的层级结构逐级获取子元素以达到遍历XML文档内容的目的
*/

/*
* 将emplist.xml文档中的所有员工信息解析出来,并转化为若干emp实例存入一个集合中
*/




//1.dom4j提供的SAXReader。不遵守java规则,没传入低级流。跟PrintWriter一样不需要自己套低级流了
SAXReader reader = new SAXReader();

//2.但是,是在read里面传,而不是跟java一样在new的时候.这一句Document把文档转成了对象
Document doc = reader.read(new FileInputStream("emplist.xml"));
+ /*step:3
*通过Document获取元素。Element也是dom4j提供的
*Element getRootElement()
*该方法用来获取XML文档中的根元素
*Element的每一个实例用于表示XML文档中的一个元素(一对标签)
*
*对于当前的例子来说,获取的即使emplist.xml文档中的<list>标签
*/

Element root = doc.getRootElement();
/*
* Element提供了获取子元素的相关方法:
* 常用的:
* List elements()
* 获取当前标签下的所有子标签,返回的集合中为若干Element实例,而每一个实例就表示其中的一个子标签

* List elements(String name)
* 获取当前标签下所有同名子标签

* Element element(String name)
* 获取当前标签下指定名字的子标签
*/
//emp是指定了标签,如果不指定就全部。当前没有其他标签,也可以不写从而获取全部
//获取当前根标签<List>下的所有子标签<EMP>
List<Element> eles = root.elements(); 
//用来存入每个员工信息的集合
List<Emp> list = new ArrayList<Emp>();

}catch(....){}












————————————————————————————————————————————————————————
//添加age
Element ageEle = empEle.addElement("age");
ageEle.addText(emp.getAge()+"");   //最简单就是加空字符串








//salary 也可以用String.valueOf(int类型)转成字符串
empEle.addElement("salary").addText(String.valueOf(emp.getSalary()));  也可以用String.valueOf(int类型)转成字符串












xml的自动格式化:ctrl+shift+f 
java也能用。但是在输出时也可以加参数以一定格式输出








//4 XMLWriter()还支持加参数,在输出的同时定义格式。OutputFormat.createPrettyPrint()
XMLWriter writer
= new XMLWriter(new FileOutputStream("myemp.xml"),OutputFormat.createPrettyPrint());








————————————————————————————————————————————————————————
XPath   以写路径的方式,快速地定位到指定的元素




.表示当前目录
..表示上级目录




<book></book>
//book忽略层级,不管在哪一级,是book就选取








@选取的是属性如,@lang








谓语[]
bookstore/book[1] 表示选择bookstore中的第一个book元素
book[last()]最后一个




bookstore/book/price[.price>35] book下的price自己大于35




bookstore/book/price[price>35] book下的price的price子项大于35








XPath不是必要组件,maven没一起下载下来
搜索jaxen,选择1.1.4








XPath在Document下,因此需要创建
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream("myemp.xml"));








String xpath = "/list/emp[age>23 and gender = '女'] /name";  //与,或,只能用and和or,小写




——————————————————————————————————————————————————————————
3部分功能,3天,1天一个部分












Test04.class.getClassLoader().getResourceAsStream()




由于在xml中是属性信息:
<emp id="2">
<name>王克晶</name>
<age>22</age>
<gender>女</gender>
<salary>4000</salary>
<hiredate>2008-02-15</hiredate>
</emp>
因此不能也跟其他标签一样用element,而应该用attribute,属于Attribute类型。但是要转成int只能通过将获取的属性类型的用getValue()方法转换,再用parseInt转成int类型,如下:
int id =Integer.parseInt(empEle.attribute("id").getValue());








——————————————————————————————————————————————————————








犯错:




//比较器要有类型<T>
Collections.sort(list,new Comparator<Emp>(){




public int compare(Emp e1,Emp e2) {
//不能直接获取变量salary,只能通过方法获取
return e1.getSalary()-e2.getSalary()>0?1:-1;
}








});








————————————————————————————————————————————————————————————




项目:








wtmpx是Linux的日志文件记录,是二进制文件。固定的大小372个字节
日志的分配:
user//...// pid进程id//type日志的类型,是整数7就是上线,8就是下线//time日志的生成时间//host用户的ip//...//...








各个客户端的日志中上线和下线的对应好数据,上传到服务器汇总








怎么解析?类型都不一样。user是字符串,pid是int,type:short time:int: host:String




raf.readInt
seek




项目主要就是解析日志,配对,发送给服务端
day1:从wtmpx解析日志保存到log.txt。把五部分读出来存到log.txt,按,分开












last-position.txt,内容为:3720
下次读的seek的开始位置
1:xml知识
2:io
3:解析








XMLread:
Element element(String name);
String elementText()
String elementTextTrim(String name);




















++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
首先,全部在集合中都是String




如果是int类型,把对应的map的value赋值给它
如果是String类型,也是跟int一样赋值
如果是file类型,那就需要先在硬盘上写出文件,如果是txt,就加后缀txt,如果没有,就用raf写








将输入的line字符串调用getBytes()给转成字节流,因为raf的write只能写入int类型
raf.write(line.getBytes());












——————————————————————————————————————————————————————————








配对日志。用户名 pid一样 7 8 一样 就可以。
日志按行读 br 再转成实例,读到集合




下线的时间减去上线的时间




没必要在单一的集合寻找。




配对就是上线下线




先不马上配对,先创建2个map,




List<LogData>
loginMap                 logoutmap
lidz,441232  |  logdata      huangr 12348 | LogData








__________________________________




先想没有计算机自己如何解决。想清楚了再用代码实现












<logfile>wtmpx</logfile>
logFile就是




//第一步:解析日志所需属性
//unix系统日志文件
private File logFile = new File("wtmpx");
//保存解析后日志的文件
private File textLogFile = new File("log.txt");
//书签文件
private File lastPositionFile = new File("last-position.txt");
//每次解析日志的条目数
private int batch = 10;








logFile表示的文件也就是wtmpx文件,从中读取10条日志。
假设能够直接读取,先判断,如果textLogFile存在,则跳过,








if textLogFile 存在,说明读取过了,就不循环读取了。return true
否则,循环10次读取
















IOUtil类中有
》》》》》》》
static List<LogData> loadLogData(File file) 方法,
* 从给定的文件中读取每一条配对日志,并存入
* 一个集合中然后返回。




》》》》》》》
saveLong方法,
传进long和File类型就给你把long转成字符串写到file文件中取,
通常用来记录指针位置




》》》》》》》
saveCollection(Collection c,File file)
该方法用来把给定的集合写道指定的file文件中








》》》》》》》
readString(RandomAccessFile raf,int length)
* 从给定的RandomAccessFile当前位置开始连续
* 读取length个字节,并转换为字符串后返回




》》》》》》》
readLong(File file)
* 从给定文件中读取第一行字符串,然后将其
* 转换为一个long值后返回




DMSClient
》》》》》》》
private long hasLogs(){




/**
* 第一步解析日志中的一个环节,
* 根据书签文件记录的位置判断是否还有
* 日志可以解析,若有,则将上次最后的位置
* 返回,若没有则返回-1。
* @return
*/








》》》》》》》
boolean parseLogs()
* 第一步:解析日志
* @return true:解析成功
*         false:解析失败




————————————————————————————————————————————————————————
指定类型和线程池的初始化:








//用来接收客户端连接的服务端的ServerSocket
private ServerSocket server;
//用来管理处理客户端请求的线程的线程池
private ExecutorService threadPool;
//保存所有客户端发送过来配对日志的文件
private File serverLogFile;




初始化如下:




try {




serverLogFile = new File( config.get("logrecfile"));




//Executors是一个类,而Executor是一个接口,ExecutorService继承了该接口
//类名.说明newFixedThreadPool是静态方法,该方法需要传参,类型是int的类型的线程
threadPool =  Executors.newFixedThreadPool(Integer.parseInt(config.get("threadsum"))); //30




server = new ServerSocket(Integer.parseInt(config.get("serverport")));//8080




}




keyset entryset返回的都是map
values()返回的是Colletion
values比list高级
————————————————————————————————————————————————————————
HashMap<K,V>




————————————————————————…^^^^^^^^




 keySet




public Set<K> keySet()




此映射所包含的映射关系的 set 视图。




————————————————————————…^^^^^^^^
 values




public Collection<V> values()








此映射中包含的值的 collection 视图




————————————————————————…^^^^^^^^
 entrySet




public Set<Map.Entry<K,V>> entrySet()




此映射所包含的映射关系的 set 视图。




————————————————————————————————————————————————————————
双缓冲:倒水和喝水。不能同时倒水和喝水,因此建2个杯子,你倒水A的时候我喝水B,我喝水A的时候你倒水B,即双缓冲




BlockingQueue
ArrayBlockingQueue FIFO
LinkedBlockingQueue FIFO最常用
PriorityBlockingQueue:排序不是FIFO的,要求传入的是能够比较大小的。而是依据对象的自然排序顺序或者构造函数的Comparator决定顺序的




——————————————————————————————————————————————————————
这里的getValue方法不是其他类型转字符串,而是Attribute下面的方法,获取属性的值
eleEmp.attribute("id").getValue()
















————————————————————————————————————————————————————————




apache下的commons下的jar包提供了java没有的方法,包括StringUtil。也有删除目录的方法




————————————————————————————————————————————————————————
Oracle:
自定义连接名
wh
123456












176.137.6.30/64








1521




xe




测试成功就连接




————————————————————————————————————————————————————————
聊天程序私聊思路:




首先,将在线的昵称都放进一个集合




如果 用户输入的以@开头




那么,遍历昵称集合,如果
匹配,则开启一个线程,进入私聊
不匹配,则提示昵称错误,然后跳出




否则 就把数据放入普通集合












——————————————————————————————————————————————
回顾:
String的方法:
/*
 * String substring(int start,int end)
 * 截取字符串,从start处开始到end处(不包含end处字符)的字符串截取出来并返回
 *  java api中有一个特点,通常使用两个数字表示范围时都是含头不含尾的 
 */
/**
 * String trim()
 * 去除当前字符串两边的空白字符
 */
/**
 * char charAt(int index)
 * 获取当前字符串中指定位置的字符
 * 
/**
 * boolean startsWith(String str)
 * boolean endsWith(String str)
 * 判断当前字符串是否是以给定字符串开始或结束的。
 */
/**
 * String toUpperCase()
 * String toLowerCase()
 * 将当前字符串中的英文部分转换为全大写或小写
 * 
 */
















VVVVVVVVVVVVV!!!!!!!!!!!!!!!!!!!!VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV








/**
 * String 提供了若干重载的静态方法valueOf
 * 作用是可以将java其他类型转换为字符串,常用于将基本类型转换为字符串使用。
 * 
 * 字符串是不变对象,每次修改都会创建一个新对象;
 */
int i=123;

String istr = String.valueOf(i);
System.out.println(istr+4);
————————————————————————————————————————————
/**
 * 频繁修改字符串用StringBuilder
 * java.lang.StringBuilder
 * 由于String的设计不适合频繁修改内容,所以java提供了一个专门的用来修改字符串内容的类
 * StringBuilder
 * 其提供了编辑字符串内容的相关方法。性能很好。
 * 
 */




StringBuffer builder = new StringBuffer(str); //线程安全的,多线程常用,同步处理的,性能稍慢
StringBuilder builder = new StringBuilder(str);// jdk1.5后出现的.非线程安全,并发处理,性能稍快。




/*
* 追加字符串操作
* StringBuilder append(String str)
* 向当前字符串末尾追加给定字符串内容。
*/
builder.append(",为了找个好工作!");
 将指定范围内的字符串替换为给定字符串
builder.replace(9,16,"就是为了改变世界!");




/*
* StringBuilder delete(int start,int end);
* 删除指定范围内的字符串
*/
//,就是为了改变世界!
builder.delete(0,8);








* StringBuilder insert(int index,String str)
* 向指定位置插入指定字符串








//反转字符串
builder.reverse();








————————————————————————————————————————
/**
 * Wrapper
 * 包装类的出现是为了解决基本数据类型不能直接参与面向对象开发的问题;
 * 
 * 6个数字类型的包装类继承自Number
 * Number是一个抽象类,提供了可以在6个基本类型数字间转换的相关方法。
 */
/*
 * 基本类型=>包装类
 *可以直接new,也可以使用包装类的静态方法valueOf(推荐)
 *Integer的valueOf会重用1个字节之内的整数包装类对象。
 *
 */




Integer i1 = Integer.valueOf(1);
Integer i2 = Integer.valueOf(1);








//还原成原来的值
int i = i1.intValue();
_______________________________——————————————————————————————————




/**
 * 包装类有两个常量: MAX_VALUE, MIN_VALUE
 * 分别表示包装类对应的基本类型的最大和最小值
 * 
 * 
 */
int imax = Integer.MAX_VALUE;
System.out.println(imax);




——————————————————————————————————————————
/**
 * 包装类支持一个静态方法:parseXXX(String str)
 * 可以将给定的字符串解析为对应的基本类型数据
 * 前提是该字符串能正确描述基本类型可以保存的值
 * 
 */
String str1 = "123.123";
String str = "123";
//int i1=Integer.parseInt(str1); //编译报错,数值格式异常,int存不下123.123
int i=Integer.parseInt(str);  




——————————————————————————————————————————————




package day02;
/**
 * JDK1.5推出了一个新的特性:自动拆装箱
 * 该特性是编译器认可,而不是虚拟机认可。
 * 编译器在编译源程序时发现基本类型和引用类型需要转换时会自动补全转换代码
 * 好处是程序员无需再关注基本类型与其对应的包装类之间的转换工作;
 */
public class IntegerDemo4 {




public static void main(String[] args) {
/**
* 触发自动拆箱,即:补全代码转为基本类型
* 下面的代码在编译后.class文件中的样子
* int i=Integer.valueOf(123).intValue(); 
*/
//jdk1.5开始类自动装箱。这里实际上已经变成:int i=Integer.valueOf(123).intValue();编译器自己补充了
int i=Integer.valueOf(123); 
/**
* 触发自动装箱,即补全代码转换为包装类
* 下面的代码在编译后的.class文件中的样子:
* Integer in=Integer.valueOf(123);
*/
//jdk1.5开始类自动装箱。这里实际上已经变成:Integer in=Integer.valueOf(123);编译器自己补充了
Integer in =123;




}




}












——————————————————————————————————————————




/*
* Object的equals内部就是使用"=="比较的,所以若不重写没有实际价值。
*/




——————————————————————————————————————————




/*
 * String支持正则表达式方法一:
 * boolean matches(String regex)
 * 判断当前字符串是否满足给定的正则表达式的格式
 * 
 */








/**
 * String[] split(String regex)
 * 将当前字符串中满足正则表达式的部分进行拆分,返回被拆分后的若干字符串。返回的数组中的每个元素为一段字符串。
 */
















/**
 * String replaceAll(String regex,String str)
 * 将当前字符串中满足正则表达式的部分替换为给定的字符串
 * 
 */


————————————————————————————————————————————
part 4


















Oracle:
自定义连接名
wh
123456












176.137.6.30/64
6.45




1521




xe




测试成功就连接




连接池的名字:




dbcp:
C3PO




VARCHAR是通用的,其他db软件也支持,包括oracle,但是在oracle中是用VARCHAR2
————————————————————————————————————————————————————
DDL:(数据定义):CREATE/ALTER/DROP/TRUNCATE
DML:(数据操作):INSERT/UPDATE/DELETE
TCL:(事务控制):COMMIT/ROLLBACK/SAVEPOINT
DQL:(数据查询):SELECT
DCL:(数据控制):GRANT/REVOKE(用于收回用户或角色已有的权限)/CREATE USER




































































DATE 7个字节,每个字节表示一个数据:日月年时分秒
[]和java一样可写可不写
CREATE TABLE [openlab.] STUDENT 方括号内表示给超级用户下的其他用户比如openlab创建表STUDENT












实际开发不用JDBC直接连数据库,都是用框架,避免各种数据库的差异




数据定义语言Data Definition Language
CREATE: 创建表或其他对象的结构
ALTER:修改表或其他对象的结构
DROP:删除表或其他对象的结构
TRUNCATE:删除表数据,保留表结构












Data Manipulation Lauguage
INSERT
UPDATE
DELETE












事务控制语言Transaction Control Language
COMMIT : 提交。事务的开始是自动的,结束是根据提交或回滚,前者算数,后者不算数
ROLLBACK: 回滚
SAVEPOINT : 保存点












Data Query Language
SELETE












Data Control Language
GRANT : 授予,用于给用户或角色授予权限
REVOKE : 用于收回用户或角色已有的权限
CREATE USER




————————————————————————————————————————————————————————
数据库中字符窜的字面量是使用单引号括起来的,并且字符串内容是区分大小写的




数据库中所有数据类型默认值都是NULL
可以通过DEFAULT关键字为字段单独指定默认值




2.3
修改字段的类型,长度,添加默认值,约束等修改表结构时尽量在表中没有数据的时候进行。
当有数据时,尽量不要修改字段的类型,修改长度时尽量增大不要减小,否则都可能修改失败








————————————————————————————————————————————————————————




DML语句
是对表中数据进行维护的语句,包含增删改操作。DML是伴随事务操作的




INSERT 语句,用于向表中插入数据












不指定字段是全列插入
INSERT INTO employee_MILO VALUES(1009,'MARY',5000,10);不指定的话需要全字段写,不能部分
建议:
INSERT INTO employee_MILO (ID ,NAME,SALARY,DEPTNO) VALUES(1009,'MARY',5000,10);












字符串区分大小写的








-——————————————————————————————————————




SCOTT DEPTNO ————》50








————————————————————————————————————————————————————————




CHAR(10 CHAR)实际中少用。
CHAR()可以不指定长度相当于默认给1个字节,相当于CHAR(1)
VARCHAR2()则必须指定








LONG VARCHAR2加长版,是变长,最多2GB。缺点:不能作为主键,每个表只能有一个long类型列,不能建立索引;不能出现在查询条件中,就是不能出现在where中




CLOB:存储定长或变长,最多4GB




CONCAT(CHAR1,CHAR2)拼接
如果char1和char2任何一个为null,相当于连接了一个空格




SELECT CONCAT(CONCAT(ename,':'),sal) FROM emp;




--多个字符连接,用||更直观
SELECT ename || ':' || sal FROM emp;








LENGTH(char)
用于返回字符串的长度
SELECT ename,LENGTH(ename) FROM emp;








————————————————————————————————————————————————————————




DQL语句:
SELECT语句用于查询表或视图中数据使用
基本组成部分:
SELECT filed1,filed2,...FROM table




SELECT 子句:指定要查询的字段
这里的SELECT后面可以指定表中的字段,函数或表达式,还以使用*查询表中所有字段FROM子句:指定数据来源的表(要查询的表)








DUAL:伪表,不是真实存在的表,当查询的内容与任何表没有关系的时候可以使用它。
凑数的,用来测试。只有1行。就是查询的跟任何表没关系的时候用。
SELECT upper('helloworld') ,LOWER('HELLOWORLD'), INITCAP('hell') FROM DUAL;








TRIM / LTRIM /RTRIM
作用:截去子串
语法形式:
-TRIM(c2 FROM c1)从c1的前后截去c2
-LTRIM(c1[,c2])从c1的左边截去c2
-RTRIM(c1[,c2])从c1的右边截去c2
————————————————————————————————————————————————————————




LPAD RPAD
补位函数。不够就凑,多了就切.但是只有从右边往左边切
可以用特定字符补,也可以用空格补。如果其他数据都是4位,少部分是3位,当LPAD(sal,3,'')则表示其他4位的数据会被从右边截断。
SELECT ename,LPAD(sal,5,'') FROM emp_milo
/*不够位数的用$补齐*/
SELECT ename , LPAD(sal,5,'$') FROM EMP_MILO;




/*5:SUBSTR(CHAR,INDEX,LENGTH)
INDEX可以是负数,负数是从倒数位置开始
LENGTH:可以不指定,不指定则是截取到末尾,超过实际可截取的数字也是到末尾,但是不能为负数。
从给定位置开始截取字符串,连续length个。数据库中下标都是从1开始,和java不同
这里8是开始位置,25是截取的个数
*/




SELECT SUBSTR('Doctor who travels in TARDIS',8,25) FROM DUAL;




————————————————————————————————————————————————————————




instr相当于java的indexOf
6.INSTR(CHAR1,CHAR2,N,M)
查看char2在char1中的位置
n:指定开始查找位置
m:第几次出现
n,m不写默认都是1
找不到是返回0,因为下标从1开始,不同于java,java是从0下标开始,返回-1
————————————————————————————————————————————
NUMBER(PRECISION ,SCALE)最多38位,不指定p则给38位
——————————————————————————————————————————————
数字函数
1:ROUND(n,m)四舍五入
对n进行四舍五入
m:保留小数点后的位数
m不写默认为0,即:保留到整数位
-1为十位,-2为百位,以此类推








TRUNC(N[,M]):用于截取,参数意义和ROUND一致,但是不进行四舍五入,而是直接截取,不管后面的数字




被除数/除数
除数不能为零,在java中会报数学异常
3:MOD(M,N)求余,n不能为0,为0则什么也不做直接返回m








4:CEIL(N), FLOOR(N)。向上取整和向下取整。
SELECT FLOOR(45.67) FROM DUAL; //FLOOR则返回45,CEIL则返回46.小于的最大整数,大于的最小整数




——————————————————————————————————————————————
日期类型相关函数
日期相关关键字
SYSDATE:对应一个内部函数,返回一个表示当前系统时间的DATE类型值
SYSTIMESTAMP:对应一个内部函数,返回一个表示当前系统时间的时间戳类型的值




SELECT SYSDATE FROM DUAL




——————————————————————————————————————————————




TO_DATE()函数
将一个字符串按照给定的日期格式解析为一个DATE类型数据
SELECT TO_DATE('2008-08-08','YYYY-MM-DD') FROM DUAL;




日期可以比大小越晚越大












——————————————————————————————————————————————




两个日期之间做减法,差表示天数








TO_CHAR()
可以使用将DATE按照给定的日期格式转换为字符串
SELECT ENAME,TO_CHAR(hiredate,'YYYY-MM-DD') FROM EMP_MILO;




除了字母数字和符号,其他都要用双引号。




SELECT ENAME,TO_CHAR(hiredate,'YYYY"年"MM"月"DD"日" ') FROM EMP_MILO;








------------------------------------------------ 
   \USER    |0-49 |50-99 |
SYS \ | | |
------------------------------------------------ 
| | |
0-49 |本世纪 |上世纪 |
| | |
------------------------------------------------ 
| | |
50-99 |下世纪 |本世纪 |
| | |
------------------------------------------------ 
STR-》DATE
98-》RR




SYS->1998
举例:给定的年份比如是98,系统当前时间是2016,16介于0-49之间,则第一行,然后USER给的
时间是98,98介于50-99之间,则选择第二列。两者第一行第二列交汇,也就是“上世纪”。因此
输出的时间是1998年。
YY-MM-DD 不管其他,系统是哪个世纪就是哪个世纪。98输出的2098
RR-MM-DD 根据表计算,输出1989




举例:给的年份如果是49,首先SYS时间是2016,16则第一行。USER的49,处于第一列,则输出本世纪
的年份2049
如果给的年份是59,则SYS是2016,16则第一行。USER的59,则第二列。即上世纪。输出1959年








——————————————————————————————————————————————




/*返回给定日期所在月的月底日期*/
LAST_DAY(date)




SELECT TO_CHAR(LAST_DAY(SYSDATE),'YYYY-MM-DD') AS "月结日" FROM DUAL;




————————————————————————————————————————————
/*
ADD_MONTHS(date,i)
对给定日期加上给定的月,若i为负数则是减去。
查看每个员工入职20周年纪念日:
*/
SELECT ename,ADD_MONTHS(hiredate,12*20) FROM  EMP_MILO;




————————————————————————————————————————————
MONTHS_BETWEEN(date1,date2)
计算两个日期之间相差的月
查看每个员工入职至今多少个月?
SELECT ename,TRUNC(MONTHS_BETWEEN(SYSDATE,hiredate)   ) AS "入职总月数"      FROM EMP_MILO;








————————————————————————————————————————————————




NEXT_DAY(date,i)
返回给定日期之后一周内的周几




SELECT NEXT_DAY(SYSDATE,5) FROM DUAL;




GREATEST(至少一个值,只要能比较大小的都可以,包括日期)
LEAST(至少一个值,只要能比较大小的都可以,包括日期)








——————————————————————————————————————————————








EXTRACT()查看给定日期中指定日期分量的值




SELECT EXTRACT(YEAR FROM SYSDATE) FROM DUAL;




查看81年入职的人员;
SELECT ename,hiredate FROM EMP_MILO WHERE EXTRACT(YEAR FROM hiredate)=1981








NULL不是值,应该是一种状态。因此gender=NULL是错误的。应该是gender IS NULL
这点跟java不同,比java严谨。








——————————————————————————————————————————————————
非空约束




NULL值的运算
NULL与字符串连接等于什么都没干
NULL与数字运算结果为NULL








NVL(arg1,arg2)空值函数
会将一个NULL只替换为非NULL值
即:当arg1为NULL,函数返回arg2的值
若arg1不为NULL,则返回arg1自身




查看绩效情况
若该员工有绩效,则显示为“有绩效”,没有的则显示为“没有绩效”












————————————————————————————————————————————————————————
/*18:查看82年以后入职的员工的入职日期,82年以前的按照 1982年01月01号显示。格式都是DD-MON-RR(默认格式)*/
SELECT ename,TO_CHAR(hiredate,'YYYY-MM-DD') FROM emp_milo WHERE EXTRACT(YEAR FROM  hiredate)>=1982;




SELECT ename,TO_CHAR(hiredate,'YYYY-MM-DD')  FROM emp_milo  WHERE EXTRACT(YEAR FROM  hiredate)<1982 ;




正解:
SELECT ename,hiredate,TO_CHAR(GREATEST(hiredate,TO_DATE('1982-01-01','RR-MM-DD')),'YYYY-MM-DD') FROM emp_milo;
————————————————————————————————————————————————————————




列的别名
当一个查询语句中的字段不是表中纯粹的字段而是一个函数或表达式时,那么查询出来的结果集中对应的该字段名就是这个函数或表达式,可读性差,为此可以为这样的字段添加别名。若希望别名中出现空格或区分大小写,可以用双引号将其括起来




SELECT ename,sal*12 "s al"  




————————————————————————————————————————————————
















不等于应该用<>而不用!=,因为前者是数据库通用的




/* 查询职员表中薪水低于2000的信息 */




/* 查询职员表中不属于部门10的信息 */

/* 查询职员表中在1982-01-01以后入职的信息,比较日期类型数据 */








/* 查询薪水大于1000 并且职位是'CLERK'的信息 */








/* 查询薪水大于1000 或者 职位是'CLERK'的信息 */




AND 的优先级高于OR
或者加括号




——————————————————————————————————————————————————————
LIKE用于模糊匹配字符串
支持两个通配符:




%表示任意字符(0-多个)
_表示单一的一个字符




SELECT ename,job FROM emp_milo WHERE ename LIKE'_A%';
————————————————————————不要漏了LIKE ————————————————————————
 IN(LIST) 和 NOT IN(LIST)
判断在列表中或不在列表中
IN 与 NOT IN 也常用在子查询中




查看职位是CLERK或SALESMAN的员工信息
SELECT ename,job FROM emp_milo WHERE job IN('SALESMAN','CLERK');
——————————————————————————————————————————————————————




/* 查询薪水在1500-3000之间的信息 */




SELECT ename,sal FROM emp_milo WHERE sal BETWEEN 1500 AND 3000;




ANY(LIST)与ALL(LIST)
联合>,>=,<,<=多个值时使用
>ANY 大于列表之一即可(大于最小)
>ALL 大于列表所有(大于最大)
<ANY 小于最大的
<ALL 小于最小的
通常被用于子查询中








————————————————————————————————————————————————————
DISTINCT前面不能有字段,后面可以有多个字段。可以对多列去重复,去重的原则是多个字段值的组合没有重复行
SELECT DISTINCT 




——————————————————————————————————————————————————————




ORDER BY只能写在最后。用于对结果集按照给定字段进行排序
排序分为:
升序:ASC,默认的可不写
降序:DESC








可以按照多字段排序,每个字段都可以单独指定排序方式,排序按照从左到右的优先级顺序排序,即,先按照第一个字段排序结果集。
当第一个字段有重复值再按照第二个字段排序,以此类推
SELECT ename,sal,deptno FROM emp_milo ORDER BY sal DESC  , deptno




————————————————————————————————————————————————————————








NULL值在排序中被认作最大值
SELECT ename,comm FROM emp_milo ORDER BY comm;








——————————————————————————————————————————————————————————
聚合函数:是对结果集进行统计使用的
对字段值的统计有:
MAX,MIN,AVG,SUM




分别求最大,最小,平均和总和




COUNT是对记录数的统计








聚合函数忽略NULL值
不想忽略NULL,可以变成0.用NVL(comm,0)
SELECT ename,NVL(COMM,0) FROM emp_milo




SELECT AVG(NVL(comm,0)) FROM emp_milo;








——————————————————————————————————————————————————————————
GROUP BY子句:可以对结果集按照给定字段值相同的记录进行分组。是配合聚合函数对结果集进行分组统计使用的




查看每个部门的平均工资?
SELECT AVG(SAL), DEPTNO FROM EMP_MILO GROUP BY DEPTNO




——————————————————————————————————————————————————————————




GROUP BY一般用于使用聚合函数时




多字段分组:分组的几个字段值都相同的记录被看作一组。
查看每个部门每种职位的最高工资




SELECT MAX(SAL),deptno,job FROM emp_milo GROUP BY deptno,job








凡是不在聚合函数的字段,都得出现在GROUP BY 里?跟DISTINST一样








/*查看部门的平均工资,前提是该部门的平均工资都高于2500 */




在WHERE里是不能使用分组函数过滤。能不能查出来是由WHERE决定的。在查询表过程中过滤的
WHERE先过滤,HAVING是过滤好了,组也分好了再过滤,是属于后过滤的。如果平均工资不满足2500,整个组都不要了




WHERE:用来过滤记录的
HAVING:用来过滤分组的
它们过滤的时机也不相同,先WHERE后HAVING。前者是在查询表时逐行过滤以选取满足条件的记录
HAVING是在数据查询后并且分组完后对分组进行过滤的,以决定分组的取舍。必须跟在GRUOP BY 后面,不能独立存在




/* 查看平均工资高于2000的那些部门的最高与最低工资。




先查平均工资高于2000的部门:
FROM EMP_MILO
GROUP BY deptno HAVING AVG(SAL)》2000
过滤了分组后再查其中的最高和最低工资
*/




SELECT MAX(SAL),MIN(SAL) ,DEPTNO FROM EMP_MILO GROUP BY DEPTNO HAVING AVG(SAL)>2000
























————————————————————————————————————————————————————




查询语句的执行顺序依下列子句次序:
1》 from子句: 执行顺序为从后往前,从右到左
数据量较少的表尽量放在后面
2》 where子句:执行顺序为自下而上,从右到左
将能过滤掉最大数量记录的条件写在where子句的最右
3》 group by--执行顺序从左往右分组
最好在group by前使用where将不需要的记录在group by之前过滤掉
4》 having子句:消耗资源
尽量避免使用,HAVING会在检索出所有记录之后才对结果集进行过滤,需要排序等操作




5》 select子句:少用*号,尽量取字段名称。
ORACLE在解析的过程中,通过查询数据字典将*号依次转换成所有的列名,消耗时间




6》order by子句:执行顺序为从左到右排序,消耗资源
——————————————————————————————————————————————




关联查询:从多张表中关联查询数据,关键点在于连接的条件,根据该条件数据库才知道这些表中的数据的对应关系,
从而分别获取这些对应记录中查询的字段并构成结果集




/* 查看每个员工的名字以及其所在的部门的名字? */








关联要有连接条件,不添加连接条件会产生迪卡尔积,这通常是一个无意义的结果集




原则上n张表关联查询至少要有n-1个连接条件








/* 查看SALESMAN所在哪个城市 */




/* 查看每个城市的平均工资 */




——————————————————————————————————————————————————
内连接;添进一张表就JOIN SQL89没有,SQL92后都有了
《《《《《警告:::JOIN ON 是成对出现的》》》》》》》




SELECT e.ename,d.dname
FROM emp_milo e JOIN dept_milo d
ON e.deptno=d.deptno
JOIN xxxx
ON d.xx=xxxx.xx
WHERE d.dname=‘SALES';




关联查询中不满足连接条件的数据不会被查询出来








——————————————————————————————————————————————————————
外连接既可以满足连接条件的记录查询出来之外,还可以将不满足连接条件的记录也查询出来。
外连接分为:
左外连接:以JOIN左侧表作为驱动表,该表中所有记录都要显示,那么来自右侧表的字段值若不满足连接条件则为NULL。
右外连接:
全外连接:除了返回满足连接条件的记录还会返回不满足连接条件的所有其他行。是左外和右外连接查询结果的总和
/*
全外连接只能用JOIN ON ,WHERE中不支持。
哪边有+就是哪边为空,也就是反向的连接。如下:
*/




/* 左连接,右边为空 */
SELECT e.ename,d.dname  FROM emp_milo e ,dept_milo d WHERE e.deptno=d.deptno(+);
/* 右连接,左边为空 */
SELECT e.ename,d.dname  FROM emp_milo e ,dept_milo d WHERE e.deptno(+)=d.deptno;








——————————————————————————————————————————————————————




自连接:是当前表的一条数据对应当前表的多条数据。用于解决相同属性的一组数据,但是又存在上下级关系的树状结构组织时使用




/* 查看每个员工的上司的名字   */




FROM emp_milo e ,emp_milo m
WHERE e.mgr=m.empno




/*  查看FORD的上司,和FORD在哪个城市   */
找到上司,找到编号,再根据编号找到地址




/*  查看FORD的上司,和FORD在哪个城市   JOIN*/
SELECT e.ename,m.ename,d.loc 
FROM emp_milo e JOIN emp_milo m 
ON e.mgr=m.empno 
JOIN dept_milo d 
ON m.deptno=d.deptno 
WHERE e.ename='FORD';




/*  查看FORD的上司,和FORD在哪个城市   WHERE*/
SELECT e.ename,m.ename,d.loc 
FROM emp_milo e ,emp_milo m,dept_milo d 
WHERE e.mgr=m.empno 
AND m.deptno=d.deptno 
AND e.ename='FORD';












关联查询一上来就查连接条件








—————————————————————————————————————————————————————








/********************************************DAY04*************************************/
/*查找工作和SCOTT一样的员工  */
/*先找出SCOTT的工作,再嵌套   */




SELECT ename ,job , sal FROM emp_milo WHERE job=(SELECT job FROM emp_milo WHERE ename='SCOTT')




/*
2,查出部门里面有SALESMAN职位但是不是SALESMAN的员工信息
思路:先查是哪个部门有SALESMAN,然后查这个部门的员工,然后职位不是的
*()*()*()* *()*()*()**()*()*()**()*()*()*
注意:子查询返回多列的需要IN在括号里面,如果是单条可不用,如上面的子查询返回单条可不IN
*()*()*()**()*()*()**()*()*()**()*()*()*




*/
SELECT ename,job,sal FROM emp_milo WHERE deptno IN (SELECT deptno FROM emp_milo WHERE job='SALESMAN') AND job<>'SALESMAN';








子查询:是一条查询语句,它是嵌套在其他SQL语句当中的,目的是为外层SQL语句提供数据使用








在DDL与DML中也可以使用子查询:
1:DDL中使用子查询可以将一个查询结果集当作表快速创建出来
当作表快速创建出来












/*  在子查询当中,某一字段有函数或计算必须加别名,如sal*12 必须加别名  */
CREATE TABLE emplyee AS(
SELECT e.deptno,e.ename,e.job,e.sal,e.sal*12 "UniSalary",d.deptno,d.dname,d.loc
FROM emp_milo e,dept_milo d
WHERE e.deptno=d.deptno(+)




)








DML中使用子查询
/*  给CLARK部门的所有员工提高10%的工资   */
UPDATE employee_milo SET sal=sal*1.1 WHERE deptno=(
SELECT deptno FROM employee_milo WHERE ename='CLARK' 
)




子查询根据查询结果集分为:
单行单列子查询:结果集只有一个值
多行单列子查询:结果集有多个值
单列通常用于过滤条件




多行多列子查询:常当作表使用








/*  多行单列子查询在过滤时要配合IN,ANY,ALL使用   */
/* 查看与SALESMAN同部门的员工  */
SELECT ename ,job FROM emp_milo WHERE deptno IN (
    SELECT deptno FROM emp_milo WHERE job='SALESMAN' )








/*  查看比30号部门所有员工工资都高的员工  */




/*
EXISTS关键字。只关注有没有,
后面要跟一个子查询,作为判断条件的依据是该子查询只要可以查询出至少一条记录就可以,
如案例:查询有员工的部门,NOT EXIST则查询没人的部门
*/
SELECT deptno,dname FROM dept_milo d WHERE EXISTS(
SELECT * FROM emp_milo  e WHERE d.deptno=e.deptno 
)








/*查看哪些员工工资高于其所在部门平均工资 */




多列用在FROM ,单列 WHERE




/* 在SELECT子句中使用    */
SELECT e.ename,e.sal,(SELECT dname FROM dept_milo d WHERE d.deptno=e.deptno ) dname 
FROM emp_milo e;




——————————————————————————————————————————————————————————
分页查询,也就是分段查询。一次查一段。勤拿少取。分页在的语法标准在SQL中没有定义,所以不同的数据库分页语句写法可能完全不同,宛如方言
当查询的数据量过大时,会导致响应速度慢资源消耗大等问题,为此,我们会使用分页查询方式,分段将数据查询出来




ROWNUM:查一条编一个号。在使用ROWNUM为结果集编号的查询过程中不要使用ROWNUM做>1的过滤判断,否则将得不到任何结果
ROWNUM:伪列,不存在于任何一张表中,但是
所有的表都可以查询该字段,该字段的值是动态
生成的,是在查询表生成结果集的过程中产生值
的。原则是,从1开始,逐次递增。在查询过程
中只要可以从表中查询出一条记录,ROWNUM字段
的值就是该记录的行号。








——————————————————————————————————————————————————————————




/*  求按工资sal排序的第6到10条的数据。 在生产环境中,6和10都是两个参数   */
SELECT *
FROM(SELECT ROWNUM rn,t.*
    FROM(
SELECT ename,job,sal
FROM emp_milo ORDER BY sal DESC) t
    WHERE ROWNUM<=10)
WHERE rn>=6








——————————————————————————————————————————————————————————
pageSize:
page:




start:(page-1)*pageSize+1
end: pageSize*page




比如一篇显示5条,2页








JAVA中,SQL就是字符串








——————————————————————————————————————————————————————————




/* DECODE函数:可以实现简单的分支效果 */
SELECT ename,job,sal,
    DECODE(job,
          'MANAGER',sal*1.2,
          'ANALYST',sal*1.1,
          'SALESMAN',sal*1.05,
          sal
    ) bonus
FROM emp_milo;




DECODE在GROUP BY子句中的应用
可以将








DECODE 内的查询值和返回值可以不同,但是各查询值必须相同,各返回值也必须类型相同。
如下案例:
SELECT deptno,dname,loc
FROM dept ORDER BY
DECODE(dname,'OPERATIONS',1,'ACCOUNTING',2,'SALES',3);
其他查询值因为没指定默认返回值,因此返回NULL。而NULL是最大,因此排在下面








————————————————————————————————————————————————————————
排序函数:可以将结果集按照给定字段分组,然后在组内按照给定的字段排序,然后生成一个组内编号




ROWNUM是伪列








/* ROW_NUMBER是函数。生成组内连续唯一的数字,相同数据的排名也不同 */








SELECT ename,sal,deptno,
ROW_NUMBER() OVER(
PARTITION BY deptno
ORDER BY sal DESC
) RANK
FROM emp_milo;








/* RANK:生成组内不连续也不唯一的数字。相同数据则相同排名,会跳号,排序数字不连续 */




SELECT ename,sal,deptno,
ROW_NUMBER() OVER(
PARTITION BY deptno
ORDER BY sal DESC
) RANK
FROM emp_milo;












/* DENSE_RANK:生成组内连续但不唯一的数字。 */




SELECT ename,sal,deptno,
DENSE_RANK() OVER(
PARTITION BY deptno
ORDER BY sal DESC
) RANK
FROM emp_milo;








UNION 两张查的顺序和数量一样。只显示一个




/**********INTERSECT*****交集****job是MANAGER的,而且sal大于2500的*********/
SELECT ename,job,sal FROM emp_milo WHERE job='MANAGER'
INTERSECT
SELECT ename,job,sal FROM emp_milo WHERE sal>2500












/*************MINUS**********差集*********/
SELECT ename,job,sal FROM emp_milo WHERE job='MANAGER'
INTERSECT
SELECT ename,job,sal FROM emp_milo WHERE sal>=2500




满足上一个,不满足下一个的。也就是job是MANAGER的,但是sal在2500以下的








————————————————————————————————————————————————————




高级分组
/*********ROLLUP*****/
当字段逐个递减时,不需要用UNION ALL连多个查询结果,只需要用ROLLUP
GROUP BY ROOLUP(a,b,c)




/**************CUBE************/
CUBE:2的n个参数次方。应用实际比较少。当各种组合都要来一次的时候使用








/*********GROUPING SETS************/
其每一个参数就是一种分组方式,然后会将这些分组统计的结果并到一个结果集中显示




/*查看每天和每月的营业额*/




SELECT year_id,month_id,day_id,sum(sales_value)
FROM sales_tab_milo
GROUP BY GROUPING SETS((year_id,month_id,day_id),(month_id,day_id))




允许重复。GROUPING SETS((month_id,day_id),(month_id,day_id))








—————————————————————————————————————————————————————




视图:
CREATE VIEW 虚表名 AS subquery
所有的数据库对象是不可以重复的
试图一般都是v开头,后部分为数据来源。v_emp_dept10




其他数据库对象
包含:表,试图,索引,序列




视图
视图在SQL语句中体现的角色与表一致,但其并非一张真实存在的表,它的数据仅来自一条SELECT语句的查询结果集








视图对应的查询语句中的字段若使用别名,那么视图的该字段名就为这个别名。对应子查询的字段若含有函数或表达式,那么该
字段必须给别名












只能对简单视图进行DML增删改,复杂视图不行。因为不通用,不通用的都是一刀切。








————————————————————————————————————————————————————




对视图进行DML操作
就是对视图数据来源的基础表进行的。并且仅能对简单视图进行,复杂视图不可以进行DML操作




对视图的插入只能视图能看到的字段,其他视图外的字段都是插入默认值,为NULL,
但是如果该字段已经是NOT NULL,再插入
NULL
就违反了基表的约束条件,会报异常。








对视图进行DML操作不当会污染基表数据,指的是对视图进行的DML操作就是对基表对应数据的DML操作,但是当对视图
进行DML操作并修改基表数据后,视图对该记录不可见。




/*只有DELETE不会污染,因为虚表和基表的数据都被删除了,同步的。如果插入的是部门20,但是虚表只有部门10的数据,因此虚表无法看见  */




/* 唯一不会污染的是删除 */












/************WITH CHECK OPTION*************************/
/*  避免由于对视图进行DML污染基表,可以对视图添加检查选项 "WITH CHECK OPTION"  */




CREATE OR REPLACE VIEW v_emp_dept10_milo AS 
SELECT empno id,ename name, sal salary , deptno  FROM emp_milo WHERE deptno=10 WITH CHECK OPTION




/* 上面加上了检查语句后,之后执行的INSERT 和 UPDATE操作如果视图不可见都属于违规    */
INSERT INTO v_emp_dept10_milo (id,name,salary,deptno) VALUES(1002,'jack',3000,10)
INSERT INTO v_emp_dept10_milo (id,name,salary,deptno) VALUES (1002,'jack',3000,20)




UPDATE v_emp_dept10_milo
SET deptno=20








——————————————————————————————————————————————————————




/***WITH READ ONLY 只读选项。当视图添加了只读选项后,该视图不可以进行DML操作***/




CREATE OR REPLACE VIEW v_emp_dept10_milo AS 
SELECT empno id,ename name, sal salary , deptno  FROM emp_milo WHERE deptno=10 WITH READ ONLY




/*    就算是视图可见内的也不可以进行DML操作了    */
INSERT INTO v_emp_dept10_milo (id,name,salary,deptno) VALUES(1002,'jack',3000,10)








/* 查看创建过的所有表 */
SELECT table_name FROM user_tables








复杂视图。对应的子查询中含有函数,表达式,分组或多表关联查询,去重等操作时,该视图就是一个复杂视图。
复杂视图不能进行DML操作
/*
创建一个部门工资情况的视图
最高,最低,平均,总和工资,部门名以及部门号 */








面对复杂的,先从基础干。先查工资,再查部门




————————————————————————————————————————————————————————
删除视图中的数据会对应的将基表数据删除,但是删除视图本身,并不会影响基表数据












NOCACHE默认20个




/***********SEQUENCE************/
序列:也是数据库对象之一,作用是生成一组数字。常用于为表的主键字段生成值使用




序列中有两个伪列:
NEXTVAL:获取序列的下个值
CURRVAL:获取当前的值
CURRVAL:获取序列当前数字
序列是不能回退的,当使用NEXTVAL获取下一个数字就会导致序列发生步进。
CURRVAL是获取序列最后一次生成的数字,不会导致步进,但是新创建的序列必须至少调用一次NEXTVAL后才可以使用








/* 新创建的序列至少要调用NEXTVAL才能调用CURRVAL */
SELECT seq_emp_id_milo.CURRVAL FROM DUAL;




SELECT seq_emp_id_milo.NEXTVAL FROM DUAL;




删除:DROP SEQUENCE 序列名




两张表共享同一张序列就会产生断裂。12378
同一张表也会。即回退。但是序列不能回退。




UUID :  数字+字母 36的32次方
32位不重复字符串,也是主键生成方式的一种




前提是该字段要够长,至少32位
SELECT SYS_GUID() FROM DUAL




——————————————————————————————————————————————————
索引:
永远不要在数据量小的表建索引。经常增删改的也没必要




/*********************************************面试问题**************************************************/




合理使用索引询效率
为经常出现在WHERE子句中的列创建索引
为经常出现在ORDER BY/ DISTINST后面的字段建立索引。如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致
为经常作为表的连接条件的列上创建索引
不要在经常做DML的表上建立索引
不要在小表上建立索引
限制表上的索引数目,索引不是越多越好
删除很少被使用的,不合理 的索引








自动创建索引的是:
UNIQUE,而不是FORIGN KEY
——————————————————————————————————————————————————
存在有管理约束的SQL语句,需要则自行搜索网络
约束:
NN
UK
PK








非空约束是列级约束,在定义和修改的时候添加




非空约束修改需要具体到列ALTER TABLE  employees1_milo MODIFY(eid NUMBER(6) NOT NULL)
但是其他UK,PK CK都属于表级的,只需要直接指定哪个字段更改即可,如下:
ALTER TABLE  employees1_milo ADD CONSTRAINT  employees1_milo_email_uk UNIQUE(name);




数据库只认可单列主键
ALTER TABLE  employees2_milo ADD CONSTRAINT  employees1_milo_pk PRIMARY KEY(eid);




主键一般叫做id。不能重复,不能为NULL








外键约束:唯一的参照的关系。子表必须有父表的主键,要么父表的主键存在该数,要么关联的子表都UPDATE为空,否则父表不能删,子表不能添加父表没有的




——————————————————————————————————————————————————————
检查约束:最灵活的约束








/*    8:创建myemployee表,字段:   
  id NUMBER(4) ,
  nameVARCHAR2(20),
  birthday DATE,
  telephone VARCHAR2(11)
  scoreNUMBER(9,2)
  其中id作为主键,name要求不能为空,telephone需要唯一,score值必须>=0   */




CREATE TABLE myemployee_milo ( id NUMBER(4) PRIMARY KEY , name VARCHAR2(20) NOT NULL, 
             birthday DATE,telephone VARCHAR2(11) UNIQUE, score NUMBER(9,2) ,CONSTRAINT myemployee_milo_socre_check CHECK(score>=0) )












//注意
1, score定义后面需要逗号,因为不是非空约束,CHECK和PRIMARY KEY 和 UNIQUE都是表级的,
只有NOT NULL才是 列级的,属于该字段,因此不能在CONSTRAINT前加逗号
2, CREATE TABLE时不需要在CONSTRAINT前加ADD。因为ADD是属于ALTER的固定搭配ALTER TABLE 。。ADD。。








——————————————————————————————————————————————————————————
<<<<<<<<<<<<<<JDBC>>>>>>>>>>>>>>








CHECK ID~!!!!!!!




pom.xml:com.oracle ojdbc14
10.2.0.4.0 jar




statement的executeQuery专门用来select的




boolean execute本身也是什么语句都能执行。insert返回false,只有查询的才返回true,通常用DDL,创建表等。








没拼一条最后都空格。否则变成下一条的第一个单词跟上一个末尾单词变成了同一个单词




jdbc事务默认自动提交。一执行就提交了








ResultSet逐行进行。先问问有没有结果集,有,才获取。跟Iterator一样




java中不要用*号查询,因为db需要先查db结构。建议全部查询也把全字段写上








这种用来表示数据库某张表的类成为“实体类” 也就是:PO








功能方法应该只调用步骤。需要几个步骤就调用几个方法








DDL->execute




会改变SQL语句:
请输入密码:123' OR '1'='1








如果登录密码输入:'123' OR '1'='1'则实际在SQL的语句变成了下面这样:
这里实际上用到了AND 和 OR优先级。改变SQL语义了。通常不会用statement进行拼接,不安全而且执行效率低下
SQL注入:WHERE username='gjagagk' AND  password='123' OR '1'='1'




xss攻击: HTML注入式攻击








——————————————————————————————————————————————————————
自动插入1000条速度慢,因为:
每插入一条就提交事务。SQL需要理解该语句做什么。SQL生成执行计划->执行该计划。SQL会把每一个statement当作新的,生成
执行计划很慢








Scanner 如果用System.in不要关闭








config.properties 读来的都是字符串,无论是否数字
简单的




注释也不能写中文




格式固定的。跟map相似。




等号两边无空格,后面无分号








不用每次都传参数。只需要放到大家等能看到的地方。




ThreadLocal<T> t;内部就是map。相当于为每个线程提供的仓库
key就是当前线程




只要把该线程存入到仓库,只要是该线程的,方法都可以调用该线程








就像行李箱,去哪里都要带着




tl就像不带行李箱,去到哪里都刷脸




现实中唯一像ThreadLocal就是银行卡,去到任何地方都可以刷卡取款




池:重用,控制数量




maxwait阻塞时间,超过指定时间就报异常








——————————————————————————————————————————————————————————
可滚动结果集:跟ResultSet 的 next方法不同的是 可以上滚




每次调用一体记录都要跟数据库通讯。实际工作中不使用
MYSQL跟其他不同,是一次性把结果集给java,其他都在SQL中
因此MYSQL必须要分页查。ORACLE不用,因为结果集都在SQL中
查一次,遍历一遍放到集合中,再关闭连接,节省资源








事务是默认提交的
try里面有return只是跳出try,后面的finally依旧会执行




针对一个数据库一个表对应一个DAO








Spring 有个:AOC








——————————————————————————————————————————————————————————
错误!报无此列错误,因为序列没有加NEXTVAL
INSERT INTO userinfo_milo(id,username,password,email,nickname,account)VALUES(seq_userinfo_id_milo,jack,666666,jj@jj.com,jj,8000)
——————————————————————————————————————————
INSERT INTO userinfo_milo(id,username,password,email,nickname,account)VALUES(seq_userinfo_id_milo.NEXTVAL,jack,666666,jj@jj.com,jj,8000)








数据库最大支持五六百个客户端连接
线程池最大的好处就是管理上限






————————————————————————————————————————————
part 6


DDL
DML
DQL
TCL




HTML解释执行,非编译执行
提高开发效率:框架 SpringMVC / struts2------->
针对:Servlet的框架: SpringMVC / struts2
针对:JDBC的框架:MyBatis / Hibernate
管理java创建的对象:Spring




针对前端的HTML/CSS/JS的框架:jQuery




面试问题:说说HTML的原理????????








AJAX:通讯。学XML传输。在这之前都是XML存储




双标签:<student></student>




单标签:<student/>




new Maven Project需要选war,war才是web项目
右键Deployment Descriptor:WebBasic,选择generate...红色即消失,消失原理,
十天后讲








元素:包含有属性,标签和内容???的整体








HTML
XHTML 严格遵守XML规范
网页是面向用户的,不能因为某一段语法错误都不显示了。
在用的都是HTML为主












html支持六级标题.一般3级就够了。
h1到h6




段落:p




列表。前边是点的为无序列表。数字的为有序
有序:ol
无序:ul




单标签:换行的:<br/>
<meta>








XML的属性位置是不固定的
顶部默认是锚点,不需要另外设置
<p>
<a herf="#">回到顶部</a>
</p>




colspan/rowspan跨行跨列,相当于表格的合并
必须是从左向右,不能跟表格一样两边都可以合并




rowspan=“2”跨2行




<div style="color:red width:960px;margin:0 auto








margin是整体居中。内容是align="center"








切记:换行是单标签<br/>




不能用div分table,不然破坏了table的结构。只能用<thead> <tbody> <tfoot>












简要描述行内元素和块级元素的区别。




参考答案




块级元素的前后都会自动换行,如同存在换行符一样。默认情况下,块级元素会独占一行。例如,<p>、<hn>、<div>都是块级元素。在显示这些元素中间的文本时,都将从新行中开始显示,其后的内容也将在新行中显示。




行内元素可以和其他行内元素位于同一行,在浏览器中显示时不会换行。例如,<a>、<span>等。




我们可以这样理解:如果元素是块级的,则总是在新行上显示,好比是书中的一个新段落;而元素如果是行内的,那么只能在当前行中显示,就像是段落中的一个单词。




因此,块级元素常用来构建网页上比较大的结构,用于包含其他块级元素、行内元素和文本;而行内元素一般只能包含其他行内元素和文本。




































——————————————————————————————————————————————————
day02








input元素(具有不同的外观)
文本框,密码框
单选框,复选框
按钮
隐藏域




换行p和br都可以。




——————————————————————————————————————————————
<!-- 单选框 设置组名,同一组单选会互斥-->
<p>
性别:
<input type="radio" name="gender"/>男
<input type="radio" name="gender"/>女
</p>








————————————————————————————————
label是将文本和选择框作为一个整体。就是控件+id




文本域双标签中间的字就是默认值,而不是用value








<style>
/*CSS的注释是酱紫的*/

</style>








h1 {color:red;font-size:12px;}
h1:选择器
color:属性
red:值
color:red:声明




CSS规则特性:
继承性:
颜色字体能继承,大小边框不行
层叠性:不冲突的声明可以叠加




优先级:哪个离样式近就优先级高。新的样式可以覆盖旧的












id在style中是以#开头
class类型的在style中是以.开头




——————————————————————————————————————————————————————




选择器组




派生选择器:




类选择器class范围小点
精准直接定位id




伪列选择器:用于设置同一个元素在不同状态下样式。
如导航网站点过的连接都变色,没点的是原来的颜色




:link向未被访问的超链接添加样式
:visited已访问的...





————————————————————————————————————————————————————
css声明:








boder样式单位:
em:lem等于当前的字体尺寸,2em等于当前字体尺寸的2倍,比如所有首行字放大的时候用
px
%




做pc端的可以固定宽为960px
手机的尺寸多,因此多用百分比








16进制颜色:
#4FC56D
红:4F
绿:C5
蓝:6D




-#EEEEEE双位相同的可以简写为:-#EEE
工作的时候颜色用取色器取色即可。如PS,FastStone








——————————————————————————————————————————————————




overflow当内容溢出元素框时的处理:








visible
scrol




————————————————————————————————————————————————————
1.box模型:
实际占宽=width+2padding+2margin+2border




实际占高=height+2padding+2margin+2border












p默认带边距
div默认不带




给元素设置内边距后,它看起来更大
给元素设置外边距后,它占有的空间变大了,就是跟其他元素的距离从默认的0变成了指定的距离








padding:10px 20px 30px 40px; 上右下左
margin:40px 30px 20px 10px;













————————————————————————————————————————————————
量尺寸:ps dreamweaver firework
工作中样式很少用id,不好复用。用class更灵活,便于扩张。将来学js和jaxon多id




在css中,
一开始做一些基础的声明,把边距都先改为0




设置body的边距为零,其子元素能继承吗?不能。只有颜色和字体能,其他都不能继承
可以选择*,代表一切








选择器的优先级:
元素选择器:1
类选择器:10
id选择器:100
.data:10
.content div:10+1








越精准分越高
分数高者优先




——————————————————————————————————————————————————————
web三要素:
服务器
浏览器
网络传输
















当行高等于元素的高时,内容垂直居中




内边距:元素会变大
外边距margin:跟其他的距离,元素本身不会变大








表格特有属性:边框合并折叠,即取消中间的空格
border-collapse:collapse








css的边框单元格需要另外设置




—————————————————————————————————————————————————————————
定位:








就算被遮挡浏览器也会将文字显示




w3c建议用id,但是在生产环境中考虑到扩展性,都用class
在哪个元素写上clear,那么该元素就 不受浮动影响,会出现在浮动元素的下方
clear:left;消除左浮动的影响,如果元素是右浮动的,就right。
clear谁,谁就出现在浮动的下方。












照片墙:通常用列表,不是div。只有一组相似的东西,就用列表。能缓存重用渲染,而且渲染效率更高。div会被每一次渲染div,渲染效率低




解决块元素横向摆放的问题用浮动












定位:
相对定位:不脱离流,小范围移动。案例:照片的抖动,鼠标移上去就移动2px,偏移量小。




绝对定位:想以谁为坐标,就给谁position属性。若父和爷都有position,实行就近原则,以父为目标
若父辈都没有,则以body。
偏移位置比较大,会离队








父辈的position一定要有,具体相对或绝对无关紧要








文字的透明度????




固定定位:常用于“回到顶部”和广告条
元素永远挂在窗口上,不会随着滚动条而滚动




离谁近就以谁为基准




如何选择定位:
1.固定定位:看元素是否要挂在窗口上保持不动
2.浮动定位:看块元素是否要横向排列。float,红绿蓝案例
3.相对定位:看元素是否要释放位置,偏移量很小
4.绝对定位:15秒内没想出来一般就是绝对定位








——————————————————————————————————————————————————————————
堆叠:
z-index属性。数值越大越在上方,越小越在底部








list-style-type




——————————————————————————————————————————————————————————




元素的显示方式:
块:有宽高,垂直排列
h1,p,div,ol,ul,table,form
行内元素:从左至右。无宽高,
span,a,br,strong,i,em,u,del,b,label
行内块:有宽高,水平排列
input,img,select,textarea




如何修改显示方式:
通过display属性加以修改
block:块
inline:行内
inline-block:行内块
none:隐藏此元素
实际中一般不会修改显示












——————————————————————————————————————————————————————————
javascript




























事件定义式----------相当于内部样式
嵌入式--------------相当于css的内联式
文件调用式----------相当于css的外联式




js中不区分单双引号
<script>可以在head写也可以在body里写,而css的style只能在head写




js中的函数都是公有的,不需要写修饰符




不区分变量的类型,都是var。未赋值的都是undefined




不区分整数小数,都是数字类型




















浏览器提供的叫做外部对象




特殊类型:null undefined




内置对象:(基本类型)number String array boolean function




外部对象:windows:浏览器对象 document:文档对象




自定义对象:Object:自定义对象




后三个为重点,其中外部对象为重点的重点!自定义较简单,内置也较简单,数量比较多
















字符串优先级最高,其次是布尔值
数字+布尔值:true转换为1,false为0




数据类型转换:
toString
——所有数据类型均可转换为String类型
parseInt
————强制转换成整数,不是四舍五入的。如果不能转换,则返回NaN(not a number)
parseFloat




typeof
————查询当前类型,返回string/number/boolean/object/function/undefined
isNaN
————判断传入的数据是不是NaN。判断被检测表达式经过转换后是否不是一个数。如果不是
数则返回true,否则返回false








//只要能转成数字,就认为是数字
//只要不能转换为数字,就认为是NaN
console.log(isNaN("abc"));   //不能转,符合 not a number条件,因此true
console.log(isNaN(56));   //可以转,不符合非数字条件,则false
console.log(isNaN("5.6")); //可以转,不符合非数字条件,则false









————————————————————————————————————————————————
1.获取元素
document.getElementById(id)
2.如何获取表单控件的值
input.value
3.如何给span设置内容
span.innerHTML="";




只要从网页取元素,方式都是一样的
//获取文本框
var input = document.getElementById("num");












debug:
## 1,看报错信息




## 2.打桩




## 3.排除法+二分法
——删除一部分代码,看还是否报错,从而确定错误的范围
——建议每次删除一半
》这种方式是用来定位问题的












——————————————————————————————————————
运算符




js中5/2结果是2.5,因为整数和小数不区分




关系运算:




全等: = = =  也就是类型和数值相同
不全等: != =




双等是equals
三等是类型和值都等












————————————————————————————————————————
错误小结:




var r = parseInt(Math.random()*100));
多了个右括号,因此一直提示缺少分号;




错误:span.innerHTML("输入非法");
该方法不是用括号,而是用等号!!!!!!!!!!,正解如下:




span.innerHTML="输入非法";








!!!!!!!!!¥¥¥¥¥¥¥¥¥¥$$$$$$$$$$$$$$$$$$!!!!!!!!!!!!!!!!!!1!!!!!!!!








js中的条件表达式
java中必须返回布尔值
js中的表达式可以是任意表达式,即可以返回任何为类型值
一切空值都false,一切非空值都是true
5个空值:

null 
"" 
undefined 
NaN




在js中:
var k=get(); //从外部获取的值
if(k!=null && k!=0 && k!="" && k!=undefined && k!=NaN){
alert("ok");
}
这样明显很繁琐,反观java如下:












而在java中则是如下判断:
if(k!=null && k.equals("")){...}








所以为了避免麻烦,js支持变量当条件




js还有如下判断:
以任何数字当条件,当k是5个值的时候,则是false,只有非这5个才是true,因此符合条件能够输出
if(k){
alert("ok");
}




————————————————————————————————————————————




//也可以这样
var g="abc";
//js中g可以当条件,右边也可以。左边true
g && console.log("yes");  //能输出




var g=null;
//js中g可以当条件,右边也可以。左边为空值,false,不满足。因此不输出
g && console.log("yes");  //不输出








——————————————————————————————————————————————————————




错题:
......
else if(n=0){ //如果输入的等于0  <------------------else if的判断少了等号
span.innerHTML=1;
}else{
var s=1;
/*for(var i=n;i>0;i--){*/
for(var i=n;i;i--){//跟上一句一样   <------------------有用的知识,面试参考
s*=i;
}span.innerHTML=s;

}
.....




else if的判断少了等号!!!!!!!!!!!!
















——————————————————————————————————————————————————————
预保留的关键字:class int float等。声明所有变量都是var,而不是其他int 等等等








js常用的内置对象有:
String
Number
Boolean
Array  较难
Math
Date
RegExp  正则表达式 较难
Function  较难








String在java中length是长度:str.length()
而在js中length是对象的属性:str.length




js中方法和属性都是公有,都是可以直接访问的








x.charCodeAt(index):js中返回指定位置字符的编码




lastIndexOf:从后往前找,第一个指定字符的位置




替换字符串
---x.replace(findstr,tostr)
findstr:要找的子字符串
tostr:替换为的字符串




——————————————————————————————————————
number:




toFixed(num):转换为字符串,并保留一定位数的小数,不足的补零,多余的进行四舍五入舍入,




举例:
var data = 23.56789;
alert(data.toFixed(2)); //23.57








——————————————————————————————————————
array:
js中一切都是对象,array是,甚至函数也是对象
js中的都是Object数组,也就不限定类型




var a1=new Array();
var a2 = new Array(7);
var a4=[100,“a”,true]
var a4=[100,200,300]








var a2 = new Array();
//js的加入方式跟java的Stack一样的push。js中集合就是数组,数组就是集合
a2.push("lisi");
a2.push(23);
a2.push(false);
console.log(a2[0]);




数组的倒转和排序




倒转:
x.reverse():反向数组,改变数组x中数值的顺序




排序:
x.sort([sortfunc]):数组排序
——sortFunction:可选项,用来确定元素顺序的函数的名称




迭代==循环




sort()方法可以传一个自定义的排序方法当作参数传进Array.sort();
js中方法可以当参数




后面讲的课程都会涉及底层原理




如何了解底层原理:
1.Spring的相关书
2.或者直接看源码




课上通过图简单了解




————————————————————————————————————————————————————




Math对象的常用方法
三角函数




计算函数




数值比较函数
Math.random();




——————————————————————————————————————————————
Date对象




回顾java日期:
java.util.Date SimpleDateFormat




java.sql.Date 年月日
java.sql.Time 时分秒
java.sql.Timestamp 年月日时分秒








js的Date:
当前软件需要的时间:客户端时间,服务器时间,数据库时间
答:需要的当前时间一定以服务器或者数据库时间为准,很少直接创建客户端时间(不准),如全世界都访问淘宝
但可能服务器发送过来一个时间需要处理,为了方便将其转为js中的日期,处理完再发送给服务器








读写时间毫秒数:getTime()/setTime()




读写时间分量:
getDate()
getDay()
getFullYear()




setDate()
setDay()
setFullYear()




转换为字符串
toString()
toLocaleTimeString()
toLocaleDateString()












getDay是一周当中的第几天,返回的是4为周四












在浏览器的控制台也能编码,作为小例子或查api








_----------_________________--------------_____---------____--------__--------------








RegExp对象
//直接写
var reg1=/^\d{3,6}$/;




//写在字符串
var reg2 = new RegExp("^\\d{3,6}$");




flags标识有:
g:全局模式 没加模式默认是非全局模式
i:忽略匹配中的大小写检测








常用方法:
reg.exec(str)  检索字符串中指定的值,返回找到的值
reg.test(str)  检索字符串中指定的值,返回true或false----->工作中经常用












字符串支持正则的方法:




//1) str.replace(reg,"")
//2) str.match(reg)
//3) str.search(reg)  只返回匹配reg的字符串的索引,只返回索引




















js只能通过class改变form的颜色,没办法用id或p等。只能class








js中\w就是包括字母数字和下划线








正则调用test,把被判断的值传进来
reg.test(pwd)




表单元素有onsubmit事件,当此事件触发时浏览器就会提交数据




任何事件都可以取消,只要在事件调用函数内返回false即可
此处是返回值,不是条件,不能用空值代替false








return是一个返回值,不是条件。








<form action="http:www.tmooc.cn"
οnsubmit="return checkCode() && checkPwd()"  >
上面一句判断不严谨




<form action="http:www.tmooc.cn"
οnsubmit="return checkCode()+checkPwd()==2;"  >
js中布尔值相加,只有两个都是true也就是1才能提交表单








——————————————————————————————————————




首字母大写的Function对象,关键字小写function




默认返回undefined
也可以返回具体值或boolean等












js函数没有重载
调用想传几个就可以传几个。js会将参数封装到arguments数组中
将数组给了函数
js直接
function x(a,b){
arguments[i]
}
arguments名字是定死的。
参数0=arguments[0]
参数1=arguments[1]
...
声明多少个参数就生成多少arguments




以参数列表给arguments赋值,没有的就不管了,比如只有3,5参数的话,9就不管了








如x()  没有参数0,而是undefined
x(3)
x(3,5)
x(3,5,9)




能够直接调用的函数:全局函数。




parseInt








eval:比如计算器中:把1+3计算了再+4
var s="2+3";
alert(s);//2+3
alert(eval(s)) //5




————————————————————————————————————————————————————
鼠标事件:
onclick
onblur :光标从文本框移除后
























VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVvvv
























var g=null;
//js中g可以当条件,右边也可以。左边为空值,false,不满足。因此不输出
g && console.log("yes");








###############################################################




else{
var s=1;
/*for(var i=n;i>0;i--){*/
for(var i=n;i;i--){//跟上一句一样
s*=i;
}span.innerHTML=s;












###############################################################








<form action="http://doc.tedu.cn"
οnsubmit="return checkUser()+checkPwd()==2;"




………………………………………………………………………………




!!!!!!!!!!!!!document.getElementById("ss").value;!!!!老是忘了value












——————————————————————————————————————————————————---








获取和输出值:
input.value
input.value="" 




span.innerHTML
span.innerHTML="" 显示值




往段落p写内容跟span一样的 








eval使用案例:计算器,把前面输入的1+2直接计算后显示3,再输入+3就继续加上然后显示加上3的值;




——————————————————————————————————————————————————
<script>
function cal(){ //获取的都是字符串
//获取文本框的值
var input= document.getElementById("ss")
var ss= input.value;
//文本框要做验证,用正则表达式.防止输入的是=-+等非数字
try{
//执行算式
var result = eval(ss);
//执行如果是成功的,把结果写到input
input.value=result;

}catch(ex){  //也就是var ex
//input文本框内显示错误
input.value="Error";
}

}




</script>
</head>
<body>
<input type="text" id="ss"/>
<input type="button" value="=" οnclick="cal();"/>
















————————————————————————————————————————————————————————




外部对象:工作中天天用,显示直观的
BOM:Browser Object Model
以浏览器为对象,划分为各个模块,各个模块暴露给js,js可以调用。具体看
day07的BOM图
通过使用BOM,可移动窗口,更改状态栏文本等等,




DOM
D:document
document.getElements








1.外部对象就是浏览器的API
2.




学每一个对象的结构,每一个的方法,如何使用








——————————————————————————————————————
Window对象
alert()
confirm()




setTimeout()
clearTimeout()




setInterval()
clearInterval()




-----------------------------------_--------------------___------------




从window开始,下级对象就开始难,特别是document是其中最复杂的!!




定时器:<-----------------------------------------------重要!!!




多用于网页动态时钟,制作跑马灯效果,倒计时等




周期性定时器
以一定周期执行
一次性定时器








周期性定时器:setInterval(todoFunction ,Millistime)








<p>的输出方式和<span>一样,都是.innerHTML=;
!!!!!!!!!注意,不要老是写成innerHTML(),而是=








完整的,应该写window.alert()/window.prompt()
只有window才可以省略




day07的重点:定时器








document的api加起来比其他loction/navigator/history等等都多
作为新手,location和history用得比较多
screen:设计师,架构师做的,判断是pc/手机的屏幕从而确定调用哪一套屏幕
和navigator:如刷票,需要变换ip,变换浏览器信息。再比如判断访问网站的客户端的浏览器版本
老手用得多












——————————————————————————————————————————————
Location对象
属性:
location.href="http://www.tmooc.cn";
方法:
location.reload();












——————————————————————————————————————————————




history对象
方法:
back()
foward()
go(num) :num如果是-2则相当于单击两次后退按钮












---——————————————————————————————————————————




screen属性:用于获取屏幕的分辨率和色彩
常用属性:
-width/height
-availWidth/availHeight












----------------------------------------------------------------------------------------




navigator对象:获取客户端浏览器和操作系统
navigator.userAgent












_————————————————————————————————————————————————




document:文档节点/根节点
body/p;元素节点
class:属性节点
注释内的:注释节点
h1内的/h2内的/p内的:aaa bbb文字:文本节点




DOM操作
查找节点
读取节点信息: 如.value
修改节点信息:如span.innerHTML=
创建新节点
删除节点








节点信息:
nodeName:节点名称
文本节点:永远是#text
文档节点:永远是#document
nodeType:节点类型




——————————————————————————————————————————
元素节点:
innerText:子标签无效
innerHTML:包含子标签
————————————————————————————————————————
这里不能取到p,因为p还没被加载
<script type="text/javascript">
//在函数之外的代码在一开始执行,body在后,这时候还没加载body
var p2=document.getElementById("p2");
-————————————————————
但是以下可以,顺序就变了:这里能取到p了
//onload是网页加载事件,在网页加载完成后自动触发,触发时自动调用等于号也就是绑定的函数。
window.onload = function (){
var p2=document.getElementById("p2");
console.log(p2.nodeName);
console.log(p2.nodeType);
}




————————————————————————————————————————————————————————




document对象
添加新节点:
parentNode.appendChild(newNode)




插入:
parentNode.insertBefore(newNode,refNode)
refNode:参考节点,新节点位于此节点之前添加




如果节点下无任何子节点是不能插入的,可以添加新节点




删除节点:
node.removeChild(childNode)
删除某个子节点,childNode必须是node的子节点
由父节点删除其下属的某个节点








也可以某节点调其父节点的方式删除自己,如下:




      A
  B       C
       D     E




c.removeChild(E);
//or
E.parentNode.removeChild(E);












————————————————————————————————————
td----->column
tr ---> row
th  --->加粗的td
放在table下的<th>跟放在<table>下的<thead>下的<th>一样,
反正,无论td还是th都放在行下,也就是tr下




th和td一样,th是特殊的td,加粗的td




——————————————————————————————————————————————————————




var obj= e.target || e.srcElement;  ----------------------------------->?????????????????????
获取event对象的两种判断
为什么要try catch,什么时候要try catch,是只有用eval等特例才需要try catch吗????????????????




自答:因为是磁盘IO操作




——————————————————————————————————————————————————————
能操作能输入的都有值,就算是input的radio也有值,下拉选select和文本域textarea都有值比如label就没有值
内容就是双标签中的文本。
比如按钮就没办法写字,按钮就属于input的一种




段落有内容,但没有值.
input有值,没有内容。




有内容的用.innerHTML
有值的用.value




//只有如下表单控件有值
//input,select,textarea.




总之,只有input,select,textarea. 才能用value,其他都用innerHTML




<img/>图片不能输入则没有值,是单标签因此没有内容,只有属性如id,src
















——————————————————————————————————————————————————————








接day07的demo6.html
//3.读写节点的值
//只有如下表单控件有值
//input,select,textarea.
var input=document.getElementById("b1");
console.log(input.value);
input.value="BBB";
//4.读写节点的属性
//4.1通过(标准的)方法读写属性(*)
//4.2通过属性名读写属性
//1)标准的属性名(*)












//className,id,style-->className用得多,外联内联样式多,在day06模拟登录的案例用过,而style用得少





//2)非标准的属性名




应该学习标准的api。*号的重点学记




获取节点属性:
getAttribute()
setAttribute()
removeAttribute()
————————————————————————————————————————————————————




如何修改显示方式:
通过display属性加以修改
block:块
inline:行内
inline-block:行内块
none:隐藏此元素
实际中一般不会修改显示
















-------------------————————————---------------------------------------————————
day08
图片轮播








style内的注释不能用//,只能用/**/   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
















//1.根据id查询
//document.getElementById("id");




//2.根据标签名查询
//document.getElementsByTagName("标签名");




//3.根据层次查询
//查询某节点的亲属(父亲,孩子,兄弟)
var bj = document.getElementById("bj");
//3.1查询父亲
var ul = bj.parentNode;
console.log(ul);
//3.2查询孩子
//带文本(空格)
console.log(ul.childNodes);




//4.根据元素的name属性查询,往往在单选上。如radio。或者多选checkbox
var radios = document.getElementsByName("sex");




对节点的增删改工作中天天用哟
















select.value
1.默认返回你选中的那个option的内容
如果selcet.value返回的序号跟城市数组(如案例的城市)的排列顺序一致即可
2.当增加value属性后,返回你选中的那个option的value值。注意:value的值由你来设置,看具体情况
如:








 p = document.getElementById("province");
var cities = province_cities[p.value];  








th和td一样,th是特殊的td,加粗的td




this在button事件中就是正在点的那个元素的值
























colspan合并列
colrow合并行












只要是网页上获取的都是字符串,value跟innerHTML都是获取到字符串。当做加法的时候必须要转成int或者float
但是乘法可以不用
var mny = price*text.value;




因为乘法有自动转型












DOM操作是工作中用得最多的地方








————————————————————————————————————————————————-
自定义对象。数据类型中的第四种
--直接创建对象
--使用构造器创建对象
--使用JSON创建对象




自定义对象
1.直接量,JSON对象
-{}大括号代表对象,里面包含多组键值对。key:value,key:value,key:value
function,date等只要是对象在js都能当成值
-key通常是字符串,
-value可以是各种类型的
2.构造器------------------->用来new的函数/首字母大写
使用中不是调用,而是new它
2.1内置构造器
---->特殊:Array,Date,RegExp,Function
---->通用:Object
(var teacher = new Object();//别人new的时候不知道结构,有什么数据)
2.2自定义构造器,函数首字母大写
--声明参数,让调用者直观地了解对象的结构




3.归纳
  3中方式创建的对象都一样,都是Object
  若创建的对象给别人使用,建议用2.2
  若创建的对象给自己用,用1或者2.1都行
















函数就是构造器,
大写开头就是构造器,小写开头的不是








外部对象用得多
——————————————————————————————————————————————








js的后绑定有什么好处?Spring有什么好处??




2.3如何取消事件




event
#3.事件对象
  3.1什么是事件
---某些特殊的业务里可能需要使用如下内容:
----鼠标点击的坐标,具体点击了哪个按键等等
----事件触发的时候,浏览器会创建一个对象记录这些内容,记录的是给我们后续用的
----调用这个对象就可以获取这些特殊的内容
----这个对象叫做事件对象event




  3.2任何获取事件对象
---直接定义事件
----在调用函数时传入event
----在函数上通过参数接收该值 




---后绑定事件
----浏览器在调用函数时自动传入event
----在函数












-----------------————————————-------------————————————————————---




js的事件处理机制:
-4.1冒泡机制
--如果内外元素都触发了单击事件
--点击内层元素,外层的单击事件也会触发
--触发的顺序:由内向外
--这种处理机制称其为冒泡机制




-4.2作用
--简化事件的定义
--本来众多子元素都要定义单击事件
--现在只需在父元素上定义一次事件即可
--此时必须要知道事件源是谁
--事件源:点击的具体位置,事件的来源








事件对象是浏览器提供的
有些浏览器用event.stopPropagation();
有些浏览器用event.cancelBubble=true;












{
"pageX":"23";
"stopPropagation":function(){}




}








-4.3如何停止冒泡
--调用event的api可以停止




-4.4如何获取事件源
--调用event的api可以获取




————————————————————————————————————————————
eval可以把字符串做计算




js:
解释型,不需要编译,运行在网页上。语法跟java相识。
类型:4种数据类型
.................................................








——————————————————————————————————————————
补充:day06
怎么查询节点?
根据id查,根据name查,根据层次查也就是子父节点的




节点信息:
nodeName:节点名称
-元素节点和属性节点:标签或属性名称
-文本节点:永远是#text
-文档节点:永远是#document
nodeType:节点类型
-返回值
-元素节点:返回1
-属性节点:返回2
-文本节点:返回3
-注释节点:返回8
-文档节点:返回9












—————————————————————————————————————————————
________________________________________________________________________________________________




JQuery




简介:js框架,轻量级的js库。封装了js,css,DOM,提供了一致的间接的api。兼容css3,及各种浏览器
耦合度越高,就越重,耦合度越低,量级越轻。
很容易实现后绑定事件
极大简化js编程。用jQuery比js效率更高
jq2.x开始不再支持IE6 7 8 
获取事件源,api不是统一的,有两种,但在jq中只需要一种..




SpringMVC,Struts2,Mybatis,hibernate也都是轻量级框架








$("p")---->jq的选择器
css ---->jquery的








function bigger(){
//获取段落原始的字号(16px)
//获取字面上所有p。$("p")相当于document.getElementsByTagName("p");
var size = $("p").css("font-size" ); 
//为方便计算,去掉单位.把px用空字符串替换
size = size.replace("px","");
//+1后再将其设置给所有段落。用js的话改样式的话需要style或className,而且循环一个个改
$("p").css("font-size",++size+"px");
}












jquery封装的方法类似如下:
var ps = document.getElementsByTagName("p");
var jobj = new Object()
jobj.data = ps
jobj.css=function){}
jobj.width=function){}
















选择器-->DOM数组--(new)--> [jQuery对象,包含了DOM数组,该对象内包含了处理数组的方法,提供了jQueryAPI]








jQuery对象不等价于DOM对象,只是对DOM数组的封装




1.jQuery对象可以调用jQuery的API
2.jQuery对象可以调用DOM的API
3.jQuery对象是对DOM数组的封装




DOM对象只能调用DOM的api




如果要调用对方的api,可以转换:
jquery转成DOM:obj[i]
DOM可以转成jQuery:$(dom)




————————————————————————————————————————————————————————
选择器:----------------------------->重点




跟css类似,很多都一样
基本选择器:
元素选择器:$("标签名")
层次:
$("select1 select2")  跟css一样选择1下的子孙
$("select1>select2")  跟css一样选择1下的子
$("select1+select2") 选中select1元素的,满足select2的下一个弟弟
$("select1~select2") 选中select1元素的,满足select2的所有弟弟
过滤:
--基本过滤选择器***********重点**************重点************重**************!!!!!!!!!!!!!!!!!!!!!:
--first
--last
--not(selector) 把selector排除在外
--even 挑选偶数行
--odd 挑选奇数行
--eq(index) 下标等于index的元素
--gt(index) 下标大于index的元素
--lt(index) 下标小于index的元素
$("tr:first")




--内容过滤..:
--contains(text) 匹配包含给定文本的元素
--empty 匹配所有不包含子元素或文本的空元素
$("p:contains('月饼')")








--可见性过滤..:
--hidden  匹配所有的不可见元素,或type为hidden的元素
--visible 匹配所有的可见元素
$("input:hidden")








--属性过滤..:
--[attribute] 匹配具有attribute属性的元素
--[attribute=value] 匹配属性等于value的元素
--[attribute!=value]匹配属性不等于value的元素
$("input[value='你好']")
a[href]------->选择带有href的a,比如锚点就没有href,如<a></a>








--状态过滤选择
--enabled 匹配可用的元素
--disabled 匹配不可用的元素
<!-- readonly:只读,框内数据依然有效,可以提交给服务器。
disabled:禁用,框内数据无效,无法提交给服务器。 -->
<input type="text" disabled/>
--checked 匹配选中的checkbox
--selected 匹配选中的option
$("input:selected")




表单选择器:
--text
--password
--radio
--checkbox
--submit
--reset
--button
--file
--hidden








$("input:radio")   //选择单选项radio,也可以不写input这样
$(":radio") 
联想:
之前学过的




DOM如何读写节点  nodeType,跟nodeName一起学的
读写值.value。
读写内容:innerHTML
读写属性:getAttribute/setAttribute




重点:过滤选择器,其中基本过滤选择器是重点的重点!!!!!!!!!!!!!!!!!!!!!!!!!!!




——————————————————————————————————




jQuery读写节点:
读写节点的HTML内容
obj.html()/obj.html("<span>123</span>")  等价与DOM的innerHTML
读写节点的文本内容
obj.text()  / obj.text("123")            等价与DOM的innerText
读写节点的value属性值
 obj.val() /obj.val("abc");
读写节点的属性值
 obj.attr("属性名")  /obj.val("属性名","属性值")




标准的可以.的属性
style
id
className
....












————————————————————————————————————————
增删节点:




创建DOM节点:比DOM的createElement()简单
$("节点内容")  如:$("<span>你好</span>")




创建之后还要挂靠的节点树上,否则不显示
——————————————————————!!!!!!!!!!!!!!
插入DOM节点:
parent.append(obj)
parent.prepend(obj)
brother.after(obj)
brother.before(obj)




删除DOM节点:
obj.remove()
obj.remove(selector)只删除满足selector的节点
obj.empty()清空节点




把节点置空也行 $().html("");
——————————————————————————
选择器也能选择亲属
方法也能选择亲属








$("p u").xxx()要处理的节点不是自己写的,
假如使用外部提供的get方法,业务处理完后但是要处理其他节点时,因为不是自己写的,该方法内的节点如何
获取的并不知道,因此这种场景就需要使用方法来选择亲属
var obj = get()
obj.xxx()
obj.children()




——————————————————————————
遍历节点:




children()/children(selector) 直接子节点
next() /next(selector) 下一个兄弟节点
prev() /prev(selector) 上一个兄弟节点
siblings() /siblings(selector) 所有兄弟
find(selector) 查找满足选择器的所有后代
parent() 父节点









————————————————————————
一,开发项目时所遇到的对象:
# 1.$()
-通过$()获得的对象为jQuery对象
$("img") 
$(img)  将对象img转换为jQuery对象




# 2.赋值(修改)
-赋值方法通常返回的是jQuery对象
# 3.取值(读取)
-返回的是文字,那么就是DOM对象,如$().html()/.value()
-返回的是元素,那么就是jQuery对象,如.siblings




# 测试
-以控制台输出内容为准








规范:为了便于阅读,jQuery对象都在前面加$




//通过$()转换DOM为jquery对象。或者不转换,直接调用innerHTML也行
//$(btn).parent().siblings()[0].html(); 




//$($obj[i])==$obj.eq(i)      // $obj代表一个对象
$(btn).parent().siblings().eq(0).html();
//$("li:eq(0)")
//$("li").eq(0)




















————————————————————————————————————
$obj.attr("style")
$obj.attr("class")-->这个用得多,因为外部样式
但是jQuery简化的方法更方便




样式操作:
addClass("") 追加样式   ------>重点!!
removeClass("") 移除指定样式 ------>重点!!
removeClass() 移除所有样式
toggleClass("") 切换样式
hasClass("") 判断是否有某个样式
css("") 读取css的值   ------>相当于style
css("","") 设置多个样式   ------>相当于style












如:
<p class = "big"></p>
<p class = "important"></p> 
<p class = "important big"></p>  可以追加多个属性值








--——————————————————————————————————————————————————




后绑定:在页面加载完后,js取到对象,然后修改属性




jQuery也支持直接绑定,但是直接绑定的缺点是:耦合度高




后绑定的jQuery不用写window.οnlοad=function(){}
而是$(function(){
$("p") //选择器绑定事件调jQuery方法
$("p").bind("click",fun);
$("p").click(fun)  //可以简化成这样




p.οnclick=function.. //javascript则是这样写的
});




使用jQuery实现事件绑定
语法:
-$obj.bind(事件类型,事件处理函数)
-如:$obj.bind('click',fn);








——————————————————————————————————————————




合成事件--js没有的
联想:js的鼠标悬停和离开事件onmouseover/onmouseout




hover(mouseenter,mouseleaver) js本身不带这个属性,因此在后绑定事件时使用,而不是直接在<p></p>中
toggle()




使图片放大缩小的方法:
$obj.addClass();
$obj.width().height()----修改内联样式,不建议使用
$obj.css("width",:"250px")---修改内联样式,不建议使用
$obj.toggleClass(“big”)












双击:dblclick
光标移除:onblur
光标切入:onfocus




——————————————————————————————————————————




模拟操作
$obj.trigger(事件类型)
如:$obj.trigger("focus");  ----->建议用这个,下面的简写容易搞混
简写形式:$obj.focus();












——————————————————————————————————————————————












function total(){
  var $trs = $("#goods tr");
  var sum=0;
  for(var i=0;i<$trs.length;i++){
  var td=$trs.eq(i).children().eq(3);
  var m = td.text();
  sum += parseFloat(m);
  }
  $("#total").text(sum);
  }




text:纯文本
html:支持标签




innerText:子标签无效
innerHTML:包含子标签
_________________________________________________________________________________________________




function total(){
  var $trs = $("#goods").children();
  console.log($trs.length);
  var sum=0;
  for(var i=0;i<$trs.length;i++){
  console.log($trs);
  var h=$trs.eq(i).find("td:eq(3)").html();
  //var h=$trs.eq(i).children().eq(3).html();
  console.log(h);
  sum+=parseFloat(h);
  }
 
  $("#total").html(sum);
  }
_________________________________________________________________!!!!!!!!!!!__!!__!_!_!_!_!_!_!_!_!_!_!_!_!_!












!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!




注意:




1)

但凡属于<input>的,要注意不要忘了上一级$("input:button")
如:
$(":button").click(function (){




2)




jQuery的parent()不要忘了双括号!








3) hover(mouseenter,mouseleave) 模拟光标悬停事件不要忘了中间的,号!!!!!!








$(function) 相当于window.onload()
$().click(funtion(){})




——————————————————————————————————————————————
显示/隐藏的动画效果




show() /hide()
slideUP()/slideDown()
fadeOut()/fadeIn();
括号内可以传参数,为定时
如:
$("#d1").show(3000);




函数能否做为参数?原理是什么?在什么场合下用过到?
答:能!js中全部都是对象,函数也是对象。场合:定时器






//参数2是一个函数,jQuery会在动画完成后调用次函数,该函数叫回调函数,
//回调函数:完成后自动调用的函数
$("#d1").hide(3000,function(){});


//显示与隐藏的动画原理:通过定时器不断修改元素的样式。(大小,透明度)
//定时器相当于支线程,f2相当于主线程,二者并发执行,主线程不会等待支线程,
//而是立刻输出了over,支线程3秒后才完成









close/class是保留字




——————————————————————————————————————————————




自定义动画效果:
animate(偏移位置,执行时间,回调函数)
--偏移位置:{}描述动画执行之后元素的样式
--执行时间:毫秒数
--回调函数:动画执行结束后要执行的函数








$("#d1").animate({"left":"500px"},3000);
以left为准,向右偏移500px,3秒后到达位置。




回顾CSS:
默认定位
特殊定位:浮动/相对/绝对/固定 




相对/绝对/固定
共同点:设置偏移量的方式一致,以父元素为准,正负。
不同:移动方向不同












jQuery:
e.target
e.propagation()








animate:底层通过不断修改偏移量。
需要偏移位置的:绝对/固定/相对




————————————————————————————————————————————
part 8


Servelet




单机程序
网络程序-主机终端
网络程序-两层CS架构: 客户端+DB
网络程序-三层CS架构:客户端+应用服务器+db
网络程序-BS架构:B/S:Browser+Web Server + db








sun指定的一种用来扩展web服务器功能的组件规范
在servelet之前可以使用CGI(common gateway interface)程序扩展web服务












终端:chmod +x *sh    获取权限
开启:./startup.sh        不行试试sh startup.sh
关闭: ./shutdown.sh      sh shutdown.sh








1.新项目,maven项目,war包
2.deployment...
3.导包:项目属性-》targeted runtimes-》勾选apache..
4.java文件放在java Resource,网页文件如注册页面reg.html,不需要重新配置web.xml的,
那么reg.html放在src的webapp下,
注意
注意
注意
不是在WEB-INF下,而是webapp下。webapp也就是项目根目录
5.add服务器到tomcat








maven中下一个包,其相关的包都会下载下来,而不需要自己一个一个下载
比如:hevean有几十个包




导入servlet包2种方法:
1)maven的pom搜javaee,选javaee javaee-api
或者:








2)
tomcat目录下的lib:servlet
eclipse内右侧servlet右键,属性,Targeted runtimes
右侧勾选Apache Tomcat,ok




src/main/resources内放自己写的配置文件




在java Resources的src/main/java建包




新建包,同时需要选择父类,选择HttpServlet-javax.servlet.http




新建TimeServlet.java后需要重写父类方法。右键,source-》Override..




选择:
service(HttpServletRequest,HttpServletResponse)








servlet:server let 服务的小片段




// TODO Auto-generated method stub 待完成








类名:一个对象,正名
别名是为了引用方便
  <!-- 1.配置Servlet类,给它取一个别名。 -->
  <servlet>
  <servlet-name>time</servlet-name>
  <servlet-class>web.TimeServlet</servlet-class>
  </servlet>




<!-- 2.通过别名引用一个类,给它设置一个网络访问路径(网名),它必须以/开头。 -->
  <servlet-mapping>
  <servlet-name>time</servlet-name>
  <url-pattern>/ts</url-pattern>
  </servlet-mapping>












上面web.xml写完后,tomcat右键add_remove.左侧服务器add到右侧
这时servlet1将会被拷贝到之前在tomcat上双击配置的第二个的设置
也就是tomcat的安装目录








500:拼写错误,类名写错
405:方法声明有误
404:找不到资源




该了代码需要:tomcat右键publish








java能不能做网页:就是用servlet
php/python/java都是服务端程序
静态是网页是HTML,动态网页也是HTML,但是动态是用java拼的








回顾:JDBC/SQL的事务的4个协议:???????????????????/






————————————————————————————————————————————————————








## 4.对开发者的要求
#### 4.1 不需要我们做的事情
-浏览器和服务器通信的过程已经由他们实现了
-请求数据的打包(3部分)由浏览器实现了
-响应数据的打包(3部分)由浏览器实现了




### 4.2需要我们做的事情
-请求及响应的业务数据由开发者提供
-使用request处理请求数据,使用response处理响应数据
》》》学会使用request和response








迭代器是23中设计模式之一。
设计模式:
哪里用到了迭代器模式:JDBC的ResultSet,Iterator,Enumeration
迭代器基本都是while
















响应数据包组成:
状态行:HTTP/1.1 200 OK 中的数字200表示成功,否则是404或者500等








reg.html不需要在web.xml配置








req.getParameter("") 取单个
如:
String user = req.getParameter("username");
req.getParameterValues("");
如:
String[] interests = req.getParameterValues("interest");




————————————————————————————————————————




<body>
<!-- action中路径的声明方式:
1.完整路径
http://localhost:8080/servlet2/reg
2.绝对路径
规则:/项目名/访问路径
举例:/servlet2/reg
3.相对路径
当前网页和目标网页的相对关系
当前:/servlet2/reg.html
目标:/servlet2/reg
相对路径是reg
上级写../
注意:绝对路径以/开头,相对路径不以/开头
-->
<form action = "reg" >
<p>账号:
。。。。。。。。。
。。。。。。。。。




request/response本次请求结束就会被销毁








//1.1--请求行request line
req.getMethod();
req.getServletPath();
req.getProtocol();








get和post请求的区别:
GET:通过路径发送数据,通过路径传参
缺点:参数传递过程中能够被看到,隐私性差
可以传少量数据
》》所有的请求默认都是get请求




POST:不是通过路径(请求行)传参,而是用实体内容(实体内容:具体的业务)传参
参数在传递过程中不可见,隐私性好
传递的数据大小不受限制
》》当form上增加了mothod="post"




## 4.如何选择?
查询时用get,一般查询条件较少
保存/提交时用post,此时数据较多








## 5.可以通过浏览器观察请求方式
-f12
-打开network








!!!!!!!!!




网上传输只能用byte不能用字符串,字节可以不需要指定编码,字符串需要指定字符集编码




_______________________________________________
mysql:show variables like "$char"




_______________________________________________








原来:
1 html页面表单form的action提交的对象就是web.xml的url-pattern
两者如果不一致就报404错。次分析在课件day01.html




2 注意缓存的问题,更改后使用HTML应该多次刷新后再试。如果路径名的后面还是之前的当然还是会
报错的。比如之前的action="aaa",改了之后而且web.xml也对应改了之后要注意看浏览器路径名是否
还是之前的  localhost:8080/项目名/aaa/




3 重启tomcat








访问静态网页路径:项目名/静态网页名.html ,如http://localhost:8080/svt/zhuce.html
访问动态的:项目名/url-pattern名 如:http://localhost:8080/svt/reg








————————————————————————————————————————————
day01




序列化:如果需要把数据存到硬盘或者网络传输都需要序列化








补充内容:
JavaBean:满足如下规范的类就叫bean
--必须要有包pacakage
--必须要有默认构造器
--必须要实现序列化接口
--通常有get/set方法




》》建议初学者将所有的类都满足规范








真正应用中dao需要实现一个接口




实现类写法:EmpDaoImpl








面试常用:preparedStatement和statement的区别
DBUtil如何分页:




不能返回结果集。因为DBUtil,管理连接,连接后才进行操作,获取结果集等等。之后就关闭
连接。刚给出结果集就关闭连接,则获取到的结果集什么都没有




因此,需要放到集合再关闭连接关闭回收资源如结果集












//1. 接收浏览器传过来的数据
//2. 查询数据库,增删改
//3. 返回响应信息








浏览器一旦提示保存,说明是格式错了,浏览器无法解析:如下text写成test
res.setContentType("test/html ; charset=utf-8");












tomcat下的部署的代码,也就是运行时的代码
workspace的是源代码




两者的结构不一样




开发还是在包模式下开发,也就是src/main/java
看则可以在src下看,因为src下也有








五。servlet访问路径的配置方式
## 1.精确匹配(/hi)
- 只有/hi这个名字可以访问此Servlet
- 此Servlet只能处理一个请求




## 2.通配符(/*)
- 所有的名字都可以访问此Servlet
- 此Servlet能处理一切请求
——如:<url-pattern>/*</url-pattern>








## 3.后缀(*.hi)
- 所有以hi为后缀的名字都可以访问此Servlet
- 此Servlet能处理多个请求
——如:<url-pattern>*.duang</url-pattern>
 
实际工作中第3中更灵活:如下:
do.hi
dept.hi
emp.hi




异常抛给服务器,而不是浏览器。浏览器只是请求




六:使用一个Servlet处理多个请求








Servlet的生命周期:
new:从无到有
init():已有,初始化
 1.tomcat一已启动就实例化对象
 2.然后调用无参的默认构造器初始化
 3.调用service()




tomcat要求要有默认构造器,必须是无参的
如果要传参,就只能init()




几时销毁?




————————————————————————————————————
1.默认情况下,第一次访问servlet时tomcat会创建它
2.可以修改为,启动tomcat时,tomcat就创建servlet
3.第1(new)/2(init())/4 destroy()执行一次,第3步(service())执行多次
4.每个类型的servlet都只有单(个实)例




maven的包拷贝到tomcat的该项目的lib目录下
注意:手动部署导包的话,包不会自动导到tomcat的lib目录下












DBUtil就满足两种模式:
多例的生产模式:不断创建连接
单列模式:??????????????








———————————————————————————————————————————————
day03:
ServeltContext
分页:




怎么调用*.properties:--->properties
访问xml用什么技术:--->dom4j
处理动态网页用什么技术:--->j2ee的servlet
连接数据库用什么技术:--->JDBC




ServletConfig和ServletContext对web.xml的作用相当于dom4j




一个SCT对应多个Servlet
一个SCF对应一个Servlet
很多都要用参数就用SCT




SCT/SCF的底层就是dom4j,非必要使用的,可以 不用,但是使用了更方便




一。config和context---------------->>>>>>>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 ## 1.对比
共同点:都能读取web.xml中的参数
- config和Servlet是1对1的关系
-  context和Servlet是1对多的关系
》都是为Servlet服务的




## 2.config
-  假设开发一个网页游戏,当在线人数超出限制时要排队
- 最大在线人数MaxOnline可配置
-  只在登录(LoginServlet)时验证是否超出限制
》想要给某一个Servlet预置参数用config




## 3.context
- 软件都有各种查询功能,一般都支持分页
-  分页需要已知:当前页,每页显示多少条size
- 其中size一般可配置
- 多个查询功能都要使用size,使用context预置比较合理
》想要给多个Servlet预置参数用context








换一个servlet就换一个config
tomcat启动时启动n个Servlet,共用context




## 4.context特殊的用途
- 提示:之前使用config和context读取的都是常量
- context还可以读写变量。而config只能读取常量
















专门建一个类用来做初始化
context在所有的servlet之前就已经创建
<load-on-startup>1</load-on-startup>可以先初始化后创建。数字1为最高优先级




InitServlet.init()  该类不需要重写service方法,不处理业务,只是初始化




————————————————————————————————————————————




Servlet上下文:理解为Servlet环境/
特点:
- 惟一性(一个Web应用对应一个servlet)
- 一直存在(只要容器不关闭,应用没有被卸载删除,servlet上下文就一直存在
————————————————————————————————————————————




二。Servlet线程安全问题:




## 1.什么时候有线程安全问题
 ### 局部变量:
- 局部变量存储于栈内
- 每个线程都有自己的栈针
》同时修改局部变量没有问题
 ### 成员变量
- 成员变量存储在堆内
- 多个线程共享同一份成员变量
》同时,并发修改同一个成员变量有问题




## 2.如何解决:




















——————————————————————————————————————————————————————




>>>>>>>>>>>>>>>>>>>JSP<<<<<<<<<<<<<<<<<<




Servlet拼网页很麻烦,参考FindEmpServlet.java




Servlet有什么用?




---->处理HTTP协议。动态拼接网页




JSP?----->作用同Servlet。
Servlet:创建类,类中写标签。
JSP:在标签内写java。如,复制美工的静态网页,再在里面写java








JSP注释:




<!-- --> 不忽略java
<%-- --%> 万能注释,忽略java




语法规则:
表达式:
<%= %>




小脚本:
<% %>












page指令:
<%@page contentType="image/gif" %> 
作用相当于Servlet的response.setContentType("image/gif");




JSP默认是text,可以不写。但是用图片等的时候需要写








jsp运行原理:详情看课件图片
找到jsp后翻译成Servlet
pageEncoding在翻译的时候被调用用








jsp里面能直接使用array,date等。因为是内置对象,也就是隐含对象(*)




jsp生成的java文件中就是在jsp代码前先声明变量




面试题:
请列举9个JSP隐含对象以及类型:












tomcat每一个项目只有一个context




注意:




JSP的开头的import导包不能用分号;结尾!!!!!!!!!!!!!!!




——————————————————————————————————————————————




Day05
转发:




Spring和SpringMVC是包含关系




# 一。开发模式




## 












Model1:java套标签,标签套java,耦合度高
使用一个组件(要么servlet要么JSP)处理请求,处理业务,显示数据




没有公司用Model1,过时的












## 2.Model 2(面试题,极为重要!!!!!!)
把之前的一个组件干的事变成两个组件干
>>>>>------MVC-----<<<<<
引入了MVC设计模式对代码解藕。80s就有了,java中只是sun引入而已。
MVC是经典的设计模式,是代码的分层思想。
M--Model,业务层,用来处理业务
V--View,视图层,用来显示数据
C--Controller,控制层,用来调度,是业务层和视图层的桥梁
该模式可以对代码解藕,便于团队开发以及维护








————————————————————————————————————
FindEmpServlet.service(req,res)
jsp生成的对象是只有的:EmpListServlet.service(req.res)




实际上就是把req和res参数传给jsp生成的类Servlet的service()
声明变量
write标签
保留脚本
print表达式




————————————————————————————————————
Servlet调用了jsp生成的那个类,然后把req和res传给它
jsp不会乱调用其他的类,只有调用9个隐式对象




以后不要直接访问jsp,而应该访问作为Controller的Servlet。
在项目jsp2的员工查询案例中,不能再像之前那么访问emp_list.jsp了,而跟之前的之前学servlet那样访问servlet
而且,回忆下,在web.xml不是已经做了配置了吗?在之前(day04)刚用jsp时都不需要配置web.xml的




之前的jsp中直接写java业务代码,数据不可控
Model2的MVC中,业务直接在java中写,jsp只将业务结果显示,如案例中的emp_list.jsp只把接收到的查询结果显示出来
————————————————————————————————————————————————————
//1.接收参数

//2.查询所有的员工
EmpDao dao = new EmpDaoImpl();
List<Emp> list = dao.findAll();

// /webapp/emp_list.jsp
//将请求转发给jsp,让它继续处理

//把数据存到request。转发时通过request给对方

req.setAttribute("emps",list); //为什么是用Attribute?是跟ServletContext一样意思?

//当前: /jsp2/findEmp
//目标路径: /jsp2/emp_list.jsp
req.getRequestDispatcher("emp_list.jsp").forward(req,res); //取到转发器。把req和res给jsp











Forward:通知服务器,让服务器去转发




request和response是一个对象,放在堆中。
FindEmpServlet调用request和response,然后把处理好的业务数据给回request和response,然后
通知服务器转发。服务器再根据目的地找emp_list.jsp,把jsp翻译成java,然后request和response开始转发给
jsp的java,最后输出




————————————————————————————————————————————————————








面试题:转发和重定向的区别:
相同点:都是解决web组件之间的跳转问题
web组件:Servlet或JSP
区别:
--两者相互依赖时用转发




转发的特点:
--1.一次请求。也就是只有一个request
--2.地址不变
--3.服务器的A和B共用一个request,它们可以通过request共享数据
--4.只能将请求转发给项目内部的组件




重定向:
--1.二次请求
--2.地址会改变
--3.服务端的A和B使用不同的request,不能通过request共享数据
--4.可以将请求重定向到项目外部的组件








何时用转发或重定向?
--查询时用转发
--增删改后重定向到查询












——————————————————————————————————————————————




day6 7 8 是补充。2天 day09半天
先讲day09,EL表达式/JSTL在实际中很常用。
明天和下周一做项目
然后讲day 6 7 8












req








EL底层用到了类反射机制,因此jsp中不再需要import了
EL的第一个作用:获取bean属性,也就是javabean属性。
什么是javabean:








补充内容:
JavaBean:满足如下规范的类就叫bean
--必须要有包pacakage
--必须要有默认构造器
--必须要实现序列化接口
--通常有get/set方法




案例如下




告知这个类的名字是什么,就能自己去找
如告知stu类,getName








  <servlet>
  <servlet-name>findStudent</servlet-name>
  <servlet-class>web.FindStudentServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  <servlet-name>findStudent</servlet-name>   //这里如果上下不一致,tomcat的Server也会开不起来
  <url-pattern>/findStudent</url-pattern>
  </servlet-mapping>




————————————————————————————————————
<!-- request.getAttribute("stu").getName() --> request.getAttribute("stu")获取的是Object
需要强转
<p>姓名:${stu.name }</p>
<!-- request.getAttribute("stu").getAge() -->
<p>年龄:${stu["age"] }</p>
<!-- request.getAttribute("stu").getId() -->  
<p>课程:${stu.course.id }</p>    




这里的id相当于自动补充了前面的get,组成getId()方法,当然不是属性,因为属性是私有的,当然不能访问,如Course类如下:




---->>




//Bean的属性id
//1.透过get方法所看到的属性
//2.去掉get然后首字母小写所获得的词
public Integer getId() {
return courseId;
}




————————————————————————————————————————————————




<!-- 
EL默认从下面4个对象中依次取值,这些对象都是隐含对象(内置对象),它们是EL的取值范围:
按照顺序取值,如果下面4个中都没有,就返回null
page->request->session->application




也可以明确指定取值的范围:
sessionScope.stu.name
requestScope.stu.name
 -->








EL表达式的+号只能求和,不能拼接字符串




——————————————————————————————————————————————




用JSTL需要导包。需要pom里面搜索:
JSTL,
jstl jstl 1.2 jar




包下的META-INF下的tld实际是xml的标签,c-..是核心的标签库




如果是maven导包的,会自动拷贝到tomcat目录的lib下
如果是自己网页下载的,需要手动拷贝到tomcat/wtpwebapps/项目/WEB-INF/lib下








  <short-name>c</short-name>  用的时候就是用这个短名
  <uri>http://java.sun.com/jsp/jstl/core</uri>  这不是网址,是名字




然后在自己的jsp页面开头就这样:




<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>




















服务器只会调用无参的




PageContext是一个管理者,可以调用另外的8个内置对象
tld的1-6都可以照抄
<validator>验证可以不写
自定义的tld要放在webapp/WEB-INF目录下












——————————————————————————————————————————




netctoss资费计费系统项目:




新建maven项目,导包:
1.导包:jstl
选择:jstl 1.2
2.导包:ojdbc
选择:com.oracle ojdbc14
10.2.0.4.0jar
3.导包:commons-dbcp
选择:commons-dbcp commons-dbcp的
commons-dbcp:1.4








DBUtil的config_properties文件不能放在项目的根目录下,而是必须放到
resource,只有这里项目部署的时候在会编译到正确位置




为何用ThreadLocal:








多次访问数据库,在查询过程中需要遍历,同时又要增删改等等,
如转账,查,取,查...




costDao.find()
EmpDao.update()
两者共用一个连接,因此DBUtil连接数据库就用ThreadLocal




学习云笔记的时候能加深对ThreadLocal的理解
如一注册就送一个笔记本,就可以在笔记本上记录数据
一个事务一个连接




log4j:记日志












选中代码,然后alt+shift+m就能自动加入到新方法中




获取路径名的4种方法:
Servlet
???????












find.jsp为何放到WEB-INF目录下?
java项目中WEB-INF里面的项目会被保护,不能直接被访问
而PHP则需要程序员自己写方法保护








netctoss_v1
--images
--style
--WEB-INF
图片放到项目根目录下了,jsp里面引入图片为何不是../images/01.jpg而是变成同级目录的路径images/01.jpg
答:因为访问的是动态网页,浏览器不知道有jsp。
地址栏是这样访问的:http://localhost:8080/netctoss_v1/findCost.do
也就是说访问的是findCost.do,而findCost.do是在项目netctoss_v1目录下的,这时候还没jsp的事。详细可以
查看浏览器的请求,最先请求的是findCost.do












重定向的使用:在项目EmpManager








日期如何插入数据库?序列呢?








就算是add页面也一并满足MVC模式,用MVC模式的话则全部都满足,方便后期扩展需求,如统一记录日志,敏感词,登录状态等,而不需要针对某个页面特殊处理重写一遍












表单提交的3要求:




1.目标和发送方式
2.name
3.设置value
















谁访问目标,谁就在那个位置








                    <!-- 
                    表单元素form有如下两个提交方式:
                    1.onsubmit事件
                    该事件通过submit按钮自动触发
                   2.submit()方法
                    通过js调用这个方法
                     -->
连接里面不能直接写方法,必须先声明
                        <a href="javascript:">








//注意没有s,submit是方法
<a href="javascript:document.forms[0].submit();">




获取表单元素有哪些方法:
1. ByName是表单空间才能用
2. ById
3. ByTagName
4. 根据层次节点查询




document.forms[0].submit()"得到的是form数组,
等价于document.getElementBy??




登录页面之所以没反应,主要在
1.表单的username和password重复了,已经有name=""的情况下还加了name="adminCode"和name="password"
2.表单提交代码多处写错
<a href="javascript:document.forms[0].submit();">
中的document多了s,
submit少了()




——————————————————————————————————————————————————————








浏览器给servlet传参:location.href="toDeleteCost.do?id=${c.costId}";但是是get方法的,不是post




el的功能:
1.获取bean的属性
2.取到数据可以直接运算
3.直接获取请求参数:  在jsp上写:value=${param.adminCode}








el取到数据如果是空的,不会返回null,而是返回“”,这样对servlet不影响








解决登录页面账号密码错误的情况下账号和密码清空的情况,
在jsp的账号和密码的input上加value值,如下:




<input name="adminCode" value="${param.adminCode }"
<input name="password" value="${param.password }"




如果单纯设置value会在框内显示出值,明显不合理。但是用el就没问题








可以存数据的:
request--》登录一个request,查询一个request,一旦登录成功就销毁登录的request.请求来了,创建,请求走了就销毁




config--》任何一个servelt都是单例的,tomcat一启动就new然后init(可以改成先初始化再new),service()可以有多个,一旦tomcat关闭就destory()。一个servlet只有一个config,如果一个请求用一个servlet呢?如FindeServlet,AddServlet,LoginServlet,这时候就没法访问不同servlet的config




context---》一个项目只有一个context。多个浏览器多用户访问,则同一个context会被覆盖








————————————————————————————————————————




jsp4_Cookies_Session项目:








Cookie没有无参的构造方法,只有2个参数的构造方法,如下:




//将其存入cookie
//Cookie中只能存一份数据,而且只能存字符串
有多个就只能new多个Cookie
Cookie c = new Cookie(要存的数据的名字,来源值)




Cookie默认是看不到的




————————————————————————————————————————
public class LoginServlet 
//接收参数
String code = req.getParameter("code");
//将其存入cookie
//Cookie中只能存一份数据,而且只能存字符串
Cookie c1 = new Cookie("code",code);

//将Cookie发送给浏览器,他会自动保存
res.addCookie(c1);

}
cookie的值可以修改,如获取name,setValue,但是记得改了之后再用addCookie()重新发送一遍
——————————————————————————————
public class IndexServlet 
//获取浏览器传入的所有cookie
Cookie[] cookies = req.getCookies();
if(cookies!=null){
res.setContentType("text/html;charset=utf-8");
PrintWriter out = res.getWriter();
for(Cookie c : cookies){
out.println(c.getName()+": "+c.getValue());
}
out.close();

}




——————————————————————————————————————————————








cookie默认存在内存中,秒数是负数,也可以存到硬盘上,如浏览器的“记住账号:
用方法:
void Cookie.setMaxAge(int seconds);
秒数如果是0则存到内存中,即刻删除




编码:
Cookie c2 = new Cookie("city",URLEncoder.encode("北京","utf-8"));








_______________________________________________________________________________________________








req.getContextPath()




浏览器出现这样是因为前一个milo的cookie对main目录有效,而后一个lvbu则对整个项目有效,两者并不冲突,不是
同一个目录因此不会覆盖,跟是否都写在硬盘上没关系。而访问cost目录的find则只能显示lvbu,因为lvbu对整个项目有效,
因此find能够访问lvbu,却不能访问milo
code: milo city: 北京 code: lvbu












Cookie的方法:
new Cookie(浏览器获取的字符串,源数据)  //创建
addCookie(c1) //发送
setMaxAge(int seconds) //设置生存时间
Cookie c2 = new Cookie("city",URLEncoder.encode("北京","utf-8"));  //编码
URLDecoder.decode("","")
setPath(req.getContextPath()) //修改生效路径
cookie只能存字符串的原因:因为要在网上传输,给浏览器用的,只能是字符串
限制:
。可以被用户禁止
。会将状态保存在浏览器端,不安全。重要数据需要encryption
。只能保存少量的数据,大约4kb
。个数有限制
。只能保存字符串




————————————————————————————————————————
快捷键:
看大纲:ctrl+o
自动装入方法:alt+shift+m








——————————————————————————————————————————————




账号可保存在客户端的cookie,但是密码不行
Cookie的三个规则:
生存时间
有效路径
——————————————————————————————————————————————
logo栏设置:
<!--  <span><%request.getCookies();%></span>  然后遍历也可以   -->




<!-- EL的默认取值范围是page,request,session,application
EL也可以从cookie中获取数据,语法:
cookie.参数名.value
 -->
<span>${adminCode}</span>  应该改成:
<span>${cookie.adminCode.value}</span>
















————————————————————————————————————————————————




Session一使用服务器就自动new,而Cookie是自己手动new的








服务器把session装到request,然后把request给LoginServlet。servlet发给服务器,服务器发给浏览器一个Cookie id如101




1。 服务器自动创建cookie
2。 服务器将sid存入cookie
3。 服务器自动将cookie发送给浏览器








浏览器再次访问服务器,服务器发现有了cookie,就不再创建了,因此也不返回sid,而是根据浏览器提供的id 101去找session(前提是session还没释放该id)
找到session后放入request,发给登录页面的servlet








一个浏览器一个cookie,session也是一个浏览器一个,sesstion保存时间一般半小时












session给浏览器一个cookie,浏览器把cookie




虽然给进session的是String类型的code,但是session返回给浏览器的是Object类型,需要强转。session因为不是在网络上传输的,因此什么类型都可以




————————————————————————————————————————————————
javaEE目录结构:
Servlet的目录结构:
WebApp
--WEB-INF用户不能直接看到的文件夹
|-web.xml web部署描述文件
|-url与Servlet对应关系












包括需要权限的也是放在WEB-INF下












n%8 和 n&7都是对8取余,有什么区别:
15%8=7
18%8=2
...[0 , 8)




不管任何数对8取余都不超过8




模运算其实就是二进制的与运算。
n=20=00010100
m=7 =00001111
-------------------
与运算就是截取后面的位数,如8则截取低三位,最大余数是7




























DMS项目非常重要!!!!!!!!!!
把DMS项目的逻辑架构做成思维导图
复习与或非/原码/反码/补码/以及浮点数格式化








HttpSession s = request.getSession(boolean flag);
true:有则使用,没有session则new
false:有则使用,没有,或虽然有sessionId但是没有session对象也是返回null,不会new。通常也不会设置为false




立即删除Session对象--》当退出或者注销的时候用:
Session.invalidate()








session默认生存时间是30分钟,tomcat也有检查时间,检查session周期




<session-config>
<session-timeout>30</session-timeout>
</session-config>








假如该用户10分钟没操作,但是还没达到生存时间30分钟,这时候就使用钝化,将session写入到硬盘,先释放内存,
因此session对象需要实现序列化




session依赖于cookie,当cookie被禁用了,session就不能用了
但是如果需要使用怎么办?使用url重写。在url上带上sessionId








<%--  <span><%request.getCookies();%></span>   然后遍历也可以   --%>




<!-- EL的默认取值范围是page,request,session,application
EL也可以从cookie中获取数据,语法:
cookie.参数名.value
 -->
<%-- <span>${cookie.adminCode.value}</span>  --%>  cookie是特殊的,特殊对待




<span>${adminCode }</span>  session是EL的默认取值范围page,request,session,application之一








string有一个忽略大小写的方法
code:用户输入的验证码
imgcode:系统生成的验证码
code.equalsIgnoreCase(imgcode)




发送给浏览器的类型可以查看tomcat的web.xml,里面有各种类型,如text/html,image/png
java对png的处理比对jpg好








读写属性3
setAttribute/getAttribute
.属性名  .id/.class/.?  如.id=要设置的值
???????












login登录页面中更改验证码
  <td><img src="createImg.do" alt="验证码" title="点击更换" οnclick="this.setAttribute('src','createImg.do');"/></td>
上一句的验证码点击对部分浏览器有效,火狐就不行,被认为源和目的一样,可以做以下改动




  <td><img src="createImg.do" alt="验证码" title="点击更换" οnclick="this.setAttribute('src','createImg.do?x='+Math.random());"/></td>




互联网公司对js更重视




_____________________________________________________________________________________________________________




cookie和session的作用(术语)
。HTTP协议是无状态协议(服务器默认没有记住浏览器)
。cookie和session是用来管理状态的(让服务器记住浏览器)
》状态:服务器记住浏览器的证明(就是一种数据)












——————————————————————————————————————————————————




过滤器/监听器:




Filter类实现的接口是javax.servlet的filter而不是其他




  <filter-mapping>
  <filter-name>log</filter-name>
  <!-- 该Filter可以过滤哪些请求路径 -->
  <!-- <url-pattern>/addCost</url-pattern>  -->
  <url-pattern>/*</url-pattern>   代表过滤所有请求
  








  <!-- 注意:多个filter之间的调用顺序以filter-mapping的顺序为准 -->








LoginFilter就看session,如果session有adminCode说明已经登录成功了
filter的强大之处在于不需要更改业务代码








—————————————————————————————————————— //通过账号判断用户是否登录
public void doFilter(ServletRequest request, 
ServletResponse response, 
FilterChain chain)
throws IOException, ServletException {





//以session为依据,获取session
//可以把request强转成HttpServletRequest
//对参数转型,便于使用,原来的ServletRequest不好用
HttpServletRequest req = (HttpServletRequest)request;

HttpServletResponse res = (HttpServletResponse)response;

HttpSession session = req.getSession();












if(adminCode==null){
//未登录,重定向到登录
res.sendRedirect(req.getContextPath()+"/toLogin.do");
}else{
//已登录,请求继续
chain.doFilter(req,res);
}








HttpServletRequest继承自ServletRequest
ServletRequest接口。javaEE提供接口
HttpServletRequest继承ServletRequest
RequestFacade实现了HttpServletRequest,有tomcat提供的实现,其他的服务器厂商的实现类不同,但是继承了接口,都适用该接口,更换了非tomcat服务器也能正常使用该接口




声明父类型,实际传入子类型




都是声明接口,是为了方便不同厂商提供不同的实现类以实现该接口












——————————————————————————————————————————————




监听器能监听到Servlet的创建/销毁的事件
只有3个事件:
request/session/context




ServletRequestListener
--
--
HttpSessionListener
--
--
ServletContextListener
--
--








写一个类,实现该接口,然后配置








————————————————————————————————————————
ServletRequest和HttpServletResponse和HttpSession返回值类型:








Interface ServletRequest:
java.lang.String getParameter(java.lang.String name)
java.lang.Object getAttribute(java.lang.String name)
void setAttribute(java.lang.String name, java.lang.Object o)








Interface HttpServletResponse:
void sendRedirect(java.lang.String location)




Interface HttpSession:
java.lang.Object getAttribute(java.lang.String name)
void invalidate()
void setAttribute(java.lang.String name, java.lang.Object value)




























jsp作用域对象:
request/session/application的作用域




request:只在单次请求中。如login和index是两个请求.request也有多个页面使用同一个请求的,如filter,?,?




session:同一个客户端,同一个浏览器.浏览器进程,只要当前页面没有被关闭(没有被程序强制清除),不管怎么跳转都是有效的




application:数据在不同的客户端中共享,服务器,只要服务器没有重启(没有被程序强制清除),数据就有效




page:只在当前jsp页面有效
从小到大:
page<request<session<application




转发是用request还是response?还是都能用?区别是?
重定向呢?
--转发使用getRequestDispatcher,因此只有request,而重定向才是response
req.setAttribute("error","密码错误");
req.getRequestDispatcher("WEB-INF/main/login.jsp").forward(req,res);




void sendRedirect(java.lang.String location)
Sends a temporary redirect response to the client using the specified redirect location URL.








res.setContentType("text/html;charset=UTF-8");












jQuery对象的访问方法?
each()
each(callback) 就像循环
$("Element").length;元素的个数,是个属性
$("Element").size();也是元素的个数,不过带括号的是方法
$("Element").get();某个元素在页面的集合,以数组的形式存储
$("Element").get(index);功能上和上面的相同,index表示第几个元素,数组的下标
$("Element").get().reverse();把得到的数组方向反转
$("Element").index($("Element2"));元素2在元素1中的索引值是


————————————————————————————————————————————————————————————




part 9






架构师:深入研究框架的设计思想,研究如何改造








Spring
——开源的,简化企业级应用开发的框架




Rod Johnson
——古典音乐博士








javaEE API:
。servlet
。jsp
。ejb
。jms
。jta
。jdbc
...
3个特点:
1.简化开发
2.管理对象
3.集成其它框架
spring可以将其它的一些框架集成进来
(比如,集成用于 任务调度的框架Quartz)。
即“不发明重复的轮子”。
(比如,可以利用spring继承mybatis(mybatis是一个用来访问数据库的框架 ))
4.?
5.?




















1. spring是什么?
是一个开源的用来简化应用开发的框架。




简化开发




spring对常用的api做了封装和简化(比如,对jdbc 做了封装,使用spring jdbc来访问数据库,就不再 需要考虑获取连接和关闭连接了)。




管理对象




spring提供了一个容器,帮我们创建对象以及建立对象 之间的依赖关系。这样做的好处是,降低对象之间的 耦合度,方便代码的维护。




集成其它框架




spring可以将其它的一些框架集成进来(比如,集成用于 任务调度的框架Quartz)。即“不发明重复的轮子”。




































































————————————————————————————————————————
1.
maven导包,
搜索spring-webmvc




选择:
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>3.2.8.RELEASE</version>
2.添加配置文件
将applicationContext.xml放到src/main/resource目录下








创建Spring:
先创建Spring类,一句话启动Spring
2.创建实体类
3.在applicationContext.xml内配置




/*
* 此行代码的作用:通过容器获得要创建的对象(注意:getBean方法的第一个参数是bean的id)
* Class对象:
Student.class:是Student在方法区中对应的class对象
*/
//Student stu1 = (Student)ac.getBean("stu1");  //强转,或加参数使用java反射机制
//使用java反射机制
Student stu1 =ac.getBean("stu1",Student.class); 




——————————————————————————————




》》》》》java反射机制简单举例:




MessageBean mb = new MessageBean("abc");
mb.sendMsg();




java底层如何处理:




java把os划分给的内存空间为3部分




栈:(一个线程一个stack)保存对象“abc”的首地址,如111
堆:对象"abc"
方法区:class对象




看方法区有没有MessageBean的class对象
class对象:编译后在硬盘上会有.class文件,但是内存里面没有,jvm调用类加载器去硬盘找到该类字节码文件,
加载到内存中变为一个对象。硬盘中是一个字节码文件,到内存中就变成了一个对象,class放到方法区




通过变量找到对象,对象通过指针指向方法区
每一个堆都有一个指针,指向方法区的方法,如sendMsg()




如:
Student stu1 =ac.getBean("stu1",Student.class); 
这里的Student.class就是class对象




Student.class:是Student在方法区中对应的class对象
——————————————————————————————————————————
静态工厂方法(了解)
<!-- factory-method属性:指定一个静态方法。
Spring容器会调用该方法来创建对象
Calendar c = Calendar.getInstance(); -->
<bean id="cal1" class="java.util.Calendar" factory-method="getInstance"></bean>












————————————————————————
















// Student stu1 =ac.getBean("stu1",Student.class);  
// System.out.println(stu1);




Calendar cal1 = ac.getBean("cal1",Calendar.class);
System.out.println(cal1);




为何已经注释了没调用stu1也会输出Student()呢?












————————————————————————————————————————————————————




作用域:




1.默认情况下,容器只会创建一个实例(单例)












——————————————————————————————————————




junit
单元测试工具,用来看模块有没有错误
导包:maven搜:junit
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>




src/test/java新建一个包和类java类












window--》showview——outline
在test1方法上右键选择run asjunit
绿色表示成功,红色错误




有了junit就不必每次写main方法测试了




在xml中:
<!-- scope属性:用来指定作用域,缺省值是
singleton(单例),如果值是prototype(原型),则会创建多个对象 -->
<bean id="sb1" class="basic.ScopeBean" scope="prototype"></bean>








——————————————————————————————————




生命周期相关的两个方法
初始化方法:对象被调用之前获取资源,只执行一次
销毁方法:(释放资源),只执行一次。作用域必须是单例的,如果设置为原型,销毁方法就失效了




__________________________________________________________________________________________________




延迟加载(LazyBean类演示)








lazy-init="true"缺省值是false,true的时候表示延迟加载








——————————————————————————————————————————




IOC(Inversion Of Control 控制反转)是目标




DI (Dependency Injection 依赖注入)是手段




举例:
容器:外包公司
















依赖注入有一个条件:bean必须是容器创建的




<bean id="b1" class="ioc.B"></bean>
<bean id="a1" class="ioc.A">
<property name="b" ref="b1"/>  
调用对象A的属性b,会自动把属性的第一个字母大写,然后变成了setB
ref:传参,因为在类A里面的setB()是下面这样的:




public void setB(B b) {
System.out.println("setB()");
this.b = b;
}
所以,ref这里是把id为b1的B注入
</bean>








————————————————————————————————————————




initializationError




>>>>看看junit的测试类中的该方法的上面是不是遗漏了@Test








作用域scope的值不是boolean类型
scope="singleton" 默认的,单例,只有一个对象
scope="prototype" 作用域变更为原型prototype后则多例,生成多个对象




延迟加载才是boolean的




lazy-init="false"  ---->默认的  
lazy-init="true"








——————————————————————————————————————————————




创建对象的三种方式:
无参构造器<bean id="" class="">
静态工厂方法<..factory-method="">调用static修饰的方法,
如Calendar.getInstance-->类名.的可看出是静态方法
实例工厂方法<..factory-bean="">  如Calendar的getTime()方法,该方法是无参的




作用域:
scope,
----singleton默认
----prototype 则生成多个对象
生命周期:
init-method destory-method





!!spring一启动,先把默认单例的singleton的对象创建出来,不管有没有调用
延迟加载(lazy-init="true/false")
----》设置为true就是spring一启动并不会马上创建,而是等调用getBean才创建该对象












DI的方式:
--1.set注入
--2.构造器方式注入








——————————————————————————————————————————————




day02




————————————————
2.构造器方式注入












<bean id="b1" class="ioc.B"></bean>
<!--constructor-arg:表示采用构造器方式注入。其中,index属性指定参数的下标(从0开始)  -->
<bean id="a1" class="ioc.A">
<!-- 传给构造器的第几个参数 -->
<constructor-arg index="0" ref="b1"/>
<constructor-arg index="1" ref="c1"/>
</bean>








——————————————————————————————————————
自动装配(了解)




默认情况下,容器不会自动装配
可以设置autowire属性,让容器依据某些规则来注入相应的对象
 autowire属性值有如下几个:
——1.byName
——2.byType
——3.constructor








容器会检查restaurant内,去找




——————————————————————————————————
byName:




<bean id="wt1" class="auto.Waiter"/>
<!-- autowire:表示让容器自动装配
byName:容器以属性名也就是类Restaurant内的wt属性作为bean的id来查找符合条件的bean,
找到之后,调用对应的set方法来注入。注意,如果找不到符合条件的bean,注入null
也不可能找到多个,因为id是唯一的 
-->
<bean id="rest" class="auto.Restaurant" autowire="byName"/>








——————————————————————————————————




byType
autowire="byType" 则跟id没关系,而是直接找类型Waiter




<bean id="wt1" class="auto.Waiter"/>
<bean id="wt2" class="auto.Waiter"/>
<!-- autowire:表示让容器自动装配
byName:容器以属性名也就是类Restaurant内的wt属性作为bean的id来查找符合条件的bean,
找到之后,调用对应的set方法来注入。注意,如果找不到符合条件的bean,注入null
也不可能找到多个,因为id是唯一的 
byType:容器以属性类型作为bean的类型来查找符合条件的bean,找到之后,调用对应的set方法来注入
如果找到多个,则会出错
constructor:容器以属性类型作为bean的类型来查找符合条件的bean,找到之后,调用 
对应的构造器来注入
 
-->




<bean id="rest" class="auto.Restaurant" autowire="constructor"/>
使用构造器注入当然Restaurant类得有有参的构造器,以及创建了waiter对象,否则也是空的
————————————————————————————




(6) 注入基本类型的值




使用value属性即可




<!-- 注入基本类型的值:

-->
<bean id="vb1" class="value.ValueBean">
<property name="name" value="胡八一"></property>
<property name="age" value="30"></property>
<property name="interest">
<list>
<value>钓鱼</value>
<value>做饭</value>
<value>看电视</value>
<!-- List允许重复 -->
<value>看电视</value>
</list>
</property>
<property name="city">
<set>
<value>北京</value>
<value>上海</value>
</bean>




__能否追加ref?___________________________________________________________




















(7) 注入集合类型的值 (支持4中类型:List /Set /Map /Properties)








Properties是一种特殊的map,key和value都是字符串
读取:
<util:properties id="config" location="classpath:config.properties"/>
————————————————————————————
(8) 引用的方式注入集合类型的值
















XML的命名空间:
namespace




<%@taglib uri="http://xxxx/" prefix="c"%>




<c:if>
</c:if>




这个uri就是命名空间,防止重名的冲突








————————————————————————————————————————————————————




<!-- 使用Spring表达式去读取其它的bean的属性,就像jstl/el一样 -->
<bean id="sb1" class="value.SpelBean">
<property name="name" value="#{vb1.name}"></property>
</bean>




找vb1为id的类,调取getName方法




<property name="pageSize" value="#{config.pagesize}"></property>




这里的pagesize是文件里的key








注意单标签/双标签
——————————————————————————————




注解:








xml配置:
<context:component-scan base-package="annocation"/>








<!--配置组件扫描
一旦加了这个组件,容器就会扫描这个包以及其子包下面的所有的类。
如果这个类前面添加了特定的注解(比如@component),
则容器会将这个类纳入容器管理(相当于配置了一个bean,其中,bean的id默认值等
于首字母小写之后的类名
 -->
其中base-package=""只需要填写包名




——————————————————
编程步骤:
1 。在类前添加特定的注解,比如@Component。
2.。在配置文件中,使用component-scan来配置组件扫描








注解标记: 描述:
@Component 通用注解 (来自于Spring框架)
@Named 通用注解 (来自用sun)
@Repository 持久化层组件注解
@Service 业务层组件注解
@Controller 控制层注解




如果不清楚哪个层,就写Component
虽然有了组件扫描,但是xml也还能用bean,
比如
让容器创建一个Date
不是自己写的,而是别人给的bean,就还需要自己配置bean
大量的bean不需要在xml写了,只需要注解








————————————————————————————————
依赖注入相关的两个注解




——@Autowired/@Qualifier  正统的Spring的注解
—— a .支持set方式注入和构造器方式注入
—— b.set方法注入
——@Resource(重点)




————————————————————————




//容器会自动装配,通过byType。去找id为wt的Waiter类型。为了防止有多个id,
//使用@Qualifier指定id
@Autowired
public void setWt(@Qualifier("wt")Waiter wt) {
System.out.println("setWt() ");
this.wt = wt;
}




但是放到set方法可以执行多个条件,而放到放到属性里,只是单纯的赋值
——————————————————
public class Hotel {
//其实可以放到属性里,只是单纯的赋值
@Autowired
@Qualifier("wt")
private Waiter wt;

public Hotel() {
System.out.println("Hotel()");
}




下面的set的方法就不需要了
其底层用的还是java反射机制








c.构造器方式注入








————————————————————————————————————————




被调用的类需要get方法,如day02的value包的ValueBean.java








——————————————————————————




day03
回顾:








1.什么是容器
2.启动
3.创建对象:无参构造器/静态工厂方法/实例工厂方法
4.作用域: singleton / prototype
5.生命周期
6.延迟加载




IOC 对象的依赖关系由容器来管理 A--> B
1.DI依赖注入
2.set方法 /构造器 (xml用<constructor-arg index="">)
3.自动装配  autowire(byName/byType/contructor)
4.基本类型值的注入(在spring中string被当作基本类型,在java中string被当作对象)
5.集合类型值的注入
List/Set/Map/Properties
<util:list id="xxxBean"></list>
<property name="" ref=""/>
<util:properties id="" location="classpath:xxx.properties"/>




6.spring表达式(注意:被调用的类里面必须有get方法,如此案例的ValueBean.java)
#{vb1.name}  
#{vb1.interest[0]}
#{vb1.score['英语']}
7.注解的方式
1.组件扫描
@Component @Service @Repository @Controller
1.类加注解
2.配置文件加<Context:component-scan base-package="包名"/>
2.
@scope
@Lazy
@PostConstruct
@PreDestroy
3.依赖注入相关的两个注解
@Autowired  /@Qualifier (支持set和构造方法注入)
@Resource(只支持set方式注入)实际中用set更多,而且这个更简单,因此更常用








—————————————————————————————




@Resource(name="wt") //不用Resource的name属性指明的话也会默认按照byType找
public void setWt(Waiter wt) {
this.wt = wt;
}








@Resource可以加在set前面也可以在属性前。其中,name属性用来指定被注入的bean的id








##  @Value注解 (可以加载set前面也可在属性前面)
——注入spring表达式的值
——注入基本类型的值
注: 可以将@Value添加到set方法前面也可在属性前面












@Value("胡八一")
private String name;

//使用spring表达式取访问另一文件的属性
@Value("#{config['jdbc.pagesize']}")
注意:这里使用外部文件在xml也还是要配置:
<util:properties id="config" location="classpath:config.properties"/>












—————————————————————————————————————




springmvc
1.springmvc是什么
可以重复使用的控制器,简化,提高开发效率。mvc大框架中的一个mvc框架




(2)五大组件
DispatcherServlet (前端控制器)




接受请求,依据HandlerMapping的配置调用相应的 模型来处理。




HandlerMapping




包含了请求路径与模型的对应关系。




Controller (处理器)




负责处理业务逻辑。




ModelAndView




封装了处理结果。
注:处理结果除了数据之外,还可能有视图名。




ViewResolver (视图解析器)




DispatcherServlet依据ViewResolver的解析, 调用真正的视图对象来生成相应的页面。








————————————————————————————




1.DispatcherServlet收到请求之后,依据HandlerMapping的配置调用响应的处理器来处理。
2.处理器将处理结果封装成ModelAndView,然后返回给DispatcherServlet
3.DispatcherServlet依据ViewResolver的解析,调用相应的视图来生成相应的页面








编程步骤:
1.导包
2.添加一个spring的配置文件
3.配置DispatcherServlet
4.写Controller(处理器)
5.写jsp
6.配置HandlerMapping,VeiwResoler
DispatcherServlet会负责启动spring容器,但要知道sping的配置文件,
因此在<param-init>需要指定








public class HelloServlet implements Controller {
....
public ModelAndView handleRequest(HttpServletRequest req, 
HttpServletResponse res) throws Exception {

return null;




}
}












return ModelAndView(“hello.jsp") //.jsp就限定死了,如果需要用其他的视图层技术如freemaker等
,这里则无法更改,耦合度太高




return ModelAndView(“hello")  //正确的做法!!








HandlerMapping是一个接口,使用其实现类SimpleUrlHandlerMapping








<!-- 配置视图解析器 -->
<bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/> 
<property name="suffix" value=".jsp"/> 
</bean








tomcat一启动就会把servlet实例化








练习:
/spring01-lab/toLogin.do








__________________________________________________________________________________




在spring-mvc.xml中:




<!-- 配置HandlerMapping -->




<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.do">hc</prop>
</props>
</property>
</bean>
<!-- 配置处理器 -->
<bean id="hc" class="controller.HelloServlet"/>
<!-- 配置视图解析器 -->
<bean  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/"/> 
    <property name="suffix" value=".jsp"/> 
</bean> 





注意: <bean id="hc" class="controller.HelloServlet"/>




这一行的class就是main目录的java类








————————————————————————————————————————————————————




## 4)使用注解简化配置
1.导包
2.添加一个spring的配置文件
3.配置DispatcherServlet
4.写Controller(处理器) 一个处理器包含多个方法
要求: 1.不用实现Controller接口
2.可以添加多个方法
3.方法名不做要求,返回值可以是ModelAndView,也可以是String(只有视图名,没有数据时)
4.将@Controller添加到类名前
5.将@RequestMapping添加到类名前或者方法前,而不要在springmvc.xml里面配置bean




5.写jsp
















使用注解方式,登录Login.html
spring的方式创建连接池
——?当xml配置好属性,读取了config.properties的数据之后,如何输出??








——————————————————————————————————




注意:@RequestMapping("/toLogin.do")一定要放在对应的方法前面,
无论是无数据响应的用String方法只返回给视图层的方法
或者有数据响应的ModelAndView类型的方法,
都一样。
而不能是类名前面,就算
是只有一个方法也不行。




加类名前面只有:
//@RequestMapping("/demo")//模块化,表明的demo下的请求用这个方法
















————————————————————————————————
eclipse设置的validate可以把验证disable,加快运行速度
day04
回顾:
springmvc:
mvc框架, 简化基于mvc架构的web应用程序的开发
五大组件
DispatcherServlet----核心,前端控制器
HandlerMapping
Controller-----处理器
ModelAndView处理结果和视图名
ViewResolver视图解析器




——————————————————————————————————————




1.读取请求参数值
1)第一种方式 通过request对象(最灵活)
将request对象作为方法的入参即可
2)第二种方式:通过@RequestParam
将@RequestParam添加到方法的形参前面即可
注意:@RequestParam负责指定请求参数名与形参的对应关系
如:public String login2(String adminCode,@RequestParam("pwd")String password){




3)第三种方式:封装成javabean(会自动给该bean内的各个属性赋值)(当参数数量比较多的时候)
step1.写一个java类,封装各个请求参数
step2.将该java类作为方法的形参类型








2.向页面传值
1)第一种方式:使用请求对象request
将数据绑定到request对象,然后转发给jsp
2)第二种方式: 使用ModelAndView对象
将数据封装到ModelAndView对象,然后作为方法的返回值
@RequestMapping("/login5.do")
/*
* 使用ModelAndView向页面传值
*/
public ModelAndView login5(AdminParam ap){
System.out.println("login5()");




String adminCode = ap.getAdminCode();

//将处理结果封装到ModelAndView
Map<String,Object> data = new HashMap<String,Object>();
//绑定到请求,相当于执行了request.setAttribute("adminCode",adminCode)
//根据key查找的
data.put("adminCode",adminCode); //el表达式跟"adminCode"一样

ModelAndView mav= new ModelAndView("index",data);

return mav;
}
3)第三种方式:使用ModelMap对象(重点关注)
将该对象作为方法的形参,将数据添加到该对象里面即可




@RequestMapping("/login6.do")
/*
* 使用ModelMap向页面传值
*/
public String login6(AdminParam ap,ModelMap mm){
System.out.println("login6()");
//将结果/处理数据添加到mm,到时候前端控制器会从controller获取
//相当于执行了request.setAttribute(”adminCode",adminCode);
mm.addAttribute("adminCode",ap.getAdminCode());
return "index";
}




4)第四种方式:使用session对象(session的生存时间比request长)
/*
* 使用session对象向页面传值
*/
public String login7(AdminParam ap,HttpSession session){
System.out.println("login7()");
session.setAttribute("adminCode",ap.getAdminCode());

return "index";

}




1/2/3都是一样的,实际都是request
以后使用request,用完释放,session时间长,占用内存空间,除非有重定向才用session,因为重定向有2个请求,request明显不行








3.重定向
1)方法的返回值String
return "redirect:重定向地址";
比如: return "redirect:toIndex.do";




2)方法的返回值是ModelAndView
RedirectView rv = new Redirect("toIndex.do")
ModelAndView mav = new ModelAndView(rv);












4.系统分层(扩展)跟mvc的分层不一样
举例:如企业的决策层,管理层,执行层
1)如何分层
表示层: 表示逻辑,请求分发
业务层: 业务逻辑的处理
持久层: 数据库访问
注意:
a.上一层通过接口调用下一层的服务
b.下一层的实现发生任何改变,不影响上一层












M:业务逻辑 业务层,持久层
V:表示逻辑(数据展现,操作界面)
C:控制逻辑(协调)




数据加工,数据库访问
























————————————————————————————




@RequestMapping("/login.do")
/*
* DispatcherServlet在调用处理器的方法之前,会分析该方法的签名,
* 如果发现该方法有一个request对象,则会将该request对象作为参数传递进来
* 也可以加响应对象,session等等。用的是java的反射机制
*/
public String login(HttpServletRequest request){ //login被DispatcherServlet调用
System.out.println("login()");
String adminCode = request.getParameter("adminCode");
String pwd = request.getParameter("pwd");
String valiCode = request.getParameter("valiCode");
return "index";




————————————————————————————————————————————————




绝对路径:
链接地址/重定向/表单提交 从应用名开始写
如: <form action="<%request.getContextPath()%>/login3.jsp> </form>
转发从应用名之后开始写
















也有把controller叫做二级控制器,如LoginController








mvc是属于表示层的一种架构








企业不用dbcp,而是C3P0
DBCP性能差




driverClassName:com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3309/sampledb
username=root




————————————————————————————————————————————————




day05:




} catch (SQLException e) {
//打印异常信息。发生异常后通常做2件事
//1.保留现场,记录日志,异常写到文件
e.printStackTrace();
/*2.看异常能否恢复(架构师的思路),
*如果能够恢复,则立即恢复;如果不能够恢复(如数据库服务停止,一般称这样的异常为系统异常),
*则提示用户稍后重试
*/
//如果是运行时异常,则不需要在方法后面声明throws,但是
//如果是其他异常如SQL,那么连带其接口也要抛这个jdbc的SQL异常,如果后续变更需求,不使用该
//技术,那么代码接口都需要更改!!!
throw new RuntimeException(e);








————————————————————————————————————




AdminDAOJdbcImpl测试报错adminDAO找不到,要看xml是不是包名用子包了








应用异常:用户输入错误,不输入等属于用户错误的异常




ApplicationException通常是自己创建一个异常类








————————————————————————————————




package com.tarena.netctoss.service;
/*
 * 应用异常类
 * 用户在使用系统时,因为一些不正确的操作引起的异常,比如输入了错误的账号
 * */
public class ApplicationException extends RuntimeException {




}




构造方法选择无参和单参的
——————————————————————————————————












重点复习:




java基础
数据库基础,查询,左右连接,子查询等等
框架,主要是spring




——————————————————————————————————————————————
day06




回顾:
1.spring容器
1)管理对象
2)启动容器(ApplicationContext ac = ClassPathXml...
3)创建对象(无参构造器(调用getBean)/静态工厂/实例工厂
4)作用域: 
scope=singleton
scope=prototype
5)生命周期
初始化
销毁方法-作用域只能是单例,使用AbstractApplicationContext
6)延迟加载
2.IOC控制反转:
1)什么是控制反转?--对象之间的依赖关系由容器来建立,如a调用b
2)什么是DI?--依赖注入
容器可以通过set或者构造器来建立
对象之间的依赖关系
3)两种方式:
set方法:
1.该类有set方法
2.<property name="b" ref="b1"/>
构造器方法:
1.该类有构造方法
2<construct-arg index="0"  ref="b1"/>
4)自动装配(了解)
autowire="byName"/ "byType"找到多个则出错/ "constructor"
5)注入基本类型的值
<property name="age" value="22"/>
6)注入集合类型的值
第一种方式:
<list> <set> <map> <props>
第二种方式
<util:list id="interestBean">
<property name="" ref="interestBean"/>




7)读取properties文件的内容
<util:properties id="" location="classpath:db.properties"/>
8)spring表达式
#{vb1.name) //vb1的类里面一定要有getName方法
#{vb1.interest[0]}
#{vb1.score['english']}




2.注解
1)组件扫描?
@Component @Service @Repository @Controller
step1:
<context:component-scan base-package="com"/>
step2:
@Component @Service @Repository @Controller
2)
@Scope("prototype")
@Lazy(true)
@PostConstruct
@PreDestroy
@Value
3)
@Autowired @Qualifier //可放到set方法里面,@Qualifier指定beanid,也可以放在
@Resource(name="beanid")








——————————————————————————————————————




springmvc
1)what?
mvc框架,用来简化基于mvc架构的web应用程序开发
2)原理:五大组件
DispatcherServlet (前端控制器)




接受请求,依据HandlerMapping的配置调用相应的 模型来处理。




HandlerMapping




包含了请求路径与模型的对应关系。




Controller (处理器)




负责处理业务逻辑。




ModelAndView




封装了处理结果。
注:处理结果除了数据之外,还可能有视图名。




ViewResolver (视图解析器)




DispatcherServlet依据ViewResolver的解析, 调用真正的视图对象来生成相应的页面。

3)编程步骤
4)读取请求参数值
request
@RequestParam
封装成javabean
5)向页面传值
request
ModelAndView
ModelMap
Session
6)重定向,默认是转发
如果返回值是字符串: "redirect:toIndex.do"
如果返回值是ModelAndView:RedirectView ModelAndView

系统分层(了解)
1)如何分层:
表示层 界面(用户交互)请求分发
业务层 业务逻辑的处理
持久层 数据库访问
上一层通过接口来调用下一层提供的服务,这样一来,下一层发生改变,不影响上一层




维护性
证券公司 CTS(集中交易系统)
业务复杂,经常变 2周一小变,一月一大变




一个大型系统好不好,就看维护性和扩展性








————————————————————————————————————————
1.处理表单的编码问题




request.setCharsetEncoding("utf-8")  //指针对post请求有效。get的话则在tomcat的server.xml设置
在实际开发中,不可能每一个请求都写一次
过滤器:过滤器先执行,然后才是servlet,而且共享同一个请求和对象
spring已经写好了过滤器,在web.xml配置




使用springmvc提供的一个过滤器
(CharacterEncodingFilter)来解决




注意:
a--表单提交方式必须为post。
b--过滤器的编码与表单提交时采用的编码一致




2.拦截器!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
登录的session验证,用spring的拦截器解决session验证的问题
如果有拦截器,前端控制器会先调用,再调用控制器
拦截器属于spring?过滤器是servlet的?
1)什么是拦截器
spring提供的一个特殊的组件,前端控制器(DispatcherServlet)在收到请求之后,会先调用拦截器,
再调用处理器(Controller)
注意:
过滤器属于servlet规范当中定义的特殊的组件
而拦截器属于spring框架
2)如何写一个拦截器
step1.。写一个java类,实现HandlerInterceptor接口
step2. 在接口方法,实现具体的拦截处理逻辑

boolean preHandle()
postHandle()
afterCompletion()
step3.配置拦截器(属于spring,因此在spring中配置)




拦截器的使用,在spring-mvc.xml一样
多个拦截器则看web.xml中的顺序
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="拦截路径"/>
<mvc:exclude-mapping path="排除不拦截的路径"/>
<bean class="拦截器类所在的包名以及类名"/>
</mvc:interceptor>
</mvc:interceptors>








——————————————
@RequestMapping("/hello.do")
public String hello(){
对于hello.do会执行拦截,但是,




就算用<mvc:mapping path="/*"/> 试图拦截所有,但是对于/demo/hello.do并不会被拦截
@RequestMapping("/demo/hello.do")








解:要想拦截所有请求,需要再加*,因为/*是对单层请求,/**是对多层请求




正解:<mvc:mapping path="/**"/>




session验证:








————————————————————————————————
过滤器和拦截器的区别:
过滤器适用性更强,跟框架没关系,更通用








3.让spring框架处理异常(将异常抛给spring框架,让spring来处理)
1)配置简单异常处理器
step1:在spring配置文件当中,




<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.NumberFormatException">error</prop>
</props>
</property>
</bean>




其中:<prop key="异常类型,如:java.lang.NumberFormatException">视图页面,如error对应的error.jsp</prop>








step2;添加异常处理页面




String str = "abcd";
str.indexOf(10); //不会报错,查询,找不到就返回-1
str.charAt(10);//报错,下标越界
2)使用@ExceptionHandler注解
step1:在处理器类中,添加一个异常处理方法
tep2;添加异常处理页面
————————————————————————————————————————
day07:
回顾:
拦截器:what?
Dispatcherervlet--》 拦截器 --》Controller
how?
step1: HandlerInterceptor接口
step2: preHandle postHandle afterCompletion












处理器Controller如果出错,则postHandle不会执行了,但是afterCompletion依旧会执行








如何配置?
使用mvc:interceptors,指定bean是哪个包哪个类。映射路径以及排除路径




______________________________________________




表单中文参数值:
<%@page contentType="text/html; charset=utf-8" %>
只要是指令,不管是taglib还算page,都会影响servlet的生成




jsp--->Servlet
response.setContentType("");
发送content-type消息头给浏览器




在spring中,配置过滤器解决中文乱码 CharacterEncodingFilter
request.setCharacterEncoding
必须是post




-------------------------------------------




异常的处理:




将异常抛给spring框架(DispatcherServlet)
方式1 :配置简单异常处理器
SimpleMappingExceptionResolver
方式2:@ExceptionHandler
step1 添加一个异常处理方法
step2 添加异常处理页面








spring-mvc总结回顾
1.spring-mvc是什么?
表示层 界面 请求分发
2.五大组件,以及相互关系(请求发给D,D依据H调用C,C将结果封装成M,C再依据V返回对象)
3.编程步骤
step1








————————————————————————————————————————————
1.springjdbc
1)什么是springjdbc?
spring对jdbc的封装
2)如何使用?
step1:导包
spring-jdbc
仅作演示,非完整应用则在new maven只需jar即可,war则需知道tomcat以及web.xml。
org.springframework spring-jdbc3.2.8




step2:添加spring配置文件
step3:配置JdbcTemplate
step4:调用JdbcTemplate提供的方法来访问数据库








——————————————————————
create table emp_warren(
id number(8) primary key,
name varchar2(50),
age number(3)




);
create sequence emp_seq_warren;




JdbcTemplate的query返回的是一个集合,查询所有或多个的时候适用
JdbcTemplate的queryForObject返回的是一个对象,查询单个的时候适用




JdbcTemplate的update():增删改








过滤器:是一个规范
________________________________________________________________________________________




MyBatis最早有apache写的  iBatis-->Google-->MyBatis--->github




oracle最大支持1024个字段








hibernate








1)MyBatis是什么?
是一个持久层框架,对jdbc做了封装,底层是jdbc
联想:springmvc是表示层框架




2)如何使用MyBatis?
step1:导包 org.mybatis mybatis 3.2.8
com.oracle ojdbc14 10.2.0.4.0
junit 4.12
step2:添加mybatis的配置文件
step3:写实体类
注意:实体类的属性名要与表的字段名一致(大小写不区分)
step4:写映射文件(以后大部分开发都是写映射文件,怎样完成数据库的记录等)**
step5:在配置文件中,指定映射文件的位置
step6:使用mybatis提供的api来访问数据库
















——————————————————
oracle.jdbc.OracleDriver
oracle.jdbc.Driver.OracleDriver也能用




只要是java类都最好实现序列化接口,不仅仅是实体类




同一个id在映射文件中不能一样
<insert id="" parameterType="entity.Emp"> id要求唯一
注意:<insert></insert>标签内的sql语句不能加分号,#{name}#不能有空格








————————————————————————————————————————————
day 08
Mybatis




查询方法,映射文件不是用<insert>标签,而是<select>,类型是resultType




<select id="findAll" resultType="entity.Emp">返回的是一个集合,因此
在测试方法中获取结果需要用集合接收。因为是查询,因此不需要提交事务session.commit(),但是
还是需要close(),毕竟是资源,资源使用完毕都要释放




查询单个实例:
<T> T selectOne(String statement ,Object parameter) 
查询所有:
<E> List<E> selectList(String statement, Object parameter)
3)mybatis的原理:
SqlSessionFactory创建很多statement对象,其实质是一个Map集合




Map的key是sqlId
value就是statement对象
SqlSessionFactory创建SqlSession
调用SqlSession是传参(sqlId,参数)。如插入操作,参数是emp实例,包含了emp的信息
有了sqlId,依据sqlId从Map中找到对应的statement并执行








——————————————————————————————————————




查询单个实例:
<T> T selectOne(String statement ,Object parameter) 
findById




<!-- parameterType="java.lang.Integer" -->
<select id="findById" parameterType="int" resultType="entity.Emp">
SELECT * FROM emp_warren WHERE id=#{id1}
</select>








#{id1}的值并不是来自某个对象的某个属性,所以可以任意名字,id或者id1都可以








@Test
public void testfindById(){
Emp e = session.selectOne("test.findById",1);

System.out.println(e);




}

mybatis查询不到数据会返回null,而jdbc是报异常




练习:
建一张表dept
create table dept_warren(
id number(8) primary key,
deptno varchar2(50),
loc varchar2(100)
);
create sequence dept_seq_warren;












____________________________________________________________________








有几条记录,就有几个map对象。
1.mybatis会将查询到的一条记录转换成一个map对象(一条记录对应一个map)
2.再将map中的数据存放到实体对象
 
emp :id name age
1 Sally 22




map : key id 1
key name Sally
key age 22




________________________________________




4)返回Map类型的结果
mybatis会将查询到的记录先转换成对应Map对象(以字段名作为key,以字段值作为value,
一条记录对应一个map




map获取返回的是大写,因为oracle默认转成大写
应用范围:当数据库表很大,有很多字段,如几十上百个,但是只需要获取其中的几个字段,就不需要使用
实体类了,而是用Map返回
————————————————————————————————————————————




实体类一般不要更改,有可能其他地方正在使用。




5)解决实体类的属性和数据库的字段不一致




方式一:使用别名
select empNo,ename,age ...
方式二:使用resultMap





<!-- 测试Emp2.java的属性名和数据库字段名不同。
使用了resultMap那么这里的resultType就不用了,改成resultMap对应 -->
<select id="findById3" parameterType="int" resultMap="emp2Map">
SELECT * FROM emp_warren WHERE id=#{id1}
</select>
<!-- id要求唯一,type:实体类的名字 
resultMap:负责告诉mybatis如何将字段名与实体类的属性名进行对应
如果实体类和数据库的字段名不一致,mybatis会看resultMap
-->
<resultMap type="entity.Emp2" id="emp2Map">
<result property="empNo" column="id"/>
<result property="ename" column="name"/>
</resultMap>




————————————————————————————————————————————








6)Mapper映射器(该功能为Google改进的ibatis)




Mapper映射器是什么?
是符合映射文件的接口
(2)Mapper映射器的要求:
接口要求如下:
a。方法名要与sql的id一致。如叫做save也一样叫做save方法,大小写必须一样
b。方法的参数类型要与parameterType一致
c。方法的返回类型要与resultType一致












映射文件要求:命名空间namespace必须等于接口名(包含包名)




————————————————————————————————————
写了接口则mybatis自动提供一个实现接口的对象,不用写DAO的实现类了
一个线程一个stack
————————————————————————————————————————
(3)编程步骤
step1. 写一个映射器(即一个接口)。
step2. 调用SqlSession提供的getMapper方法。
注:该方法会返回一个符合映射器要求的对象












获取只需要调用接口的方法即可
EmpDAO dao = session.getMapper(EmpDAO.class); 

List<Emp> emps = dao.findAll()
————————————————————————————————————————
spring集成mybatis




step1. 导包。
spring-webmvc3.2.8
mybatis3.2.8
mybatis-spring1.2.3
spring-jdbc3.2.8
dbcp1.4
ojdbc10.2.0.4.0
junit4.12




step2.配置文件
注意:只需要添加spring的配置文件,在该文件中,配置一个SqlSessionFactoryBean
SqlSessionFactoryBean包含了连接池和映射文件的信息
step3. 实体类 
step4. 映射文件 
step5. Mapper映射器 
step6. 在spring的配置文件当中,添加 MapperScannerConfigurer。
该bean负责调用SqlSession的getMapper方法, 创建符合Mapper映射器要求的对象。




注:
该bean会将这个对象添加到spring容器里面
(默认id是首字母小写之后的接口名,也可以使用@Repository重命名,(可回忆前面讲的注解),
而且,
在配置文件中,不需要另外再加上注解扫描了,因为MapperScannerconfigure自己会扫描)。








step7.启动spring容器,调用getBean方法
————————————————————————————————————————




<!-- 配置SqlSessionFactoryBean -->
<bean id="ssfb" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定连接池的位置 -->
<property name="dataSource" ref="ds"/>
<!-- 指定映射文件的位置 -->
<property name="mapperLocations" value="classpath:entity/*.xml"/>
</bean>




<!-- 配置MapperScannerConfigurer -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定Mapper映射器所在的包 -->
<property name="basePackage" value="dao"></property>
</bean>








mapperLocations注意不要少了s












————————————————————————








sqlSessionFactory属性可以不用指定,会以Autowired方式自动注入




缺省值:映射器的首字母小写
如EmpDAO接口,则getBean("empDAO),当然也可以使用前面学的注解修改为指定的名字,@Repository()
































晨曲
晨旭
晨映








——————————————————————————————————————




回顾:mybatis:持久层的框架,底层是jdbc,只不过做了封装




mybatis
mybatis-spring。




可能有些DAO接口不使用mybatis实现,而是用其他的。对于某些特定的查询,要求查询快,比如jdbc就比mybatis快




讲究开发效率:mybatis
要求查询高效:jdbc
当多种持久层技术共存时,如何解决?
——给MapperScannerConfigurer加个属性,叫annotationClass
其属性值就是一个注解value="org.tarena.annotation.MyBatisRepository"




哪个要被扫描就注解MyBatisRepository
需要自己写该注解












2)只扫描特定的Mapper映射器
step1.自定义一个注解。src/main/java右键new一个annotation
起个标识作用,就像之前学的Serializable接口一样




step2.将该注解添加到要扫描的映射器文件。加在映射器文件前面,EmpDAO接口
@Repository("empDAO")
@MyBatisRepository
public interface EmpDAO {...
step3.配置MapperScannerConfigurer的属性annotationClass




——————————————————————————————————————————
3)spring集成mybatis的另外一种方式(了解)
SqlSessionTemplate




SqlSessiontemplate利用sqlsessionfactorybean获取sqlsession








step1. 导包。
step2. 添加spring的配置文件。
注:删除MapperScannerConfigurer的配置。
step3. 实体类。
step4. 映射文件。
step5. DAO接口。
step6. DAO实现类。
注:注入SqlSessionTemplate,调用该对象的方法。
step7.配置SqlSessionTemplate。




















Spring+Mybatis
系统分层
表示层 springmvc
业务层 spring
持久层 mybatis




毕业前5天讲:
SSH 
表示层 Struts2 
业务层 Spring
持久层 Hibernate




练习:
使用spring+mybatis完成NETCTOSS的登录




step1.导包
mybatis包,mybatis-spring包
step2.在spring的配置文件中,添加:
SqlSessionFactoryBean。
MapperScannerConfigurer
step3.解决实体类和数据库实例名不一致的情况,用别名或者resultMap
step4.映射文件
step5.映射器。
step6.测试AdminDAO












注意:




在spring配置文件中,如果配置了MapperScannerConfigurer,而且还保留了之前的组件扫描和注解扫描,则在
测试AdminDAO持久层的时候会报出CostDAO冲突。这时候删除之前的组件扫描和注解扫描可正常运行




<!-- 配置组件扫描 -->
<context:component-scan base-package="com.tarena.netctoss"/>
<!-- 配置mvc注解扫描 -->
<mvc:annotation-driven/> 








但是需要注意




<!-- 配置MapperScannerConfigurer -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定Mapper映射器所在的包 -->
<property name="basePackage" value="com.tarena.netctoss.dao"/>  
<!-- 指定只有带该注解的映射器才会被扫描 -->

</bean>




正确写法:
路径要classpath,用/
property name="mapperLocations" value="classpath:com/tarena/netctoss/entity/*.xml"/>
包才是.
<property name="basePackage" value="com.tarena.netctoss.dao"/>  




























这里MapperScannerConfigurer的扫描路径是com/tarena/netctoss/dao
而之前的组件扫描是com.tarena.netctoss,
测试其他子包的类时注意,比如此时包controller内的注解便已经失效




总结:原有的组件扫描和mvc注解扫描是不能删除的,而把
MapperScannerConfigurer的扫描路径改为上一级com/tarena/netctoss
明显不能解决问题,这时候的状态就是多种DAO技术共存的局面,jdbc和mybatis,
因此需要特定扫描,既能用MapperScannerConfigurer,也不影响原有的组件扫描和mvc注解扫描
所以,加个属性:
<!-- 指定只有带该注解的映射器才会被扫描 -->
<property name="annotationClass"  value="com.tarena.netctoss.annotations.MybatisRepository"></property>
</bean>












SqlSessionTemplate实际较少用,属于mybatis早期的技术,比较麻烦,需自己写DAO的实现类




——————————————————————————————————————————————




复制项目必须要修改pom的<artifactId>spring-netctoss_v2</artifactId>,否则无法启动服务器




路径要classpath,用/
property name="mapperLocations" value="classpath:com/tarena/netctoss/entity/*.xml"/>
包才是.
<property name="basePackage" value="com.tarena.netctoss.dao"/>  








理解:老师的netcotss之所以不写annotationClass属性也能正常运行,是因为其dao包里面只有一个AdminDAO
,而如果加上CostDAO,一样提示冲突!!!!!!!








————————————————————————————————————————————————————




AJAX:
是一种用来改善用户体验的技术,其本质是利用浏览器 提供的一个特殊的对象(XMLHttpRequest,也可称之为 ajax对象)向服务器发送异步请求。服务器返回部分数据 (通常不需要返回完整页面),浏览器利用这些数据对当前 页面做部分更新。整个过程,页面无刷新,不打断用户的操作








asynchronous javascript and xml
改善用户体验




javascript/jquery




一个ajax对象就是XMLHttpRequest








xml非常重要,明后天讲json,代替部分xml功能
特定场合如服务器返回的数据比较复杂,则用xml




原理:








2)如何获得ajax对象
javascript 有兼容性问题
ajax最早在ie5.5提供 activeXobject
firefox,chrome等效仿提供此类对象,叫XMLHttpRequest




w3c 整合




——————————————————————————————————————————————————
day10
ajax对象的几个重要属性




onreadystatechange:绑定一个事件处理函数,该函数用来处理reaystatechange事件
注:当ajax对象的readyState属性值发生了改变,比如,从0变成了1,则会产生readystatechange事件
readyState请求的状态,有5个值(0,1,2,3,4),表示ajax对象与服务器通信的进展,其中,4表示ajax对象已经获得了服务器返回的所有的数据
0:尚未初始化
1:正在发送请求
2:请求完成
3:请求成功,正在接受数据
4:数据接收成功
responseText:获得服务器返回的文本数据
responseXML:获得服务器返回的xml数据
status:获得状态码,如200就是正常




获得服务器返回的数据if(readState==4)  //js




4)编程步骤
step1.获得ajax对象
比如 var xhr = getXhr();
step2.发送请求
方式一:get请求
xhr.open('get','check_uname.do?name=sally&age=22',true); //true:表示异步请求,如果是
false则表示同步请求(当ajax对象发送请求时,浏览器会锁定当前页面,用户不能够对当前页面做任何操作)
xhr.onreadystatechange=f1;
xhr.send(null);




方式二:post请求
xhr.open('post','check_uname.do');
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
xhr.onreadystatechange=f1;
xhr.send('uname=Sally');




按照http协议的要求,如果发送的请求是post,要求携带content-type消息头
(浏览器提交表单自动添加了消息头),非表单提交都不加消息头,所以需要调用Request
Header方法来添加
































step3.编写服务器端的程序。通过只需要返回部分数据(不再需奥返回完整的页面
step4.写事件处理函数
function f1(){
if(xhr.readState==4 && xhr.state==200){
//获得服务器返回的数据
var text = xhr.responseText;
}

}
















————————————————————————————————————————————
5)缓存问题:
什么是缓存问题?
当使用ie浏览器时,ajax对象如果发送的是get的请求,
会检查请求地址是否访问过,如果访问过,则不再发送新的请求,而且显示之前访问过的结果
(也就是说,第一次访问请求时,会将结果缓存下来)




如何解决?
在请求地址后面加上随机数
















!!!!!!!!!!!!!!!!
if(xhr.readState==4 && xhr.status==200){  //又是少写了个y
注意ready的拼写
















6)中文乱码:




虽然tomcat的server.xml配置了 URIEncoding="utf-8",但是用ie浏览器用get请求发送,也还是乱码,虽然非ie已经正常




因为ie浏览器默认使用gbk对中文进行编码,其他非ie浏览器默认
会使用utf-8对中文进行编码。
而服务器默认会使用iso-8859-1对中文进行编码




所以 URIEncoding="utf-8" 不能保证所有的浏览器编码正常
解决方式:
step1.服务器端统一使用utf-8来解码。比如 URIEncoding="utf-8"
step2.在客户端,使用encodeURI函数对中文数据进行编码
注:encodeURI是javascript内置的函数。








发送post请求
产生乱码的原有:
浏览器默认会使用utf-8对中文进行编码,服务器使用iso-8859-1来解码




解决方式:




req.setCharacterEncoding("utf-8");








练习:级联下拉列表








————————————————————————————————————————————




day11
回顾:
ajax
what?
how?
step1:获得ajax对象
step2 发请求
get

post
step3. 编写服务器端的程序。通过只需要返回部分 数据(不再需要返回完整的页面)。
step4. 写事件处理函数。








缓存问题:当用ie且使用get请求时。
解决:1.在请求地址后面添加一个随机数。
2.使用post发送




——————————————————————————————————————————
1.JSON(javascript object notation)js对象声明
1)什么是JSON
是一种轻量级的数据交换格式
直接读取xml会比较慢,json解析更简单更快
借鉴了js中的一种创建对象的语法
数据交换:将数据先转换成一种与平台无关的数据格式(比如转换成xml),然后发送给接收方来处理




轻量级:与xml相比,JSON文档要小,解析的速度更快




2)JSON语法:
表示一个对象
{属性名:属性值,属性名:属性值,属性名:属性值}
注:属性名必须使用双括号括起来
属性值可以是String,number,true/false,null,Object
3)属性值如果是字符串,也必须使用双引号括起来




js中:
{"name":"sally","age":22}
{name:"sally",age:22}
{'name':'sally','age':22}








表示一个对象组成的数组
[{},{},{} ]












java对象如何转换成json对象?
json-lib
JSONObject/JSONArray
jackson
fastjson




javascript两个内置对象:Math/Object




新加入:JSON.parse(str)




————————————————————————————————————




Stock s = new Stock();
//使用json官方提供的工具(json-lib)来转换
JSONObject jsonObj = JSONObject.fromObject(s);
String jsonStr = jsonObj.toString();




——————————————————————————————
List<Stock> stocks = new ArrayList<Stock> ();
/*
 * fromObject方法可以传入数组或者List集合
 */
JSONArray jsonArr = JSONArray.fromObject(stocks);




String jsonStr = jsonArr.toString();








——————————————————————————————————————————








### 将json字符串转换成javascript对象
javascript内置的




$(function(){})整个页面加载完成之后执行








$.ajax({
"url":"quoto.do",
"type":"post",
"data":"size=3&id=4",  //参数名(服务器getParameter获取的):size,值:3
也可以这样:  "data":{"size":"3","id","4"}




"dataType":"json",
"success":function(这里传参数,即服务器返回的数据,如果是字符串,会自动转成js对象,如果是数组则转成js数组){}  //相当于自己写的ontreadystatechange
});
















对于jquery, $.ajax方法会自动将json字符串转换成js对象








#jQuery对ajax的支持
## $.ajax方法
用法:
$.ajax({});
常见的选项参数有这样的一些:
url:请求地址
type:请求类型(比如:get)
data:请求参数有两种格式:
第一种:请求的字符串形式,比如size=3
第二种:对象形式,比如{"size":3}
dataType:服务器返回的数据类型(text,json)
text:文本
json:json字符串
xml:xml文档(比较复杂的数据)




success:当服务器处理正确,用来处理服务器返回的数据的函数




error:当服务器出错,用来处理的函数












业务分离:
html:数据
jquery:行为
css:样式




jquery的显示:
$("span").html(num);
$("input.button").value(num);
js的显示:
obj.innerHTML=num;
obj.value=num;








如果server发送的不是Object或者数组,而是Sring或者基本数据类型,不需要写JSONObject
那么,
将$.ajax的dataType设置为text即可,而不是用json,




————————————————————————————————————————








## load方法:




服务器返回的数据不需要处理,直接追加到节点上,适用于随机数案例




用法:
$obj.load(url);




作用:向服务器发送异步请求,将服务器返回的数据直接添加到符合要求的节点之上




function f2(){
/*
*向服务器发送异步请求(请求地址是getNum.do),然后将服务器返回的数据
*直接添加到#d1对应的节点相当于给该节点innerHTML赋值
*/
$("#d3").load('getNum.do');
}




练习:
检查用户名注册,用jquery写




————————————————————————————————————


part10










阶段目标
根据项目文档独立实现需求




阶段二:自写,老师重写
阶段三:分析
阶段四:课后自写小功能








课程安排:
day01:项目简介/搭建项目环境
2-9:实现项目需求
10-12:spring-AOP(ASPECT ORIENTED PROGRAMMING)
事务处理
关联映射
动态SQL




正课:
    项目简介
    搭建项目环境




spring webmvc+Spring+Mybatis




1.导包
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.2.3</version>
  </dependency>
  <dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.2.3</version>
  </dependency>
  <dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.2.3</version>
  </dependency>




扫描多个包
<context:component-scan base-package="cn.tedu,com.tedu"/>
在实际开发中:
凡是带id属性的实体类都必须重写equals和hashCode方法,只需要重写id的equals和hashCode方法
















@ResponseBody  //调用jackson




public User loadUser(){
User user = new User(1,"Robin",28);

return user;
}








如何使用:
-导包:jackson
-在放回数据的方法上加@ResponseBody
















——————————————————————
项目简介:
- 项目概述
>>云笔记,是tmooc上的一个子项目,用于客户进行在线学习记录,分享,收藏笔记,以及参与社区活动.
- 模块划分
>> 用户模块: 登录 注册 修改密码,退出
笔记本模块:创建 删除 更新 查看
笔记模块: 创建 删除 更新 查看 转移
分享/收藏功能:分享 收藏 查看 搜索
回收模块: 查看 彻底删除 恢复
活动模块: 查看活动 参加活动
- 设计思想
- 技术架构








项目规范:
-所有请求使用html








关联关系;
一对一
一对多
多对多
-——————————————————————————————
常用命令




mysql -uroot -t //启动mysql命令行




show databases; //查看有哪些数据库




create database cloud_note; //创建数据库




drop database cloud_note; //删除数据库




use 数据库名; 连接数据库




show tables; 查看有哪些表;




导入SQL文件 
set names utf8; 
source /home/soft01/cloud_note.sql;
windows系统下:
set names utf8; 
source e:\\cloud_note.sql;
E-R 实体-关系模型图




由业务分析产生,作为实体类和数据库设计的依据.








<property name="url" value="jdbc:mysql:///cloud_note?useUnicode=true&amp;characterEncoding=utf8"/>
相当于<property name="url" value="jdbc:mysql://localhost:3306....cloud_note?useUnicode=true&amp;characterEncoding=utf8"/>
//cloud_note是数据库名
//xml里面不能直接写&,而需要转义&amp;




























————————————————————








jQuery API 1.11.3 速查表  --作者:Shifone








html登录页面如何获取路径?$.ajax({"url":path+"/user/login.do});中的path怎么来的?
widow.loation.path??  




为何UserDao不需要注解userDao?而UserService的实现类又有?
难道因为是dao是使用了mybatis-spring的mapper扫描?加了注解userDao反而报错该bean不存在?








service实现类的User user =userdao.findByName(name);  这里为何空指针异常?
但是测试dao的findByName()方法又正常




正常来说,这里UserDao是有其实现类的,
UserDao u = new UserDao();不可行,因为接口类型指向实现类




好吧,思路是对的。context component接管了bean的生成,如果不指定名字,如@Resource("userDao“)
则会自动生成个第一个字母小写的实例,也就是bean。而对于userDao接口,因为使用了Mybatis,应该是已经生成了该接口的
实现类的了,比如配置了Mapper,写了映射文件。




反正现在是改名重新导入项目结果竟然可以了。








!!!!!!!!!!!
要求:需要复习下从mvc模式,在xml中配置bean,之后的内容








在注册的函数中:$("#warning_1").show();  //这句的作用是什么?




______________________________________________________________________________








day02




之所以继承RuntimeException,就是为了事务处理。只有该异常才能进行事务回滚








jquery.min.js是一个简化的版本








md5 摘要算法
最初用于文本比较
将任意长度的字节处理成等长的结果
不可逆




public static String md5(String src){
try {
MessageDigest md = MessageDigest.getInstance("MD5");
//MD5加密
byte[] output = md.digest(src.getBytes());

//Base64.

return new String(output);
}








Base64
a-z:26
A-Z:26
0-9:10
= +








JsonResult数据格式: {"status":xxx,"data":xxx,"message":xxx}












—————————————————————————————————————




作业:
完成登录功能的服务器处理:
-Controller
-Service
-Dao












在mysql中没有序列这个对象,不同于oracle。
mysql中有一个自增的?uuid




UUID算法:(生成的id不重复












——————————————————
day04:
将try/catch去除,改用 @ExceptionHandler可以统一处理控制器中的异常类型




重复性的异常抽到抽象类中




实现序列话接口
一定有无参
对属性赋值有setter/getter方法
重写toString
重写equals/hashCode
















//将bookId绑定到元素中.data为数据缓存
$li.data("bookId",bookId);








2.尝试点击笔记本事件绑定
父元素.on("click","元素",Function());
3.点击笔记本记录,显示被选中的效果












事件绑定:
$("#book_ui li").click(function(){
alert("绑定成功");
})




在做绑定的时候,




$(function(){
//加载笔记本列表
loadBooks();
});
页面的loadBooks还没加载完。loadBooks发送请求完成后就执行
$("#book_ui li").click(function(){了,而这时候服务器还没返回笔记本数据




ul已经存在,但是li还没有。
因此使用
父元素.on("click","li",fn);的监听方式

$("#note_ui").on("click","li",fn);




________________________________________________________________




//监听笔记本li元素的单击事件
$("#book_ul").on("click","li",function(){ 
//获取参数bookId
var bookId=$(this).data("bookId");
console.log(bookId);
//发送ajax请求


});
















controller的传参的参数名也就是浏览器发给服务器的参数名!!!!








List<Map<String,Object>>
key:字段名,或者是as以后的字段名








Mapper.xml复制之后记得更改id,最好sql语句全部删除,否则容易出错
如果总是invalid statement,那就是id名没改回来








——————————————————————————————————————————




//先清除
$("#book_ul a").removeClass("checked");
//$("#book_ul a").remove("checked");  




//设置选中效果//选中当前的,找到a,加上属性Class
$(this).find("a").addClass("checked");




//下面这句的效果:鼠标移出之后就失去效果了,但是上面那句不会,效果会保留
//$(this).find("a").addClass(".checked");








——————————————————————————




//在开始本次之前把上一次的清除
//$("#note_ul").empty();
//上下两句效果相同
$("#note_ul li").remove();












————————————————————————————————————




富文本编辑器
ue
UEditor








怎么用?




1.引入组件的js文件
2.Script代码中生成实例
var um = UM.getEditor('myEditor');
3.通过id,将组件防止到预期的位置
<!--- 笔记标题 --->
<div class="row">
<div class="col-sm-12">
<!--- 输入框 --->
<script type="text/plain" id="myEditor" style="width:100%;height:400px;">
</script>
<!--- 输入框 --->




</div>
</div>




4.通过set/get方法操作组件
-setContent
-getContent












select cn_note_title as title,cn_note_body as body from cn_note where cn_note_status_id='1' and cn_note_id=#{noteId}
——————————————————————————————————




分页:
select * from(
select c.*,rownum r from 
(
select * from cost order by cost_id
)c 
where r between #(start) and #{end}
)






为什么测试方法总会报空指针异常?




因为service层的方法return 还是null啊 
 还是null啊
 还是null啊
 还是null啊
 还是null啊
 还是null啊
 还是null啊








dao使用int update(Note note)
在映射文件Mapper中的select不支持返回值类型resultType








mybatis不支持传多参数,
如需要可以传对象,如果是无关的参数可以传map




















————————————————————————————————————————————————————
补充
day07
二进制和反射




-n=~n+1




~取反
>>> >> <<移位运算








计算机中位运算性能比乘法运算好








>>>和>>的区别




>> : 数学右移位运算,负数(高位为1的数)高位 补1,正数补0
>>> :逻辑右移位运算,无论正负都补0








i=10010010 00010101 11110100 10110000
n=i>>>1
n=010010010 00010101 11110100 1011000
m=i>>1
m=110010010 00010101 11110100 1011000












>>>:应用案例:
IO流
网络/磁盘写入单位是1个字节
发送:
i=10010010 00010101 11110100 10110000




b1=10010010
b2=00010101
b3=11110100
b4=10110000




& 与运算: 逻辑乘












面试题:
优化n%8为(n&7)








n%8 和 n&7都是对8取余,有什么区别:
15%8=7
18%8=2
...[0 , 8)




不管任何数对8取余都不超过8




模运算其实就是二进制的与运算。
n=20=00010100
m=7 =00001111
-------------------
与运算就是截取后面的位数,如8则截取低三位,最大余数是7




——————————————————————————————————————————

//& 与运算: 逻辑乘
/*
* 0&0=0
* 0&1=0
* 1&0=0
* 1&1=1
*/




//将00001001010000100111010010111001切割成4份
int i=0x94274b9;


//m的11111111相当于孔洞,把每次8位漏下来
// 一个f叫做4个掩码。如ip地址配置的子网掩码
//192.168.1.1
//8位/8位/8位/8位
//255.255.255.255.0

//192.168.23.11/24中的24表示24个1,也就是掩码是24,如这里的m,f就是4个1
int m= 0xff; //Mask  
int b1=i&m; 
int b2=(i>>>8)&m;  //掩码运算
int b3=(i>>>16)&m;
int b4=(i>>>24)&m;


try {
RandomAccessFile raf = new RandomAccessFile("config","rw");
raf.writeInt(4);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

print(i);
print(m);
System.out.println("将一个4字节的int数切割4份:");
print(b1);
print(b2);
print(b3);
print(b4);
System.out.println("拼接后的结果:");
//组装:b4左移24位,b3左移16,b2左移8,b1左移0.然后数学+即可
int result = (b4<<24)+(b3<<16)+(b2<<8)+b1;
print(result);
System.out.println("源数值和拼接结果是否一致:");
System.out.println(i==result);


//或运算。|相当于加法
/*
* 0|1=1

*/
/*
* RandomAccessFile源代码中:
*  public final int readInt() throws IOException {
       int ch1 = this.read();
       int ch2 = this.read();
       int ch3 = this.read();
       int ch4 = this.read();
       if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }



* raf的read()方法,-1表示读到文件末尾
* ch1 =00000000 00000000 00000000 11100101
* ch2 =00000000 00000000 00000000 11001101
* ch3 =11111111 11111111 11111111 11111111
* ch4 =11111111 11111111 11111111 11111111
* |——————————————————————————————————————
* 11111111 11111111 11111111 11111111
*因此源代码中这句判断 if ((ch1 | ch2 | ch3 | ch4) < 0)
*只要有一个字节是全1,则进行或运算之后都是-1,表示读取到了文件末尾
*/












__________________________________________________________________________________________________________




对象的序列化:把对象的切割成一组组二进制




二进制上一层:方法




————————————————————————————




反射:




java中动态执行api,反射api可以:
动态创建对象,动态调用方法,动态访问属性




动态执行:








静态执行:经过编译确定执行次序,在运行期间按照编译次序执行








JAVA 中的动态执行: 运行期间才能确定加载哪些类, 创建哪些对象, 执行哪些方法...




动态加载类,在程序执行期间动态获得类名,根据类名加载类




API
Class cls = Class.forName(类名);




动态创建对象
Object obj = cls.newInstance();




//动态创建对象.要求类必须有无参构造器,无则抛异常








动态读取属性

Field fld
fld.get();
步骤:
加载类
找到类中的属性声明信息Field对象(属性是属于对象的)
创建对象
读取对象的属性值












面试:怎样在对象的外部读取一个对象的私有属性?




反射不仅能够访问普通属性,还能访问私有属性。




注意:需要在访问之前打开,使用fld.setAccessible(true);












System.out.println("输入属性名:");
String name=in.nextLine();
//动态在cls代表的类信息上找到属性信息
Field fld = cls.getDeclaredField(name);
//属性值=fld.get(被访问对象); fld的属性必须跟obj一致
//obj="abc"; //用来测试因为field上对应的属性不一致而报异常








//读取属性之前使用setAccessible方法就可以访问私有属性了
fld.setAccessible(true);












Object val = fld.get(obj);

System.out.println(val);




虽然注解使用了私有属性,如
@Resource
private NoteService noteService;




spring也是用了反射




反射是对封装的破坏,不能乱用




访问私有属性只是反射的一个功能。








所有的框架,底层都是反射。spring/mybatis/junit都是








——————————————————————————————————————————————




day07










二进制在1609的集合里面
反射在spring的拦截器












反射
java提供的动态








System.out.println("Input: ");
String className = in.nextLine();
//Class是反射API的入口
Class cls = Class.forName(className);
//cls引用了类的相关信息.getDeclaredField返回一堆属性信息
Field[] field = cls.getDeclaredFields();

for(Field f : field){
System.out.println(f);
}




//可以获取类中全部的方法信息.包括父类的
Method[] method = cls.getMethods();
for(Method m: method){
System.out.println(m);
}
Junit3中一个方法名为test开头,就作为测试运行




反射的用途:












案例:执行一个类中全部以test为开头的方法,这些方法都是无返回值的无参的。如果不用反射,没法写,因为不知道类名,
不知道方法名,只知道方法名特征,比如以test开头,其他都不知道




工作中,遇到被执行的类,被执行的方法不知道是哪个方法哪个类,用反射








解决方案:
1.动态加载一个类
2.动态找到全部方法信息




Method[] method = cls.getMethods();
for(Method m: method){
System.out.println(m);
}
3.遍历方法信息,检查方法名是否以test为开头。用正则或者startsWith过滤
String有哪些api
map有哪些api
4.执行这个方法








for(Method m : method){
//System.out.println(m);
//在方法信息上获取方法名
String name = m.getName();
//检查方法是否以test为开头的
if(name.startsWith("test")){
System.out.println(name);
//执行/调用(invoke)方法
m.invoke(obj.args);  //对象所拥有的方法
}




invoke重点!!








如Spring,xml中告知类名即可
注解也是。注到方法,属性要动态获得其方法和属性








动态加载类
Class.forName
获取方法
Method invoke








junit4:查询一个类中所有方法,如果方法包含了注解,就加载








利用?????/












TestCase中编译完@Test就被擦除了




SOURCE:注解只在源代码存在




类加载注解就被删除
反射实在运行期的,而注解已经在编译完就被擦除了




@Retention(RetentionPolicy.RUNTIME)  //编译完了注解有,放到方法区,这样运行期也还有注解
//@Retention(RetentionPolicy.SOURCE) //注解只在源代码中
//@Retention(RetentionPolicy.CLASS)  //注解只保留在类中
public @interface Test {
















class是单例的:也就是在内存中只有一份








单例模式:
1.构造方法私有化,防止在本类外实例化对象
2.声明一个本类对象
3.给外部提供一个静态的方法获取对象实例




饿汉式:不管用不用,先创建
懒汉式:要用才创建




/**
 * 单例模式的解释 
 */
public class Demo04 {
public static void main(String[] args) {
//Girl g1 = new Girl();
//Girl g1 = new Girl();
//Girl g = Girl.one;
//Girl.one = null;
Girl g1 = Girl.getOne();
Girl g2 = Girl.getOne();
Girl g3 = Girl.getOne();
}
}
class Boy{
private static Boy one;  //懒汉式,one是空的
private Boy(){
}
public synchronized static Boy getOne(){  //假如并发调用呢?多线程访问get方法,
if(one==null){  //这里是读
//按需加载,不用则不创建  
//这里是写。读写一起会出现线程安全问题。除非加同步关键字synchronized 
one=new Boy();
}
return one;
}
}
/**
 * 不管用不用都先创建Girl,这个是饿汉式/非懒汉式的单例模式
 */
//私有的one+只读的get方法就不能被修改了,这个类的结构即单例模式,永远保证只有一个
class Girl{
//Girl类型的属性,但是获取属性要先有对象。但是还需要static,否则也还是拿不到
private static Girl one = new Girl();  //static Girl one类加载器只有一个,不需要加同步关键字也可以
private Girl(){
}
public static Girl getOne(){
return one;  //这里是只读
}
}




java中流就是23中模式中的装饰器模式
工厂模式:多次反复创建对象的时候。再需要对象只需要调用方法。用来解决反复创建对象




MVC:在桌面系统中是用观察者模式解决的




工厂模式:多次反复创建对象的时候。再需要对象只需要调用方法。用来解决反复创建对象








————————————————————————————————————
day09




查询被分享的笔记.
select n.cn_note_id,n.cn_note_title from cn_note n JOIN (select * from cn_share)s ON n.cn_note_id=s.cn_note_id




————————————————————————————————————————————




















————————————————————————
check SecurityInsurance
copy RepositoryProcedure
take SecondMask
















————————————————————————————————————————
搜索分页显示




select * from cn_share where cn_share_title like '%java% limit n, m




n:抓取数据的起点,mysql中从0开始的,0代表第一条而Oracle是从1开始的
m:每页所显示的最大数




10条记录,每页最多显示3条,则m=3,最后一页只有1条
















——————————————————————————————
select * from cn_share like %关键词%




select * from cn_share  like #{title}
limit #{begin},3




m:记录的位置
n:每页显示的最大记录数
page1  启始位置:0
page2  启始位置:3
page3  启始位置:6
n  (n-1)*3








“更多”按钮是基于回车的,同一个结果集












————————————————————————————————————————————————————
day10
#spring AOP
##AOP概念
aspect oriented programming
案例:
新注册用户赠送80,此80为广告促销预算。假设100万或者5万预算。预算花到头就必须停止。促销的商品加价,总计加价50万。
注册账户,同时在用户表增加一条记录,同时也在账户表增加50元,而且总促销账户减50.推荐人账户加20。
多张表只能是一起加减或者一起不加。因此需要事务控制,要么成功,要么不成功。
利用aop可以实现事务




面向切面编程




##是什么?
将共同的业务处理从传统业务处理中抽离出来,单独封装,
然后以配置的形式进行关联








都是对service层下的操作
把每一个方法当作一个面








对系统service层进行AOP处理
对系统service下所有方法追加相同的功能处理




案例:
如在每一个方法增加执行时间统计,方法开始执行的时间,方法结束的时间。




使用AOP只需要写一个方法,作用到每一个方法上,而不需要在每一个方法上都增加代码








如某段时间需要加上性能监测,而性能改进之后,项目迭代之后,需要撤销性能监测。
所以需要AOP












————————————————————————
long t1;
利用反射,调用业务方法
long t2;
t2-t1;
















————————————————————————
分三个步骤:
1.导包。AspentJ
2.创建切面组件。aspect包,以及类如AspcetDemo
AspcetDemo启用注解@AspcectJ
@Component








配置spring-aop.xml
<!-- 启用aop扫描 对@Component生效-->
<context:component-scan base-package="cn.tedu.cloudnote.aspect"></context:component-scan>

<!-- 启用aop注解对@AspcectJ生效-->
<aop:aspectj-autoproxy/>




















3.配置切面组件,作用到需要的地方




案例:在每个controller上增加打印信息
1.导包:
  <dependency>
  <groupId>aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.5.4</version>
  </dependency>




2.




















<!-- within为类限定表达式 -->
<aop:before method="logController" 




pointcut="within(cn.tedu.cloudnote.controller..*)"/>
其中..包和子包以及子包下的所有方法




--注解方式实现:
@Component @Aspect @Before








#AOP相关概念
- OOP:类,对象,封装,继承,多态
- AOP:切面,切入点,通知,动态代理
















##切面(aspect)
指的是封装了共同处理的组件,并且能够切入到其他组件的方法上.
##切入点(pointcut)
"within(cn.tedu.cloudnote.controller..*)"








用于指定目标组件的方法.切入点要加入到哪个组件上












- 方法限定表达式》》》》




可以切入到具体的方法上
  可以给某个组件中部分方法追加共同功能
  execution(修饰符? 返回类型 方法名(参数) 异常抛出?)
  //匹配到add开头的所有方法
  execution(* add*(..)) //不管返回值,不管参数列表是什么,只要是add开头的方法都匹配
execution(void add*(..)) //只要是add开头的,而且没有返回值的方法都匹配




  //匹配UserService包下的所有方法
  execution(* cn.tedu.UserService.*(..))
  //匹配service包下所有类的所有方法
  execution(* cn.tedu.service.*.*(..))
  //匹配service包及子包下的所有方法
  execution(* cn.tedu.service..*(..))
——————————————————————————————————-
 execution在相关设定的时候替换了within
————————————————————————————————————








- 类型限定表达式》》》》








  可以给某个组件的所有方法追加功能
  within(类型)
  //匹配UserService组件下所有方法
  within(cn.tedu.service.UserService)
  //匹配service包下所有类的所有方法
  within(cn.tedu.service.*)
  //匹配service包及子包下的所有方法
  within(cn.tedu.service..*)








——————————————————————————————————








- bean名称限定表达式》》》》








  可以给某个组件中所有的方法追加功能
  bean(id名)
  //匹配id=userService的组件的所有方法
  bean(userService)
  //匹配以Service结尾的所有组件的所有方法
  bean(*Service)




————————————————————————




@Before("bean(userController)")
























##通知
用于指定切入的时机




spring提供了五种通知类型




    try{
      前置通知<aop:before>
      //执行的目标方法
      后置通知<aop:after-returning>
    }catch{
      异常通知<aop:after-throwing>
    }finally{
      最终通知:<aop:after>
    }
环绕通知:
@around=前置+后置通知




注意:环绕通知跟其他4个的方法不同,返回Object的有参的,如下的性能审计。
——————————————————————————————————————————————————————————
@Around("within(cn.tedu.cloudnote.service..*)") //service包下所有子包所有类的所有方法
public Object log(ProceedingJoinPoint point) throws Throwable{
Object obj = new Object();
try {
long start = System.currentTimeMillis();




obj= point.proceed(); //代表具体执行的方法,返回的是一个对象

long end = System.currentTimeMillis();

//需要获取方法名,否则测试的方法太多不知道是哪个方法的时间
//签名:返回的是一个对象,包含方法名和参数类型.
//导包apectj.lang.Signature
Signature s = point.getSignature();





System.out.println(s+"耗时:"+(end-start));


} catch (Throwable e) {
e.printStackTrace();
throw e;
}





return obj;




一个类中方法签名是唯一的。
按理说java反射应该有,但是却没有。按照我们编程的理解,一个概念一定是有一个对象的
————————————————————————————————————












- 切面:   追加啥功能? 单独封装的代码
- 切入点: 切谁? 方法/类型/bean表达式,如所有Controller
- 通知:   啥时候切? 前置/后置/环绕




##动态代理
AOP原理:底层使用动态代理技术
动态代理技术:动态创建类的技术
动态代理技术有两种:
- 基于接口技术:实现接口,重写接口中的方法
public class $Proxy25 implements 目标接口{
//事务处理
login() //将AOP的事务处理和login一起封装了








}








- 基于目标技术:继承类后,重写类方法
























可以创建一个新的类型,重写目标接口或目标类的方法
在重写方法中,追加了要切入的功能代码和方法代码




spring有两种动态技术:
- 基于目标接口的
- 基于目标类的








    public class $Proxy22 implements 目标接口{
    public void checkLogin(){
    //追加了事务处理
    //重写了UserServiceImpl.checkLogin
    }
    }
    public class $Proxy22 extends 目标类{
    
    
    }




#AOP注解配置
##注解标记
- @Component 起到应以<bean>的作用
- @Aspect    <aop:aspect ref="loggerBean">
- @Before    <aop:Before pointcut=within()>




案例:生成异常日志
- 要求:当系统发生service异常,将异常信息写入日志文件
- 切面:将异常信息写入文件
- 切入点:after-throwing("within(service..*)")




AOP生成的新的类型:重写了service接口的方法,注入了AOP后的
com.sun.proxy.$Proxy25








————————————————————————————————








案例:实现性能审计
--切面:输出消耗时间
--切入点:所有service下的所有方法
--通知:@Around








______________________________________________________________________________________________








案例:异常信息写入日志
- 要求:当系统发生service异常,将异常信息写入日志文件(AOP实现)
- 切面:将异常信息写入文件(FileWriter--PrintWriter)
- 切入点:service层面的所有方法("within(service..*)")
通知:@after-throwing








————————————————————————————————————————————
回顾9个对象和作用域:




page:
page,pageContext,config,exception,response.out(Jspwriter)
request
request
session
session
application
application
















作业:
创建切面组件使用bean/方法/类型限定表达式指定切入点




独立完成云笔记service层的性能审计












————————————————————————————————
day11




事务管理:
什么是?
事务:程序为了保证业务处理的完整性,执行的一条或多条SQL语句。
事务管理:对事务中的SQL语句进行提交或者回滚




为什么要使用:
确保数据库数据的完整性,不出现脏数据




A B账户间的转账








每一个dao都当成一个事务








1. 配置Spring-transaction.xml
2. 使用@Transactional标记
















事务处理只能是RuntimeException




编程式事务管理
try{
业务SQL1;
业务SQL2;




业务SQL3;




conn.commit();
}catch(Exception e){
conn.rollback();
}
声明式事务管理(使用注解,配置)!!!!!!!!!重点!!!!!!!!!!!!!!!!!
案例:批量删除使用变长的参数
如:
deleteNotes(String... args);
















——————————————————————————————
##可读可写:readonly
作用于select语句的事务上
语法:
select操作时,可采用只读事务
  @Transaction(readOnly=true)




——————————————————————————————————————————————
##回滚特性
  默认RuntimeException回滚,其他异常不回滚。当遇到其他异常,也需要回滚的时候,就用到该roolBackFor属性
如上传头像和注册,如果上传头像出现了异常,则把信息回滚,此时该异常不是runtimeException,属于IO异常,
否则即便头像出错了,信息也已经写入到持久层了
    @Transaction(rollbackFor=IOException.class)
public void f1(){
//db操作(insert)
//IOException










——————————————————————————————————————
##传播特性
默认类型:REQUIRED
##Spring中常用事务类型:




REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。------》》》默认值




SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。




MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。




REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。




NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。




NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。




NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。




@TRANSACTIONAL
public void f1(){
//业务代码A
f2(); //方法1调用了方法2.默认值REQUIED的时候:当方法2的业务C出错则影响的f1。把f2看作是f1的业务,只要f2出错了,f1也回滚。工作中都采用默认值,也是最常用的处理方式。如果有其他需求,不会在数据库属性上处理,而是在代码上处理
//业务代码B
}




@TRANSACTIONAL(propagation=REQUIRES_NEW)
public void f2(){
//业务代码C //报错
}




————————————————————————————————————————




##隔离特性——————》为了解决并发处理而设计的。
默认属性:READ_COMMITED
针对事务并发进行处理.
脏读-------->>
事务1进行了增删改DML操作,但并未提交,此时事务2读取了事务操作的数据。此时,事务1进行了回滚,则事务2进行了一次脏读的操作




幻读-------->>事务1在一定范围内查询数据,同时事务2....




(理解:事务1查询了表中全部的数据,在操作的同时,事务2进行了批量插入操作,此时事务1查询的数据变成了一部分,称为幻读)




级别越过,越限制并发操作,如序列化操作的并发为0,安全最高,性能最低。
如级别最低的数据并发经常发生。




读已提交:默认值。兼顾安全和性能

-READ_UNCOMMITTED 读未提交(级别最低)
-READ_COMMITTED 读已提交
-REPEATABLE_READ 可重复读
-SERIALIZABLE 序列化操作(级别最高)
-DEFAULT 根据数据库自动选择READ_COMMITTED
?或REPEATABLE_READ
















什么是数据库的事务?
:事务(Transaction)是数据库运行中的一个逻辑工作单位,是用户定义的一个罗辑操作。这些操作要么不成功,要么都成功,是一个不可分割的工作单位。通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。 
(2):事务通常是以begin transaction开始,以COMMIT或ROLLBACK结束。 
COMMIT表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。 
ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。 
(3):事务运行的三种模式: 
A:自动提交事务 
每条单独的语句都是一个事务。每个语句后都隐含一个COMMIT。 
B:显式事务 
以BEGIN TRANSACTION显式开始,以COMMIT或ROLLBACK显式结束。 
C:隐性事务 
在前一个事务完成时,新事务隐式启动,但每个事务仍以COMMIT或ROLLBACK显式结束。 
(4):事务的特性(ACID特性) 
A:原子性(Atomicity) 
事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。 
B:一致性(Consistency) 
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。 
C:隔离性(Isolation) 
一个事务的执行不能被其他事务干扰。 
D:持续性/永久性(Durability) 
一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。 
注:事务是恢复和并发控制的基本单位。 








——————————————————————————————————————————————




关联映射:
将数据库的数据关联到实体的属性
实体对象的引用反应了它们之间的关联关系
表与表直接的关系!
什么是??通过数据库对象之间的关联关系,反映到实体对象之间的引用。
多表查询的时候会用到。
如:通过id查询到用户下的所有笔记,加载到实体类中








#Mybatis关联映射
什么是?将数据库中有关联关系的表,以实体对象引用的方式体现出来




WHY?
加载多个表中的关联数据,封装到实体对象中




















关联方式:
- 单个对象关联
cn_user--->User
cn_notebook--->Book




需要把另一个对象作为属性加入到另一个实体对象中
如:
在Book实体类中,增加对象属性private User user;
- 多个对象关联

class User{




private List<Book> books; 
}








单个对象关联
class Book{




private User user;
}




什么时候用?
业务需要对数据库进行关联查询的时候.




可以通过一条SQL语句完成关联查询,也可以通过两条SQL语句进行关联查询




##案例:通过userId查询用户信息和关联的笔记本信息
1. User 实体类
2. 定义Dao接口,配置Mapper文件
3. 定义测试类验证查询结果




2个SQL语句: 语句简单,但配置繁琐,与DB两次交互
1个SQL语句: 语句复杂,配置较简单,与数据库交互一次








##案例:通过查询笔记信息,关联用户信息
用一条查询语句实现




#主键的字段处理
在数据库使用自增列或序列作为主键值时,如何在insert执行后,立刻获取ID值.
-mysql
create table t_emp(id int primary key auto_increment, name varchar(20),age int)












User实体类增加Book类型的属性后跟数据库表无法匹配,因此xml不能用resultType="cn.tedu.cloudnote.entity.User">




而是用resultMap




resultMap type="cn.tedu.cloudnote.entity.User" id="userMap1">
<id/>  //该id是做主键映射配置的








association:关联单个对象的时候用
collection:关联多个对象的时候用,也就是集合




<resultMap type="cn.tedu.cloudnote.entity.User" id="userMap1">
<!-- 按名称对应装载,可省略 -->
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="books" 
javaType="" 
ofType=""  //集合当中的类型
select=""  //这个集合是谁查出来的。先预定义,后面再写
column="" //条件是哪个字段。传进来的值去和数据库中的哪个字段匹配
></collection>

</resultMap>








关联原理是?????????????????




<resultMap type="cn.tedu.cloudnote.entity.User" id="userMap1">
<!-- 按名称对应装载,可省略 -->
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="books" 
javaType="java.util.List" 
ofType="cn.tedu.cloudnote.entity.Book" 
select="findBooks" 
column="id"></collection>

</resultMap>
<!-- 查询笔记本表 -->
<select id="findBooks" parameterType="String" 
resultType="cn.tedu.cloudnote.entity.Book">








————————————————————————————————————————————




从cn_user表和cn_notebook表中查出用户名下的笔记:
两张表通过user_id关联




select u.cn_user_name, n.cn_notebook_name from cn_notebook n join cn_user u on u.cn_user_id=n.cn_user_id where u.cn_user_id='48595f52-b22c-4485-9244-f4004255b972';








updateUser表的Token
登录时更新用户的Token
if(user.getPassword().equals(md5)){
String token = UUID.randomUUID().toString();
user.setToken(token); //虽然只设定一个字段,实际全部更新了.set返回后有了新的token,带到cookie
//也可通过map做部分更改
Map<String,Object> userInfo = new HashMap<String,Objcet>();




userInfo.put("id",user.getId());
userInfo.put("token",token);
userDao.updateUser(userInfo);
return user;
}












——————————————————————————————————————————————————————
动态sql
mysql也有个自增列,mysql自己从列表的直接生成的
MySql, DB2, SQLServer 等数据库都提供了自增类型, MyBatis提供了这种类型的支持.








创建 表:采用自增列作为主键
create table t_emp (id int primary key auto_increment, name varchar(20),age int);








练习:Mybatis自动获取主键值
1.创建Emp类
2.Dao接口定义save(Emp e)方法
3.Mapper定义<insert useGeneratedKeys="true" keyProperty="id" parameterType="" resultType="">
</insert>
4.创建测试类




注意:
useGenerated
而不是
useGenerate




Oracle数据库的自增ID设置
<insert id="save1">
<selectKey order="BEFORE" resultType="int" keyProperty="id">
select emp_seq.nextval from dual
</selectKey>查出序列之后oracle才会真正执行
insert into emp(id,name,age)values(#{id},#{name},#{age}) 这里的id就是上面kp的id
</insert>




——————————————————————————————————————————————————
MyBatis提供了丰富的动态SQL拼接功能:




<if test=""></if>
<trim>
<set>
<where>
<choose> <when>
<foreach>
















————————————————————————————————————————————
choose




业务:




模糊查询笔记:




有title 参数则 title like ?
有body 参数则 body like ?
有key 参数则 title like ? and body like ?
如何实现?
<if test="" > </if>
<choose> 跟java的Switcher一样
<when test=""></when>
<when test=""></when>
<otherwise><otherwise> 相当于java的Switcher的default
</choose>
<trim>
<set>
<where>
<foreach>
————————————————————————————————————————




<select id="findNotesByParam"
    parameterType="map"
    resultType="map">
    select 
        cn_note_id as id,
        cn_note_title as title,
        cn_note_body as body
    from
        cn_note
    where
        <choose>
            <when test="key != null">
                cn_note_title like #{key} and
                cn_note_body like #{key}
            </when>
            <when test="title != null">
                cn_note_title like #{title} 
            </when>
            <when test="body != null">
                cn_note_body like #{body}
            </when>




        </choose>




    order by
        cn_note_last_modify_time desc   
</select>












————————————————————————————————————————————————————












输入了笔记名称进行搜索的时候
<insert id="">
select * from cn_note
where cn_note_status_id=1
加一个过滤条件,输入了笔记本名称进行搜索的时候
<if test="bookName!=null">
and cn_notebook_name=#{bookName}
</if>
再加一个过滤条件,输入了笔记名称进行搜索的时候
<if test="noteName!=null">
and cn_notebook_name=#{noteName}
</if>
如果再加一个过滤条件,输入了用户名称进行搜索的时候,则继续拼接条件语句
<if test="userName!=null">
and cn_notebook_name=#{userName}
</if>
</insert>




————————————————————————————————————
<where>的用法,代替where.
当下面第一个条件不满足的时候,sql不就变成了这样吗?




select * from cn_note where and cn_notebook_name=#{noteName}




这样多出了“and”
注意:




不仅可以去除无用的前缀后缀。如update value出现多余,
号的时候,where能够去除,如空格
<insert id="">
select * from cn_note
<where> cn_note_status_id=1

<if test="bookName!=null">
cn_notebook_name=#{bookName}
</if>

<if test="noteName!=null">
and cn_notebook_name=#{noteName}
</if>
如果再加一个过滤条件,输入了用户名称进行搜索的时候,则继续拼接条件语句
<if test="userName!=null">
and cn_notebook_name=#{userName}
</if>




</where>
</insert>




——————————————————————————————————————————————————
<set>作用跟where一样,代替了set,在update语句中。update emp set(empname=?) where empid=1
<set>
empname=?
</set>




————————————————————————————————————————————————




<trim>当执行语句没走最后一个条件的时候,如下面的第三个条件未执行,则语句多出了,




<if test="bookName!=null">
cn_notebook_name=#{bookName},
</if>

<if test="noteName!=null">
and cn_notebook_name=#{noteName},
</if>

<if test="userName!=null">
and cn_notebook_name=#{userName}
</if>




trim的使用演示:
<select id="">
update cn_note
set
<!-- 前缀prefix后缀suffix -->
<trim prefix="" prefixOverrides="and / or"
suffix="" suffixOverrides=",">
<if test="bookName!=null">
cn_notebook_name=#{bookName},
</if>

<if test="noteName!=null">
and cn_notebook_name=#{noteName},
</if>
如果再加一个过滤条件,输入了用户名称进行搜索的时候,则继续拼接条件语句
<if test="userName!=null">
and cn_notebook_name=#{userName}
</if>
</trim>
</select>
——————————————————————————————————————




<foreach>的使用




<delete id="deleteNotes"
    parameterType="map">
    delete from 
        cn_note
    where 
        cn_note_id in 
        <foreach collection="idList"
            item="id"
            open="(" separator="," close=")">
            #{id}
        </foreach>
</delete>




——————————————————————————————————————————————
void deleteNoteById(String...ids);
















<delete id="deleteNotes" parameterType="String">
delete from cn_note where cn_note_id = #{id}
<foreach collection="list/array"  //固定写法?
item="id" //别名,如id
//结构的处理从哪个符号开始,到哪里结束,用什么分割
open="(" 
close=")"
separator=",">
#{id}
</foreach>
</delete>




————————————————————————————————————————————
作业:完成组合查询笔记功能
-service处理
-controller处理
-回调处理
















































——————————————————————————————————————————————
String常用方法:
charAt
contains
concat
compareTo
compareToIgnoreCase
endsWith
equals
getBytes
format
indexOf
lastIndexOf
matches
replace
replaceAll
split
startsWith
subString
toCharArray
toLowerCase
valueOf
trim
isEmpty




&gt; 大于号>
&lt;小于号,< less than
&nbsp;空格
&amp; &符号
















——————————————————————————————————————————————————————












update cn_note
set
<trim suffixOverrides=",">   //有时候不加trim也能工作,但最好加上
<if test="title!=null">
cn_note_title=#{title},
</if>
<if test="body!=null">
cn_note_body=#{body},
</if>
<choose>       //if-else语句。choose可以nested
<when test="time!=null">
cn_note_last_modify_time=#{time}
</when>
<otherwise>
cn_note_last_modify_time=unix_timestamp()
</otherwise>

</choose>
</trim>
where
cn_note_id=#{noteId}





当错误变成where
cn_note_id==#{noteId}则会输出sql
——————————————————————————————————
select unix_timestamp     //系统时间 跟oracle的sysdate一样。不同的数据库完全不同








foreach:循环,大批量。如批量删除笔记
set
where
if
trim
<choose>
<when>
</when>
<when>
</when>
<otherwise>
</otherwise>
</choose>








____________________________________________________________________________________




web向服务器发送数组:
key是一样的即可








<where><set>
<where>能够去除and,但是如果不行的时候需要另外使用<trim>处理and








——————————————————————————————————————————




事务:
登录:
验证用户名和密码
登录时间,在线时长,登录次数,登录时间段。给对应的登录积分。




发表评论,需要积分
一个网站用到事务很多,都用try/catch明显工作量大,因此需要aop








利用aop,在业务开始的地方,开启事务。




加了@Transactional,就自动执行以下代码
try{ try{
//开启事务<---------------------------------------------------//@Before
@Transactional//加到业务层上
处理事务过程 处理事务过程
CRUD。。。 CRUD。。。




//提交事务<---------------------------------------------------//@AfterReturning
}catch(){
//回滚事务<---------------------------------------------------//@AfterThrowing




}finally{
//释放资源<---------------------------------------------------//@Return
}












声明式事务:利用aop处理事务








加了@Transactional,方法即套用了try/catch












————————————————————————————————————————————————————




方法的调用栈:一层调用一层。看控制台从下往上的异常可见是调用层级








java.lang.RuntimeException: 删错了
at cn.tedu.cloudnote.service.NoteServiceImpl.deleteBatchNotes(NoteServiceImpl.java:169)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)

AOP拦截器。在执行deleteBatchNotes业务方法的时候,
通过反射先执行AOP也就是切面组件,这时候是不是执行业务方法呢?不是,而是先执行业务组件
也就是切面组件,切面组件执行完了,再利用反射调用了业务方法




at cn.tedu.cloudnote.aspect.AuditBean.log(AuditBean.java:18)












at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)




Spring的AOP,AOP是动态代理做的,最底层就是反射




at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)




at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy27.deleteBatchNotes(Unknown Source)
上下可见动态代理,aop的底层  测试方法调用了deleteBatchNotes方法,而且是调用了动态代理。
deleteBatchNotes调了JdkDynamicAopProxy.




at cn.tedu.cloudnote.test.TestNoteService.delleteNotes(TestNoteService.java:113)








at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) //c语言调用,java底层
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  //java底层
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  //java底层




at java.lang.reflect.Method.invoke(Method.java:606)  //反射的方法调用
上下可见junit调用了反射。可见invoke
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)




at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
















junit底层就是反射做的




junit调用反射,反射调用测试方法,测试方法运行,测试方法调用delelenotes方法




aop切面组件执行完再利用反射调用业务的delete方法








业务方法--》tran---》aop---》aop异常拦截---》抛异常---》事务回滚
业务方法--》tran---》aop---》aop异常拦截---》不抛异常---》事务无异常正常执行




————————————————————————————————————


part11




————————————经典Bug——————————————————————————————————————
@Component
@Aspect
public class AuditBean {
@Around("within(cn.tedu.cloudnote.service..*)")  //service包下所有子包所有类的所有方法
public Object log(ProceedingJoinPoint point) throws Throwable{
Object obj = new Object();
try {
long startTime = System.currentTimeMillis();
obj = point.proceed(); //代表了具体方法的执行。通过执行返回一个对象
long endTime = System.currentTimeMillis();
//要知道哪个方法的耗时多少
String str = point.getSignature().toString();

//需要获取方法名,否则测试的方法太多不知道是哪个方法的时间
//签名:返回的是一个对象,包含方法名和参数类型.
//导包apectj.lang.Signature
Signature s = point.getSignature();
System.out.println(s+"耗时:"+(endTime-startTime));

} catch (Throwable e) {

e.printStackTrace();
throw e;  //!!!!!!注意:异常要扔出,否则事务处理遇到异常无法回滚
}
return obj;
}

业务层进行事务处理的时候遇到异常就终止,进行事务回滚。
如果该业务层还加入了AOP,如这里的性能审计,而且该AOP的catch没有抛出异常,则事务回滚失败!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
所以一定要抛异常!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!












————————————————————————————————————————————————








SSH








SSM:好处:spring-mvc已经把web相关都设置好了。
分工合作,dao/service分开写












SSH:
mybatis:优势:零编码。如10行做完
hibernate:有编程量。需要20-30行
jdbc:需要200行








struts相当于spring-mvc




struts相当于拦截器:在servlet之前执行




sun推荐在web使用MVC
Apache struts1实现了MVC 编码多
Webwork xwork 编码少
合并,apache名字,webwork内容。变成
apache strut2(webwork) 编码少
spring MVC 编码更少




上面的底层都是servlet




————————————————————————————————————
注意:
过滤器属于servlet规范当中定义的特殊的组件
而拦截器属于spring框架












来自Apache基金会的软件: http://struts.apache.org
Struts2 与 Struts1 完全没有关系
Struts2 的前身是 WebWorks
Spring MVC\Struts2\Struts1 都是 MVC 模式的Web框架
MVC是非常流行的 用户界面设计模式。
MVC是3层架构中的表现层




更改查看项目视图:
window-》showview-other-java-package explorer




pom:struts2-core  2.3.24
jar包如果有小纸片说明有源代码




struts在web.xml配置时不需要loadonstart配置,因为过滤器天生在容器启动时初始化,
而spring-mvc在web.xml配置dispatcherservlet的时候需要配置loadon...








file-》new-》other-web--》filter--
--》create filter中勾选use exsting,然后browsing选择现有的filter
选择StrutsPrepareAndExecuteFilter




下一步,把filter mappings的URL Pattem/Servlet Name改成/*




点击完成。即可自动在web.xml配置executeFilter




按照路径分层/授权




————————————————————————————————————————————
webapp(项目,如cloudnote)
|-WEB-INF 用户不能直接访问
| |-web.xml部署描述文件
| |-classes 开发的Servlet/Service/Dao...
| | |-conf/spring-mybatis.xml
| |-lib 第三方的jar包:dbcp...
| |-jsp
| | |-*.jsp 是用户不能直接访问的,界面视图组件,需要服务器提供数据拼接的
|-*.jsp完整的有数据的jsp
|-*.html
|-js/*.js
|-css/*.css








tomcat部署目录结构:








|-webapps
| |-cloudnote
(拷贝项目cloudnote下的文件目录)












部署web应用
1.copy
2.eclipse(copy)
3.maven(copy)。maven:开发部署打包测试
















tomcat/jBoss/Weblogic








strut2默认是到class中找struts.xml
struts是默认名,不能写成struts2,否则相当于无用








strut2支持两种请求:路径或.action
如:
/login/form
或带action的
/login/form.action




当需要接收的参数很多的时候,
struts2提供了实体封装//域模型封装












有两种方式可以从页面向控制器传输数据:




基本Bean属性传递方式
域模型属性传递方式
————————————————————————————
域模型属性传递方式
浏览器
用户名 name=user.name
密码 password=user.password




strut2封装成一个BeanUserInfo
表单
用户名 name
密码 password








如login和update的表单是雷同的,此时这个BeanUserInfo就能重用了




在服务器的Login2Action{
User user;
setUser(User user){
this.user=user
}
}
只需要传User即可,不需要用传大量bean属性




UpdateAction{
User user;
....
}




————————————————————————————




有id的类需要重写equals








LoginAction2先调用getUser,如果为空,再调用setUser




每次都创建一个对象,只填一个属性。
如第一次创建对象User,但只填了属性name
第二次再调用对象,但只填了password




所以,调用对象或者属性都要设置get和set方法












——————————————————————————————————————————————




public String execute(){
/**
* ActionContext在Strut2中代表当前Strut2
* 环境相关信息.ActionContext能获取很多很多信息,get...
*/
ActionContext ctx = ActionContext.getContext();
/**
* Map类型的session不依赖于ServletAPI
* HttpSession(与Servlet API耦合性低)就可以进行与容器无关的测试等离线操作。

* 离线:脱离web容器单独使用,比如进行junit测试
*  
* 在底层strut2容器会将map session中的信息同步到httpsession中
* 也就是不会用到servlet api也就是单独的bean,也就是单独的类/方法,也就是可以用junit测试。
* 正常来说,junit不能测试servlet
* 因为servlet测试需要httpservletrequest和response。
*/
Map<String,Object> session = ctx.getSession();








——————————————————————————————————————
正因为更servlet没关系才可以进行外部测试




————————————————————————————————————————




strut2与spring整合:
1.利用Spring管理Action
2.spring管理Action,同时可以为控制器注入业务层
最终目的:将控制器与业务层整合
导包strut2-spring-plug 2.3.24












spring有另外一个加载方式:spring listener




org.springframework.web.context.ContextLoaderListener用来初始化spring容器,不初始化spring
无法帮我们管理bean




在部署描述文件也就是web中配置




spring的xml配置文件需要将3.2版本改成3.0
只需配置component scan扫描指定包的controller即可,这样strut2和spring就能一起工作了












——————————————————————————————————————————————————
//为何?web应用是多线程的
@Scope("prototype")  
public class WebAction extends BaseAction{








查看线程:关闭tomcat后debug开启,bio即是用户线程












一个浏览器发送给服务器都天生是串行发送的








当多个线程并发访问同一个临界资源就会出现线程安全问题








!!!!!!!!!!!!!
strut2的Action如何避免线程安全性问题?:每个请创建一个Action对象,如果使用spring管理Action对象,
请使用@Scope(prototype)




spring-mvc有没有安全问题?
有!默认就是单例的。因此避免写公共变量




strut2默认是一个请求一个线程的,可以不加scope,但是如果使用了spring,则必须加scope








service没有定义公共变量,因此可以不必担心线程安全问题
保证service内没有公共变量
访问session和application的时候一定要同步,尤其是application,如果只读可不必在意,只要有写就要注意




dao默认都是单例的




———————————————————————————————————————————————————




现在的抢购网站都是用队列处理








spring提供了多种result,支持各种文件的转发,图片视频...
<result type=? name="success">/WEB-INF/success.jsp</result>








http响应协议支持:jpg/png/mp3/avi/json
strut2在服务端支持了多种响应类型,多种result类型,也就对应上面的类型,以及301重定向




301url
第一次,控制器响应回浏览器301 url 
第二次:然后浏览器再向服务器发一次请求




http网页支持多种媒体类型的下载




多种resulet类型
despatcher
stream
json
redirect
redirectAction




把流属性放在控制器上,就能下载




后面半小时json只序列化了字符串,看day02课件








map用得更多,键值对的








任何一个result。。。




default。xml有:
 <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>




然后查看strut2api的struts2/struts2-core/apidocs/

org.apache.struts2.dispatcher
Class StreamResult




可见ContentType
可以设置媒体类型








contentType=image/jpeg
contentType=application/json
contentType=mpeg/audio








despatcher--->html
stream
--->jpg
--->png
--->mp3
--->avi




json--->json
redirect--->301重定向
redirectAction--->301重定向
















public class StreamResult
extends StrutsResultSupport




A custom Result type for sending raw data (via an InputStream) directly to the HttpServletResponse. Very useful for allowing users to download content.




This result type takes the following parameters:




  ***重要  contentType - the stream mime-type as sent to the web browser (default = text/plain).
    contentLength - the stream length in bytes (the browser displays a progress bar).




 ***重要   contentDisposition - the content disposition header value for specifing the file name (default = inline在浏览器默认直接显示, values are typically attachment如果设置为附件形式,则变成下载;filename="document.pdf".  //点击下载,而不是显示




  ***重要  inputName - the name of the InputStream property from the chained action (default = inputStream). //用哪个流,把哪个流发给客户。如果是照片就把照片放入到这个流,如果是音乐则放到这里发,如果是doc则生成doc放到这里。如果bean写了默认属性,则这里可以不写??




    bufferSize - the size of the buffer to copy from input to output (default = 1024).
    allowCaching if set to 'false' it will set the headers 'Pragma' and 'Cache-Control' to 'no-cahce', and prevent client from caching the content. (default = true)
    contentCharSet if set to a string, ';charset=value' will be added to the content-type header, where value is the string set. If set to an expression, the result of evaluating the expression will be used. If not set, then no charset will be set on the header












——————————————————————————————————————————————




extends="struts-default">因为json-default的媒体类型比较全












BufferedImage img = new BufferedImage(400, 300, BufferedImage.TYPE_3BYTE_BGR);
//照片:大号的二维数组。横400pix,竖300pix。
//一个pix是3个byte,每个字节第一个是blue,第二个字节是green,第三个字节是red 
















要导包strut2-json








contentType的配置,查看tomcat的conf的web.xml
   <mime-type>video/x-msvideo</mime-type> 对应的avi的contentType的配置








Excel新的:
 <extension>xlsx</extension>
        <mime-type>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</mime-type>
    </mime-mapping>




Excel旧的:
     <extension>xls</extension>
        <mime-type>application/vnd.ms-excel</mime-type>








————————————————————————————————————
重定向:




ServletRedirectResult




 <result name="success" type="redirect">
   <param name="location">foo.jsp</param>
   <param name="parse">false</param>
   <param name="anchor">FRAGMENT</param>
 </result>




————————————————————————————————————————




<!-- servletresult -->
<action name="test" class="redirectAction">
<result name="doc" type="redirect">
http://doc.tedu.cn
<!--  因为location是默认属性,可以不写xml标签,即下面和上面一样的
<param name="location">  
http://doc.tedu.cn
</param>
-->
</result>
<!-- redirectAction用于重定向到action。photo是Action的名字,因为是默认值,因此只写photo
写demo/photo也行
-->
<result name="photo" type="redirectAction">
photo
</result>








——————————————————————
浏览器地址输入:
http://localhost:8080/struts_day03/demo/test?type=0




拦截器:
Interceptor不改变控制器的前提下,在控制器前后执行,增加功能
intercept(
//控制器前执行的代码
invocation.invoke()//有这句调用则调用子控制器,没有调用则跳过
//控制器后执行的代码








strut2本身也是依靠拦截器工作的,所有的控制器,但凡注入了,都用到了拦截器
strut2天生有一个拦截器。需要带上basicStack,否则strut都半残废了。
parameter调用




————————————————————————————————————————
所有的标签库都是在服务器端执行的,无论是jstl还算strut2的lib
java所有的包括jsp都是在服务器端执行的
————————————————————————————————————————
ValueStack:
浏览器-->主控制器-->子控制器执行,收到数据--->将数据保存的ValueStack
包括控制器本身放到ValueStack




在jsp中利用OGNL/EL读取ValueStack值




<s:debug/>展示ValueStack数据




是控制器向jsp传送数据的通道,就是一个集合








————————————————————————————————
OGNL:spring/mybatis等获取属性的时候用过,都是OGNL




stack Context
#key获取环境信息




ValueStack:
两个区:




内容区:控制器的对象
content:保存所有的环境信息








因为key包含了点,只能用[]
<s:property value="#request['struts.actionMapping']"/>




具体为何要用,看以下js的演示:








javascript中对象就是一个map
在浏览器的console中的:




"tom", "jerry", "andy"]
ary
["tom", "jerry", "andy"]
ary[0
SyntaxError: Unexpected token }
ary[0]
"tom"
ary[1]
"jerry"
ary[2
SyntaxError: Unexpected token }
ary[2]
"andy"
ary[1].length
5
obj = new Object();
Object {}
obj.name=tom;
ReferenceError: tom is not defined
obj.name="tom";
"tom"
obj
Object {name: "tom"}
obj.age=20;
20
obj.height=5.6;
5.6
obj
Object {name: "tom", age: 20, height: 5.6}
obj["phone"]="110";
"110"
obj
Object {name: "tom", age: 20, height: 5.6, phone: "110"}




obj['user.address']='beijing';
"beijing"
obj
Object {name: "tom", age: 20, height: 5.6, phone: "110", user.address: "beijing"}
obj.name 获取name,没问题
"tom"
obj.age 获取age,也正常
20
obj.user.address 但是,获取user.address,就或报错,
因为obj会去找user,可是并没有user,而是只有user.address。
obj['001']="Dog";
"Dog"
obj
Object {name: "tom", age: 20, height: 5.6, phone: "110", user.address: "beijing"…}
obj.001  //这样获取也一样报错。所以也许要用中括号!!
因此<s:property value="#request['struts.actionMapping']"/>需要中括号




先有js,el的语法也跟js一样




如果是map套map,获取时则方括号套方括号




————————————————————————————————————
在js中:




data=[{name:'tom',age:20},{name:'jerry',age:33}]
[
Object

Object
]
data[1].age
33
data[1]['age']
33
data[1]['name'].length
5




同样,el也能这样用




OGNL在做计算的时候不区分list/map的
















map {age=20, name=Tom, user.address=北京, 001=狗狗}
sun公司在数组对象上没有很好地重写toString,
而直接输出结构
data [Ljava.util.Map;@3ebfd8




@3ebfd8不是地址,而是通过运算转换的值




可以把data类型换成list,因为list重写过了








————————————————————————————————
OGNL只能在strut标签内用
el配合jstl用
el为何也可以访问value
strut2把el底层做了修改,造成el可以直接方法ValueStack




现在都用ajax/json处理




ValueStack在面试会问题
用来从浏览器到服务器承载数据的








加入Property Name有两个texts呢??
从上往下查找,找到一个Property Name,剩下的就不管了








________________________________________________________________________________




Hibernate




不用写SQL,写HQL。所有数据库的子集,特定数据库则操作不了
mybatis:轻量化,不用写java,需要写sql




ORM:对象关系映射,将对象映射到关系数据库。可以实现对象的CRUD(增删改查)操作




EJB:调试实体bean很麻烦




JPA:java持久层api,sun招来Hibernate creator写的








JPA==Hibernate








1.导包:Hibernate+JDBC Driver
2.配置Hibernate主配置文件(连接db的参数)
当使用了spring,就不再需要了
3.映射文件
--一个实体类对应一个映射文件








mybatis:配置文件写sql
Hibernate:配置文件,类与表,属性与列的对应关系




4.创建session,跟mybatis的sqlsession(crud)相似
--Session对象提供了crud方法
5.使用session对象实现crud








只需要4








持久状态下(save以后),user对象转化为持久状态。持久状态的修改将直接影响数据库




游离状态一改属性状态不变,
一旦调用update方法,游离状态又变成持久状态,其属性也会一点点改到数据库












面试问题:出现异常:




ClassNotFoundException说明导包导少了
MethodNotFoundException:版本不对
空指针异常:变量没有正常赋值,正常赋值就行了








————————————————————————————————————————————
User user = new User("100","tom","123","ok","cat");

Session session = factory.openSession();
  
//执行了save数据库里面也没有。
//要加上Transaction和commit() 正常有事务应该有try/catch的。
Transaction tx = session.beginTransaction();
session.save(user);


tx.commit();
session.close()












————————————————————————————————————————————————








Hibernate生成的sql不可控,无法知道低效还是高效,生成的是低效的




















——————————————————————————————————————————————————————————




Spring哪个接口最重要?ApplicationContext




Hibernate哪个接口最重要?Session




Mybatis呢?SqlSession








































———————————————————————————————————————————————————————————




sqlsession:提供了crud的方法,利用它可以实现对数据库crud




指定某种dialect,Hibernate会自动生成sql语句




<hibernate-configuration>




<session-factory>
<!-- dialect -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>








PostgreSQL:学院化的数据库








<property name="show_sql">true</property> //调试需要,运行不需要。hibernate输出生成的接口
<property name="format_sql">true</property>   //分行显示,格式化输出。也是用来做调试的
















POJO












一、PO:persistant object 持久对象,可以看成是与数据库中的表相映射的java对象。
最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合。PO中应该不包含任何对数据库的操作。  




二、VO:value object值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。
但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要.个人觉得同DTO(数据传输对象),在web上传递。   




三、DAO:data access object 数据访问对象,此对象用于访问数据库。通常和PO结合使用,DAO中包含了各种数据库的操作方法。
通过它的方法,结合PO对数据库进行相关的操作。   




四、BO:business object 业务对象,封装业务逻辑的java对象,通过调用DAO方法,结合PO,VO进行业务操作。   




五、POJO:plain ordinary java object 简单无规则java对象,我个人觉得它和其他不是一个层面上的东西,VO和PO应该都属于它。    




O/R Mapping 是 Object Relational Mapping(对象关系映射)的缩写。
通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据。
在O/R Mapping的世界里,有两个基本的也是重要的东东需要了解,即VO,PO。    VO,值对象(Value Object),PO,持久对象(Persisent Object),它们是由一组属性和属性的get和set方法组成。
从结构上看,它们并没有什么不同的地方。
但从其意义和本质上来看是完全不同的。  




1.VO是用new关键字创建,由GC回收的。    PO则是向数据库中添加新数据时创建,删除数据库中数据时削除的。
并且它只能存活在一个数据库连接中,断开连接即被销毁。  




2.VO是值对象,精确点讲它是业务对象,是存活在业务层的,是业务逻辑使用的,它存活的目的就是为数据提供一个生存的地方。    
PO则是有状态的,每个属性代表其当前的状态。它是物理数据的对象表示。
使用它,可以使我们的程序与物理数据解耦,并且可以简化对象数据与物理数据之间的转换。  




3.VO的属性是根据当前业务的不同而不同的,也就是说,它的每一个属性都一一对应当前业务逻辑所需要的数据的名称。    
PO的属性是跟数据库表的字段一一对应的。   PO对象需要实现序列化接口。












——————————————————————————————————————————————————————




Hibernate的生成周期:








刚new的时候,内存中有对象,数据库没有数据,属于新建状态
一调用save,,则变成持久状态
持久状态:对应的数据库有对应的行












get回来的对象就是持久状态的。
get回来直接set也会直接改掉数据库








session:一级缓存
调用了close则脱离session
clear:把session里面所有的对象全部清空,都变成游离状态
evict(对象):只清除指定对象








面试问题:被Hibernate管理的对象有哪几个状态?
临时状态
new之后
持久状态
调用了save,或get
游离状态
clear/evict之后












Spring最核心功能::IoC:管理对象
AOP:管理行为
Spring在管理对象的基础上还做了其他的扩展




————————————————————————————




导spring-orm后spring和hibernate有关的包都导进来的
orm:Object Relation Mapping








——————————————————————————
HibernateTemplate:底层封装了session,比session更简洁,把事务等封装了
HT也提供了CRUD
HT天生给dao使用的












只要涉及数据库操作,都会有事务管理








HibernateTemplate能够自动关连接,封装了事务
而session需要手动open,管理事务,手动close




一般都是在dao使用HT
如:




@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Resource  //@Autowired---->Spring Standar
private HibernateTemplate hibernateTemplate;

public int addUser(User user)








HT是spring提供的




——————————————————————————————
NoSuchBean 'userDao' defined
注意是否组件扫描没加或者扫描路径未指定




<context:component-scan 
base-package="cn.tedu.dao"/>








————————————————————————————————————




hibernate执行sql是batch执行的,如删除2个user,
sql在控制台输出可见是先执行两次select,然后再两次delete
delete是最后commit才生效的








如果不是maven项目,maven导的包放到项目的lib里面








面试问题
hashmap有什么好处?
集合/数组?




————————————————————————————————————————————
poi:




实际上很多时候我们只利用POI来操作Excel。甚至只用xls这一种格式。
那么就没有必要全部都导入了。具体应该使用哪个JAR包请参考以下内容:




Component Application type Maven artifactId Notes
POIFS OLE2 Filesystem poi Required to work with OLE2 / POIFS based files
HPSF OLE2 Property Sets poi  
HSSF Excel XLS poi For HSSF only, if common SS is needed see below
HSLF PowerPoint PPT poi-scratchpad  
HWPF Word DOC poi-scratchpad  
HDGF Visio VSD poi-scratchpad  
HPBF Publisher PUB poi-scratchpad  
HSMF Outlook MSG poi-scratchpad  
OpenXML4J OOXML poi-ooxml plus one of
poi-ooxml-schemas, ooxml-schemas Only one schemas jar is needed, see below for differences
XSSF Excel XLSX poi-ooxml  
XSLF PowerPoint PPTX poi-ooxml  
XWPF Word DOCX poi-ooxml  
Common SS Excel XLS and XLSX poi-ooxml WorkbookFactory and friends all require poi-ooxml, not just core poi




————————————————————————————————————————————————————




读取properties




properties p = new properties();
try{
p.load(JdbcDao.class.getResoureceAsStream("config.properties"))




}




//HQL表中的属性换成了这个列。写*号的时候可以省略
//select * from cn_user where cn_user_name=?
// from User where name=?




mybatis的sql可以在控制台测试,而hibernate不行,hql需要hibernate下测试






hql工作的时候






responsebody是spring-mvc的








可以去tomcat查看已经编译的文件,如apache-tomcat-7.0.67/wtpwebapps/ssh/WEB-INF/classes的struts.xml
配置没错,服务器部署的时候出问题时,把服务器停止,右键clean
,然后在eclipse的菜单的project选择clean,则把整个项目重新编译




socket编程,就像DMS一样
DMS:服务器多线程接收,客户端单线程保存,
服务器:生产者/消费者模型




————————————————————————————————————————————




用map封装结果






UserAction 内两个方法都有try/catch,可以放到拦截器




strut2往web上解决了mvc,使开发更规范




spring框架和mvc的关系:




mvc不是3层结构。
mvc和3层结构没有任何关系,但是有交集
M:业务+数据层
v:浏览器
C:控制器(主/子控制器)




springMVC:
M:数据的存储
V:跟用户打交道
C:接收请求,访问模型,数据收回再发给V












三层结构:
表现层:用户看见的,包含了MVC中的V和C
业务层:MVC的M的一半
数据层:MVC的M的一半




springMVC/struct2:三层结构中的表现层
业务层:自己写的
持久层:mybatis/hibernate




spring不管业务层,而是管理bean,加aop,扩展代码




举例:
商品结算:数据来自哪里?
商品单价,数量,余额。从DB获取
账户钱消,商品数量消,物流发货,写到DB
service添加算法完成结算。外来的参数从控制器获取

一个功能怎么做?先想数据在哪里?
1.数据来自哪里?
2.算法实现
3.如何展现给浏览器






软件采用三层结构
表现层:使用SpringMVC框架 (或struts)
持久层:使用Mybatis(或hibernate)
整体的耦合使用spring

如何修改能够比较string类型的大小

10-23
ElemType的类型是指所有类型还是指基础类型比如int double char bool等 可以指代为string类吗? 以下是题目 顺序表ADT模板简单应用算法设计:在给定的顺序表中找出最大和最小的元素 作者: 冯向阳时间限制: 1S章节: DS:线性表 问题描述 : 目的:使用C++模板设计顺序表的抽象数据类型(ADT)。并在此基础上,使用顺序表ADT的基本操作,设计并实现顺序表的简单算法设计。 内容:(1)请使用模板设计顺序表的抽象数据类型。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。参考网盘中的ADT原型文件。) (2)ADT的简单应用:使用该ADT设计并实现顺序表应用场合的一些简单算法设计。 应用8:试设计一个算法,找出顺序表A中最大和最小的元素(输出在屏幕上),并保持原顺序表不变。 参考函数原型: template<class ElemType> bool Search_Max_Min( SqList<ElemType> &A, ElemType &max, ElemType &min ); 输入说明 : 第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string) 第二行:顺序表A的长度 第三行:顺序表A的数据元素(数据元素之间以空格分隔) 输出说明 : 如第一行输入值为0、1、2、3之外的值,直接输出“err” 否则: 第一行:顺序表A的遍历结果 第二行:最大值max 第三行:最小值min 代码 #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string> #include <string.h> using namespace std; template<class ElemType> class SqList { private: ElemType *elem; // 存储空间基址 int length; // 当前长度 int listsize; // 允许的最大存储容量(以sizeof(ElemType)为单位 public: //初始化顺序表 SqList(int ms = 20) { listsize=ms; elem=(ElemType*)malloc(listsize*sizeof(ElemType)); //******************************** length=0; } //删除顺序表 ~SqList(){delete [] elem;} //将顺序表置为空表 void ListClear( ){length = 0;} //返回顺序表的长度 int ListLength() const {return length;} //设置顺序表的长度 void SetListLength(int len) { listsize=len; } //判断顺序表是否为空表 bool ListEmpty() const { if(length==0) return true; else return false; } //判断顺序表是否为满表 bool ListFull() const { if(length==listsize) return true; else return false; } //用e返回顺序表的第i个元素 ElemType GetElem(int i) const { return elem[i]; } //用e设置顺序表的第i个元素 bool SetElem(int i, ElemType e) { if(i<0||i>length) return false; else elem[i-1]=e; return true; } //在顺序表的第pos个位置之前插入e元素 bool ListInsert(int pos,ElemType e,int n) { if(pos<0||pos>length) return false ; if(length>=listsize) return false ; if(n!=3) {for(int i=length;i>pos;i--) { elem[i]=elem[i-1]; } elem[pos]=e;} else{ for(int i=length;i>pos;i--) { elem[i].assign(elem[i-1]); } elem[pos].assign(e); } length++; return true; } //删除顺序表的第pos个位置的元素 bool ListDelete(int pos) { if(pos<0||pos>=length) return false ; for(int i=pos+1;i<length;i++) { elem[i-1]=elem[i]; } length--; return true; } //compare函数,用来判断a和b是否相等 bool compare(ElemType a, ElemType *b) { if(a==b) return true; else return false; } //按指定条件查找 int LocateElem(ElemType e) { int i; for(i=0;i<length;i++) { if(elem[i]==e) break; } if (i==length) return -1; else return i; } //逆置顺序表 void Invert(int a, int b) { ElemType w; for(int i=a-1;i<b;i++) { w=elem[i]; elem[i]=elem[b+a-2-i]; elem[b+a-2-i]=w; } } //返回线性表给定数据元素的前驱数据元素的值 bool PriorElem(ElemType cur_e, ElemType &pri_e) { int i; for( i=0;i<length;i++) { if(elem[i]==cur_e) break; } if(i==length||i==0) return false ; else { pri_e=elem[i-1]; return pri_e; } } //返回线性表给定数据元素的后继数据元素的值 bool NextElem(ElemType cur_e, ElemType &nex_e) { int i; for( i=0;i<length;i++) { if(elem[i]==cur_e) break; } if(i==length) return false ; else { nex_e=elem[i+1]; return nex_e; } } //销毁线性表 void ListDestroy() { free(elem); } //遍历顺序表 const void ListTraverse() { for(int i=0;i<length;i++) { cout<<elem[i]<<" "; } cout<<endl; } void change(int m) { ElemType w; int i; int n=length-m; for(i=0;i<length/2;i++) { w=elem[i]; elem[i]=elem[length-i-1]; elem[length-1-i]=w; } for(i=0;i<n/2;i++) { w=elem[i]; elem[i]=elem[n-1-i]; elem[n-1-i]=w; } for(i=n;i<n+m/2;i++) { w=elem[i]; elem[i]=elem[length-1-i+n]; elem[length-1-i+n]=w; } } void Purge_Sq() { int i,j; for(i=0;i<length;i++) { for(j=i+1;j<length;j++) { if(elem[i]==elem[j]) ListDelete(j); } } } bool Search_Max_Min(ElemType &max, ElemType &min ,int n) { int i; ElemType temp1=elem[0],temp2=elem[0]; if(n==0||n==1||n==2) {for(i=1;i<length;i++) { if(elem[i]>=temp1) temp1=elem[i]; if(elem[i]<=temp2) temp2=elem[i]; }} else { for(i=1;i<length;i++) { if(elem[i]>temp1) temp1=elem[i]; if(elem[i]<temp2) temp2=elem[i]; } } max=temp1;min=temp2; return true; } }; int main() { int n; cin>>n; if(n!=0&&n!=1&&n!=2&&n!=3) { cout<<"err"<<endl; return 0; } else{ int ms,i; cin>>ms; if(n==0) {SqList <int>d(ms); int md; for(i=0;i<ms;i++) { cin>>md; d.ListInsert(i,md,n); } int max,min; d.ListTraverse(); d.Search_Max_Min(max,min,n); cout<<max<<endl<<min<<endl; } if(n==1) {SqList <double>d(ms); double md; for( i=0;i<ms;i++) { cin>>md; d.ListInsert(i,md,n); } double max,min; d.ListTraverse(); d.Search_Max_Min(max,min,n); cout<<max<<endl<<min<<endl;} if(n==2) {SqList <char>d(ms); char md; for( i=0;i<ms;i++) { cin>>md; d.ListInsert(i,md,n); } char max,min; d.ListTraverse(); d.Search_Max_Min(max,min,n);cout<<max<<endl<<min<<endl;} if(n==3) {SqList <string>d(ms); string md; for( i=0;i<ms;i++) { cin>>md; d.ListInsert(i,md,n); } string max,min; d.ListTraverse(); d.Search_Max_Min(max,min,n);} return 0; } }
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值