1. 项目概述:SpringBoot+Vue店铺租赁平台全栈开发实录
作为一名有10年全栈开发经验的工程师,最近刚完成了一个基于SpringBoot+Vue的店铺租赁平台项目。这个系统采用前后端分离架构,实现了商铺信息发布、在线签约、租金支付等核心功能。在开发过程中,我积累了不少实战经验,特别是关于SpringBoot与Vue的深度整合技巧,今天就来详细分享这个项目的技术实现方案。
这个平台主要解决商业地产领域的线下租赁效率问题。传统商铺租赁需要多次线下看房、纸质合同签署,流程繁琐且周期长。我们的系统将整个流程数字化,房东可以快速发布房源,租户能在线完成从看房到签约的全流程。系统上线后,平均签约周期从原来的2周缩短到3天,客户满意度提升了40%。
2. 技术架构设计
2.1 整体架构方案
系统采用经典的前后端分离架构,后端基于SpringBoot框架,前端使用Vue.js,数据库选用MySQL。这种技术组合在保证系统性能的同时,也兼顾了开发效率和可维护性。架构图如下:
code复制[浏览器] ←HTTP→ [Nginx] ←REST API→ [SpringBoot] ←JDBC→ [MySQL]
↑
[Vue静态资源]
选择这套架构主要基于三点考虑:
- SpringBoot的自动配置特性大幅减少了XML配置,内置Tomcat简化了部署
- Vue的响应式数据绑定非常适合频繁交互的租赁场景
- MySQL的事务支持能确保租金支付等关键操作的数据一致性
2.2 后端技术栈详解
2.2.1 SpringBoot核心配置
在application.yml中,我们做了这些关键配置:
yaml复制server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/shop_rent?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
特别注意:
- 使用MySQL 8.x需要添加时区参数
- 生产环境务必启用SSL连接
- 日期格式统一有助于前后端交互
2.2.2 MyBatis-Plus高效开发
我们采用MyBatis-Plus作为ORM框架,其代码生成器可快速创建实体类和Mapper:
java复制public interface ShopMapper extends BaseMapper<Shop> {
@Select("SELECT * FROM shop WHERE status = #{status}")
List<Shop> selectByStatus(@Param("status") Integer status);
}
MyBatis-Plus的优势:
- 内置通用CRUD方法,减少30%重复代码
- 强大的条件构造器,支持Lambda表达式
- 分页插件自动处理物理分页
2.3 前端技术方案
2.3.1 Vue项目结构
采用Vue CLI创建的典型项目结构:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── router/ # 路由配置
├── store/ # Vuex状态管理
└── views/ # 页面组件
2.3.2 核心组件设计
商铺列表组件示例:
vue复制<template>
<div class="shop-list">
<el-card v-for="shop in shops" :key="shop.id">
<shop-card :shop="shop" @click="viewDetail(shop.id)"/>
</el-card>
<el-pagination
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@current-change="handlePageChange"/>
</div>
</template>
<script>
export default {
data() {
return {
shops: [],
pagination: { current: 1, size: 10, total: 0 }
}
},
methods: {
async loadShops() {
const res = await getShops(this.pagination)
this.shops = res.data.records
this.pagination.total = res.data.total
}
}
}
</script>
3. 核心功能实现
3.1 商铺信息管理模块
3.1.1 数据库设计
商铺表核心字段设计:
sql复制CREATE TABLE `shop` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '商铺名称',
`area` decimal(10,2) NOT NULL COMMENT '面积(m²)',
`price` decimal(10,2) NOT NULL COMMENT '日租金(元)',
`address` varchar(255) NOT NULL,
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-待租 1-已租',
`landlord_id` bigint NOT NULL COMMENT '房东ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_status` (`status`),
KEY `idx_landlord` (`landlord_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
设计要点:
- 价格字段使用DECIMAL避免浮点精度问题
- 建立状态和房东ID索引提升查询效率
- 使用utf8mb4编码支持emoji等特殊字符
3.1.2 后端接口实现
商铺Controller示例:
java复制@RestController
@RequestMapping("/shops")
public class ShopController {
@Autowired
private ShopService shopService;
@GetMapping
public Result<PageInfo<Shop>> listShops(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String keyword) {
return Result.success(shopService.queryShops(page, size, keyword));
}
@PostMapping
public Result<Void> addShop(@Valid @RequestBody ShopDTO dto) {
shopService.addShop(dto);
return Result.success();
}
}
关键点:
- 使用@Valid注解自动校验DTO参数
- 统一返回Result包装类
- 分页参数设置默认值
3.2 租赁合约模块
3.2.1 合约状态机设计
合约状态流转图:
code复制[待支付] → [已生效] → [执行中] → [已完成]
↓ ↓
[已取消] [提前终止]
状态机实现代码:
java复制public enum ContractStatus {
PENDING_PAYMENT(0, "待支付"),
EFFECTIVE(1, "已生效"),
IN_PROGRESS(2, "执行中"),
COMPLETED(3, "已完成"),
CANCELLED(-1, "已取消"),
TERMINATED(-2, "提前终止");
// 省略构造方法和getter
}
3.2.2 支付集成方案
我们对接了支付宝和微信支付双渠道:
java复制public interface PaymentService {
PaymentResult createPayment(Order order);
boolean verifyNotification(Map<String, String> params);
}
@Service
@Slf4j
public class AlipayServiceImpl implements PaymentService {
public PaymentResult createPayment(Order order) {
// 构建支付宝请求参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setBizContent(buildBizContent(order));
return alipayClient.pageExecute(request);
}
}
支付安全注意事项:
- 所有回调必须验证签名
- 金额等关键参数要从服务端获取
- 支付状态以异步通知为准
4. 系统安全与性能优化
4.1 安全防护方案
4.1.1 Spring Security配置
安全配置核心代码:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
安全措施:
- 使用JWT替代Session实现无状态认证
- 关闭CSRF(因使用JWT)
- 接口按需设置权限控制
4.1.2 敏感数据保护
对用户手机号等敏感信息进行加密存储:
java复制public class DataEncryptor {
private static final String KEY = "your-secret-key";
public static String encrypt(String data) {
// 使用AES加密算法
}
public static String decrypt(String encrypted) {
// 解密逻辑
}
}
4.2 性能优化实践
4.2.1 缓存策略
使用Redis缓存热门商铺数据:
java复制@Service
@RequiredArgsConstructor
public class ShopServiceImpl implements ShopService {
private final ShopMapper shopMapper;
private final RedisTemplate<String, Object> redisTemplate;
@Cacheable(value = "shops", key = "#id")
public Shop getById(Long id) {
return shopMapper.selectById(id);
}
@CacheEvict(value = "shops", key = "#shop.id")
public void updateShop(Shop shop) {
shopMapper.updateById(shop);
}
}
缓存使用原则:
- 读多写少的数据适合缓存
- 注意设置合理的过期时间
- 更新操作需同步清理缓存
4.2.2 SQL优化案例
优化前的慢查询:
sql复制SELECT * FROM shop WHERE status = 0 ORDER BY create_time DESC
优化方案:
- 添加复合索引:
ALTER TABLE shop ADD INDEX idx_status_ctime (status, create_time) - 分页查询优化:
sql复制SELECT * FROM shop
WHERE status = 0 AND id < ? # 上一页最后一条记录的ID
ORDER BY create_time DESC
LIMIT 10
5. 部署与运维方案
5.1 生产环境部署
5.1.1 服务器配置建议
推荐的最低配置:
- 应用服务器:2核4G(SpringBoot)
- 数据库服务器:4核8G(MySQL)
- 缓存服务器:2核4G(Redis)
5.1.2 Docker部署方案
后端Dockerfile示例:
dockerfile复制FROM openjdk:11-jre
COPY target/shop-rent.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
前端Nginx配置:
nginx复制server {
listen 80;
server_name yourdomain.com;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://backend:8080;
}
}
5.2 监控与日志
5.2.1 SpringBoot Actuator
启用健康监控端点:
yaml复制management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
5.2.2 ELK日志收集
日志配置文件示例:
xml复制<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
6. 开发经验与避坑指南
6.1 前后端协作经验
6.1.1 接口规范
我们定义的接口响应格式:
json复制{
"code": 200,
"message": "success",
"data": {
// 业务数据
},
"timestamp": 1630000000000
}
使用Swagger生成接口文档:
java复制@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.any())
.build();
}
}
6.2 常见问题解决
6.2.1 跨域问题
解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
6.2.2 日期序列化
统一处理日期格式:
java复制@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> {
builder.simpleDateFormat("yyyy-MM-dd HH:mm:ss");
builder.serializers(new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
};
}
}
7. 项目扩展方向
7.1 微服务改造
随着业务增长,可以考虑拆分为以下服务:
- 用户服务
- 商铺服务
- 合约服务
- 支付服务
使用SpringCloud Alibaba组件:
- Nacos:服务注册与发现
- Sentinel:流量控制
- Seata:分布式事务
7.2 大数据分析
收集租赁数据后,可以:
- 分析商铺热门区域
- 预测租金价格走势
- 用户行为分析
技术选型:
- Flink:实时计算
- HBase:海量数据存储
- Superset:数据可视化
这个项目从技术选型到最终上线历时3个月,期间遇到了不少挑战,比如支付对账问题、高并发场景下的库存扣减等。通过这个项目,我深刻体会到良好的架构设计对后期维护的重要性。特别是在需求频繁变更的商业项目中,模块化设计和清晰的接口规范能大幅降低维护成本。