ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot3+Vue3全栈漫画平台开发实战:从环境搭建到多端部署

SpringBoot3+Vue3全栈漫画平台开发实战:从环境搭建到多端部署 最近在开发漫画阅读类项目时发现很多开发者对如何构建一个完整的全栈平台存在困惑特别是SpringBoot3和Vue3的技术整合。本文将分享一套基于SpringBoot3Vue3的漫小天漫画阅读平台完整实现方案涵盖Web管理端、微信小程序端和H5端包含从环境搭建到生产部署的全流程。1. 项目背景与技术选型1.1 项目需求分析漫小天漫画阅读平台需要满足多端用户需求管理员通过Web后台管理漫画内容用户通过微信小程序和H5页面阅读漫画。核心功能包括漫画分类管理、章节阅读、用户收藏、搜索推荐等。1.2 技术栈选择理由选择SpringBoot3作为后端框架因其提供了更现代化的Java开发体验支持GraalVM原生镜像编译。Vue3作为前端框架组合式API更适合复杂业务逻辑。微信小程序采用uni-app框架可实现一套代码多端发布。1.3 架构设计概述系统采用前后端分离架构后端提供RESTful API前端通过HTTP请求交互。数据库使用MySQL存储业务数据Redis缓存热点数据阿里云OSS存储漫画图片资源。2. 开发环境准备2.1 基础环境配置操作系统Windows 10/11 或 macOS 12JDK版本OpenJDK 17SpringBoot3最低要求Node.js版本16.20.2 LTS开发工具IntelliJ IDEA VS Code数据库MySQL 8.0 Redis 7.02.2 后端依赖配置创建SpringBoot3项目时在pom.xml中添加核心依赖dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.18/version /dependency /dependencies2.3 前端环境搭建Vue3项目初始化及依赖安装# 创建Vue3项目 npm create vuelatest manxiao-tian-admin cd manxiao-tian-admin # 安装必要依赖 npm install element-plus element-plus/icons-vue npm install axios vue-router4 pinia3. 数据库设计与核心表结构3.1 漫画相关表设计漫画表存储基本信息章节表管理漫画章节图片表存储具体页面CREATE TABLE comic ( id bigint NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL COMMENT 漫画标题, author varchar(50) DEFAULT NULL COMMENT 作者, cover_url varchar(255) DEFAULT NULL COMMENT 封面图, status tinyint DEFAULT 0 COMMENT 状态0-连载中 1-已完结, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE comic_chapter ( id bigint NOT NULL AUTO_INCREMENT, comic_id bigint NOT NULL COMMENT 漫画ID, chapter_number int NOT NULL COMMENT 章节序号, title varchar(100) NOT NULL COMMENT 章节标题, page_count int DEFAULT 0 COMMENT 页数, PRIMARY KEY (id), KEY idx_comic_id (comic_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 用户与阅读记录表用户表管理微信用户信息阅读记录表跟踪阅读进度CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, openid varchar(100) NOT NULL COMMENT 微信openid, nickname varchar(100) DEFAULT NULL COMMENT 昵称, avatar_url varchar(255) DEFAULT NULL COMMENT 头像, last_login_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE reading_history ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL, comic_id bigint NOT NULL, chapter_id bigint NOT NULL, current_page int DEFAULT 1 COMMENT 当前阅读页数, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_user_comic (user_id,comic_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;4. 后端核心功能实现4.1 SpringBoot3配置优化应用配置文件采用多环境配置数据库连接池使用Druid并开启SQL监控# application-dev.yml spring: datasource: url: jdbc:mysql://localhost:3306/comic_db?useUnicodetruecharacterEncodingutf8 username: root password: 123456 druid: filters: stat,wall stat-view-servlet: enabled: true login-username: admin login-password: admin mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl4.2 MyBatis Plus代码生成与CRUD使用MyBatis Plus代码生成器自动生成实体类和Mapper// Comic实体类 Data TableName(comic) public class Comic { TableId(type IdType.AUTO) private Long id; private String title; private String author; private String coverUrl; private Integer status; private LocalDateTime createTime; } // Service层实现 Service public class ComicService extends ServiceImplComicMapper, Comic { public PageComic searchComics(String keyword, PageComic page) { LambdaQueryWrapperComic wrapper Wrappers.lambdaQuery(); if (StringUtils.hasText(keyword)) { wrapper.like(Comic::getTitle, keyword) .or().like(Comic::getAuthor, keyword); } return baseMapper.selectPage(page, wrapper); } }4.3 微信小程序登录接口实现微信登录获取用户信息并生成JWT tokenRestController RequestMapping(/api/wx) public class WxLoginController { PostMapping(/login) public ResultLoginVO login(RequestBody LoginDTO loginDTO) { // 调用微信接口验证code String openid wxService.getOpenid(loginDTO.getCode()); if (openid null) { return Result.error(登录失败); } // 查询或创建用户 User user userService.getOrCreateUser(openid, loginDTO.getUserInfo()); // 生成JWT token String token jwtUtil.generateToken(user.getId()); return Result.success(new LoginVO(token, user)); } }5. Vue3管理端开发5.1 项目结构与路由配置采用Vue3组合式API路由按功能模块懒加载// router/index.js const routes [ { path: /, component: Layout, redirect: /dashboard, children: [ { path: dashboard, component: () import(/views/dashboard/index.vue), meta: { title: 仪表板 } }, { path: comic, component: () import(/views/comic/index.vue), meta: { title: 漫画管理 } } ] } ]5.2 漫画管理页面实现使用Element Plus组件构建数据表格和表单template div classcomic-management el-card template #header div classcard-header span漫画列表/span el-button typeprimary clickhandleAdd新增漫画/el-button /div /template el-table :datatableData v-loadingloading el-table-column proptitle label标题 width200 / el-table-column propauthor label作者 width120 / el-table-column propstatus label状态 width100 template #defaultscope el-tag :typescope.row.status 1 ? success : info {{ scope.row.status 1 ? 已完结 : 连载中 }} /el-tag /template /el-table-column el-table-column label操作 width200 template #defaultscope el-button sizesmall clickhandleEdit(scope.row)编辑/el-button el-button sizesmall typedanger clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-table el-pagination v-model:current-pagecurrentPage v-model:page-sizepageSize :totaltotal current-changehandlePageChange layouttotal, sizes, prev, pager, next, jumper / /el-card /div /template script setup import { ref, onMounted } from vue import { ElMessage, ElMessageBox } from element-plus import { getComicList, deleteComic } from /api/comic const tableData ref([]) const loading ref(false) const currentPage ref(1) const pageSize ref(10) const total ref(0) const loadData async () { loading.value true try { const res await getComicList({ page: currentPage.value, size: pageSize.value }) tableData.value res.data.records total.value res.data.total } catch (error) { ElMessage.error(加载失败) } finally { loading.value false } } const handleDelete async (row) { try { await ElMessageBox.confirm(确认删除该漫画, 提示, { type: warning }) await deleteComic(row.id) ElMessage.success(删除成功) loadData() } catch (error) { // 用户取消删除 } } onMounted(() { loadData() }) /script6. uni-app微信小程序开发6.1 项目初始化与配置创建uni-app项目并配置微信小程序相关设置// manifest.json { name: 漫小天漫画, appid: __UNI__XXXXXX, description: 漫画阅读小程序, versionName: 1.0.0, versionCode: 100, mp-weixin: { appid: wxxxxxxxxxxxxxxx, setting: { urlCheck: false }, usingComponents: true } }6.2 首页漫画列表实现使用uni-app的scroll-view组件实现下拉刷新和上拉加载template view classhome scroll-view scroll-y classscroll-view scrolltolowerloadMore refresher-enabled refresherrefreshonRefresh view classbanner swiper indicator-dots autoplay circular swiper-item v-foritem in banners :keyitem.id image :srcitem.image modeaspectFill / /swiper-item /swiper /view view classcomic-list view v-forcomic in comicList :keycomic.id classcomic-item clickgoDetail(comic.id) image :srccomic.coverUrl modeaspectFill classcover / text classtitle{{ comic.title }}/text text classauthor{{ comic.author }}/text /view /view view v-ifloading classloading加载中.../view view v-ifnoMore classno-more没有更多了/view /scroll-view /view /template script setup import { ref, onMounted } from vue import { onPullDownRefresh, onReachBottom } from dcloudio/uni-app const comicList ref([]) const currentPage ref(1) const loading ref(false) const noMore ref(false) const loadComics async (page 1, isRefresh false) { if (loading.value) return loading.value true try { const res await uni.request({ url: /api/comic/list, data: { page, size: 10 } }) if (isRefresh) { comicList.value res.data.data } else { comicList.value [...comicList.value, ...res.data.data] } noMore.value res.data.data.length 10 currentPage.value page } catch (error) { uni.showToast({ title: 加载失败, icon: none }) } finally { loading.value false uni.stopPullDownRefresh() } } const onRefresh () { loadComics(1, true) } const loadMore () { if (!noMore.value !loading.value) { loadComics(currentPage.value 1) } } onMounted(() { loadComics(1) }) // 监听下拉刷新 onPullDownRefresh(() { onRefresh() }) // 监听上拉触底 onReachBottom(() { loadMore() }) /script6.3 漫画阅读器实现实现左右滑动翻页和阅读进度记录template view classreader swiper :currentcurrentPage changeonPageChange classreader-swiper swiper-item v-forpage in pages :keypage.id image :srcpage.imageUrl modewidthFix classpage-image loadonImageLoad / /swiper-item /swiper view classreader-controls text classpage-info{{ currentPage 1 }} / {{ pages.length }}/text view classcontrols-right text classsetting-btn clickshowSetting true设置/text /view /view /view /template script setup import { ref, onMounted, onUnmounted } from vue const props defineProps({ chapterId: String }) const pages ref([]) const currentPage ref(0) const showSetting ref(false) const loadPages async () { try { const res await uni.request({ url: /api/chapter/${props.chapterId}/pages }) pages.value res.data.data } catch (error) { uni.showToast({ title: 加载失败, icon: none }) } } const onPageChange (e) { currentPage.value e.detail.current // 记录阅读进度 recordReadingProgress() } const recordReadingProgress () { uni.request({ url: /api/reading/progress, method: POST, data: { chapterId: props.chapterId, page: currentPage.value 1 } }) } onMounted(() { loadPages() }) onUnmounted(() { // 离开时保存最终进度 recordReadingProgress() }) /script7. 常见问题与解决方案7.1 微信小程序兼容性问题微信小程序环境与H5环境存在差异需要针对性处理// 环境判断与兼容处理 const isWeixin () { return typeof wx ! undefined wx.request } const request (options) { if (isWeixin()) { // 微信小程序请求 return new Promise((resolve, reject) { wx.request({ ...options, success: resolve, fail: reject }) }) } else { // H5环境使用axios return axios(options) } } // 图片下载兼容处理 const downloadImage (url) { if (isWeixin()) { return new Promise((resolve, reject) { wx.downloadFile({ url, success: (res) resolve(res.tempFilePath), fail: reject }) }) } else { // H5环境直接使用URL return Promise.resolve(url) } }7.2 图片加载优化方案漫画图片体积较大需要优化加载体验// 图片懒加载与预加载 class ImageLoader { constructor() { this.cache new Map() } async loadImage(url) { if (this.cache.has(url)) { return this.cache.get(url) } // 微信小程序使用本地缓存 if (isWeixin()) { try { const localPath await this.downloadToLocal(url) this.cache.set(url, localPath) return localPath } catch (error) { console.error(图片下载失败:, error) return url } } else { // H5环境直接使用网络图片 return url } } // 预加载下一章节图片 preloadImages(urls) { urls.forEach(url { this.loadImage(url).catch(() {}) }) } }7.3 数据同步与缓存策略多端数据同步需要合理的缓存策略Service public class ReadingProgressService { Autowired private RedisTemplateString, Object redisTemplate; // 保存阅读进度先写缓存再异步持久化 public void saveProgress(Long userId, Long chapterId, Integer page) { String key String.format(reading:%d:%d, userId, chapterId); // 写入Redis缓存 redisTemplate.opsForValue().set(key, page, Duration.ofHours(24)); // 异步持久化到数据库 CompletableFuture.runAsync(() - { ReadingHistory history new ReadingHistory(); history.setUserId(userId); history.setChapterId(chapterId); history.setCurrentPage(page); readingHistoryMapper.insertOrUpdate(history); }); } }8. 部署与性能优化8.1 后端服务部署配置使用Docker部署SpringBoot应用配置JVM参数优化性能FROM openjdk:17-jdk-slim VOLUME /tmp COPY target/manxiao-tian.jar app.jar ENV JAVA_OPTS-Xmx512m -Xms256m -XX:UseG1GC ENTRYPOINT [sh, -c, java $JAVA_OPTS -Djava.security.egdfile:/dev/./urandom -jar /app.jar]8.2 前端资源优化Vue3项目构建优化配置// vite.config.js export default defineConfig({ build: { rollupOptions: { output: { manualChunks: { vendor: [vue, vue-router, pinia], element: [element-plus] } } }, chunkSizeWarningLimit: 600 }, server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })8.3 微信小程序分包优化大体积小程序采用分包加载策略{ pages: [ pages/index/index, pages/category/category ], subpackages: [ { root: packageComic, pages: [ detail/detail, reader/reader ] } ] }9. 项目总结与扩展方向本漫小天漫画平台实现了完整的全栈开发流程涵盖了SpringBoot3后端API、Vue3管理端和uni-app微信小程序。项目采用现代化技术栈具备良好的可维护性和扩展性。在实际开发中需要特别注意微信小程序的环境兼容性问题合理设计数据库索引提升查询性能优化图片加载体验。后续可以扩展社交功能、推荐算法、付费阅读等高级功能进一步提升用户体验和商业价值。对于初学者来说建议先掌握每个技术栈的基础知识再尝试整合开发。遇到问题时可以查阅官方文档和社区解决方案逐步积累实战经验。
返回列表