commit 5aa2017eefb3e60133fbc24edfd3ca97bbfe58f7 Author: qingfeng1121 Date: Mon Nov 24 15:02:19 2025 +0800 feat: 初始化后端项目基础架构 添加项目基础配置文件和目录结构 实现用户、角色、权限等核心模块的实体类、Mapper接口和服务层 配置数据库连接和MyBatis-Plus支持 添加统一响应格式和异常处理机制 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..667aaef --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c0bcafe --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip diff --git a/Plain.text b/Plain.text new file mode 100644 index 0000000..9093616 --- /dev/null +++ b/Plain.text @@ -0,0 +1,81 @@ +e:\TaoTaoWang\backend\ +├── pom.xml # Maven依赖配置 +├── src/main/java/com/taotaowang/ +│ ├── TaotaoWangApplication.java # 应用主启动类 +│ ├── config/ # 配置类 +│ │ ├── SecurityConfig.java # 安全配置 +│ │ ├── MyBatisPlusConfig.java # MyBatis-Plus配置 +│ │ ├── RedisConfig.java # Redis配置 +│ │ ├── SwaggerConfig.java # Swagger文档配置 +│ │ └── WebConfig.java # Web配置 +│ ├── controller/ # 控制器层 +│ │ ├── AuthController.java # 认证相关接口 +│ │ ├── UserController.java # 用户管理接口 +│ │ ├── RoleController.java # 角色管理接口 +│ │ ├── PermissionController.java # 权限管理接口 +│ │ ├── ProductController.java # 商品管理接口 +│ │ ├── OrderController.java # 订单管理接口 +│ │ ├── ShopController.java # 店铺管理接口 +│ │ └── MarketingController.java # 营销活动接口 +│ ├── service/ # 业务层 +│ │ ├── impl/ # 业务实现类 +│ │ │ ├── AuthServiceImpl.java +│ │ │ ├── UserServiceImpl.java +│ │ │ ├── RoleServiceImpl.java +│ │ │ ├── PermissionServiceImpl.java +│ │ │ ├── ProductServiceImpl.java +│ │ │ ├── OrderServiceImpl.java +│ │ │ ├── ShopServiceImpl.java +│ │ │ └── MarketingServiceImpl.java +│ │ ├── AuthService.java # 认证服务接口 +│ │ ├── UserService.java # 用户服务接口 +│ │ ├── RoleService.java # 角色服务接口 +│ │ ├── PermissionService.java # 权限服务接口 +│ │ ├── ProductService.java # 商品服务接口 +│ │ ├── OrderService.java # 订单服务接口 +│ │ ├── ShopService.java # 店铺服务接口 +│ │ └── MarketingService.java # 营销服务接口 +│ ├── mapper/ # 数据访问层 +│ │ ├── UserMapper.java +│ │ ├── RoleMapper.java +│ │ ├── PermissionMapper.java +│ │ ├── ProductMapper.java +│ │ ├── OrderMapper.java +│ │ └── ShopMapper.java +│ ├── entity/ # 实体层 +│ │ ├── User.java +│ │ ├── Role.java +│ │ ├── Permission.java +│ │ ├── Product.java +│ │ ├── Order.java +│ │ ├── Shop.java +│ │ └── Marketing.java +│ ├── dto/ # 数据传输对象 +│ │ ├── request/ # 请求DTO +│ │ │ ├── LoginRequest.java +│ │ │ ├── RegisterRequest.java +│ │ │ ├── ProductRequest.java +│ │ │ └── OrderRequest.java +│ │ └── response/ # 响应DTO +│ │ ├── LoginResponse.java +│ │ ├── UserResponse.java +│ │ ├── ProductResponse.java +│ │ └── OrderResponse.java +│ ├── exception/ # 异常处理 +│ │ ├── GlobalExceptionHandler.java # 全局异常处理器 +│ │ ├── BusinessException.java # 业务异常 +│ │ └── ErrorCode.java # 错误码定义 +│ ├── util/ # 工具类 +│ │ ├── JwtUtil.java # JWT工具 +│ │ ├── SecurityUtil.java # 安全工具 +│ │ └── ResponseUtil.java # 响应工具 +│ └── interceptor/ # 拦截器 +│ ├── JwtInterceptor.java # JWT拦截器 +│ └── LogInterceptor.java # 日志拦截器 +└── src/main/resources/ + ├── application.yml # 主配置文件 + ├── application-dev.yml # 开发环境配置 + ├── application-test.yml # 测试环境配置 + ├── application-prod.yml # 生产环境配置 + ├── mapper/ # MyBatis映射文件 + └── static/ # 静态资源 \ No newline at end of file diff --git a/doc/数据库关系图.md b/doc/数据库关系图.md new file mode 100644 index 0000000..e914ee6 --- /dev/null +++ b/doc/数据库关系图.md @@ -0,0 +1,268 @@ +# 数据库关系图 + +下面使用Mermaid语法生成的数据库实体关系图(ER图),展示了系统中各个表之间的关联关系: + +```mermaid +erDiagram + %% 用户相关表 + users ||--o{ user_details : has + users ||--o{ shops : owns + users ||--o{ orders : places + users ||--o{ payments : makes + users ||--o{ refunds : requests + users ||--o{ shop_ratings : writes + users ||--o{ user_roles : assigned_to + + %% 权限相关表 + roles ||--o{ user_roles : has + roles ||--o{ role_permissions : contains + permissions ||--o{ role_permissions : included_in + + %% 店铺相关表 + shops ||--o{ products : sells + shops ||--o{ orders : receives + shops ||--o{ refunds : processes + shops ||--o{ shop_ratings : receives + shop_categories ||--o{ shops : categorizes + shop_categories }o--|| shop_categories : parent + + %% 商品相关表 + products ||--o{ product_images : has + products ||--o{ product_skus : contains + products ||--o{ product_attribute_values : has + products ||--o{ order_items : included_in + product_categories ||--o{ products : categorizes + product_categories }o--|| product_categories : parent + product_categories ||--o{ product_attributes : defines + product_attributes ||--o{ product_attribute_values : has + product_skus ||--o{ product_inventories : manages + product_skus ||--o{ order_items : selected_in + + %% 订单相关表 + orders ||--o{ order_items : contains + orders ||--o{ order_status_history : tracks + orders ||--o{ payments : related_to + orders ||--o{ refunds : triggers + orders ||--o{ shop_ratings : based_on + + %% 支付与退款相关表 + payments ||--o{ refunds : reversed_by + order_items ||--o{ refunds : includes + + %% 表定义 + users { + BIGINT id PK + VARCHAR username + VARCHAR password + VARCHAR email + VARCHAR phone + INTEGER status + } + + user_details { + BIGINT id PK + BIGINT userId FK + VARCHAR realName + VARCHAR idCard + INTEGER gender + } + + roles { + BIGINT id PK + VARCHAR roleName + INTEGER roleType + INTEGER status + } + + permissions { + BIGINT id PK + VARCHAR permissionName + VARCHAR permissionCode + INTEGER status + } + + user_roles { + BIGINT id PK + BIGINT userId FK + BIGINT roleId FK + } + + role_permissions { + BIGINT id PK + BIGINT roleId FK + BIGINT permissionId FK + } + + shops { + BIGINT id PK + VARCHAR shopName + BIGINT userId FK + BIGINT categoryId FK + INTEGER status + } + + shop_categories { + BIGINT id PK + VARCHAR categoryName + BIGINT parentId FK + INTEGER level + INTEGER status + } + + products { + BIGINT id PK + VARCHAR productName + BIGINT shopId FK + BIGINT categoryId FK + DECIMAL price + INTEGER stock + INTEGER status + } + + product_categories { + BIGINT id PK + VARCHAR categoryName + BIGINT parentId FK + INTEGER level + INTEGER status + } + + product_attributes { + BIGINT id PK + VARCHAR attributeName + BIGINT categoryId FK + INTEGER attributeType + INTEGER status + } + + product_attribute_values { + BIGINT id PK + BIGINT productId FK + BIGINT attributeId FK + VARCHAR attributeValue + } + + product_images { + BIGINT id PK + BIGINT productId FK + VARCHAR imageUrl + INTEGER isMain + } + + product_skus { + BIGINT id PK + BIGINT productId FK + VARCHAR skuCode + DECIMAL price + INTEGER stock + INTEGER status + } + + product_inventories { + BIGINT id PK + BIGINT skuId FK + INTEGER currentStock + INTEGER safetyStock + INTEGER lockStock + } + + orders { + BIGINT id PK + VARCHAR orderNo + BIGINT userId FK + BIGINT shopId FK + DECIMAL totalAmount + INTEGER orderStatus + } + + order_items { + BIGINT id PK + BIGINT orderId FK + BIGINT productId FK + BIGINT skuId FK + DECIMAL price + INTEGER quantity + INTEGER itemStatus + } + + order_status_history { + BIGINT id PK + BIGINT orderId FK + INTEGER previousStatus + INTEGER currentStatus + } + + payments { + BIGINT id PK + VARCHAR paymentNo + BIGINT orderId FK + BIGINT userId FK + DECIMAL amount + INTEGER paymentStatus + } + + refunds { + BIGINT id PK + VARCHAR refundNo + BIGINT orderId FK + BIGINT orderItemId FK + BIGINT userId FK + BIGINT shopId FK + DECIMAL refundAmount + INTEGER refundStatus + } + + shop_ratings { + BIGINT id PK + BIGINT shopId FK + BIGINT userId FK + BIGINT orderId FK + INTEGER rating + INTEGER status + } +``` + +## 关系说明 + +### 一对一关系 +- **users 和 user_details**:每个用户只有一个详细信息记录 + +### 一对多关系 +- **users 和 shops**:一个用户可以创建多个店铺 +- **shops 和 products**:一个店铺可以有多个商品 +- **users 和 orders**:一个用户可以有多个订单 +- **shops 和 orders**:一个店铺可以有多个订单 +- **orders 和 order_items**:一个订单可以包含多个商品项 +- **products 和 product_images**:一个商品可以有多个图片 +- **products 和 product_skus**:一个商品可以有多个SKU +- **product_skus 和 product_inventories**:一个SKU对应一个库存记录 +- **orders 和 order_status_history**:一个订单可以有多个状态历史记录 +- **orders 和 payments**:一个订单可以有多个支付记录 +- **orders 和 refunds**:一个订单可以有多个退款记录 +- **order_items 和 refunds**:一个订单项可以有多个退款记录 +- **shops 和 shop_ratings**:一个店铺可以有多个评价 +- **users 和 shop_ratings**:一个用户可以对多个店铺进行评价 +- **orders 和 shop_ratings**:一个订单对应一个店铺评价 + +### 多对多关系 +- **users 和 roles**:通过user_roles表关联 +- **roles 和 permissions**:通过role_permissions表关联 + +### 自关联关系 +- **shop_categories 和 shop_categories**:店铺分类的父子关系 +- **product_categories 和 product_categories**:商品分类的父子关系 + +## 查看方法 + +要查看此关系图,可以使用支持Mermaid语法的工具或编辑器,例如: + +1. **在线工具**: + - [Mermaid Live Editor](https://mermaid.live/) + - [Markdown Preview Enhanced](https://shd101wyy.github.io/markdown-preview-enhanced/#/) + +2. **IDE插件**: + - VS Code的Markdown Preview Enhanced插件 + - IntelliJ IDEA的Mermaid插件 + +3. **版本控制系统**: + - GitHub、GitLab等平台已支持Mermaid语法渲染 \ No newline at end of file diff --git a/doc/数据库关系图_简洁版.md b/doc/数据库关系图_简洁版.md new file mode 100644 index 0000000..e339323 --- /dev/null +++ b/doc/数据库关系图_简洁版.md @@ -0,0 +1,95 @@ +# 数据库关系图(简洁版) + +下面是使用Mermaid语法生成的简洁版数据库实体关系图,重点突出表之间的关联关系: + +```mermaid +erDiagram + %% 用户与权限系统 + users ||--o{ user_details : has + users }o--o{ roles : "多对多" via user_roles + roles }o--o{ permissions : "多对多" via role_permissions + + %% 店铺系统 + users ||--o{ shops : owns + shops ||--o{ products : sells + shop_categories ||--o{ shops : categorizes + shop_categories }o--|| shop_categories : parent-child + + %% 商品系统 + products ||--o{ product_images : has + products ||--o{ product_skus : contains + products ||--o{ product_attribute_values : has_attributes + product_categories ||--o{ products : categorizes + product_categories }o--|| product_categories : parent-child + product_categories ||--o{ product_attributes : defines + product_attributes ||--o{ product_attribute_values : values + product_skus ||--o{ product_inventories : inventory + + %% 订单系统 + users ||--o{ orders : places + shops ||--o{ orders : receives + orders ||--o{ order_items : contains + orders ||--o{ order_status_history : status_history + order_items ||--o{ products : product + order_items ||--o{ product_skus : sku + + %% 支付与退款 + orders ||--o{ payments : payment + orders ||--o{ refunds : refund + order_items ||--o{ refunds : item_refund + payments ||--o{ refunds : reversed_by + + %% 评价系统 + users ||--o{ shop_ratings : reviews + shops ||--o{ shop_ratings : rated + orders ||--o{ shop_ratings : based_on +``` + +## 核心表关系说明 + +### 1. 用户与权限模块 +- **用户-详情**:一对一关系,用户信息和用户详细资料分离存储 +- **用户-角色**:多对多关系,通过user_roles关联表实现 +- **角色-权限**:多对多关系,通过role_permissions关联表实现 + +### 2. 店铺模块 +- **用户-店铺**:一对多关系,一个用户可以创建多个店铺 +- **店铺分类-店铺**:一对多关系,一个分类包含多个店铺 +- **店铺分类自身**:自关联,支持多级分类结构 + +### 3. 商品模块 +- **店铺-商品**:一对多关系,一个店铺可以销售多个商品 +- **商品-图片**:一对多关系,一个商品可以有多张图片 +- **商品-SKU**:一对多关系,一个商品可以有多个SKU(库存单元) +- **SKU-库存**:一对一关系,每个SKU对应一个库存记录 +- **商品-属性值**:一对多关系,一个商品可以有多个属性值 +- **商品分类-商品**:一对多关系,一个分类包含多个商品 +- **商品分类-属性**:一对多关系,一个分类定义多个属性 +- **属性-属性值**:一对多关系,一个属性可以有多个值 + +### 4. 订单模块 +- **用户-订单**:一对多关系,一个用户可以下多个订单 +- **店铺-订单**:一对多关系,一个店铺可以接收多个订单 +- **订单-订单项**:一对多关系,一个订单包含多个商品项 +- **订单项-商品/SKU**:多对一关系,订单项关联到具体的商品和SKU +- **订单-状态历史**:一对多关系,记录订单状态变更历史 + +### 5. 支付与退款模块 +- **订单-支付**:一对多关系,一个订单可以有多次支付记录 +- **订单-退款**:一对多关系,一个订单可以有多次退款 +- **订单项-退款**:一对多关系,一个订单项可以有多次退款 +- **支付-退款**:一对多关系,一笔支付可以对应多笔退款 + +### 6. 评价模块 +- **用户-评价**:一对多关系,用户可以对多个店铺评价 +- **店铺-评价**:一对多关系,店铺可以收到多个评价 +- **订单-评价**:一对一关系,一个订单对应一个评价 + +## 表关系符号说明 + +- `||--o{` : 一对一关系(1:1) +- `||--o{` : 一对多关系(1:N) +- `}o--o{` : 多对多关系(N:M) +- `}o--||` : 自关联关系 + +此简洁版关系图重点突出了系统各模块之间的核心关联,有助于理解整个数据库的设计架构。 \ No newline at end of file diff --git a/doc/数据库表结构与关系文档.md b/doc/数据库表结构与关系文档.md new file mode 100644 index 0000000..fdddda9 --- /dev/null +++ b/doc/数据库表结构与关系文档.md @@ -0,0 +1,467 @@ +# 数据库表结构与关系文档 + +## 目录 + +1. [用户相关表](#用户相关表) +2. [权限相关表](#权限相关表) +3. [店铺相关表](#店铺相关表) +4. [商品相关表](#商品相关表) +5. [订单相关表](#订单相关表) +6. [支付与退款相关表](#支付与退款相关表) +7. [评价相关表](#评价相关表) +8. [表与表之间的关系](#表与表之间的关系) + +## 用户相关表 + +### users表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 用户ID | 主键,自增 | +| username | VARCHAR | 用户名 | 唯一 | +| password | VARCHAR | 密码 | 加密存储 | +| email | VARCHAR | 邮箱 | 唯一 | +| phone | VARCHAR | 手机号 | 唯一 | +| avatar | VARCHAR | 头像URL | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| lastLoginTime | DATE | 最后登录时间 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### user_details表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 详情ID | 主键,自增 | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| realName | VARCHAR | 真实姓名 | | +| idCard | VARCHAR | 身份证号 | | +| gender | INTEGER | 性别 | | +| birthday | DATE | 生日 | | +| address | VARCHAR | 地址 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +## 权限相关表 + +### roles表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 角色ID | 主键,自增 | +| roleName | VARCHAR | 角色名称 | | +| description | VARCHAR | 角色描述 | | +| roleType | INTEGER | 角色类型 | 0:默认用户,1:店主,2:管理员 | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### permissions表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 权限ID | 主键,自增 | +| permissionName | VARCHAR | 权限名称 | | +| permissionCode | VARCHAR | 权限编码 | | +| description | VARCHAR | 权限描述 | | +| module | VARCHAR | 所属模块 | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### user_roles表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 关联ID | 主键,自增 | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| roleId | BIGINT | 角色ID | 外键,关联roles表 | +| createdAt | DATE | 创建时间 | | + +### role_permissions表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 关联ID | 主键,自增 | +| roleId | BIGINT | 角色ID | 外键,关联roles表 | +| permissionId | BIGINT | 权限ID | 外键,关联permissions表 | +| createdAt | DATE | 创建时间 | | + +## 店铺相关表 + +### shops表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 店铺ID | 主键,自增 | +| shopName | VARCHAR | 店铺名称 | | +| userId | BIGINT | 店主用户ID | 外键,关联users表 | +| categoryId | BIGINT | 店铺分类ID | 外键,关联shop_categories表 | +| logo | VARCHAR | 店铺Logo | | +| coverImage | VARCHAR | 店铺封面图 | | +| description | VARCHAR | 店铺描述 | | +| status | INTEGER | 状态 | 0:待审核, 1:正常, 2:封禁 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### shop_categories表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 分类ID | 主键,自增 | +| categoryName | VARCHAR | 分类名称 | | +| parentId | BIGINT | 父分类ID | | +| level | INTEGER | 分类级别 | | +| sort | INTEGER | 排序 | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +## 商品相关表 + +### products表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 商品ID | 主键,自增 | +| productName | VARCHAR | 商品名称 | | +| shopId | BIGINT | 店铺ID | 外键,关联shops表 | +| categoryId | BIGINT | 商品分类ID | 外键,关联product_categories表 | +| brand | VARCHAR | 品牌 | | +| description | VARCHAR | 商品描述 | | +| mainImage | VARCHAR | 主图URL | | +| price | DECIMAL | 价格 | | +| originalPrice | DECIMAL | 原价 | | +| stock | INTEGER | 库存 | | +| sales | INTEGER | 销量 | | +| status | INTEGER | 状态 | 0:下架, 1:上架 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### product_categories表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 分类ID | 主键,自增 | +| categoryName | VARCHAR | 分类名称 | | +| parentId | BIGINT | 父分类ID | | +| level | INTEGER | 分类级别 | | +| sort | INTEGER | 排序 | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### product_attributes表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 属性ID | 主键,自增 | +| attributeName | VARCHAR | 属性名称 | | +| categoryId | BIGINT | 分类ID | 外键,关联product_categories表 | +| attributeType | INTEGER | 属性类型 | 0:普通属性, 1:规格属性 | +| sort | INTEGER | 排序 | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### product_attribute_values表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 属性值ID | 主键,自增 | +| productId | BIGINT | 商品ID | 外键,关联products表 | +| attributeId | BIGINT | 属性ID | 外键,关联product_attributes表 | +| attributeValue | VARCHAR | 属性值 | | +| sort | INTEGER | 排序 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### product_images表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 图片ID | 主键,自增 | +| productId | BIGINT | 商品ID | 外键,关联products表 | +| imageUrl | VARCHAR | 图片URL | | +| sort | INTEGER | 排序 | | +| isMain | INTEGER | 是否主图 | 0:非主图, 1:主图 | +| createdAt | DATE | 创建时间 | | + +### product_skus表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | SKU ID | 主键,自增 | +| productId | BIGINT | 商品ID | 外键,关联products表 | +| skuCode | VARCHAR | SKU编码 | | +| skuSpecs | VARCHAR | SKU规格信息 | JSON格式存储 | +| price | DECIMAL | 价格 | | +| stock | INTEGER | 库存 | | +| image | VARCHAR | 图片 | | +| status | INTEGER | 状态 | 0:禁用, 1:启用 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### product_inventories表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 库存ID | 主键,自增 | +| skuId | BIGINT | SKU ID | 外键,关联product_skus表 | +| currentStock | INTEGER | 当前库存 | | +| safetyStock | INTEGER | 安全库存 | | +| lockStock | INTEGER | 锁定库存 | | +| lastUpdateTime | DATE | 最后更新时间 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +## 订单相关表 + +### orders表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 订单ID | 主键,自增 | +| orderNo | VARCHAR | 订单号 | | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| shopId | BIGINT | 店铺ID | 外键,关联shops表 | +| totalAmount | DECIMAL | 总金额 | | +| actualAmount | DECIMAL | 实际支付金额 | | +| shippingFee | DECIMAL | 运费 | | +| orderStatus | INTEGER | 订单状态 | 0:待付款, 1:待发货, 2:待收货, 3:已完成, 4:已取消, 5:已退款 | +| shippingAddress | VARCHAR | 收货地址 | | +| receiverName | VARCHAR | 收件人姓名 | | +| receiverPhone | VARCHAR | 收件人电话 | | +| paymentMethod | VARCHAR | 支付方式 | | +| paymentTime | DATE | 支付时间 | | +| shippingTime | DATE | 发货时间 | | +| deliveryTime | DATE | 送达时间 | | +| completeTime | DATE | 完成时间 | | +| remark | VARCHAR | 备注 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### order_items表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 订单项ID | 主键,自增 | +| orderId | BIGINT | 订单ID | 外键,关联orders表 | +| productId | BIGINT | 商品ID | 外键,关联products表 | +| skuId | BIGINT | SKU ID | 外键,关联product_skus表 | +| productName | VARCHAR | 商品名称 | | +| skuSpecs | VARCHAR | SKU规格 | | +| productImage | VARCHAR | 商品图片 | | +| price | DECIMAL | 价格 | | +| quantity | INTEGER | 数量 | | +| subtotal | DECIMAL | 小计 | | +| itemStatus | INTEGER | 商品状态 | 0:正常, 1:已退款, 2:退款中 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### order_status_history表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 历史ID | 主键,自增 | +| orderId | BIGINT | 订单ID | 外键,关联orders表 | +| previousStatus | INTEGER | 之前状态 | | +| currentStatus | INTEGER | 当前状态 | | +| changeReason | VARCHAR | 变更原因 | | +| operator | VARCHAR | 操作人 | | +| changeTime | DATE | 变更时间 | | +| createdAt | DATE | 创建时间 | | + +## 支付与退款相关表 + +### payments表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 支付ID | 主键,自增 | +| paymentNo | VARCHAR | 支付单号 | | +| orderId | BIGINT | 订单ID | 外键,关联orders表 | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| amount | DECIMAL | 支付金额 | | +| paymentMethod | VARCHAR | 支付方式 | | +| transactionId | VARCHAR | 第三方交易流水号 | | +| paymentStatus | INTEGER | 支付状态 | 0:待支付, 1:支付成功, 2:支付失败, 3:已退款 | +| paymentUrl | VARCHAR | 支付链接 | | +| expireTime | DATE | 过期时间 | | +| paymentTime | DATE | 支付时间 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +### refunds表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 退款ID | 主键,自增 | +| refundNo | VARCHAR | 退款单号 | | +| orderId | BIGINT | 订单ID | 外键,关联orders表 | +| orderItemId | BIGINT | 订单项ID | 外键,关联order_items表 | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| shopId | BIGINT | 店铺ID | 外键,关联shops表 | +| refundAmount | DECIMAL | 退款金额 | | +| refundReason | VARCHAR | 退款原因 | | +| refundType | VARCHAR | 退款类型 | | +| refundStatus | INTEGER | 退款状态 | 0:申请中, 1:退款成功, 2:退款失败, 3:已拒绝 | +| refundAccount | VARCHAR | 退款账户 | | +| transactionId | VARCHAR | 交易ID | | +| applyTime | DATE | 申请时间 | | +| processTime | DATE | 处理时间 | | +| processRemark | VARCHAR | 处理备注 | | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +## 评价相关表 + +### shop_ratings表 + +| 字段名 | 类型 | 描述 | 备注 | +| :--- | :--- | :--- | :--- | +| id | BIGINT | 评价ID | 主键,自增 | +| shopId | BIGINT | 店铺ID | 外键,关联shops表 | +| userId | BIGINT | 用户ID | 外键,关联users表 | +| orderId | BIGINT | 订单ID | 外键,关联orders表 | +| rating | INTEGER | 评分 | 1-5星 | +| content | VARCHAR | 评价内容 | | +| images | VARCHAR | 评价图片 | JSON格式存储 | +| status | INTEGER | 状态 | 0:待审核, 1:已审核, 2:已删除 | +| createdAt | DATE | 创建时间 | | +| updatedAt | DATE | 更新时间 | | + +## 表与表之间的关系 + +### 一对一关系 + +1. **users 和 user_details** + - 关系:一对一 + - 描述:每个用户只有一个详细信息记录 + - 外键:user_details.userId -> users.id + +### 一对多关系 + +1. **users 和 shops** + - 关系:一对多 + - 描述:一个用户可以创建多个店铺(店主) + - 外键:shops.userId -> users.id + +2. **shops 和 products** + - 关系:一对多 + - 描述:一个店铺可以有多个商品 + - 外键:products.shopId -> shops.id + +3. **users 和 orders** + - 关系:一对多 + - 描述:一个用户可以有多个订单 + - 外键:orders.userId -> users.id + +4. **shops 和 orders** + - 关系:一对多 + - 描述:一个店铺可以有多个订单 + - 外键:orders.shopId -> shops.id + +5. **orders 和 order_items** + - 关系:一对多 + - 描述:一个订单可以包含多个商品项 + - 外键:order_items.orderId -> orders.id + +6. **products 和 product_images** + - 关系:一对多 + - 描述:一个商品可以有多个图片 + - 外键:product_images.productId -> products.id + +7. **products 和 product_skus** + - 关系:一对多 + - 描述:一个商品可以有多个SKU + - 外键:product_skus.productId -> products.id + +8. **product_skus 和 product_inventories** + - 关系:一对一/一对多(实际为一对一) + - 描述:一个SKU对应一个库存记录 + - 外键:product_inventories.skuId -> product_skus.id + +9. **orders 和 order_status_history** + - 关系:一对多 + - 描述:一个订单可以有多个状态历史记录 + - 外键:order_status_history.orderId -> orders.id + +10. **orders 和 payments** + - 关系:一对多 + - 描述:一个订单可以有多个支付记录(如多次支付尝试) + - 外键:payments.orderId -> orders.id + +11. **orders 和 refunds** + - 关系:一对多 + - 描述:一个订单可以有多个退款记录 + - 外键:refunds.orderId -> orders.id + +12. **order_items 和 refunds** + - 关系:一对多 + - 描述:一个订单项可以有多个退款记录 + - 外键:refunds.orderItemId -> order_items.id + +13. **shops 和 shop_ratings** + - 关系:一对多 + - 描述:一个店铺可以有多个评价 + - 外键:shop_ratings.shopId -> shops.id + +14. **users 和 shop_ratings** + - 关系:一对多 + - 描述:一个用户可以对多个店铺进行评价 + - 外键:shop_ratings.userId -> users.id + +15. **orders 和 shop_ratings** + - 关系:一对一 + - 描述:一个订单对应一个店铺评价 + - 外键:shop_ratings.orderId -> orders.id + +16. **product_categories 和 products** + - 关系:一对多 + - 描述:一个商品分类可以包含多个商品 + - 外键:products.categoryId -> product_categories.id + +17. **shop_categories 和 shops** + - 关系:一对多 + - 描述:一个店铺分类可以包含多个店铺 + - 外键:shops.categoryId -> shop_categories.id + +18. **product_categories 和 product_attributes** + - 关系:一对多 + - 描述:一个商品分类可以有多个属性 + - 外键:product_attributes.categoryId -> product_categories.id + +19. **products 和 product_attribute_values** + - 关系:一对多 + - 描述:一个商品可以有多个属性值 + - 外键:product_attribute_values.productId -> products.id + +20. **product_attributes 和 product_attribute_values** + - 关系:一对多 + - 描述:一个属性可以有多个值 + - 外键:product_attribute_values.attributeId -> product_attributes.id + +### 多对多关系 + +1. **users 和 roles** + - 关系:多对多 + - 描述:一个用户可以有多个角色,一个角色可以分配给多个用户 + - 关联表:user_roles (userId, roleId) + +2. **roles 和 permissions** + - 关系:多对多 + - 描述:一个角色可以有多个权限,一个权限可以分配给多个角色 + - 关联表:role_permissions (roleId, permissionId) + +### 自关联关系 + +1. **shop_categories 和 shop_categories** + - 关系:自关联(一对多) + - 描述:店铺分类的父子关系 + - 外键:shop_categories.parentId -> shop_categories.id + +2. **product_categories 和 product_categories** + - 关系:自关联(一对多) + - 描述:商品分类的父子关系 + - 外键:product_categories.parentId -> product_categories.id \ No newline at end of file diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..bd8896b --- /dev/null +++ b/mvnw @@ -0,0 +1,295 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.4 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..92450f9 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,189 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..60c374b --- /dev/null +++ b/pom.xml @@ -0,0 +1,187 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.7 + + + com.qf + backend + 0.0.1-SNAPSHOT + backend + backend + + + + + + + + + + + + + + + 21 + 0.12.5 + 3.5.6 + 2.0.52 + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.5 + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mybatis.spring.boot + mybatis-spring-boot-starter-test + 3.0.5 + test + + + org.springframework.security + spring-security-test + test + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + runtime + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + runtime + + + + + com.mysql + mysql-connector-j + runtime + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + + com.baomidou + mybatis-plus-generator + ${mybatis-plus.version} + test + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.apache.commons + commons-pool2 + + + + + org.projectlombok + lombok + true + + + + + com.alibaba.fastjson2 + fastjson2 + ${fastjson2.version} + + + + + org.apache.commons + commons-lang3 + + + + + commons-io + commons-io + 2.16.1 + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + com.github.penggle + kaptcha + 2.3.2 + + + + + joda-time + joda-time + 2.12.7 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/com/qf/backend/BackendApplication.java b/src/main/java/com/qf/backend/BackendApplication.java new file mode 100644 index 0000000..3063f53 --- /dev/null +++ b/src/main/java/com/qf/backend/BackendApplication.java @@ -0,0 +1,15 @@ +package com.qf.backend; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@MapperScan("com.qf.backend.mapper") +public class BackendApplication { + + public static void main(String[] args) { + SpringApplication.run(BackendApplication.class, args); + } + +} diff --git a/src/main/java/com/qf/backend/common/Result.java b/src/main/java/com/qf/backend/common/Result.java new file mode 100644 index 0000000..9eaad14 --- /dev/null +++ b/src/main/java/com/qf/backend/common/Result.java @@ -0,0 +1,98 @@ +package com.qf.backend.common; + +import lombok.Data; + +/** + * 统一响应格式 + * 根据项目文档6.2节统一响应格式定义 + */ +@Data +public class Result { + + /** + * 状态码 + */ + private int code; + + /** + * 状态信息 + */ + private String message; + + /** + * 响应数据 + */ + private T data; + + /** + * 构造私有方法 + */ + private Result() { + } + + + /** + * 成功响应(无数据) + */ + public static Result success() { + Result result = new Result<>(); + result.setCode(200); + result.setMessage("success"); + return result; + } + + /** + * 成功响应(有数据) + */ + public static Result success(T data) { + Result result = new Result<>(); + result.setCode(200); + result.setMessage("success"); + result.setData(data); + return result; + } + + /** + * 失败响应 + */ + public static Result fail(int code, String message) { + Result result = new Result<>(); + result.setCode(code); + result.setMessage(message); + return result; + } + + /** + * 失败响应(带数据) + */ + public static Result fail(int code, String message, T data) { + Result result = new Result<>(); + result.setCode(code); + result.setMessage(message); + result.setData(data); + return result; + } + // getters setters + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public T getData() { + return data; + } + public void setCode(int code) { + this.code = code; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setData(T data) { + this.data = data; + } +} \ No newline at end of file diff --git a/src/main/java/com/qf/backend/common/ResultUtils.java b/src/main/java/com/qf/backend/common/ResultUtils.java new file mode 100644 index 0000000..ba02e79 --- /dev/null +++ b/src/main/java/com/qf/backend/common/ResultUtils.java @@ -0,0 +1,87 @@ +package com.qf.backend.common; + +import com.qf.backend.exception.ErrorCode; + +/** + * 响应结果工具类 + * 提供各种响应结果的快速创建方法 + */ +public class ResultUtils { + + /** + * 成功响应(无数据) + */ + public static Result success() { + return Result.success(); + } + + /** + * 成功响应(有数据) + */ + public static Result success(T data) { + return Result.success(data); + } + + /** + * 失败响应(使用错误码) + */ + public static Result fail(ErrorCode errorCode) { + return Result.fail(errorCode.getCode(), errorCode.getMessage()); + } + + /** + * 失败响应(使用错误码和自定义消息) + */ + public static Result fail(ErrorCode errorCode, String message) { + return Result.fail(errorCode.getCode(), message); + } + + /** + * 失败响应(使用错误码和数据) + */ + public static Result fail(ErrorCode errorCode, T data) { + return Result.fail(errorCode.getCode(), errorCode.getMessage(), data); + } + + /** + * 失败响应(自定义状态码和消息) + */ + public static Result fail(int code, String message) { + return Result.fail(code, message); + } + + /** + * 参数错误响应 + */ + public static Result paramError(String message) { + return Result.fail(ErrorCode.PARAM_ERROR.getCode(), message); + } + + /** + * 未授权响应 + */ + public static Result unauthorized() { + return Result.fail(ErrorCode.UNAUTHORIZED.getCode(), ErrorCode.UNAUTHORIZED.getMessage()); + } + + /** + * 禁止访问响应 + */ + public static Result forbidden() { + return Result.fail(ErrorCode.FORBIDDEN.getCode(), ErrorCode.FORBIDDEN.getMessage()); + } + + /** + * 资源不存在响应 + */ + public static Result notFound(String message) { + return Result.fail(ErrorCode.NOT_FOUND.getCode(), message); + } + + /** + * 服务器错误响应 + */ + public static Result serverError() { + return Result.fail(ErrorCode.SYSTEM_ERROR.getCode(), ErrorCode.SYSTEM_ERROR.getMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/com/qf/backend/entity/OrderItems.java b/src/main/java/com/qf/backend/entity/OrderItems.java new file mode 100644 index 0000000..ba27d9b --- /dev/null +++ b/src/main/java/com/qf/backend/entity/OrderItems.java @@ -0,0 +1,34 @@ +package com.qf.backend.entity; + +import java.math.BigDecimal; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * 订单商品项表 + */ +@Data +@TableName("order_items") +public class OrderItems { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long orderId; + private Long productId; + private Long skuId; + private String productName; + private String skuSpecs; + private String productImage; + private BigDecimal price; + private Integer quantity; + private BigDecimal subtotal; + private Integer itemStatus; // 0: 正常, 1: 已退款, 2: 退款中 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/OrderStatusHistory.java b/src/main/java/com/qf/backend/entity/OrderStatusHistory.java new file mode 100644 index 0000000..a04c7c7 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/OrderStatusHistory.java @@ -0,0 +1,26 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 订单状态历史表 + */ +@Data +@TableName("order_status_history") +public class OrderStatusHistory { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long orderId; + private Integer previousStatus; + private Integer currentStatus; + private String changeReason; + private String operator; + private Date changeTime; + private Date createdAt; +} diff --git a/src/main/java/com/qf/backend/entity/Orders.java b/src/main/java/com/qf/backend/entity/Orders.java new file mode 100644 index 0000000..bffdc3e --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Orders.java @@ -0,0 +1,40 @@ +package com.qf.backend.entity; + +import java.math.BigDecimal; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * 订单主表 + */ +@Data +@TableName("orders") +public class Orders { + + @TableId(type = IdType.AUTO) + private Long id; + + private String orderNo; + private Long userId; + private Long shopId; + private BigDecimal totalAmount; + private BigDecimal actualAmount; + private BigDecimal shippingFee; + private Integer orderStatus; // 0: 待付款, 1: 待发货, 2: 待收货, 3: 已完成, 4: 已取消, 5: 已退款 + private String shippingAddress; + private String receiverName; + private String receiverPhone; + private String paymentMethod; // 支付方式 + private Date paymentTime; + private Date shippingTime; + private Date deliveryTime; + private Date completeTime; + private String remark; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/Payments.java b/src/main/java/com/qf/backend/entity/Payments.java new file mode 100644 index 0000000..314f90a --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Payments.java @@ -0,0 +1,32 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 支付信息表 + */ +@Data +@TableName("payments") +public class Payments { + + @TableId(type = IdType.AUTO) + private Long id; + + private String paymentNo; + private Long orderId; + private Long userId; + private BigDecimal amount; + private String paymentMethod; // 支付方式 + private String transactionId; // 第三方交易流水号 + private Integer paymentStatus; // 0: 待支付, 1: 支付成功, 2: 支付失败, 3: 已退款 + private String paymentUrl; // 支付链接 + private Date expireTime; + private Date paymentTime; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/Permissions.java b/src/main/java/com/qf/backend/entity/Permissions.java new file mode 100644 index 0000000..72fd1fe --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Permissions.java @@ -0,0 +1,26 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 权限信息表 + */ +@Data +@TableName("permissions") +public class Permissions { + + @TableId(type = IdType.AUTO) + private Long id; + + private String permissionName; + private String permissionCode; + private String description; + private String module; + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductAttributeValues.java b/src/main/java/com/qf/backend/entity/ProductAttributeValues.java new file mode 100644 index 0000000..9e7abb3 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductAttributeValues.java @@ -0,0 +1,25 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 商品属性值表 + */ +@Data +@TableName("product_attribute_values") +public class ProductAttributeValues { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long productId; + private Long attributeId; + private String attributeValue; + private Integer sort; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductAttributes.java b/src/main/java/com/qf/backend/entity/ProductAttributes.java new file mode 100644 index 0000000..c34c73f --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductAttributes.java @@ -0,0 +1,25 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 商品属性表 + */ +@Data +@TableName("product_attributes") +public class ProductAttributes { + + @TableId(type = IdType.AUTO) + private Long id; + + private String attributeName; + private Long categoryId; + private Integer attributeType; // 0: 规格属性, 1: 销售属性 + private Integer sort; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductCategories.java b/src/main/java/com/qf/backend/entity/ProductCategories.java new file mode 100644 index 0000000..2e977d7 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductCategories.java @@ -0,0 +1,28 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 商品分类表 + */ +@Data +@TableName("product_categories") +public class ProductCategories { + + @TableId(type = IdType.AUTO) + private Long id; + + private String categoryName; + private Long parentId; // 父分类ID,顶级分类为0 + private Integer level; // 分类级别:1、2、3 + private String icon; + private String banner; + private Integer sort; + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductImages.java b/src/main/java/com/qf/backend/entity/ProductImages.java new file mode 100644 index 0000000..d2d6cab --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductImages.java @@ -0,0 +1,24 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 商品图片表 + */ +@Data +@TableName("product_images") +public class ProductImages { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long productId; + private String imageUrl; + private Integer sort; + private Integer isMain; // 0: 非主图, 1: 主图 + private Date createdAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductInventories.java b/src/main/java/com/qf/backend/entity/ProductInventories.java new file mode 100644 index 0000000..3a4deaa --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductInventories.java @@ -0,0 +1,28 @@ +package com.qf.backend.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * 库存信息表 + */ +@Data +@TableName("product_inventories") +public class ProductInventories { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long skuId; + private Integer currentStock; + private Integer safetyStock; + private Integer lockStock; // 锁定库存 + private Date lastUpdateTime; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ProductSkus.java b/src/main/java/com/qf/backend/entity/ProductSkus.java new file mode 100644 index 0000000..6c14caf --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ProductSkus.java @@ -0,0 +1,31 @@ +package com.qf.backend.entity; + +import java.math.BigDecimal; +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * 商品SKU表 + */ +@Data +@TableName("product_skus") +public class ProductSkus { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long productId; + private String skuCode; + private String skuSpecs; // SKU规格信息,JSON格式存储 + private BigDecimal price; + private Integer stock; + private String image; + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/Products.java b/src/main/java/com/qf/backend/entity/Products.java new file mode 100644 index 0000000..2409c96 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Products.java @@ -0,0 +1,32 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 商品基本信息表 + */ +@Data +@TableName("products") +public class Products { + + @TableId(type = IdType.AUTO) + private Long id; + + private String productName; + private Long shopId; + private Long categoryId; + private String description; + private BigDecimal originalPrice; + private BigDecimal currentPrice; + private Integer salesVolume; + private Integer status; // 0: 下架, 1: 上架 + private String mainImage; + private Integer isDeleted; // 0: 未删除, 1: 已删除 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/Refunds.java b/src/main/java/com/qf/backend/entity/Refunds.java new file mode 100644 index 0000000..644943e --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Refunds.java @@ -0,0 +1,36 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 退款信息表 + */ +@Data +@TableName("refunds") +public class Refunds { + + @TableId(type = IdType.AUTO) + private Long id; + + private String refundNo; + private Long orderId; + private Long orderItemId; + private Long userId; + private Long shopId; + private BigDecimal refundAmount; + private String refundReason; + private String refundType; // 退款类型 + private Integer refundStatus; // 0: 申请中, 1: 退款成功, 2: 退款失败, 3: 已拒绝 + private String refundAccount; + private String transactionId; + private Date applyTime; + private Date processTime; + private String processRemark; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/RolePermissions.java b/src/main/java/com/qf/backend/entity/RolePermissions.java new file mode 100644 index 0000000..7d9287c --- /dev/null +++ b/src/main/java/com/qf/backend/entity/RolePermissions.java @@ -0,0 +1,22 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 角色-权限关联表 + */ +@Data +@TableName("role_permissions") +public class RolePermissions { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long roleId; + private Long permissionId; + private Date createdAt; +} diff --git a/src/main/java/com/qf/backend/entity/Roles.java b/src/main/java/com/qf/backend/entity/Roles.java new file mode 100644 index 0000000..1f5b951 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Roles.java @@ -0,0 +1,25 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 角色信息表 + */ +@Data +@TableName("roles") +public class Roles { + + @TableId(type = IdType.AUTO) + private Long id; + + private String roleName; + private String description; + private Integer roleType; // 0: 默认用户, 1: 店主, 2: 管理员 + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ShopCategories.java b/src/main/java/com/qf/backend/entity/ShopCategories.java new file mode 100644 index 0000000..ce362d4 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ShopCategories.java @@ -0,0 +1,27 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 店铺分类表 + */ +@Data +@TableName("shop_categories") +public class ShopCategories { + + @TableId(type = IdType.AUTO) + private Long id; + + private String categoryName; + private Long parentId; // 父分类ID,顶级分类为0 + private Integer level; // 分类级别 + private String icon; + private Integer sort; + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/ShopRatings.java b/src/main/java/com/qf/backend/entity/ShopRatings.java new file mode 100644 index 0000000..19fb38f --- /dev/null +++ b/src/main/java/com/qf/backend/entity/ShopRatings.java @@ -0,0 +1,28 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 店铺评分表 + */ +@Data +@TableName("shop_ratings") +public class ShopRatings { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long shopId; + private Long userId; + private Long orderId; + private Integer rating; // 评分:1-5星 + private String content; + private String images; // 评价图片,JSON格式存储 + private Integer status; // 0: 待审核, 1: 已审核, 2: 已删除 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/Shops.java b/src/main/java/com/qf/backend/entity/Shops.java new file mode 100644 index 0000000..f02ebbd --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Shops.java @@ -0,0 +1,37 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 店铺信息表 + */ +@Data +@TableName("shops") +public class Shops { + + @TableId(type = IdType.AUTO) + private Long id; + + private String shopName; + private Long userId; // 店主用户ID + private Long categoryId; + private String shopLogo; + private String coverImage; + private String description; + private String address; + private String contactPhone; + private String contactPerson; + private BigDecimal rating; // 店铺评分 + private Integer salesVolume; + private Integer status; // 0: 未审核, 1: 已审核, 2: 已关闭, 3: 审核失败 + private String businessLicense; + private Date businessStartTime; + private Date businessEndTime; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/UserDetails.java b/src/main/java/com/qf/backend/entity/UserDetails.java new file mode 100644 index 0000000..e14c044 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/UserDetails.java @@ -0,0 +1,30 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 用户详细信息表 + */ +@Data +@TableName("user_details") +public class UserDetails { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long userId; + private String realName; + private String idCard; + private String gender; //男、女、保密 + private Date birthday; + private String address; + private String province; + private String city; + private String district; + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/entity/UserRoles.java b/src/main/java/com/qf/backend/entity/UserRoles.java new file mode 100644 index 0000000..5138d65 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/UserRoles.java @@ -0,0 +1,22 @@ +package com.qf.backend.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import java.util.Date; + +/** + * 用户-角色关联表 + */ +@Data +@TableName("user_roles") +public class UserRoles { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long userId; + private Long roleId; + private Date createdAt; +} diff --git a/src/main/java/com/qf/backend/entity/Users.java b/src/main/java/com/qf/backend/entity/Users.java new file mode 100644 index 0000000..61c26f5 --- /dev/null +++ b/src/main/java/com/qf/backend/entity/Users.java @@ -0,0 +1,29 @@ +package com.qf.backend.entity; + +import java.util.Date; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; + +/** + * 用户基本信息表 + */ +@Data +@TableName("users") +public class Users { + + @TableId(type = IdType.AUTO) + private Long id; + private String username; + private String password; + private String email; + private String phone; + private String nickname; + private String avatar; + private Integer status; // 0: 禁用, 1: 启用 + private Date createdAt; + private Date updatedAt; +} diff --git a/src/main/java/com/qf/backend/exception/BusinessException.java b/src/main/java/com/qf/backend/exception/BusinessException.java new file mode 100644 index 0000000..b0e5897 --- /dev/null +++ b/src/main/java/com/qf/backend/exception/BusinessException.java @@ -0,0 +1,81 @@ +package com.qf.backend.exception; + +import lombok.Getter; + +/** + * 业务异常类 用于封装业务逻辑中产生的异常 + */ +@Getter +public class BusinessException extends RuntimeException { + + private final int code; + private final String message; + private final Object data; + + /** + * 使用错误码构造业务异常 + * + * @param errorCode 错误码枚举 + */ + public BusinessException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.code = errorCode.getCode(); + this.message = errorCode.getMessage(); + this.data = null; + } + + /** + * 使用错误码和自定义消息构造业务异常 + * + * @param errorCode 错误码枚举 + * @param message 自定义错误消息 + */ + public BusinessException(ErrorCode errorCode, String message) { + super(message); + this.code = errorCode.getCode(); + this.message = message; + this.data = null; + } + + /** + * 使用错误码和附加数据构造业务异常 + * + * @param errorCode 错误码枚举 + * @param data 附加数据 + */ + public BusinessException(ErrorCode errorCode, Object data) { + super(errorCode.getMessage()); + this.code = errorCode.getCode(); + this.message = errorCode.getMessage(); + this.data = data; + } + + /** + * 使用错误码、自定义消息和附加数据构造业务异常 + * + * @param errorCode 错误码枚举 + * @param message 自定义错误消息 + * @param data 附加数据 + */ + public BusinessException(ErrorCode errorCode, String message, Object data) { + super(message); + this.code = errorCode.getCode(); + this.message = message; + this.data = data; + } + + /** + * 使用错误码、自定义消息和原始异常构造业务异常 + * + * @param errorCode 错误码枚举 + * @param message 自定义错误消息 + * @param cause 原始异常 + */ + public BusinessException(ErrorCode errorCode, String message, Throwable cause) { + super(message, cause); + this.code = errorCode.getCode(); + this.message = message; + this.data = null; + } + +} diff --git a/src/main/java/com/qf/backend/exception/ErrorCode.java b/src/main/java/com/qf/backend/exception/ErrorCode.java new file mode 100644 index 0000000..a810e77 --- /dev/null +++ b/src/main/java/com/qf/backend/exception/ErrorCode.java @@ -0,0 +1,55 @@ +package com.qf.backend.exception; + +import lombok.Getter; + +/** + * 错误码定义 + * 根据项目文档6.3节状态码定义进行扩展 + */ +@Getter +public enum ErrorCode { + // 成功状态码 + SUCCESS(200, "success"), + + // 参数错误 + PARAM_ERROR(400, "请求参数错误"), + MISSING_PARAM(4001, "缺少必要参数"), + INVALID_PARAM(4002, "无效的参数值"), + + // 认证授权错误 + UNAUTHORIZED(401, "未授权访问"), + INVALID_TOKEN(4011, "无效的令牌"), + TOKEN_EXPIRED(4012, "令牌已过期"), + + // 权限错误 + FORBIDDEN(403, "禁止访问"), + PERMISSION_DENIED(4031, "权限不足"), + + // 资源错误 + NOT_FOUND(404, "资源不存在"), + USER_NOT_FOUND(4041, "用户不存在"), + PRODUCT_NOT_FOUND(4042, "商品不存在"), + ORDER_NOT_FOUND(4043, "订单不存在"), + SHOP_NOT_FOUND(4044, "店铺不存在"), + + // 业务错误 + BUSINESS_ERROR(409, "业务逻辑错误"), + USER_EXISTED(4091, "用户已存在"), + PRODUCT_OFF_SHELF(4092, "商品已下架"), + INSUFFICIENT_STOCK(4093, "库存不足"), + ORDER_CANCELLED(4094, "订单已取消"), + + // 服务器错误 + SYSTEM_ERROR(500, "服务器内部错误"), + DATABASE_ERROR(5001, "数据库操作错误"), + NETWORK_ERROR(5002, "网络请求错误"), + UNKNOWN_ERROR(5003, "未知错误"); + + private final int code; + private final String message; + + ErrorCode(int code, String message) { + this.code = code; + this.message = message; + } +} \ No newline at end of file diff --git a/src/main/java/com/qf/backend/exception/ExceptionUsageExample.java b/src/main/java/com/qf/backend/exception/ExceptionUsageExample.java new file mode 100644 index 0000000..790dacc --- /dev/null +++ b/src/main/java/com/qf/backend/exception/ExceptionUsageExample.java @@ -0,0 +1,111 @@ +package com.qf.backend.exception; + +import com.qf.backend.common.Result; +import com.qf.backend.common.ResultUtils; + +/** + * 异常处理使用示例 + * 演示如何在业务代码中使用异常处理相关类 + */ +public class ExceptionUsageExample { + + /** + * 示例1:抛出业务异常 + */ + public void throwBusinessExceptionExample(Long userId) { + // 业务逻辑判断 + if (userId == null || userId <= 0) { + // 使用预定义错误码抛出业务异常 + throw new BusinessException(ErrorCode.PARAM_ERROR, "用户ID无效"); + } + + // 模拟用户不存在的场景 + boolean userExists = false; // 假设从数据库查询 + if (!userExists) { + throw new BusinessException(ErrorCode.USER_NOT_FOUND); + } + + // 抛出带附加数据的异常 + Object additionalData = new Object(); // 可以是任何附加信息 + throw new BusinessException(ErrorCode.BUSINESS_ERROR, "业务逻辑错误", additionalData); + } + + /** + * 示例2:返回统一响应格式 + */ + public Result returnResultExample(boolean success) { + if (success) { + // 返回成功响应 + return ResultUtils.success("操作成功"); + } else { + // 返回失败响应 + return ResultUtils.fail(ErrorCode.BUSINESS_ERROR); + } + } + + /** + * 示例3:使用不同类型的错误响应 + */ + public Result useDifferentErrorResponses() { + // 参数错误 + Result paramError = ResultUtils.paramError("参数校验失败"); + + // 未授权错误 + Result unauthorizedError = ResultUtils.unauthorized(); + + // 禁止访问错误 + Result forbiddenError = ResultUtils.forbidden(); + + // 资源不存在错误 + Result notFoundError = ResultUtils.notFound("请求的资源不存在"); + + // 服务器错误 + Result serverError = ResultUtils.serverError(); + + return paramError; // 示例返回 + } + + /** + * 示例4:在Service层使用异常处理 + */ + public void serviceLayerExample(Long productId, int quantity) { + // 校验参数 + if (productId == null || productId <= 0) { + throw new BusinessException(ErrorCode.PARAM_ERROR, "商品ID无效"); + } + + if (quantity <= 0) { + throw new BusinessException(ErrorCode.PARAM_ERROR, "购买数量必须大于0"); + } + + // 模拟业务逻辑检查 + boolean productExists = true; // 假设从数据库查询 + if (!productExists) { + throw new BusinessException(ErrorCode.PRODUCT_NOT_FOUND); + } + + // 模拟库存检查 + boolean hasStock = false; // 假设从数据库查询 + if (!hasStock) { + throw new BusinessException(ErrorCode.INSUFFICIENT_STOCK); + } + + // 正常业务逻辑处理... + } + + /** + * 示例5:在Controller层使用统一响应 + */ + public Result controllerLayerExample(Long id) { + try { + // 调用业务逻辑 + Object result = new Object(); // 假设这是业务处理结果 + return ResultUtils.success(result); + } catch (BusinessException e) { + // 业务异常已经被GlobalExceptionHandler捕获,这里可以做额外处理 + // 例如记录日志等 + throw e; // 重新抛出,让全局异常处理器处理 + } + // 系统异常也会被GlobalExceptionHandler自动捕获 + } +} \ No newline at end of file diff --git a/src/main/java/com/qf/backend/exception/GlobalExceptionHandler.java b/src/main/java/com/qf/backend/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..0ebda93 --- /dev/null +++ b/src/main/java/com/qf/backend/exception/GlobalExceptionHandler.java @@ -0,0 +1,212 @@ +package com.qf.backend.exception; + +import java.sql.SQLException; +import java.util.Objects; +import java.util.StringJoiner; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.NoHandlerFoundException; + +import com.qf.backend.common.Result; +import com.qf.backend.common.ResultUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 全局异常处理器 + * 处理系统中所有的异常,提供统一的错误响应格式 + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理业务异常 + */ + @ExceptionHandler(BusinessException.class) + public Result handleBusinessException(BusinessException e, HttpServletRequest request) { + log.warn("BusinessException: {} - Request: {}", e.getMessage(), request.getRequestURI()); + return ResultUtils.fail(e.getCode(), e.getMessage()); + } + + /** + * 处理参数验证异常(@Valid) + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) { + BindingResult bindingResult = e.getBindingResult(); + StringJoiner joiner = new StringJoiner(", "); + for (FieldError fieldError : bindingResult.getFieldErrors()) { + joiner.add(fieldError.getField() + ": " + fieldError.getDefaultMessage()); + } + String errorMsg = joiner.toString(); + log.warn("MethodArgumentNotValidException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.paramError(errorMsg); + } + + /** + * 处理参数绑定异常(@RequestParam) + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleBindException(BindException e, HttpServletRequest request) { + BindingResult bindingResult = e.getBindingResult(); + StringJoiner joiner = new StringJoiner(", "); + for (FieldError fieldError : bindingResult.getFieldErrors()) { + joiner.add(fieldError.getField() + ": " + fieldError.getDefaultMessage()); + } + String errorMsg = joiner.toString(); + log.warn("BindException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.paramError(errorMsg); + } + + /** + * 处理缺少请求参数异常 + */ + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest request) { + String errorMsg = "缺少必要参数: " + e.getParameterName(); + log.warn("MissingServletRequestParameterException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.paramError(errorMsg); + } + + /** + * 处理参数类型不匹配异常 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { + String errorMsg = "参数类型错误: " + e.getName() + " 应为 " + Objects.requireNonNull(e.getRequiredType()).getSimpleName(); + log.warn("MethodArgumentTypeMismatchException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.paramError(errorMsg); + } + + /** + * 处理HTTP消息不可读异常(如JSON格式错误) + */ + @ExceptionHandler(HttpMessageNotReadableException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleHttpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) { + String errorMsg = "请求体格式错误: " + e.getMostSpecificCause().getMessage(); + log.warn("HttpMessageNotReadableException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.paramError(errorMsg); + } + + /** + * 处理不支持的HTTP方法异常 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { + String errorMsg = "不支持的HTTP方法: " + e.getMethod(); + log.warn("HttpRequestMethodNotSupportedException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.fail(HttpStatus.METHOD_NOT_ALLOWED.value(), errorMsg); + } + + /** + * 处理不支持的媒体类型异常 + */ + @ExceptionHandler(HttpMediaTypeNotSupportedException.class) + @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) + public Result handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e, HttpServletRequest request) { + String errorMsg = "不支持的媒体类型: " + e.getContentType(); + log.warn("HttpMediaTypeNotSupportedException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.fail(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), errorMsg); + } + + /** + * 处理404异常 + */ + @ExceptionHandler(NoHandlerFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Result handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) { + String errorMsg = "请求路径不存在: " + request.getRequestURI(); + log.warn("NoHandlerFoundException: {} - Request: {}", errorMsg, request.getRequestURI()); + return ResultUtils.notFound(errorMsg); + } + + /** + * 处理数据库异常 + */ + @ExceptionHandler(SQLException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleSQLException(SQLException e, HttpServletRequest request) { + log.error("SQLException: {} - Request: {}", e.getMessage(), request.getRequestURI(), e); + return ResultUtils.fail(ErrorCode.DATABASE_ERROR); + } + + /** + * 处理认证异常 + */ + @ExceptionHandler(AuthenticationException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleAuthenticationException(AuthenticationException e, HttpServletRequest request) { + String errorMsg = "认证失败: " + e.getMessage(); + log.warn("AuthenticationException: {} - Request: {}", errorMsg, request.getRequestURI()); + + if (e instanceof BadCredentialsException) { + return ResultUtils.fail(ErrorCode.UNAUTHORIZED, "用户名或密码错误"); + } else if (e instanceof InsufficientAuthenticationException) { + return ResultUtils.fail(ErrorCode.UNAUTHORIZED, "缺少认证信息"); + } + + return ResultUtils.unauthorized(); + } + + /** + * 处理权限不足异常 + */ + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Result handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { + log.warn("AccessDeniedException: {} - Request: {}", e.getMessage(), request.getRequestURI()); + return ResultUtils.fail(ErrorCode.PERMISSION_DENIED); + } + + /** + * 处理其他所有未捕获的异常 + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleException(Exception e, HttpServletRequest request) { + log.error("Unhandled Exception: {} - Request: {}", e.getMessage(), request.getRequestURI(), e); + return ResultUtils.serverError(); + } + + /** + * 处理运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) { + log.error("RuntimeException: {} - Request: {}", e.getMessage(), request.getRequestURI(), e); + + // 可以根据具体的运行时异常类型进行特殊处理 + if (e instanceof NullPointerException) { + log.warn("NullPointerException occurred: {}", e.getMessage()); + return ResultUtils.fail(ErrorCode.SYSTEM_ERROR, "系统内部错误:空指针异常"); + } + + return ResultUtils.serverError(); + } +} diff --git a/src/main/java/com/qf/backend/mapper/OrderItemsMapper.java b/src/main/java/com/qf/backend/mapper/OrderItemsMapper.java new file mode 100644 index 0000000..927cdad --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/OrderItemsMapper.java @@ -0,0 +1,30 @@ +package com.qf.backend.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Select; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.OrderItems; + +/** + * 订单商品项表 Mapper 接口 + */ +public interface OrderItemsMapper extends BaseMapper { + QueryWrapper qw = new QueryWrapper<>(); + /** + * 根据订单ID查询订单项 + * @param orderId 订单ID + * @return 订单项列表 + */ + @Select("select * from order_items where order_id = #{orderId}") + List selectByOrderId(Long orderId); + /** + * 根据商品ID查询订单项 + * @param productId 商品ID + * @return 订单项列表 + */ + @Select("select * from order_items where product_id = #{productId}") + List selectByProductId(Long productId); +} diff --git a/src/main/java/com/qf/backend/mapper/OrderStatusHistoryMapper.java b/src/main/java/com/qf/backend/mapper/OrderStatusHistoryMapper.java new file mode 100644 index 0000000..1e77483 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/OrderStatusHistoryMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.OrderStatusHistory; + +/** + * 订单状态历史表 Mapper 接口 + */ +public interface OrderStatusHistoryMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/OrdersMapper.java b/src/main/java/com/qf/backend/mapper/OrdersMapper.java new file mode 100644 index 0000000..93e955c --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/OrdersMapper.java @@ -0,0 +1,16 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Orders; + +/** + * 订单主表 Mapper 接口 + */ +public interface OrdersMapper extends BaseMapper { + /** + * 根据订单号查询订单 + * @param orderNumber 订单号 + * @return 订单信息 + */ + Orders selectByOrderNumber(String orderNumber); +} diff --git a/src/main/java/com/qf/backend/mapper/PaymentsMapper.java b/src/main/java/com/qf/backend/mapper/PaymentsMapper.java new file mode 100644 index 0000000..cbcd03f --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/PaymentsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Payments; + +/** + * 支付信息表 Mapper 接口 + */ +public interface PaymentsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/PermissionsMapper.java b/src/main/java/com/qf/backend/mapper/PermissionsMapper.java new file mode 100644 index 0000000..9e3f793 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/PermissionsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Permissions; + +/** + * 权限信息表 Mapper 接口 + */ +public interface PermissionsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductAttributeValuesMapper.java b/src/main/java/com/qf/backend/mapper/ProductAttributeValuesMapper.java new file mode 100644 index 0000000..a4afeaf --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductAttributeValuesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductAttributeValues; + +/** + * 商品属性值表 Mapper 接口 + */ +public interface ProductAttributeValuesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductAttributesMapper.java b/src/main/java/com/qf/backend/mapper/ProductAttributesMapper.java new file mode 100644 index 0000000..0b432e5 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductAttributesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductAttributes; + +/** + * 商品属性表 Mapper 接口 + */ +public interface ProductAttributesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductCategoriesMapper.java b/src/main/java/com/qf/backend/mapper/ProductCategoriesMapper.java new file mode 100644 index 0000000..6b14b3c --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductCategoriesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductCategories; + +/** + * 商品分类表 Mapper 接口 + */ +public interface ProductCategoriesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductImagesMapper.java b/src/main/java/com/qf/backend/mapper/ProductImagesMapper.java new file mode 100644 index 0000000..03440d8 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductImagesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductImages; + +/** + * 商品图片表 Mapper 接口 + */ +public interface ProductImagesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductInventoriesMapper.java b/src/main/java/com/qf/backend/mapper/ProductInventoriesMapper.java new file mode 100644 index 0000000..47c929c --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductInventoriesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductInventories; + +/** + * 库存信息表 Mapper 接口 + */ +public interface ProductInventoriesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductSkusMapper.java b/src/main/java/com/qf/backend/mapper/ProductSkusMapper.java new file mode 100644 index 0000000..e43e0f3 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductSkusMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ProductSkus; + +/** + * 商品SKU表 Mapper 接口 + */ +public interface ProductSkusMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ProductsMapper.java b/src/main/java/com/qf/backend/mapper/ProductsMapper.java new file mode 100644 index 0000000..bff509f --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ProductsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Products; + +/** + * 商品基本信息表 Mapper 接口 + */ +public interface ProductsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/RefundsMapper.java b/src/main/java/com/qf/backend/mapper/RefundsMapper.java new file mode 100644 index 0000000..7cad79e --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/RefundsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Refunds; + +/** + * 退款信息表 Mapper 接口 + */ +public interface RefundsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/RolePermissionsMapper.java b/src/main/java/com/qf/backend/mapper/RolePermissionsMapper.java new file mode 100644 index 0000000..b050ae6 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/RolePermissionsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.RolePermissions; + +/** + * 角色-权限关联表 Mapper 接口 + */ +public interface RolePermissionsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/RolesMapper.java b/src/main/java/com/qf/backend/mapper/RolesMapper.java new file mode 100644 index 0000000..b5577d9 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/RolesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Roles; + +/** + * 角色信息表 Mapper 接口 + */ +public interface RolesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ShopCategoriesMapper.java b/src/main/java/com/qf/backend/mapper/ShopCategoriesMapper.java new file mode 100644 index 0000000..7ea5f86 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ShopCategoriesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ShopCategories; + +/** + * 店铺分类表 Mapper 接口 + */ +public interface ShopCategoriesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ShopRatingsMapper.java b/src/main/java/com/qf/backend/mapper/ShopRatingsMapper.java new file mode 100644 index 0000000..4741058 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ShopRatingsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.ShopRatings; + +/** + * 店铺评分表 Mapper 接口 + */ +public interface ShopRatingsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/ShopsMapper.java b/src/main/java/com/qf/backend/mapper/ShopsMapper.java new file mode 100644 index 0000000..211124f --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/ShopsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Shops; + +/** + * 店铺信息表 Mapper 接口 + */ +public interface ShopsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/UserDetailsMapper.java b/src/main/java/com/qf/backend/mapper/UserDetailsMapper.java new file mode 100644 index 0000000..bf298dc --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/UserDetailsMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.UserDetails; + +/** + * 用户详细信息表 Mapper 接口 + */ +public interface UserDetailsMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/UserRolesMapper.java b/src/main/java/com/qf/backend/mapper/UserRolesMapper.java new file mode 100644 index 0000000..67ca38b --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/UserRolesMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.UserRoles; + +/** + * 用户-角色关联表 Mapper 接口 + */ +public interface UserRolesMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/mapper/UsersMapper.java b/src/main/java/com/qf/backend/mapper/UsersMapper.java new file mode 100644 index 0000000..95f4473 --- /dev/null +++ b/src/main/java/com/qf/backend/mapper/UsersMapper.java @@ -0,0 +1,10 @@ +package com.qf.backend.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.entity.Users; + +/** + * 用户基本信息表 Mapper 接口 + */ +public interface UsersMapper extends BaseMapper { +} diff --git a/src/main/java/com/qf/backend/service/OrderItemsService.java b/src/main/java/com/qf/backend/service/OrderItemsService.java new file mode 100644 index 0000000..ac784a3 --- /dev/null +++ b/src/main/java/com/qf/backend/service/OrderItemsService.java @@ -0,0 +1,83 @@ +package com.qf.backend.service; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.OrderItems; + +/** + * 订单项服务接口 + */ +public interface OrderItemsService extends IService { + + /** + * 根据订单ID查询订单项 + * @param orderId 订单ID + * @return 订单项列表 + */ + Result> getOrderItemsByOrderId(Long orderId); + + /** + * 根据商品ID查询订单项 + * @param productId 商品ID + * @return 订单项列表 + */ + Result> getOrderItemsByProductId(Long productId); + + /** + * 创建订单项 + * @param orderItems 订单项信息 + * @return 是否成功 + */ + Result createOrderItem(OrderItems orderItems); + + /** + * 更新订单项信息 + * @param orderItems 订单项信息 + * @return 是否成功 + */ + Result updateOrderItem(OrderItems orderItems); + + /** + * 删除订单项 + * @param id 订单项ID + * @return 是否成功 + */ + Result deleteOrderItem(Long id); + + /** + * 根据订单项ID查询订单项 + * @param id 订单项ID + * @return 订单项信息 + */ + Result getOrderItemById(Long id); + + /** + * 批量创建订单项 + * @param orderItemsList 订单项列表 + * @return 是否成功 + */ + Result batchCreateOrderItems(List orderItemsList); + + /** + * 根据订单ID删除所有订单项 + * @param orderId 订单ID + * @return 是否成功 + */ + Result deleteOrderItemsByOrderId(Long orderId); + + /** + * 计算订单总金额 + * @param orderId 订单ID + * @return 订单总金额 + */ + Result calculateOrderTotal(Long orderId); + + /** + * 根据SKU ID查询订单项 + * @param skuId SKU ID + * @return 订单项列表 + */ + Result> getOrderItemsBySkuId(Long skuId); +} diff --git a/src/main/java/com/qf/backend/service/OrderStatusHistoryService.java b/src/main/java/com/qf/backend/service/OrderStatusHistoryService.java new file mode 100644 index 0000000..c23f5f7 --- /dev/null +++ b/src/main/java/com/qf/backend/service/OrderStatusHistoryService.java @@ -0,0 +1,77 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.OrderStatusHistory; + +import java.util.List; + +/** + * 订单状态历史服务接口 + */ +public interface OrderStatusHistoryService extends IService { + + /** + * 根据订单ID查询状态历史 + * @param orderId 订单ID + * @return 订单状态历史列表 + */ + Result> getHistoryByOrderId(Long orderId); + + /** + * 创建订单状态历史记录 + * @param orderStatusHistory 订单状态历史信息 + * @return 是否成功 + */ + Result createStatusHistory(OrderStatusHistory orderStatusHistory); + + /** + * 更新订单状态历史信息 + * @param orderStatusHistory 订单状态历史信息 + * @return 是否成功 + */ + Result updateStatusHistory(OrderStatusHistory orderStatusHistory); + + /** + * 删除订单状态历史记录 + * @param id 记录ID + * @return 是否成功 + */ + Result deleteStatusHistory(Long id); + + /** + * 根据记录ID查询订单状态历史 + * @param id 记录ID + * @return 订单状态历史信息 + */ + Result getStatusHistoryById(Long id); + + /** + * 批量创建订单状态历史记录 + * @param historyList 订单状态历史列表 + * @return 是否成功 + */ + Result batchCreateStatusHistory(List historyList); + + /** + * 根据订单ID和状态查询历史记录 + * @param orderId 订单ID + * @param status 订单状态 + * @return 订单状态历史列表 + */ + Result> getHistoryByOrderIdAndStatus(Long orderId, Integer status); + + /** + * 获取订单最新状态 + * @param orderId 订单ID + * @return 最新订单状态历史信息 + */ + Result getLatestStatusHistory(Long orderId); + + /** + * 根据订单ID删除所有状态历史 + * @param orderId 订单ID + * @return 是否成功 + */ + Result deleteHistoryByOrderId(Long orderId); +} diff --git a/src/main/java/com/qf/backend/service/OrdersService.java b/src/main/java/com/qf/backend/service/OrdersService.java new file mode 100644 index 0000000..5caebf1 --- /dev/null +++ b/src/main/java/com/qf/backend/service/OrdersService.java @@ -0,0 +1,85 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.Orders; + +import java.util.List; + +/** + * 订单服务接口 + */ +public interface OrdersService extends IService { + + /** + * 根据订单号查询订单 + * @param orderNumber 订单号 + * @return 订单信息 + */ + Result getOrderByNumber(String orderNumber); + + /** + * 根据用户ID查询订单列表 + * @param userId 用户ID + * @return 订单列表 + */ + Result> getOrdersByUserId(Long userId); + + /** + * 创建订单 + * @param orders 订单信息 + * @return 是否成功 + */ + Result createOrder(Orders orders); + + /** + * 更新订单信息 + * @param orders 订单信息 + * @return 是否成功 + */ + Result updateOrder(Orders orders); + + /** + * 删除订单 + * @param id 订单ID + * @return 是否成功 + */ + Result deleteOrder(Long id); + + /** + * 根据订单ID查询订单 + * @param id 订单ID + * @return 订单信息 + */ + Result getOrderById(Long id); + + /** + * 分页查询订单 + * @param page 当前页码 + * @param size 每页数量 + * @return 订单列表 + */ + Result> listOrdersByPage(int page, int size); + + /** + * 根据店铺ID查询订单 + * @param shopId 店铺ID + * @return 订单列表 + */ + Result> getOrdersByShopId(Long shopId); + + /** + * 更新订单状态 + * @param orderId 订单ID + * @param status 订单状态 + * @return 是否成功 + */ + Result updateOrderStatus(Long orderId, Integer status); + + /** + * 根据订单状态查询订单 + * @param status 订单状态 + * @return 订单列表 + */ + Result> getOrdersByStatus(Integer status); +} diff --git a/src/main/java/com/qf/backend/service/PaymentsService.java b/src/main/java/com/qf/backend/service/PaymentsService.java new file mode 100644 index 0000000..fda54ae --- /dev/null +++ b/src/main/java/com/qf/backend/service/PaymentsService.java @@ -0,0 +1,84 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.entity.Payments; + +import java.util.List; + +/** + * 支付服务接口 + */ +public interface PaymentsService extends IService { + + /** + * 根据订单ID查询支付记录 + * @param orderId 订单ID + * @return 支付记录 + */ + Payments getPaymentByOrderId(Long orderId); + + /** + * 根据支付流水号查询支付记录 + * @param transactionId 支付流水号 + * @return 支付记录 + */ + Payments getPaymentByTransactionId(String transactionId); + + /** + * 创建支付记录 + * @param payments 支付信息 + * @return 是否成功 + */ + boolean createPayment(Payments payments); + + /** + * 更新支付信息 + * @param payments 支付信息 + * @return 是否成功 + */ + boolean updatePayment(Payments payments); + + /** + * 删除支付记录 + * @param id 支付ID + * @return 是否成功 + */ + boolean deletePayment(Long id); + + /** + * 根据支付ID查询支付记录 + * @param id 支付ID + * @return 支付记录 + */ + Payments getPaymentById(Long id); + + /** + * 根据用户ID查询支付记录 + * @param userId 用户ID + * @return 支付记录列表 + */ + List getPaymentsByUserId(Long userId); + + /** + * 根据支付状态查询支付记录 + * @param status 支付状态 + * @return 支付记录列表 + */ + List getPaymentsByStatus(Integer status); + + /** + * 更新支付状态 + * @param paymentId 支付ID + * @param status 支付状态 + * @return 是否成功 + */ + boolean updatePaymentStatus(Long paymentId, Integer status); + + /** + * 分页查询支付记录 + * @param page 当前页码 + * @param size 每页数量 + * @return 支付记录列表 + */ + List listPaymentsByPage(int page, int size); +} diff --git a/src/main/java/com/qf/backend/service/PermissionsService.java b/src/main/java/com/qf/backend/service/PermissionsService.java new file mode 100644 index 0000000..0e6b625 --- /dev/null +++ b/src/main/java/com/qf/backend/service/PermissionsService.java @@ -0,0 +1,74 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.entity.Permissions; + +import java.util.List; + +/** + * 权限服务接口 + */ +public interface PermissionsService extends IService { + + /** + * 根据权限编码查询权限 + * @param permissionCode 权限编码 + * @return 权限信息 + */ + Permissions getPermissionByCode(String permissionCode); + + /** + * 创建权限 + * @param permissions 权限信息 + * @return 是否成功 + */ + boolean createPermission(Permissions permissions); + + /** + * 更新权限信息 + * @param permissions 权限信息 + * @return 是否成功 + */ + boolean updatePermission(Permissions permissions); + + /** + * 删除权限 + * @param id 权限ID + * @return 是否成功 + */ + boolean deletePermission(Long id); + + /** + * 查询所有权限 + * @return 权限列表 + */ + List listAllPermissions(); + + /** + * 根据权限ID查询权限 + * @param id 权限ID + * @return 权限信息 + */ + Permissions getPermissionById(Long id); + + /** + * 批量删除权限 + * @param ids 权限ID列表 + * @return 是否成功 + */ + boolean batchDeletePermissions(List ids); + + /** + * 根据菜单ID查询权限 + * @param menuId 菜单ID + * @return 权限列表 + */ + List listPermissionsByMenuId(Long menuId); + + /** + * 根据权限类型查询权限 + * @param permissionType 权限类型 + * @return 权限列表 + */ + List listPermissionsByType(String permissionType); +} diff --git a/src/main/java/com/qf/backend/service/ProductAttributeValuesService.java b/src/main/java/com/qf/backend/service/ProductAttributeValuesService.java new file mode 100644 index 0000000..40d9c6c --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductAttributeValuesService.java @@ -0,0 +1,77 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductAttributeValues; + +import java.util.List; + +/** + * 商品属性值服务接口 + */ +public interface ProductAttributeValuesService extends IService { + + /** + * 根据商品ID查询属性值 + * @param productId 商品ID + * @return 属性值列表 + */ + Result> getAttributeValuesByProductId(Long productId); + + /** + * 根据属性ID查询属性值 + * @param attributeId 属性ID + * @return 属性值列表 + */ + Result> getAttributeValuesByAttributeId(Long attributeId); + + /** + * 创建属性值 + * @param productAttributeValues 属性值信息 + * @return 是否成功 + */ + Result createAttributeValue(ProductAttributeValues productAttributeValues); + + /** + * 更新属性值信息 + * @param productAttributeValues 属性值信息 + * @return 是否成功 + */ + Result updateAttributeValue(ProductAttributeValues productAttributeValues); + + /** + * 删除属性值 + * @param id 属性值ID + * @return 是否成功 + */ + Result deleteAttributeValue(Long id); + + /** + * 根据属性值ID查询属性值 + * @param id 属性值ID + * @return 属性值信息 + */ + Result getAttributeValueById(Long id); + + /** + * 批量创建商品属性值 + * @param attributeValues 属性值列表 + * @return 是否成功 + */ + Result batchCreateAttributeValues(List attributeValues); + + /** + * 根据商品ID和属性ID查询属性值 + * @param productId 商品ID + * @param attributeId 属性ID + * @return 属性值信息 + */ + Result getAttributeValueByProductAndAttribute(Long productId, Long attributeId); + + /** + * 根据商品ID删除所有属性值 + * @param productId 商品ID + * @return 是否成功 + */ + Result deleteAttributeValuesByProductId(Long productId); +} diff --git a/src/main/java/com/qf/backend/service/ProductAttributesService.java b/src/main/java/com/qf/backend/service/ProductAttributesService.java new file mode 100644 index 0000000..34a2c0b --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductAttributesService.java @@ -0,0 +1,76 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductAttributes; + +import java.util.List; + +/** + * 商品属性服务接口 + */ +public interface ProductAttributesService extends IService { + + /** + * 根据分类ID查询属性 + * @param categoryId 分类ID + * @return 属性列表 + */ + Result> getAttributesByCategoryId(Long categoryId); + + /** + * 根据属性名称查询属性 + * @param attributeName 属性名称 + * @return 属性列表 + */ + Result> getAttributesByName(String attributeName); + + /** + * 创建属性 + * @param productAttributes 属性信息 + * @return 是否成功 + */ + Result createAttribute(ProductAttributes productAttributes); + + /** + * 更新属性信息 + * @param productAttributes 属性信息 + * @return 是否成功 + */ + Result updateAttribute(ProductAttributes productAttributes); + + /** + * 删除属性 + * @param id 属性ID + * @return 是否成功 + */ + Result deleteAttribute(Long id); + + /** + * 根据属性ID查询属性 + * @param id 属性ID + * @return 属性信息 + */ + Result getAttributeById(Long id); + + /** + * 批量删除属性 + * @param ids 属性ID列表 + * @return 是否成功 + */ + Result batchDeleteAttributes(List ids); + + /** + * 根据属性类型查询属性 + * @param attributeType 属性类型 + * @return 属性列表 + */ + Result> getAttributesByType(String attributeType); + + /** + * 查询是否可搜索的属性 + * @param searchable 是否可搜索 + * @return 属性列表 + */ + Result> getAttributesBySearchable(Boolean searchable); +} diff --git a/src/main/java/com/qf/backend/service/ProductCategoriesService.java b/src/main/java/com/qf/backend/service/ProductCategoriesService.java new file mode 100644 index 0000000..dbd206f --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductCategoriesService.java @@ -0,0 +1,74 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductCategories; + +import java.util.List; + +/** + * 商品分类服务接口 + */ +public interface ProductCategoriesService extends IService { + + /** + * 根据分类名称查询分类 + * @param categoryName 分类名称 + * @return 分类信息 + */ + Result getCategoryByName(String categoryName); + + /** + * 根据父分类ID查询子分类 + * @param parentId 父分类ID + * @return 子分类列表 + */ + Result> getSubCategoriesByParentId(Long parentId); + + /** + * 创建分类 + * @param productCategories 分类信息 + * @return 是否成功 + */ + Result createCategory(ProductCategories productCategories); + + /** + * 更新分类信息 + * @param productCategories 分类信息 + * @return 是否成功 + */ + Result updateCategory(ProductCategories productCategories); + + /** + * 删除分类 + * @param id 分类ID + * @return 是否成功 + */ + Result deleteCategory(Long id); + + /** + * 查询所有根分类(父分类ID为0或null的分类) + * @return 根分类列表 + */ + Result> listRootCategories(); + + /** + * 根据分类ID查询分类 + * @param id 分类ID + * @return 分类信息 + */ + Result getCategoryById(Long id); + + /** + * 批量删除分类 + * @param ids 分类ID列表 + * @return 是否成功 + */ + Result batchDeleteCategories(List ids); + + /** + * 查询所有分类(树形结构) + * @return 分类树形列表 + */ + Result> listAllCategoriesWithTree(); +} diff --git a/src/main/java/com/qf/backend/service/ProductImagesService.java b/src/main/java/com/qf/backend/service/ProductImagesService.java new file mode 100644 index 0000000..bcd70b2 --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductImagesService.java @@ -0,0 +1,77 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductImages; + +import java.util.List; + +/** + * 商品图片服务接口 + */ +public interface ProductImagesService extends IService { + + /** + * 根据商品ID查询图片 + * @param productId 商品ID + * @return 图片列表 + */ + Result> getImagesByProductId(Long productId); + + /** + * 根据商品ID查询主图 + * @param productId 商品ID + * @return 主图信息 + */ + Result getMainImageByProductId(Long productId); + + /** + * 创建商品图片 + * @param productImages 图片信息 + * @return 是否成功 + */ + Result createImage(ProductImages productImages); + + /** + * 更新图片信息 + * @param productImages 图片信息 + * @return 是否成功 + */ + Result updateImage(ProductImages productImages); + + /** + * 删除图片 + * @param id 图片ID + * @return 是否成功 + */ + Result deleteImage(Long id); + + /** + * 根据图片ID查询图片 + * @param id 图片ID + * @return 图片信息 + */ + Result getImageById(Long id); + + /** + * 批量创建商品图片 + * @param images 图片列表 + * @return 是否成功 + */ + Result batchCreateImages(List images); + + /** + * 根据商品ID删除所有图片 + * @param productId 商品ID + * @return 是否成功 + */ + Result deleteImagesByProductId(Long productId); + + /** + * 设置主图 + * @param productId 商品ID + * @param imageId 图片ID + * @return 是否成功 + */ + Result setMainImage(Long productId, Long imageId); +} diff --git a/src/main/java/com/qf/backend/service/ProductInventoriesService.java b/src/main/java/com/qf/backend/service/ProductInventoriesService.java new file mode 100644 index 0000000..1b8b42e --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductInventoriesService.java @@ -0,0 +1,86 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductInventories; + +import java.util.List; + +/** + * 商品库存服务接口 + */ +public interface ProductInventoriesService extends IService { + + /** + * 根据商品ID查询库存 + * @param productId 商品ID + * @return 库存列表 + */ + Result> getInventoriesByProductId(Long productId); + + /** + * 根据SKU ID查询库存 + * @param skuId SKU ID + * @return 库存信息 + */ + Result getInventoryBySkuId(Long skuId); + + /** + * 创建库存记录 + * @param productInventories 库存信息 + * @return 是否成功 + */ + Result createInventory(ProductInventories productInventories); + + /** + * 更新库存信息 + * @param productInventories 库存信息 + * @return 是否成功 + */ + Result updateInventory(ProductInventories productInventories); + + /** + * 删除库存记录 + * @param id 库存ID + * @return 是否成功 + */ + Result deleteInventory(Long id); + + /** + * 根据库存ID查询库存 + * @param id 库存ID + * @return 库存信息 + */ + Result getInventoryById(Long id); + + /** + * 增加库存 + * @param skuId SKU ID + * @param quantity 增加数量 + * @return 是否成功 + */ + Result increaseInventory(Long skuId, Integer quantity); + + /** + * 减少库存 + * @param skuId SKU ID + * @param quantity 减少数量 + * @return 是否成功 + */ + Result decreaseInventory(Long skuId, Integer quantity); + + /** + * 检查库存是否充足 + * @param skuId SKU ID + * @param quantity 需要的数量 + * @return 是否充足 + */ + Result checkInventorySufficient(Long skuId, Integer quantity); + + /** + * 批量更新库存 + * @param inventoryUpdates 库存更新列表 + * @return 是否成功 + */ + Result batchUpdateInventory(List inventoryUpdates); +} diff --git a/src/main/java/com/qf/backend/service/ProductSkusService.java b/src/main/java/com/qf/backend/service/ProductSkusService.java new file mode 100644 index 0000000..6e65d81 --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductSkusService.java @@ -0,0 +1,84 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ProductSkus; + +import java.util.List; + +/** + * 商品SKU服务接口 + */ +public interface ProductSkusService extends IService { + + /** + * 根据商品ID查询SKU + * @param productId 商品ID + * @return SKU列表 + */ + Result> getSkusByProductId(Long productId); + + /** + * 根据SKU编码查询SKU + * @param skuCode SKU编码 + * @return SKU信息 + */ + Result getSkuByCode(String skuCode); + + /** + * 创建SKU + * @param productSkus SKU信息 + * @return 是否成功 + */ + Result createSku(ProductSkus productSkus); + + /** + * 更新SKU信息 + * @param productSkus SKU信息 + * @return 是否成功 + */ + Result updateSku(ProductSkus productSkus); + + /** + * 删除SKU + * @param id SKU ID + * @return 是否成功 + */ + Result deleteSku(Long id); + + /** + * 根据SKU ID查询SKU + * @param id SKU ID + * @return SKU信息 + */ + Result getSkuById(Long id); + + /** + * 批量创建SKU + * @param skus SKU列表 + * @return 是否成功 + */ + Result batchCreateSkus(List skus); + + /** + * 根据商品ID删除所有SKU + * @param productId 商品ID + * @return 是否成功 + */ + Result deleteSkusByProductId(Long productId); + + /** + * 更新SKU库存 + * @param skuId SKU ID + * @param quantity 库存数量 + * @return 是否成功 + */ + Result updateSkuStock(Long skuId, Integer quantity); + + /** + * 批量查询SKU + * @param skuIds SKU ID列表 + * @return SKU列表 + */ + Result> batchGetSkus(List skuIds); +} diff --git a/src/main/java/com/qf/backend/service/ProductsService.java b/src/main/java/com/qf/backend/service/ProductsService.java new file mode 100644 index 0000000..3216fcb --- /dev/null +++ b/src/main/java/com/qf/backend/service/ProductsService.java @@ -0,0 +1,87 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.Products; + +import java.util.List; + +/** + * 商品服务接口 + */ +public interface ProductsService extends IService { + + /** + * 根据商品名称查询商品 + * @param productName 商品名称 + * @return 商品列表 + */ + Result> getProductsByName(String productName); + + /** + * 根据分类ID查询商品 + * @param categoryId 分类ID + * @return 商品列表 + */ + Result> getProductsByCategoryId(Long categoryId); + + /** + * 创建商品 + * @param products 商品信息 + * @return 是否成功 + */ + Result createProduct(Products products); + + /** + * 更新商品信息 + * @param products 商品信息 + * @return 是否成功 + */ + Result updateProduct(Products products); + + /** + * 删除商品 + * @param id 商品ID + * @return 是否成功 + */ + Result deleteProduct(Long id); + + /** + * 根据商品ID查询商品 + * @param id 商品ID + * @return 商品信息 + */ + Result getProductById(Long id); + + /** + * 分页查询商品 + * @param page 当前页码 + * @param size 每页数量 + * @return 商品列表 + */ + Result> listProductsByPage(int page, int size); + + /** + * 根据店铺ID查询商品 + * @param shopId 店铺ID + * @return 商品列表 + */ + Result> getProductsByShopId(Long shopId); + + /** + * 批量上下架商品 + * @param ids 商品ID列表 + * @param status 状态(上架/下架) + * @return 是否成功 + */ + Result batchUpdateProductStatus(List ids, Integer status); + + /** + * 搜索商品 + * @param keyword 关键词 + * @param page 当前页码 + * @param size 每页数量 + * @return 商品列表 + */ + Result> searchProducts(String keyword, int page, int size); +} diff --git a/src/main/java/com/qf/backend/service/RefundsService.java b/src/main/java/com/qf/backend/service/RefundsService.java new file mode 100644 index 0000000..f091db2 --- /dev/null +++ b/src/main/java/com/qf/backend/service/RefundsService.java @@ -0,0 +1,84 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.entity.Refunds; + +import java.util.List; + +/** + * 退款服务接口 + */ +public interface RefundsService extends IService { + + /** + * 根据订单ID查询退款记录 + * @param orderId 订单ID + * @return 退款记录列表 + */ + List getRefundsByOrderId(Long orderId); + + /** + * 根据退款单号查询退款记录 + * @param refundNumber 退款单号 + * @return 退款记录 + */ + Refunds getRefundByNumber(String refundNumber); + + /** + * 创建退款记录 + * @param refunds 退款信息 + * @return 是否成功 + */ + boolean createRefund(Refunds refunds); + + /** + * 更新退款信息 + * @param refunds 退款信息 + * @return 是否成功 + */ + boolean updateRefund(Refunds refunds); + + /** + * 删除退款记录 + * @param id 退款ID + * @return 是否成功 + */ + boolean deleteRefund(Long id); + + /** + * 根据退款ID查询退款记录 + * @param id 退款ID + * @return 退款记录 + */ + Refunds getRefundById(Long id); + + /** + * 根据用户ID查询退款记录 + * @param userId 用户ID + * @return 退款记录列表 + */ + List getRefundsByUserId(Long userId); + + /** + * 根据退款状态查询退款记录 + * @param status 退款状态 + * @return 退款记录列表 + */ + List getRefundsByStatus(Integer status); + + /** + * 更新退款状态 + * @param refundId 退款ID + * @param status 退款状态 + * @return 是否成功 + */ + boolean updateRefundStatus(Long refundId, Integer status); + + /** + * 分页查询退款记录 + * @param page 当前页码 + * @param size 每页数量 + * @return 退款记录列表 + */ + List listRefundsByPage(int page, int size); +} diff --git a/src/main/java/com/qf/backend/service/RolePermissionsService.java b/src/main/java/com/qf/backend/service/RolePermissionsService.java new file mode 100644 index 0000000..6c9419a --- /dev/null +++ b/src/main/java/com/qf/backend/service/RolePermissionsService.java @@ -0,0 +1,72 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.entity.RolePermissions; + +import java.util.List; + +/** + * 角色权限关联服务接口 + */ +public interface RolePermissionsService extends IService { + + /** + * 根据角色ID查询角色权限关联 + * @param roleId 角色ID + * @return 角色权限关联列表 + */ + List getRolePermissionsByRoleId(Long roleId); + + /** + * 根据权限ID查询角色权限关联 + * @param permissionId 权限ID + * @return 角色权限关联列表 + */ + List getRolePermissionsByPermissionId(Long permissionId); + + /** + * 为角色添加权限 + * @param roleId 角色ID + * @param permissionId 权限ID + * @return 是否成功 + */ + boolean addPermissionToRole(Long roleId, Long permissionId); + + /** + * 从角色移除权限 + * @param roleId 角色ID + * @param permissionId 权限ID + * @return 是否成功 + */ + boolean removePermissionFromRole(Long roleId, Long permissionId); + + /** + * 批量为角色添加权限 + * @param roleId 角色ID + * @param permissionIds 权限ID列表 + * @return 是否成功 + */ + boolean batchAddPermissionsToRole(Long roleId, List permissionIds); + + /** + * 清空角色的所有权限 + * @param roleId 角色ID + * @return 是否成功 + */ + boolean clearRolePermissions(Long roleId); + + /** + * 检查角色是否拥有指定权限 + * @param roleId 角色ID + * @param permissionId 权限ID + * @return 是否拥有 + */ + boolean checkRoleHasPermission(Long roleId, Long permissionId); + + /** + * 根据角色ID查询其拥有的权限ID列表 + * @param roleId 角色ID + * @return 权限ID列表 + */ + List listPermissionIdsByRoleId(Long roleId); +} diff --git a/src/main/java/com/qf/backend/service/RolesService.java b/src/main/java/com/qf/backend/service/RolesService.java new file mode 100644 index 0000000..a1b441a --- /dev/null +++ b/src/main/java/com/qf/backend/service/RolesService.java @@ -0,0 +1,67 @@ +package com.qf.backend.service; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.entity.Roles; + +/** + * 角色服务接口 + */ +public interface RolesService extends IService { + + /** + * 根据角色名称查询角色 + * @param roleName 角色名称 + * @return 角色信息 + */ + Roles getRoleByName(String roleName); + + /** + * 创建角色 + * @param roles 角色信息 + * @return 是否成功 + */ + boolean createRole(Roles roles); + + /** + * 更新角色信息 + * @param roles 角色信息 + * @return 是否成功 + */ + boolean updateRole(Roles roles); + + /** + * 删除角色 + * @param id 角色ID + * @return 是否成功 + */ + boolean deleteRole(Long id); + + /** + * 查询所有角色 + * @return 角色列表 + */ + List listAllRoles(); + + /** + * 根据角色ID查询角色 + * @param id 角色ID + * @return 角色信息 + */ + Roles getRoleById(Long id); + + /** + * 批量删除角色 + * @param ids 角色ID列表 + * @return 是否成功 + */ + boolean batchDeleteRoles(List ids); + + /** + * 根据用户ID查询其拥有的角色列表 + * @param userId 用户ID + * @return 角色列表 + */ + List listRolesByUserId(Long userId); +} diff --git a/src/main/java/com/qf/backend/service/ShopCategoriesService.java b/src/main/java/com/qf/backend/service/ShopCategoriesService.java new file mode 100644 index 0000000..3fafdf4 --- /dev/null +++ b/src/main/java/com/qf/backend/service/ShopCategoriesService.java @@ -0,0 +1,74 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ShopCategories; + +import java.util.List; + +/** + * 店铺分类服务接口 + */ +public interface ShopCategoriesService extends IService { + + /** + * 根据分类名称查询分类 + * @param categoryName 分类名称 + * @return 分类信息 + */ + Result getCategoryByName(String categoryName); + + /** + * 根据父分类ID查询子分类 + * @param parentId 父分类ID + * @return 子分类列表 + */ + Result> getSubCategoriesByParentId(Long parentId); + + /** + * 创建分类 + * @param shopCategories 分类信息 + * @return 是否成功 + */ + Result createCategory(ShopCategories shopCategories); + + /** + * 更新分类信息 + * @param shopCategories 分类信息 + * @return 是否成功 + */ + Result updateCategory(ShopCategories shopCategories); + + /** + * 删除分类 + * @param id 分类ID + * @return 是否成功 + */ + Result deleteCategory(Long id); + + /** + * 查询所有根分类(父分类ID为0或null的分类) + * @return 根分类列表 + */ + Result> listRootCategories(); + + /** + * 根据分类ID查询分类 + * @param id 分类ID + * @return 分类信息 + */ + Result getCategoryById(Long id); + + /** + * 批量删除分类 + * @param ids 分类ID列表 + * @return 是否成功 + */ + Result batchDeleteCategories(List ids); + + /** + * 查询所有分类(树形结构) + * @return 分类树形列表 + */ + Result> listAllCategoriesWithTree(); +} diff --git a/src/main/java/com/qf/backend/service/ShopRatingsService.java b/src/main/java/com/qf/backend/service/ShopRatingsService.java new file mode 100644 index 0000000..200f003 --- /dev/null +++ b/src/main/java/com/qf/backend/service/ShopRatingsService.java @@ -0,0 +1,94 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.ShopRatings; + +import java.util.List; + +/** + * 店铺评分服务接口 + */ +public interface ShopRatingsService extends IService { + + /** + * 根据店铺ID查询评分 + * @param shopId 店铺ID + * @return 评分列表 + */ + Result> getRatingsByShopId(Long shopId); + + /** + * 根据用户ID查询评分 + * @param userId 用户ID + * @return 评分列表 + */ + Result> getRatingsByUserId(Long userId); + + /** + * 创建评分 + * @param shopRatings 评分信息 + * @return 是否成功 + */ + Result createRating(ShopRatings shopRatings); + + /** + * 更新评分信息 + * @param shopRatings 评分信息 + * @return 是否成功 + */ + Result updateRating(ShopRatings shopRatings); + + /** + * 删除评分 + * @param id 评分ID + * @return 是否成功 + */ + Result deleteRating(Long id); + + /** + * 根据评分ID查询评分 + * @param id 评分ID + * @return 评分信息 + */ + Result getRatingById(Long id); + + /** + * 获取店铺平均评分 + * @param shopId 店铺ID + * @return 平均评分 + */ + Result getAverageRatingByShopId(Long shopId); + + /** + * 获取店铺评分数量 + * @param shopId 店铺ID + * @return 评分数量 + */ + Result getRatingCountByShopId(Long shopId); + + /** + * 根据评分星级查询店铺评分 + * @param shopId 店铺ID + * @param rating 评分星级 + * @return 评分列表 + */ + Result> getRatingsByShopIdAndRating(Long shopId, Integer rating); + + /** + * 检查用户是否已对店铺评分 + * @param shopId 店铺ID + * @param userId 用户ID + * @return 是否已评分 + */ + Result checkUserHasRated(Long shopId, Long userId); + + /** + * 分页查询店铺评分 + * @param shopId 店铺ID + * @param page 当前页码 + * @param size 每页数量 + * @return 评分列表 + */ + Result> listRatingsByShopIdAndPage(Long shopId, int page, int size); +} diff --git a/src/main/java/com/qf/backend/service/ShopsService.java b/src/main/java/com/qf/backend/service/ShopsService.java new file mode 100644 index 0000000..d12bf45 --- /dev/null +++ b/src/main/java/com/qf/backend/service/ShopsService.java @@ -0,0 +1,87 @@ +package com.qf.backend.service; + +import java.util.List; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.Shops; + +/** + * 店铺服务接口 + */ +public interface ShopsService extends IService { + + /** + * 根据店铺名称查询店铺 + * @param shopName 店铺名称 + * @return 店铺列表 + */ + Result> getShopsByName(String shopName); + + /** + * 根据用户ID查询店铺 + * @param userId 用户ID + * @return 店铺信息 + */ + Result getShopByUserId(Long userId); + + /** + * 创建店铺 + * @param shops 店铺信息 + * @return 是否成功 + */ + Result createShop(Shops shops); + + /** + * 更新店铺信息 + * @param shops 店铺信息 + * @return 是否成功 + */ + Result updateShop(Shops shops); + + /** + * 删除店铺 + * @param id 店铺ID + * @return 是否成功 + */ + Result deleteShop(Long id); + + /** + * 根据店铺ID查询店铺 + * @param id 店铺ID + * @return 店铺信息 + */ + Result getShopById(Long id); + + /** + * 分页查询店铺 + * @param page 当前页码 + * @param size 每页数量 + * @return 店铺列表 + */ + Result> listShopsByPage(int page, int size); + + /** + * 根据店铺分类ID查询店铺 + * @param categoryId 分类ID + * @return 店铺列表 + */ + Result> getShopsByCategoryId(Long categoryId); + + /** + * 更新店铺状态 + * @param shopId 店铺ID + * @param status 店铺状态 + * @return 是否成功 + */ + Result updateShopStatus(Long shopId, Integer status); + + /** + * 搜索店铺 + * @param keyword 关键词 + * @param page 当前页码 + * @param size 每页数量 + * @return 店铺列表 + */ + Result> searchShops(String keyword, int page, int size); +} diff --git a/src/main/java/com/qf/backend/service/UserDetailsService.java b/src/main/java/com/qf/backend/service/UserDetailsService.java new file mode 100644 index 0000000..3ae0cb7 --- /dev/null +++ b/src/main/java/com/qf/backend/service/UserDetailsService.java @@ -0,0 +1,55 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.UserDetails; + +/** + * 用户详情服务接口 + */ +public interface UserDetailsService extends IService { + + /** + * 根据用户ID查询用户详情 + * @param userId 用户ID + * @return 用户详情信息 + */ + Result getUserDetailsByUserId(Long userId); + + /** + * 创建用户详情 + * @param userDetails 用户详情信息 + * @return 是否成功 + */ + Result createUserDetails(UserDetails userDetails); + + /** + * 更新用户详情 + * @param userDetails 用户详情信息 + * @return 是否成功 + */ + Result updateUserDetails(UserDetails userDetails); + + /** + * 根据用户ID删除用户详情 + * @param userId 用户ID + * @return 是否成功 + */ + Result deleteUserDetailsByUserId(Long userId); + + /** + * 根据用户详情ID查询 + * @param id 用户详情ID + * @return 用户详情信息 + */ + Result getUserDetailsById(Long id); + + /** + * 更新用户联系方式 + * @param userId 用户ID + * @param phone 手机号 + * @param email 邮箱 + * @return 是否成功 + */ + Result updateContactInfo(Long userId, String phone, String email); +} diff --git a/src/main/java/com/qf/backend/service/UserRolesService.java b/src/main/java/com/qf/backend/service/UserRolesService.java new file mode 100644 index 0000000..ebff741 --- /dev/null +++ b/src/main/java/com/qf/backend/service/UserRolesService.java @@ -0,0 +1,66 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.UserRoles; + +import java.util.List; + +/** + * 用户角色关联服务接口 + */ +public interface UserRolesService extends IService { + + /** + * 根据用户ID查询用户角色关联 + * @param userId 用户ID + * @return 用户角色关联列表 + */ + Result> getUserRolesByUserId(Long userId); + + /** + * 根据角色ID查询用户角色关联 + * @param roleId 角色ID + * @return 用户角色关联列表 + */ + Result> getUserRolesByRoleId(Long roleId); + + /** + * 为用户添加角色 + * @param userId 用户ID + * @param roleId 角色ID + * @return 是否成功 + */ + Result addRoleToUser(Long userId, Long roleId); + + /** + * 从用户移除角色 + * @param userId 用户ID + * @param roleId 角色ID + * @return 是否成功 + */ + Result removeRoleFromUser(Long userId, Long roleId); + + /** + * 批量为用户添加角色 + * @param userId 用户ID + * @param roleIds 角色ID列表 + * @return 是否成功 + */ + Result batchAddRolesToUser(Long userId, List roleIds); + + /** + * 清空用户的所有角色 + * @param userId 用户ID + * @return 是否成功 + */ + Result clearUserRoles(Long userId); + + /** + * 检查用户是否拥有指定角色 + * @param userId 用户ID + * @param roleId 角色ID + * @return 是否拥有 + */ + Result checkUserHasRole(Long userId, Long roleId); +} diff --git a/src/main/java/com/qf/backend/service/UsersService.java b/src/main/java/com/qf/backend/service/UsersService.java new file mode 100644 index 0000000..45b8e99 --- /dev/null +++ b/src/main/java/com/qf/backend/service/UsersService.java @@ -0,0 +1,77 @@ +package com.qf.backend.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.qf.backend.common.Result; +import com.qf.backend.entity.Users; + +import java.util.List; + +/** + * 用户服务接口 + */ +public interface UsersService extends IService { + + /** + * 根据用户名查询用户 + * @param username 用户名 + * @return 用户信息 + */ + Result getUserByUsername(String username); + + /** + * 根据邮箱查询用户 + * @param email 邮箱 + * @return 用户信息 + */ + Result getUserByEmail(String email); + + /** + * 创建用户 + * @param users 用户信息 + * @return 是否成功 + */ + Result createUser(Users users); + + /** + * 更新用户信息 + * @param users 用户信息 + * @return 是否成功 + */ + Result updateUser(Users users); + + /** + * 删除用户 + * @param id 用户ID + * @return 是否成功 + */ + Result deleteUser(Long id); + + /** + * 查询所有用户 + * @return 用户列表 + */ + Result> listAllUsers(); + + /** + * 分页查询用户 + * @param page 当前页码 + * @param size 每页数量 + * @return 用户列表 + */ + Result> listUsersByPage(int page, int size); + + /** + * 根据用户ID查询用户 + * @param id 用户ID + * @return 用户信息 + */ + Result getUserById(Long id); + + /** + * 更新用户密码 + * @param id 用户ID + * @param newPassword 新密码 + * @return 是否成功 + */ + Result updatePassword(Long id, String newPassword); +} diff --git a/src/main/java/com/qf/backend/service/impl/OrderItemsServiceImpl.java b/src/main/java/com/qf/backend/service/impl/OrderItemsServiceImpl.java new file mode 100644 index 0000000..9bd6a91 --- /dev/null +++ b/src/main/java/com/qf/backend/service/impl/OrderItemsServiceImpl.java @@ -0,0 +1,142 @@ +package com.qf.backend.service.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.qf.backend.common.Result; +import com.qf.backend.common.ResultUtils; +import com.qf.backend.entity.OrderItems; +import com.qf.backend.exception.ErrorCode; +import com.qf.backend.mapper.OrderItemsMapper; +import com.qf.backend.service.OrderItemsService; + +@Service +public class OrderItemsServiceImpl implements OrderItemsService { + + @Autowired + private OrderItemsMapper orderItemsMapper; + + @Override + public Result> getOrderItemsByOrderId(Long orderId) { + try { + List orderItems = orderItemsMapper.selectByOrderId(orderId); + if (orderItems == null || orderItems.isEmpty()) { + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + return ResultUtils.success(orderItems); + } catch (Exception e) { + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + } + @Override + public Result> getOrderItemsByProductId(Long productId) { + try { + List orderItems = orderItemsMapper.selectByProductId(productId); + if (orderItems == null || orderItems.isEmpty()) { + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + return ResultUtils.success(orderItems); + } catch (Exception e) { + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + } + @Override + public BaseMapper getBaseMapper() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getBaseMapper'"); + } + @Override + public Class getEntityClass() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getEntityClass'"); + } + @Override + public Map getMap(Wrapper queryWrapper) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getMap'"); + } + @Override + public V getObj(Wrapper queryWrapper, Function mapper) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getObj'"); + } + @Override + public OrderItems getOne(Wrapper queryWrapper, boolean throwEx) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOne'"); + } + @Override + public Optional getOneOpt(Wrapper queryWrapper, boolean throwEx) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOneOpt'"); + } + @Override + public boolean saveBatch(Collection entityList, int batchSize) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'saveBatch'"); + } + @Override + public boolean saveOrUpdate(OrderItems entity) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'saveOrUpdate'"); + } + @Override + public boolean saveOrUpdateBatch(Collection entityList, int batchSize) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'saveOrUpdateBatch'"); + } + @Override + public boolean updateBatchById(Collection entityList, int batchSize) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'updateBatchById'"); + } + @Override + public Result createOrderItem(OrderItems orderItems) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'createOrderItem'"); + } + @Override + public Result updateOrderItem(OrderItems orderItems) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'updateOrderItem'"); + } + @Override + public Result deleteOrderItem(Long id) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deleteOrderItem'"); + } + @Override + public Result getOrderItemById(Long id) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrderItemById'"); + } + @Override + public Result batchCreateOrderItems(List orderItemsList) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'batchCreateOrderItems'"); + } + @Override + public Result deleteOrderItemsByOrderId(Long orderId) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deleteOrderItemsByOrderId'"); + } + @Override + public Result calculateOrderTotal(Long orderId) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'calculateOrderTotal'"); + } + @Override + public Result> getOrderItemsBySkuId(Long skuId) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrderItemsBySkuId'"); + } + +} diff --git a/src/main/java/com/qf/backend/service/impl/OrdersServiceImpl.java b/src/main/java/com/qf/backend/service/impl/OrdersServiceImpl.java new file mode 100644 index 0000000..bd2b12f --- /dev/null +++ b/src/main/java/com/qf/backend/service/impl/OrdersServiceImpl.java @@ -0,0 +1,93 @@ +package com.qf.backend.service.impl; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.qf.backend.common.Result; +import com.qf.backend.common.ResultUtils; +import com.qf.backend.entity.Orders; +import com.qf.backend.exception.ErrorCode; +import com.qf.backend.mapper.OrdersMapper; +import com.qf.backend.service.OrdersService; + +import ch.qos.logback.classic.Logger; + +@Service +public class OrdersServiceImpl extends ServiceImpl implements OrdersService { + @Autowired + private OrdersMapper ordersMapper; + @Autowired + private Logger logger; + + @Override + public Result getOrderByNumber(String orderNumber) { + logger.info("根据订单号查询订单: {}", orderNumber); + try { + Orders orders = ordersMapper.selectByOrderNumber(orderNumber); + if (orders == null) { + logger.warn("订单号 {} 不存在", orderNumber); + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + return ResultUtils.success(orders); + } catch (Exception e) { + return ResultUtils.fail(ErrorCode.ORDER_NOT_FOUND); + } + } + + @Override + public Result> getOrdersByUserId(Long userId) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrdersByUserId'"); + } + + @Override + public Result createOrder(Orders orders) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'createOrder'"); + } + + @Override + public Result updateOrder(Orders orders) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'updateOrder'"); + } + + @Override + public Result deleteOrder(Long id) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'deleteOrder'"); + } + + @Override + public Result getOrderById(Long id) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrderById'"); + } + + @Override + public Result> listOrdersByPage(int page, int size) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'listOrdersByPage'"); + } + + @Override + public Result> getOrdersByShopId(Long shopId) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrdersByShopId'"); + } + + @Override + public Result updateOrderStatus(Long orderId, Integer status) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'updateOrderStatus'"); + } + + @Override + public Result> getOrdersByStatus(Integer status) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getOrdersByStatus'"); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..912ee01 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.application.name=backend + +# 数据库连接配置 +spring.datasource.url=jdbc:mysql://localhost:3306/TaoTaoWang?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true +spring.datasource.username=root +spring.datasource.password=123456 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver diff --git a/src/test/java/com/qf/backend/BackendApplicationTests.java b/src/test/java/com/qf/backend/BackendApplicationTests.java new file mode 100644 index 0000000..5ab11d5 --- /dev/null +++ b/src/test/java/com/qf/backend/BackendApplicationTests.java @@ -0,0 +1,13 @@ +package com.qf.backend; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class BackendApplicationTests { + + @Test + void contextLoads() { + } + +}