SpingBoot框架课
一、IDEA安装
1.下载
- 官方下载地址:https://www.jetbrains.com/zh-cn/idea/download/#section=windows
- 下载专业版(Ultimate版)
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)
:查找,找不到返回-1equals()
:判断两个字符串是否相等,注意不能直接用==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 StringBuilder
、StringBuffer
String
不能被修改,如果打算修改字符串,可以使用StringBuilder
和StringBuffer
。
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 类
class
与C++
、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 接口
interface
与class
类似。主要用来定义类中所需包含的函数。
接口也可以继承其他接口,一个类可以实现多个接口。
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++
的template
,Java
的类和接口也可以定义泛型,即同一套函数可以作用于不同的对象类型。
泛型只能使用对象类型,不能使用基本变量类型。
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的最小元素,不存在则返回nullfloorEntry(key)
:返回小于等于key的最大元素,不存在则返回null
四、配置git环境与项目创建
1.项目设计
- 名称:
King Of Bots
,简称KOB
- 图标:
- 项目包含的模块:
- PK模块:匹配界面(微服务)、实况直播界面(WebSocket协议)
- 对局列表模块:对局列表界面、对局录像界面
- 排行榜模块:Bot排行榜界面
- 用户中心模块:注册界面、登录界面、我的Bot界面、每个Bot的详情界面
- 前后端分离模式
SpringBoot
实现后端Vue
3实现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 status
、git add .
、git commit -m "这里输入本次日志"
- 查看历史版本代码:
4.创建项目Web端与AcApp端
- vscode下载地址:https://code.visualstudio.com/
- Bootstrap官网地址:https://v5.bootcss.com/
不熟悉Vue3
的参考《Web应用课》的讲义和视频讲解: - 讲义
- 视频讲解
步骤:
- 然后就搞代码:
- 跟着视频搞就行。
- 安装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
(如果安装到了其他目录,填写相应目录的地址即可)添加到环境变量PAT
H中,这样就可以在任意目录的终端中执行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;
:使用数据库kobshow tables;
:列出当前数据库的所有表create table user(id int, username varchar(100))
:创建名称为user
的表,表中包含id
和username
两个属性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();
}
}
- 实现
utils.JwtUtil
类,为jwt
工具类,用来创建、解析jwt token
- 实现
config.filter.JwtAuthenticationTokenFilter
类,用来验证jwt token
,如果验证成功,则将User
信息注入上下文中 - 配置
config.SecurityConfig
类,放行登录、注册等接口
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)
content
:varchar(10000)
rating
:int
:默认值为1500createtime
: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" />