news 2026/10/2 2:36:07

SpringBoot+MySQL古诗词网站:从表设计到权限控制全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+MySQL古诗词网站:从表设计到权限控制全解析

简介:基于 Java(SpringBoot)+ MySQL 开发的古诗词学习网站完整项目,面向 Java 学习者、课程设计及毕业设计学生,可灵活用于课程设计、毕业设计或 SpringBoot 入门实战。系统实现用户端与管理员端双角色功能:用户可浏览不同类别、朝代的诗词,查看详情(全文、注释、翻译),支持收藏、评论、分享,并提供头部搜索;管理员可管理诗词、诗人、朝代、类别,审核用户分享内容并发布通知。资源包共 596 个文件,以 java 源码、class 字节码、xml 配置、html/js/css 前端页面、png/jpg 图片及 sql 数据库脚本为主,兼顾 React 相关元素,压缩包约 39.9MB,目录结构清晰,运行配置完备。项目包含完整业务逻辑与分层代码,可直接导入 IDE 运行调试,配合 SQL 脚本快速建库,适合作为课设/毕设蓝本二次开发。目前已有 951 人学习下载,能帮助理解 SpringBoot 分层架构、MySQL 表设计以及前后端交互流程,具有较高参考价值。

1. 从 SpringBoot 到 MySQL:一套古诗词学习网站到底解决什么

很多人拿到 Java 课程设计资源包的第一反应是双击运行,结果要么数据库连不上,要么代码缺文件。这套编号 100011164 的「基于 Java(SpringBoot)+ MySQL 古诗词学习网站」资源,跟你平时下到的「单页 Demo」不一样:它把用户端和管理员端拆成 15 条明确需求,从诗词浏览、详情、收藏、评论、分享到管理员审核、通知发布,是一套完整课设覆盖范围。你把它拿去做毕设或课程设计,能直接对上答辩老师要的「业务完整度」和「权限隔离」两个关键点。

它的价值不在页面多漂亮,而在后端模块划分清晰——从项目正文给出的核心类来看,PoetryController、CommentController、AdminController、DynastyController 这些类名几乎就是一张 MVC 分层地图。适合两类人:一是写 Java 课设还差一个完整业务闭环的在校生;二是想快速搭一套「内容管理 + 用户互动」SpringBoot 项目模板、方便二次改造的开发者。接下来我按「怎么把这份资源搞清楚、怎么复现、怎么避坑」的顺序,把整个项目拆开讲。

2. 项目骨架与核心类:从 Controller 到 DAO 的调用链怎么还原

2.1 从 class 文件清单逆推工程结构

项目正文给的不是传统意义的「全部源码压缩包」,而是一串编译后的 .class 类名。先别看懵,这类课设资源包里只有编译产物太常见了,反而能从类名精确反推完整的 SpringBoot 工程结构。核心类清单我整理成表:

类名职责定位对应需求
PoetryController诗词浏览、详情、搜索入口用户需求①②③⑩
PoetController诗人信息查询用户需求②
DynastyController朝代列表与筛选用户需求②
PoetryTypeController诗词类别列表用户需求①
CollectionController收藏新增/删除/列表用户需求⑤
CommentController评论查看与发表用户需求⑥
UserController注册登录、个人信息修改用户需求⑧
UserImp用户模块核心实现类用户需求⑧,管理员需求①
AdminController管理后台统一入口管理员需求①—⑤
NoticeController通知查看与发布用户需求⑨,管理员需求④

先说一个命名坑:很多课设里把 Implementation 简写成 Imp,所以 UserImp 不是「用户导入」,大概率是 UserService 的实现类。这一点看清楚,还原时就不会给 UserController 凭空加一个奇怪的依赖。还原后的标准包结构是这样的:

com.example.poetry ├── controller # PoetryController、PoetController、AdminController 等 ├── service # PoetryService、UserService、CollectionService、CommentService ├── impl # UserImp、PoetryServiceImpl、CollectionServiceImpl ├── mapper # PoetryMapper、UserMapper、CollectionMapper、CommentMapper ├── entity # Poetry、Poet、Dynasty、PoetryType、User、Collection、Comment └── config # 拦截器、CORS 配置、MyBatis 配置

这样做的原因很简单:class 文件只保留编译后的字节码,但它的包路径和类名没法伪装。按照 SpringBoot 约定大于配置的惯例,Controller 必然依赖 Service,Service 必然依赖 Mapper。把 10 个类名填进上面这个骨架,项目结构基本就复原了七成。

2.2 请求路径设计:先把路由规划好再写代码

古诗词网站的路由命名有讲究,既要让前端好对接,也要让用户需求逐条闭环。常规做法是 Controller 类名直接决定前缀,方法名决定操作。我一般会按下面的路径来规划:

请求方法路径功能涉及 Controller
GET/poetry/list分页查询诗词列表PoetryController
GET/poetry/detail/{id}查看诗词详情(含注释翻译)PoetryController
GET/poetry/search?keyword=关键词搜索诗词PoetryController
GET/poetry/recommend推荐页热门诗词PoetryController
GET/collection/list/{userId}查看用户收藏列表CollectionController
POST/collection/add新增收藏CollectionController
POST/collection/delete删除收藏CollectionController
POST/comment/add发表评论CommentController
GET/comment/list/{poetryId}查看某首诗的评论CommentController
POST/share/upload上传分享内容UserController
GET/notice/list查看通知列表NoticeController
POST/admin/audit/share审核用户分享AdminController

不建议把搜索、推荐、列表全塞到一个/poetry/query里——那样后期想加缓存或者拆表时会很痛苦。每个需求点对应一个独立端点,答辩时老师问「搜索怎么做的」,你直接点出/poetry/search这个入口即可。

2.3 手写一个「按朝代查诗词」的标准链路

还原到这里,可以动手写第一个完整接口验证链路通不通。最典型的是朝代筛选:前端传dynastyId,后端去 poetry 表按朝代过滤并分页。PoetryController 的写法:

@RestController @RequestMapping("/poetry") public class PoetryController { @Autowired private PoetryService poetryService; /** * 按朝代分页查询诗词 * @param dynastyId 朝代ID,null 时查询全部 * @param pageNum 页码,从 1 开始 * @param pageSize 每页条数,默认 10 */ @GetMapping("/list") public Result pageList(@RequestParam(required = false) Integer dynastyId, @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize) { PageInfo<Poetry> pageInfo = poetryService.pageByDynasty(dynastyId, pageNum, pageSize); return Result.ok(pageInfo); } }

对应的 Service 实现,配合 MyBatis 分页插件 PageHelper 可以省去手写分页逻辑:

@Service public class PoetryServiceImpl implements PoetryService { @Autowired private PoetryMapper poetryMapper; @Override public PageInfo<Poetry> pageByDynasty(Integer dynastyId, Integer pageNum, Integer pageSize) { // PageHelper.startPage 之后,紧跟的那条 SQL 会自动被拦截并加上 LIMIT PageHelper.startPage(pageNum, pageSize); List<Poetry> list = poetryMapper.selectByDynastyId(dynastyId); return new PageInfo<>(list); } }

逻辑说明:@RequestParam(required = false)把dynastyId设为可选——不传朝代就看全部,传了就按朝代过滤,这正好覆盖用户需求第一、二条。PageHelper.startPage只对下一条查询生效,所以它必须紧挨 Mapper 调用,中间不能插入其他数据库操作,否则分页会串到别的 SQL 上去。Result.ok(...)是统一的返回包装,建议用code + message + data三段式,前端拿到后好做全局拦截。

参数说明:pageNum从 1 开始而不是 0,这是 PageHelper 的默认风格,前端对接时注意别把「当前页」直接当页数传;pageSize默认给 10,课设场景不用做动态调整,但接口里保留这个参数方便测试。

3. MySQL 表设计与诗词检索:核心数据落点

3.1 数据模型:九张表怎么支撑 15 条需求

所有功能最终都要落到 MySQL 表上。我仔细过了一遍需求清单,这套项目最少需要 9 张表:user(用户)、dynasty(朝代)、poet(诗人)、poetry_type(诗词类别)、poetry(诗词)、collection(收藏)、comment(评论)、share(用户分享)、notice(通知)。其中poetry是绝对核心,它跟poet、dynasty、poetry_type都是外键关联。这里有个容易犯的设计错误:把朝代名、诗人名直接塞进 poetry 表。当时偷懒的话,后面做「按朝代筛选」「按诗人筛选」就得写大量字符串匹配,性能和可维护性都很差。

collection和comment是典型的中间表,分别关联user和poetry。share比较特殊,它保存用户上传的分享内容,同时需要有一个状态字段给管理员审核用。notice独立成表,内容和发布时间就够。

字段类型上有个小建议:诗词正文可能包含生僻字和标点,长度不固定,用TEXT而非VARCHAR,避免长度溢出;translation和annotation同样用TEXT。

3.2 建表 SQL:把需求固化成字段约束

这部分的建表语句直接决定整套功能能不能跑通,我给出核心表的精简版:

CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE COMMENT '登录名', password VARCHAR(100) NOT NULL COMMENT 'MD5或BCrypt密文', nickname VARCHAR(50) DEFAULT '' COMMENT '昵称', role TINYINT DEFAULT 0 COMMENT '0普通用户 1管理员', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; CREATE TABLE poetry ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(100) NOT NULL COMMENT '诗词标题', content TEXT NOT NULL COMMENT '全文', annotation TEXT COMMENT '注释', translation TEXT COMMENT '翻译', poet_id INT NOT NULL COMMENT '关联诗人', dynasty_id INT NOT NULL COMMENT '关联朝代', type_id INT NOT NULL COMMENT '关联类别', view_count INT DEFAULT 0 COMMENT '浏览量', collection_count INT DEFAULT 0 COMMENT '收藏数,冗余字段' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='诗词表'; CREATE TABLE collection ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, poetry_id INT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_poetry (user_id, poetry_id), CONSTRAINT fk_collection_user FOREIGN KEY (user_id) REFERENCES user(id), CONSTRAINT fk_collection_poetry FOREIGN KEY (poetry_id) REFERENCES poetry(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收藏表'; CREATE TABLE share ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL COMMENT '上传用户', title VARCHAR(100) NOT NULL, content TEXT NOT NULL COMMENT '分享内容', status TINYINT DEFAULT 0 COMMENT '0待审核 1通过 2驳回', audit_msg VARCHAR(255) DEFAULT '' COMMENT '审核意见', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户分享表';

设计说明:collection表加了UNIQUE KEY (user_id, poetry_id),这是防止重复收藏的关键约束——后端接口再粗心,数据库这层也能兜底。poetry表里冗余了collection_count,虽然是空间换时间,但课设场景下做推荐排序时收益很明显,不用每次COUNT(*)全表扫描。share.status默认 0,正好对应管理员「审核未处理」的状态,审核通过改成 1,驳回改成 2 并填audit_msg,后面后台查询时WHERE status = 0就能拿到待审核列表。

3.3 关键词搜索:LIKE 与分页的三处细节

用户需求第十条要求头部搜索栏输入关键词,返回匹配的诗词列表。这里最常见的实现是 SQL 模糊查询配合分页:

<select id="searchByKeyword" resultType="com.example.poetry.entity.Poetry"> SELECT * FROM poetry WHERE title LIKE CONCAT('%', #{keyword}, '%') OR content LIKE CONCAT('%', #{keyword}, '%') ORDER BY collection_count DESC </select>

这条 SQL 有三个细节值得记下来。第一,用CONCAT('%', #{keyword}, '%')而不是'%${keyword}%',后者会把用户输入直接拼进 SQL,存在注入风险;MyBatis 里#{}是预编译参数占位符,${}是字符串替换,搜索场景必须用前者。第二,在标题和内容两个字段上都匹配,这符合用户习惯——很多人记不全整句诗,只记得一句半句。第三,排序用collection_count DESC,让热门诗词排在前面,顺手兼顾了推荐页的逻辑。如果对性能有进一步要求,可以给title加普通索引,但课设数据量通常几千条,LIKE '%...%'虽然不走索引,体验上差别不大,没必要为这个上全文索引。

4. 用户侧核心流程:详情、收藏、评论、分享的实现路径

4.1 详情页组装:三张表关联一次查出来

诗词详情页要展示标题、正文、注释、翻译、作者、朝代、类别,这些信息分布在四张表里。最简单的方式是写一个关联查询,一次拿全:

@Mapper public interface PoetryMapper { // 联表查询诗词详情 PoetryDetailVO selectDetailById(@Param("poetryId") Integer poetryId); }
<select id="selectDetailById" resultType="com.example.poetry.vo.PoetryDetailVO"> SELECT p.id, p.title, p.content, p.annotation, p.translation, po.name AS poetName, d.name AS dynastyName, t.name AS typeName FROM poetry p JOIN poet po ON p.poet_id = po.id JOIN dynasty d ON p.dynasty_id = d.id JOIN poetry_type t ON p.type_id = t.id WHERE p.id = #{poetryId} </select>

逻辑说明:用JOIN替代三次单表查询,减少一次网络往返。PoetryDetailVO是专门给前端展示用的视图对象,避免把整个实体类直接吐给前端——实体类里如果还有update_time、deleted这类字段,直接返回会让接口变得臃肿。参数说明:@Param注解在 Mapper 方法只有一个参数时也可以省略,但写上之后 SQL 里的名字对应关系更明确,后面加参数时不容易踩坑。

4.2 收藏与取消收藏:幂等操作比想象中重要

用户会在详情页点收藏,也可能在收藏列表里取消收藏。这个接口最好的设计是「同一用户同一诗词只能插一条记录,重复请求不报错」。配合前面collection表的唯一索引,代码可以这么写:

@Service public class CollectionServiceImpl implements CollectionService { @Autowired private CollectionMapper collectionMapper; @Override @Transactional(rollbackFor = Exception.class) public boolean toggleCollection(Integer userId, Integer poetryId) { // 先查是否已收藏,已收藏则删除,未收藏则新增 int exists = collectionMapper.countByUserAndPoetry(userId, poetryId); if (exists > 0) { collectionMapper.deleteByUserAndPoetry(userId, poetryId); // 收藏数减一,但不能小于 0 poetryMapper.decreaseCollectionCount(poetryId); } else { collectionMapper.insert(userId, poetryId); poetryMapper.increaseCollectionCount(poetryId); } return exists == 0; } }

逻辑说明:@Transactional保证「插入收藏 + 更新收藏数」要么都成功,要么都失败。toggle这个方法返回布尔值表示当前操作是收藏(true)还是取消收藏(false),前端拿到后可以同步切换按钮状态。参数说明:poetryMapper.increaseCollectionCount实际执行的是UPDATE poetry SET collection_count = collection_count + 1 WHERE id = #{poetryId},用数据库自增而不是先查后改,避免并发下的数据不一致。这个接口没有做「未登录拦截」,实际项目里应该配合拦截器,在 Controller 层就拦住未登录请求。

4.3 评论与分享:事务和状态机是关键

评论功能要处理的是「登录用户才能发表评论」。常规做法是在 Controller 层通过HttpSession或 Token 拿到当前用户 ID:

@RestController @RequestMapping("/comment") public class CommentController { @Autowired private CommentService commentService; @PostMapping("/add") public Result addComment(@RequestBody CommentAddDTO dto, @RequestAttribute("userId") Integer userId) { // userId 由拦截器从 Token 解析后塞进 Request 属性 if (dto.getContent() == null || dto.getContent().trim().isEmpty()) { return Result.error("评论内容不能为空"); } int count = commentService.addComment(userId, dto.getPoetryId(), dto.getContent()); return count > 0 ? Result.ok() : Result.error("评论失败"); } }

一个容易被忽视的点:评论内容要认真做长度限制和 XSS 过滤。用户一旦能往页面里塞<script>,整个网站就变成钓鱼平台了。很多 SpringBoot 课设都有这个问题——全局过滤器只处理了上传 PDF 文件的 XSS,却漏了评论和分享这类文本输入。建议在前端做textContent插入而不是innerHTML,后端再用过滤器把<script>、<iframe>等标签统一转义,双重防护才稳。

分享功能的重点在状态流转。用户上传时status = 0(待审核),管理员审核后改成 1 或 2。用户端「分享页面」只查status = 1的数据,管理端待审核列表查status = 0,这样就形成了一条完整的状态机链路。

4.4 推荐页:一张 SQL 就能做出来的热门榜单

推荐页面不一定非要上协同过滤算法,课设级别最稳的方案是按收藏数倒序取前 10 首。SQL 非常简单:

<select id="selectRecommendList" resultType="com.example.poetry.entity.Poetry"> SELECT * FROM poetry ORDER BY collection_count DESC LIMIT 10 </select>

这个方案的合理性在于:收藏是用户主动行为,收藏数天然代表内容质量。配合前面collection_count冗余字段,这条 SQL 不需要任何聚合操作,执行效率很高。如果你想让它「看起来更像推荐」,可以加view_count做加权排序,比如ORDER BY collection_count * 0.7 + view_count * 0.3 DESC,但课设答辩时老师问起来「推荐算法是什么」,直接说基于收藏热度的排序,比含糊说「用了推荐算法」更经得起追问。

5. 管理员侧与权限控制:避坑与排查

5.1 管理员权限:一个拦截器搞定角色校验

AdminController 是管理后台的统一入口,必须保证只有管理员能访问。最简单可靠的方案是定义拦截器,在进入 AdminController 之前校验登录态和角色:

@Component public class AdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从 Session 或 Header 中获取用户信息 User user = (User) request.getSession().getAttribute("loginUser"); if (user == null) { response.setStatus(401); return false; } // role 字段:0 普通用户,1 管理员 if (user.getRole() == null || user.getRole() != 1) { response.setStatus(403); return false; } return true; } }

配置类里要指定拦截路径:

@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private AdminInterceptor adminInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(adminInterceptor) .addPathPatterns("/admin/**") .excludePathPatterns("/admin/login"); } }

逻辑说明:这种拦截方式比在每个 Controller 方法里if (role != 1) return error强很多,新写一个管理接口只需要把路径放进/admin/**就自动受保护,不容易漏。参数说明:response.setStatus(403)返回 HTTP 状态码,前端拿到后统一跳转登录页或提示无权限;excludePathPatterns("/admin/login")是为了放行管理员登录接口,否则还没登录就被拦死了。注意拦截器只能保证「接口层面安全」,真正细粒度的权限校验还是要在 Service 层做。

5.2 管理端的增删改查套路:抽象成通用方法

管理员要对用户、诗词、朝代、类别、通知做增删改查。如果每个 Controller 都写一遍 CRUD,代码会膨胀得很厉害。常见做法是定义一个 BaseService 把通用的「逻辑删除、分页查询」抽象出去:

public abstract class BaseServiceImpl<T> { @Autowired protected BaseMapper<T> baseMapper; public PageInfo<T> page(Integer pageNum, Integer pageSize) { PageHelper.startPage(pageNum, pageSize); List<T> list = baseMapper.selectList(null); return new PageInfo<>(list); } public boolean deleteById(Integer id) { return baseMapper.deleteById(id) > 0; } }

然后让PoetryTypeServiceImpl、DynastyServiceImpl继承它,自己只写特殊方法。好处很明显:朝代和类别表的结构几乎一样,继承之后代码量能压缩一半。管理员审核分享内容的接口也不复杂:查status = 0的列表,点击通过就把status改成 1。关键点是审核动作要记录操作管理员 ID 和审核意见,万一误审还能追溯。

5.3 避坑与排查:五条真实踩坑记录

坑一:全项目编译后才能跑?还原源码时不要漏反编译

现象:拿到资源包后SpringBoot启动正常,但一访问页面就报 404 或类找不到,排查半天发现 resources 目录下没有 mapper XML 文件。 原因:课设资源交付时往往只给了编译后的 class,没有把源码 XML 和前端页面一起打包,启动不报错是因为 class 在,访问报错是因为映射文件缺失。 解决:用反编译工具(比如 jd-gui)打开PoetryController.class等文件,先恢复 Controller 层的访问路径,再用 IDEA 的 FernFlower 把 class 整体反编译回 Java 源码。拿到源码后,补建resources/mapper目录,把 XML 文件放回去,再检查application.yml里的mybatis.mapper-locations配置路径是否匹配。

坑二:MySQL 8.0 驱动连接失败,启动报 SSL 错误

现象:本地明明装了 MySQL,SpringBoot 启动时却报Communications link failure或者 SSL 连接错误。 原因:课设资源大概率是基于 MySQL 5.7 写的,pom 里引入的是老版驱动路径。MySQL 8.0 之后驱动类名变成了com.mysql.cj.jdbc.Driver,连接串还必须指定时区。 解决:pom 里把mysql-connector-java版本升级到 8.x(或让 SpringBoot 依赖管理自动选择),application.yml的连接串改成jdbc:mysql://localhost:3306/poetry?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8。useSSL=false不是必须,但能省掉一堆证书警告。

坑三:中文乱码,全文都是问号

现象:页面标题、用户昵称正常,但诗词正文和评论全是????。 原因:数据库连接串没配characterEncoding=utf8,加上建表时用了默认的latin1字符集。 解决:utf8mb4对生僻字的支持比utf8更完整,建议建库时执行CREATE DATABASE poetry DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;,已有表则用ALTER TABLE poetry CONVERT TO CHARACTER SET utf8mb4;转换。同时确认application.yml里连接串包含characterEncoding=utf8,这是最容易漏的一环。

坑四:PageHelper 分页失效,一页返回所有数据

现象:第一次查询正常,第二次点下一页发现数据没变,控制台打出的 SQL 没有 LIMIT。 原因:PageHelper.startPage(pageNum, pageSize)只对紧随其后的一条 SQL 生效。如果代码里在它和 Mapper 调用之间执行了其他查询,比如提前查了一次用户信息,分页就作用到那条 SQL 上去了。 解决:把PageHelper.startPage放在 Mapper 方法调用之前、且两者之间不做任何其他数据库操作。推荐直接在 Controller 层完成「设分页参数 -> 调 service 查列表」的顺序,Service 里不要再启动新的分页页。

坑五:管理员接口裸奔,任何人都能调

现象:前端隐藏了管理入口,但用 Postman 直接请求/admin/deletePoetry?id=1居然成功了。 原因:只在前端做了按钮级权限隐藏,后端没有校验角色。 解决:按 5.1 节配置AdminInterceptor,并在WebConfig中注册。另外提醒一句:User实体里的role字段建议用Integer而不是boolean,为将来扩展「运营人员」「超级管理员」等角色留余地。

6. 跑通与进阶:从本地验证到答辩加分技巧

完整跑通这套项目的验证顺序,比直接打开浏览器点一圈更重要。我先说本地部署的三个必做步骤。第一步,确认 MySQL 和 JDK 环境,MySQL 8.0 与 Java 8 以上是标配,java -version和mysql --version各敲一遍。第二步,新建数据库并导入建表 SQL,导入成功后重点检查poetry、collection、user三张表是否出现。第三步,改application.yml,MySQL 密码千万别用123456写死在代码里——哪怕只是课设,也建议用@Value读取环境变量。跑起来之后验证接口,我的习惯是准备一个最小测试清单:

验证点请求示例预期结果
搜索接口GET /poetry/search?keyword=月返回包含「月」的诗词分页列表
收藏幂等连续两次POST /collection/add第二次返回已收藏提示或自动取消
管理员鉴权未登录访问GET /admin/notice/listHTTP 401,提示未登录
审核状态流上传分享后查列表用户端不显示,管理端待审核列表显示

验证通过后,答辩想加分可以做三个低成本改进。第一,把HikariCP连接池参数调出来,在配置里加上maximum-pool-size: 10、connection-timeout: 30000,老师问「数据库连接池怎么配置的」你就有话可说。第二,给/poetry/recommend加一个Redis缓存,把热门诗词缓存 10 分钟,这是最有性价比的进阶亮点。第三,用 Knife4j 生成接口文档,Controller 上写几个@ApiOperation注解,展示时直接给老师看接口面板,比对着代码讲直观得多。

最后分享一个我自己的教训。早期做课设时,我拿到资源包直接打开 IDEA 就开始跑,结果被一堆 class 文件绕晕了三天。从那以后,我每次拿到课设资源包的第一件事是「盘点源码完整性」:先统计.java文件数量,再看有没有resources目录和 SQL 脚本,最后看 pom.xml 的依赖版本。这个动作花不了五分钟,但能避免把大量时间浪费在与代码无关的环境问题上。这套古诗词学习网站本身结构清楚,只要你照着我上面列的类映射和表设计走一遍,两三天就能把它梳理成自己能讲明白的项目。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 2:35:46

T级大流量攻击防御实战:高防IP与流量清洗架构指南

1. 面对T级大流量攻击&#xff0c;先弄清楚你接到了什么“流量”先说句实话&#xff1a;很多人对“T级大流量攻击”没有概念&#xff0c;以为就是带宽被占满、网站变慢而已。真到了那个量级&#xff0c;你会发现情况完全不是这样——机房交换机端口被打满只是最低级的症状&…

作者头像 李华
网站建设 2026/10/2 2:35:30

Python入门到精通:这7个核心知识点你必须掌握

一、数据类型与可变性&#xff0c;一切bug的源头字符串、列表、元组、字典、集合&#xff0c;各有各的脾气。最要命的是可变与不可变的区别。你把列表当参数传给函数&#xff0c;函数里改了它&#xff0c;外面也跟着变——这不是bug&#xff0c;是你没搞懂引用传递。默认参数千…

作者头像 李华
网站建设 2026/10/2 2:34:27

讯灵AiGEO系统支持定制化参数配置,适用于深圳本地化部署

AI搜索时代来临&#xff0c;GEO优化正成为企业获客新赛道随着豆包、DeepSeek、通义千问、Kimi、腾讯元宝等AI大模型的普及&#xff0c;越来越多用户习惯通过AI问答直接获取答案&#xff0c;传统搜索引擎的流量入口地位正在被重新分配。GEO(生成式引擎优化)作为2025年才出现的新…

作者头像 李华
网站建设 2026/10/2 2:34:26

手语识别系统全流程避坑:从zip伪加密到关键点提取与CNN+LSTM部署

简介&#xff1a;手语识别是深度学习在视频理解中的典型应用。这套基于深度学习的手语识别系统&#xff0c;以Python编写&#xff0c;从数据预处理、模型构建到训练测试均提供完整代码&#xff0c;适合毕业设计、期末大作业及人工智能实践参考。系统核心网络融合多层卷积、池化…

作者头像 李华
网站建设 2026/10/2 2:33:27

揭秘当下知名的SEO优化渠道,你知道几个?

痛点深度剖析我们团队在实践中发现&#xff0c;当下SEO优化领域存在诸多痛点。在流量获取方面&#xff0c;SEO见效慢&#xff0c;很多企业做了半年优化&#xff0c;关键词排名却毫无变化&#xff1b;SEM则烧钱快&#xff0c;谷歌广告点击成本不断攀升&#xff0c;投资回报率难以…

作者头像 李华
网站建设 2026/10/2 2:33:05

美国载人飞船Crew-13明晚发射!

美国载人飞船Crew-13明晚发射&#xff01;计划7小时50分对接&#xff0c;冲刺空间站最快纪录 摘要&#xff1a;NASA 的 Crew-13 载人飞船计划于北京时间 10 月 1 日 23:10 发射&#xff0c;目标在 7 小时 50 分内与国际空间站完成对接&#xff0c;有望刷新美国载人飞船最快对接…

作者头像 李华