前端转Java,从0到1学习教程

Java后端开发从0到1学习教程

学习目标

让前端开发者(0Java基础)能够:

  1. 理解Java后端开发基础概念
  2. 掌握Spring Boot框架使用
  3. 能够独立开发REST API接口
  4. 理解数据库操作和ORM框架
  5. 能够维护和扩展现有项目

ps:本人前端菜鸡一枚,最近在学习java,本文乃学习过程中记录的笔记,可能有所错误,欢迎大佬们指正!

第一阶段:Java基础入门

1:Java环境搭建

1.1 安装JDK
bash 复制代码
# 下载JDK 8或11
# 官网:https://www.oracle.com/java/technologies/downloads/

# 安装后验证
java -version
javac -version
1.2 配置环境变量
bash 复制代码
# Windows系统
JAVA_HOME=C:\Program Files\Java\jdk-11.0.16
PATH=%JAVA_HOME%\bin;%PATH%

# 验证配置
echo %JAVA_HOME%
1.3 第一个Java程序
java 复制代码
// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, Java!");
        System.out.println("欢迎来到Java世界!");
    }
}

// 编译和运行
// javac HelloWorld.java
// java -cp . HelloWorld

前端对比理解

javascript 复制代码
// JavaScript
console.log("Hello, JavaScript!");

// Java
System.out.println("Hello, Java!");

2:Java基本语法

2.1 变量和数据类型
基本类型
1.整数类型:

byte、short、int、long

java 复制代码
 byte b = 127;           // 8位,-128到127
 short s = 32767;        // 16位,-32768到32767
 int i = 2147483647;     // 32位,-2^31到2^31-1
 long l = 9223372036854775807L;  // 64位,需要L后缀
 
/**
Java:4种整数类型,需要明确指定类型
JavaScript:只有Number类型,自动处理整数和浮点数
**/
2.浮点数类型

float、double

java 复制代码
float f = 3.14f;        // 32位,需要f后缀
double d = 3.141592653589793;  // 64位,默认类型

/**
Java:float和double两种精度
JavaScript:只有Number类型,但精度问题相同
**/
3.字符类型

char

java 复制代码
char c = 'A';           // 16位Unicode字符
char chinese = '中';     // 支持中文字符

/**
varchar是数据库的类型,不是java的类型
Java:有专门的char类型
JavaScript:字符就是单字符字符串
**/
4.布尔类型

boolean

java 复制代码
 boolean b1 = true;
 boolean b2 = false;
 
 /**
 Java:只有true和false
 JavaScript:有"假值"概念(0、""、null、undefined、NaN)
 **/
5.字符串类型

string

java 复制代码
String str1 = "Hello";           // 字符串字面量
String str2 = new String("World"); // 对象创建
String str3 = str1 + " " + str2;  // 字符串拼接

 /**
 Java:String是不可变对象,对象创建后,其内部状态不能被修改。
 可以理解为:声明一个string之后,如果对这个string进行重新赋值了,那就相当于重新创建了一个string,而不是对原始的string进行修改。
 示例:
 String str = "Hello";
 System.out.println("第一次赋值 - 内存地址: " + System.identityHashCode(str));
        
 // 重新赋值 = 创建新String对象
 str = "World";
 System.out.println("重新赋值后 - 内存地址: " + System.identityHashCode(str));
        
 // 再次重新赋值 = 又创建新String对象
 str = "Java";
 System.out.println("再次赋值后 - 内存地址: " + System.identityHashCode(str));
 
 运行结果:
 第一次赋值 - 内存地址: 1234567890
重新赋值后 - 内存地址: 9876543210  // 地址变了!
再次赋值后 - 内存地址: 5555555555  // 地址又变了!
可以看到每次赋值后,内存地址发生了变化
JavaScript:字符串也是不可变的,但可以重新赋值
 **/

String不可变设计的好处:

  1. 线程安全:多线程环境下安全使用
  2. 性能优化:字符串常量池共享内存
  3. 安全性:作为HashMap key安全,密码传递安全
  4. 简化设计:无需同步,避免副作用
  5. 函数式支持:支持链式调用
  6. 内存效率:相同字符串共享内存
  7. 易于维护:代码更可预测,bug更少

字符串类型常用函数

功能 Java JavaScript
长度 length() length
去空格 trim() trim()
转大写 toUpperCase() toUpperCase()
转小写 toLowerCase() toLowerCase()
子字符串 substring(start, end) substring(start, end)
替换 replace(old, new) replace(old, new)
分割 split(delimiter) split(delimiter)
包含检查 contains(str) includes(str)
开始检查 startsWith(str) startsWith(str)
结束检查 endsWith(str) endsWith(str)
比较 equals(str) ===
引用类型
1.数组类型
java 复制代码
//java
int[] numbers = {1, 2, 3, 4, 5};           // 一维数组
String[] names = new String[3];             // 声明数组
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
        
// 二维数组
int[][] matrix = {{1, 2}, {3, 4}};


//javascript
let numbers = [1, 2, 3, 4, 5];           // 数组字面量
let names = new Array(3);                 // 声明数组
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";

// 二维数组
let matrix = [[1, 2], [3, 4]];



/**
Java:数组长度固定,类型固定
JavaScript:数组长度可变,类型可变

**/
2.对象类型
java 复制代码
//定义类
class Person {
    private String name;
    private int age;
    
    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
}


public class ObjectTypes {
    public static void main(String[] args) {
        // 创建对象
        Person person = new Person("张三", 25);
    }
}

/**
Java:需要先定义类,再创建对象
JavaScript:可以直接创建对象,动态添加属性
**/
3.类型转换
java 复制代码
public class TypeConversion {
    public static void main(String[] args) {
        // 自动类型转换(隐式转换)
        int i = 100;
        long l = i;        // int自动转换为long
        double d = i;      // int自动转换为double
        
        // 强制类型转换(显式转换)
        double d2 = 3.14;
        int i2 = (int) d2;  // double强制转换为int,结果为3
        
        // 字符串转换
        String str = "123";
        int num = Integer.parseInt(str);  // 字符串转整数
        String str2 = String.valueOf(num); // 整数转字符串
        
        System.out.println("i2: " + i2);
        System.out.println("num: " + num);
        System.out.println("str2: " + str2);
    }
}

/**
Java:类型转换更严格,需要显式转换
JavaScript:类型转换更灵活,有隐式转换
**/
4. List集合类型

4.1 ArrayList(最常用)

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        // 创建ArrayList
        List<String> list = new ArrayList<>();

        // 添加元素
        list.add("张三");
        list.add("李四");
        list.add("王五");

        // 访问元素
        System.out.println("列表: " + list);
        System.out.println("第一个元素: " + list.get(0));
        System.out.println("列表大小: " + list.size());

        // 遍历
        for (String name : list) {
            System.out.println("姓名: " + name);
        }

    }
}


/**
运行结果:
列表: [张三, 李四, 王五]
第一个元素: 张三
列表大小: 3
姓名: 张三
姓名: 李四
姓名: 王五
**/

特点:基于数组,随机访问快,插入删除慢

list常用方法

功能 Java List JavaScript Array
添加元素 add(item) push(item)
插入元素 add(index, item) splice(index, 0, item)
获取元素 get(index) array[index]
获取大小 size() length
包含检查 contains(item) includes(item)
查找索引 indexOf(item) indexOf(item)
删除元素 remove(item) splice(index, 1)
清空 clear() length = 0
是否为空 isEmpty() length === 0
遍历 for-each forEach()

4.2 LinkedList

java 复制代码
import java.util.LinkedList;
import java.util.List;

public class LinkedListExample {
    public static void main(String[] args) {
        // 创建LinkedList
        List<String> list = new LinkedList<>();
        
        // 添加元素
        list.add("张三");
        list.add("李四");
        list.add("王五");
        
        // 在指定位置插入
        list.add(1, "赵六");
        
        // 删除元素
        list.remove("李四");
        
        
        System.out.println("列表内容: " + list);
    }
}

/**
运行结果:
列表内容: [张三, 赵六, 王五]
**/

特点:基于链表,插入删除快,随机访问慢

4.3 Vector

java 复制代码
import java.util.Vector;

public class VectorExample {
    public static void main(String[] args) {
        // 创建Vector
        Vector<String> vector = new Vector<>();
        
        // 添加元素
        vector.add("张三");
        vector.add("李四");
        
        // 特点:线程安全,但性能较低
        System.out.println("Vector内容: " + vector);
    }
}


/**
运行结果:
Vector内容: [张三, 李四]
**/
类型 特点 适用场景 性能
ArrayList 基于数组,随机访问快 频繁查询,少量插入删除 查询O(1),插入O(n)
LinkedList 基于链表,插入删除快 频繁插入删除,少量查询 查询O(n),插入O(1)
Vector 线程安全 多线程环境 性能较低
5.Map集合类型

5.1HashMap(最常用)

java 复制代码
import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建HashMap
        Map<String, Integer> map = new HashMap<>();
        
        // 添加键值对
        map.put("张三", 25);
        map.put("李四", 30);
        map.put("王五", 28);
        
        // 获取值
        Integer age = map.get("张三");
        System.out.println("张三的年龄: " + age);
        
        // 检查键是否存在
        boolean hasKey = map.containsKey("李四");
        System.out.println("是否有李四: " + hasKey);
        
        // 遍历
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        
    }
}


/**
张三的年龄: 25
是否有李四: true
李四: 30
张三: 25
王五: 28

**/


//前端JavaScript对比

// JavaScript对象
let map = {};
map["张三"] = 25;
map["李四"] = 30;
map["王五"] = 28;

console.log("张三的年龄:", map["张三"]);
console.log("是否有李四:", "李四" in map);

Object.keys(map).forEach(key => {
    console.log(key + ": " + map[key]);
});

特点:无序,允许null键值,性能好

map常用函数方法

功能 Java Map JavaScript Object
添加键值对 put(key, value) obj[key] = value
获取值 get(key) obj[key]
获取大小 size() Object.keys(obj).length
检查键 containsKey(key) key in obj
检查值 containsValue(value) Object.values(obj).includes(value)
删除键值对 remove(key) delete obj[key]
清空 clear() obj = {}
是否为空 isEmpty() Object.keys(obj).length === 0
遍历键 keySet() Object.keys(obj)
遍历值 values() Object.values(obj)
遍历键值对 entrySet() Object.entries(obj)

5.2 LinkedHashMap(保持插入顺序)

java 复制代码
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        // 创建LinkedHashMap
        Map<String, Integer> map = new LinkedHashMap<>();
        
        // 添加元素
        map.put("张三", 25);
        map.put("李四", 30);
        map.put("王五", 28);
        
        // 遍历(保持插入顺序)
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        
    }
}

/**
运行结果:
张三: 25
李四: 30
王五: 28
**/

特点:保持插入顺序,性能略低于HashMap

5.3 TreeMap(有序)

java 复制代码
import java.util.TreeMap;
import java.util.Map;

public class TreeMapExample {
    public static void main(String[] args) {
        // 创建TreeMap
        Map<String, Integer> map = new TreeMap<>();
        
        // 添加元素
        map.put("张三", 25);
        map.put("李四", 30);
        map.put("王五", 28);
        
        // 遍历(按键排序)
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
       
    }
}

/**
运行结果:
张三: 25
李四: 30
王五: 28
**/

特点:按键排序,性能低于HashMap

类型 特点 适用场景 性能
HashMap 无序,性能好 一般用途 O(1)
LinkedHashMap 保持插入顺序 需要保持顺序 O(1)
TreeMap 有序 需要排序 O(log n)
6.Set集合类型

6.1 HashSet(去重) (常用)

java 复制代码
import java.util.HashSet;
import java.util.Set;

public class HashSetExample {
    public static void main(String[] args) {
        // 创建HashSet
        Set<String> set = new HashSet<>();

        // 添加元素
        set.add("张三");
        set.add("李四");
        set.add("张三");  // 重复元素,不会添加

        System.out.println("set: " +set);
        // 检查元素是否存在
        boolean hasName = set.contains("张三");
        System.out.println("是否有张三: " + hasName);

        // 遍历
        for (String name : set) {
            System.out.println("姓名: " + name);
        }

    }
}

/**
运行结果:
set: [李四, 张三]
是否有张三: true
姓名: 李四
姓名: 张三
**/

特点:去重,无序,性能好

set常用函数方法

功能 Java Set JavaScript Set
添加元素 add(item) add(item)
获取大小 size() size
包含检查 contains(item) has(item)
删除元素 remove(item) delete(item)
清空 clear() clear()
是否为空 isEmpty() size === 0
遍历 for-each forEach()
转数组 toArray() Array.from()

6.2 LinkedHashSet(去重+保持顺序)

java 复制代码
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetExample {
    public static void main(String[] args) {
        // 创建LinkedHashSet
        Set<String> set = new LinkedHashSet<>();
        
        // 添加元素
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三");  // 重复元素,不会添加
        
         System.out.println("set: " +set);
        // 遍历(保持插入顺序)
        for (String name : set) {
            System.out.println("姓名: " + name);
        }
    }
}

/**
运行结果:
set: [张三, 李四, 王五]
姓名: 张三
姓名: 李四
姓名: 王五
**/

特点:去重,保持插入顺序

6.3 TreeSet(去重+排序)

java 复制代码
import java.util.TreeSet;
import java.util.Set;

public class TreeSetExample {
    public static void main(String[] args) {
        // 创建TreeSet
        Set<String> set = new TreeSet<>();
        
        // 添加元素
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三");  // 重复元素,不会添加
        
         System.out.println("set: " +set);
        // 遍历(按字母排序)
        for (String name : set) {
            System.out.println("姓名: " + name);
        }
        
    }
}

/**
运行结果:
set: [张三, 李四, 王五]
姓名: 张三
姓名: 李四
姓名: 王五
**/

特点:去重,排序

类型 特点 适用场景 性能
HashSet 去重,无序 去重操作 O(1)
LinkedHashSet 去重,保持顺序 去重+保持顺序 O(1)
TreeSet 去重,排序 去重+排序 O(log n)
2.2 控制结构
java 复制代码
public class ControlStructures {
    public static void main(String[] args) {
        int score = 85;
        
        // if-else语句
        if (score >= 90) {
            System.out.println("优秀");
        } else if (score >= 80) {
            System.out.println("良好");
        } else if (score >= 70) {
            System.out.println("中等");
        } else {
            System.out.println("需要努力");
        }
        
        // for循环
        for (int i = 1; i <= 5; i++) {
            System.out.println("第" + i + "次循环");
        }
        
        // while循环
        int count = 0;
        while (count < 3) {
            System.out.println("计数: " + count);
            count++;
        }
    }
}

前端对比理解

javascript 复制代码
// JavaScript
let score = 85;

if (score >= 90) {
    console.log("优秀");
} else if (score >= 80) {
    console.log("良好");
} else {
    console.log("需要努力");
}

for (let i = 1; i <= 5; i++) {
    console.log(`第${i}次循环`);
}

3:面向对象编程

3.1 类和对象

前端在数据类型里已经讲过java的对象需先定义类,再创建对象

java 复制代码
// 用户类
public class User {
    // 属性(类似Vue3的data)
    private String name;
    private Integer age;
    private String email;
    
    // 构造函数
    public User(String name, Integer age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    
    // Getter方法(类似Vue3的computed)
    public String getName() {
        return name;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public String getEmail() {
        return email;
    }
    
    // Setter方法
    public void setName(String name) {
        this.name = name;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    // 方法(类似Vue3的methods)
    public void displayInfo() {
        System.out.println("姓名: " + name + ", 年龄: " + age + ", 邮箱: " + email);
    }
    
    public boolean isAdult() {
        return age >= 18;
    }
}

// 测试类
public class UserTest {
    public static void main(String[] args) {
        // 创建用户对象
        User user1 = new User("张三", 25, "zhangsan@example.com");
        User user2 = new User("李四", 17, "lisi@example.com");
        
        // 调用方法
        user1.displayInfo();
        user2.displayInfo();
        
        // 判断是否成年
        System.out.println("张三是否成年: " + user1.isAdult());
        System.out.println("李四是否成年: " + user2.isAdult());
    }
}

前端对比理解

javascript 复制代码
// Vue3
export default {
  data() {
    return {
      name: '',
      age: 0,
      email: ''
    }
  },
  computed: {
    isAdult() {
      return this.age >= 18
    }
  },
  methods: {
    displayInfo() {
      console.log(`姓名: ${this.name}, 年龄: ${this.age}, 邮箱: ${this.email}`)
    }
  }
}
3.2 抽象类和接口

在了解抽象类时,我们先了解一下抽象类、抽象方法、具体实现类、具体方法的含义与区别。

抽象类:

就像是一个"半成品模板",它定义了基本的结构,但有些部分还没有完成。

想象你要开一家餐厅:

  • 抽象类 = 餐厅的基本框架(有厨房、有桌椅、有收银台)

  • 具体实现类 = 具体的餐厅(中餐厅、西餐厅、快餐店)

特点:

  1. 可以有具体方法:已经实现的功能
  2. 可以有抽象方法:待实现的功能
  3. 可以有属性:餐厅的基本设施
  4. 不能直接创建对象:不能直接生产菜品
  5. 单继承:一个餐厅只能继承一个母公司
java 复制代码
// 抽象类:餐厅的基本框架
public abstract class Restaurant {
    protected String name;
    protected String address;
    
    // 构造函数
    public Restaurant(String name, String address) {
        this.name = name;
        this.address = address;
    }
    
    // 具体方法:所有餐厅都有的功能
    public void welcome() {
        System.out.println("欢迎光临" + name + "!");
    }
    
    public void showMenu() {
        System.out.println("这是" + name + "的菜单");
    }
    
    public void takeOrder() {
        System.out.println("正在为您点餐...");
    }
    
    // 抽象方法:每个餐厅都不同,需要子类自己实现
    public abstract void cook();        // 做菜方式不同
    public abstract void serve();       // 服务方式不同
    public abstract String getCuisine(); // 菜系不同
}
抽象方法:

抽象方法就像是一个"待办事项",告诉子类"你必须做这件事,但具体怎么做你自己决定"

特点
  • 只有方法声明,没有方法体

  • 用abstract关键字修饰

  • 必须在抽象类中

  • 子类必须实现(重写)这些方法

java 复制代码
// 抽象方法示例
public abstract class Vehicle {
    protected String brand;
    
    // 具体方法:所有车辆都有的功能
    public void start() {
        System.out.println("车辆启动");
    }
    
    // 抽象方法:每个车辆都不同,需要子类自己实现
    public abstract void drive();    // 驾驶方式不同
    public abstract void stop();    // 停车方式不同
    public abstract String getType(); // 车辆类型不同
}
具体实现类:

具体实现类就像是一个"完整的成品",它继承了抽象类的框架,并实现了所有抽象方法。

java 复制代码
// 具体实现类1:中餐厅
public class ChineseRestaurant extends Restaurant {
    public ChineseRestaurant(String name, String address) {
        super(name, address);
    }
    
    // 实现抽象方法
    @Override
    public void cook() {
        System.out.println("用中式方法烹饪:炒、煮、蒸、炸");
    }
    
    @Override
    public void serve() {
        System.out.println("用筷子和碗为您服务");
    }
    
    @Override
    public String getCuisine() {
        return "中式菜系";
    }
    
    // 具体实现类特有的方法
    public void serveTea() {
        System.out.println("为您奉上热茶");
    }
}

// 具体实现类2:西餐厅
public class WesternRestaurant extends Restaurant {
    public WesternRestaurant(String name, String address) {
        super(name, address);
    }
    
    // 实现抽象方法
    @Override
    public void cook() {
        System.out.println("用西式方法烹饪:烤、煎、焗、煮");
    }
    
    @Override
    public void serve() {
        System.out.println("用刀叉和盘子为您服务");
    }
    
    @Override
    public String getCuisine() {
        return "西式菜系";
    }
    
    // 具体实现类特有的方法
    public void serveWine() {
        System.out.println("为您推荐红酒");
    }
}
具体方法:

具体方法就像是一个"已经完成的功能",有具体的实现代码,可以直接使用。

java 复制代码
// 具体方法示例
public abstract class Animal {
    protected String name;
    protected int age;
    
    // 具体方法:所有动物都有的功能,已经实现好了
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
    
    public void eat() {
        System.out.println(name + "正在吃东西");
    }
    
    public void displayInfo() {
        System.out.println("名字:" + name + ",年龄:" + age);
    }
    
    // 抽象方法:每个动物都不同,需要子类自己实现
    public abstract void makeSound();
    public abstract void move();
}

// 具体实现类
public class Dog extends Animal {
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 实现抽象方法
    @Override
    public void makeSound() {
        System.out.println(name + "汪汪叫");
    }
    
    @Override
    public void move() {
        System.out.println(name + "在跑步");
    }
    
    // 具体方法:子类特有的功能
    public void fetch() {
        System.out.println(name + "在捡球");
    }
}
接口:

接口就像是一个"标准规范",它定义了"必须做什么",但不关心"怎么做"。

想象你要开一家餐厅:

  • 接口 = 餐厅的标准规范(必须有点餐、上菜、结账功能)

  • 具体实现类 = 具体的餐厅(中餐厅、西餐厅、快餐店

特点:

  1. 只能有抽象方法:只有规范,没有实现

  2. 不能有属性:只有方法声明

  3. 不能直接创建对象:不能直接开餐厅

  4. 多实现:一个餐厅可以实现多个规范

  5. 所有方法都是public:规范是公开的

java 复制代码
// 接口:餐厅标准规范
public interface Restaurant {
    // 抽象方法:每个餐厅都必须实现
    void takeOrder();    // 点餐
    void serveFood();    // 上菜
    void collectPayment(); // 结账
    String getCuisine(); // 获取菜系
}

// 接口:外卖服务规范
public interface DeliveryService {
    void prepareDelivery(); // 准备外卖
    void deliverFood();     // 送餐
    double calculateDeliveryFee(); // 计算配送费
}

// 接口:会员服务规范
public interface MembershipService {
    void registerMember();  // 注册会员
    void giveDiscount();    // 给折扣
    void sendPromotion();   // 发送促销信息
}
特性 抽象类 接口
关键字 abstract class interface
继承/实现 extends implements
数量限制 单继承 多实现
方法类型 可以有具体方法和抽象方法 只能有抽象方法
属性 可以有属性 不能有属性
构造函数 可以有构造函数 不能有构造函数
访问修饰符 可以是任意修饰符 默认public
使用场景 有共同属性和行为的类 定义规范和行为契约

选择原则:

  1. 有共同属性 → 使用抽象类
  2. 需要多继承 → 使用接口
  3. 定义行为规范 → 使用接口
  4. 有共同实现 → 使用抽象类

通过抽象类和接口,我们可以:

  • 统一接口:所有实现类都有相同的方法

  • 灵活实现:每个实现类可以有不同的实现

  • 代码复用:共同的功能在抽象类中实现

  • 易于扩展:添加新类型只需要继承或实现

3.3 封装、继承和多态
封装
java 复制代码
public class BankAccount {
    // 私有属性,外部不能直接访问
    private String accountNumber;
    private double balance;
    private String ownerName;
    
    // 构造函数
    public BankAccount(String accountNumber, String ownerName, double initialBalance) {
        this.accountNumber = accountNumber;
        this.ownerName = ownerName;
        this.balance = initialBalance;
    }
    
    // 公共方法,提供受控的访问
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存款成功,当前余额:" + balance);
        } else {
            System.out.println("存款金额必须大于0");
        }
    }
    
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取款成功,当前余额:" + balance);
        } else {
            System.out.println("取款失败:金额无效或余额不足");
        }
    }
    
    public double getBalance() {
        return balance;
    }
    
    public String getAccountNumber() {
        return accountNumber;
    }
    
    public String getOwnerName() {
        return ownerName;
    }
    
    // 私有方法,只能在类内部使用
    private void logTransaction(String type, double amount) {
        System.out.println("交易记录:" + type + " " + amount + "元");
    }
}

// 使用封装的类
public class BankTest {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("123456789", "张三", 1000.0);
        
        // 只能通过公共方法访问
        account.deposit(500.0);
        account.withdraw(200.0);
        
        // 不能直接访问私有属性
        // account.balance = 10000;  // 编译错误!
        
        // 只能通过getter获取余额
        System.out.println("当前余额:" + account.getBalance());
    }
}

/**
private 定义私有属性、方法,类似于JavaScript里的闭包
public 定义公共属性、方法 

**/

上述如果用JavaScript实现

JavaScript 复制代码
// JavaScript中的封装(使用闭包)
function BankAccount(accountNumber, ownerName, initialBalance) {
    // 私有变量
    let balance = initialBalance;
    let accountNum = accountNumber;
    let owner = ownerName;
    
    // 公共方法
    this.deposit = function(amount) {
        if (amount > 0) {
            balance += amount;
            console.log(`存款成功,当前余额:${balance}`);
        } else {
            console.log("存款金额必须大于0");
        }
    };
    
    this.withdraw = function(amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            console.log(`取款成功,当前余额:${balance}`);
        } else {
            console.log("取款失败:金额无效或余额不足");
        }
    };
    
    this.getBalance = function() {
        return balance;
    };
    
    this.getAccountNumber = function() {
        return accountNum;
    };
    
    this.getOwnerName = function() {
        return owner;
    };
    
    // 私有方法
    function logTransaction(type, amount) {
        console.log(`交易记录:${type} ${amount}元`);
    }
}

// 使用封装的类
let account = new BankAccount("123456789", "张三", 1000.0);

account.deposit(500.0);
account.withdraw(200.0);

// 不能直接访问私有变量
// console.log(account.balance);  // undefined

console.log("当前余额:" + account.getBalance());
继承
java 复制代码
// 父类
public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void eat() {
        System.out.println(name + "正在吃东西");
    }
    
    public void sleep() {
        System.out.println(name + "正在睡觉");
    }
}

// 子类
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    
    @Override
    public void eat() {
        System.out.println(name + "正在吃狗粮");
    }
    
    public void bark() {
        System.out.println(name + "正在汪汪叫");
    }
}

// 测试
public class AnimalTest {
    public static void main(String[] args) {
        Animal animal = new Animal("动物");
        Dog dog = new Dog("旺财");
        
        animal.eat();
        dog.eat();
        dog.bark();
    }
}

/**
使用extends关键字,super调用父类,同JavaScript里ES6的extends、super
extends关键字用于建立继承关系,表示"扩展"或"继承"。
super关键字用于访问父类的成员,包括:
调用父类构造函数
访问父类属性
调用父类方法
**/
多态

多态是指同一个接口可以有不同的实现,即一个对象可以表现出多种形态。

  • 一个接口,多种实现

  • 同一个方法调用,不同的行为

  • 运行时决定调用哪个方法

java 复制代码
// 抽象类
public abstract class Shape {
    protected String name;
    
    public Shape(String name) {
        this.name = name;
    }
    
    // 抽象方法
    public abstract double getArea();
    public abstract double getPerimeter();
    
    // 具体方法
    public void displayInfo() {
        System.out.println("形状:" + name);
        System.out.println("面积:" + getArea());
        System.out.println("周长:" + getPerimeter());
    }
}

// 具体实现类
public class Circle extends Shape {
    private double radius;
    
    public Circle(String name, double radius) {
        super(name);
        this.radius = radius;
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

public class Rectangle extends Shape {
    private double width;
    private double height;
    
    public Rectangle(String name, double width, double height) {
        super(name);
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double getArea() {
        return width * height;
    }
    
    @Override
    public double getPerimeter() {
        return 2 * (width + height);
    }
}

// 使用多态
public class ShapeTest {
    public static void main(String[] args) {
        // 多态:同一个接口,不同的实现
        Shape[] shapes = {
            new Circle("圆形", 5.0),
            new Rectangle("矩形", 4.0, 6.0),
            new Circle("大圆", 10.0)
        };
        
        // 多态调用
        for (Shape shape : shapes) {
            shape.displayInfo();  // 每个形状都有不同的实现
            System.out.println("---");
        }
        
        // 计算总面积
        double totalArea = 0;
        for (Shape shape : shapes) {
            totalArea += shape.getArea();
        }
        System.out.println("总面积:" + totalArea);
    }
}

上述用JavaScript实现

javascript 复制代码
// JavaScript中的多态
class Shape {
    constructor(name) {
        this.name = name;
    }
    
    getArea() {
        throw new Error("子类必须实现getArea方法");
    }
    
    getPerimeter() {
        throw new Error("子类必须实现getPerimeter方法");
    }
    
    displayInfo() {
        console.log(`形状:${this.name}`);
        console.log(`面积:${this.getArea()}`);
        console.log(`周长:${this.getPerimeter()}`);
    }
}

class Circle extends Shape {
    constructor(name, radius) {
        super(name);
        this.radius = radius;
    }
    
    getArea() {
        return Math.PI * this.radius * this.radius;
    }
    
    getPerimeter() {
        return 2 * Math.PI * this.radius;
    }
}

class Rectangle extends Shape {
    constructor(name, width, height) {
        super(name);
        this.width = width;
        this.height = height;
    }
    
    getArea() {
        return this.width * this.height;
    }
    
    getPerimeter() {
        return 2 * (this.width + this.height);
    }
}

// 使用多态
let shapes = [
    new Circle("圆形", 5.0),
    new Rectangle("矩形", 4.0, 6.0),
    new Circle("大圆", 10.0)
];

// 多态调用
shapes.forEach(shape => {
    shape.displayInfo();  // 每个形状都有不同的实现
    console.log("---");
});

// 计算总面积
let totalArea = shapes.reduce((sum, shape) => sum + shape.getArea(), 0);
console.log("总面积:" + totalArea);

多态的优势:

  1. 代码复用:减少重复代码
  2. 易于扩展:添加新类型不影响现有代码
  3. 接口统一:统一的接口,不同的实现
  4. 灵活性:运行时决定行为

4:异常处理

4.1 异常处理基础

就是try catch

java 复制代码
public class ExceptionExample {
    public static void main(String[] args) {
        try {
            // 可能抛出异常的代码
            int result = divide(10, 0);
            System.out.println("结果: " + result);
        } catch (ArithmeticException e) {
            // 捕获异常
            System.out.println("除零错误: " + e.getMessage());
        } catch (Exception e) {
            // 捕获其他异常
            System.out.println("其他错误: " + e.getMessage());
        } finally {
            // 无论是否异常都会执行
            System.out.println("程序执行完毕");
        }
    }
    
    public static int divide(int a, int b) throws ArithmeticException {
        if (b == 0) {
            throw new ArithmeticException("除数不能为零");
        }
        return a / b;
    }
}

前端对比理解

javascript 复制代码
// Vue3
export default {
  methods: {
    async divide(a, b) {
      try {
        if (b === 0) {
          throw new Error("除数不能为零");
        }
        return a / b;
      } catch (error) {
        console.error("错误:", error.message);
      } finally {
        console.log("程序执行完毕");
      }
    }
  }
}

第二阶段:Spring Boot框架入门

5:Spring Boot基础

可以将Spring Boot理解为一个同vue一样的框架,可以通过命令或者编译器直接创建项目。下面就以IDE编辑器创建一个简单的项目。

5.1 通过IDE创建第一个Spring Boot项目

创建一个简单的接口

创建后得到如下图所示的空项目

1. 添加Spring Boot依赖
xml 复制代码
<!-- 文件 pom.xml  -->

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>javademo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <java.version>8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Boot Web Starter - 提供Web开发所需的核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Test Starter - 提供测试相关依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <!-- Spring Boot Maven插件 - 用于打包和运行应用 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


<!-- 
pom.xml文件解释:
作用:这是Maven项目的配置文件,类似于Vue项目中的package.json
为什么需要:定义了项目依赖、构建配置等,让Maven知道需要下载哪些库
Spring Boot Parent:提供了Spring Boot的版本管理和默认配置
spring-boot-starter-web:包含了Web开发所需的所有依赖(如Spring MVC、Tomcat等)

-->
2.创建实体类

我们可以在src\main\java\org\example文件夹下创建一个文件夹dto文件夹,用来存放实体类文件

然后在dto文件夹里,创建请求实体类HelloRequest.java,用于接收前端传来的参数:

java 复制代码
//HelloRequest.java

package org.example.dto;

public class HelloRequest {
    private String name;

    /**
     * 有参构造函数
     * 方便创建对象时直接传入参数
     *
     * @param name 用户姓名
     */
    public HelloRequest(String name) {
        this.name = name;
    }

    /**
     * 获取用户姓名
     * Getter方法,用于获取name字段的值
     *
     * @return 用户姓名
     */
    public String getName() {
        return name;
    }

    /**
     * 设置用户姓名
     * Setter方法,用于设置name字段的值
     * Spring Boot会自动调用此方法来设置从JSON转换来的值
     *
     * @param name 用户姓名
     */
    public void setName(String name) {
        this.name = name;
    }
}


/**
为什么创建:用于定义API请求的数据结构,类似于Vue中的接口定义
类比Vue:就像Vue组件中的props定义,用于接收父组件传递的数据
主要功能:
定义请求参数的结构(name字段)
提供getter/setter方法供Spring Boot自动调用
包含构造函数用于创建对象实例
**/

然后在dto文件夹里,创建响应实体类 HelloResponse.java

java 复制代码
package org.example.dto;

/**
 * Hello接口返回实体类
 * 用于封装返回给前端的数据
 * 
 * 类比Vue中的响应数据对象
 * 例如:{ message: "hello 张三" }
 */
public class HelloResponse {
    
    /**
     * 返回消息
     * 包含问候语和用户姓名
     */
    private String message;
    
    /**
     * 状态码
     * 用于标识请求处理状态(可选字段)
     */
    private int code;
    
    /**
     * 简化的有参构造函数
     * 只传入消息,状态码默认为200(成功)
     * 
     * @param message 返回消息
     */
    public HelloResponse(String message) {
        this.message = message;
        this.code = 200; // 默认成功状态码
    }
  
}

 /**
     * 完整的有参构造函数
     * 传入消息和状态码
     *
     * @param message 返回消息
     * @param code 状态码
     */
    public HelloResponse(String message, int code) {
        this.message = message;
        this.code = code;
    }

    /**
     * 获取返回消息
     * @return 返回消息
     */
    public String getMessage() {
        return message;
    }

    /**
     * 设置返回消息
     * @param message 返回消息
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     * 获取状态码
     * @return 状态码
     */
    public int getCode() {
        return code;
    }

    /**
     * 设置状态码
     * @param code 状态码
     */
    public void setCode(int code) {
        this.code = code;
    }

/**
为什么创建:用于定义API返回的数据结构,确保返回数据格式统一
类比Vue:就像Vue组件中定义的数据结构,用于规范组件间的数据传递
主要功能:
定义返回数据的结构(message和code字段)
提供多种构造函数方便不同场景使用
包含getter/setter方法供Spring Boot自动序列化为JSON

**/
3.创建业务逻辑服务类

为了规范美观,我们先创建文件夹service,专门用来存放逻辑服务类,然后在service里新建服务类文件HelloService.java

java 复制代码
package org.example.service;

import org.example.dto.HelloRequest;
import org.example.dto.HelloResponse;
import org.springframework.stereotype.Service;

/**
 * Hello业务逻辑服务类
 * 处理Hello相关的业务逻辑
 * 
 * 类比Vue中的methods或computed,包含具体的业务处理逻辑
 * 类似于Vue组件中的方法,处理数据并返回结果
 */
@Service
public class HelloService {
    
    /**
     * 生成问候消息
     * 根据传入的姓名生成问候语
     * 
     * 类比Vue中的方法:
     * methods: {
     *   generateHelloMessage(name) {
     *     return `hello ${name}`;
     *   }
     * }
     * 
     * @param request 包含用户姓名的请求对象
     * @return 包含问候消息的响应对象
     */
    public HelloResponse generateHelloMessage(HelloRequest request) {
        // 获取用户姓名
        String name = request.getName();
        
        // 生成问候消息
        String message = "hello " + name;
        
        // 创建并返回响应对象
        return new HelloResponse(message, 200);
    }
    
}


/**
为什么创建:将业务逻辑从控制器中分离出来,遵循单一职责原则
类比Vue:就像Vue组件中的methods部分,包含具体的业务处理方法
@Service注解:告诉Spring这是一个服务类,需要被Spring容器管理
主要功能:
处理具体的业务逻辑(生成问候消息)
进行参数校验
提供多个重载方法增加灵活性

**/
4.创建控制器Controller

同逻辑服务类一样,先创建一个文件夹Controller专门存放控制器,然后创建控制器HelloController.java

java 复制代码
package org.example.controller;

import org.example.dto.HelloRequest;
import org.example.dto.HelloResponse;
import org.example.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * Hello控制器类
 * 处理HTTP请求,调用业务逻辑服务
 * 
 * 类比Vue中的路由处理函数或API调用函数
 * 类似于Vue Router中的路由处理,接收请求并返回响应
 */
@RestController
@RequestMapping("/hello")
public class HelloController {
    
    /**
     * 注入HelloService服务
     * 通过依赖注入获取业务逻辑服务实例
     * 
     * 类比Vue中的依赖注入或组件引用
     * 类似于Vue中通过props或inject获取其他组件的方法
     */
    @Autowired
    private HelloService helloService;
    
    /**
     * Hello接口
     * 处理GET请求,通过URL参数传递姓名
     * 
     * 类比Vue中的API调用:
     * async callHelloApi(name) {
     *   const response = await axios.get(`/hello/helloApi?name=${name}`);
     *   return response.data;
     * }
     * 
     * @param name 用户姓名(通过URL参数传递)
     * @return 包含问候消息的响应对象
     */
    @GetMapping("/helloApi")
    public HelloResponse helloApi(@RequestParam String name) {
        // 调用业务逻辑服务处理请求
        return helloService.generateHelloMessage(name);
    }
}



/**
为什么创建:作为Web层的入口,处理HTTP请求并调用业务逻辑
类比Vue:就像Vue Router中的路由处理函数,接收请求并返回响应
主要注解:
@RestController:标识这是一个REST控制器,自动将返回值转换为JSON
@RequestMapping("/hello"):定义基础路径为/hello
@PostMapping("/helloApi"):处理POST请求到/hello/helloApi
@GetMapping("/helloApi"):处理GET请求到/hello/helloApi
@RequestBody:将请求体JSON转换为Java对象
@RequestParam:获取URL参数

**/
5.更新主启动类

更新Main.java文件

java 复制代码
package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring Boot主启动类
 * 应用程序的入口点
 * 
 * 类比Vue中的main.js文件,是整个应用的启动入口
 * 类似于Vue项目的入口文件,负责启动整个应用
 */
@SpringBootApplication
public class Main {
    
    /**
     * 主方法
     * 启动Spring Boot应用程序
     * 
     * 类比Vue中的:
     * import { createApp } from 'vue'
     * import App from './App.vue'
     * createApp(App).mount('#app')
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 启动Spring Boot应用
        SpringApplication.run(Main.class, args);
        System.out.println("项目已启动成功");
    }
}

/**
为什么创建:这是Spring Boot应用的入口点,类似于Vue项目的main.js
@SpringBootApplication注解:标识这是一个Spring Boot应用,包含自动配置功能
类比Vue:就像Vue项目中的main.js文件,负责启动整个应用
现在让我检查是否有任何编译错误:

**/

通过IDE启动项目:

1.找到启动类Main.java;

2.右键 运行;

3.在控制台看到启动成功信息;

4.在浏览器地址栏访问 http://localhost:8080/hello/helloApi?name=张三

即可得到访问成功信息

至此我们已经成功创建了一个完整的Spring Boot项目

项目结构如下

javaDemo/

├── pom.xml # Maven配置文件(类比package.json)

├── API测试说明.md # 测试说明文档

└── src/main/java/org/example/

├── Main.java # 主启动类(类比main.js)

├── controller/

│ └── HelloController.java # 控制器(类比Vue Router)

├── service/

│ └── HelloService.java # 业务逻辑服务(类比Vue methods)

└── dto/

├── HelloRequest.java # 请求实体类(类比Vue props)

└── HelloResponse.java # 返回实体类(类比Vue data)

第三阶段:数据库和ORM框架

6:数据库

数据库就像一个超级大的Excel表格仓库,专门用来存储和管理数据

6.1 数据库的作用
  1. 持久化存储:数据不会因为程序关闭而丢失
  2. 数据共享:多个程序可以同时访问同一份数据
  3. 数据安全:提供权限控制和备份机制
  4. 高效查询:快速查找和筛选数据

下面以MySql数据库为例,讲解常用的数据类型与语法

6.2 数据类型
1. 数值类型

整数类型

sql 复制代码
-- MySQL整数类型
TINYINT     -- 1字节,范围:-128到127
SMALLINT    -- 2字节,范围:-32768到32767
MEDIUMINT   -- 3字节,范围:-8388608到8388607
INT         -- 4字节,范围:-2147483648到2147483647
BIGINT      -- 8字节,范围:-9223372036854775808到9223372036854775807

浮点数类型

sql 复制代码
-- MySQL浮点数类型
FLOAT       -- 单精度浮点数,4字节
DOUBLE      -- 双精度浮点数,8字节
DECIMAL     -- 精确小数,用于货币等精确计算
2. 字符串类型
sql 复制代码
-- MySQL字符串类型
CHAR(n)     -- 固定长度字符串,最多255字符
VARCHAR(n)  -- 可变长度字符串,最多65535字符
TEXT        -- 长文本,最多65535字符
LONGTEXT    -- 超长文本,最多4GB
3. 日期时间类型
sql 复制代码
-- MySQL日期时间类型
DATE        -- 日期,格式:YYYY-MM-DD
TIME        -- 时间,格式:HH:MM:SS
DATETIME    -- 日期时间,格式:YYYY-MM-DD HH:MM:SS
TIMESTAMP   -- 时间戳,自动更新
YEAR        -- 年份,格式:YYYY
4. 其他类型
sql 复制代码
-- MySQL其他类型
BOOLEAN     -- 布尔值,实际存储为TINYINT(1)
ENUM        -- 枚举类型
SET         -- 集合类型
JSON        -- JSON数据类型(MySQL 5.7+)
6.3 常用语法
1. 数据库操作

创建数据库

sql 复制代码
-- 创建数据库
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 使用数据库
USE mydb;

-- 删除数据库。。传说中的删库跑路的删库
DROP DATABASE mydb;

创建表

sql 复制代码
-- 创建用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    age INT DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
2. 数据操作(CRUD)

插入数据(CREATE)

sql 复制代码
-- 插入单条数据
INSERT INTO users (name, email, age) VALUES ('张三', 'zhangsan@example.com', 25);

-- 插入多条数据
INSERT INTO users (name, email, age) VALUES 
('李四', 'lisi@example.com', 30),
('王五', 'wangwu@example.com', 28);

查询数据(READ)

sql 复制代码
-- 查询所有数据
SELECT * FROM users;

-- 查询指定字段
SELECT id, name, email FROM users;

-- 条件查询
SELECT * FROM users WHERE age > 25;

-- 排序查询
SELECT * FROM users ORDER BY age DESC;

-- 分页查询
SELECT * FROM users LIMIT 10 OFFSET 0;

更新数据(UPDATE)

sql 复制代码
-- 更新单条数据
UPDATE users SET age = 26 WHERE id = 1;

-- 更新多条数据
UPDATE users SET age = age + 1 WHERE age < 30;

-- 更新多个字段
UPDATE users SET name = '张三三', email = 'zhangsan3@example.com' WHERE id = 1;

删除数据(DELETE)

sql 复制代码
-- 删除单条数据
DELETE FROM users WHERE id = 1;

-- 删除多条数据
DELETE FROM users WHERE age < 18;

-- 清空表
DELETE FROM users;
3. 高级查询

连接查询

sql 复制代码
-- 内连接
SELECT u.name, p.title 
FROM users u 
INNER JOIN posts p ON u.id = p.user_id;

-- 左连接
SELECT u.name, p.title 
FROM users u 
LEFT JOIN posts p ON u.id = p.user_id;

-- 右连接
SELECT u.name, p.title 
FROM users u 
RIGHT JOIN posts p ON u.id = p.user_id;

聚合函数

sql 复制代码
-- 统计数量
SELECT COUNT(*) FROM users;

-- 计算平均值
SELECT AVG(age) FROM users;

-- 计算总和
SELECT SUM(age) FROM users;

-- 查找最大值
SELECT MAX(age) FROM users;

-- 查找最小值
SELECT MIN(age) FROM users;

-- 分组统计
SELECT age, COUNT(*) FROM users GROUP BY age;
4. 索引和约束

创建索引

sql 复制代码
-- 创建普通索引
CREATE INDEX idx_name ON users(name);

-- 创建唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);

-- 创建复合索引
CREATE INDEX idx_name_age ON users(name, age);

添加约束

sql 复制代码
-- 添加主键约束
ALTER TABLE users ADD PRIMARY KEY (id);

-- 添加外键约束
ALTER TABLE posts ADD FOREIGN KEY (user_id) REFERENCES users(id);

-- 添加检查约束
ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age >= 0 AND age <= 150);

示例

sql 复制代码
-- 创建用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    age INT DEFAULT 0,
    status ENUM('active', 'inactive', 'banned') DEFAULT 'active',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- 创建文章表
CREATE TABLE posts (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    title VARCHAR(200) NOT NULL,
    content TEXT,
    status ENUM('draft', 'published', 'archived') DEFAULT 'draft',
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 插入测试数据
INSERT INTO users (username, email, password, age) VALUES 
('zhangsan', 'zhangsan@example.com', 'password123', 25),
('lisi', 'lisi@example.com', 'password456', 30),
('wangwu', 'wangwu@example.com', 'password789', 28);

INSERT INTO posts (user_id, title, content, status) VALUES 
(1, '我的第一篇文章', '这是文章内容...', 'published'),
(1, '草稿文章', '这是草稿内容...', 'draft'),
(2, '李四的文章', '这是李四的文章内容...', 'published');

7.ORM框架

什么是ORM?

ORM (Object-Relational Mapping) = 对象关系映射

简单理解:ORM就像一个翻译官,帮我们在Java对象和数据库表之间进行转换。

ORM的优势
  1. 简化开发:不需要手写复杂的SQL语句
  2. 类型安全:编译时就能发现错误
  3. 代码复用:通用的CRUD操作
  4. 维护性好:代码更清晰易懂
7.1 MyBatis-Plus

MyBatis-Plus是基于MyBatis的增强工具,提供了更多便利的功能。

类比Vue:

  • MyBatis = Vue的基础响应式系统

  • MyBatis-Plus = Vue + Vuex + 各种插件(功能更强大)

核心功能

1. 代码生成器

作用:自动生成实体类、Mapper、Service等代码

java 复制代码
// MyBatis-Plus代码生成器类似
 自动生成:
 - User.java (实体类)
 - UserMapper.java (数据访问层)
 - UserService.java (业务逻辑层)

2. 通用CRUD操作

作用:提供基础的增删改查操作

java 复制代码
// MyBatis-Plus中的通用操作
@Service
public class UserService {
  @Autowired
  private UserMapper userMapper;
  
  // 查询
  public List<User> getUsers() {
    return userMapper.selectList(null);
  }
  
  // 添加
  public int addUser(User user) {
    return userMapper.insert(user);
  }
  
  // 更新
  public int updateUser(User user) {
    return userMapper.updateById(user);
  }
  
  // 删除
  public int deleteUser(Long id) {
    return userMapper.deleteById(id);
  }
}

条件构造器

作用:动态构建查询条件

java 复制代码
// MyBatis-Plus中的条件查询
public List<User> searchUsers(String name, Integer minAge) {
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  
  if (name != null) {
    wrapper.like("name", name);
  }
  
  if (minAge != null) {
    wrapper.ge("age", minAge);
  }
  
  return userMapper.selectList(wrapper);
}

分页插件

作用:自动处理分页查询

java 复制代码
// MyBatis-Plus中的分页
public IPage<User> getUsers(int current, int size) {
  Page<User> page = new Page<>(current, size);
  return userMapper.selectPage(page, null);
}

完结

相关推荐
来旺3 小时前
互联网大厂Java面试全解析及三轮问答专项
java·数据库·spring boot·安全·缓存·微服务·面试
Json____3 小时前
使用node Express 框架框架开发一个前后端分离的二手交易平台项目。
java·前端·express
詩句☾⋆᭄南笙3 小时前
Mybatis一对一、一对多
java·mybatis·resulttype·resultmap·一对多·一对一
Andya_net3 小时前
Java | 基于redis实现分布式批量设置各个数据中心的服务器配置方案设计和代码实践
java·服务器·分布式
lang201509283 小时前
Spring Boot 外部化配置最佳实践指南
java·spring boot
OliverH-yishuihan3 小时前
FPGA 入门 3 个月学习计划表
学习·fpga开发
小奋斗3 小时前
面试官:[1] == '1'和[1] == 1结果是什么?
前端·面试
萌萌哒草头将军3 小时前
尤雨溪宣布 oxfmt 即将发布!比 Prettier 快45倍 🚀🚀🚀
前端·webpack·vite
weixin_405023373 小时前
webpack 学习
前端·学习·webpack