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

SpringBoot+Vue微信小程序电商系统开发实战
在开发电商类小程序时很多同学会遇到前后端分离架构的整合难题特别是SpringBoot后端与Vue前端的对接经常出现跨域、数据格式不匹配等问题。本文将完整分享一个基于JavaSpringBootVue的护肤购物系统小程序实战方案包含从环境搭建到部署上线的全流程适合计算机专业毕业设计和中小型电商项目开发参考。1. 项目背景与技术选型1.1 项目需求分析护肤购物系统需要满足基本的电商功能需求包括用户注册登录、商品浏览、购物车管理、订单处理、支付集成等核心模块。与传统电商系统相比护肤品类对商品详情展示、用户肤质匹配、产品成分分析等功能有更高要求。1.2 技术栈选择理由选择SpringBootVueMySQL的技术组合主要基于以下考虑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.0Vue CLI 4.0微信开发者工具VSCode或WebStorm2.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) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 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 groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.4.3.4/version /dependency dependency groupIdio.springfox/groupId artifactIdspringfox-boot-starter/artifactId version3.0.0/version /dependency /dependencies3.3 用户管理模块实现用户注册登录是系统的基础功能需要实现密码加密、会话管理等功能// UserController.java RestController RequestMapping(/api/user) Api(tags 用户管理) public class UserController { Autowired private UserService userService; PostMapping(/register) ApiOperation(用户注册) public ResultUserVO register(RequestBody UserRegisterDTO registerDTO) { return Result.success(userService.register(registerDTO)); } PostMapping(/login) ApiOperation(用户登录) public ResultLoginVO 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 ResultPageResultProductVO 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 ResultProductDetailVO 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) { // 验证商品库存 ListOrderItem 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-ui4.2 前端项目结构src/ ├── api/ # API接口 ├── components/ # 公共组件 ├── pages/ # 页面组件 ├── router/ # 路由配置 ├── store/ # 状态管理 └── utils/ # 工具函数4.3 首页组件实现首页需要展示商品分类、推荐商品、轮播图等!-- Home.vue -- template div classhome !-- 搜索栏 -- div classsearch-bar el-input placeholder搜索护肤品 v-modelsearchKeyword el-button slotappend iconel-icon-search clickhandleSearch/el-button /el-input /div !-- 轮播图 -- el-carousel :interval4000 typecard height200px el-carousel-item v-forbanner in banners :keybanner.id img :srcbanner.imageUrl :altbanner.title classbanner-image /el-carousel-item /el-carousel !-- 商品分类 -- div classcategory-section h3商品分类/h3 div classcategory-list div v-forcategory in categories :keycategory.id classcategory-item clickgoCategory(category.id) img :srccategory.icon :altcategory.name span{{ category.name }}/span /div /div /div !-- 推荐商品 -- div classrecommend-section h3热门推荐/h3 el-row :gutter20 el-col :span6 v-forproduct in recommendProducts :keyproduct.id product-card :productproduct clickgoDetail(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}) } } } /script4.4 商品详情页商品详情页需要展示商品信息、用户评价、相关推荐等!-- ProductDetail.vue -- template div classproduct-detail !-- 商品图片 -- el-carousel :interval0 arrowalways classproduct-images el-carousel-item v-forimage in product.images :keyimage img :srcimage classproduct-image /el-carousel-item /el-carousel !-- 商品信息 -- div classproduct-info h2 classproduct-name{{ product.name }}/h2 div classproduct-price span classcurrent-price¥{{ product.price }}/span span classoriginal-price v-ifproduct.originalPrice¥{{ product.originalPrice }}/span /div !-- 商品规格 -- div classproduct-specs h4规格选择/h4 el-radio-group v-modelselectedSpec el-radio v-forspec in product.specifications :keyspec.id :labelspec.id {{ spec.name }} /el-radio /el-radio-group /div !-- 购买数量 -- div classquantity span数量/span el-input-number v-modelquantity :min1 :maxproduct.stock/el-input-number span classstock库存 {{ product.stock }} 件/span /div !-- 操作按钮 -- div classactions el-button typeprimary sizemedium clickaddToCart 加入购物车 /el-button el-button typedanger sizemedium clickbuyNow 立即购买 /el-button /div /div !-- 商品详情 -- div classproduct-content el-tabs v-modelactiveTab el-tab-pane label商品详情 namedetail div v-htmlproduct.detail/div /el-tab-pane el-tab-pane label用户评价 namereviews review-list :product-idproductId/review-list /el-tab-pane /el-tabs /div /div /template5. 微信小程序端开发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 request6. 前后端联调与部署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.egdfile:/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 MapString, String createWxPayment(Order order, String openid) { // 调用微信支付统一下单接口 MapString, 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 RedisTemplateString, 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加密实现接口限流防止恶意请求对用户输入进行严格验证和过滤这个护肤购物系统小程序项目涵盖了从需求分析到部署上线的完整开发流程采用主流的技术栈和最佳实践可以作为计算机专业毕业设计的优秀参考案例。在实际开发过程中还需要根据具体需求进行功能扩展和优化调整。