stu01:创建项目到学生接口完成

This commit is contained in:
awin-x 2025-12-14 19:38:02 +08:00
parent 492b497d63
commit c2c9cc4e50
36 changed files with 1379 additions and 0 deletions

32
stu01/HELP.md Normal file
View File

@ -0,0 +1,32 @@
# Read Me First
The following was discovered as part of building this project:
* The JVM level was changed from '25' to '24', review the [JDK Version Range](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions#jdk-version-range) on the wiki for more details.
# Getting Started
### Reference Documentation
For further reference, please consider the following sections:
* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.12/maven-plugin)
* [Create an OCI image](https://docs.spring.io/spring-boot/3.4.12/maven-plugin/build-image.html)
* [Spring Web](https://docs.spring.io/spring-boot/3.4.12/reference/web/servlet.html)
* [MyBatis Framework](https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/)
### Guides
The following guides illustrate how to use some features concretely:
* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
* [MyBatis Quick Start](https://github.com/mybatis/spring-boot-starter/wiki/Quick-Start)
* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/)
### Maven Parent overrides
Due to Maven's design, elements are inherited from the parent POM to the project POM.
While most of the inheritance is fine, it also inherits unwanted elements like `<license>` and `<developers>` from the parent.
To prevent this, the project POM contains empty overrides for these elements.
If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides.

89
stu01/db.sql Normal file
View File

@ -0,0 +1,89 @@
-- 切换到test01_db数据库
USE stu01_db;
-- 1. 用户表sys_user存储登录账号、密码、权限类型
DROP TABLE IF EXISTS sys_user;
CREATE TABLE sys_user (
id BIGINT AUTO_INCREMENT COMMENT '用户ID主键' PRIMARY KEY,
username VARCHAR(50) NOT NULL COMMENT '登录账号(唯一)',
password VARCHAR(50) NOT NULL COMMENT '登录密码(无需加密,测试用)',
user_type TINYINT NOT NULL COMMENT '权限类型1-学生 2-教师 3-管理员',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
real_name VARCHAR(50) NOT NULL COMMENT '真实姓名'
) COMMENT '用户表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加账号唯一索引
CREATE UNIQUE INDEX idx_sys_user_username ON sys_user(username);
-- 插入测试数据管理员账号admin/123456学生账号stu001/123456教师账号tea001/123456
INSERT INTO sys_user (username, password, user_type) VALUES
('admin', '123456', 3),
('stu001', '123456', 1),
('tea001', '123456', 2);
-- 2. 学生表student存储学生基础信息
DROP TABLE IF EXISTS student;
CREATE TABLE student (
id BIGINT AUTO_INCREMENT COMMENT '学生ID主键' PRIMARY KEY,
stu_no VARCHAR(8) NOT NULL COMMENT '学号8位纯数字唯一',
name VARCHAR(20) NOT NULL COMMENT '学生姓名',
major VARCHAR(30) NOT NULL COMMENT '专业(仅允许:计算机/数学/英语)',
user_id BIGINT NOT NULL COMMENT '关联用户ID',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 外键关联用户表
CONSTRAINT fk_student_user_id FOREIGN KEY (user_id) REFERENCES sys_user(id)
) COMMENT '学生表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加学号唯一索引
CREATE UNIQUE INDEX idx_student_stu_no ON student(stu_no);
-- 插入测试数据关联学生账号stu001的user_id需先查询sys_user中stu001的id再替换示例中假设id=2
INSERT INTO student (stu_no, name, major, user_id) VALUES ('20250001', '张三', '计算机', 2);
-- 3. 教师表teacher存储教师基础信息
DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher (
id BIGINT AUTO_INCREMENT COMMENT '教师ID主键' PRIMARY KEY,
tea_no VARCHAR(8) NOT NULL COMMENT '教师编号8位纯数字唯一',
name VARCHAR(20) NOT NULL COMMENT '教师姓名',
user_id BIGINT NOT NULL COMMENT '关联用户ID',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 外键关联用户表
CONSTRAINT fk_teacher_user_id FOREIGN KEY (user_id) REFERENCES sys_user(id)
) COMMENT '教师表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加教师编号唯一索引
CREATE UNIQUE INDEX idx_teacher_tea_no ON teacher(tea_no);
-- 插入测试数据关联教师账号tea001的user_id示例中假设id=3
INSERT INTO teacher (tea_no, name, user_id) VALUES ('20250001', '李老师', 3);
-- 4. 课程表course存储课程信息关联授课教师
DROP TABLE IF EXISTS course;
CREATE TABLE course (
id BIGINT AUTO_INCREMENT COMMENT '课程ID主键' PRIMARY KEY,
course_name VARCHAR(50) NOT NULL COMMENT '课程名称(仅允许中文/数字/字母长度2-20',
tea_id BIGINT NOT NULL COMMENT '关联教师ID',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 外键关联教师表(用于教师删除时的关联拦截)
CONSTRAINT fk_course_tea_id FOREIGN KEY (tea_id) REFERENCES teacher(id)
) COMMENT '课程表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据关联李老师的teacher_id示例中假设id=1
INSERT INTO course (course_name, tea_id) VALUES ('Java编程', 1);
-- 5. 学分表score存储学生课程成绩关联学生和课程
DROP TABLE IF EXISTS score;
CREATE TABLE score (
id BIGINT AUTO_INCREMENT COMMENT '学分ID主键' PRIMARY KEY,
stu_id BIGINT NOT NULL COMMENT '关联学生ID',
course_id BIGINT NOT NULL COMMENT '关联课程ID',
score INT NOT NULL COMMENT '分数0-100',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-- 外键关联学生表和课程表
CONSTRAINT fk_score_stu_id FOREIGN KEY (stu_id) REFERENCES student(id),
CONSTRAINT fk_score_course_id FOREIGN KEY (course_id) REFERENCES course(id)
) COMMENT '学分表' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据关联张三的student_id=1Java编程的course_id=1
INSERT INTO score (stu_id, course_id, score) VALUES (1, 1, 90);

147
stu01/pom.xml Normal file
View File

@ -0,0 +1,147 @@
<?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 https://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>3.4.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.awinx</groupId>
<artifactId>stu01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>stu01</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>24</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.5</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.13.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.13.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.13.0</version>
<scope>runtime</scope>
</dependency>
<!-- 核心Jakarta Validation API接口层 -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.1.0</version> <!-- 适配Jakarta EE 10稳定版 -->
</dependency>
<!-- 必需Hibernate ValidatorAPI的官方实现 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version> <!-- 与API 3.1.0兼容 -->
</dependency>
<!-- 可选:注解处理器(提升编译期校验体验) -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>8.0.1.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

41
stu01/prompt.txt Normal file
View File

@ -0,0 +1,41 @@
一、核心协作规则重申
任务拆分:严格按照《学生管理系统(测试用例适配)开发任务计划表》执行,每个会话仅完成 1 个最小粒度的任务(如 1.1、1.2),确保任务足够简单、无遗漏;
计划表更新:每完成 1 个任务后,在输出末尾更新计划表,标注对应任务 “完成状态” 为 “已完成”,并在 “备注” 栏记录执行细节、遇到的问题、后续注意点(规避遗忘 / 幻觉);
代码要求:所有开发代码仅满足测试用例覆盖需求,尽可能简洁,无冗余逻辑、无过度设计 / 优化(如密码无需加密、并发仅保证接收请求即可);
协作模式:由助手主导任务拆解与代码编写,用户负责实际操作(创建项目、粘贴代码、运行调试),助手需提供 “复制即用” 的代码及清晰的操作指引;
输出结构:每个任务的输出需包含「操作指引」「核心代码」「验证方式」「更新后的计划表」四部分,确保用户可直接落地。
二、任务计划表引用
所有操作均基于下方《学生管理系统(测试用例适配)开发任务计划表》,每次会话需携带该计划表的最新版本(含已完成任务标注):
阶段 任务 ID 任务名称 核心目标 关键提示词 完成状态 备注(仅保留执行结果和后续影响)
1. 项目初始化与环境搭建 1.1 创建 SpringBoot 后端基础项目 搭建后端工程骨架,引入核心依赖 SpringBoot、MySQL 驱动、MyBatis、JWT、lombok 已完成 Spring Boot 3.4.12,包名 top.awinx.stu01Java 25依赖MyBatis-Plus 3.5.15、JJWT 0.13.0;启动方式:./mvnw spring-boot:run
1. 项目初始化与环境搭建 1.3 设计 MySQL 数据库表结构 设计核心实体表 用户表、学生表、教师表、课程表、学分表 已完成 数据库 stu01_dbMariaDB用户 stu01/123456核心表含 sys_user预置 admin/stu001/tea001密码 123456字段约束学号 / 教师编号 8 位纯数字,专业限 3 类,课程名 2-20 字符,分数 0-100
1. 项目初始化与环境搭建 1.4 后端基础配置 配置数据库、跨域、JWT 参数 application.yml、跨域、JWT 密钥 已完成 数据库连接正常;跨域允许 5173 端口(独立 CorsConfigJWT32 位密钥、1 小时过期context-path=/api端口 8080MyBatis-Plus 开启下划线转驼峰、SQL 日志
2. 用户登录模块开发 2.1 后端用户登录核心逻辑 实现账号密码校验 合法账号、缺少账号 / 密码、错误账号密码 已完成 接口POST /api/login校验逻辑空值 + 存在性 + 密码匹配返回格式Resultcode/message/data
2. 用户登录模块开发 2.2 JWT 令牌生成与校验 生成 token、校验 token、令牌刷新 合法 token、token 拦截、令牌刷新 已完成 接口:① POST /api/login返回 token+user② GET /api/login/refresh刷新 tokenJWT 拦截器放行登录 / 刷新接口,拦截其他 /api/**token 载荷含 user_type1 - 学生 / 2 - 教师 / 3 - 管理员)
2. 用户登录模块开发 2.4 登录异常处理 统一异常返回格式,明确异常信息 缺少账号 / 密码、错误账号密码、token 无效 / 过期 已完成 全局异常处理器捕获业务 / 参数 / 系统异常;返回统一 Result 格式:业务异常 code=400、系统异常 code=500支持空参数、账号密码错误、token 异常等场景,提示信息简洁
2. 用户登录模块开发 2.5 多用户登录性能基础支持 支持高并发请求 多用户登陆性能测试 已完成 依赖 Spring Boot 3.x 默认线程池
3. 学生信息模块开发 3.1 后端学生基础 CRUD 实现学生添加 / 查询接口(支持模糊查询) 学生添加、学生查询(学号 / 姓名 / 专业筛选) 已完成 1. 接口:① POST /api/student/add添加校验学号唯一② GET/POST/api/student/query查询学号精确、姓名 / 专业模糊2. 依赖 JWT 拦截器,需携带合法 token3. 返回格式统一为 Result兼容全局异常处理4. 支持组合条件筛选
3. 学生信息模块开发 3.2 学生添加参数校验 校验学号、专业合法性 缺少学号、不合法学号、非法专业 已完成 学号规则8 位纯数字、非空、唯一;专业限计算机 / 数学 / 英语;用 3.x 参数校验注解
3. 学生信息模块开发 3.3 学生查询参数校验 校验 ID 合法性、防 SQL 注入 合法 ID、非法 ID、SQL 注入拦截 未完成 防注入MyBatis-Plus 参数绑定ID 校验:非负整数 + 存在性
3. 学生信息模块开发 3.5 学生并发测试基础支持 支持添加 / 查询接口并发请求 学生查询 / 添加并发测试 未完成 依赖 3.x 默认配置
4. 教师信息模块开发 4.1 后端教师基础 CRUD 实现教师添加 / 更新 / 删除接口 教师添加、更新、删除 未完成 接口路径POST /api/teacher/add、PUT /api/teacher/update、DELETE /api/teacher/delete
4. 教师信息模块开发 4.2 教师删除关联拦截 教师关联课程 / 学分时拦截删除 删除关联拦截 未完成 校验逻辑:查询 course 表关联关系,存在则拦截;可选 @Transactional 事务处理
4. 教师信息模块开发 4.3 教师查询防 SQL 注入 校验查询参数、防 SQL 注入 教师查询、SQL 注入拦截 未完成 接口:/api/teacher/query防注入MyBatis-Plus 参数绑定
4. 教师信息模块开发 4.5 教师查询并发基础支持 确保教师查询接口支持并发请求 老师查询接口并发测试 未完成 依赖 3.x 默认配置
5. 课程与学分模块开发 5.1 后端课程 / 学分基础 CRUD 编写课程 / 学分实体 / DAO/Service/Controller 课程添加、学分添加 未完成 接口路径POST /api/course/add、POST /api/score/add
5. 课程与学分模块开发 5.2 课程参数校验 校验课程名称合法性、实现课程查询 课程查询、不合法名称 未完成 课程名规则2-20 字符(中文 / 数字 / 字母);接口路径:/api/course/query
5. 课程与学分模块开发 5.3 学分参数校验 校验分数合法性、实现学分更新 学分更新、错误分数 未完成 分数规则0-100超范围返回校验失败接口路径PUT /api/score/update
5. 课程与学分模块开发 5.5 课程查询并发基础支持 确保课程查询接口支持并发请求 课程查询并发测试 未完成 依赖 3.x 默认配置
6. 权限控制模块开发 6.1 JWT 权限标识 令牌中添加用户类型 访问权限 - 未登录、权限标识 已完成 用户类型1 - 学生、2 - 教师、3 - 管理员JWT 载荷已包含 user_type
6. 权限控制模块开发 6.2 后端接口权限拦截 拦截未登录请求、越权访问请求 越权访问 - 学生 - 老师、学生 - 管理员、老师 - 管理员 未完成 基于 JWT 的 user_type 判断权限;拦截器扩展:学生禁访 /api/teacher/、/api/admin/,教师禁访 /api/admin/**
7. 测试适配与代码精简 7.1 测试用例全覆盖核对 逐一核对测试用例,确保功能点无遗漏 用例全覆盖、功能校验 未完成 核对类别:登录 / 学生 / 教师 / 课程学分 / 权限 / 并发 / 注入;适配 3.x、MariaDB
7. 测试适配与代码精简 7.2 代码精简 移除冗余逻辑,仅保留测试必需功能 代码简洁、无冗余 未完成 删除冗余代码,简化逻辑;移除无用配置依赖;统一异常处理逻辑
7. 测试适配与代码精简 7.3 基础联调 确保后端接口通信正常,核心功能可运行 联调、接口通联 未完成 测试核心接口(登录、增删改查、权限、刷新);前后端跨域正常;数据库读写正常
三、执行反馈模块(每次会话必填)
问题解决核心是添加了一个springboot的关于validation的starter依赖。
确认3.2完成开始3.3

View File

@ -0,0 +1,16 @@
package top.awinx.stu01;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("top.awinx.stu01.mapper")
public class Stu01Application {
public static void main(String[] args) {
SpringApplication.run(Stu01Application.class, args);
}
}

View File

@ -0,0 +1,49 @@
package top.awinx.stu01.common;
import lombok.Data;
/**
* 全局统一返回结果
* code200成功400失败
* message提示信息
* data返回数据
*/
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
// 成功返回无数据
public static <T> Result<T> success(String message) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage(message);
return result;
}
// 成功返回带数据
public static <T> Result<T> success(String message, T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage(message);
result.setData(data);
return result;
}
// 失败返回
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.setCode(400);
result.setMessage(message);
return result;
}
// 失败返回
public static <T> Result<T> error(Integer code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
}

View File

@ -0,0 +1,34 @@
package top.awinx.stu01.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* Spring Boot 3.x跨域配置类适配前端5173端口
*/
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许前端5173端口访问
config.addAllowedOrigin("http://localhost:5174");
// 允许携带Cookie
config.setAllowCredentials(true);
// 允许所有请求方法
config.addAllowedMethod("*");
// 允许所有请求头
config.addAllowedHeader("*");
// 暴露响应头方便前端获取JWT令牌
config.addExposedHeader("Authorization");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 所有接口都允许跨域
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,54 @@
package top.awinx.stu01.config;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
/**
* JWT配置类适配jjwt 0.13.0
*/
@Configuration
public class JwtConfig {
// 从yml配置中读取密钥
@Value("${jwt.secret}")
private String secret;
// 从yml配置中读取过期时间
@Value("${jwt.expire}")
private long expire;
// 从yml配置中读取请求头key
@Value("${jwt.header}")
private String header;
// 从yml配置中读取令牌前缀
@Value("${jwt.prefix}")
private String prefix;
/**
* 创建JWT签名密钥jjwt 0.13.0要求密钥长度256位
*/
@Bean
public SecretKey jwtSecretKey() {
// 将字符串密钥转换为SecretKey对象
return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
}
// 提供getter方法方便其他类获取配置
public long getExpire() {
return expire;
}
public String getHeader() {
return header;
}
public String getPrefix() {
return prefix;
}
}

View File

@ -0,0 +1,32 @@
package top.awinx.stu01.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.awinx.stu01.interceptor.JwtInterceptor;
/**
* SpringMVC配置注册JWT拦截器+跨域配置适配Spring Boot 3.x
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 注册JWT拦截器Bean
*/
@Bean
public JwtInterceptor jwtInterceptor() {
return new JwtInterceptor();
}
/**
* 配置拦截规则放行登录接口拦截其他/api/**接口
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor())
.addPathPatterns("/**") // 拦截所有/api开头的接口
.excludePathPatterns("/login"); // 放行登录接口
}
}

View File

@ -0,0 +1,89 @@
package top.awinx.stu01.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.awinx.stu01.common.Result;
import top.awinx.stu01.config.JwtConfig;
import top.awinx.stu01.dto.LoginRequest;
import top.awinx.stu01.entity.SysUser;
import top.awinx.stu01.service.SysUserService;
import top.awinx.stu01.utils.JwtUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import top.awinx.stu01.exception.BusinessException;
/**
* 登录接口Controller
*/
@RestController
@RequestMapping("/login")
public class LoginController {
@Resource
private SysUserService sysUserService;
@Resource
private JwtUtil jwtUtil;
@Resource
private JwtConfig jwtConfig;
/**
* 登录接口POST请求接收JSON参数
* @param loginRequest JSON格式的登录参数
* @return 统一返回结果
*/
@PostMapping("")
public Result<Object> login(@Valid @RequestBody LoginRequest loginRequest) {
// 提取账号密码
String username = loginRequest.getUsername();
String password = loginRequest.getPassword();
// 调用Service校验账号密码
SysUser sysUser = sysUserService.loginCheck(username, password);
// 校验失败
if (sysUser == null) {
// throw new BusinessException("账号或密码错误");
return Result.error("账号或密码错误");
}
// 生成JWT令牌
String token = jwtUtil.generateToken(sysUser);
// 组装返回数据token+基础用户信息
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("token", token);
resultMap.put("user", sysUser);
// 校验成功
return Result.success("登录成功", resultMap);
}
/**
* 登陆令牌刷新接口GET请求无参数
* @return 统一返回结果
*/
@GetMapping("/refresh")
public Result<Object> refresh(HttpServletRequest request) {
String oldToken = request.getHeader(jwtConfig.getHeader());
if (oldToken != null && oldToken.startsWith(jwtConfig.getPrefix())){
oldToken = oldToken.substring(jwtConfig.getPrefix().length());
oldToken = oldToken.trim();
}
if (oldToken == null || !jwtUtil.validateToken(oldToken)) {
throw new BusinessException("请先登录或token已过期");
}
SysUser sysUser = jwtUtil.getUserFromToken(oldToken);
String newToken = jwtUtil.generateToken(sysUser);
return Result.success("刷新成功", newToken);
}
}

View File

@ -0,0 +1,56 @@
package top.awinx.stu01.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.awinx.stu01.common.Result;
import top.awinx.stu01.dto.StudentAddDTO;
import top.awinx.stu01.dto.StudentQueryDTO;
import top.awinx.stu01.entity.Student;
import top.awinx.stu01.service.StudentService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
/**
* 学生CRUD控制器
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Resource
private StudentService studentService;
/**
* 添加学生接口
* 请求方式POST
* 接口路径/api/student/add
*/
@PostMapping("/add")
public Result<Student> addStudent(@Valid @RequestBody StudentAddDTO addDTO) {
Student student = studentService.addStudent(addDTO);
return Result.success("添加学生成功", student);
}
/**
* 查询学生接口兼容GET/POST支持模糊查询
* 请求方式GET/POST
* 接口路径/api/student/query
*/
@GetMapping("/query")
public Result<List<Student>> queryStudentByGet(StudentQueryDTO queryDTO) {
List<Student> studentList = studentService.queryStudent(queryDTO);
return Result.success("查询成功", studentList);
}
@PostMapping("/query")
public Result<List<Student>> queryStudentByPost(@RequestBody StudentQueryDTO queryDTO) {
List<Student> studentList = studentService.queryStudent(queryDTO);
return Result.success("查询成功", studentList);
}
}

View File

@ -0,0 +1,16 @@
package top.awinx.stu01.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 测试接口验证数据库和跨域配置
*/
@RestController
public class TestController {
@GetMapping("/test")
public String test() {
return "后端配置生效,前端可跨域访问!";
}
}

View File

@ -0,0 +1,15 @@
package top.awinx.stu01.dto;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 登录请求参数DTO接收JSON格式参数
*/
@Data
public class LoginRequest {
@NotBlank(message = "用户名不能为空")
private String username; // 登录账号
@NotBlank(message = "密码不能为空")
private String password; // 登录密码
}

View File

@ -0,0 +1,39 @@
package top.awinx.stu01.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
/**
* 添加学生请求参数DTO
*/
@Data
public class StudentAddDTO {
/**
* 学号8位纯数字
*/
@NotBlank(message = "学号不能为空")
@Pattern(regexp = "^\\d{8}$", message = "学号必须为8位纯数字不能包含特殊字符")
private String stuNo;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空")
private String name;
/**
* 专业计算机/数学/英语
*/
@NotBlank(message = "专业不能为空")
@Pattern(regexp = "^(计算机|数学|英语)$", message = "专业仅支持:计算机、数学、英语")
private String major;
/**
* 关联用户ID
*/
@NotNull(message = "关联用户ID不能为空")
private Long userId;
}

View File

@ -0,0 +1,24 @@
package top.awinx.stu01.dto;
import jakarta.validation.constraints.Min;
import lombok.Data;
@Data
public class StudentQueryDTO {
/**
* 学号精确匹配
*/
private String stuNo;
/**
* 姓名模糊匹配
*/
private String name;
/**
* 专业模糊匹配
*/
private String major;
}

View File

@ -0,0 +1,53 @@
package top.awinx.stu01.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 学生实体类对应student表
*/
@Data
@TableName("student") // 关联数据库表名
public class Student {
/**
* 主键ID自增
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 学号8位纯数字唯一
*/
@TableField("stu_no")
private String stuNo;
/**
* 学生姓名
*/
@TableField("name")
private String name;
/**
* 专业计算机/数学/英语
*/
@TableField("major")
private String major;
/**
* 关联用户ID外键
*/
@TableField("user_id")
private Long userId;
/**
* 创建时间默认当前时间
*/
@TableField("create_time")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,20 @@
package top.awinx.stu01.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 系统用户实体对应sys_user表
*/
@Data
@TableName("sys_user") // 关联数据库表名
public class SysUser {
@TableId(type = IdType.AUTO) // 主键自增
private Integer id; // 用户ID
private String username; // 登录账号
private String password; // 登录密码测试用明文无需加密
private Integer userType; // 用户类型1-学生 2-教师 3-管理员
private String realName; // 真实姓名
}

View File

@ -0,0 +1,12 @@
package top.awinx.stu01.exception;
import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
private final int code = 400;
private final String message;
public BusinessException(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,80 @@
package top.awinx.stu01.exception;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.fasterxml.jackson.core.JsonParseException;
import top.awinx.stu01.common.Result;
/**
* 全局异常处理器统一捕获所有接口异常返回标准Result格式
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 捕获业务异常如账号密码错误token无效等
*/
@ExceptionHandler(BusinessException.class)
public Result<Object> handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
/**
* 捕获参数校验异常@NotBlank@Pattern触发的异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Object> handleValidException(MethodArgumentNotValidException e) {
// 获取第一个校验失败的字段提示信息
String message = e.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
return Result.error(400, message);
}
/**
* 捕获JSON解析异常如JSON字段名称不匹配JSON语法错误等
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public Result<Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
// 判断是否是JSON解析错误
Throwable rootCause = e.getRootCause();
if (rootCause instanceof JsonParseException) {
return Result.error(400, "JSON格式错误请检查字段名需用双引号、括号匹配、无多余逗号/特殊字符");
} else {
return Result.error(400, "请求体格式错误请检查JSON语法");
}
}
/**
* 捕获数据库约束异常如非空字段为空字段长度超出限制等
*/
@ExceptionHandler(DataIntegrityViolationException.class)
public Result<Object> handleDataIntegrityException(DataIntegrityViolationException e) {
String msg = e.getMessage();
if (msg.contains("constraint")) {
if (msg.contains("primary")){
return Result.error(400, "主键冲突,请检查");
} else if (msg.contains("unique")) {
return Result.error(400, "唯一约束冲突,请检查");
} else {
return Result.error(400, "数据库约束冲突,请检查");
}
} else {
return Result.error(400, "数据库操作失败,请检查");
}
}
/**
* 捕获系统异常兜底处理
*/
@ExceptionHandler(Exception.class)
public Result<Object> handleSystemException(Exception e) {
// 系统异常返回通用提示避免暴露敏感信息
e.printStackTrace();
return Result.error(500, "服务器内部错误,请稍后重试");
}
}

View File

@ -0,0 +1,54 @@
package top.awinx.stu01.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.HandlerInterceptor;
import top.awinx.stu01.common.Result;
import top.awinx.stu01.config.JwtConfig;
import top.awinx.stu01.utils.JwtUtil;
import java.io.PrintWriter;
/**
* JWT拦截器校验请求头中的token合法性
*/
public class JwtInterceptor implements HandlerInterceptor {
@Resource
private JwtUtil jwtUtil;
@Resource
private JwtConfig jwtConfig;
/**
* 预处理请求到达Controller前校验token
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 获取请求头中的token
String token = request.getHeader(jwtConfig.getHeader());
String prefix = jwtConfig.getPrefix();
if (token != null && token.startsWith(prefix)) {
token = token.substring(prefix.length());
token = token.trim();
}
// 2. 校验token是否存在且合法
if (token == null || !jwtUtil.validateToken(token)) {
// 3. 非法token/无token返回400错误
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
Result<Object> result = Result.error("请先登录或token已过期");
PrintWriter writer = response.getWriter();
writer.write(new ObjectMapper().writeValueAsString(result));
writer.flush();
writer.close();
return false; // 拦截请求
}
// 4. token合法放行请求
return true;
}
}

View File

@ -0,0 +1,12 @@
package top.awinx.stu01.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import top.awinx.stu01.entity.Student;
/**
* 学生Mapper继承MyBatis-Plus BaseMapper无需自定义SQL
*/
@Mapper
public interface StudentMapper extends BaseMapper<Student> {
}

View File

@ -0,0 +1,14 @@
package top.awinx.stu01.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import top.awinx.stu01.entity.SysUser;
import org.apache.ibatis.annotations.Mapper;
/**
* MyBatis-Plus MapperDAO层
* BaseMapper已封装CRUD无需手动写SQL
*/
@Mapper // 标识为MyBatis MapperSpring扫描
public interface SysUserMapper extends BaseMapper<SysUser> {
// 无需新增方法BaseMapper已包含selectOneselectList等
}

View File

@ -0,0 +1,28 @@
package top.awinx.stu01.service;
import com.baomidou.mybatisplus.extension.service.IService;
import top.awinx.stu01.dto.StudentAddDTO;
import top.awinx.stu01.dto.StudentQueryDTO;
import top.awinx.stu01.entity.Student;
import java.util.List;
/**
* 学生Service接口
*/
public interface StudentService extends IService<Student> {
/**
* 添加学生
* @param addDTO 添加参数
* @return 添加后的学生信息
*/
Student addStudent(StudentAddDTO addDTO);
/**
* 模糊查询学生支持学号精确姓名/专业模糊
* @param queryDTO 查询参数
* @return 学生列表
*/
List<Student> queryStudent(StudentQueryDTO queryDTO);
}

View File

@ -0,0 +1,12 @@
package top.awinx.stu01.service;
import com.baomidou.mybatisplus.extension.service.IService;
import top.awinx.stu01.entity.SysUser;
/**
* 用户服务接口
*/
public interface SysUserService extends IService<SysUser> {
// 登录校验方法返回用户信息null表示校验失败
SysUser loginCheck(String username, String password);
}

View File

@ -0,0 +1,73 @@
package top.awinx.stu01.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.awinx.stu01.dto.StudentAddDTO;
import top.awinx.stu01.dto.StudentQueryDTO;
import top.awinx.stu01.entity.Student;
import top.awinx.stu01.exception.BusinessException;
import top.awinx.stu01.mapper.StudentMapper;
import top.awinx.stu01.service.StudentService;
import java.util.List;
/**
* 学生Service实现类
*/
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
/**
* 添加学生校验学号唯一性转换DTO为实体并保存
*/
@Override
public Student addStudent(StudentAddDTO addDTO) {
// 1. 校验学号是否已存在
LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Student::getStuNo, addDTO.getStuNo());
if (this.count(wrapper) > 0) {
throw new BusinessException("学号" + addDTO.getStuNo() + "已存在");
}
// 2. DTO转换为实体
Student student = new Student();
student.setStuNo(addDTO.getStuNo());
student.setName(addDTO.getName());
student.setMajor(addDTO.getMajor());
student.setUserId(addDTO.getUserId());
// 3. 保存学生信息
this.save(student);
return student;
}
/**
* 模糊查询学生学号精确匹配姓名/专业模糊匹配
*/
@Override
public List<Student> queryStudent(StudentQueryDTO queryDTO) {
LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
// 学号精确匹配
if (queryDTO.getStuNo() != null && !queryDTO.getStuNo().isEmpty()) {
wrapper.eq(Student::getStuNo, queryDTO.getStuNo());
}
// 姓名模糊匹配包含
if (queryDTO.getName() != null && !queryDTO.getName().isEmpty()) {
wrapper.like(Student::getName, queryDTO.getName());
}
// 专业模糊匹配包含
if (queryDTO.getMajor() != null && !queryDTO.getMajor().isEmpty()) {
wrapper.like(Student::getMajor, queryDTO.getMajor());
}
// 按创建时间降序排列
wrapper.orderByDesc(Student::getCreateTime);
// 查询并返回结果
return this.list(wrapper);
}
}

View File

@ -0,0 +1,47 @@
package top.awinx.stu01.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.awinx.stu01.entity.SysUser;
import top.awinx.stu01.mapper.SysUserMapper;
import top.awinx.stu01.service.SysUserService;
/**
* 用户服务实现类核心业务逻辑
*/
@Service // 标识为Spring服务Bean
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
/**
* 登录校验逻辑
* 1. 校验账号非空
* 2. 校验密码非空
* 3. 查询数据库是否存在该账号
* 4. 校验密码是否匹配
*/
@Override
public SysUser loginCheck(String username, String password) {
// 1. 空值校验
if (username == null || username.isEmpty()) {
return null;
}
if (password == null || password.isEmpty()) {
return null;
}
// 2. 根据账号查询用户LambdaQueryWrapper避免SQL注入
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getUsername, username); // 等值查询username
SysUser sysUser = this.baseMapper.selectOne(queryWrapper);
// 3. 校验用户存在且密码匹配测试用明文对比
if (sysUser == null || !password.equals(sysUser.getPassword())) {
return null;
}
// 4. 校验通过返回用户信息后续生成JWT用
return sysUser;
}
}

View File

@ -0,0 +1,86 @@
package top.awinx.stu01.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import top.awinx.stu01.config.JwtConfig;
import top.awinx.stu01.entity.SysUser;
import javax.crypto.SecretKey;
import java.util.Date;
/**
* JWT工具类适配jjwt 0.13.0
* 功能生成token解析token校验token
*/
@Component
public class JwtUtil {
@Resource
private JwtConfig jwtConfig;
/**
* 生成JWT令牌
* @param sysUser 登录成功的用户信息
* @return token字符串
*/
public String generateToken(SysUser sysUser) {
// 生成密钥适配jjwt 0.13.0需32位密钥
SecretKey secretKey = jwtConfig.jwtSecretKey();
// 构建token载荷包含user_iduser_typeusername
return Jwts.builder()
.claim("user_id", sysUser.getId()) // 用户ID
.claim("user_type", sysUser.getUserType()) // 用户类型1-学生/2-教师/3-管理员
.claim("username", sysUser.getUsername()) // 用户名
.issuedAt(new Date()) // 签发时间
.expiration(new Date(System.currentTimeMillis() + jwtConfig.getExpire() * 1000)) // 过期时间
.signWith(secretKey) // 签名
.compact();
}
/**
* 解析token获取载荷信息
* @param token JWT令牌
* @return 载荷Claims
*/
public Claims parseToken(String token) {
SecretKey secretKey = jwtConfig.jwtSecretKey();
return Jwts.parser()
.verifyWith(secretKey)
.build()
.parseSignedClaims(token)
.getPayload();
}
/**
* 获取token中的用户信息
* @param token
* @return 用户信息
*/
public SysUser getUserFromToken(String token) {
Claims claims = parseToken(token);
SysUser sysUser = new SysUser();
sysUser.setId(claims.get("user_id", Integer.class));
sysUser.setUserType(claims.get("user_type", Integer.class));
sysUser.setUsername(claims.get("username", String.class));
return sysUser;
}
/**
* 校验token是否合法未过期+签名正确
* @param token JWT令牌
* @return true-合法false-非法
*/
public boolean validateToken(String token) {
try {
Claims claims = parseToken(token);
// 校验是否过期
return !claims.getExpiration().before(new Date());
} catch (Exception e) {
// 签名错误过期格式错误等均返回false
return false;
}
}
}

View File

@ -0,0 +1,46 @@
# 服务器配置
server:
port: 8080 # 后端端口,与前端代理配置一致
servlet:
context-path: /api # 接口前缀,适配前端跨域代理
# 数据源配置适配MariaDB兼容MySQL驱动
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver # Spring Boot 3.x推荐驱动类
url: jdbc:mysql://localhost:3306/stu01_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: stu01 # 自定义数据库用户
password: 123456 # 数据库用户密码
# 跨域配置配合CorsConfig类双重保障
web:
cors:
allowed-origins: http://localhost:5174 # 前端实际端口
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
# MyBatis-Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志测试用
global-config:
db-config:
id-type: AUTO # 主键自增
type-aliases-package: top.awinx.stu01.entity # 实体类包扫描
# mapper-locations: classpath:mapper/*.xml # Mapper XML文件扫描
# mybatis:
# mapperLocations: classpath:mapper/*.xml
logging:
level:
top.awinx.stu01.mapper: debug
com.baomidou.mybatisplus: debug
org.mybatis: debug
# JWT自定义配置适配jjwt 0.13.0
jwt:
secret: abcdefghijklmnopqrstuvwxyz123456 # 32位密钥测试用生产需替换
expire: 3600000 # 过期时间1小时毫秒
header: Authorization # 请求头中JWT令牌的key
prefix: Bearer # 令牌前缀

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.awinx.stu01.mapper.SysUserMapper">
<!-- 这个文件可以是空的MyBatis-Plus会动态生成SQL -->
<!-- 如果需要自定义SQL可以在这里添加 -->
</mapper>

View File

@ -0,0 +1,13 @@
package top.awinx.stu01;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Stu01ApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,46 @@
# 服务器配置
server:
port: 8080 # 后端端口,与前端代理配置一致
servlet:
context-path: /api # 接口前缀,适配前端跨域代理
# 数据源配置适配MariaDB兼容MySQL驱动
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver # Spring Boot 3.x推荐驱动类
url: jdbc:mysql://localhost:3306/stu01_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: stu01 # 自定义数据库用户
password: 123456 # 数据库用户密码
# 跨域配置配合CorsConfig类双重保障
web:
cors:
allowed-origins: http://localhost:5174 # 前端实际端口
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
# MyBatis-Plus配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志测试用
global-config:
db-config:
id-type: AUTO # 主键自增
type-aliases-package: top.awinx.stu01.entity # 实体类包扫描
# mapper-locations: classpath:mapper/*.xml # Mapper XML文件扫描
# mybatis:
# mapperLocations: classpath:mapper/*.xml
logging:
level:
top.awinx.stu01.mapper: debug
com.baomidou.mybatisplus: debug
org.mybatis: debug
# JWT自定义配置适配jjwt 0.13.0
jwt:
secret: abcdefghijklmnopqrstuvwxyz123456 # 32位密钥测试用生产需替换
expire: 3600000 # 过期时间1小时毫秒
header: Authorization # 请求头中JWT令牌的key
prefix: Bearer # 令牌前缀

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.awinx.stu01.mapper.SysUserMapper">
<!-- 这个文件可以是空的MyBatis-Plus会动态生成SQL -->
<!-- 如果需要自定义SQL可以在这里添加 -->
</mapper>

View File

@ -0,0 +1,11 @@
top/awinx/stu01/config/JwtConfig.class
top/awinx/stu01/service/impl/SysUserServiceImpl.class
top/awinx/stu01/config/CorsConfig.class
top/awinx/stu01/dto/LoginRequest.class
top/awinx/stu01/entity/SysUser.class
top/awinx/stu01/Stu01Application.class
top/awinx/stu01/controller/LoginController.class
top/awinx/stu01/service/SysUserService.class
top/awinx/stu01/mapper/SysUserMapper.class
top/awinx/stu01/controller/TestController.class
top/awinx/stu01/common/Result.class

View File

@ -0,0 +1,23 @@
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/Stu01Application.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/common/Result.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/config/CorsConfig.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/config/JwtConfig.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/config/WebMvcConfig.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/LoginController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/StudentController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/controller/TestController.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/LoginRequest.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/StudentAddDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/dto/StudentQueryDTO.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/entity/Student.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/entity/SysUser.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/exception/BusinessException.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/exception/GlobalExceptionHandler.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/interceptor/JwtInterceptor.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/mapper/StudentMapper.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/mapper/SysUserMapper.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/StudentService.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/SysUserService.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/impl/StudentServiceImpl.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/service/impl/SysUserServiceImpl.java
/home/awinx/code/java/lerning/java_web/stu01/src/main/java/top/awinx/stu01/utils/JwtUtil.java

View File

@ -0,0 +1 @@
top/awinx/stu01/Stu01ApplicationTests.class

View File

@ -0,0 +1 @@
/home/awinx/code/java/lerning/java_web/stu01/src/test/java/top/awinx/stu01/Stu01ApplicationTests.java