SpingBoot框架课

一、IDEA安装

1.下载

2.安装

下面的页面可以全选,其他页面一律默认即可。安装完需要重启电脑。

3.激活

优先下载最新专业版

  • 试用30天:免费
  • 教育邮箱(xxx@xxx.edu.cn)激活:免费
  • 学信网激活:免费
  • 在官网购买激活码:个人专业版1000元左右,可以购买当前版本的永久权限;更新版本需要1000元/年。
  • 去淘宝买激活码:几块 - 几十元不等。
  • 其他

4.新建项目

选项:

  • Language:Java
  • Build system:Maven
  • JDK:1.8 (Amazon Corretto version 1.8.0_332)会自动安装,无需下载
  • Add sample code:勾选上

5.切换成中文界面


6.切换成白色界面

二、基本概念

  • JDK、JRE、JVM的关系:
    • JDK:Java Development Kit,Java开发工具包
    • JRE: Java Runtime Environment,Java运行环境
    • JVM:Java Virtual Machine,Java虚拟机
    • JDK包含JRE,JRE包含JVM
  • JDK版本选择
    • 目前JDK1.8(也叫JDK8,注意不是JDK18)用得最多
  • Java代码的编译运行流程
    • 将Java源码编译成Java字节码。
    • 使用JVM将Java字节码转化成机器码。
    • JVM作用:跨平台、内存管理、安全。
  • JSE、JEE、JME的区别
    • JSE: Java Standard Edition,标准版
    • JEE:Java Enterprise Edition,企业版
    • JME: Java Mirco Edition,移动版
    • Spring是JEE的轻量级替代品
    • SpringBoot是Spring + 自动化配置

三、Java语法

1.变量、运算符、输入与输出

类似于C#,Java的所有变量和函数都要定义在class中。
3.1.1 内置数据类型

类型 字节数 举例
byte 1 123
short 2 12345
int 4 123456789
long 8 1234567891011L
float 4 1.2F
double 8 1.2, 1.2D
boolean 1 true, false
char 2 ‘A’

3.1.2 常量
使用final修饰:

final int N = 110;

3.1.3 类型转化

  • 显示转化:int x = (int)'A';
  • 隐式转化: double x = 12, y = 4 * 3.3;

3.1.4 表达式
与C++、Python3类似:

int a = 1, b = 2, c = 3;
int x = (a + b) * c;
x ++;

3.1.5 输入
方式1,效率较低,输入规模较小时使用。

Scanner sc = new Scanner(System.in);
String str = sc.next();  // 读入下一个字符串
int x = sc.nextInt();  // 读入下一个整数
float y = sc.nextFloat();  // 读入下一个单精度浮点数
double z = sc.nextDouble();  // 读入下一个双精度浮点数
String line = sc.nextLine();  // 读入下一行

方式2,效率较高,输入规模较大时使用。注意需要抛异常。

package com.yxc;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine();
        System.out.println(str);
    }
}

3.1.6 输出
方式1,效率较低,输出规模较小时使用。

System.out.println(123);  // 输出整数 + 换行
System.out.println("Hello World");  // 输出字符串 + 换行
System.out.print(123);  // 输出整数
System.out.print("yxc\n");  // 输出字符串
System.out.printf("%04d %.2f\n", 4, 123.456D);  // 格式化输出,float与double都用%f输出

方式2,效率较高,输出规模较大时使用。注意需要抛异常。

package com.yxc;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        bw.write("Hello World\n");
        bw.flush();  // 需要手动刷新缓冲区
    }
}

2.判断语句

3.2.1 if-else语句

c++Python中类似
例如:

package com.yxc;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int year = sc.nextInt();
        if (year % 100 == 0) {
            if (year % 400 == 0)
                System.out.printf("%d是闰年\n", year);
            else
                System.out.printf("%d不是闰年\n", year);
        } else {
            if (year % 4 == 0)
                System.out.printf("%d是闰年\n", year);
            else
                System.out.printf("%d不是闰年\n", year);
        }
    }
}

3.2.2 switch语句
C++中类似。

package com.yxc;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int day = sc.nextInt();
        String name;
        switch (day) {
            case 1:
                name = "Monday";
                break;
            case 2:
                name = "Tuesday";
                break;
            case 3:
                name = "Wednesday";
                break;
            case 4:
                name = "Thursday";
                break;
            case 5:
                name = "Friday";
                break;
            case 6:
                name = "Saturday";
                break;
            case 7:
                name = "Sunday";
                break;
            default:
                name = "not valid";
        }
        System.out.println(name);
    }
}

3.2.3 逻辑运算符与条件表达式
C++Python类似。

package com.yxc;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int year = sc.nextInt();
        if (year % 100 != 0 && year % 4 == 0 || year % 400 == 0)
            System.out.printf("%d是闰年\n", year);
        else
            System.out.printf("%d不是闰年\n", year);
    }
}

3.循环语句

3.3.1 while循环
C++Python类似,例如:

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

3.3.2 do while循环
C++Python类似,例如:

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

do while语句与while语句非常相似。唯一的区别是,do while语句限制性循环体后检查条件。不管条件的值如何,我们都要至少执行一次循环。

3.3.3 for循环
C++Python类似,例如:

for (int i = 0; i < 5; i ++ ) {  // 普通循环
    System.out.println(i);
}

int[] a = {0, 1, 2, 3, 4};
for (int x: a) {  // forEach循环
    System.out.println(x);
}

4.数组

Java中的数组与C++中的数组类似。
3.4.1 初始化
C++类似。
初始化定长数组,长度可以是变量,可以在初始化时赋值。

int[] a = new int[5];  // 初始化长度为5的int数组,初始值为0
int n = 10;
float[] b = new float[n];  // 初始化长度为n的float数组,初始值为0.0F
char[] c = {'a', 'b', 'c'};  // 初始化长度为3的char数组,初始值为:'a', 'b', 'c'
char[] d = c;  // d与c地址相同,更改c中的元素,d中的元素也会改变

3.4.2 数组元素的读取与写入
C++类似。

int[] a = new int[5];

for (int i = 0; i < 5; i++) {
    a[i] = i;
}
for (int i = 0; i < 5; i ++ ) {
    System.out.println(a[i] * a[i]);
}

3.4.3 多维数组
C++类似。

int[][] a = new int[2][3];
a[1][2] = 1;
int[][] b = {
        {1, 2, 3},
        {4, 5, 6},
};
System.out.println(a[1][2]);
System.out.println(b[0][1]);

3.4.4 常用API

  • 属性length:返回数组长度,注意不加小括号
  • Arrays.sort():数组排序
  • Arrays.fill(int[] a, int val):填充数组
  • Arrays.toString():将数组转化为字符串
  • Arrays.deepToString():将多维数组转化为字符串
  • 数组不可变长

5.字符串

3.5.1 String
初始化:

String a = "Hello World";
String b = "My name is";
String x = b;  // 存储到了相同地址
String c = b + "yxc";  // String可以通过加号拼接
String d = "My age is " + 18;  // int会被隐式转化成字符串"18"
String str = String.format("My age is %d", 18);  // 格式化字符串,类似于C++中的sprintf
String money_str = "123.45";
double money = Double.parseDouble(money_str);  // String转double

只读变量,不能修改,例如:

String a = "Hello ";
a += "World";  // 会构造一个新的字符串

访问String中的字符:

String str = "Hello World";
for (int i = 0; i < str.length(); i ++ ) {
    System.out.print(str.charAt(i));  // 只能读取,不能写入
}

常用API:

  • length():返回长度
  • split(String regex):分割字符串
  • indexOf(char c)、indexOf(String str):查找,找不到返回-1
  • equals():判断两个字符串是否相等,注意不能直接用==
  • compareTo():判断两个字符串的字典序大小,负数表示小于,0表示相等,正数表示大于
  • startsWith():判断是否以某个前缀开头
  • endsWith():判断是否以某个后缀结尾
  • trim():去掉首位的空白字符
  • toLowerCase():全部用小写字符
  • toUpperCase():全部用大写字符
  • replace(char oldChar, char newChar):替换字符
  • replace(String oldRegex, String newRegex):替换字符串
  • substring(int beginIndex, int endIndex):返回[beginIndex, endIndex)中的子串

3.5.2 StringBuilderStringBuffer
String不能被修改,如果打算修改字符串,可以使用StringBuilderStringBuffer
StringBuffer线程安全,速度较慢;StringBuilder线程不安全,速度较快。

StringBuilder sb = new StringBuilder("Hello ");  // 初始化
sb.append("World");  // 拼接字符串
System.out.println(sb);

for (int i = 0; i < sb.length(); i ++ ) {
    sb.setCharAt(i, (char)(sb.charAt(i) + 1));  // 读取和写入字符
}

System.out.println(sb);

常用API:

  • reverse():翻转字符串

6.函数

Java的所有变量和函数都要定义在类中。

函数或变量前加static表示静态对象,类似于全局变量。
静态对象属于class,而不属于class的具体实例。

静态函数中只能调用静态函数和静态变量。

示例:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        System.out.println(max(3, 4));
        int[][] a = new int[3][4];
        fill(a, 3);
        System.out.println(Arrays.deepToString(a));

        int[][] b = getArray2d(2, 3, 5);
        System.out.println(Arrays.deepToString(b));
    }

    private static int max(int a, int b) {
        if (a > b) return a;
        return b;
    }

    private static void fill(int[][] a, int val) {
        for (int i = 0; i < a.length; i ++ )
            for (int j = 0; j < a[i].length; j ++ )
                a[i][j] = val;
    }

    private static int[][] getArray2d(int row, int col, int val) {
        int[][] a = new int[row][col];
        for (int i = 0; i < row; i ++ )
            for (int j = 0; j < col; j ++ )
                a[i][j] = val;
        return a;
    }
}

7.类与接口

3.7.1 类
classC++Python类似。
3.7.1.1 源文件声明规则

  • 一个源文件中只能有一个public类。
  • 一个源文件可以有多个非public类。
  • 源文件的名称应该和public类的类名保持一致
  • 每个源文件中,先写package语句,再写import语句,最后定义类。

3.7.1.2 类的定义

  • public: 所有对象均可以访问
  • private: 只有自己可以访问
class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public String toString() {
        return String.format("(%d, %d)", x, y);
    }
}

3.7.3 类的继承
每个类只能继承一个类。

class ColorPoint extends Point {
    private String color;

    public ColorPoint(int x, int y, String color) {
        super(x, y);
        this.color = color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String toString() {
        return String.format("(%d, %d, %s)", super.getX(), super.getY(), this.color);
    }
}

3.7.4 类的多态

public class Main {
    public static void main(String[] args) {
        Point point = new Point(3, 4);
        Point colorPoint = new ColorPoint(1, 2, "red");

        // 多态,同一个类的实例,调用相同的函数,运行就结果不同
        System.out.println(point.toString());
        System.out.println(colorPoint.toString());
    }
}

3.7.2 接口
interfaceclass类似。主要用来定义类中所需包含的函数。
接口也可以继承其他接口,一个类可以实现多个接口。

3.7.2.1 接口的定义

interface Role {
    public void greet();
    public void move();
    public int getSpeed();
}

3.7.2.2 接口的继承
每个接口可以继承多个接口

interface Hero extends Role {
    public void attack();
}

3.7.2.3 接口的实现
每个类可以实现多个接口

class Zeus implements Hero {
    private final String name = "Zeus";
    public void attack() {
        System.out.println(name + ": attack!");
    }

    public void greet() {
        System.out.println(name + ": Hi!");
    }

    public void move() {
        System.out.println(name + ": Move!");
    }

    public int getSpeed() {
        return 10;
    }
}

3.7.2.4 接口的多态

class Athena implements Hero {
    private final String name = "Athena";
    public void attack() {
        System.out.println(name + ": attack!");
    }

    public void greet() {
        System.out.println(name + ": Hi!");
    }

    public void move() {
        System.out.println(name + ": Move!");
    }

    public int getSpeed() {
        return 10;
    }
}

public class Main {
    public static void main(String[] args) {
        Hero[] heros = {new Zeus(), new Athena()};
        for (Hero hero: heros) {
            hero.greet();
        }
    }
}

3.7.3 泛型
类似于C++templateJava的类和接口也可以定义泛型,即同一套函数可以作用于不同的对象类型。
泛型只能使用对象类型,不能使用基本变量类型。

8.常用容器

3.8.1 List
接口:java.util.List<>

实现:

  • java.util.ArrayList<>:变长数组
  • java.util.LinkedList<>:双链表

函数:

  • add():在末尾添加一个元素
  • clear():清空
  • size():返回长度
  • isEmpty():是否为空
  • get(i):获取第i个元素
  • set(i, val):将第i个元素设置为val

3.8.2 栈
类:java.util.Stack<>

函数:

  • push():压入元素
  • pop():弹出栈顶元素,并返回栈顶元素
  • peek():返回栈顶元素
  • size():返回长度
  • empty():栈是否为空
  • clear():清空

3.8.3 队列
接口:java.util.Queue<>

实现:

  • java.util.LinkedList<>:双链表
  • java.util.PriorityQueue<>:优先队列
    • 默认是小根堆,大根堆写法:new PriorityQueue<>(Collections.reverseOrder())

函数:

  • add():在队尾添加元素
  • remove():删除并返回队头
  • isEmpty():是否为空
  • size():返回长度
  • peek():返回队头
  • clear():清空

3.8.4 Set
接口:java.util.Set<K>

实现:

  • java.util.HashSet<K>:哈希表
  • java.util.TreeSet<K>:平衡树

函数:

  • add():添加元素
  • contains():是否包含某个元素
  • remove():删除元素
  • size():返回元素数
  • isEmpty():是否为空
  • clear():清空

java.util.TreeSet多的函数:

  • ceiling(key):返回大于等于key的最小元素,不存在则返回null
  • floor(key):返回小于等于key的最大元素,不存在则返回null

3.8.5 Map
接口:java.util.Map<K, V>

实现:
java.util.HashMap<K, V>:哈希表
java.util.TreeMap<K, V>:平衡树

函数:

  • put(key, value):添加关键字和其对应的值
  • get(key):返回关键字对应的值
  • containsKey(key):是否包含关键字
  • remove(key):删除关键字
  • size():返回元素数
  • isEmpty():是否为空
  • clear():清空
  • entrySet():获取Map中的所有对象的集合
  • Map.Entry<K, V>:Map中的对象类型
  • getKey():获取关键字
  • getValue():获取值

java.util.TreeMap<K, V>多的函数:

  • ceilingEntry(key):返回大于等于key的最小元素,不存在则返回null
  • floorEntry(key):返回小于等于key的最大元素,不存在则返回null

四、配置git环境与项目创建

1.项目设计

  • 名称:King Of Bots,简称KOB
  • 图标:
  • 项目包含的模块:
    • PK模块:匹配界面(微服务)、实况直播界面(WebSocket协议)
    • 对局列表模块:对局列表界面、对局录像界面
    • 排行榜模块:Bot排行榜界面
    • 用户中心模块:注册界面、登录界面、我的Bot界面、每个Bot的详情界面
  • 前后端分离模式
    • SpringBoot实现后端
    • Vue3实现Web端和AcApp端

2.配置git环境

  • (1) 安装Git Bash(使用Mac和Linux的可以跳过这一步):https://gitforwindows.org/
  • (2) 进入家目录生成秘钥:执行命令ssh-keygen
  • (3) 在Ac Git上注册账号,地址:https://git.acwing.com/
  • (4) 将id_rsa.pub的内容复制到Ac Git
    注意事项:
  • 如果之前有生成ssh密钥,那么就会出现这种情况:
    只需要将之前的删除即可。代码为:rm -rf ~/.ssh/* 不过这是把所有ssh删掉。注意不要在末尾多输入空格,否则很可能会重装系统。
  • 进入id_rsa.pub 要用vim操作里的cat:cat id_rsa.pub
  • 进入AcGit 注册账号后,点击偏好设置:
  • 之后点击SSH密钥,根据图示进行操作。

3.创建项目后端

  • https://start.spring.io/加载慢的话,可以换成:https://start.aliyun.com
    步骤:
  • 首先确定项目位置,之后创建项目文件夹。打开Git初始化 git Init 会出现如下情况:
  • 在AcGit中点击菜单-项目-您的项目-新建项目-创建空白项目。
  • 分别复制一下内容到git里 不过要把global删除掉

  • 如何在公司通过git实现继续工作项目呢?
    打开git bash 输入:git pull 就可以把项目文件拉取下来。
    更新 git的操作: git statusgit add .git commit -m "这里输入本次日志"
  • 查看历史版本代码:

4.创建项目Web端与AcApp端

步骤:

  • 然后就搞代码:
  • 跟着视频搞就行。
  • 安装Vue:建议安装npm i -g @vue/cli@4 版本。否则会出现打开不了的情况。
  • 卸载vue的命令:npm uninstall -g @vue/cli
  • 在PoweShell 输入vue ui 打开Vue项目,分别创建web和acapp。










  • 然后更新git
    git add . git commit -m "创建wed端和acapp段"
  • 然后跟着视频敲代码。。。

5.在SpringBoot中解决跨域问题

添加配置类:CorsConfig

package com.kob.backend.config;

import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class CorsConfig implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;

        String origin = request.getHeader("Origin");
        if(origin!=null) {
            response.setHeader("Access-Control-Allow-Origin", origin);
        }

        String headers = request.getHeader("Access-Control-Request-Headers");
        if(headers!=null) {
            response.setHeader("Access-Control-Allow-Headers", headers);
            response.setHeader("Access-Control-Expose-Headers", headers);
        }

        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void destroy() {
    }
}

这里就是创建一个包,把内容复制到包里。

6.素材

  • 背景图片
    不知道为什么@/assrts/background.png没有用。要用 ./assets/background.png"
    最后上效果图:

五、创建菜单与游戏页面

1. 创建菜单页面

2. 创建游戏页面

六、配置Mysql与注册登录模块

1. 配置Mysql

  • 1.1 下载

  • 1.2 安装


    其他页面全选默认即可

  • 1.3 配置环境变量
    C:\Program Files\MySQL\MySQL Server 8.0\bin(如果安装到了其他目录,填写相应目录的地址即可)添加到环境变量PATH中,这样就可以在任意目录的终端中执行mysql命令了。

  • 1.4 mysql服务的关闭与启动(默认开机自动启动,如果想手动操作,可以参考如下命令)

    • 关闭:net stop mysql80
    • 启动:net start mysql80
  • 1.5 mysql的常用操作

    • 连接用户名为root,密码为123456的数据库服务:mysql -uroot -p123456
    • show databases;:列出所有数据库
    • create database kob;:创建数据库
    • drop database kob;:删除数据库
    • use kob;:使用数据库kob
    • show tables;:列出当前数据库的所有表
    • create table user(id int, username varchar(100)):创建名称为user的表,表中包含idusername两个属性
    • drop table user;:删除表
    • insert into user values(1, 'Sky');:在表中插入数据
    • select * from user;:查询表中所有数据
    • delete from user where id = 2;:删除某行数据

2. 配置SpringBoot

  • Maven仓库地址
  • Mybatis-Plus官网
  • pom.xml文件中添加依赖:
    • Spring Boot Starter JDBC
    • Project Lombok
    • MySQL Connector/J
    • mybatis-plus-boot-starter
    • mybatis-plus-generator
    • spring-boot-starter-security
    • jjwt-api
  • application.properties中添加数据库配置:
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/kob?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  • SpringBoot中的常用模块
    • pojo层:将数据库中的表对应成Java中的Class
    • mapper层(也叫Dao层):将pojo层的class中的操作,映射成sql语句
    • service层:写具体的业务逻辑,组合使用mapper中的操作
    • controller层:负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面

3. 修改Spring Security

  • 实现service.impl.UserDetailsServiceImpl类,继承自UserDetailsService接口,用来接入数据库信息
  • 实现config.SecurityConfig类,用来实现用户密码的加密存储
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

4. 编写API

  • 将数据库中的id域变为自增
  • 在数据库中将id列变为自增
  • pojo.User类中添加注解:@TableId(type = IdType.AUTO)
  • 实现/user/account/token/:验证用户名密码,验证成功后返回jwt token(令牌)
  • 实现/user/account/info/:根据令牌返回用户信息
  • 实现/user/account/register/:注册账号

七、创建个人中心页面

1.在数据库中创建表bot

表中包含的列

  • id: int:非空、自动增加、唯一、主键
  • user_id: int:非空
  • 注意:在pojo中需要定义成userId,在queryWrapper中的名称仍然为user_id
  • title: varchar(100)
  • description: varchar(300)
  • contentvarchar(10000)
  • rating: int:默认值为1500
  • createtime: datetime
  • pojo中定义日期格式的注解:@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  • modifytime: datetime
  • pojo中定义日期格式的注解:@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

2.实现后端API

  • /user/bot/add/:创建一个Bot
  • /user/bot/remove/:删除一个Bot
  • /user/bot/update/:修改一个Bot
  • /user/bot/getlist/:查询Bot列表

3.实现前端界面

  • 安装依赖:vue3-ace-editor
import { VAceEditor } from 'vue3-ace-editor';
import ace from 'ace-builds';
ace.config.set(
    "basePath", 
    "https://cdn.jsdelivr.net/npm/ace-builds@" + require('ace-builds').version + "/src-noconflict/")
<VAceEditor
    v-model:value="botadd.content"
    @init="editorInit"
    lang="c_cpp"
    theme="textmate"
    style="height: 300px" />
posted @ 2022-07-07 15:06  飘向远方丶  阅读(76)  评论(0编辑  收藏  举报