在公益与商业融合的浪潮中,构建一个集领养、救助与商城于一体的流浪宠物管理系统,不仅能提升运营效率,更能为流浪动物带来更多关爱。本文基于SpringBoot2与Vue2,深度剖析该系统的架构设计、核心模块与代码实现,带你掌握全栈开发的核心技巧。
项目概览:功能与技术栈
该系统分为前台用户端与后台管理端。用户可浏览宠物信息、提交领养申请、参与救助互动、在商城购物;管理员则负责数据维护、订单处理与审核。技术栈方面,后端采用SpringBoot2 + MyBatis Plus + Shiro,前端使用Vue2 + Element UI,前后端通过RESTful API通信。数据库选用MySQL,并利用数据字典与全局拦截器提升代码复用性。
| 层级 | 技术/框架 | 说明 |
|---|---|---|
| 后端框架 | Spring Boot 2.2.2.RELEASE | 项目的基础框架,提供自动配置和快速开发能力。 |
| 持久层 | MyBatis Plus 2.3 | 增强的MyBatis ORM框架,简化数据库操作。 |
| 安全控制 | Apache Shiro 1.3.2 | 用于身份认证和权限管理。 |
| 数据库 | MySQL 5.7.32-log | 关系型数据库,存储系统业务数据。 |
| 前端框架 | Vue.js (后台管理) layui (前台) | 后台管理使用Vue + Element UI构建SPA;前台使用layui和jQuery。 |
| 前端组件 | Element UI, ECharts, Axios, Swiper | 丰富用户界面交互和数据可视化。 |
| 工具库 | Fastjson, Hutool, Commons-lang3 | 用于JSON处理、工具方法、字符串操作等。 |
核心模块拆解:从宠物到订单
系统涵盖四大核心模块:流浪宠物管理支持用户按类型与状态筛选,管理员可审核领养申请;宠物用品商城实现商品浏览、购物车、下单支付与订单管理;流浪动物救助允许用户发布故事、互动(点赞/踩、留言、收藏);公告管理用于发布通知。每个模块均包含增删改查与状态流转,形成完整业务闭环。
数据库设计:表结构详解
数据库共设计15张表,涵盖用户、宠物、订单、交互与基础数据。用户相关表包括yonghu与users;核心业务表有chongwu、chongwu_lingyang、liulangdongwujiuzhu、chongwuyongpin;交易相关表为cart、chongwuyongpin_order、address;交互相关表包括liulangdongwujiuzhu_liuyan、liulangdongwujiuzhu_collection、chongwuyongpin_commentback;基础数据有dictionary、config、news。
后端架构与权限控制
后端采用经典三层架构:Controller处理请求,Service实现业务,Dao通过MyBatis Plus操作数据库。权限控制使用Shiro框架,通过自定义@IgnoreAuth注解与AuthorizationInterceptor拦截器实现Token验证。数据字典通过dictionary表与DictionaryServletContextListener监听器,在启动时加载到全局ServletContext中,并在DictionaryService提供转换方法。此外,工具类如ValidatorUtils、SQLFilter、PoiUtil增强了安全性与复用性。
关键代码实战解析
以下是流浪宠物实体类ChongwuEntity.java的代码,展示字段映射:
// 部分关键代码展示
package com.entity;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@TableName("chongwu")
public class ChongwuEntity<T> implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Integer id;
@TableField(value = "chongwu_name")
private String chongwuName; // 宠物名称
@TableField(value = "chongwu_photo")
private String chongwuPhoto; // 宠物照片
@TableField(value = "chongwu_types")
private Integer chongwuTypes; // 宠物类型 (关联字典表)
@TableField(value = "chongwu_status_types")
private Integer chongwuStatusTypes; // 认领状态 (关联字典表)
@TableField(value = "chongwu_content")
private String chongwuContent; // 宠物简介
@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
@DateTimeFormat
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime; // 创建时间
// ... 省略 getter 和 setter 方法 ...
}流浪宠物控制器ChongwuController.java处理前端请求:
// 部分关键代码展示
package com.controller;
import com.entity.ChongwuEntity;
import com.service.ChongwuService;
import com.utils.PageUtils;
import com.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/chongwu")
public class ChongwuController {
@Autowired
private ChongwuService chongwuService;
// 前端列表查询接口
@IgnoreAuth
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params) {
// 处理分页和查询参数
PageUtils page = chongwuService.queryPage(params);
// 返回分页数据
return R.ok().put("data", page);
}
// 前端详情查询接口,同时增加点击次数
@RequestMapping("/detail/{id}")
public R detail(@PathVariable("id") Long id) {
ChongwuEntity chongwu = chongwuService.selectById(id);
if (chongwu != null) {
// 点击数量加1
chongwu.setChongwuClicknum(chongwu.getChongwuClicknum() + 1);
chongwuService.updateById(chongwu);
// ... 省略数据转换 ...
return R.ok().put("data", chongwu);
} else {
return R.error(511, "查不到数据");
}
}
// ... 省略其他方法 ...
}MyBatis Plus映射文件ChongwuDao.xml演示多表联查,关联chongwu与dictionary表,查询chongwu_types与chongwu_status_types:
<!-- 部分关键代码展示 -->
<mapper namespace="com.dao.ChongwuDao">
<sql id="Base_Column_List">
a.id as id
,a.chongwu_name as chongwuName
,a.chongwu_photo as chongwuPhoto
-- ... 其他基础字段
</sql>
<select id="selectListView" parameterType="map" resultType="com.entity.view.ChongwuView">
SELECT
<include refid="Base_Column_List" />
, b.index_name as chongwuValue
, c.index_name as chongwuStatusValue
FROM chongwu a
LEFT JOIN dictionary b ON a.chongwu_types = b.code_index AND b.dic_code = 'chongwu_types'
LEFT JOIN dictionary c ON a.chongwu_status_types = c.code_index AND c.dic_code = 'chongwu_status_types'
<where>
<if test="params.ids != null"> ... </if>
<if test=" params.chongwuName != null and params.chongwuName != '' ">
and a.chongwu_name like CONCAT('%',#{params.chongwuName},'%')
</if>
<!-- ... 其他查询条件 -->
</where>
order by a.${params.orderBy} desc
</select>
</mapper>商品订单处理逻辑ChongwuyongpinOrderController.java涉及库存扣减、余额校验与事务管理:
// 部分关键代码展示
@RestController
@RequestMapping("/chongwuyongpinOrder")
public class ChongwuyongpinOrderController {
@Autowired
private ChongwuyongpinOrderService chongwuyongpinOrderService;
@Autowired
private ChongwuyongpinService chongwuyongpinService;
@Autowired
private YonghuService yonghuService;
@Autowired
private CartService cartService;
@RequestMapping("/order")
public R add(@RequestParam Map<String, Object> params, HttpServletRequest request) {
// 1. 获取订单参数:地址ID、支付方式、商品列表等
Integer userId = (Integer) request.getSession().getAttribute("userId");
// ...
// 2. 遍历购物车商品,逐一处理
for (Map<String, Object> map : chongwuyongpins) {
ChongwuyongpinEntity chongwuyongpinEntity = chongwuyongpinService.selectById(chongwuyongpinId);
// 3. 校验库存
if(chongwuyongpinEntity.getChongwuyongpinKucunNumber() < buyNumber) {
return R.error(chongwuyongpinEntity.getChongwuyongpinName()+"的库存不足");
}
// 4. 更新库存
chongwuyongpinEntity.setChongwuyongpinKucunNumber(chongwuyongpinEntity.getChongwuyongpinKucunNumber() - buyNumber);
// 5. 计算价格,并校验用户余额是否充足
if(chongwuyongpinOrderPaymentTypes == 1) { // 余额支付
if(yonghuEntity.getNewMoney() - money < 0 ) {
return R.error("余额不足,请充值!!!");
}
// 扣减余额
yonghuEntity.setNewMoney(yonghuEntity.getNewMoney() - money);
}
// 创建订单详情对象...
}
// 6. 批量插入订单、更新商品库存、更新用户余额、清空购物车
chongwuyongpinOrderService.insertBatch(chongwuyongpinOrderList);
chongwuyongpinService.updateBatchById(chongwuyongpinList);
yonghuService.updateById(yonghuEntity);
cartService.deleteBatchIds(cartIds);
return R.ok();
}
// ... 其他方法 ...
}前端页面chongwuyongpin/detail.html实现商品详情与购物车交互:
<!-- 部分关键代码展示 -->
<div class="detail-item">
<!-- 数量加减按钮 -->
<button type="button" @click="buyNumber>0?buyNumber--:buyNumber">-</button>
<input type="number" v-model="buyNumber" id="buyNumber" disabled="disabled" />
<button type="button" @click="buyNumber++">+</button>
<!-- 加入购物车按钮 -->
<button @click="addChongwuyongpinCart()" type="button">
添加到购物车
</button>
</div>
<script>
// ... 省略Vue实例定义 ...
methods: {
// 添加到购物车方法
addChongwuyongpinCart() {
// 1. 检查库存
if (this.detail.chongwuyongpinKucunNumber < this.buyNumber) {
layui.layer.msg(`库存不足`, { icon: 5 });
return false;
}
// 2. 检查购物车是否已存在该商品
layui.http.request('cart/list', 'get', {
yonghuId: localStorage.getItem('userid'),
chongwuyongpinId: this.detail.id,
}, (res) => {
if(res.data.list.length > 0) {
layui.layer.msg("该商品已经添加到购物车", { icon: 5 });
return false;
}
// 3. 发起请求,将商品加入购物车
layui.http.requestJson('cart/add', 'post', {
yonghuId: localStorage.getItem('userid'),
chongwuyongpinId: this.detail.id,
buyNumber: this.buyNumber,
}, (res) => {
if(res.code==0){
layui.layer.msg('添加到购物车成功', { icon: 6 });
}
});
});
}
}
</script>前端开发亮点:Vue2与UI交互
在前端开发中,我们利用Vue2的组件化与Element UI构建了响应式界面。例如,商品详情页的数量选择器与加入购物车功能,通过v-model双向绑定与axios异步请求实现流畅体验。对于UI开发,我们遵循模块化设计,将宠物列表、救助故事、购物车等拆分为独立组件,便于维护与扩展。与React或Angular相比,Vue2的学习曲线更平缓,且生态丰富,适合中小型项目快速迭代。
实践建议:在开发中,注意使用路由懒加载优化首屏加载速度,并利用Vuex管理全局状态(如用户登录信息与购物车数据),避免组件间数据传递混乱。
[AFFILIATE_SLOT_1]系统截图与运行效果
以下是系统运行时的部分截图,展示前台首页、宠物列表、商品详情、购物车、订单管理、后台数据维护等界面:








































项目总结与扩展思考
该系统功能全面,覆盖领养、救助、电商与公告,形成业务闭环。技术选型成熟,SpringBoot2 + MyBatis Plus + Vue2组合保证了开发效率与可维护性。交互设计完善,点赞/踩、留言、收藏、购物车等功能提升了用户体验。数据字典、统一拦截器、全局异常处理等设计增强了系统健壮性。
扩展方向:未来可引入Redis缓存热点数据,使用Elasticsearch实现宠物与商品的全文搜索,或集成微信支付与小程序,提升移动端体验。对于前端工具,可尝试迁移至Vue3 + Vite或React + Next.js,以获得更好的性能与SSR支持。
[AFFILIATE_SLOT_2]⚠️ 注意事项:在开发中务必注意SQL注入防护(使用MyBatis Plus的预编译机制),并合理设计数据库索引以优化查询性能。同时,建议在订单处理逻辑中引入消息队列(如RabbitMQ)以解耦与削峰。
浙公网安备 33010602011771号