SpringBoot+Vue超市管理系统实战:从零搭建前后端分离项目

发布时间:2026/7/19 7:48:27
SpringBoot+Vue超市管理系统实战:从零搭建前后端分离项目 超市管理系统是Java开发者必备的实战项目之一尤其对于即将毕业的学生和正在寻找工作的开发者来说一个完整的SpringBootVue前后端分离项目能够显著提升简历竞争力。在实际开发中很多同学会遇到前后端对接困难、权限控制复杂、数据库设计不合理等问题导致项目难以真正运行起来。本文将手把手带你从零搭建一个功能完整的鲜享超市管理系统涵盖商品管理、库存管理、订单管理、会员管理等核心模块。无论你是刚接触SpringBoot和Vue的新手还是需要完善毕设项目的同学都能通过本文获得完整的可运行代码和详细的技术讲解。1. 项目概述与技术选型1.1 项目背景与业务需求鲜享超市管理系统是一个面向中小型超市的综合性管理平台主要解决传统超市在商品管理、库存跟踪、销售统计等方面的手工操作效率低下问题。系统需要实现以下核心功能商品管理商品分类、商品信息维护、价格管理库存管理入库出库记录、库存预警、盘点功能订单管理销售订单处理、订单状态跟踪、退货管理会员管理会员信息、积分管理、消费记录统计报表销售统计、库存统计、会员消费分析1.2 技术栈选择理由选择SpringBootVueMySQL的技术组合主要基于以下考虑后端技术栈SpringBoot 2.7快速构建RESTful API内置Tomcat服务器MyBatis-Plus简化数据库操作提供强大的CRUD功能Spring Security实现权限控制和用户认证MySQL 8.0稳定可靠的关系型数据库前端技术栈Vue 3.0渐进式JavaScript框架组件化开发Element Plus丰富的UI组件库提升开发效率AxiosHTTP请求库处理前后端数据交互Vue Router前端路由管理实现单页面应用这种技术组合的优势在于前后端分离架构清晰SpringBoot提供稳定的后端服务Vue提供灵活的前端交互非常适合中小型管理系统的开发需求。2. 开发环境准备2.1 软件版本要求在开始项目之前需要确保本地开发环境包含以下软件后端开发环境JDK 1.8或更高版本Maven 3.6 用于依赖管理IntelliJ IDEA或Eclipse开发工具MySQL 8.0数据库前端开发环境Node.js 16.0npm或yarn包管理器Vue CLI 5.0 脚手架工具Visual Studio Code或WebStorm编辑器2.2 数据库环境配置首先创建项目所需的数据库-- 创建数据库 CREATE DATABASE IF NOT EXISTS supermarket DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 使用数据库 USE supermarket; -- 创建用户表 CREATE TABLE sys_user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码, real_name varchar(50) DEFAULT NULL COMMENT 真实姓名, phone varchar(20) DEFAULT NULL COMMENT 手机号, email varchar(100) DEFAULT NULL COMMENT 邮箱, status tinyint(1) DEFAULT 1 COMMENT 状态0-禁用1-启用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户表; -- 插入管理员用户 INSERT INTO sys_user (username, password, real_name, phone, email, status) VALUES (admin, $2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTV2UiC, 系统管理员, 13800138000, adminsupermarket.com, 1);2.3 项目结构规划采用标准的前后端分离项目结构supermarket-management/ ├── supermarket-backend/ # SpringBoot后端项目 │ ├── src/main/java/ │ │ └── com/supermarket/ │ │ ├── controller/ # 控制器层 │ │ ├── service/ # 业务层 │ │ ├── mapper/ # 数据访问层 │ │ ├── entity/ # 实体类 │ │ └── config/ # 配置类 │ ├── src/main/resources/ │ │ ├── application.yml # 主配置文件 │ │ └── mapper/ # MyBatis映射文件 │ └── pom.xml # Maven依赖配置 ├── supermarket-frontend/ # Vue前端项目 │ ├── public/ # 静态资源 │ ├── src/ │ │ ├── components/ # 公共组件 │ │ ├── views/ # 页面组件 │ │ ├── router/ # 路由配置 │ │ ├── api/ # API接口 │ │ └── utils/ # 工具类 │ ├── package.json # 项目依赖 │ └── vue.config.js # Vue配置 └── README.md # 项目说明文档3. 后端SpringBoot项目搭建3.1 创建SpringBoot项目使用Spring Initializr创建项目基础结构选择以下依赖Spring WebSpring SecurityMyBatis FrameworkMySQL DriverLombokpom.xml关键依赖配置?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.0/version relativePath/ /parent groupIdcom.supermarket/groupId artifactIdsupermarket-backend/artifactId version1.0.0/version properties java.version1.8/java.version mybatis-plus.version3.5.2/mybatis-plus.version jwt.version0.9.1/jwt.version /properties dependencies !-- SpringBoot基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency !-- MyBatis-Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version${mybatis-plus.version}/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- JWT令牌 -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version${jwt.version}/version /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies /project3.2 数据库配置与实体类设计application.yml配置文件server: port: 8080 servlet: context-path: /api spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/supermarket?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 logging: level: com.supermarket.mapper: debug商品实体类设计package com.supermarket.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; Data TableName(product) public class Product { TableId(type IdType.AUTO) private Long id; private String productCode; // 商品编码 private String productName; // 商品名称 private Long categoryId; // 分类ID private String unit; // 单位 private BigDecimal price; // 售价 private BigDecimal costPrice; // 成本价 private Integer stock; // 库存数量 private Integer minStock; // 最小库存预警 private String description; // 商品描述 private String imageUrl; // 商品图片 private Integer status; // 状态0-下架1-上架 TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; }3.3 Spring Security权限配置实现JWT认证和权限控制package com.supermarket.config; import com.supermarket.filter.JwtAuthenticationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; Configuration EnableGlobalMethodSecurity(prePostEnabled true) public class SecurityConfig extends WebSecurityConfigurerAdapter { Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } Bean Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } Override protected void configure(HttpSecurity http) throws Exception { http // 关闭csrf .csrf().disable() // 不通过Session获取SecurityContext .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() // 对于登录接口允许匿名访问 .antMatchers(/user/login).anonymous() // 除上面外的所有请求都需要认证 .anyRequest().authenticated(); // 添加JWT过滤器 http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } }3.4 商品管理核心接口实现商品控制器类package com.supermarket.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.supermarket.entity.Product; import com.supermarket.service.ProductService; import com.supermarket.vo.ProductQueryVO; import com.supermarket.vo.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; RestController RequestMapping(/product) public class ProductController { Autowired private ProductService productService; /** * 分页查询商品列表 */ GetMapping(/list) public ResultIPageProduct list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, ProductQueryVO queryVO) { PageProduct page new Page(pageNum, pageSize); QueryWrapperProduct wrapper new QueryWrapper(); if (queryVO.getProductName() ! null) { wrapper.like(product_name, queryVO.getProductName()); } if (queryVO.getCategoryId() ! null) { wrapper.eq(category_id, queryVO.getCategoryId()); } if (queryVO.getStatus() ! null) { wrapper.eq(status, queryVO.getStatus()); } wrapper.orderByDesc(create_time); IPageProduct productPage productService.page(page, wrapper); return Result.success(productPage); } /** * 添加商品 */ PostMapping(/add) public ResultString add(RequestBody Product product) { // 检查商品编码是否重复 QueryWrapperProduct wrapper new QueryWrapper(); wrapper.eq(product_code, product.getProductCode()); if (productService.getOne(wrapper) ! null) { return Result.error(商品编码已存在); } productService.save(product); return Result.success(添加成功); } /** * 更新商品信息 */ PutMapping(/update) public ResultString update(RequestBody Product product) { productService.updateById(product); return Result.success(更新成功); } /** * 删除商品 */ DeleteMapping(/delete/{id}) public ResultString delete(PathVariable Long id) { productService.removeById(id); return Result.success(删除成功); } /** * 商品上架/下架 */ PutMapping(/status/{id}/{status}) public ResultString updateStatus(PathVariable Long id, PathVariable Integer status) { Product product new Product(); product.setId(id); product.setStatus(status); productService.updateById(product); return Result.success(status 1 ? 上架成功 : 下架成功); } }商品服务实现类package com.supermarket.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.supermarket.entity.Product; import com.supermarket.mapper.ProductMapper; import com.supermarket.service.ProductService; import org.springframework.stereotype.Service; Service public class ProductServiceImpl extends ServiceImplProductMapper, Product implements ProductService { Override public boolean updateStock(Long productId, Integer quantity) { Product product this.getById(productId); if (product null) { return false; } Integer newStock product.getStock() quantity; if (newStock 0) { throw new RuntimeException(库存不足); } Product updateProduct new Product(); updateProduct.setId(productId); updateProduct.setStock(newStock); return this.updateById(updateProduct); } }4. 前端Vue项目开发4.1 Vue项目初始化使用Vue CLI创建项目# 创建Vue项目 vue create supermarket-frontend # 进入项目目录 cd supermarket-frontend # 安装必要依赖 npm install element-plus element-plus/icons-vue axios vue-router项目主入口文件main.jsimport { createApp } from vue import App from ./App.vue import router from ./router import ElementPlus from element-plus import element-plus/dist/index.css import * as ElementPlusIconsVue from element-plus/icons-vue const app createApp(App) // 注册Element Plus图标 for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.use(ElementPlus) app.use(router) app.mount(#app)4.2 前端路由配置router/index.js路由配置import { createRouter, createWebHistory } from vue-router const routes [ { path: /login, name: Login, component: () import(/views/Login.vue) }, { path: /, name: Layout, component: () import(/layout/Layout.vue), redirect: /dashboard, children: [ { path: dashboard, name: Dashboard, component: () import(/views/Dashboard.vue), meta: { title: 控制台 } }, { path: product, name: Product, component: () import(/views/product/ProductList.vue), meta: { title: 商品管理 } }, { path: product/add, name: ProductAdd, component: () import(/views/product/ProductForm.vue), meta: { title: 添加商品 } }, { path: product/edit/:id, name: ProductEdit, component: () import(/views/product/ProductForm.vue), meta: { title: 编辑商品 } }, { path: category, name: Category, component: () import(/views/category/CategoryList.vue), meta: { title: 分类管理 } } ] } ] const router createRouter({ history: createWebHistory(), routes }) // 路由守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path ! /login !token) { next(/login) } else { next() } }) export default router4.3 商品管理页面实现商品列表页面template div classproduct-container el-card template #header div classcard-header span商品管理/span el-button typeprimary clickhandleAdd iconPlus添加商品/el-button /div /template !-- 搜索条件 -- el-form :modelqueryParams inline el-form-item label商品名称 el-input v-modelqueryParams.productName placeholder请输入商品名称 clearable / /el-form-item el-form-item label商品分类 el-select v-modelqueryParams.categoryId placeholder请选择分类 clearable el-option v-forcategory in categoryList :keycategory.id :labelcategory.categoryName :valuecategory.id / /el-select /el-form-item el-form-item label状态 el-select v-modelqueryParams.status placeholder请选择状态 clearable el-option label上架 value1 / el-option label下架 value0 / /el-select /el-form-item el-form-item el-button typeprimary clickloadProductList搜索/el-button el-button clickhandleReset重置/el-button /el-form-item /el-form !-- 商品表格 -- el-table :dataproductList v-loadingloading el-table-column propproductCode label商品编码 width120 / el-table-column propproductName label商品名称 min-width150 / el-table-column propcategoryName label分类 width100 / el-table-column propprice label售价 width100 template #defaultscope ¥{{ scope.row.price }} /template /el-table-column el-table-column propstock label库存 width80 / el-table-column propstatus label状态 width80 template #defaultscope el-tag :typescope.row.status 1 ? success : info {{ scope.row.status 1 ? 上架 : 下架 }} /el-tag /template /el-table-column el-table-column propcreateTime label创建时间 width180 / el-table-column label操作 width200 fixedright template #defaultscope el-button sizesmall clickhandleEdit(scope.row)编辑/el-button el-button sizesmall :typescope.row.status 1 ? warning : success clickhandleStatus(scope.row) {{ scope.row.status 1 ? 下架 : 上架 }} /el-button el-button sizesmall typedanger clickhandleDelete(scope.row)删除/el-button /template /el-table-column /el-table !-- 分页 -- div classpagination-container el-pagination v-model:current-pagequeryParams.pageNum v-model:page-sizequeryParams.pageSize :totaltotal current-changeloadProductList size-changehandleSizeChange layouttotal, sizes, prev, pager, next, jumper :page-sizes[10, 20, 50, 100] / /div /el-card /div /template script import { getProductList, updateProductStatus, deleteProduct } from /api/product import { getCategoryList } from /api/category export default { name: ProductList, data() { return { loading: false, productList: [], categoryList: [], total: 0, queryParams: { pageNum: 1, pageSize: 10, productName: , categoryId: null, status: null } } }, mounted() { this.loadProductList() this.loadCategoryList() }, methods: { // 加载商品列表 async loadProductList() { this.loading true try { const response await getProductList(this.queryParams) this.productList response.data.records this.total response.data.total } catch (error) { this.$message.error(加载商品列表失败) } finally { this.loading false } }, // 加载分类列表 async loadCategoryList() { try { const response await getCategoryList() this.categoryList response.data } catch (error) { this.$message.error(加载分类列表失败) } }, // 添加商品 handleAdd() { this.$router.push(/product/add) }, // 编辑商品 handleEdit(row) { this.$router.push(/product/edit/${row.id}) }, // 上架/下架商品 async handleStatus(row) { const newStatus row.status 1 ? 0 : 1 const statusText newStatus 1 ? 上架 : 下架 try { await updateProductStatus(row.id, newStatus) this.$message.success(${statusText}成功) this.loadProductList() } catch (error) { this.$message.error(${statusText}失败) } }, // 删除商品 handleDelete(row) { this.$confirm(确定要删除商品${row.productName}吗, 提示, { type: warning }).then(async () { try { await deleteProduct(row.id) this.$message.success(删除成功) this.loadProductList() } catch (error) { this.$message.error(删除失败) } }) }, // 重置搜索条件 handleReset() { this.queryParams { pageNum: 1, pageSize: 10, productName: , categoryId: null, status: null } this.loadProductList() }, // 分页大小改变 handleSizeChange(size) { this.queryParams.pageSize size this.loadProductList() } } } /script style scoped .product-container { padding: 20px; } .card-header { display: flex; justify-content: space-between; align-items: center; } .pagination-container { margin-top: 20px; text-align: right; } /style4.4 API接口封装前端API接口统一管理// api/product.js import request from /utils/request // 获取商品列表 export function getProductList(params) { return request({ url: /product/list, method: get, params }) } // 添加商品 export function addProduct(data) { return request({ url: /product/add, method: post, data }) } // 更新商品 export function updateProduct(data) { return request({ url: /product/update, method: put, data }) } // 删除商品 export function deleteProduct(id) { return request({ url: /product/delete/${id}, method: delete }) } // 更新商品状态 export function updateProductStatus(id, status) { return request({ url: /product/status/${id}/${status}, method: put }) }请求拦截器配置// utils/request.js import axios from axios import { ElMessage } from element-plus import router from /router // 创建axios实例 const service axios.create({ baseURL: http://localhost:8080/api, timeout: 10000 }) // 请求拦截器 service.interceptors.request.use( config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }, error { return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message || Error)) } return res }, error { if (error.response.status 401) { ElMessage.error(登录已过期请重新登录) localStorage.removeItem(token) router.push(/login) } else { ElMessage.error(error.message || 请求失败) } return Promise.reject(error) } ) export default service5. 核心业务功能实现5.1 库存管理模块库存实体类和Mapperpackage com.supermarket.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; Data TableName(stock) public class Stock { TableId(type IdType.AUTO) private Long id; private Long productId; // 商品ID private String operationType; // 操作类型IN-入库OUT-出库 private Integer quantity; // 操作数量 private BigDecimal unitPrice; // 单价 private BigDecimal totalAmount; // 总金额 private String operator; // 操作人 private String remark; // 备注 TableField(fill FieldFill.INSERT) private LocalDateTime createTime; } // StockMapper.java package com.supermarket.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.supermarket.entity.Stock; import org.apache.ibatis.annotations.Mapper; Mapper public interface StockMapper extends BaseMapperStock { }库存服务实现package com.supermarket.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.supermarket.entity.Stock; import com.supermarket.mapper.StockMapper; import com.supermarket.service.ProductService; import com.supermarket.service.StockService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; Service public class StockServiceImpl extends ServiceImplStockMapper, Stock implements StockService { Autowired private ProductService productService; /** * 入库操作 */ Override Transactional public boolean stockIn(Stock stock) { // 更新商品库存 boolean success productService.updateStock(stock.getProductId(), stock.getQuantity()); if (success) { // 记录入库流水 stock.setOperationType(IN); return this.save(stock); } return false; } /** * 出库操作 */ Override Transactional public boolean stockOut(Stock stock) { // 更新商品库存数量为负数 boolean success productService.updateStock(stock.getProductId(), -stock.getQuantity()); if (success) { // 记录出库流水 stock.setOperationType(OUT); return this.save(stock); } return false; } }5.2 订单管理模块订单相关实体类package com.supermarket.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; Data TableName(order) public class Order { TableId(type IdType.AUTO) private Long id; private String orderNo; // 订单编号 private Long memberId; // 会员ID private BigDecimal totalAmount; // 订单总金额 private BigDecimal discountAmount; // 优惠金额 private BigDecimal payAmount; // 实付金额 private Integer status; // 订单状态0-待支付1-已支付2-已完成3-已取消 private String payMethod; // 支付方式CASH-现金ALIPAY-支付宝WECHAT-微信 private String remark; // 备注 TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; // 订单明细列表非数据库字段 TableField(exist false) private ListOrderItem orderItems; } Data TableName(order_item) public class OrderItem { TableId(type IdType.AUTO) private Long id; private Long orderId; // 订单ID private Long productId; // 商品ID private String productName; // 商品名称 private BigDecimal price; // 单价 private Integer quantity; // 数量 private BigDecimal amount; // 金额 }订单服务核心逻辑package com.supermarket.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.supermarket.entity.Order; import com.supermarket.entity.OrderItem; import com.supermarket.mapper.OrderMapper; import com.supermarket.service.OrderService; import com.supermarket.service.StockService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; Service public class OrderServiceImpl extends ServiceImplOrderMapper, Order implements OrderService { Autowired private StockService stockService; /** * 创建订单 */ Override Transactional public boolean createOrder(Order order) { // 生成订单编号 order.setOrderNo(generateOrderNo()); // 计算订单金额 calculateOrderAmount(order); // 保存订单 boolean orderSaved this.save(order); if (orderSaved) { // 保存订单明细 for (OrderItem item : order.getOrderItems()) { item.setOrderId(order.getId()); // 这里需要调用OrderItem的保存方法 } // 扣减库存 for (OrderItem item : order.getOrderItems()) { // 创建出库记录 // stockService.stockOut(...); } return true; } return false; } /** * 生成订单编号 */ private String generateOrderNo() { return ORD System.currentTimeMillis(); } /** * 计算订单金额 */ private void calculateOrderAmount(Order order) { BigDecimal totalAmount BigDecimal.ZERO; for (OrderItem item : order.getOrderItems()) { BigDecimal itemAmount item.getPrice().multiply(new BigDecimal(item.getQuantity())); item.setAmount(itemAmount); totalAmount totalAmount.add(itemAmount); } order.setTotalAmount(totalAmount); order.setPayAmount(totalAmount.subtract(order.getDiscountAmount() ! null ? order.getDiscountAmount() : BigDecimal.ZERO)); } }6. 系统部署与运行6.1 后端项目打包部署使用Maven打包SpringBoot项目# 进入后端项目目录 cd supermarket-backend # 清理并打包 mvn clean package -Dmaven.test.skiptrue # 运行jar包 java -jar target/supermarket-backend-1.0.0.jarDocker部署配置# Dockerfile FROM openjdk:8-jre-slim VOLUME /tmp COPY target/supermarket-backend-1.0.0.jar app.jar ENTRYPOINT [java,-Djava.security.egdfile:/dev/./urandom,-jar,/app.jar]6.2 前端项目构建部署构建前端项目# 进入前端项目目录 cd supermarket-frontend # 安装依赖 npm install # 构建生产版本 npm run buildNginx配置server { listen 80; server_name localhost; # 前端静态资源 location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } # 后端API代理 location /api/ { proxy_pass http://backend-server:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }6.3 数据库初始化脚本完整的数据库表结构-- 商品分类表 CREATE TABLE product_category ( id bigint(20) NOT NULL AUTO