diff --git a/shop-api/Dockerfile b/shop-api/Dockerfile new file mode 100644 index 0000000..5fdea24 --- /dev/null +++ b/shop-api/Dockerfile @@ -0,0 +1,14 @@ +FROM openjdk:17.0.2 + + +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + +RUN mkdir -p /opt/projects/mall4j + +WORKDIR /opt/projects/mall4j + +EXPOSE 8086 + +ADD ./yami-shop-api/target/yami-shop-api-0.0.1-SNAPSHOT.jar ./ + +CMD java -jar -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -Dspring.profiles.active=docker yami-shop-api-0.0.1-SNAPSHOT.jar diff --git a/shop-api/pom.xml b/shop-api/pom.xml new file mode 100644 index 0000000..d797674 --- /dev/null +++ b/shop-api/pom.xml @@ -0,0 +1,44 @@ + + + + yami-shop + com.yami.shop + 0.0.1-SNAPSHOT + + 4.0.0 + + yami-shop-api + jar + + + + com.yami.shop + yami-shop-service + ${yami.shop.version} + + + com.yami.shop + yami-shop-security-api + ${yami.shop.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + diff --git a/shop-api/src/main/java/com/yami/shop/api/ApiApplication.java b/shop-api/src/main/java/com/yami/shop/api/ApiApplication.java new file mode 100644 index 0000000..5c5f18b --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/ApiApplication.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.ComponentScan; + +/** + * @author lgh + */ +@SpringBootApplication +@ComponentScan(basePackages = {"com.yami.shop"}) +public class ApiApplication extends SpringBootServletInitializer{ + + public static void main(String[] args) { + SpringApplication.run(ApiApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return builder.sources(ApiApplication.class); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/config/ApiBeanConfig.java b/shop-api/src/main/java/com/yami/shop/api/config/ApiBeanConfig.java new file mode 100644 index 0000000..485feb0 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/config/ApiBeanConfig.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.config; + +import cn.hutool.core.lang.Snowflake; +import lombok.AllArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author lanhai + */ +@Configuration +@AllArgsConstructor +public class ApiBeanConfig { + + private final ApiConfig apiConfig; + + @Bean + public Snowflake snowflake() { + return new Snowflake(apiConfig.getWorkerId(), apiConfig.getDatacenterId()); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/config/ApiConfig.java b/shop-api/src/main/java/com/yami/shop/api/config/ApiConfig.java new file mode 100644 index 0000000..03469db --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/config/ApiConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + + +/** + * 商城配置文件 + * @author lgh + */ +@Data +@Component +@PropertySource("classpath:api.properties") +@ConfigurationProperties(prefix = "api") +public class ApiConfig { + + /** + * 数据中心ID + */ + private Integer datacenterId; + + /** + * 终端ID + */ + private Integer workerId; + + /** + * 域名 + */ + private String domainName; + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/config/SwaggerConfiguration.java b/shop-api/src/main/java/com/yami/shop/api/config/SwaggerConfiguration.java new file mode 100644 index 0000000..e2048f3 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/config/SwaggerConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger文档,只有在测试环境才会使用 + * @author LGH + */ +@Configuration +public class SwaggerConfiguration { + + @Bean + public GroupedOpenApi createRestApi() { + return GroupedOpenApi.builder() + .group("接口文档") + .packagesToScan("com.yami.shop.api").build(); + } + + + @Bean + public OpenAPI springShopOpenApi() { + return new OpenAPI() + .info(new Info().title("Mall4j接口文档") + .description("Mall4j接口文档,openapi3.0 接口,用于前端对接") + .version("v0.0.1") + .license(new License().name("使用请遵守AGPL3.0授权协议").url("https://www.mall4j.com"))); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/AddrController.java b/shop-api/src/main/java/com/yami/shop/api/controller/AddrController.java new file mode 100644 index 0000000..739cd7e --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/AddrController.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yami.shop.bean.app.dto.UserAddrDto; +import com.yami.shop.bean.app.param.AddrParam; +import com.yami.shop.bean.model.UserAddr; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.response.ServerResponseEntity; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.UserAddrService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import cn.hutool.core.bean.BeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.Date; +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/address") +@Tag(name = "地址接口") +@AllArgsConstructor +public class AddrController { + + @Autowired + private UserAddrService userAddrService; + + /** + * 选择订单配送地址 + */ + @GetMapping("/list") + @Operation(summary = "用户地址列表" , description = "获取用户的所有地址信息") + public ServerResponseEntity> dvyList() { + String userId = SecurityUtils.getUser().getUserId(); + List userAddrs = userAddrService.list(new LambdaQueryWrapper().eq(UserAddr::getUserId, userId).orderByDesc(UserAddr::getCommonAddr).orderByDesc(UserAddr::getUpdateTime)); + return ServerResponseEntity.success(BeanUtil.copyToList(userAddrs, UserAddrDto.class)); + } + + @PostMapping("/addAddr") + @Operation(summary = "新增用户地址" , description = "新增用户地址") + public ServerResponseEntity addAddr(@Valid @RequestBody AddrParam addrParam) { + String userId = SecurityUtils.getUser().getUserId(); + + if (addrParam.getAddrId() != null && addrParam.getAddrId() != 0) { + return ServerResponseEntity.showFailMsg("该地址已存在"); + } + long addrCount = userAddrService.count(new LambdaQueryWrapper().eq(UserAddr::getUserId, userId)); + UserAddr userAddr = BeanUtil.copyProperties(addrParam, UserAddr.class); + + if (addrCount == 0) { + userAddr.setCommonAddr(1); + } else { + userAddr.setCommonAddr(0); + } + userAddr.setUserId(userId); + userAddr.setStatus(1); + userAddr.setCreateTime(new Date()); + userAddr.setUpdateTime(new Date()); + userAddrService.save(userAddr); + if (userAddr.getCommonAddr() == 1) { + // 清除默认地址缓存 + userAddrService.removeUserAddrByUserId(0L, userId); + } + return ServerResponseEntity.success("添加地址成功"); + } + + /** + * 修改订单配送地址 + */ + @PutMapping("/updateAddr") + @Operation(summary = "修改订单用户地址" , description = "修改用户地址") + public ServerResponseEntity updateAddr(@Valid @RequestBody AddrParam addrParam) { + String userId = SecurityUtils.getUser().getUserId(); + + UserAddr dbUserAddr = userAddrService.getUserAddrByUserId(addrParam.getAddrId(), userId); + if (dbUserAddr == null) { + return ServerResponseEntity.showFailMsg("该地址已被删除"); + } + + UserAddr userAddr = BeanUtil.copyProperties(addrParam, UserAddr.class); + userAddr.setUserId(userId); + userAddr.setUpdateTime(new Date()); + userAddrService.updateById(userAddr); + // 清除当前地址缓存 + userAddrService.removeUserAddrByUserId(addrParam.getAddrId(), userId); + // 清除默认地址缓存 + userAddrService.removeUserAddrByUserId(0L, userId); + return ServerResponseEntity.success("修改地址成功"); + } + + /** + * 删除订单配送地址 + */ + @DeleteMapping("/deleteAddr/{addrId}") + @Operation(summary = "删除订单用户地址" , description = "根据地址id,删除用户地址") + @Parameter(name = "addrId", description = "地址ID" , required = true) + public ServerResponseEntity deleteDvy(@PathVariable("addrId") Long addrId) { + String userId = SecurityUtils.getUser().getUserId(); + UserAddr userAddr = userAddrService.getUserAddrByUserId(addrId, userId); + if (userAddr == null) { + return ServerResponseEntity.showFailMsg("该地址已被删除"); + } + if (userAddr.getCommonAddr() == 1) { + return ServerResponseEntity.showFailMsg("默认地址无法删除"); + } + userAddrService.removeById(addrId); + userAddrService.removeUserAddrByUserId(addrId, userId); + return ServerResponseEntity.success("删除地址成功"); + } + + /** + * 设置默认地址 + */ + @PutMapping("/defaultAddr/{addrId}") + @Operation(summary = "设置默认地址" , description = "根据地址id,设置默认地址") + public ServerResponseEntity defaultAddr(@PathVariable("addrId") Long addrId) { + String userId = SecurityUtils.getUser().getUserId(); + + userAddrService.updateDefaultUserAddr(addrId, userId); + + userAddrService.removeUserAddrByUserId(0L, userId); + userAddrService.removeUserAddrByUserId(addrId, userId); + return ServerResponseEntity.success("修改地址成功"); + } + + /** + * 获取地址信息订单配送地址 + */ + @GetMapping("/addrInfo/{addrId}") + @Operation(summary = "获取地址信息" , description = "根据地址id,获取地址信息") + @Parameter(name = "addrId", description = "地址ID" , required = true) + public ServerResponseEntity addrInfo(@PathVariable("addrId") Long addrId) { + String userId = SecurityUtils.getUser().getUserId(); + UserAddr userAddr = userAddrService.getUserAddrByUserId(addrId, userId); + if (userAddr == null) { + throw new YamiShopBindException("该地址已被删除"); + } + return ServerResponseEntity.success(BeanUtil.copyProperties(userAddr, UserAddrDto.class)); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/AreaController.java b/shop-api/src/main/java/com/yami/shop/api/controller/AreaController.java new file mode 100644 index 0000000..b2c1d1b --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/AreaController.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import java.util.List; + +import com.yami.shop.service.AreaService; +import org.springframework.beans.factory.annotation.Autowired; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.yami.shop.bean.model.Area; + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +/** + * + * @author lgh on 2018/10/26. + */ +@RestController +@RequestMapping("/p/area") +@Tag(name = "省市区接口") +public class AreaController { + + @Autowired + private AreaService areaService; + + /** + * 分页获取 + */ + @GetMapping("/listByPid") + @Operation(summary = "获取省市区信息" , description = "根据省市区的pid获取地址信息") + @Parameter(name = "pid", description = "省市区的pid(pid为0获取所有省份)" , required = true) + public ServerResponseEntity> listByPid(Long pid){ + List list = areaService.listByPid(pid); + return ServerResponseEntity.success(list); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/CategoryController.java b/shop-api/src/main/java/com/yami/shop/api/controller/CategoryController.java new file mode 100644 index 0000000..939a315 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/CategoryController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.yami.shop.bean.app.dto.CategoryDto; +import com.yami.shop.bean.model.Category; +import com.yami.shop.service.CategoryService; + +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import cn.hutool.core.bean.BeanUtil; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/category") +@Tag(name = "分类接口") +public class CategoryController { + + @Autowired + private CategoryService categoryService; + + + /** + * 分类信息列表接口 + */ + @GetMapping("/categoryInfo") + @Operation(summary = "分类信息列表" , description = "获取所有的产品分类信息,顶级分类的parentId为0,默认为顶级分类") + @Parameter(name = "parentId", description = "分类ID", required = false) + public ServerResponseEntity> categoryInfo(@RequestParam(value = "parentId", defaultValue = "0") Long parentId) { + List categories = categoryService.listByParentId(parentId); + List categoryDtos = BeanUtil.copyToList(categories, CategoryDto.class); + return ServerResponseEntity.success(categoryDtos); + } + + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/DeliveryController.java b/shop-api/src/main/java/com/yami/shop/api/controller/DeliveryController.java new file mode 100644 index 0000000..64b9060 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/DeliveryController.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.yami.shop.service.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.yami.shop.bean.app.dto.DeliveryDto; +import com.yami.shop.bean.model.Delivery; +import com.yami.shop.bean.model.Order; +import com.yami.shop.common.util.Json; +import com.yami.shop.service.DeliveryService; + +import cn.hutool.http.HttpUtil; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/delivery") +@Tag(name = "查看物流接口") +public class DeliveryController { + + @Autowired + private DeliveryService deliveryService; + @Autowired + private OrderService orderService; + + /** + * 查看物流接口 + */ + @GetMapping("/check") + @Operation(summary = "查看物流" , description = "根据订单号查看物流") + @Parameter(name = "orderNumber", description = "订单号" , required = true) + public ServerResponseEntity checkDelivery(String orderNumber) { + + Order order = orderService.getOrderByOrderNumber(orderNumber); + Delivery delivery = deliveryService.getById(order.getDvyId()); + String url = delivery.getQueryUrl().replace("{dvyFlowId}", order.getDvyFlowId()); + String deliveryJson = HttpUtil.get(url); + + DeliveryDto deliveryDto = Json.parseObject(deliveryJson, DeliveryDto.class); + deliveryDto.setDvyFlowId(order.getDvyFlowId()); + deliveryDto.setCompanyHomeUrl(delivery.getCompanyHomeUrl()); + deliveryDto.setCompanyName(delivery.getDvyName()); + return ServerResponseEntity.success(deliveryDto); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/IndexImgController.java b/shop-api/src/main/java/com/yami/shop/api/controller/IndexImgController.java new file mode 100644 index 0000000..487a093 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/IndexImgController.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.yami.shop.bean.app.dto.IndexImgDto; +import com.yami.shop.bean.model.IndexImg; +import com.yami.shop.service.IndexImgService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import cn.hutool.core.bean.BeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@Tag(name = "首页轮播图接口") +public class IndexImgController { + + @Autowired + private IndexImgService indexImgService; + + /** + * 首页轮播图接口 + */ + @GetMapping("/indexImgs") + @Operation(summary = "首页轮播图" , description = "获取首页轮播图列表信息") + public ServerResponseEntity> indexImgs() { + List indexImgList = indexImgService.listIndexImg(); + List indexImgDtos = BeanUtil.copyToList(indexImgList, IndexImgDto.class); + return ServerResponseEntity.success(indexImgDtos); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/MyOrderController.java b/shop-api/src/main/java/com/yami/shop/api/controller/MyOrderController.java new file mode 100644 index 0000000..711bfc1 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/MyOrderController.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.bean.app.dto.*; +import com.yami.shop.bean.enums.OrderStatus; +import com.yami.shop.bean.model.Order; +import com.yami.shop.bean.model.OrderItem; +import com.yami.shop.bean.model.ShopDetail; +import com.yami.shop.bean.model.UserAddrOrder; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.response.ServerResponseEntity; +import com.yami.shop.common.util.Arith; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/myOrder") +@Tag(name = "我的订单接口") +@AllArgsConstructor +public class MyOrderController { + + private final OrderService orderService; + + + private final UserAddrOrderService userAddrOrderService; + + private final ProductService productService; + + private final SkuService skuService; + + private final MyOrderService myOrderService; + + private final ShopDetailService shopDetailService; + + private final OrderItemService orderItemService; + + + /** + * 订单详情信息接口 + */ + @GetMapping("/orderDetail") + @Operation(summary = "订单详情信息", description = "根据订单号获取订单详情信息") + @Parameter(name = "orderNumber", description = "订单号", required = true) + public ServerResponseEntity orderDetail(@RequestParam(value = "orderNumber") String orderNumber) { + + String userId = SecurityUtils.getUser().getUserId(); + OrderShopDto orderShopDto = new OrderShopDto(); + + Order order = orderService.getOrderByOrderNumber(orderNumber); + + if (order == null) { + throw new RuntimeException("该订单不存在"); + } + if (!Objects.equals(order.getUserId(), userId)) { + throw new RuntimeException("你没有权限获取该订单信息"); + } + + ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(order.getShopId()); + UserAddrOrder userAddrOrder = userAddrOrderService.getById(order.getAddrOrderId()); + UserAddrDto userAddrDto = BeanUtil.copyProperties(userAddrOrder, UserAddrDto.class); + List orderItems = orderItemService.getOrderItemsByOrderNumber(orderNumber); + List orderItemList = BeanUtil.copyToList(orderItems, OrderItemDto.class); + + orderShopDto.setShopId(shopDetail.getShopId()); + orderShopDto.setShopName(shopDetail.getShopName()); + orderShopDto.setActualTotal(order.getActualTotal()); + orderShopDto.setUserAddrDto(userAddrDto); + orderShopDto.setOrderItemDtos(orderItemList); + orderShopDto.setTransfee(order.getFreightAmount()); + orderShopDto.setReduceAmount(order.getReduceAmount()); + orderShopDto.setCreateTime(order.getCreateTime()); + orderShopDto.setRemarks(order.getRemarks()); + orderShopDto.setStatus(order.getStatus()); + + double total = 0.0; + Integer totalNum = 0; + for (OrderItemDto orderItem : orderShopDto.getOrderItemDtos()) { + total = Arith.add(total, orderItem.getProductTotalAmount()); + totalNum += orderItem.getProdCount(); + } + orderShopDto.setTotal(total); + orderShopDto.setTotalNum(totalNum); + + return ServerResponseEntity.success(orderShopDto); + } + + + /** + * 订单列表接口 + */ + @GetMapping("/myOrder") + @Operation(summary = "订单列表信息", description = "根据订单状态获取订单列表信息,状态为0时获取所有订单") + @Parameters({ + @Parameter(name = "status", description = "订单状态 1:待付款 2:待发货 3:待收货 4:待评价 5:成功 6:失败") + }) + public ServerResponseEntity> myOrder(@RequestParam(value = "status") Integer status, PageParam page) { + String userId = SecurityUtils.getUser().getUserId(); + IPage myOrderDtoIpage = myOrderService.pageMyOrderByUserIdAndStatus(page, userId, status); + return ServerResponseEntity.success(myOrderDtoIpage); + } + + /** + * 取消订单 + */ + @PutMapping("/cancel/{orderNumber}") + @Operation(summary = "根据订单号取消订单", description = "根据订单号取消订单") + @Parameter(name = "orderNumber", description = "订单号", required = true) + public ServerResponseEntity cancel(@PathVariable("orderNumber") String orderNumber) { + String userId = SecurityUtils.getUser().getUserId(); + Order order = orderService.getOrderByOrderNumber(orderNumber); + if (!Objects.equals(order.getUserId(), userId)) { + throw new YamiShopBindException("你没有权限获取该订单信息"); + } + if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value())) { + throw new YamiShopBindException("订单已支付,无法取消订单"); + } + List orderItems = orderItemService.getOrderItemsByOrderNumber(orderNumber); + order.setOrderItems(orderItems); + // 取消订单 + orderService.cancelOrders(Collections.singletonList(order)); + + // 清除缓存 + for (OrderItem orderItem : orderItems) { + productService.removeProductCacheByProdId(orderItem.getProdId()); + skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId()); + } + return ServerResponseEntity.success(); + } + + + /** + * 确认收货 + */ + @PutMapping("/receipt/{orderNumber}") + @Operation(summary = "根据订单号确认收货", description = "根据订单号确认收货") + public ServerResponseEntity receipt(@PathVariable("orderNumber") String orderNumber) { + String userId = SecurityUtils.getUser().getUserId(); + Order order = orderService.getOrderByOrderNumber(orderNumber); + if (!Objects.equals(order.getUserId(), userId)) { + throw new YamiShopBindException("你没有权限获取该订单信息"); + } + if (!Objects.equals(order.getStatus(), OrderStatus.CONSIGNMENT.value())) { + throw new YamiShopBindException("订单未发货,无法确认收货"); + } + List orderItems = orderItemService.getOrderItemsByOrderNumber(orderNumber); + order.setOrderItems(orderItems); + // 确认收货 + orderService.confirmOrder(Collections.singletonList(order)); + + for (OrderItem orderItem : orderItems) { + productService.removeProductCacheByProdId(orderItem.getProdId()); + skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId()); + } + return ServerResponseEntity.success(); + } + + /** + * 删除订单 + */ + @DeleteMapping("/{orderNumber}") + @Operation(summary = "根据订单号删除订单", description = "根据订单号删除订单") + @Parameter(name = "orderNumber", description = "订单号", required = true) + public ServerResponseEntity delete(@PathVariable("orderNumber") String orderNumber) { + String userId = SecurityUtils.getUser().getUserId(); + + Order order = orderService.getOrderByOrderNumber(orderNumber); + if (order == null) { + throw new YamiShopBindException("该订单不存在"); + } + if (!Objects.equals(order.getUserId(), userId)) { + throw new YamiShopBindException("你没有权限获取该订单信息"); + } + if (!Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value()) && !Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) { + throw new YamiShopBindException("订单未完成或未关闭,无法删除订单"); + } + + // 删除订单 + orderService.deleteOrders(Collections.singletonList(order)); + + return ServerResponseEntity.success("删除成功"); + } + + /** + * 获取我的订单订单数量 + */ + @GetMapping("/orderCount") + @Operation(summary = "获取我的订单订单数量", description = "获取我的订单订单数量") + public ServerResponseEntity getOrderCount() { + String userId = SecurityUtils.getUser().getUserId(); + OrderCountData orderCountMap = orderService.getOrderCount(userId); + return ServerResponseEntity.success(orderCountMap); + } + + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/NoticeController.java b/shop-api/src/main/java/com/yami/shop/api/controller/NoticeController.java new file mode 100644 index 0000000..918ee35 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/NoticeController.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.bean.app.dto.NoticeDto; +import com.yami.shop.bean.model.Notice; +import com.yami.shop.common.response.ServerResponseEntity; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.service.NoticeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/shop/notice") +@Tag(name = "公告管理接口") +@AllArgsConstructor +public class NoticeController { + + private NoticeService noticeService; + + + + /** + * 置顶公告列表接口 + */ + @GetMapping("/topNoticeList") + @Operation(summary = "置顶公告列表信息" , description = "获取所有置顶公告列表信息") + public ServerResponseEntity> getTopNoticeList() { + List noticeList = noticeService.listNotice(); + List noticeDtoList = BeanUtil.copyToList(noticeList, NoticeDto.class); + return ServerResponseEntity.success(noticeDtoList); + } + + /** + * 获取公告详情 + */ + @GetMapping("/info/{id}") + @Operation(summary = "公告详情" , description = "获取公告id公告详情") + public ServerResponseEntity getNoticeById(@PathVariable("id") Long id) { + Notice notice = noticeService.getNoticeById(id); + NoticeDto noticeDto = BeanUtil.copyProperties(notice, NoticeDto.class); + return ServerResponseEntity.success(noticeDto); + } + + /** + * 公告列表 + */ + @GetMapping("/noticeList") + @Operation(summary = "公告列表信息" , description = "获取所有公告列表信息") + @Parameters({ + }) + public ServerResponseEntity> pageNotice(PageParam page) { + + return ServerResponseEntity.success(noticeService.pageNotice(page)); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/OrderController.java b/shop-api/src/main/java/com/yami/shop/api/controller/OrderController.java new file mode 100644 index 0000000..bf20799 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/OrderController.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import cn.hutool.core.collection.CollectionUtil; +import com.yami.shop.bean.app.dto.*; +import com.yami.shop.bean.app.param.OrderParam; +import com.yami.shop.bean.app.param.OrderShopParam; +import com.yami.shop.bean.app.param.SubmitOrderParam; +import com.yami.shop.bean.event.ConfirmOrderEvent; +import com.yami.shop.bean.model.Order; +import com.yami.shop.bean.model.UserAddr; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.util.Arith; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.*; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.hutool.core.bean.BeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import jakarta.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/order") +@Tag(name = "订单接口") +public class OrderController { + + @Autowired + private OrderService orderService; + @Autowired + private SkuService skuService; + @Autowired + private ProductService productService; + @Autowired + private UserAddrService userAddrService; + @Autowired + private BasketService basketService; + @Autowired + private ApplicationContext applicationContext; + + + /** + * 生成订单 + */ + @PostMapping("/confirm") + @Operation(summary = "结算,生成订单信息" , description = "传入下单所需要的参数进行下单") + public ServerResponseEntity confirm(@Valid @RequestBody OrderParam orderParam) { + String userId = SecurityUtils.getUser().getUserId(); + + // 订单的地址信息 + UserAddr userAddr = userAddrService.getUserAddrByUserId(orderParam.getAddrId(), userId); + UserAddrDto userAddrDto = BeanUtil.copyProperties(userAddr, UserAddrDto.class); + + + // 组装获取用户提交的购物车商品项 + List shopCartItems = basketService.getShopCartItemsByOrderItems(orderParam.getBasketIds(),orderParam.getOrderItem(),userId); + + if (CollectionUtil.isEmpty(shopCartItems)) { + throw new YamiShopBindException("请选择您需要的商品加入购物车"); + } + + // 根据店铺组装购车中的商品信息,返回每个店铺中的购物车商品信息 + List shopCarts = basketService.getShopCarts(shopCartItems); + + // 将要返回给前端的完整的订单信息 + ShopCartOrderMergerDto shopCartOrderMergerDto = new ShopCartOrderMergerDto(); + + shopCartOrderMergerDto.setUserAddr(userAddrDto); + + // 所有店铺的订单信息 + List shopCartOrders = new ArrayList<>(); + + double actualTotal = 0.0; + double total = 0.0; + int totalCount = 0; + double orderReduce = 0.0; + for (ShopCartDto shopCart : shopCarts) { + + // 每个店铺的订单信息 + ShopCartOrderDto shopCartOrder = new ShopCartOrderDto(); + shopCartOrder.setShopId(shopCart.getShopId()); + shopCartOrder.setShopName(shopCart.getShopName()); + + + List shopCartItemDiscounts = shopCart.getShopCartItemDiscounts(); + + // 店铺中的所有商品项信息 + List shopAllShopCartItems = new ArrayList<>(); + for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) { + List discountShopCartItems = shopCartItemDiscount.getShopCartItems(); + shopAllShopCartItems.addAll(discountShopCartItems); + } + + shopCartOrder.setShopCartItemDiscounts(shopCartItemDiscounts); + + applicationContext.publishEvent(new ConfirmOrderEvent(shopCartOrder,orderParam,shopAllShopCartItems)); + + actualTotal = Arith.add(actualTotal,shopCartOrder.getActualTotal()); + total = Arith.add(total,shopCartOrder.getTotal()); + totalCount = totalCount + shopCartOrder.getTotalCount(); + orderReduce = Arith.add(orderReduce,shopCartOrder.getShopReduce()); + shopCartOrders.add(shopCartOrder); + + + } + + shopCartOrderMergerDto.setActualTotal(actualTotal); + shopCartOrderMergerDto.setTotal(total); + shopCartOrderMergerDto.setTotalCount(totalCount); + shopCartOrderMergerDto.setShopCartOrders(shopCartOrders); + shopCartOrderMergerDto.setOrderReduce(orderReduce); + + shopCartOrderMergerDto = orderService.putConfirmOrderCache(userId, shopCartOrderMergerDto); + + return ServerResponseEntity.success(shopCartOrderMergerDto); + } + + /** + * 购物车/立即购买 提交订单,根据店铺拆单 + */ + @PostMapping("/submit") + @Operation(summary = "提交订单,返回支付流水号" , description = "根据传入的参数判断是否为购物车提交订单,同时对购物车进行删除,用户开始进行支付") + public ServerResponseEntity submitOrders(@Valid @RequestBody SubmitOrderParam submitOrderParam) { + String userId = SecurityUtils.getUser().getUserId(); + ShopCartOrderMergerDto mergerOrder = orderService.getConfirmOrderCache(userId); + if (mergerOrder == null) { + throw new YamiShopBindException("订单已过期,请重新下单"); + } + + List orderShopParams = submitOrderParam.getOrderShopParam(); + + List shopCartOrders = mergerOrder.getShopCartOrders(); + // 设置备注 + if (CollectionUtil.isNotEmpty(orderShopParams)) { + for (ShopCartOrderDto shopCartOrder : shopCartOrders) { + for (OrderShopParam orderShopParam : orderShopParams) { + if (Objects.equals(shopCartOrder.getShopId(), orderShopParam.getShopId())) { + shopCartOrder.setRemarks(orderShopParam.getRemarks()); + } + } + } + } + + List orders = orderService.submit(userId,mergerOrder); + + + + StringBuilder orderNumbers = new StringBuilder(); + for (Order order : orders) { + orderNumbers.append(order.getOrderNumber()).append(","); + } + orderNumbers.deleteCharAt(orderNumbers.length() - 1); + + boolean isShopCartOrder = false; + // 移除缓存 + for (ShopCartOrderDto shopCartOrder : shopCartOrders) { + for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartOrder.getShopCartItemDiscounts()) { + for (ShopCartItemDto shopCartItem : shopCartItemDiscount.getShopCartItems()) { + Long basketId = shopCartItem.getBasketId(); + if (basketId != null && basketId != 0) { + isShopCartOrder = true; + } + skuService.removeSkuCacheBySkuId(shopCartItem.getSkuId(),shopCartItem.getProdId()); + productService.removeProductCacheByProdId(shopCartItem.getProdId()); + } + } + } + // 购物车提交订单时(即有购物车ID时) + if (isShopCartOrder) { + basketService.removeShopCartItemsCacheByUserId(userId); + } + orderService.removeConfirmOrderCache(userId); + return ServerResponseEntity.success(new OrderNumbersDto(orderNumbers.toString())); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/PayController.java b/shop-api/src/main/java/com/yami/shop/api/controller/PayController.java new file mode 100644 index 0000000..fd12a1f --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/PayController.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.yami.shop.bean.app.param.PayParam; +import com.yami.shop.bean.pay.PayInfoDto; +import com.yami.shop.security.api.model.YamiUser; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.PayService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/order") +@Tag(name = "订单接口") +@AllArgsConstructor +public class PayController { + + private final PayService payService; + + /** + * 支付接口 + */ + @PostMapping("/pay") + @Operation(summary = "根据订单号进行支付" , description = "根据订单号进行支付") + public ServerResponseEntity pay(@RequestBody PayParam payParam) { + YamiUser user = SecurityUtils.getUser(); + String userId = user.getUserId(); + + + PayInfoDto payInfo = payService.pay(userId, payParam); + payService.paySuccess(payInfo.getPayNo(), ""); + return ServerResponseEntity.success(); + } + + /** + * 普通支付接口 + */ + @PostMapping("/normalPay") + @Operation(summary = "根据订单号进行支付" , description = "根据订单号进行支付") + public ServerResponseEntity normalPay(@RequestBody PayParam payParam) { + + YamiUser user = SecurityUtils.getUser(); + String userId = user.getUserId(); + PayInfoDto pay = payService.pay(userId, payParam); + + // 根据内部订单号更新order settlement + payService.paySuccess(pay.getPayNo(), ""); + + return ServerResponseEntity.success(true); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/PayNoticeController.java b/shop-api/src/main/java/com/yami/shop/api/controller/PayNoticeController.java new file mode 100644 index 0000000..4cfe7c8 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/PayNoticeController.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import lombok.AllArgsConstructor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.Hidden; + +/** + * @author lanhai + */ +@Hidden +@RestController +@RequestMapping("/notice/pay") +@AllArgsConstructor +public class PayNoticeController { +//模拟支付不需要回调 +// /** +// * 小程序支付 +// */ +// private final WxPayService wxMiniPayService; +// +// private final PayService payService; +// +// +// @RequestMapping("/order") +// public ServerResponseEntity submit(@RequestBody String xmlData) throws WxPayException { +// WxPayOrderNotifyResult parseOrderNotifyResult = wxMiniPayService.parseOrderNotifyResult(xmlData); +// +// String payNo = parseOrderNotifyResult.getOutTradeNo(); +// String bizPayNo = parseOrderNotifyResult.getTransactionId(); +// +// // 根据内部订单号更新order settlement +// payService.paySuccess(payNo, bizPayNo); +// +// +// return ServerResponseEntity.success(); +// } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/ProdCommController.java b/shop-api/src/main/java/com/yami/shop/api/controller/ProdCommController.java new file mode 100644 index 0000000..bcd9b44 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/ProdCommController.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.bean.app.dto.ProdCommDataDto; +import com.yami.shop.bean.app.dto.ProdCommDto; +import com.yami.shop.bean.app.param.ProdCommParam; +import com.yami.shop.bean.model.ProdComm; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.ProdCommService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/prodComm") +@Tag(name = "评论接口") +@AllArgsConstructor +public class ProdCommController { + + private final ProdCommService prodCommService; + + + @GetMapping("/prodCommData") + @Operation(summary = "返回商品评论数据(好评率 好评数量 中评数 差评数)" , description = "根据商品id获取") + public ServerResponseEntity getProdCommData(Long prodId) { + return ServerResponseEntity.success(prodCommService.getProdCommDataByProdId(prodId)); + } + + @GetMapping("/prodCommPageByUser") + @Operation(summary = "根据用户返回评论分页数据" , description = "传入页码") + public ServerResponseEntity> getProdCommPage(PageParam page) { + return ServerResponseEntity.success(prodCommService.getProdCommDtoPageByUserId(page, SecurityUtils.getUser().getUserId())); + } + + @GetMapping("/prodCommPageByProd") + @Operation(summary = "根据商品返回评论分页数据" , description = "传入商品id和页码") + @Parameters({ + @Parameter(name = "prodId", description = "商品id" , required = true), + @Parameter(name = "evaluate", description = "-1或null 全部,0好评 1中评 2差评 3有图" , required = true), + }) + public ServerResponseEntity> getProdCommPageByProdId(PageParam page, Long prodId, Integer evaluate) { + return ServerResponseEntity.success(prodCommService.getProdCommDtoPageByProdId(page, prodId, evaluate)); + } + + @PostMapping + @Operation(summary = "添加评论") + public ServerResponseEntity saveProdCommPage(ProdCommParam prodCommParam) { + ProdComm prodComm = new ProdComm(); + prodComm.setProdId(prodCommParam.getProdId()); + prodComm.setOrderItemId(prodCommParam.getOrderItemId()); + prodComm.setUserId(SecurityUtils.getUser().getUserId()); + prodComm.setScore(prodCommParam.getScore()); + prodComm.setContent(prodCommParam.getContent()); + prodComm.setPics(prodCommParam.getPics()); + prodComm.setIsAnonymous(prodCommParam.getIsAnonymous()); + prodComm.setRecTime(new Date()); + prodComm.setStatus(0); + prodComm.setEvaluate(prodCommParam.getEvaluate()); + prodCommService.save(prodComm); + return ServerResponseEntity.success(); + } + + @DeleteMapping + @Operation(summary = "删除评论" , description = "根据id删除") + public ServerResponseEntity deleteProdComm(Long prodCommId) { + prodCommService.removeById(prodCommId); + return ServerResponseEntity.success(); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java b/shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java new file mode 100644 index 0000000..6c61fc0 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/ProdController.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.bean.app.dto.ProductDto; +import com.yami.shop.bean.app.dto.TagProductDto; +import com.yami.shop.bean.model.Product; +import com.yami.shop.bean.model.Sku; +import com.yami.shop.bean.model.Transport; +import com.yami.shop.common.response.ServerResponseEntity; +import com.yami.shop.common.util.Json; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.service.ProductService; +import com.yami.shop.service.SkuService; +import com.yami.shop.service.TransportService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.tags.Tag; +import cn.hutool.core.bean.BeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author lgh on 2018/11/26. + */ +@RestController +@RequestMapping("/prod") +@Tag(name = "商品接口") +public class ProdController { + + @Autowired + private ProductService prodService; + + + @Autowired + private SkuService skuService; + + @Autowired + private TransportService transportService; + + + @GetMapping("/pageProd") + @Operation(summary = "通过分类id商品列表信息" , description = "根据分类ID获取该分类下所有的商品列表信息") + @Parameters({ + @Parameter(name = "categoryId", description = "分类ID" , required = true), + }) + public ServerResponseEntity> prodList( + @RequestParam(value = "categoryId") Long categoryId,PageParam page) { + IPage productPage = prodService.pageByCategoryId(page, categoryId); + return ServerResponseEntity.success(productPage); + } + + @GetMapping("/prodInfo") + @Operation(summary = "商品详情信息" , description = "根据商品ID(prodId)获取商品信息") + @Parameter(name = "prodId", description = "商品ID" , required = true) + public ServerResponseEntity prodInfo(Long prodId) { + + Product product = prodService.getProductByProdId(prodId); + if (product == null) { + return ServerResponseEntity.success(); + } + + List skuList = skuService.listByProdId(prodId); + // 启用的sku列表 + List useSkuList = skuList.stream().filter(sku -> sku.getStatus() == 1).collect(Collectors.toList()); + product.setSkuList(useSkuList); + ProductDto productDto = BeanUtil.copyProperties(product, ProductDto.class); + + + // 商品的配送方式 + Product.DeliveryModeVO deliveryModeVO = Json.parseObject(product.getDeliveryMode(), Product.DeliveryModeVO.class); + // 有店铺配送的方式, 且存在运费模板,才返回运费模板的信息,供前端查阅 + if (deliveryModeVO.getHasShopDelivery() && product.getDeliveryTemplateId() != null) { + Transport transportAndAllItems = transportService.getTransportAndAllItems(product.getDeliveryTemplateId()); + productDto.setTransport(transportAndAllItems); + } + + return ServerResponseEntity.success(productDto); + } + + @GetMapping("/lastedProdPage") + @Operation(summary = "新品推荐" , description = "获取新品推荐商品列表") + @Parameters({ + }) + public ServerResponseEntity> lastedProdPage(PageParam page) { + IPage productPage = prodService.pageByPutAwayTime(page); + return ServerResponseEntity.success(productPage); + } + + @GetMapping("/prodListByTagId") + @Operation(summary = "通过分组标签获取商品列表" , description = "通过分组标签id(tagId)获取商品列表") + @Parameters({ + @Parameter(name = "tagId", description = "当前页,默认为1" , required = true), + }) + public ServerResponseEntity> prodListByTagId( + @RequestParam(value = "tagId") Long tagId,PageParam page) { + IPage productPage = prodService.pageByTagId(page, tagId); + return ServerResponseEntity.success(productPage); + } + + @GetMapping("/moreBuyProdList") + @Operation(summary = "每日疯抢" , description = "获取销量最多的商品列表") + @Parameters({}) + public ServerResponseEntity> moreBuyProdList(PageParam page) { + IPage productPage = prodService.moreBuyProdList(page); + return ServerResponseEntity.success(productPage); + } + + @GetMapping("/tagProdList") + @Operation(summary = "首页所有标签商品接口" , description = "获取首页所有标签商品接口") + public ServerResponseEntity> getTagProdList() { + List productDtoList = prodService.tagProdList(); + return ServerResponseEntity.success(productDtoList); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/ProdTagController.java b/shop-api/src/main/java/com/yami/shop/api/controller/ProdTagController.java new file mode 100644 index 0000000..d1a1e65 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/ProdTagController.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.yami.shop.bean.app.dto.ProdTagDto; +import com.yami.shop.bean.model.ProdTag; +import com.yami.shop.service.ProdTagService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import cn.hutool.core.bean.BeanUtil; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/prod/tag") +@Tag(name = "商品分组标签接口") +@AllArgsConstructor +public class ProdTagController { + + private ProdTagService prodTagService; + + + + /** + * 商品分组标签列表接口 + */ + @GetMapping("/prodTagList") + @Operation(summary = "商品分组标签列表" , description = "获取所有的商品分组列表") + public ServerResponseEntity> getProdTagList() { + List prodTagList = prodTagService.listProdTag(); + List prodTagDtoList = BeanUtil.copyToList(prodTagList, ProdTagDto.class); + return ServerResponseEntity.success(prodTagDtoList); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/SearchController.java b/shop-api/src/main/java/com/yami/shop/api/controller/SearchController.java new file mode 100644 index 0000000..900bf31 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/SearchController.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.bean.dto.HotSearchDto; +import com.yami.shop.bean.dto.SearchProdDto; +import com.yami.shop.service.HotSearchService; +import com.yami.shop.service.ProductService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/search") +@Tag(name = "搜索接口") +@AllArgsConstructor +public class SearchController { + + private final HotSearchService hotSearchService; + + private final ProductService productService; + + @GetMapping("/hotSearchByShopId") + @Operation(summary = "查看店铺热搜" , description = "根据店铺id,热搜数量获取热搜") + @Parameters({ + @Parameter(name = "shopId", description = "店铺id" , required = true), + @Parameter(name = "number", description = "取数" , required = true), + @Parameter(name = "sort", description = "是否按照顺序(0 否 1是)"), + }) + public ServerResponseEntity> hotSearchByShopId(Long shopId,Integer number,Integer sort) { + List list = hotSearchService.getHotSearchDtoByShopId(shopId); + + return getListResponseEntity(number, sort, list); + } + + @GetMapping("/hotSearch") + @Operation(summary = "查看全局热搜" , description = "根据店铺id,热搜数量获取热搜") + @Parameters({ + @Parameter(name = "number", description = "取数" , required = true), + @Parameter(name = "sort", description = "是否按照顺序(0 否 1是)", required = false ), + }) + public ServerResponseEntity> hotSearch(Integer number,Integer sort) { + List list = hotSearchService.getHotSearchDtoByShopId(0L); + return getListResponseEntity(number, sort, list); + } + + private ServerResponseEntity> getListResponseEntity(Integer number, Integer sort, List list) { + if(sort == null || sort == 0){ + Collections.shuffle(list); + } + if(!CollectionUtil.isNotEmpty(list) || list.size()< number){ + return ServerResponseEntity.success(list); + } + return ServerResponseEntity.success(list.subList(0, number)); + } + + @GetMapping("/searchProdPage") + @Operation(summary = "分页排序搜索商品" , description = "根据商品名搜索") + @Parameters({ + @Parameter(name = "prodName", description = "商品名" , required = true), + @Parameter(name = "sort", description = "排序(0 默认排序 1销量排序 2价格排序)"), + @Parameter(name = "orderBy", description = "排序(0升序 1降序)"), + @Parameter(name = "shopId", description = "店铺id" , required = true), + }) + public ServerResponseEntity> searchProdPage(PageParam page, String prodName, Integer sort, Integer orderBy, Long shopId) { + + return ServerResponseEntity.success(productService.getSearchProdDtoPageByProdName(page,prodName,sort,orderBy)); + } + + + + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/ShopCartController.java b/shop-api/src/main/java/com/yami/shop/api/controller/ShopCartController.java new file mode 100644 index 0000000..f77c367 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/ShopCartController.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import com.google.common.collect.Lists; +import com.yami.shop.bean.app.dto.*; +import com.yami.shop.bean.app.param.ChangeShopCartParam; +import com.yami.shop.bean.app.param.ShopCartParam; +import com.yami.shop.bean.event.ShopCartEvent; +import com.yami.shop.bean.model.Basket; +import com.yami.shop.bean.model.Product; +import com.yami.shop.bean.model.Sku; +import com.yami.shop.common.util.Arith; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.BasketService; +import com.yami.shop.service.ProductService; +import com.yami.shop.service.SkuService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import org.springframework.context.ApplicationContext; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/shopCart") +@Tag(name = "购物车接口") +@AllArgsConstructor +public class ShopCartController { + + private final BasketService basketService; + + private final ProductService productService; + + private final SkuService skuService; + + private final ApplicationContext applicationContext; + + /** + * 获取用户购物车信息 + * + * @param basketIdShopCartParamMap 购物车参数对象列表 + * @return + */ + @PostMapping("/info") + @Operation(summary = "获取用户购物车信息" , description = "获取用户购物车信息,参数为用户选中的活动项数组,以购物车id为key") + public ServerResponseEntity> info(@RequestBody Map basketIdShopCartParamMap) { + String userId = SecurityUtils.getUser().getUserId(); + + // 更新购物车信息, + if (MapUtil.isNotEmpty(basketIdShopCartParamMap)) { + basketService.updateBasketByShopCartParam(userId, basketIdShopCartParamMap); + } + + // 拿到购物车的所有item + List shopCartItems = basketService.getShopCartItems(userId); + return ServerResponseEntity.success(basketService.getShopCarts(shopCartItems)); + + } + + @DeleteMapping("/deleteItem") + @Operation(summary = "删除用户购物车物品" , description = "通过购物车id删除用户购物车物品") + public ServerResponseEntity deleteItem(@RequestBody List basketIds) { + String userId = SecurityUtils.getUser().getUserId(); + basketService.deleteShopCartItemsByBasketIds(userId, basketIds); + return ServerResponseEntity.success(); + } + + @DeleteMapping("/deleteAll") + @Operation(summary = "清空用户购物车所有物品" , description = "清空用户购物车所有物品") + public ServerResponseEntity deleteAll() { + String userId = SecurityUtils.getUser().getUserId(); + basketService.deleteAllShopCartItems(userId); + return ServerResponseEntity.success("删除成功"); + } + + @PostMapping("/changeItem") + @Operation(summary = "添加、修改用户购物车物品", description = "通过商品id(prodId)、skuId、店铺Id(shopId),添加/修改用户购物车商品,并传入改变的商品个数(count)," + + "当count为正值时,增加商品数量,当count为负值时,将减去商品的数量,当最终count值小于0时,会将商品从购物车里面删除") + public ServerResponseEntity addItem(@Valid @RequestBody ChangeShopCartParam param) { + + if (param.getCount() == 0) { + return ServerResponseEntity.showFailMsg("输入更改数量"); + } + + String userId = SecurityUtils.getUser().getUserId(); + List shopCartItems = basketService.getShopCartItems(userId); + Product prodParam = productService.getProductByProdId(param.getProdId()); + Sku skuParam = skuService.getSkuBySkuId(param.getSkuId()); + + // 当商品状态不正常时,不能添加到购物车 + if (prodParam.getStatus() != 1 || skuParam.getStatus() != 1) { + return ServerResponseEntity.showFailMsg("当前商品已下架"); + } + for (ShopCartItemDto shopCartItemDto : shopCartItems) { + if (Objects.equals(param.getSkuId(), shopCartItemDto.getSkuId())) { + Basket basket = new Basket(); + basket.setUserId(userId); + basket.setBasketCount(param.getCount() + shopCartItemDto.getProdCount()); + basket.setBasketId(shopCartItemDto.getBasketId()); + + // 防止购物车变成负数 + if (basket.getBasketCount() <= 0) { + basketService.deleteShopCartItemsByBasketIds(userId, Collections.singletonList(basket.getBasketId())); + return ServerResponseEntity.success(); + } + + // 当sku实际库存不足时,不能添加到购物车 + if (skuParam.getStocks() < basket.getBasketCount() && shopCartItemDto.getProdCount() > 0) { + return ServerResponseEntity.showFailMsg("库存不足"); + } + basketService.updateShopCartItem(basket); + return ServerResponseEntity.success(); + } + } + + // 防止购物车已被删除的情况下,添加了负数的商品 + if (param.getCount() < 0) { + return ServerResponseEntity.showFailMsg("商品已从购物车移除"); + } + // 当sku实际库存不足时,不能添加到购物车 + if (skuParam.getStocks() < param.getCount()) { + return ServerResponseEntity.showFailMsg("库存不足"); + } + // 所有都正常时 + basketService.addShopCartItem(param,userId); + return ServerResponseEntity.success("添加成功"); + } + + @GetMapping("/prodCount") + @Operation(summary = "获取购物车商品数量" , description = "获取所有购物车商品数量") + public ServerResponseEntity prodCount() { + String userId = SecurityUtils.getUser().getUserId(); + List shopCartItems = basketService.getShopCartItems(userId); + if (CollectionUtil.isEmpty(shopCartItems)) { + return ServerResponseEntity.success(0); + } + Integer totalCount = shopCartItems.stream().map(ShopCartItemDto::getProdCount).reduce(0, Integer::sum); + return ServerResponseEntity.success(totalCount); + } + + @GetMapping("/expiryProdList") + @Operation(summary = "获取购物车失效商品信息" , description = "获取购物车失效商品列表") + public ServerResponseEntity> expiryProdList() { + String userId = SecurityUtils.getUser().getUserId(); + List shopCartItems = basketService.getShopCartExpiryItems(userId); + //根据店铺ID划分item + Map> shopCartItemDtoMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDto::getShopId)); + + // 返回一个店铺对应的所有信息 + List shopcartExpiryitems = Lists.newArrayList(); + + for (Long key : shopCartItemDtoMap.keySet()) { + ShopCartExpiryItemDto shopCartExpiryItemDto = new ShopCartExpiryItemDto(); + shopCartExpiryItemDto.setShopId(key); + List shopCartItemDtos = Lists.newArrayList(); + for (ShopCartItemDto tempShopCartItemDto : shopCartItemDtoMap.get(key)) { + shopCartExpiryItemDto.setShopName(tempShopCartItemDto.getShopName()); + shopCartItemDtos.add(tempShopCartItemDto); + } + shopCartExpiryItemDto.setShopCartItemDtoList(shopCartItemDtos); + shopcartExpiryitems.add(shopCartExpiryItemDto); + } + + return ServerResponseEntity.success(shopcartExpiryitems); + } + + @DeleteMapping("/cleanExpiryProdList") + @Operation(summary = "清空用户失效商品" , description = "清空用户失效商品") + public ServerResponseEntity cleanExpiryProdList() { + String userId = SecurityUtils.getUser().getUserId(); + basketService.cleanExpiryProdList(userId); + return ServerResponseEntity.success(); + } + + @PostMapping("/totalPay") + @Operation(summary = "获取选中购物项总计、选中的商品数量" , description = "获取选中购物项总计、选中的商品数量,参数为购物车id数组") + public ServerResponseEntity getTotalPay(@RequestBody List basketIds) { + + // 拿到购物车的所有item + List dbShopCartItems = basketService.getShopCartItems(SecurityUtils.getUser().getUserId()); + + List chooseShopCartItems = dbShopCartItems + .stream() + .filter(shopCartItemDto -> { + for (Long basketId : basketIds) { + if (Objects.equals(basketId,shopCartItemDto.getBasketId())) { + return true; + } + } + return false; + }) + .toList(); + + // 根据店铺ID划分item + Map> shopCartMap = chooseShopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDto::getShopId)); + + double total = 0.0; + int count = 0; + double reduce = 0.0; + for (Long shopId : shopCartMap.keySet()) { + //获取店铺的所有商品项 + List shopCartItemDtoList = shopCartMap.get(shopId); + // 构建每个店铺的购物车信息 + ShopCartDto shopCart = new ShopCartDto(); + shopCart.setShopId(shopId); + + applicationContext.publishEvent(new ShopCartEvent(shopCart, shopCartItemDtoList)); + + List shopCartItemDiscounts = shopCart.getShopCartItemDiscounts(); + + for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) { + List shopCartItems = shopCartItemDiscount.getShopCartItems(); + + for (ShopCartItemDto shopCartItem : shopCartItems) { + count = shopCartItem.getProdCount() + count; + total = Arith.add(shopCartItem.getProductTotalAmount(), total); + } + } + } + ShopCartAmountDto shopCartAmountDto = new ShopCartAmountDto(); + shopCartAmountDto.setCount(count); + shopCartAmountDto.setTotalMoney(total); + shopCartAmountDto.setSubtractMoney(reduce); + shopCartAmountDto.setFinalMoney(Arith.sub(shopCartAmountDto.getTotalMoney(), shopCartAmountDto.getSubtractMoney())); + + return ServerResponseEntity.success(shopCartAmountDto); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/SkuController.java b/shop-api/src/main/java/com/yami/shop/api/controller/SkuController.java new file mode 100644 index 0000000..217c29e --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/SkuController.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yami.shop.bean.app.dto.SkuDto; +import com.yami.shop.bean.model.Sku; +import com.yami.shop.service.SkuService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import cn.hutool.core.bean.BeanUtil; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/sku") +@Tag(name = "sku规格接口") +@AllArgsConstructor +public class SkuController { + + private final SkuService skuService; + + + + @GetMapping("/getSkuList") + @Operation(summary = "通过prodId获取商品全部规格列表" , description = "通过prodId获取商品全部规格列表") + @Parameter(name = "prodId", description = "商品id" ) + public ServerResponseEntity> getSkuListByProdId(Long prodId) { + List skus = skuService.list(new LambdaQueryWrapper() + .eq(Sku::getStatus, 1) + .eq(Sku::getIsDelete, 0) + .eq(Sku::getProdId, prodId) + ); + List skuDtoList = BeanUtil.copyToList(skus, SkuDto.class); + return ServerResponseEntity.success(skuDtoList); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/SmsController.java b/shop-api/src/main/java/com/yami/shop/api/controller/SmsController.java new file mode 100644 index 0000000..9c04760 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/SmsController.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.google.common.collect.Maps; +import com.yami.shop.bean.app.param.SendSmsParam; +import com.yami.shop.bean.enums.SmsType; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.SmsLogService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import org.springframework.beans.factory.annotation.Autowired; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/sms") +@Tag(name = "发送验证码接口") +public class SmsController { + + @Autowired + private SmsLogService smsLogService; + /** + * 发送验证码接口 + */ + @PostMapping("/send") + @Operation(summary = "发送验证码" , description = "用户的发送验证码") + public ServerResponseEntity audit(@RequestBody SendSmsParam sendSmsParam) { + String userId = SecurityUtils.getUser().getUserId(); + smsLogService.sendSms(SmsType.VALID, userId, sendSmsParam.getMobile(),Maps.newHashMap()); + + return ServerResponseEntity.success(); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/UserCollectionController.java b/shop-api/src/main/java/com/yami/shop/api/controller/UserCollectionController.java new file mode 100644 index 0000000..9022d2d --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/UserCollectionController.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yami.shop.bean.app.dto.ProductDto; +import com.yami.shop.bean.app.dto.UserCollectionDto; +import com.yami.shop.bean.model.Product; +import com.yami.shop.bean.model.UserCollection; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.util.PageParam; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.ProductService; +import com.yami.shop.service.UserCollectionService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.Objects; +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/user/collection") +@Tag(name = "收藏接口") +@AllArgsConstructor +public class UserCollectionController { + + private final UserCollectionService userCollectionService; + + private final ProductService productService; + + @GetMapping("/page") + @Operation(summary = "分页返回收藏数据" , description = "根据用户id获取") + public ServerResponseEntity> getUserCollectionDtoPageByUserId(PageParam page) { + return ServerResponseEntity.success(userCollectionService.getUserCollectionDtoPageByUserId(page, SecurityUtils.getUser().getUserId())); + } + + @GetMapping("isCollection") + @Operation(summary = "根据商品id获取该商品是否在收藏夹中" , description = "传入收藏商品id") + public ServerResponseEntity isCollection(Long prodId) { + if (productService.count(new LambdaQueryWrapper() + .eq(Product::getProdId, prodId)) < 1) { + throw new YamiShopBindException("该商品不存在"); + } + return ServerResponseEntity.success(userCollectionService.count(new LambdaQueryWrapper() + .eq(UserCollection::getProdId, prodId) + .eq(UserCollection::getUserId, SecurityUtils.getUser().getUserId())) > 0); + } + + @PostMapping("/addOrCancel") + @Operation(summary = "添加/取消收藏" , description = "传入收藏商品id,如果商品未收藏则收藏商品,已收藏则取消收藏") + @Parameter(name = "prodId", description = "商品id" , required = true) + public ServerResponseEntity addOrCancel(@RequestBody Long prodId) { + if (Objects.isNull(productService.getProductByProdId(prodId))) { + throw new YamiShopBindException("该商品不存在"); + } + String userId = SecurityUtils.getUser().getUserId(); + if (userCollectionService.count(new LambdaQueryWrapper() + .eq(UserCollection::getProdId, prodId) + .eq(UserCollection::getUserId, userId)) > 0) { + userCollectionService.remove(new LambdaQueryWrapper() + .eq(UserCollection::getProdId, prodId) + .eq(UserCollection::getUserId, userId)); + } else { + UserCollection userCollection = new UserCollection(); + userCollection.setCreateTime(new Date()); + userCollection.setUserId(userId); + userCollection.setProdId(prodId); + userCollectionService.save(userCollection); + } + return ServerResponseEntity.success(); + } + + /** + * 查询用户收藏商品数量 + */ + @GetMapping("count") + @Operation(summary = "查询用户收藏商品数量" , description = "查询用户收藏商品数量") + public ServerResponseEntity findUserCollectionCount() { + String userId = SecurityUtils.getUser().getUserId(); + return ServerResponseEntity.success(userCollectionService.count(new LambdaQueryWrapper().eq(UserCollection::getUserId, userId))); + } + + @GetMapping("/prods") + @Operation(summary = "获取用户收藏商品列表" , description = "获取用户收藏商品列表") + public ServerResponseEntity> collectionProds(PageParam page) { + String userId = SecurityUtils.getUser().getUserId(); + IPage productDtoPage = productService.collectionProds(page, userId); + return ServerResponseEntity.success(productDtoPage); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/UserController.java b/shop-api/src/main/java/com/yami/shop/api/controller/UserController.java new file mode 100644 index 0000000..1d8843f --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/UserController.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.controller; + +import com.yami.shop.bean.app.dto.UserDto; +import com.yami.shop.bean.app.param.UserInfoParam; +import com.yami.shop.bean.model.User; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import cn.hutool.core.bean.BeanUtil; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.web.bind.annotation.*; +/** + * @author lanhai + */ +@RestController +@RequestMapping("/p/user") +@Tag(name = "用户接口") +@AllArgsConstructor +public class UserController { + + private final UserService userService; + + + /** + * 查看用户接口 + */ + @GetMapping("/userInfo") + @Operation(summary = "查看用户信息" , description = "根据用户ID(userId)获取用户信息") + public ServerResponseEntity userInfo() { + String userId = SecurityUtils.getUser().getUserId(); + User user = userService.getById(userId); + UserDto userDto = BeanUtil.copyProperties(user, UserDto.class); + return ServerResponseEntity.success(userDto); + } + + @PutMapping("/setUserInfo") + @Operation(summary = "设置用户信息" , description = "设置用户信息") + public ServerResponseEntity setUserInfo(@RequestBody UserInfoParam userInfoParam) { + String userId = SecurityUtils.getUser().getUserId(); + User user = new User(); + user.setUserId(userId); + user.setPic(userInfoParam.getAvatarUrl()); + user.setNickName(userInfoParam.getNickName()); + userService.updateById(user); + return ServerResponseEntity.success(); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/controller/UserRegisterController.java b/shop-api/src/main/java/com/yami/shop/api/controller/UserRegisterController.java new file mode 100644 index 0000000..0241868 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/controller/UserRegisterController.java @@ -0,0 +1,101 @@ +package com.yami.shop.api.controller; + + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yami.shop.bean.model.User; +import com.yami.shop.bean.param.UserRegisterParam; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.security.common.bo.UserInfoInTokenBO; +import com.yami.shop.security.common.enums.SysTypeEnum; +import com.yami.shop.security.common.manager.PasswordManager; +import com.yami.shop.security.common.manager.TokenStore; +import com.yami.shop.security.common.vo.TokenInfoVO; +import com.yami.shop.service.UserService; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import lombok.AllArgsConstructor; +import com.yami.shop.common.response.ServerResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; + +import jakarta.validation.Valid; +import java.util.Date; + +/** + * 用户信息 + * + * @author SJL + */ +@RestController +@RequestMapping("/user") +@Tag(name = "用户注册相关接口") +@AllArgsConstructor +public class UserRegisterController { + + private final UserService userService; + + private final PasswordEncoder passwordEncoder; + + private final TokenStore tokenStore; + + private final PasswordManager passwordManager; + + @PostMapping("/register") + @Operation(summary = "注册" , description = "用户注册或绑定手机号接口") + public ServerResponseEntity register(@Valid @RequestBody UserRegisterParam userRegisterParam) { + if (StrUtil.isBlank(userRegisterParam.getNickName())) { + userRegisterParam.setNickName(userRegisterParam.getUserName()); + } + // 正在进行申请注册 + if (userService.count(new LambdaQueryWrapper().eq(User::getNickName, userRegisterParam.getNickName())) > 0) { + // 该用户名已注册,无法重新注册 + throw new YamiShopBindException("该用户名已注册,无法重新注册"); + } + Date now = new Date(); + User user = new User(); + user.setModifyTime(now); + user.setUserRegtime(now); + user.setStatus(1); + user.setNickName(userRegisterParam.getNickName()); + user.setUserMail(userRegisterParam.getUserMail()); + String decryptPassword = passwordManager.decryptPassword(userRegisterParam.getPassWord()); + user.setLoginPassword(passwordEncoder.encode(decryptPassword)); + String userId = IdUtil.simpleUUID(); + user.setUserId(userId); + userService.save(user); + // 2. 登录 + UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO(); + userInfoInTokenBO.setUserId(user.getUserId()); + userInfoInTokenBO.setSysType(SysTypeEnum.ORDINARY.value()); + userInfoInTokenBO.setIsAdmin(0); + userInfoInTokenBO.setEnabled(true); + return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO)); + } + + + @PutMapping("/updatePwd") + @Operation(summary = "修改密码" , description = "修改密码") + public ServerResponseEntity updatePwd(@Valid @RequestBody UserRegisterParam userPwdUpdateParam) { + User user = userService.getOne(new LambdaQueryWrapper().eq(User::getNickName, userPwdUpdateParam.getNickName())); + if (user == null) { + // 无法获取用户信息 + throw new YamiShopBindException("无法获取用户信息"); + } + String decryptPassword = passwordManager.decryptPassword(userPwdUpdateParam.getPassWord()); + if (StrUtil.isBlank(decryptPassword)) { + // 新密码不能为空 + throw new YamiShopBindException("新密码不能为空"); + } + String password = passwordEncoder.encode(decryptPassword); + if (StrUtil.equals(password, user.getLoginPassword())) { + // 新密码不能与原密码相同 + throw new YamiShopBindException("新密码不能与原密码相同"); + } + user.setModifyTime(new Date()); + user.setLoginPassword(password); + userService.updateById(user); + return ServerResponseEntity.success(); + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/listener/ConfirmOrderListener.java b/shop-api/src/main/java/com/yami/shop/api/listener/ConfirmOrderListener.java new file mode 100644 index 0000000..c7f11c7 --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/listener/ConfirmOrderListener.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.listener; + +import com.yami.shop.bean.app.dto.ShopCartItemDto; +import com.yami.shop.bean.app.dto.ShopCartOrderDto; +import com.yami.shop.bean.app.param.OrderParam; +import com.yami.shop.bean.event.ConfirmOrderEvent; +import com.yami.shop.bean.model.Product; +import com.yami.shop.bean.model.Sku; +import com.yami.shop.bean.model.UserAddr; +import com.yami.shop.bean.order.ConfirmOrderOrder; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.util.Arith; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.ProductService; +import com.yami.shop.service.SkuService; +import com.yami.shop.service.TransportManagerService; +import com.yami.shop.service.UserAddrService; +import lombok.AllArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 确认订单信息时的默认操作 + * @author LGH + */ +@Component("defaultConfirmOrderListener") +@AllArgsConstructor +public class ConfirmOrderListener { + + private final UserAddrService userAddrService; + + private final TransportManagerService transportManagerService; + + private final ProductService productService; + + private final SkuService skuService; + + /** + * 计算订单金额 + */ + @EventListener(ConfirmOrderEvent.class) + @Order(ConfirmOrderOrder.DEFAULT) + public void defaultConfirmOrderEvent(ConfirmOrderEvent event) { + + + ShopCartOrderDto shopCartOrderDto = event.getShopCartOrderDto(); + + OrderParam orderParam = event.getOrderParam(); + + String userId = SecurityUtils.getUser().getUserId(); + + // 订单的地址信息 + UserAddr userAddr = userAddrService.getUserAddrByUserId(orderParam.getAddrId(), userId); + + double total = 0.0; + + int totalCount = 0; + + double transfee = 0.0; + + for (ShopCartItemDto shopCartItem : event.getShopCartItems()) { + // 获取商品信息 + Product product = productService.getProductByProdId(shopCartItem.getProdId()); + // 获取sku信息 + Sku sku = skuService.getSkuBySkuId(shopCartItem.getSkuId()); + if (product == null || sku == null) { + throw new YamiShopBindException("购物车包含无法识别的商品"); + } + if (product.getStatus() != 1 || sku.getStatus() != 1) { + throw new YamiShopBindException("商品[" + sku.getProdName() + "]已下架"); + } + + totalCount = shopCartItem.getProdCount() + totalCount; + total = Arith.add(shopCartItem.getProductTotalAmount(), total); + // 用户地址如果为空,则表示该用户从未设置过任何地址相关信息 + if (userAddr != null) { + // 每个产品的运费相加 + transfee = Arith.add(transfee, transportManagerService.calculateTransfee(shopCartItem, userAddr)); + } + + shopCartItem.setActualTotal(shopCartItem.getProductTotalAmount()); + shopCartOrderDto.setActualTotal(Arith.add(total, transfee)); + shopCartOrderDto.setTotal(total); + shopCartOrderDto.setTotalCount(totalCount); + shopCartOrderDto.setTransfee(transfee); + } + } +} diff --git a/shop-api/src/main/java/com/yami/shop/api/listener/ShopCartListener.java b/shop-api/src/main/java/com/yami/shop/api/listener/ShopCartListener.java new file mode 100644 index 0000000..4c4087e --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/listener/ShopCartListener.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.listener; + +import com.google.common.collect.Lists; +import com.yami.shop.bean.app.dto.ShopCartDto; +import com.yami.shop.bean.app.dto.ShopCartItemDiscountDto; +import com.yami.shop.bean.app.dto.ShopCartItemDto; +import com.yami.shop.bean.event.ShopCartEvent; +import com.yami.shop.bean.order.ShopCartEventOrder; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 默认的购物车链进行组装时的操作 + * @author LGH + */ +@Component("defaultShopCartListener") +public class ShopCartListener { + + /** + * 将店铺下的所有商品归属到该店铺的购物车当中 + * @param event#getShopCart() 购物车 + * @param event#shopCartItemDtoList 该购物车的商品 + * @return 是否继续组装 + */ + @EventListener(ShopCartEvent.class) + @Order(ShopCartEventOrder.DEFAULT) + public void defaultShopCartEvent(ShopCartEvent event) { + ShopCartDto shopCart = event.getShopCartDto(); + List shopCartItemDtoList = event.getShopCartItemDtoList(); + // 对数据进行组装 + List shopCartItemDiscountDtoList = Lists.newArrayList(); + ShopCartItemDiscountDto shopCartItemDiscountDto = new ShopCartItemDiscountDto(); + + shopCartItemDiscountDto.setShopCartItems(shopCartItemDtoList); + shopCartItemDiscountDtoList.add(shopCartItemDiscountDto); + + shopCart.setShopCartItemDiscounts(shopCartItemDiscountDtoList); + } + +} diff --git a/shop-api/src/main/java/com/yami/shop/api/listener/SubmitOrderListener.java b/shop-api/src/main/java/com/yami/shop/api/listener/SubmitOrderListener.java new file mode 100644 index 0000000..2cb0f8d --- /dev/null +++ b/shop-api/src/main/java/com/yami/shop/api/listener/SubmitOrderListener.java @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.api.listener; + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.StrUtil; +import com.yami.shop.bean.app.dto.ShopCartItemDiscountDto; +import com.yami.shop.bean.app.dto.ShopCartItemDto; +import com.yami.shop.bean.app.dto.ShopCartOrderDto; +import com.yami.shop.bean.app.dto.ShopCartOrderMergerDto; +import com.yami.shop.bean.enums.OrderStatus; +import com.yami.shop.bean.event.SubmitOrderEvent; +import com.yami.shop.bean.model.*; +import com.yami.shop.bean.order.SubmitOrderOrder; +import com.yami.shop.common.constants.Constant; +import com.yami.shop.common.exception.YamiShopBindException; +import com.yami.shop.common.util.Arith; +import com.yami.shop.dao.*; +import com.yami.shop.security.api.util.SecurityUtils; +import com.yami.shop.service.ProductService; +import com.yami.shop.service.SkuService; +import com.yami.shop.service.UserAddrOrderService; +import lombok.AllArgsConstructor; +import cn.hutool.core.bean.BeanUtil; +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.*; + +/** + * 确认订单信息时的默认操作 + * + * @author LGH + */ +@Component("defaultSubmitOrderListener") +@AllArgsConstructor +public class SubmitOrderListener { + + + + + private final UserAddrOrderService userAddrOrderService; + + private final ProductService productService; + + private final SkuService skuService; + + private final Snowflake snowflake; + + private final OrderItemMapper orderItemMapper; + + private final SkuMapper skuMapper; + + private final ProductMapper productMapper; + + private final OrderMapper orderMapper; + + private final OrderSettlementMapper orderSettlementMapper; + + private final BasketMapper basketMapper; + + /** + * 计算订单金额 + */ + @EventListener(SubmitOrderEvent.class) + @Order(SubmitOrderOrder.DEFAULT) + public void defaultSubmitOrderListener(SubmitOrderEvent event) { + Date now = new Date(); + String userId = SecurityUtils.getUser().getUserId(); + + ShopCartOrderMergerDto mergerOrder = event.getMergerOrder(); + + // 订单商品参数 + List shopCartOrders = mergerOrder.getShopCartOrders(); + + List basketIds = new ArrayList<>(); + // 商品skuId为key 需要更新的sku为value的map + Map skuStocksMap = new HashMap<>(16); + // 商品productId为key 需要更新的product为value的map + Map prodStocksMap = new HashMap<>(16); + + // 把订单地址保存到数据库 + UserAddrOrder userAddrOrder = BeanUtil.copyProperties(mergerOrder.getUserAddr(), UserAddrOrder.class); + if (userAddrOrder == null) { + throw new YamiShopBindException("请填写收货地址"); + } + userAddrOrder.setUserId(userId); + userAddrOrder.setCreateTime(now); + userAddrOrderService.save(userAddrOrder); + + // 订单地址id + Long addrOrderId = userAddrOrder.getAddrOrderId(); + + + // 每个店铺生成一个订单 + for (ShopCartOrderDto shopCartOrderDto : shopCartOrders) { + createOrder(event, now, userId, basketIds, skuStocksMap, prodStocksMap, addrOrderId, shopCartOrderDto); + + } + + // 删除购物车的商品信息 + if (!basketIds.isEmpty()) { + basketMapper.deleteShopCartItemsByBasketIds(userId, basketIds); + + } + + + // 更新sku库存 + skuStocksMap.forEach((key, sku) -> { + + if (skuMapper.updateStocks(sku) == 0) { + skuService.removeSkuCacheBySkuId(key, sku.getProdId()); + throw new YamiShopBindException("商品:[" + sku.getProdName() + "]库存不足"); + } + }); + + // 更新商品库存 + prodStocksMap.forEach((prodId, prod) -> { + + if (productMapper.updateStocks(prod) == 0) { + productService.removeProductCacheByProdId(prodId); + throw new YamiShopBindException("商品:[" + prod.getProdName() + "]库存不足"); + } + }); + + } + + private void createOrder(SubmitOrderEvent event, Date now, String userId, List basketIds, Map skuStocksMap, Map prodStocksMap, Long addrOrderId, ShopCartOrderDto shopCartOrderDto) { + // 使用雪花算法生成的订单号 + String orderNumber = String.valueOf(snowflake.nextId()); + shopCartOrderDto.setOrderNumber(orderNumber); + + Long shopId = shopCartOrderDto.getShopId(); + + // 订单商品名称 + StringBuilder orderProdName = new StringBuilder(100); + + List orderItems = new ArrayList<>(); + + List shopCartItemDiscounts = shopCartOrderDto.getShopCartItemDiscounts(); + for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) { + List shopCartItems = shopCartItemDiscount.getShopCartItems(); + for (ShopCartItemDto shopCartItem : shopCartItems) { + Sku sku = checkAndGetSku(shopCartItem.getSkuId(), shopCartItem, skuStocksMap); + Product product = checkAndGetProd(shopCartItem.getProdId(), shopCartItem, prodStocksMap); + + OrderItem orderItem = getOrderItem(now, userId, orderNumber, shopId, orderProdName, shopCartItem, sku, product); + + orderItems.add(orderItem); + + if (shopCartItem.getBasketId() != null && shopCartItem.getBasketId() != 0) { + basketIds.add(shopCartItem.getBasketId()); + } + } + + } + + + orderProdName.subSequence(0, Math.min(orderProdName.length() - 1, 100)); + if (orderProdName.lastIndexOf(Constant.COMMA) == orderProdName.length() - 1) { + orderProdName.deleteCharAt(orderProdName.length() - 1); + } + + + // 订单信息 + com.yami.shop.bean.model.Order order = getOrder(now, userId, addrOrderId, shopCartOrderDto, orderNumber, shopId, orderProdName, orderItems); + event.getOrders().add(order); + // 插入订单结算表 + OrderSettlement orderSettlement = new OrderSettlement(); + orderSettlement.setUserId(userId); + orderSettlement.setIsClearing(0); + orderSettlement.setCreateTime(now); + orderSettlement.setOrderNumber(orderNumber); + orderSettlement.setPayAmount(order.getActualTotal()); + orderSettlement.setPayStatus(0); + orderSettlement.setVersion(0); + orderSettlementMapper.insert(orderSettlement); + } + + private com.yami.shop.bean.model.Order getOrder(Date now, String userId, Long addrOrderId, ShopCartOrderDto shopCartOrderDto, String orderNumber, Long shopId, StringBuilder orderProdName, List orderItems) { + com.yami.shop.bean.model.Order order = new com.yami.shop.bean.model.Order(); + + order.setShopId(shopId); + order.setOrderNumber(orderNumber); + // 订单商品名称 + order.setProdName(orderProdName.toString()); + // 用户id + order.setUserId(userId); + // 商品总额 + order.setTotal(shopCartOrderDto.getTotal()); + // 实际总额 + order.setActualTotal(shopCartOrderDto.getActualTotal()); + order.setStatus(OrderStatus.UNPAY.value()); + order.setUpdateTime(now); + order.setCreateTime(now); + order.setIsPayed(0); + order.setDeleteStatus(0); + order.setProductNums(shopCartOrderDto.getTotalCount()); + order.setAddrOrderId(addrOrderId); + order.setReduceAmount(Arith.sub(Arith.add(shopCartOrderDto.getTotal(), shopCartOrderDto.getTransfee()), shopCartOrderDto.getActualTotal())); + order.setFreightAmount(shopCartOrderDto.getTransfee()); + order.setRemarks(shopCartOrderDto.getRemarks()); + + order.setOrderItems(orderItems); + return order; + } + + private OrderItem getOrderItem(Date now, String userId, String orderNumber, Long shopId, StringBuilder orderProdName, ShopCartItemDto shopCartItem, Sku sku, Product product) { + OrderItem orderItem = new OrderItem(); + orderItem.setShopId(shopId); + orderItem.setOrderNumber(orderNumber); + orderItem.setProdId(sku.getProdId()); + orderItem.setSkuId(sku.getSkuId()); + orderItem.setSkuName(sku.getSkuName()); + orderItem.setProdCount(shopCartItem.getProdCount()); + orderItem.setProdName(sku.getProdName()); + orderItem.setPic(StrUtil.isBlank(sku.getPic()) ? product.getPic() : sku.getPic()); + orderItem.setPrice(shopCartItem.getPrice()); + orderItem.setUserId(userId); + orderItem.setProductTotalAmount(shopCartItem.getProductTotalAmount()); + orderItem.setRecTime(now); + orderItem.setCommSts(0); + orderItem.setBasketDate(shopCartItem.getBasketDate()); + orderProdName.append(orderItem.getProdName()).append(","); + //推广员卡号 + orderItem.setDistributionCardNo(shopCartItem.getDistributionCardNo()); + return orderItem; + } + + @SuppressWarnings({"Duplicates"}) + private Product checkAndGetProd(Long prodId, ShopCartItemDto shopCartItem, Map prodStocksMap) { + Product product = productService.getProductByProdId(prodId); + if (product == null) { + throw new YamiShopBindException("购物车包含无法识别的商品"); + } + + if (product.getStatus() != 1) { + throw new YamiShopBindException("商品[" + product.getProdName() + "]已下架"); + } + + // 商品需要改变的库存 + Product mapProduct = prodStocksMap.get(prodId); + + if (mapProduct == null) { + mapProduct = new Product(); + mapProduct.setTotalStocks(0); + mapProduct.setProdId(prodId); + mapProduct.setProdName(product.getProdName()); + + } + + if (product.getTotalStocks() != -1) { + mapProduct.setTotalStocks(mapProduct.getTotalStocks() + shopCartItem.getProdCount()); + prodStocksMap.put(product.getProdId(), mapProduct); + } + + // -1为无限库存 + if (product.getTotalStocks() != -1 && mapProduct.getTotalStocks() > product.getTotalStocks()) { + throw new YamiShopBindException("商品:[" + product.getProdName() + "]库存不足"); + } + + return product; + } + + @SuppressWarnings({"Duplicates"}) + private Sku checkAndGetSku(Long skuId, ShopCartItemDto shopCartItem, Map skuStocksMap) { + // 获取sku信息 + Sku sku = skuService.getSkuBySkuId(skuId); + if (sku == null) { + throw new YamiShopBindException("购物车包含无法识别的商品"); + } + + if (sku.getStatus() != 1) { + throw new YamiShopBindException("商品[" + sku.getProdName() + "]已下架"); + } + // -1为无限库存 + if (sku.getStocks() != -1 && shopCartItem.getProdCount() > sku.getStocks()) { + throw new YamiShopBindException("商品:[" + sku.getProdName() + "]库存不足"); + } + + if (sku.getStocks() != -1) { + Sku mapSku = new Sku(); + mapSku.setProdId(sku.getProdId()); + // 这里的库存是改变的库存 + mapSku.setStocks(shopCartItem.getProdCount()); + mapSku.setSkuId(sku.getSkuId()); + mapSku.setProdName(sku.getProdName()); + skuStocksMap.put(sku.getSkuId(), mapSku); + } + return sku; + } + + +} diff --git a/shop-api/src/main/resources/api.properties b/shop-api/src/main/resources/api.properties new file mode 100644 index 0000000..82620f9 --- /dev/null +++ b/shop-api/src/main/resources/api.properties @@ -0,0 +1,3 @@ +api.datacenterId=1 +api.workerId=1 +api.domainName=http://xxx.com \ No newline at end of file diff --git a/shop-api/src/main/resources/application-dev.yml b/shop-api/src/main/resources/application-dev.yml new file mode 100644 index 0000000..e014318 --- /dev/null +++ b/shop-api/src/main/resources/application-dev.yml @@ -0,0 +1,22 @@ +server: + port: 8086 +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/yami_shops?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 0 + maximum-pool-size: 20 + idle-timeout: 10000 + connection-test-query: select 1 + data: + redis: + host: 127.0.0.1 + port: 6379 + database: 0 +logging: + config: classpath:logback/logback-dev.xml + diff --git a/shop-api/src/main/resources/application-docker.yml b/shop-api/src/main/resources/application-docker.yml new file mode 100644 index 0000000..2ccd9fe --- /dev/null +++ b/shop-api/src/main/resources/application-docker.yml @@ -0,0 +1,21 @@ +server: + port: 8086 + +spring: + datasource: + url: jdbc:mysql://${MYSQL_HOST:mall4j-mysql}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:yami_shops}?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + username: ${MYSQL_USERNAME:root} + password: ${MYSQL_PASSWORD:root} + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 0 + maximum-pool-size: 20 + connection-test-query: select 1 + data: + redis: + host: ${REDIS_HOST:mall4j-redis} + port: ${REDIS_PORT:6379} + database: ${REDIS_DATABASE:0} +logging: + config: classpath:logback/logback-prod.xml diff --git a/shop-api/src/main/resources/application-prod.yml b/shop-api/src/main/resources/application-prod.yml new file mode 100644 index 0000000..d25012f --- /dev/null +++ b/shop-api/src/main/resources/application-prod.yml @@ -0,0 +1,21 @@ +server: + port: 8112 + +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/yami_shops?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 0 + maximum-pool-size: 20 + connection-test-query: select 1 + data: + redis: + host: 127.0.0.1 + port: 6379 + database: ${REDIS_DATABASE:0} +logging: + config: classpath:logback/logback-prod.xml diff --git a/shop-api/src/main/resources/application.yml b/shop-api/src/main/resources/application.yml new file mode 100644 index 0000000..da39db5 --- /dev/null +++ b/shop-api/src/main/resources/application.yml @@ -0,0 +1,42 @@ +spring: + # 环境 dev|test|prod + profiles: + active: dev + #文件上传设置 + servlet: + multipart: + max-file-size: 100MB + max-request-size: 100MB + enabled: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 +# mybaits-plus配置 +mybatis-plus: + # MyBatis Mapper所对应的XML文件位置 + mapper-locations: classpath*:/mapper/*Mapper.xml + global-config: + # 关闭MP3.0自带的banner + banner: false + db-config: + # 主键类型 0:数据库ID自增 1.未定义 2.用户输入 3 id_worker 4.uuid 5.id_worker字符串表示 + id-type: AUTO + #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" + field-strategy: NOT_NULL + # 默认数据库表下划线命名 + table-underline: true + +management: + server: + add-application-context-header: false +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token(不共用,避免登出时导致其他用户也登出) + is-share: false + # token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: false diff --git a/shop-api/src/main/resources/banner.txt b/shop-api/src/main/resources/banner.txt new file mode 100644 index 0000000..9fdec0d --- /dev/null +++ b/shop-api/src/main/resources/banner.txt @@ -0,0 +1,11 @@ + .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. +| .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +| | ____ ____ | || | __ | || | _____ | || | _____ | || | _ _ | || | _____ | | +| ||_ \ / _|| || | / \ | || | |_ _| | || | |_ _| | || | | | | | | || | |_ _| | | +| | | \/ | | || | / /\ \ | || | | | | || | | | | || | | |__| |_ | || | | | | | +| | | |\ /| | | || | / ____ \ | || | | | _ | || | | | _ | || | |____ _| | || | _ | | | | +| | _| |_\/_| |_ | || | _/ / \ \_ | || | _| |__/ | | || | _| |__/ | | || | _| |_ | || | | |_' | | | +| ||_____||_____|| || ||____| |____|| || | |________| | || | |________| | || | |_____| | || | `.___.' | | +| | | || | | || | | || | | || | | || | | | +| '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' diff --git a/shop-api/src/main/resources/logback/logback-dev.xml b/shop-api/src/main/resources/logback/logback-dev.xml new file mode 100644 index 0000000..37ddf47 --- /dev/null +++ b/shop-api/src/main/resources/logback/logback-dev.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/shop-api/src/main/resources/logback/logback-prod.xml b/shop-api/src/main/resources/logback/logback-prod.xml new file mode 100644 index 0000000..e4809c9 --- /dev/null +++ b/shop-api/src/main/resources/logback/logback-prod.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + true + + ${FILE_LOG_PATTERN} + UTF-8 + + ${PROJECT_PATH}/log/api.log + + + ${logging.level} + + + ${PROJECT_PATH}/log/api/%d{yyyy-MM}/api-%d{yyyy-MM-dd}-%i.log.gz + ${LOG_FILE_MAX_SIZE} + ${LOG_FILE_MAX_HISTORY} + + + + + + + + + + + + + +