SpringBoot+Vue+MyBatis+MySQL前后端分离动漫网站系统部署实战
上个月在群里又看到有人问想搭一个国产动漫资讯站自己练手用前后端要分离技术栈别太老也别太花哨有没有能从零跑到线上的完整方案我当时直接把手上一套整理过的项目丢了过去就是标题里这套 SpringBoot Vue MyBatis MySQL 的国产动漫网站系统。后端只出 JSON 接口前端负责页面渲染源码、数据库脚本、部署文档都齐全照着步骤执行就能把整个网站跑起来。如果你正在学 Java 全栈想找一个能写进简历的完整项目或者你正在准备毕业设计需要一个前后端分离的实战案例再或者你只是想把自己收藏的动漫资料整理成一个带后台管理功能的站点这套系统的链路基本覆盖了所有环节。我下面会把功能拆解、技术选型逻辑、核心接口实现、前端页面设计、完整部署步骤以及我实际开发中踩过的坑都写清楚。1. 先看项目长什么样页面、角色和功能拆分1.1 用户能看到的页面从首页到详情页这个项目不是那种只有一个 CRUD 表格的后台管理系统而是有完整前台展示功能的动漫内容站。前台部分我按正常用户浏览习惯拆成了几个页面首页是整个项目的门面顶部是导航栏中间是 banner 轮播区下面是按照点击量排名的热门动漫卡片墙底部带分页。首页数据来自后端的列表接口前端通过 axios 请求拿到数据后用 v-for 渲染卡片点卡片就跳详情页。列表页承担分类筛选和搜索能力。用户可以从顶部导航点“全部动漫”进入也可以点某个分类标签进入。页面上有筛选条件栏支持按动漫类型、年份、地区组合筛选关键词搜索走的是单独接口。这个页面我用的是动态路由同一个页面组件通过 URL 上的 query 参数区分当前是分类列表还是搜索列表。详情页展示单个动漫的完整信息封面大图、标题、类型标签、地区、年份、状态、剧情简介、收藏按钮。这里需要注意详情页的路由是/detail/:id进入页面后要根据 id 调后端接口拿详情数据。登录注册页面走的是表单校验前端校验手机号格式、密码长度通过后请求后端登录接口拿到 JWT 令牌存到本地存储后续请求都在请求头里带上这个令牌。个人中心目前只做了“我的收藏”和“退出登录”两个核心功能收藏列表是用户登录后通过 userId 查询出来的。考虑到收藏本身是用户数据里最有代表性的功能所以我把它的前后端链路完整实现了后续加评论、历史记录也都是同样的套路。1.2 管理员后台不只是增删改查后台管理部分我单独做了一套页面入口在登录页的“管理员登录”按钮默认给了一个管理员账号。后台主要由四个功能块组成仪表盘页面显示基础统计数字动漫总数、分类总数、注册用户数、收藏总数。这个功能不复杂本质是后端提供几个 count 统计接口前端用数字卡片展示但对管理员来说一眼能看出站点规模非常实用。动漫管理页面是后台最核心的模块。管理员可以在表格中看到所有动漫条目支持标题搜索可以新增动漫、编辑已有条目、删除条目、上传封面图。新增和编辑共用同一个弹窗表单表单里包含标题、分类、地区、年份、简介、封面地址这些字段。分类管理就是非常直白的增删改查三个字段分类名称、排序值、备注。我提醒一句分类删除时要判断该分类下是否还有动漫数据否则会出现前台列表“孤儿数据”这点很多人刚开始做会漏掉。用户管理页面展示注册用户列表支持搜索和禁用操作。禁用用户后该用户的 JWT 令牌在鉴权拦截器中会被判定为无效这比只删 token 要优雅得多。1.3 三种角色怎么划分权限整个系统按角色分成三类游客、注册用户、管理员。我做权限的思路很直接后端拦截器按 URL 前缀区分游客不需要登录能访问的接口是首页列表、分类列表、详情、搜索这些公开接口注册用户可以访问收藏相关接口管理员可以访问/api/admin/**下的所有接口。前端也做了对应的路由守卫个人中心需要登录后才能进入后台管理页面需要本地存储里有管理员身份标识才能进入。角色可访问页面可执行操作身份验证游客首页、列表页、详情页浏览、搜索、查看详情无注册用户以上全部 个人中心收藏动漫、取消收藏、退出登录JWT 令牌管理员以上全部 后台管理页动漫增删改、分类管理、用户管理、统计查看JWT 令牌 管理员角色校验这套权限模型虽然简单但覆盖了绝大多数内容站点的基本需求。如果后续要加评论、点赞只需要在拦截器里配置对应的接口路径和角色即可。2. 技术选型不是拍脑袋四个核心组件各自解决了什么问题2.1 SpringBoot把后端开发从“配置地狱”里解放出来早期做 Java Web最麻烦的不是写业务代码而是配置各种 XML。一个 SSM 项目要配 web.xml、Spring 配置、SpringMVC 配置、MyBatis 配置还要处理各类 jar 包依赖冲突。SpringBoot 的核心价值是约定优于配置你只需要引入spring-boot-starter-web再配合自动配置就能直接写 Controller。这个项目中我只是按标准的分层结构组织代码Controller 接收请求和参数Service 处理业务逻辑Mapper 操作数据库。SpringBoot 的依赖注入很好地解耦了三层比如 Controller 里不用手动 new Service直接Autowired注进来就行。实际开发中我还有一个习惯所有接口返回统一的数据结构ResultT包含 code、msg、data 三个字段。这样前端在做 axios 响应拦截时只需要判断 code 是否为 200不用针对每个接口单独解析异常结构非常省事。2.2 Vue为什么放弃 JSP改用前后端分离如果说 JSP 时代的典型问题是 HTML、CSS、Java 代码全混在一起那前后端分离的核心思路就是“后端不懂页面前端不懂数据库”。后端把数据通过 JSON 接口吐出来前端只负责把数据渲染成页面。这样两边可以独立开发、独立部署接口约定好就能并行推进。Vue 在这个项目里的优势主要体现在三方面第一组件化非常方便动漫卡片、分页器、搜索表单、后台表格都能抽成独立组件复用第二响应式数据绑定让“请求数据—填充页面”这个操作变成了直接给 data 赋值视图自动更新第三生态成熟Element Plus 提供了后台管理需要的表格、表单、弹窗、上传组件UI 不用从头写。我选择 Vue3 Vite 而不是 Vue2 Webpack是因为 Vite 在开发模式下冷启动和热更新速度都明显更快对本地调试体验提升很大。2.3 MyBatis MySQL查询要掌控在自己手里有人问为什么不用 JPA我的回答很实际列表页的搜索、筛选、分类统计这类场景需要对 SQL 有精确控制能力。JPA 擅长单表 CRUD 和简单的关联查询但一旦出现多条件动态拼接、多表关联、复杂统计这类查询调优 SQL 就会很别扭。MyBatis 是半自动 ORMSQL 由开发者手写参数映射和结果映射交给框架处理。这样既保留了 SQL 的灵活性又解决了手动操作 JDBC 那套繁琐的ResultSet映射问题。在这个项目里动漫列表的分页查询、收藏列表的关联查询、后台的统计查询我都写了对应的 Mapper XML逻辑一目了然。MySQL 那边没什么好说的稳定、部署轻量、资料多对一个学习项目来说完全够用。数据库设计时我特意统一了字符集为utf8mb4否则存中文标题和简介时很容易出现乱码。2.4 推荐技术栈版本组合如果照着这个项目做我建议版本按这个组合来都验证过能正常跑组件推荐版本说明JDK1.8 或 17两者都可以SpringBoot 2.7 兼容SpringBoot2.7.x稳定学习资料多MyBatis3.5.x mybatis-spring-boot-starter 2.x半自动 ORM 标准配置MySQL8.0.x字符集记得用 utf8mb4Vue3.x组合式 API 写起来更顺手Vite4.x开发服务器和构建工具Element Plus2.x后台页面 UI 组件库Node.js16.x 或 18.x运行前端脚手架和构建命令3. 后端核心实现一个“动漫列表页”身后的完整链路3.1 核心表结构设计数据库我命名为anime_db核心表包括系统用户表、管理员表、动漫分类表、动漫信息表、收藏表。下面是精简后的建表语句我在每个表里都加了必要的索引和注释方便直接导入CREATE DATABASE anime_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 用户ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名, password VARCHAR(100) NOT NULL COMMENT BCrypt加密后的密码, avatar VARCHAR(255) DEFAULT NULL COMMENT 头像地址, status TINYINT DEFAULT 1 COMMENT 1启用 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间 ) COMMENT 系统用户表; CREATE TABLE sys_admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL ) COMMENT 管理员表; CREATE TABLE anime_category ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 分类名称, sort INT DEFAULT 0 COMMENT 排序值越小越靠前, remark VARCHAR(255) DEFAULT NULL ) COMMENT 动漫分类表; CREATE TABLE anime_info ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL COMMENT 动漫标题, cover_url VARCHAR(255) COMMENT 封面图片地址, intro TEXT COMMENT 剧情简介, category_id INT COMMENT 所属分类ID, area VARCHAR(30) COMMENT 地区, publish_year INT COMMENT 上映年份, status TINYINT DEFAULT 1 COMMENT 1连载中 2已完结, click_count INT DEFAULT 0 COMMENT 点击量, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_category (category_id), KEY idx_publish_year (publish_year) ) COMMENT 动漫信息表; CREATE TABLE anime_favorite ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, anime_id INT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_anime (user_id, anime_id) ) COMMENT 用户收藏表;这里有两个设计细节值得说明。第一密码字段存的是 BCrypt 加密后的密文绝不能存明文第二收藏表加了(user_id, anime_id)唯一索引从数据库层面防止用户重复收藏比前端判重可靠得多。3.2 RESTful 接口规划前后端分离项目的关键约定是接口文档。我按 RESTful 风格规划了主要接口前端调用时基本不用想太多路径和请求方式一目了然方法路径功能是否需要登录GET/api/anime/list分页查询动漫列表支持分类、年份、地区筛选否GET/api/anime/{id}根据ID查询动漫详情否GET/api/anime/search按关键词搜索动漫否GET/api/category/list获取全部分类否POST/api/user/login用户登录否POST/api/user/register用户注册否GET/api/user/favorites获取当前用户收藏列表是POST/api/user/favorite/{animeId}添加收藏是DELETE/api/user/favorite/{animeId}取消收藏是GET/api/admin/statistics后台统计管理员POST/api/admin/anime新增动漫管理员PUT/api/admin/anime编辑动漫管理员DELETE/api/admin/anime/{id}删除动漫管理员3.3 MyBatis 动态 SQL 与分页查询动漫列表是最典型的动态查询场景分类不为空时拼分类条件关键词不为空时拼模糊搜索条件年份区间不为空时拼年份条件。这种需求用 MyBatis 的if标签非常清晰。我直接用 PageHelper 做物理分页一行代码就能在查询前拦截并自动生成 LIMIT 语句// Service 层代码 public PageResultAnimeVO pageAnime(Integer pageNum, Integer pageSize, Integer categoryId, String keyword, Integer year) { PageHelper.startPage(pageNum, pageSize); ListAnimeVO list animeMapper.selectAnimePage(categoryId, keyword, year); PageInfoAnimeVO pageInfo new PageInfo(list); return PageResult.from(pageInfo); }对应的 Mapper XML 长这样注意我用了where标签它会智能去掉第一个多余的 ANDselect idselectAnimePage resultTypecom.example.anime.vo.AnimeVO SELECT a.id, a.title, a.cover_url, a.intro, a.publish_year, a.status, a.click_count, c.name AS category_name FROM anime_info a LEFT JOIN anime_category c ON a.category_id c.id where if testcategoryId ! null AND a.category_id #{categoryId} /if if testkeyword ! null and keyword ! AND a.title LIKE CONCAT(%, #{keyword}, %) /if if testyear ! null AND a.publish_year #{year} /if /where ORDER BY a.click_count DESC /select这里有个容易踩的坑如果只查动漫主表可以用 MyBatis 的自动驼峰映射但一旦 LEFT JOIN 分类表查询分类名称最好用 VO 对象接收把category_name这种带下划线的列直接映射到categoryName属性上避免前端拿到 null。3.4 登录鉴权拦截器 JWT整个鉴权链路是这样的用户登录成功后端生成一个 JWT 令牌返回给前端前端把令牌存到 localStorage每次请求在 axios 拦截器里加上Authorization: Bearer token后端定义一个登录拦截器拦截需要认证的路径解析令牌成功后把用户信息放入上下文。核心代码大致如下// 登录 Service Override public Result login(String username, String password) { SysUser user userMapper.findByUsername(username); if (user null || !BCrypt.checkpw(password, user.getPassword())) { return Result.error(用户名或密码错误); } if (user.getStatus() 0) { return Result.error(账号已被禁用); } String token JwtUtil.createToken(user.getId(), user.getUsername(), user); return Result.success(Collections.singletonMap(token, token)); }注册的时候密码一定用BCrypt.hashpw(password, BCrypt.gensalt())加密后再入库。千万不要用 MD5现在 MD5 加盐都很容易被彩虹表破解BCrypt 是行业标准做法。拦截器里我做了一个比较实用的设计从 token 中解析出用户的角色字段如果是/api/admin/**开头的路径且角色不是 admin直接返回 403。这样后台接口和普通用户接口共用一个拦截器只是通过路径前缀做了一次角色判断。4. 前端实现思路Vue Router、Axios 与组件拆分4.1 前端工程结构前端我用 Vite 创建项目整个src目录结构如下src/ api/ anime.js # 动漫相关接口 user.js # 用户登录注册收藏 admin.js # 后台管理接口 assets/ # 静态资源 components/ AnimeCard.vue # 动漫卡片组件 Pagination.vue# 分页组件 router/ index.js # 路由配置 store/ user.js # 用户状态 views/ Home.vue AnimeList.vue AnimeDetail.vue Login.vue UserCenter.vue admin/ Dashboard.vue AnimeManage.vue CategoryManage.vue UserManage.vue main.js App.vue这种按功能模块分目录的方式可能和网上很多教程不一样但实际维护下来很清晰。api目录单独放接口请求函数页面组件里不直接写 axios 代码只调用 api 模块暴露的函数。这样以后后端地址变了只需要改一个配置文件。4.2 路由与导航守卫路由配置使用了 Vue Router 4。一个设计上的关键点是详情页和后台页面用动态路由和懒加载避免首屏一次性加载所有页面代码const routes [ { path: /, name: Home, component: () import(/views/Home.vue) }, { path: /list, name: AnimeList, component: () import(/views/AnimeList.vue) }, { path: /detail/:id, name: AnimeDetail, component: () import(/views/AnimeDetail.vue) }, { path: /login, name: Login, component: () import(/views/Login.vue) }, { path: /user, name: UserCenter, component: () import(/views/UserCenter.vue), meta: { requiresAuth: true } }, { path: /admin, component: () import(/views/admin/Layout.vue), meta: { requiresAdmin: true }, children: [ { path: , redirect: /admin/dashboard }, { path: dashboard, component: () import(/views/admin/Dashboard.vue) }, { path: anime, component: () import(/views/admin/AnimeManage.vue) }, { path: category, component: () import(/views/admin/CategoryManage.vue) }, { path: user, component: () import(/views/admin/UserManage.vue) } ] } ]导航守卫做两件事一是检查meta.requiresAuth没登录就跳登录页并带上回跳地址二是检查meta.requiresAdmin本地存储里没有管理员标识就提示无权限并跳回首页。4.3 Axios 封装与状态管理整个前端共用一个 axios 实例我在api/request.js里做了统一封装import axios from axios const request axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { if (res.code 401) { localStorage.removeItem(token) window.location.href /login } return Promise.reject(new Error(res.msg)) } return res.data }, error Promise.reject(error) ) export default request用户状态我用一个轻量的 store 来管理存了用户 id、用户名、是否管理员。每次刷新页面时会先从 localStorage 里恢复基础信息如果登录过期请求接口时会收到 401响应拦截器自动清掉本地身份并跳转登录页。4.4 核心组件怎么拆分动漫卡片是比较典型的复用组件在首页、列表页、后台表格弹窗里都会用到。我把AnimeCard.vue设计成一个纯展示组件只接收一个anime对象作为 prop输出封面、标题、点击量和分类名称template div classanime-card clickgoDetail img :srcanime.coverUrl alt封面 / h3{{ anime.title }}/h3 div classmeta span{{ anime.categoryName }}/span span{{ anime.clickCount }} 次浏览/span /div /div /template script setup import { useRouter } from vue-router const props defineProps({ anime: { type: Object, required: true } }) const router useRouter() function goDetail() { router.push(/detail/${props.anime.id}) } /script这样设计的价值在于前端组件关注点分离展示逻辑写在组件内部数据获取留在页面组件里。排查问题时如果数据不对就查页面组件和接口如果展示不对就查卡片组件不用在几百行代码里翻来翻去。5. 从零到一本地完整部署运行看这篇就够5.1 环境准备清单部署之前先确认本机安装了以下基础环境。没有安装的可以先去官网下载这里不展开安装细节软件最低版本要求检查命令JDK1.8 或 17java -versionMaven3.6mvn -vNode.js16node -vMySQL8.0mysql --versionGit可选git --version我建议把 MySQL 字符集设置成 utf8mb4这样既能兼容中文又能支持将来存 emoji 表情避免出现存储时截断报错的问题。5.2 初始化数据库拿到项目源码后找到sql/anime_db.sql这个脚本文件。用命令行导入或者用可视化工具执行都行mysql -u root -p anime_db anime_db.sql如果你用的是 Navicat直接连接数据库后新建库再右键运行 SQL 文件即可。脚本里除了五张核心表还预置了管理员账号admin / admin123、一个测试用户账号以及几十条虚构的动漫演示数据。导入完成后可以用下面这条 SQL 做一次完整验证确认分类表和数据表关联正常SELECT a.title, c.name, a.publish_year FROM anime_info a LEFT JOIN anime_category c ON a.category_id c.id LIMIT 10;5.3 后端配置修改与启动后端项目根目录下有src/main/resources/application.yml核心配置就是数据源和 JWT。打开文件把数据库账号密码改成你本机的值server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/anime_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true jwt: secret: your-custom-secret-key expire: 604800然后启动后端两种方式# 方式一开发调试模式 mvn spring-boot:run # 方式二打包后运行 mvn clean package -DskipTests java -jar target/anime-server.jar启动成功后后端会监听 8080 端口。可以用浏览器直接访问http://localhost:8080/api/category/list如果能看到 JSON 数据说明后端已经正常工作了。这一步是排查问题的快速抓手我强烈建议在碰前端之前先验证后端接口。5.4 前端依赖安装与开发模式启动前端目录是web/。先进入目录安装依赖cd web npm install npm run dev默认启动端口是 5173。此时浏览器访问http://localhost:5173页面会通过 Vite 的代理把/api开头的请求转发到后端 8080 端口。代理配置在vite.config.js里export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })到这里前后端已经联调通了。你可以试试注册一个账号、给某条动漫加收藏、退出登录再从管理员入口进入后台体验完整权限链路。5.5 打包发布部署如果要上线前后端要分开部署。前端跑构建命令cd web npm run build构建完成后dist目录里的静态文件放到 Nginx 的 html 目录然后配置反向代理把/api请求转发给 Java 服务server { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }注意如果后端单独跑在云服务器上记得在安全组放行 8080 端口或者只通过 Nginx 反向代理暴露 80后端 8080 不直接对外开放。这是基本的端口安全习惯。6. 我实际开发中踩过的坑以及后续优化方向6.1 跨域问题前后端联调第一关前后端分离开发时前端跑在 5173后端跑在 8080端口不同必然产生跨域。我最初直接用后端解决写了一个全局 CorsFilter后来发现这样得在生产环境也处理而且要是以后前端域名变了配置都得跟着改。更好的方案是开发环境用 Vite 代理生产环境用 Nginx 反向代理。这样从浏览器看所有请求都是同源的跨域问题在后端根本不出现。如果你非要在后端配置跨域可以这样Configuration public class WebConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowCredentials(true); } }6.2 MyBatis 字段映射下划线转驼峰的坑这个坑非常隐蔽。数据库字段是publish_yearJava 实体属性是publishYear没有配置驼峰映射时MyBatis 会把查询结果里的publish_year字段赋值给publishYear失败页面上的年份显示就是 null。解决办法是全局开启驼峰映射在application.yml里加上mybatis: configuration: map-underscore-to-camel-case: true万一加了之后某个字段还是 null就要检查 Mapper XML 里是不是手动写了 resultMap手动 resultMap 会覆盖全局配置这时需要自己在 resultMap 里显式做columnpublish_year propertypublishYear映射。6.3 图片资源访问 404后台封面上传后图片会保存到本地磁盘的upload目录。默认情况下 SpringBoot 不会把项目外的路径当作静态资源处理直接访问/upload/xxx.jpg会 404。我在项目里写了一个资源映射配置把/upload/**映射到本地绝对路径Configuration public class FileConfig implements WebMvcConfigurer { Value(${file.upload-dir}) private String uploadDir; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: uploadDir /); } }生产环境上线前建议把上传目录改成独立磁盘路径别放在项目 jar 包同一级目录下不然升级部署时容易把用户上传的图片清掉。6.4 慢查询与索引优化功能开发完还没有真正跑起来之前我先往动漫表里插了 2 万条测试数据实测发现列表页首次响应稳定在 1.5 秒左右明显偏慢。用 EXPLAIN 看执行计划后发现WHERE category_id xxx ORDER BY click_count DESC这条查询走了全表扫描。解决办法很简单给高频查询字段加索引ALTER TABLE anime_info ADD INDEX idx_category_click (category_id, click_count);加完索引后同一查询耗时降到 0.05 秒左右。这个优化思路放在任何项目里都通用先排查慢 SQL再针对 WHERE 和 ORDER BY 的字段建立联合索引。需要提醒的是LIKE %关键词%这种模糊查询即使有索引也用不上所以搜索量不大时可以先接受后面量大了再考虑全文索引方案。6.5 后续可以继续扩展的方向这套系统目前已经完成了内容展示、分类检索、用户收藏、后台管理这几条完整链路后续如果还想继续加内容我建议按下面顺序扩展评论模块动漫详情页加评论区核心是新增评论表和用户关联查询。每日推荐在首页加一个“小编推荐”区块后台可以设置推荐套餐。浏览历史记录用户最近浏览的动漫列表就是收藏表加一个历史记录表。数据缓存热点列表接口加 Redis 缓存降低 MySQL 压力。我个人的习惯是每完成一个独立功能模块就顺手用 Postman 把接口全部过一遍再回到前端验证页面。这样排查问题很快基本不会出现攒了一堆 Bug 最后一起炸的情况。这套动漫网站系统做到当前程度已经能把 SpringBoot、MyBatis、Vue 三者的核心配合逻辑完整跑明白照着这份部署文档实操一遍你对前后端分离项目的理解会上一个台阶。

相关新闻

从零搭建可视化图表设计工具:数据模型、SVG渲染与工程化实践

从零搭建可视化图表设计工具:数据模型、SVG渲染与工程化实践

1. 从零搭建 diagram-design 项目:一个可视化图表设计工具的完整落地记录第一次看到diagram-design这个项目名的时候,我脑子里蹦出来的第一个念头是:这又是一个"画图工具"?市面上流程图、架构图、思维导图的工具已经多到…

2026/10/17 4:15:03 阅读更多 →
artcraft项目实战:从草图到成品的可复现创作流程设计

artcraft项目实战:从草图到成品的可复现创作流程设计

1. 从“artcraft”这个名字说起:它到底想解决什么问题第一次看到“artcraft”这个项目标题,我的直觉是:这大概率是一个把“艺术创作”和“手工实现”捏在一起的东西。拆开看,art 指向审美、设计、视觉表达,craft 指向手…

2026/10/17 4:15:03 阅读更多 →
拼多多客服机器人开发实战:从Webhook接入到自动回复

拼多多客服机器人开发实战:从Webhook接入到自动回复

简介:面向拼多多商家的智能客服机器人解决方案,基于官方平台插件接入,可稳定处理大量用户咨询,支持人机全程协作,并在语义理解、情感分析等AI能力辅助下提升回复质量与客户体验。资源包共18个文件,压缩后约…

2026/10/17 4:14:03 阅读更多 →

最新新闻

12月PMP第八版新纲首考,老题库还能刷吗?

12月PMP第八版新纲首考,老题库还能刷吗?

距离12月PMP考试越来越近,最近后台被问得最多的一个问题就是:"第八版新纲来了,我手里第七版的资料和旧题库还能不能用?"这个问题看似简单,实则关系到接下来两个多月的备考方向。用错资料,等于花双…

2026/10/17 6:48:00 阅读更多 →
用四类订单现场验证生产型ERP:改期、缺料、返工与交付

用四类订单现场验证生产型ERP:改期、缺料、返工与交付

生产型ERP演示别只看模块:拿四种真实业务逐项验证选型演示如果只展示销售、采购、库存、生产和财务菜单,难以判断订单变更是否会影响后续业务。更有效的办法是带入企业自己的单据,检查数据从哪里来、经过什么规则、由哪个岗位确认&#xff0c…

2026/10/17 6:48:00 阅读更多 →
大厂AI校招薪资大揭秘!小白也能看懂,高薪Offer收藏起来!

大厂AI校招薪资大揭秘!小白也能看懂,高薪Offer收藏起来!

文章详细对比了腾讯、字节、阿里、华为、蚂蚁等互联网大厂AI校招的薪资情况,包括不同岗位的薪资福利待遇。内容涵盖了从普通岗位到天才少年的薪资差异,以及各公司的核心福利,如股票、期权、住房补贴、落户支持等。文章提醒读者注意薪资构成&a…

2026/10/17 6:48:00 阅读更多 →
13|知识入库:从原始文档到可检索索引 - eino教程

13|知识入库:从原始文档到可检索索引 - eino教程

13|知识入库:从原始文档到可检索索引 《Eino 实战:用 Go 构建 AI 应用与智能体》 第 13 篇 关键词:Document Loader、Transformer、Embedding、Indexer、切分、元数据 前置条件:已完成 11|Tool 与 ToolsNod…

2026/10/17 6:48:00 阅读更多 →
普通宽带 + SD-WAN,真的能替代昂贵专线吗?稳定性与安全性深度解析

普通宽带 + SD-WAN,真的能替代昂贵专线吗?稳定性与安全性深度解析

在企业数字化转型的浪潮中,多分支互联、混合云接入、SaaS 应用普及正在重构企业广域网的需求模型。沿用了二十余年的 MPLS 专线,曾经是企业组网的 "标准答案",如今却在成本、部署效率与业务灵活性上频频遭遇瓶颈。与此同时&#xf…

2026/10/17 6:48:00 阅读更多 →
雷达点云地面过滤:为什么Ray Filter比RANSAC更适配激光扫描物理特性

雷达点云地面过滤:为什么Ray Filter比RANSAC更适配激光扫描物理特性

简介:本资源是一个面向ROS机器人开发者的点云地面滤除实践项目,聚焦于自动驾驶与移动机器人环境感知中的关键预处理环节——利用Ray Filter算法高效分离地面与非地面点云。项目基于PCL库实现,封装为可直接编译运行的ROS节点,适用于…

2026/10/17 6:47:00 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →