From d179c9d96baf61ae854075efd67f1d7af7a58d1f Mon Sep 17 00:00:00 2001 From: puzvv <1@> Date: Thu, 18 Dec 2025 00:05:35 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=A8=A1=E5=9D=97=E4=B8=8E?= =?UTF-8?q?=E5=95=86=E5=93=81=E6=A8=A1=E5=9D=97=E5=BC=80=E5=8F=91=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 18 ++- .../Common/Constant/DeletedConstant.java | 6 + .../Common/Constant/JwtClaimsConstant.java | 10 ++ .../Common/Constant/MessageConstant.java | 21 +++ .../Common/Constant/StatusConstant.java | 14 ++ .../Exception/AccountNotFoundException.java | 15 ++ .../Common/Exception/BaseException.java | 15 ++ .../Common/Exception/BusinessException.java | 11 ++ .../Common/Properties/JwtProperties.java | 18 +++ .../Common/{ => Response}/ResponseEntity.java | 2 +- .../Common/Utils/JwtUtil.java | 69 +++++++++ .../Config/MyBatisPlusConfig.java | 22 +++ .../Config/MyMetaObjectHandler.java | 26 ++++ .../ai_spring_example/Controllers/Admin.java | 2 +- .../ai_spring_example/Controllers/Auth.java | 2 +- .../ai_spring_example/Controllers/Course.java | 2 +- .../Controllers/ProductController.java | 86 +++++++++++ .../Controllers/UserController.java | 79 ++++++++++ .../Handler/GlobalExceptionHandler.java | 21 +++ .../Mapper/ProductCategoryMapper.java | 17 +++ .../Mapper/ProductMapper.java | 29 ++++ .../Mapper/ProductSkuMapper.java | 26 ++++ .../ai_spring_example/Mapper/UserMapper.java | 20 +++ .../Service/Impl/ProductServiceImpl.java | 136 ++++++++++++++++++ .../Service/Impl/UserServiceImpl.java | 54 +++++++ .../Service/ProductService.java | 48 +++++++ .../pojo/Dto/ProductDTO.java | 21 +++ .../pojo/Dto/ProductSkuDTO.java | 14 ++ .../ai_spring_example/pojo/Dto/UserDTO.java | 15 ++ .../pojo/Entity/OrderInfo.java | 106 ++++++++++++++ .../pojo/Entity/OrderItem.java | 91 ++++++++++++ .../pojo/Entity/Product.java | 96 +++++++++++++ .../pojo/Entity/ProductCategory.java | 65 +++++++++ .../pojo/Entity/ProductSku.java | 71 +++++++++ .../pojo/Entity/ShoppingCart.java | 65 +++++++++ .../ai_spring_example/pojo/Entity/User.java | 78 ++++++++++ .../pojo/Entity/UserAddress.java | 80 +++++++++++ .../pojo/Vo/ProductListVO.java | 18 +++ .../pojo/Vo/ProductSkuVO.java | 17 +++ .../ai_spring_example/pojo/Vo/ProductVO.java | 32 +++++ .../pojo/Vo/UserLoginVO.java | 17 +++ .../ai_spring_example/pojo/Vo/UserVO.java | 17 +++ src/main/resources/application.yaml | 11 +- src/main/resources/mapper/ProductMapper.xml | 18 +++ .../resources/mapper/ProductSkuMapper.xml | 21 +++ src/main/resources/mapper/UserMapper.xml | 19 +++ 46 files changed, 1635 insertions(+), 6 deletions(-) create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Constant/DeletedConstant.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Constant/JwtClaimsConstant.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Constant/MessageConstant.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Constant/StatusConstant.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Exception/AccountNotFoundException.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Exception/BaseException.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Exception/BusinessException.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Properties/JwtProperties.java rename src/main/java/icu/sunway/ai_spring_example/Common/{ => Response}/ResponseEntity.java (98%) create mode 100644 src/main/java/icu/sunway/ai_spring_example/Common/Utils/JwtUtil.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Config/MyBatisPlusConfig.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Config/MyMetaObjectHandler.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Controllers/ProductController.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Controllers/UserController.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Handler/GlobalExceptionHandler.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Mapper/ProductCategoryMapper.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Mapper/ProductMapper.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Mapper/ProductSkuMapper.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Mapper/UserMapper.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Service/Impl/ProductServiceImpl.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Service/Impl/UserServiceImpl.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/Service/ProductService.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductDTO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductSkuDTO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Dto/UserDTO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderInfo.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderItem.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/Product.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductCategory.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductSku.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ShoppingCart.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/User.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Entity/UserAddress.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductListVO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductSkuVO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductVO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserLoginVO.java create mode 100644 src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserVO.java create mode 100644 src/main/resources/mapper/ProductMapper.xml create mode 100644 src/main/resources/mapper/ProductSkuMapper.xml create mode 100644 src/main/resources/mapper/UserMapper.xml diff --git a/pom.xml b/pom.xml index e63083c..e5900c9 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ 1.18.30 3.5.5 4.3.1 + 8.0.33 @@ -49,7 +50,7 @@ com.mysql mysql-connector-j - runtime + ${mysql.version} com.baomidou @@ -69,6 +70,21 @@ true + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + org.springdoc diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Constant/DeletedConstant.java b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/DeletedConstant.java new file mode 100644 index 0000000..9ee3ec3 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/DeletedConstant.java @@ -0,0 +1,6 @@ +package icu.sunway.ai_spring_example.Common.Constant; + +public class DeletedConstant { + public static final Integer DELETED = 1; + public static final Integer NOT_DELETED = 0; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Constant/JwtClaimsConstant.java b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/JwtClaimsConstant.java new file mode 100644 index 0000000..96b0d76 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/JwtClaimsConstant.java @@ -0,0 +1,10 @@ +package icu.sunway.ai_spring_example.Common.Constant; + +public class JwtClaimsConstant { + + public static final String USER_ID = "userId"; + public static final String PHONE = "phone"; + public static final String USERNAME = "username"; + public static final String NAME = "name"; + +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Constant/MessageConstant.java b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/MessageConstant.java new file mode 100644 index 0000000..db61dbe --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/MessageConstant.java @@ -0,0 +1,21 @@ +package icu.sunway.ai_spring_example.Common.Constant; + +/** + * 信息提示常量类 + */ +public class MessageConstant { + public static final String ALREADY_EXISTS = "账号已存在"; + public static final String PASSWORD_ERROR = "密码错误"; + public static final String ACCOUNT_NOT_FOUND = "账号不存在"; + public static final String ACCOUNT_LOCKED = "账号被锁定"; + public static final String UNKNOWN_ERROR = "未知错误"; + public static final String USER_NOT_LOGIN = "用户未登录"; + public static final String SHOPPING_CART_IS_NULL = "购物车数据为空,不能下单"; + public static final String ADDRESS_BOOK_IS_NULL = "用户地址为空,不能下单"; + public static final String LOGIN_FAILED = "登录失败"; + public static final String UPLOAD_FAILED = "文件上传失败"; + public static final String PASSWORD_EDIT_FAILED = "密码修改失败"; + public static final String ORDER_STATUS_ERROR = "订单状态错误"; + public static final String ORDER_NOT_FOUND = "订单不存在"; + public static final String PRODUCT_NOT_FOUND = "商品不存在"; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Constant/StatusConstant.java b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/StatusConstant.java new file mode 100644 index 0000000..9fd11ef --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Constant/StatusConstant.java @@ -0,0 +1,14 @@ +package icu.sunway.ai_spring_example.Common.Constant; + +/** + * 状态常量,启用或者禁用 + */ +public class StatusConstant { + + //启用 + public static final Integer ENABLE = 1; + + //禁用 + public static final Integer DISABLE = 0; +} + diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Exception/AccountNotFoundException.java b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/AccountNotFoundException.java new file mode 100644 index 0000000..55d97f1 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/AccountNotFoundException.java @@ -0,0 +1,15 @@ +package icu.sunway.ai_spring_example.Common.Exception; + +/** + * 账号不存在异常 + */ +public class AccountNotFoundException extends BaseException { + + public AccountNotFoundException() { + } + + public AccountNotFoundException(String msg) { + super(msg); + } + +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BaseException.java b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BaseException.java new file mode 100644 index 0000000..3abe031 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BaseException.java @@ -0,0 +1,15 @@ +package icu.sunway.ai_spring_example.Common.Exception; + +/** + * 业务异常 + */ +public class BaseException extends RuntimeException { + + public BaseException() { + } + + public BaseException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BusinessException.java b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BusinessException.java new file mode 100644 index 0000000..afeaeb7 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Exception/BusinessException.java @@ -0,0 +1,11 @@ +package icu.sunway.ai_spring_example.Common.Exception; +/** + * 交易异常 + */ +public class BusinessException extends BaseException { + public BusinessException() { + } + public BusinessException(String message) { + super(message); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Properties/JwtProperties.java b/src/main/java/icu/sunway/ai_spring_example/Common/Properties/JwtProperties.java new file mode 100644 index 0000000..59daf1d --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Properties/JwtProperties.java @@ -0,0 +1,18 @@ +package icu.sunway.ai_spring_example.Common.Properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "zhiwei.jwt") +@Data +public class JwtProperties { + + /** + * 用户生成jwt令牌相关配置 + */ + private String userSecretKey; + private long userTtl; + private String userTokenName; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/ResponseEntity.java b/src/main/java/icu/sunway/ai_spring_example/Common/Response/ResponseEntity.java similarity index 98% rename from src/main/java/icu/sunway/ai_spring_example/Common/ResponseEntity.java rename to src/main/java/icu/sunway/ai_spring_example/Common/Response/ResponseEntity.java index eb33a3d..86e39aa 100644 --- a/src/main/java/icu/sunway/ai_spring_example/Common/ResponseEntity.java +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Response/ResponseEntity.java @@ -1,4 +1,4 @@ -package icu.sunway.ai_spring_example.Common; +package icu.sunway.ai_spring_example.Common.Response; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/icu/sunway/ai_spring_example/Common/Utils/JwtUtil.java b/src/main/java/icu/sunway/ai_spring_example/Common/Utils/JwtUtil.java new file mode 100644 index 0000000..b837b95 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Common/Utils/JwtUtil.java @@ -0,0 +1,69 @@ +package icu.sunway.ai_spring_example.Common.Utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.Map; + +public class JwtUtil { + /** + * 生成jwt + * 使用Hs256算法, 私匙使用固定秘钥 + * + * @param secretKey jwt秘钥 + * @param ttlMillis jwt过期时间(毫秒) + * @param claims 设置的信息 + * @return + */ + public static String createJWT(String secretKey, long ttlMillis, Map claims) { + // 生成安全密钥 + SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); + + // 指定签名的时候使用的签名算法,也就是header那部分 + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; + + // 生成JWT的时间 + long expMillis = System.currentTimeMillis() + ttlMillis; + Date exp = new Date(expMillis); + + // 设置jwt的body + JwtBuilder builder = Jwts.builder() + // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 + .setClaims(claims) + // 设置签名使用的签名算法和签名使用的秘钥 + .signWith(key, signatureAlgorithm) + // 设置过期时间 + .setExpiration(exp); + + return builder.compact(); + } + + /** + * Token解密 + * + * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个 + * @param token 加密后的token + * @return + */ + public static Claims parseJWT(String secretKey, String token) { + // 生成安全密钥 + SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); + + // 得到DefaultJwtParser + Claims claims = Jwts.parserBuilder() + // 设置签名的秘钥 + .setSigningKey(key) + // 设置需要解析的jwt + .build() + .parseClaimsJws(token) + .getBody(); + return claims; + } + +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/Config/MyBatisPlusConfig.java b/src/main/java/icu/sunway/ai_spring_example/Config/MyBatisPlusConfig.java new file mode 100644 index 0000000..86a937d --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Config/MyBatisPlusConfig.java @@ -0,0 +1,22 @@ +package icu.sunway.ai_spring_example.Config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * MyBatis-Plus核心配置(分页插件等) + */ +@Configuration +public class MyBatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 分页插件 + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Config/MyMetaObjectHandler.java b/src/main/java/icu/sunway/ai_spring_example/Config/MyMetaObjectHandler.java new file mode 100644 index 0000000..dea8310 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Config/MyMetaObjectHandler.java @@ -0,0 +1,26 @@ +package icu.sunway.ai_spring_example.Config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.context.annotation.Configuration; +import java.time.LocalDateTime; + +/** + * MyBatis-Plus字段自动填充配置 + */ +@Configuration +public class MyMetaObjectHandler implements MetaObjectHandler { + + @Override + public void insertFill(MetaObject metaObject) { + // 插入时填充创建时间和更新时间 + this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); + this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); + } + + @Override + public void updateFill(MetaObject metaObject) { + // 更新时填充更新时间 + this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Controllers/Admin.java b/src/main/java/icu/sunway/ai_spring_example/Controllers/Admin.java index 97fbb98..057b0da 100644 --- a/src/main/java/icu/sunway/ai_spring_example/Controllers/Admin.java +++ b/src/main/java/icu/sunway/ai_spring_example/Controllers/Admin.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import icu.sunway.ai_spring_example.Common.ResponseEntity; +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; /** * 用户管理后台接口 diff --git a/src/main/java/icu/sunway/ai_spring_example/Controllers/Auth.java b/src/main/java/icu/sunway/ai_spring_example/Controllers/Auth.java index e975a8e..62826a4 100644 --- a/src/main/java/icu/sunway/ai_spring_example/Controllers/Auth.java +++ b/src/main/java/icu/sunway/ai_spring_example/Controllers/Auth.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import icu.sunway.ai_spring_example.Common.ResponseEntity; +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; /** * 认证控制器 diff --git a/src/main/java/icu/sunway/ai_spring_example/Controllers/Course.java b/src/main/java/icu/sunway/ai_spring_example/Controllers/Course.java index d4bcda5..dfbf458 100644 --- a/src/main/java/icu/sunway/ai_spring_example/Controllers/Course.java +++ b/src/main/java/icu/sunway/ai_spring_example/Controllers/Course.java @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import icu.sunway.ai_spring_example.Common.ResponseEntity; +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; /** * 课程控制器 diff --git a/src/main/java/icu/sunway/ai_spring_example/Controllers/ProductController.java b/src/main/java/icu/sunway/ai_spring_example/Controllers/ProductController.java new file mode 100644 index 0000000..318c1e0 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Controllers/ProductController.java @@ -0,0 +1,86 @@ +package icu.sunway.ai_spring_example.Controllers; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; +import icu.sunway.ai_spring_example.Service.ProductService; +import icu.sunway.ai_spring_example.pojo.Dto.ProductDTO; +import icu.sunway.ai_spring_example.pojo.Vo.ProductListVO; +import icu.sunway.ai_spring_example.pojo.Vo.ProductVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/product") +@Slf4j +public class ProductController { + + @Autowired + private ProductService productService; + + /** + * 新增商品 + */ + @PostMapping + public ResponseEntity save(@RequestBody ProductDTO productDTO) { + log.info("新增商品: {}", productDTO); + productService.saveProduct(productDTO); + return ResponseEntity.success("商品新增成功"); + } + + /** + * 修改商品 + */ + @PutMapping + public ResponseEntity update(@RequestBody ProductDTO productDTO) { + log.info("修改商品: {}", productDTO); + productService.updateProduct(productDTO); + return ResponseEntity.success("商品修改成功"); + } + + /** + * 商品上下架 + */ + @PutMapping("/status/{id}/{status}") + public ResponseEntity updateStatus(@PathVariable Long id, @PathVariable Integer status) { + log.info("商品上下架: id={}, status={}", id, status); + productService.updateStatus(id, status); + return ResponseEntity.success("状态更新成功"); + } + + /** + * 分页查询商品列表 + */ + @GetMapping("/page") + public ResponseEntity> page( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size, + Long categoryId, + String name, + Integer status + ) { + log.info("分页查询商品列表: page={}, size={}, categoryId={}, name={}, status={}", + page, size, categoryId, name, status); + Page productPage = productService.getProductPage(page, size, categoryId, name, status); + + Map result = new HashMap<>(); + result.put("list", productPage.getRecords()); + result.put("total", productPage.getTotal()); + result.put("page", page); + result.put("size", size); + return ResponseEntity.success(result); + } + + /** + * 查询商品详情 + */ + @GetMapping("/{id}") + public ResponseEntity detail(@PathVariable Long id) { + log.info("查询商品详情: id={}", id); + ProductVO productVO = productService.getProductDetail(id); + return ResponseEntity.success(productVO); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Controllers/UserController.java b/src/main/java/icu/sunway/ai_spring_example/Controllers/UserController.java new file mode 100644 index 0000000..dbf05c7 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Controllers/UserController.java @@ -0,0 +1,79 @@ +package icu.sunway.ai_spring_example.Controllers; + +import icu.sunway.ai_spring_example.Common.Constant.DeletedConstant; +import icu.sunway.ai_spring_example.Common.Constant.JwtClaimsConstant; +import icu.sunway.ai_spring_example.Common.Constant.StatusConstant; +import icu.sunway.ai_spring_example.Common.Properties.JwtProperties; +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; +import icu.sunway.ai_spring_example.Common.Utils.JwtUtil; +import icu.sunway.ai_spring_example.Service.UserService; +import icu.sunway.ai_spring_example.pojo.Dto.UserDTO; +import icu.sunway.ai_spring_example.pojo.Entity.User; +import icu.sunway.ai_spring_example.pojo.Vo.UserLoginVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.DigestUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/user") +@Slf4j +public class UserController { + + @Autowired + private UserService userService; + + @Autowired + private JwtProperties jwtProperties; + @PostMapping("/login") + public ResponseEntity login(@RequestBody UserDTO userDTO){ + log.info("用户登录:{}",userDTO); + + User user = userService.login(userDTO); + + //登录成功后生成jwt令牌 + Map claims = new HashMap<>(); + claims.put(JwtClaimsConstant.USER_ID, user.getId()); + String token = JwtUtil.createJWT( + jwtProperties.getUserSecretKey(), + jwtProperties.getUserTtl(), + claims); + + UserLoginVO userLoginVO = UserLoginVO.builder() + .id(user.getId()) + .username(user.getUsername()) + .nickname(user.getNickname()) + .token(token) + .build(); + + return ResponseEntity.success(userLoginVO); + } + + @PostMapping("/logout") + public ResponseEntity logout(){ + return ResponseEntity.success("注销成功"); + } + + @PostMapping("/register") + public ResponseEntity register(@RequestBody UserDTO userDTO){ + log.info("用户注册:{}",userDTO); + User user = new User(); + BeanUtils.copyProperties(userDTO,user); + user.setStatus(StatusConstant.ENABLE); + user.setIsDeleted(DeletedConstant.NOT_DELETED); + user.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes())); + userService.save(user); + return ResponseEntity.success("注册成功"); + } + + @PutMapping("/update") + public ResponseEntity update(@RequestBody UserDTO userDTO){ + log.info("编辑用户信息:{}",userDTO); + userService.update(userDTO); + return ResponseEntity.success("更新成功"); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Handler/GlobalExceptionHandler.java b/src/main/java/icu/sunway/ai_spring_example/Handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..9eed9e3 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Handler/GlobalExceptionHandler.java @@ -0,0 +1,21 @@ +package icu.sunway.ai_spring_example.Handler; + +import icu.sunway.ai_spring_example.Common.Response.ResponseEntity; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + /** + * 捕获业务异常 + * @param e + * @return + */ + @ExceptionHandler + public ResponseEntity exceptionHandler(Exception e) { + log.error("全局异常捕获:{}", e.getMessage()); + return ResponseEntity.error(e.getMessage()); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductCategoryMapper.java b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductCategoryMapper.java new file mode 100644 index 0000000..ac19911 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductCategoryMapper.java @@ -0,0 +1,17 @@ +package icu.sunway.ai_spring_example.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import icu.sunway.ai_spring_example.pojo.Entity.ProductCategory; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface ProductCategoryMapper extends BaseMapper { + + /** + * 查询所有分类(树形结构) + * @return 分类列表 + */ + List selectAllCategories(); +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductMapper.java b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductMapper.java new file mode 100644 index 0000000..50f6ea0 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductMapper.java @@ -0,0 +1,29 @@ +package icu.sunway.ai_spring_example.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import icu.sunway.ai_spring_example.pojo.Entity.Product; +import icu.sunway.ai_spring_example.pojo.Vo.ProductListVO; +import icu.sunway.ai_spring_example.pojo.Vo.ProductVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface ProductMapper extends BaseMapper { + + /** + * 分页查询商品列表 + * @param page 分页参数 + * @param categoryId 分类ID(可选) + * @param name 商品名称(模糊查询,可选) + * @param status 状态(可选) + * @return 分页商品列表 + */ + IPage selectProductPage( + Page page, + @Param("categoryId") Long categoryId, + @Param("name") String name, + @Param("status") Integer status + ); +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductSkuMapper.java b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductSkuMapper.java new file mode 100644 index 0000000..b2ee847 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Mapper/ProductSkuMapper.java @@ -0,0 +1,26 @@ +package icu.sunway.ai_spring_example.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import icu.sunway.ai_spring_example.pojo.Entity.ProductSku; +import icu.sunway.ai_spring_example.pojo.Vo.ProductSkuVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface ProductSkuMapper extends BaseMapper { + + /** + * 根据商品ID查询规格列表 + * @param productId 商品ID + * @return 规格VO列表 + */ + List selectByProductId(@Param("productId") Long productId); + + /** + * 批量插入规格 + * @param skuList 规格列表 + */ + void batchInsert(@Param("list") List skuList); +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Mapper/UserMapper.java b/src/main/java/icu/sunway/ai_spring_example/Mapper/UserMapper.java new file mode 100644 index 0000000..c5385e3 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Mapper/UserMapper.java @@ -0,0 +1,20 @@ +package icu.sunway.ai_spring_example.Mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import icu.sunway.ai_spring_example.pojo.Entity.User; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface UserMapper extends BaseMapper { + + /** + * 根据用户名查询用户 + * @param username + * @return + */ + @Select("select * from sys_user where username = #{username}") + User getByUsername(String username); + + void update(User user); +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Service/Impl/ProductServiceImpl.java b/src/main/java/icu/sunway/ai_spring_example/Service/Impl/ProductServiceImpl.java new file mode 100644 index 0000000..612b3d5 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Service/Impl/ProductServiceImpl.java @@ -0,0 +1,136 @@ +package icu.sunway.ai_spring_example.Service.Impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import icu.sunway.ai_spring_example.Common.Exception.BusinessException; +import icu.sunway.ai_spring_example.Common.Constant.MessageConstant; +import icu.sunway.ai_spring_example.Mapper.ProductMapper; +import icu.sunway.ai_spring_example.Mapper.ProductSkuMapper; +import icu.sunway.ai_spring_example.Service.ProductService; +import icu.sunway.ai_spring_example.pojo.Dto.ProductDTO; +import icu.sunway.ai_spring_example.pojo.Dto.ProductSkuDTO; +import icu.sunway.ai_spring_example.pojo.Entity.Product; +import icu.sunway.ai_spring_example.pojo.Entity.ProductSku; +import icu.sunway.ai_spring_example.pojo.Vo.ProductListVO; +import icu.sunway.ai_spring_example.pojo.Vo.ProductVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class ProductServiceImpl extends ServiceImpl implements ProductService { + + @Autowired + private ProductMapper productMapper; + + @Autowired + private ProductSkuMapper productSkuMapper; + + @Override + @Transactional + public void saveProduct(ProductDTO productDTO) { + // 1. 保存商品基本信息 + Product product = new Product(); + BeanUtils.copyProperties(productDTO, product); + productMapper.insert(product); + + // 2. 保存商品规格 + List skuList = new ArrayList<>(); + for (ProductSkuDTO skuDTO : productDTO.getSkuList()) { + ProductSku sku = new ProductSku(); + BeanUtils.copyProperties(skuDTO, sku); + sku.setProductId(product.getId()); // 设置商品ID关联 + skuList.add(sku); + } + if (!skuList.isEmpty()) { + productSkuMapper.batchInsert(skuList); + } + } + + @Override + @Transactional + public void updateProduct(ProductDTO productDTO) { + // 1. 验证商品是否存在 + Product product = productMapper.selectById(productDTO.getId()); + if (product == null) { + throw new BusinessException(MessageConstant.PRODUCT_NOT_FOUND); + } + + // 2. 更新商品基本信息 + BeanUtils.copyProperties(productDTO, product); + productMapper.updateById(product); + + // 3. 先删除原有规格 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ProductSku::getProductId, product.getId()); + productSkuMapper.delete(queryWrapper); + + // 4. 重新插入新规格 + List skuList = new ArrayList<>(); + for (ProductSkuDTO skuDTO : productDTO.getSkuList()) { + ProductSku sku = new ProductSku(); + BeanUtils.copyProperties(skuDTO, sku); + sku.setProductId(product.getId()); + skuList.add(sku); + } + if (!skuList.isEmpty()) { + productSkuMapper.batchInsert(skuList); + } + } + + @Override + public Page getProductPage(Integer page, Integer size, Long categoryId, String name, Integer status) { + Page pageInfo = new Page<>(page, size); + IPage result = productMapper.selectProductPage(pageInfo, categoryId, name, status); + return (Page) result; + } + @Override + public ProductVO getProductDetail(Long id) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("id", id); + Product product = productMapper.selectOne(queryWrapper); + ProductVO productVO = ProductVO.builder() + .id(product.getId()) + .categoryId(product.getCategoryId()) + .name(product.getName()) + .subtitle(product.getSubtitle()) + .mainImage(product.getMainImage()) + .subImages(product.getSubImages()) + .description(product.getDescription()) + .price(product.getPrice()) + .stock(product.getStock()) + .sort(product.getSort()) + .sales(product.getSales()) + .status(product.getStatus()) + //TODO:查询分类名称 + .categoryName(null) + .createTime(product.getCreateTime()) + .updateTime(product.getUpdateTime()) + .build(); + if (productVO == null) { + throw new BusinessException(MessageConstant.PRODUCT_NOT_FOUND); + } + // 查询规格列表 + productVO.setSkuList(productSkuMapper.selectByProductId(id)); + return productVO; + } + + @Override + public void updateStatus(Long id, Integer status) { + Product product = productMapper.selectById(id); + if (product == null) { + throw new BusinessException(MessageConstant.PRODUCT_NOT_FOUND); + } + product.setStatus(status); + productMapper.updateById(product); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Service/Impl/UserServiceImpl.java b/src/main/java/icu/sunway/ai_spring_example/Service/Impl/UserServiceImpl.java new file mode 100644 index 0000000..a8918f8 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Service/Impl/UserServiceImpl.java @@ -0,0 +1,54 @@ +package icu.sunway.ai_spring_example.Service.Impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import icu.sunway.ai_spring_example.Common.Constant.MessageConstant; +import icu.sunway.ai_spring_example.Common.Constant.StatusConstant; +import icu.sunway.ai_spring_example.Common.Exception.AccountNotFoundException; +import icu.sunway.ai_spring_example.Mapper.UserMapper; +import icu.sunway.ai_spring_example.Service.UserService; +import icu.sunway.ai_spring_example.pojo.Dto.UserDTO; +import icu.sunway.ai_spring_example.pojo.Entity.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.DigestUtils; + + +@Service +@Slf4j +public class UserServiceImpl extends ServiceImpl implements UserService { + + @Autowired + private UserMapper userMapper; + @Override + public User login(UserDTO userDTO) { + String username = userDTO.getUsername(); + String password = userDTO.getPassword(); + + User user = userMapper.getByUsername(username); + + if(user == null){ + throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND); + } + + password = DigestUtils.md5DigestAsHex(password.getBytes()); + log.info("用户密码:{}",password); + if(!password.equals(user.getPassword())){ + throw new AccountNotFoundException(MessageConstant.PASSWORD_ERROR); + } + + if(user.getStatus() == StatusConstant.DISABLE){ + throw new AccountNotFoundException(MessageConstant.ACCOUNT_LOCKED); + } + + return user; + } + + @Override + public void update(UserDTO userDTO) { + User user = new User(); + BeanUtils.copyProperties(userDTO,user); + userMapper.update(user); + } +} diff --git a/src/main/java/icu/sunway/ai_spring_example/Service/ProductService.java b/src/main/java/icu/sunway/ai_spring_example/Service/ProductService.java new file mode 100644 index 0000000..a2273ca --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/Service/ProductService.java @@ -0,0 +1,48 @@ +package icu.sunway.ai_spring_example.Service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import icu.sunway.ai_spring_example.pojo.Dto.ProductDTO; +import icu.sunway.ai_spring_example.pojo.Entity.Product; +import icu.sunway.ai_spring_example.pojo.Vo.ProductListVO; +import icu.sunway.ai_spring_example.pojo.Vo.ProductVO; + +public interface ProductService extends IService { + + /** + * 新增商品(包含规格) + * @param productDTO 商品信息 + */ + void saveProduct(ProductDTO productDTO); + + /** + * 修改商品(包含规格) + * @param productDTO 商品信息 + */ + void updateProduct(ProductDTO productDTO); + + /** + * 分页查询商品列表 + * @param page 页码 + * @param size 每页条数 + * @param categoryId 分类ID + * @param name 商品名称 + * @param status 状态 + * @return 分页结果 + */ + Page getProductPage(Integer page, Integer size, Long categoryId, String name, Integer status); + + /** + * 根据ID查询商品详情 + * @param id 商品ID + * @return 商品详情 + */ + ProductVO getProductDetail(Long id); + + /** + * 上下架商品 + * @param id 商品ID + * @param status 状态(0-下架,1-上架) + */ + void updateStatus(Long id, Integer status); +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductDTO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductDTO.java new file mode 100644 index 0000000..6ec9d67 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductDTO.java @@ -0,0 +1,21 @@ +package icu.sunway.ai_spring_example.pojo.Dto; + +import lombok.Data; +import java.math.BigDecimal; +import java.util.List; + +@Data +public class ProductDTO { + private Long id; // 商品ID(修改时使用) + private Long categoryId; // 分类ID + private String name; // 商品名称 + private String subtitle; // 副标题 + private String mainImage; // 主图URL + private String subImages; // 子图URL(逗号分隔) + private String description; // 商品描述 + private BigDecimal price; // 价格 + private Integer stock; // 库存 + private Integer status; // 状态 0-下架 1-上架 + private Integer sort; // 排序 + private List skuList; // 规格列表 +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductSkuDTO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductSkuDTO.java new file mode 100644 index 0000000..d027dc7 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/ProductSkuDTO.java @@ -0,0 +1,14 @@ +package icu.sunway.ai_spring_example.pojo.Dto; + +import lombok.Data; +import java.math.BigDecimal; + +@Data +public class ProductSkuDTO { + private Long id; // 规格ID(修改时使用) + private String skuName; // 规格名称(如"红色-XL") + private String skuCode; // 规格编码 + private BigDecimal price; // 规格价格 + private Integer stock; // 规格库存 + private String specJson; // 规格参数JSON +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/UserDTO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/UserDTO.java new file mode 100644 index 0000000..1d739f0 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Dto/UserDTO.java @@ -0,0 +1,15 @@ +package icu.sunway.ai_spring_example.pojo.Dto; + +import lombok.Data; + +@Data +public class UserDTO { + private Long id; + private String username; + private String password; + private String phone; + private String email; + private String avatar; + private String nickname; + private Integer gender; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderInfo.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderInfo.java new file mode 100644 index 0000000..27c87dc --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderInfo.java @@ -0,0 +1,106 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 订单表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("order_info") +public class OrderInfo { + + /** + * 订单ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 订单编号(唯一) + */ + private String orderNo; + + /** + * 用户ID + */ + private Long userId; + + /** + * 订单总金额 + */ + private BigDecimal totalAmount; + + /** + * 实付金额 + */ + private BigDecimal payAmount; + + /** + * 运费 + */ + private BigDecimal freightAmount; + + /** + * 支付方式 0-未支付 1-微信 2-支付宝 + */ + private Integer payType; + + /** + * 订单状态 0-待付款 1-待发货 2-待收货 3-已完成 4-已取消 + */ + private Integer status; + + /** + * 收货人姓名 + */ + private String receiverName; + + /** + * 收货人手机号 + */ + private String receiverPhone; + + /** + * 收货人地址 + */ + private String receiverAddress; + + /** + * 支付时间 + */ + private LocalDateTime payTime; + + /** + * 发货时间 + */ + private LocalDateTime deliveryTime; + + /** + * 收货时间 + */ + private LocalDateTime receiveTime; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderItem.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderItem.java new file mode 100644 index 0000000..e0453b6 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/OrderItem.java @@ -0,0 +1,91 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 订单项表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("order_item") +public class OrderItem { + + /** + * 订单项ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 订单ID + */ + private Long orderId; + + /** + * 订单编号 + */ + private String orderNo; + + /** + * 商品ID + */ + private Long productId; + + /** + * SKU ID + */ + private Long skuId; + + /** + * 商品名称 + */ + private String productName; + + /** + * SKU名称 + */ + private String skuName; + + /** + * 商品图片 + */ + private String productImage; + + /** + * 单价 + */ + private BigDecimal price; + + /** + * 数量 + */ + private Integer quantity; + + /** + * 小计金额 + */ + private BigDecimal totalPrice; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/Product.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/Product.java new file mode 100644 index 0000000..1ea4e1e --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/Product.java @@ -0,0 +1,96 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 商品表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("product") +public class Product { + + /** + * 商品ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 分类ID + */ + private Long categoryId; + + /** + * 商品名称 + */ + private String name; + + /** + * 副标题 + */ + private String subtitle; + + /** + * 主图URL + */ + private String mainImage; + + /** + * 子图URL(逗号分隔) + */ + private String subImages; + + /** + * 商品描述 + */ + private String description; + + /** + * 价格 + */ + private BigDecimal price; + + /** + * 库存 + */ + private Integer stock; + + /** + * 销量 + */ + private Integer sales; + + /** + * 状态 0-下架 1-上架 + */ + private Integer status; + + /** + * 排序 + */ + private Integer sort; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductCategory.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductCategory.java new file mode 100644 index 0000000..5fdd412 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductCategory.java @@ -0,0 +1,65 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 商品分类表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("product_category") +public class ProductCategory { + + /** + * 分类ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 父分类ID(0为一级分类) + */ + private Long parentId; + + /** + * 分类名称 + */ + private String name; + + /** + * 排序(升序) + */ + private Integer sort; + + /** + * 图标URL + */ + private String icon; + + /** + * 层级(1/2/3) + */ + private Integer level; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductSku.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductSku.java new file mode 100644 index 0000000..292b8ec --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ProductSku.java @@ -0,0 +1,71 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 商品规格表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("product_sku") +public class ProductSku { + + /** + * SKU ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 商品ID + */ + private Long productId; + + /** + * SKU名称(如"红色-XL") + */ + private String skuName; + + /** + * SKU编码(唯一) + */ + private String skuCode; + + /** + * SKU价格 + */ + private BigDecimal price; + + /** + * SKU库存 + */ + private Integer stock; + + /** + * 规格JSON({"颜色":"红","尺寸":"XL"}) + */ + private String specJson; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ShoppingCart.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ShoppingCart.java new file mode 100644 index 0000000..7c60485 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/ShoppingCart.java @@ -0,0 +1,65 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 购物车表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("shopping_cart") +public class ShoppingCart { + + /** + * 购物车ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 商品ID + */ + private Long productId; + + /** + * SKU ID + */ + private Long skuId; + + /** + * 数量 + */ + private Integer count; + + /** + * 勾选状态 0-未勾选 1-已勾选 + */ + private Integer checked; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/User.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/User.java new file mode 100644 index 0000000..2b558a8 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/User.java @@ -0,0 +1,78 @@ +package icu.sunway.ai_spring_example.pojo.Entity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 用户表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("sys_user") +public class User { + /** + * 用户ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 用户名(唯一) + */ + private String username; + + /** + * 加密密码(BCrypt) + */ + private String password; + + /** + * 手机号(唯一) + */ + private String phone; + + /** + * 邮箱(可选) + */ + private String email; + + /** + * 头像URL + */ + private String avatar; + + /** + * 昵称 + */ + private String nickname; + + /** + * 性别 0-未知 1-男 2-女 + */ + private Integer gender; + + /** + * 状态 0-禁用 1-正常 + */ + private Integer status; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/UserAddress.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/UserAddress.java new file mode 100644 index 0000000..49c65cb --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Entity/UserAddress.java @@ -0,0 +1,80 @@ +package icu.sunway.ai_spring_example.pojo.Entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import java.time.LocalDateTime; + +/** + * 用户地址表实体类 + * + * @author ZhiWei + * @since 2025-12-17 + */ +@Data +@TableName("user_address") +public class UserAddress { + + /** + * 地址ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 收货人姓名 + */ + private String receiverName; + + /** + * 收货人手机号 + */ + private String receiverPhone; + + /** + * 省 + */ + private String province; + + /** + * 市 + */ + private String city; + + /** + * 区/县 + */ + private String district; + + /** + * 详细地址 + */ + private String detailAddress; + + /** + * 是否默认 0-非默认 1-默认 + */ + private Integer isDefault; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** + * 逻辑删除 0-未删 1-已删 + */ + @TableLogic + private Integer isDeleted; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductListVO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductListVO.java new file mode 100644 index 0000000..d756d93 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductListVO.java @@ -0,0 +1,18 @@ +package icu.sunway.ai_spring_example.pojo.Vo; + +import lombok.Builder; +import lombok.Data; +import java.math.BigDecimal; + +@Data +@Builder +//用于商品列表页面的数据展示 +public class ProductListVO { + private Long id; + private String name; + private String mainImage; + private BigDecimal price; + private Integer sales; + private Integer status; + private String categoryName; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductSkuVO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductSkuVO.java new file mode 100644 index 0000000..29f02c1 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductSkuVO.java @@ -0,0 +1,17 @@ +package icu.sunway.ai_spring_example.pojo.Vo; + +import lombok.Builder; +import lombok.Data; +import java.math.BigDecimal; + +@Data +@Builder +public class ProductSkuVO { + private Long id; + private Long productId; + private String skuName; + private String skuCode; + private BigDecimal price; + private Integer stock; + private String specJson; +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductVO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductVO.java new file mode 100644 index 0000000..6de08a3 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/ProductVO.java @@ -0,0 +1,32 @@ +package icu.sunway.ai_spring_example.pojo.Vo; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@TableName("product") +public class ProductVO { + private Long id; + private Long categoryId; + private String categoryName; // 分类名称 + private String name; + private String subtitle; + private String mainImage; + private String subImages; + private String description; + private BigDecimal price; + private Integer stock; + private Integer sales; + private Integer status; + private Integer sort; + + private LocalDateTime createTime; + private LocalDateTime updateTime; + private List skuList; // 规格列表 +} \ No newline at end of file diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserLoginVO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserLoginVO.java new file mode 100644 index 0000000..ed06c84 --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserLoginVO.java @@ -0,0 +1,17 @@ +package icu.sunway.ai_spring_example.pojo.Vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserLoginVO { + private Long id; + private String username; + private String nickname; + private String token; +} diff --git a/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserVO.java b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserVO.java new file mode 100644 index 0000000..f8cf49f --- /dev/null +++ b/src/main/java/icu/sunway/ai_spring_example/pojo/Vo/UserVO.java @@ -0,0 +1,17 @@ +package icu.sunway.ai_spring_example.pojo.Vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserVO { + private Long id; + private String username; + private String nickname; + private String token; +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 316f504..3d09c6b 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -8,7 +8,7 @@ spring: strict: false datasource: master: - url: jdbc:mysql://182.92.242.196:3306/sys_user?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai + url: jdbc:mysql://182.92.242.196:3306/ZhiWeiMarket?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: remote_user password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver @@ -27,3 +27,12 @@ spring: server: port: 8080 + +zhiwei: + jwt: + # 设置jwt签名加密时使用的秘钥 + user-secret-key: itcast_hmac_sha_key_minimum_length_32_bytes_required + # 设置jwt过期时间 + user-ttl: 7200000 + # 设置前端传递过来的令牌名称 + user-token-name: token \ No newline at end of file diff --git a/src/main/resources/mapper/ProductMapper.xml b/src/main/resources/mapper/ProductMapper.xml new file mode 100644 index 0000000..4496ecf --- /dev/null +++ b/src/main/resources/mapper/ProductMapper.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/ProductSkuMapper.xml b/src/main/resources/mapper/ProductSkuMapper.xml new file mode 100644 index 0000000..c09c955 --- /dev/null +++ b/src/main/resources/mapper/ProductSkuMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + INSERT INTO product_sku ( + product_id, sku_name, sku_code, price, stock, spec_json, create_time, update_time + ) VALUES + + ( + #{item.productId}, #{item.skuName}, #{item.skuCode}, #{item.price}, + #{item.stock}, #{item.specJson}, NOW(), NOW() + ) + + + \ No newline at end of file diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..f9b7c85 --- /dev/null +++ b/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,19 @@ + + + + + + UPDATE sys_user + + username = #{username}, + nickname = #{nickname}, + phone = #{phone}, + email = #{email}, + avatar = #{avatar}, + nickname = #{nickname}, + gender = #{gender}, + update_time = NOW() + + WHERE id = #{id} + +