大家好,我是Java1234_小锋老师,分享一套锋哥原创的SpringBoot4+Vue3电子相册管理系统。

项目介绍
随着移动互联网与数字影像技术的快速发展,个人与组织积累的电子照片数量持续增长,传统的本地文件夹管理方式已难以满足分类整理、在线分享、互动交流和统一维护等需求。针对上述问题,本文设计并实现了一套基于Spring Boot与Vue3的电子相册管理系统。系统采用前后端分离架构,后端以Spring Boot作为核心框架,结合MyBatis-Plus完成数据持久化,使用JWT实现身份认证与权限控制;前端基于Vue3、Vite、Element Plus与ECharts构建管理端与用户端界面,实现相册创建、照片上传、广场浏览、点赞收藏、评论互动、公告发布及后台数据统计等功能。
在需求分析阶段,本文从可行性、功能性需求和非功能性需求三个维度展开分析,明确了用户端与管理员端的业务边界。系统设计阶段则涵盖了总体架构、功能结构、数据库E-R模型以及关键表结构的设计。在实现阶段,我们围绕认证授权、相册与照片管理、互动模块、评论审核、统计看板等核心功能,详细阐述了实现思路并提供了关键代码示例。最后,通过全面的功能测试验证了系统的可用性。实践结果表明,该系统结构清晰、交互友好、扩展性良好,能够有效满足电子相册日常管理与内容运营的基本需求,对同类Web应用的设计与开发具有一定的参考价值。
源码下载
链接: https://pan.baidu.com/s/1GpCCtiT9Dm6PBC-zMVYvvQ?pwd=1234
提取码: 1234
系统展示









核心代码
package com.java1234.controller;
import com.java1234.aspect.OperLog;
import com.java1234.common.R;
import com.java1234.entity.Photo;
import com.java1234.service.impl.UserManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 照片管理控制器
*/
@RestController
@RequestMapping("/api/photo")
public class PhotoController {
@Autowired
private UserManageService userManageService;
/**
* 分页查询照片
*/
@GetMapping("/page")
public R<?> page(@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "12") int pageSize,
@RequestParam(required = false) String name,
@RequestParam(required = false) Long albumId,
@RequestParam(required = false) Long userId) {
return R.ok(userManageService.pagePhotos(pageNum, pageSize, name, albumId, userId));
}
/**
* 新增照片
*/
@PostMapping
@OperLog("上传照片")
public R<Void> add(@RequestBody Photo photo) {
userManageService.addPhoto(photo);
return R.ok();
}
/**
* 修改照片
*/
@PutMapping
public R<Void> update(@RequestBody Photo photo) {
userManageService.updatePhoto(photo);
return R.ok();
}
/**
* 删除照片
*/
@DeleteMapping("/{id}")
@OperLog("删除照片")
public R<Void> delete(@PathVariable Long id) {
userManageService.deletePhoto(id);
return R.ok();
}
}
<template>
<div class="page-container">
<div class="card-box">
<div class="search-bar">
<el-input v-model="query.name" placeholder="搜索相册名称" clearable style="width:220px" @clear="loadData" />
<el-button type="primary" @click="loadData"><el-icon><Search /></el-icon>搜索</el-button>
</div>
<el-table :data="tableData" stripe border>
<el-table-column prop="id" label="ID" min-width="60" />
<el-table-column label="封面" min-width="80">
<template #default="{ row }">
<el-image :src="row.cover" style="width:50px;height:50px;border-radius:6px" fit="cover" />
</template>
</el-table-column>
<el-table-column prop="name" label="相册名称" min-width="120" />
<el-table-column prop="username" label="所属用户" min-width="100" />
<el-table-column prop="categoryName" label="分类" min-width="80" />
<el-table-column label="公开" min-width="70">
<template #default="{ row }">
<el-tag :type="row.isPublic === 1 ? 'success' : 'info'" size="small">{{ row.isPublic === 1 ? '公开' : '私密' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="photoCount" label="照片数" min-width="70" />
<el-table-column prop="viewCount" label="浏览量" min-width="70" />
<el-table-column label="创建时间" min-width="160">
<template #default="{ row }">{{ formatDateTime(row.createTime) }}</template>
</el-table-column>
<el-table-column label="操作" min-width="100" fixed="right">
<template #default="{ row }">
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination style="margin-top:16px;justify-content:flex-end" v-model:current-page="query.pageNum" v-model:page-size="query.pageSize"
:total="total" :page-sizes="[10,20,50]" layout="total,sizes,prev,pager,next" @change="loadData" />
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { pageAlbum, deleteAlbum, formatDateTime } from '@/api'
import { ElMessage, ElMessageBox } from 'element-plus'
const tableData = ref([])
const total = ref(0)
const query = reactive({ pageNum: 1, pageSize: 10, name: '' })
const loadData = async () => {
const res = await pageAlbum(query)
tableData.value = res.data.records
total.value = res.data.total
}
const handleDelete = (row) => {
if (row.photoCount > 0) {
ElMessage.warning('相册内还有照片,请先删除全部照片后再删除相册')
return
}
ElMessageBox.confirm(`确定删除相册「${row.name}」吗?`, '删除确认', { type: 'warning' }).then(async () => {
await deleteAlbum(row.id)
ElMessage.success('删除成功')
loadData()
}).catch(() => {})
}
onMounted(loadData)
</script>
43万+

被折叠的 条评论
为什么被折叠?



