SpringBoot+Vue微信小程序电商系统开发实战

📅 2026/7/19 8:56:17 👁️ 阅读次数 📝 编程学习
SpringBoot+Vue微信小程序电商系统开发实战

在开发电商类小程序时,很多同学会遇到前后端分离架构的整合难题,特别是SpringBoot后端与Vue前端的对接经常出现跨域、数据格式不匹配等问题。本文将完整分享一个基于Java+SpringBoot+Vue的护肤购物系统小程序实战方案,包含从环境搭建到部署上线的全流程,适合计算机专业毕业设计和中小型电商项目开发参考。

1. 项目背景与技术选型

1.1 项目需求分析

护肤购物系统需要满足基本的电商功能需求,包括用户注册登录、商品浏览、购物车管理、订单处理、支付集成等核心模块。与传统电商系统相比,护肤品类对商品详情展示、用户肤质匹配、产品成分分析等功能有更高要求。

1.2 技术栈选择理由

选择SpringBoot+Vue+MySQL的技术组合主要基于以下考虑:

  • SpringBoot:简化Spring应用初始搭建和开发过程,内嵌Tomcat,无需单独部署WAR包
  • Vue.js:轻量级前端框架,组件化开发便于维护,与小程序开发理念高度契合
  • MySQL:成熟稳定的关系型数据库,社区活跃,学习成本低
  • 微信小程序:跨平台解决方案,用户无需下载安装即可使用

1.3 系统架构设计

系统采用典型的前后端分离架构,后端提供RESTful API接口,前端通过HTTP请求与后端交互。这种架构有利于团队分工协作,前后端可以并行开发,提高开发效率。

2. 开发环境准备

2.1 后端开发环境

  • JDK 1.8或更高版本
  • Maven 3.6+ 用于依赖管理
  • IntelliJ IDEA或Eclipse开发工具
  • MySQL 5.7或8.0版本
  • Redis(可选,用于缓存和会话管理)

2.2 前端开发环境

  • Node.js 14.0+
  • Vue CLI 4.0+
  • 微信开发者工具
  • VSCode或WebStorm

2.3 数据库环境配置

创建数据库并导入初始数据:

CREATE DATABASE skincare_shop DEFAULT CHARACTER SET utf8mb4; USE skincare_shop; -- 用户表 CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '密码', `phone` varchar(20) DEFAULT NULL COMMENT '手机号', `email` varchar(100) DEFAULT NULL COMMENT '邮箱', `avatar` varchar(200) DEFAULT NULL COMMENT '头像', `skin_type` varchar(20) DEFAULT NULL COMMENT '肤质类型', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

3. SpringBoot后端实现

3.1 项目结构设计

采用标准Maven多模块结构:

skincare-backend/ ├── skincare-common/ # 公共模块 ├── skincare-dao/ # 数据访问层 ├── skincare-service/ # 业务逻辑层 ├── skincare-controller/ # 控制层 └── skincare-app/ # 启动模块

3.2 Maven依赖配置

核心依赖包括SpringBoot Starter、MyBatis Plus、MySQL驱动等:

<!-- pom.xml --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3.4</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> </dependencies>

3.3 用户管理模块实现

用户注册登录是系统的基础功能,需要实现密码加密、会话管理等功能:

// UserController.java @RestController @RequestMapping("/api/user") @Api(tags = "用户管理") public class UserController { @Autowired private UserService userService; @PostMapping("/register") @ApiOperation("用户注册") public Result<UserVO> register(@RequestBody UserRegisterDTO registerDTO) { return Result.success(userService.register(registerDTO)); } @PostMapping("/login") @ApiOperation("用户登录") public Result<LoginVO> login(@RequestBody UserLoginDTO loginDTO) { return Result.success(userService.login(loginDTO)); } } // UserServiceImpl.java @Service public class UserServiceImpl implements UserService { @Override public UserVO register(UserRegisterDTO registerDTO) { // 检查用户名是否已存在 if (userMapper.selectByUsername(registerDTO.getUsername()) != null) { throw new BusinessException("用户名已存在"); } // 密码加密 String encryptedPassword = passwordEncoder.encode(registerDTO.getPassword()); User user = new User(); user.setUsername(registerDTO.getUsername()); user.setPassword(encryptedPassword); user.setPhone(registerDTO.getPhone()); user.setSkinType(registerDTO.getSkinType()); userMapper.insert(user); return convertToVO(user); } }

3.4 商品管理模块

商品模块需要支持分类管理、商品详情、库存管理等功能:

// ProductController.java @RestController @RequestMapping("/api/product") @Api(tags = "商品管理") public class ProductController { @GetMapping("/list") @ApiOperation("商品列表") public Result<PageResult<ProductVO>> getProductList( @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size, @RequestParam(required = false) Long categoryId) { return Result.success(productService.getProductList(page, size, categoryId)); } @GetMapping("/{id}") @ApiOperation("商品详情") public Result<ProductDetailVO> getProductDetail(@PathVariable Long id) { return Result.success(productService.getProductDetail(id)); } }

3.5 购物车和订单模块

实现完整的购物流程,包括添加购物车、生成订单、支付回调等:

// OrderServiceImpl.java @Service @Transactional public class OrderServiceImpl implements OrderService { @Override public OrderVO createOrder(OrderCreateDTO createDTO) { // 验证商品库存 List<OrderItem> orderItems = validateStock(createDTO.getItems()); // 计算总金额 BigDecimal totalAmount = calculateTotalAmount(orderItems); // 创建订单 Order order = new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(createDTO.getUserId()); order.setTotalAmount(totalAmount); order.setStatus(OrderStatus.PENDING_PAYMENT); orderMapper.insert(order); // 创建订单项 orderItems.forEach(item -> { item.setOrderId(order.getId()); orderItemMapper.insert(item); // 扣减库存 productMapper.decreaseStock(item.getProductId(), item.getQuantity()); }); return convertToVO(order, orderItems); } }

4. Vue前端开发

4.1 项目初始化

使用Vue CLI创建项目并安装必要依赖:

vue create skincare-frontend cd skincare-frontend npm install axios vue-router vuex element-ui

4.2 前端项目结构

src/ ├── api/ # API接口 ├── components/ # 公共组件 ├── pages/ # 页面组件 ├── router/ # 路由配置 ├── store/ # 状态管理 └── utils/ # 工具函数

4.3 首页组件实现

首页需要展示商品分类、推荐商品、轮播图等:

<!-- Home.vue --> <template> <div class="home"> <!-- 搜索栏 --> <div class="search-bar"> <el-input placeholder="搜索护肤品" v-model="searchKeyword"> <el-button slot="append" icon="el-icon-search" @click="handleSearch"></el-button> </el-input> </div> <!-- 轮播图 --> <el-carousel :interval="4000" type="card" height="200px"> <el-carousel-item v-for="banner in banners" :key="banner.id"> <img :src="banner.imageUrl" :alt="banner.title" class="banner-image"> </el-carousel-item> </el-carousel> <!-- 商品分类 --> <div class="category-section"> <h3>商品分类</h3> <div class="category-list"> <div v-for="category in categories" :key="category.id" class="category-item" @click="goCategory(category.id)"> <img :src="category.icon" :alt="category.name"> <span>{{ category.name }}</span> </div> </div> </div> <!-- 推荐商品 --> <div class="recommend-section"> <h3>热门推荐</h3> <el-row :gutter="20"> <el-col :span="6" v-for="product in recommendProducts" :key="product.id"> <product-card :product="product" @click="goDetail(product.id)"></product-card> </el-col> </el-row> </div> </div> </template> <script> import { getBanners, getCategories, getRecommendProducts } from '@/api/home' import ProductCard from '@/components/ProductCard.vue' export default { name: 'Home', components: { ProductCard }, data() { return { searchKeyword: '', banners: [], categories: [], recommendProducts: [] } }, async created() { await this.loadData() }, methods: { async loadData() { try { const [bannerRes, categoryRes, productRes] = await Promise.all([ getBanners(), getCategories(), getRecommendProducts() ]) this.banners = bannerRes.data this.categories = categoryRes.data this.recommendProducts = productRes.data } catch (error) { this.$message.error('数据加载失败') } }, handleSearch() { this.$router.push({ path: '/search', query: { keyword: this.searchKeyword } }) }, goCategory(categoryId) { this.$router.push(`/category/${categoryId}`) }, goDetail(productId) { this.$router.push(`/product/${productId}`) } } } </script>

4.4 商品详情页

商品详情页需要展示商品信息、用户评价、相关推荐等:

<!-- ProductDetail.vue --> <template> <div class="product-detail"> <!-- 商品图片 --> <el-carousel :interval="0" arrow="always" class="product-images"> <el-carousel-item v-for="image in product.images" :key="image"> <img :src="image" class="product-image"> </el-carousel-item> </el-carousel> <!-- 商品信息 --> <div class="product-info"> <h2 class="product-name">{{ product.name }}</h2> <div class="product-price"> <span class="current-price">¥{{ product.price }}</span> <span class="original-price" v-if="product.originalPrice">¥{{ product.originalPrice }}</span> </div> <!-- 商品规格 --> <div class="product-specs"> <h4>规格选择</h4> <el-radio-group v-model="selectedSpec"> <el-radio v-for="spec in product.specifications" :key="spec.id" :label="spec.id"> {{ spec.name }} </el-radio> </el-radio-group> </div> <!-- 购买数量 --> <div class="quantity"> <span>数量:</span> <el-input-number v-model="quantity" :min="1" :max="product.stock"></el-input-number> <span class="stock">库存 {{ product.stock }} 件</span> </div> <!-- 操作按钮 --> <div class="actions"> <el-button type="primary" size="medium" @click="addToCart"> 加入购物车 </el-button> <el-button type="danger" size="medium" @click="buyNow"> 立即购买 </el-button> </div> </div> <!-- 商品详情 --> <div class="product-content"> <el-tabs v-model="activeTab"> <el-tab-pane label="商品详情" name="detail"> <div v-html="product.detail"></div> </el-tab-pane> <el-tab-pane label="用户评价" name="reviews"> <review-list :product-id="productId"></review-list> </el-tab-pane> </el-tabs> </div> </div> </template>

5. 微信小程序端开发

5.1 小程序项目结构

miniprogram/ ├── pages/ # 页面文件 ├── components/ # 自定义组件 ├── utils/ # 工具函数 ├── app.js # 小程序逻辑 ├── app.json # 小程序配置 └── app.wxss # 全局样式

5.2 小程序页面配置

// app.json { "pages": [ "pages/index/index", "pages/category/category", "pages/product/detail", "pages/cart/cart", "pages/order/confirm", "pages/user/user" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "护肤商城", "navigationBarTextStyle": "black" }, "tabBar": { "color": "#999", "selectedColor": "#ff6b81", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "images/home.png", "selectedIconPath": "images/home-active.png" }, { "pagePath": "pages/category/category", "text": "分类", "iconPath": "images/category.png", "selectedIconPath": "images/category-active.png" }, { "pagePath": "pages/cart/cart", "text": "购物车", "iconPath": "images/cart.png", "selectedIconPath": "images/cart-active.png" }, { "pagePath": "pages/user/user", "text": "我的", "iconPath": "images/user.png", "selectedIconPath": "images/user-active.png" } ] } }

5.3 小程序API封装

封装统一的网络请求方法,处理token管理和错误处理:

// utils/request.js const baseURL = 'https://your-api-domain.com/api' const request = (options) => { return new Promise((resolve, reject) => { wx.request({ url: baseURL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' }, success: (res) => { if (res.statusCode === 200) { if (res.data.code === 0) { resolve(res.data.data) } else { wx.showToast({ title: res.data.message || '请求失败', icon: 'none' }) reject(res.data) } } else { reject(res) } }, fail: (err) => { wx.showToast({ title: '网络错误', icon: 'none' }) reject(err) } }) }) } export default request

6. 前后端联调与部署

6.1 跨域问题解决

SpringBoot配置CORS支持:

@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }

6.2 接口文档生成

使用Swagger生成API文档:

@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.skincare.controller")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("护肤商城API文档") .description("前后端接口文档") .version("1.0") .build(); } }

6.3 生产环境部署

使用Docker容器化部署:

# Dockerfile FROM openjdk:8-jre-slim VOLUME /tmp ADD target/skincare-backend-1.0.0.jar app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

7. 常见问题与解决方案

7.1 微信登录集成问题

微信小程序登录需要获取code并调用后端接口换取openid:

// 小程序登录逻辑 wx.login({ success: (res) => { if (res.code) { request({ url: '/auth/wxlogin', method: 'POST', data: { code: res.code } }).then(result => { wx.setStorageSync('token', result.token) wx.setStorageSync('userInfo', result.userInfo) }) } } })

7.2 图片上传与存储

使用云存储或本地存储方案:

@Service public class FileService { @Value("${file.upload-path}") private String uploadPath; public String uploadFile(MultipartFile file) { try { String filename = UUID.randomUUID().toString() + getFileExtension(file.getOriginalFilename()); File dest = new File(uploadPath + filename); file.transferTo(dest); return "/uploads/" + filename; } catch (IOException e) { throw new BusinessException("文件上传失败"); } } }

7.3 支付集成方案

集成微信支付需要处理预支付订单和回调:

@Service public class PaymentService { public Map<String, String> createWxPayment(Order order, String openid) { // 调用微信支付统一下单接口 Map<String, String> params = new HashMap<>(); params.put("appid", wxConfig.getAppId()); params.put("mch_id", wxConfig.getMchId()); params.put("nonce_str", generateNonceStr()); params.put("body", "护肤商城订单"); params.put("out_trade_no", order.getOrderNo()); params.put("total_fee", order.getTotalAmount().multiply(new BigDecimal("100")).intValue() + ""); params.put("spbill_create_ip", order.getIp()); params.put("notify_url", wxConfig.getNotifyUrl()); params.put("trade_type", "JSAPI"); params.put("openid", openid); // 生成签名并调用微信API String sign = generateSign(params); params.put("sign", sign); // 调用微信支付接口并返回前端所需参数 return invokeWxPayApi(params); } }

8. 性能优化与安全考虑

8.1 数据库优化策略

  • 为常用查询字段添加索引
  • 使用连接池管理数据库连接
  • 定期清理无效数据

8.2 缓存策略实现

使用Redis缓存热点数据:

@Service public class ProductService { @Autowired private RedisTemplate<String, Object> redisTemplate; private static final String PRODUCT_KEY_PREFIX = "product:"; public ProductDetailVO getProductDetail(Long productId) { String cacheKey = PRODUCT_KEY_PREFIX + productId; ProductDetailVO cached = (ProductDetailVO) redisTemplate.opsForValue().get(cacheKey); if (cached != null) { return cached; } ProductDetailVO detail = productMapper.selectDetailById(productId); if (detail != null) { redisTemplate.opsForValue().set(cacheKey, detail, Duration.ofHours(1)); } return detail; } }

8.3 安全防护措施

  • 使用HTTPS加密传输
  • 对用户密码进行bcrypt加密
  • 实现接口限流防止恶意请求
  • 对用户输入进行严格验证和过滤

这个护肤购物系统小程序项目涵盖了从需求分析到部署上线的完整开发流程,采用主流的技术栈和最佳实践,可以作为计算机专业毕业设计的优秀参考案例。在实际开发过程中,还需要根据具体需求进行功能扩展和优化调整。