1. 项目背景与核心价值
玩具租赁这个细分市场近年来在国内悄然兴起。根据中国玩具协会2022年的行业报告,国内玩具租赁市场规模已达37亿元,年增长率保持在15%以上。这种商业模式特别适合现代城市家庭——既能满足孩子对新玩具的好奇心,又能避免家中堆积大量使用率低的玩具。
这个前后端分离的玩具租赁系统采用当前主流的技术栈组合:
- 后端:Spring Boot 2.7 + MyBatis 3.5
- 前端:Vue 3.2 + Element Plus
- 数据库:MySQL 8.0
我在实际开发中发现,这种技术组合特别适合中小型电商类项目。Spring Boot的自动配置让后端服务能快速搭建,Vue的响应式特性完美适配商品展示页面的动态需求,而MyBatis的灵活SQL编写能力则能应对租赁业务中复杂的查询逻辑(比如根据租赁时长动态计算价格)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统核心功能模块拆解
2.1 用户服务模块
采用JWT进行认证,这里有个实际开发中的经验:在租赁系统中,我特别增加了"家长身份验证"的扩展字段。通过Spring Security的过滤器链改造,实现了以下业务逻辑:
java复制// 自定义JWT过滤器片段
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
// 解析JWT获取用户基础信息
Claims claims = JwtUtil.parseToken(token);
// 特别处理家长认证状态
if (claims.get("isParentVerified") != null) {
request.setAttribute("parentVerified",
Boolean.parseBoolean(claims.get("isParentVerified").toString()));
}
// ...其他处理
}
}
2.2 玩具库存管理
使用MySQL实现SKU体系时,我设计了一个三层结构:
- 玩具基础表(toy_base)
- 规格属性表(toy_spec)
- 库存明细表(toy_inventory)
这里有个关键点:在租赁业务中,库存扣减需要处理"预占"状态。我的解决方案是给inventory表增加了lease_status字段,使用状态机模式管理库存流转:
sql复制CREATE TABLE `toy_inventory` (
`id` bigint NOT NULL AUTO_INCREMENT,
`toy_id` bigint NOT NULL COMMENT '关联玩具ID',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-可租 1-已租 2-维修中',
`lease_start` datetime DEFAULT NULL COMMENT '租赁开始时间',
`lease_end` datetime DEFAULT NULL COMMENT '租赁结束时间',
`preemption_token` varchar(64) DEFAULT NULL COMMENT '预占令牌',
PRIMARY KEY (`id`),
KEY `idx_toy_status` (`toy_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.3 租赁订单系统
订单模块采用了状态模式设计,核心状态包括:
- 待支付
- 已支付
- 发货中
- 租赁中
- 已完成
- 已取消
在Spring Boot中,我使用Enum实现状态机流转:
java复制public enum OrderStatus {
INIT(0) {
@Override
public boolean canTransferTo(OrderStatus nextStatus) {
return nextStatus == PAID || nextStatus == CANCELLED;
}
},
PAID(1) {
// 其他状态实现...
};
private final int code;
// 状态转移校验方法
public abstract boolean canTransferTo(OrderStatus nextStatus);
}
3. 关键技术实现细节
3.1 前后端分离架构设计
系统采用完全分离的架构:
- 前端:Vue 3 + Vite构建
- 后端:Spring Boot提供RESTful API
- 交互:Axios + 自定义拦截器
在跨域处理上,我推荐使用Spring Boot的CorsFilter而非注解方式,因为租赁系统需要灵活控制不同环境的CORS策略:
java复制@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
// 实际生产环境应限制为具体域名
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.setAllowCredentials(true);
source.registerCorsConfiguration("/api/**", config);
return new CorsFilter(source);
}
}
3.2 MyBatis动态SQL实践
在玩具搜索功能中,我大量使用了MyBatis的动态SQL能力。比如这个根据多条件查询玩具的Mapper:
xml复制<select id="selectToysByCondition" resultMap="ToyResultMap">
SELECT * FROM toy_base
<where>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
<if test="minPrice != null">
AND price >= #{minPrice}
</if>
<if test="maxPrice != null">
AND price <= #{maxPrice}
</if>
<if test="keywords != null and keywords != ''">
AND (name LIKE CONCAT('%',#{keywords},'%')
OR description LIKE CONCAT('%',#{keywords},'%'))
</if>
</where>
ORDER BY
<choose>
<when test="sortType == 'price_asc'">price ASC</when>
<when test="sortType == 'price_desc'">price DESC</when>
<otherwise>create_time DESC</otherwise>
</choose>
</select>
3.3 Vue前端状态管理
对于租赁车这种需要跨组件共享的状态,我使用Pinia代替Vuex:
javascript复制// stores/cart.js
export const useCartStore = defineStore('cart', {
state: () => ({
items: [],
selectedLeaseDays: 7 // 默认租赁天数
}),
actions: {
async addToCart(toy, leaseDays) {
const existing = this.items.find(item => item.toy.id === toy.id);
if (existing) {
existing.leaseDays = leaseDays;
} else {
this.items.push({ toy, leaseDays });
}
// 持久化到localStorage
localStorage.setItem('cart', JSON.stringify(this.items));
}
}
});
4. 部署实战与优化技巧
4.1 生产环境部署方案
我推荐使用Docker Compose进行一体化部署,这是完整的docker-compose.yml配置:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: toy_mysql
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: toy_lease
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
restart: always
backend:
build: ./backend
container_name: toy_backend
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/toy_lease
depends_on:
- mysql
restart: always
frontend:
build: ./frontend
container_name: toy_frontend
ports:
- "80:80"
restart: always
volumes:
mysql_data:
4.2 性能优化实践
在压力测试中,我发现玩具列表页的QPS在100左右时响应时间明显上升。通过以下优化手段将性能提升了3倍:
- 添加Redis缓存层:
java复制@Cacheable(value = "toyList", key = "#condition.hashCode()")
public List<ToyVO> queryToysByCondition(SearchCondition condition) {
return toyMapper.selectByCondition(condition);
}
-
MySQL查询优化:
- 为常用查询字段添加复合索引
- 大文本字段(如玩具描述)拆分为单独表
- 使用EXPLAIN分析慢查询
-
前端启用路由懒加载:
javascript复制const routes = [
{
path: '/toys',
component: () => import('../views/ToyList.vue')
}
]
4.3 安全防护措施
针对租赁系统的特殊需求,我实施了以下安全方案:
-
XSS防护:
- 前端使用DOMPurify处理富文本
- 后端添加Spring Security的XSS过滤器
-
支付安全:
- 敏感操作(如支付)需要二次密码确认
- 使用时间戳+随机数生成防重放token
-
数据加密:
- 用户敏感信息使用AES加密存储
- 数据库连接启用SSL
5. 开发中的典型问题与解决方案
5.1 跨域会话保持问题
在开发初期,前端请求无法携带Cookie。解决方案是:
- Axios配置:
javascript复制axios.defaults.withCredentials = true
- 后端CORS配置需要明确允许凭证:
java复制config.setAllowCredentials(true);
- Nginx配置添加:
code复制proxy_cookie_path / "/; secure; SameSite=None";
5.2 MyBatis分页插件冲突
当同时使用PageHelper和MyBatis-Plus时,会出现分页插件冲突。我的解决方式是:
- 排除冲突依赖:
xml复制<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
<exclusions>
<exclusion>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</exclusion>
</exclusions>
</dependency>
- 自定义分页拦截器顺序:
java复制@Bean
@Order(0)
public PaginationInnerInterceptor paginationInterceptor() {
return new PaginationInnerInterceptor();
}
5.3 Vue响应式数据丢失
在编辑玩具信息时,遇到表单数据响应式丢失的问题。最终发现是因为直接赋值了从接口返回的数据。解决方案:
javascript复制// 错误做法
this.form = response.data;
// 正确做法 - 使用展开运算符创建新对象
this.form = { ...response.data };
// 或者使用Object.assign
this.form = Object.assign({}, response.data);
6. 项目扩展方向
基于现有系统,可以考虑以下扩展:
-
智能推荐模块:
- 基于用户租赁历史实现协同过滤推荐
- 使用Redis的Sorted Set实现实时排行榜
-
物流跟踪集成:
- 对接快递鸟API实现物流轨迹查询
- 使用WebSocket推送物流状态更新
-
会员成长体系:
- 设计积分规则和等级制度
- 实现优惠券发放策略
-
小程序端开发:
- 使用Uniapp重构前端
- 接入微信支付能力
这个玩具租赁系统的完整源码我已经整理在GitHub仓库中,包含详细的部署文档和数据库初始化脚本。对于想学习现代Web开发全栈技术的小伙伴,这个项目涵盖了从技术选型到性能优化的完整链路,特别适合作为毕业设计或全栈实战项目。
