first commit
This commit is contained in:
commit
a3e7faed94
72
.gitignore
vendored
Normal file
72
.gitignore
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# ========== IDEA ==========
|
||||||
|
# IntelliJ IDEA 项目文件
|
||||||
|
.idea/
|
||||||
|
# IDEA 模块文件
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
# IDEA 生成的工作区文件
|
||||||
|
workspace.xml
|
||||||
|
# 代码样式、运行配置等
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/dictionaries
|
||||||
|
.idea/vcs.xml
|
||||||
|
# 防止提交本地历史
|
||||||
|
.idea/**/localHistory/
|
||||||
|
|
||||||
|
# ========== 编译输出 ==========
|
||||||
|
# Maven 默认输出目录
|
||||||
|
target/
|
||||||
|
# Gradle 默认输出目录
|
||||||
|
build/
|
||||||
|
|
||||||
|
# ========== 操作系统 ==========
|
||||||
|
# Windows 缓存文件
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
# macOS 缓存文件
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
# Linux 缓存文件
|
||||||
|
*~
|
||||||
|
|
||||||
|
# ========== 日志和临时文件 ==========
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# ========== Test 输出 ==========
|
||||||
|
test-output/
|
||||||
|
surefire-reports/
|
||||||
|
failsafe-reports/
|
||||||
|
|
||||||
|
# ========== 依赖管理 ==========
|
||||||
|
# Maven 本地仓库
|
||||||
|
.mvn/repository/
|
||||||
|
# Gradle 缓存(可选)
|
||||||
|
.gradle/
|
||||||
|
|
||||||
|
# ========== 打包文件 ==========
|
||||||
|
# Spring Boot 可执行包
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
# Spring Boot 可执行包目录
|
||||||
|
BOOT-INF/
|
||||||
|
|
||||||
|
# ========== IDE 外插件 ==========
|
||||||
|
# Lombok 插件生成文件
|
||||||
|
*.class
|
||||||
|
# JRebel 缓存
|
||||||
|
rebel.xml
|
||||||
|
|
||||||
|
# ========== 其它 ==========
|
||||||
|
# 环境变量文件(如包含敏感配置)
|
||||||
|
*.env
|
||||||
|
# Docker 相关
|
||||||
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
# 如果你用到 IDEA 自带的 File-Based Storage(8+版本默认),可以添加:
|
||||||
|
# .idea/.name
|
||||||
|
# .idea/gradle.xml
|
58
cart-service/pom.xml
Normal file
58
cart-service/pom.xml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>hmall</artifactId>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>cart-service</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<!--common-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<artifactId>hm-common</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!--web-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--数据库-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--mybatis-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<artifactId>hm-service</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.hmall.cart;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@MapperScan("com.hmall.cart.mapper")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class CartApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
SpringApplication.run(CartApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.hmall.cart.controller;
|
||||||
|
|
||||||
|
import com.hmall.cart.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.cart.domain.po.Cart;
|
||||||
|
import com.hmall.cart.domain.vo.CartVO;
|
||||||
|
import com.hmall.cart.service.ICartService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "购物车相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/carts")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CartController {
|
||||||
|
private final ICartService cartService;
|
||||||
|
|
||||||
|
@ApiOperation("添加商品到购物车")
|
||||||
|
@PostMapping
|
||||||
|
public void addItem2Cart(@Valid @RequestBody CartFormDTO cartFormDTO){
|
||||||
|
cartService.addItem2Cart(cartFormDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("更新购物车数据")
|
||||||
|
@PutMapping
|
||||||
|
public void updateCart(@RequestBody Cart cart){
|
||||||
|
cartService.updateById(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除购物车中商品")
|
||||||
|
@DeleteMapping("{id}")
|
||||||
|
public void deleteCartItem(@Param ("购物车条目id")@PathVariable("id") Long id){
|
||||||
|
cartService.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("查询购物车列表")
|
||||||
|
@GetMapping
|
||||||
|
public List<CartVO> queryMyCarts(){
|
||||||
|
return cartService.queryMyCarts();
|
||||||
|
}
|
||||||
|
@ApiOperation("批量删除购物车中商品")
|
||||||
|
@ApiImplicitParam(name = "ids", value = "购物车条目id集合")
|
||||||
|
@DeleteMapping
|
||||||
|
public void deleteCartItemByIds(@RequestParam("ids") List<Long> ids){
|
||||||
|
cartService.removeByItemIds(ids);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.cart.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "新增购物车商品表单实体")
|
||||||
|
public class CartFormDTO {
|
||||||
|
@ApiModelProperty("商品id")
|
||||||
|
private Long itemId;
|
||||||
|
@ApiModelProperty("商品标题")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty("商品动态属性键值集")
|
||||||
|
private String spec;
|
||||||
|
@ApiModelProperty("价格,单位:分")
|
||||||
|
private Integer price;
|
||||||
|
@ApiModelProperty("商品图片")
|
||||||
|
private String image;
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.hmall.cart.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("cart")
|
||||||
|
public class Cart implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购物车条目id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sku商品id
|
||||||
|
*/
|
||||||
|
private Long itemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买数量
|
||||||
|
*/
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品标题
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品动态属性键值集
|
||||||
|
*/
|
||||||
|
private String spec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 价格,单位:分
|
||||||
|
*/
|
||||||
|
private Integer price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品图片
|
||||||
|
*/
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.hmall.cart.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "购物车VO实体")
|
||||||
|
public class CartVO {
|
||||||
|
@ApiModelProperty("购物车条目id ")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("sku商品id")
|
||||||
|
private Long itemId;
|
||||||
|
@ApiModelProperty("购买数量")
|
||||||
|
private Integer num;
|
||||||
|
@ApiModelProperty("商品标题")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty("商品动态属性键值集")
|
||||||
|
private String spec;
|
||||||
|
@ApiModelProperty("价格,单位:分")
|
||||||
|
private Integer price;
|
||||||
|
@ApiModelProperty("商品最新价格")
|
||||||
|
private Integer newPrice;
|
||||||
|
@ApiModelProperty("商品最新状态")
|
||||||
|
private Integer status = 1;
|
||||||
|
@ApiModelProperty("商品最新库存")
|
||||||
|
private Integer stock = 10;
|
||||||
|
@ApiModelProperty("商品图片")
|
||||||
|
private String image;
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.hmall.cart.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
import com.hmall.cart.domain.po.Cart;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface CartMapper extends BaseMapper<Cart> {
|
||||||
|
|
||||||
|
@Update("UPDATE cart SET num = num + 1 WHERE user_id = #{userId} AND item_id = #{itemId}")
|
||||||
|
void updateNum(@Param("itemId") Long itemId, @Param("userId") Long userId);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.hmall.cart.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hmall.cart.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.cart.domain.po.Cart;
|
||||||
|
import com.hmall.cart.domain.vo.CartVO;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface ICartService extends IService<Cart> {
|
||||||
|
|
||||||
|
void addItem2Cart(CartFormDTO cartFormDTO);
|
||||||
|
|
||||||
|
List<CartVO> queryMyCarts();
|
||||||
|
|
||||||
|
void removeByItemIds(Collection<Long> itemIds);
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package com.hmall.cart.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.cart.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.cart.domain.po.Cart;
|
||||||
|
import com.hmall.cart.domain.vo.CartVO;
|
||||||
|
import com.hmall.cart.mapper.CartMapper;
|
||||||
|
import com.hmall.cart.service.ICartService;
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.common.utils.CollUtils;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {
|
||||||
|
|
||||||
|
// private final IItemService itemService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addItem2Cart(CartFormDTO cartFormDTO) {
|
||||||
|
// 1.获取登录用户
|
||||||
|
Long userId = UserContext.getUser();
|
||||||
|
|
||||||
|
// 2.判断是否已经存在
|
||||||
|
if(checkItemExists(cartFormDTO.getItemId(), userId)){
|
||||||
|
// 2.1.存在,则更新数量
|
||||||
|
baseMapper.updateNum(cartFormDTO.getItemId(), userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2.2.不存在,判断是否超过购物车数量
|
||||||
|
checkCartsFull(userId);
|
||||||
|
|
||||||
|
// 3.新增购物车条目
|
||||||
|
// 3.1.转换PO
|
||||||
|
Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
|
||||||
|
// 3.2.保存当前用户
|
||||||
|
cart.setUserId(userId);
|
||||||
|
// 3.3.保存到数据库
|
||||||
|
save(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CartVO> queryMyCarts() {
|
||||||
|
// 1.查询我的购物车列表
|
||||||
|
List<Cart> carts = lambdaQuery().eq(Cart::getUserId,1L /*UserContext.getUser()*/).list();
|
||||||
|
if (CollUtils.isEmpty(carts)) {
|
||||||
|
return CollUtils.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.转换VO
|
||||||
|
List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);
|
||||||
|
|
||||||
|
// 3.处理VO中的商品信息
|
||||||
|
handleCartItems(vos);
|
||||||
|
|
||||||
|
// 4.返回
|
||||||
|
return vos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCartItems(List<CartVO> vos) {
|
||||||
|
// // 1.获取商品id
|
||||||
|
// Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
|
||||||
|
// // 2.查询商品
|
||||||
|
// List<ItemDTO> items = itemService.queryItemByIds(itemIds);
|
||||||
|
// if (CollUtils.isEmpty(items)) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // 3.转为 id 到 item的map
|
||||||
|
// Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
|
||||||
|
// // 4.写入vo
|
||||||
|
// for (CartVO v : vos) {
|
||||||
|
// ItemDTO item = itemMap.get(v.getItemId());
|
||||||
|
// if (item == null) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// v.setNewPrice(item.getPrice());
|
||||||
|
// v.setStatus(item.getStatus());
|
||||||
|
// v.setStock(item.getStock());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeByItemIds(Collection<Long> itemIds) {
|
||||||
|
// 1.构建删除条件,userId和itemId
|
||||||
|
QueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();
|
||||||
|
queryWrapper.lambda()
|
||||||
|
.eq(Cart::getUserId, UserContext.getUser())
|
||||||
|
.in(Cart::getItemId, itemIds);
|
||||||
|
// 2.删除
|
||||||
|
remove(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCartsFull(Long userId) {
|
||||||
|
long count = lambdaQuery()
|
||||||
|
.eq(Cart::getUserId, userId)
|
||||||
|
.count(); // ← 这里返回 long
|
||||||
|
if (count >= 10) {
|
||||||
|
throw new BizIllegalException(
|
||||||
|
StrUtil.format("用户购物车课程不能超过{}", 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkItemExists(Long itemId, Long userId) {
|
||||||
|
long count = lambdaQuery()
|
||||||
|
.eq(Cart::getUserId, userId)
|
||||||
|
.eq(Cart::getItemId, itemId)
|
||||||
|
.count();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
4
cart-service/src/main/resources/application-dev.yaml
Normal file
4
cart-service/src/main/resources/application-dev.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
hm:
|
||||||
|
db:
|
||||||
|
host: mysql
|
||||||
|
pw: 123
|
4
cart-service/src/main/resources/application-local.yaml
Normal file
4
cart-service/src/main/resources/application-local.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
hm:
|
||||||
|
db:
|
||||||
|
host: localhost # 修改为你自己的虚拟机IP地址
|
||||||
|
pw: 123456 # 修改为docker中的MySQL密码
|
43
cart-service/src/main/resources/application.yaml
Normal file
43
cart-service/src/main/resources/application.yaml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
server:
|
||||||
|
port: 8082
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: cart-service
|
||||||
|
profiles:
|
||||||
|
active: local
|
||||||
|
datasource:
|
||||||
|
url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
username: root
|
||||||
|
password: ${hm.db.pw}
|
||||||
|
mybatis-plus:
|
||||||
|
configuration:
|
||||||
|
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
|
||||||
|
global-config:
|
||||||
|
db-config:
|
||||||
|
update-strategy: not_null
|
||||||
|
id-type: auto
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
com.hmall: debug
|
||||||
|
pattern:
|
||||||
|
dateformat: HH:mm:ss:SSS
|
||||||
|
file:
|
||||||
|
path: "logs/${spring.application.name}"
|
||||||
|
knife4j:
|
||||||
|
enable: true
|
||||||
|
openapi:
|
||||||
|
title: 黑马商城购物车接口文档
|
||||||
|
description: "黑马商城购物车接口文档"
|
||||||
|
email: zhangsan@itcast.cn
|
||||||
|
concat: 宇哥
|
||||||
|
url: https://www.itcast.cn
|
||||||
|
version: v1.0.0
|
||||||
|
group:
|
||||||
|
default:
|
||||||
|
group-name: default
|
||||||
|
api-rule: package
|
||||||
|
api-rule-resources:
|
||||||
|
- com.hmall.cart.controller
|
||||||
|
|
||||||
|
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
|
5
cart-service/src/main/resources/mapper/CartMapper.xml
Normal file
5
cart-service/src/main/resources/mapper/CartMapper.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.hmall.mapper.CartMapper">
|
||||||
|
|
||||||
|
</mapper>
|
95
hm-common/pom.xml
Normal file
95
hm-common/pom.xml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>hmall</artifactId>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>hm-common</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--hutool工具包-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--完成SpringMVC自动装配-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--日志-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>9.0.73</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-core</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-extension</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.validator</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!--caffeine-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--AMQP依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.amqp</groupId>
|
||||||
|
<artifactId>spring-amqp</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--Spring整合Rabbit依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.amqp</groupId>
|
||||||
|
<artifactId>spring-rabbit</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<!--json处理-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-xml</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,68 @@
|
|||||||
|
package com.hmall.common.advice;
|
||||||
|
|
||||||
|
import com.hmall.common.domain.R;
|
||||||
|
import com.hmall.common.exception.BadRequestException;
|
||||||
|
import com.hmall.common.exception.CommonException;
|
||||||
|
import com.hmall.common.exception.DbException;
|
||||||
|
import com.hmall.common.utils.WebUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.validation.ObjectError;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.util.NestedServletException;
|
||||||
|
|
||||||
|
import java.net.BindException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class CommonExceptionAdvice {
|
||||||
|
|
||||||
|
@ExceptionHandler(DbException.class)
|
||||||
|
public Object handleDbException(DbException e) {
|
||||||
|
log.error("mysql数据库操作异常 -> ", e);
|
||||||
|
return processResponse(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(CommonException.class)
|
||||||
|
public Object handleBadRequestException(CommonException e) {
|
||||||
|
log.error("自定义异常 -> {} , 异常原因:{} ",e.getClass().getName(), e.getMessage());
|
||||||
|
log.debug("", e);
|
||||||
|
return processResponse(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||||
|
String msg = e.getBindingResult().getAllErrors()
|
||||||
|
.stream().map(ObjectError::getDefaultMessage)
|
||||||
|
.collect(Collectors.joining("|"));
|
||||||
|
log.error("请求参数校验异常 -> {}", msg);
|
||||||
|
log.debug("", e);
|
||||||
|
return processResponse(new BadRequestException(msg));
|
||||||
|
}
|
||||||
|
@ExceptionHandler(BindException.class)
|
||||||
|
public Object handleBindException(BindException e) {
|
||||||
|
log.error("请求参数绑定异常 ->BindException, {}", e.getMessage());
|
||||||
|
log.debug("", e);
|
||||||
|
return processResponse(new BadRequestException("请求参数格式错误"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(NestedServletException.class)
|
||||||
|
public Object handleNestedServletException(NestedServletException e) {
|
||||||
|
log.error("参数异常 -> NestedServletException,{}", e.getMessage());
|
||||||
|
log.debug("", e);
|
||||||
|
return processResponse(new BadRequestException("请求参数处理异常"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
public Object handleRuntimeException(Exception e) {
|
||||||
|
log.error("其他异常 uri : {} -> ", WebUtils.getRequest().getRequestURI(), e);
|
||||||
|
return processResponse(new CommonException("服务器内部异常", 500));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseEntity<R<Void>> processResponse(CommonException e){
|
||||||
|
return ResponseEntity.status(e.getCode()).body(R.error(e));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.hmall.common.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(ObjectMapper.class)
|
||||||
|
public class JsonConfig {
|
||||||
|
@Bean
|
||||||
|
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
|
||||||
|
return jacksonObjectMapperBuilder -> {
|
||||||
|
// long -> string
|
||||||
|
jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
|
||||||
|
jacksonObjectMapperBuilder.serializerByType(BigInteger.class, ToStringSerializer.instance);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.hmall.common.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({MybatisPlusInterceptor.class, BaseMapper.class})
|
||||||
|
public class MyBatisConfig {
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||||
|
// 1.分页拦截器
|
||||||
|
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
|
||||||
|
paginationInnerInterceptor.setMaxLimit(1000L);
|
||||||
|
interceptor.addInnerInterceptor(paginationInnerInterceptor);
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
}
|
61
hm-common/src/main/java/com/hmall/common/domain/PageDTO.java
Normal file
61
hm-common/src/main/java/com/hmall/common/domain/PageDTO.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package com.hmall.common.domain;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.common.utils.CollUtils;
|
||||||
|
import com.hmall.common.utils.Convert;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class PageDTO<T> {
|
||||||
|
protected Long total;
|
||||||
|
protected Long pages;
|
||||||
|
protected List<T> list;
|
||||||
|
|
||||||
|
public static <T> PageDTO<T> empty(Long total, Long pages) {
|
||||||
|
return new PageDTO<>(total, pages, CollUtils.emptyList());
|
||||||
|
}
|
||||||
|
public static <T> PageDTO<T> empty(Page<?> page) {
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(), CollUtils.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> PageDTO<T> of(Page<T> page) {
|
||||||
|
if(page == null){
|
||||||
|
return new PageDTO<>();
|
||||||
|
}
|
||||||
|
if (CollUtils.isEmpty(page.getRecords())) {
|
||||||
|
return empty(page);
|
||||||
|
}
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(), page.getRecords());
|
||||||
|
}
|
||||||
|
public static <T,R> PageDTO<T> of(Page<R> page, Function<R, T> mapper) {
|
||||||
|
if(page == null){
|
||||||
|
return new PageDTO<>();
|
||||||
|
}
|
||||||
|
if (CollUtils.isEmpty(page.getRecords())) {
|
||||||
|
return empty(page);
|
||||||
|
}
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(),
|
||||||
|
page.getRecords().stream().map(mapper).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
public static <T> PageDTO<T> of(Page<?> page, List<T> list) {
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz) {
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz, Convert<R, T> convert) {
|
||||||
|
return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz, convert));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.hmall.common.domain;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "分页查询条件")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class PageQuery {
|
||||||
|
public static final Integer DEFAULT_PAGE_SIZE = 20;
|
||||||
|
public static final Integer DEFAULT_PAGE_NUM = 1;
|
||||||
|
@ApiModelProperty("页码")
|
||||||
|
@Min(value = 1, message = "页码不能小于1")
|
||||||
|
private Integer pageNo = DEFAULT_PAGE_NUM;
|
||||||
|
@ApiModelProperty("页码")
|
||||||
|
@Min(value = 1, message = "每页查询数量不能小于1")
|
||||||
|
private Integer pageSize = DEFAULT_PAGE_SIZE;
|
||||||
|
@ApiModelProperty("是否升序")
|
||||||
|
private Boolean isAsc = true;
|
||||||
|
@ApiModelProperty("排序方式")
|
||||||
|
private String sortBy;
|
||||||
|
|
||||||
|
public int from(){
|
||||||
|
return (pageNo - 1) * pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Page<T> toMpPage(OrderItem... orderItems) {
|
||||||
|
Page<T> page = new Page<>(pageNo, pageSize);
|
||||||
|
// 是否手动指定排序方式
|
||||||
|
if (orderItems != null && orderItems.length > 0) {
|
||||||
|
for (OrderItem orderItem : orderItems) {
|
||||||
|
page.addOrder(orderItem);
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
// 前端是否有排序字段
|
||||||
|
if (StrUtil.isNotEmpty(sortBy)){
|
||||||
|
OrderItem orderItem = new OrderItem();
|
||||||
|
orderItem.setAsc(isAsc);
|
||||||
|
orderItem.setColumn(sortBy);
|
||||||
|
page.addOrder(orderItem);
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) {
|
||||||
|
if (StringUtils.isBlank(sortBy)){
|
||||||
|
sortBy = defaultSortBy;
|
||||||
|
this.isAsc = isAsc;
|
||||||
|
}
|
||||||
|
Page<T> page = new Page<>(pageNo, pageSize);
|
||||||
|
OrderItem orderItem = new OrderItem();
|
||||||
|
orderItem.setAsc(this.isAsc);
|
||||||
|
orderItem.setColumn(sortBy);
|
||||||
|
page.addOrder(orderItem);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {
|
||||||
|
return toMpPage("create_time", false);
|
||||||
|
}
|
||||||
|
}
|
45
hm-common/src/main/java/com/hmall/common/domain/R.java
Normal file
45
hm-common/src/main/java/com/hmall/common/domain/R.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package com.hmall.common.domain;
|
||||||
|
|
||||||
|
import com.hmall.common.exception.CommonException;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class R<T> {
|
||||||
|
private int code;
|
||||||
|
private String msg;
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
public static R<Void> ok() {
|
||||||
|
return ok(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> ok(T data) {
|
||||||
|
return new R<>(200, "OK", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> error(String msg) {
|
||||||
|
return new R<>(500, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> error(int code, String msg) {
|
||||||
|
return new R<>(code, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> R<T> error(CommonException e) {
|
||||||
|
return new R<>(e.getCode(), e.getMessage(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public R() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public R(int code, String msg, T data) {
|
||||||
|
this.code = code;
|
||||||
|
this.msg = msg;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean success(){
|
||||||
|
return code == 200;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
public class BadRequestException extends CommonException{
|
||||||
|
|
||||||
|
public BadRequestException(String message) {
|
||||||
|
super(message, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadRequestException(String message, Throwable cause) {
|
||||||
|
super(message, cause, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadRequestException(Throwable cause) {
|
||||||
|
super(cause, 400);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
public class BizIllegalException extends CommonException{
|
||||||
|
|
||||||
|
public BizIllegalException(String message) {
|
||||||
|
super(message, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BizIllegalException(String message, Throwable cause) {
|
||||||
|
super(message, cause, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BizIllegalException(Throwable cause) {
|
||||||
|
super(cause, 500);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class CommonException extends RuntimeException{
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
public CommonException(String message, int code) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommonException(String message, Throwable cause, int code) {
|
||||||
|
super(message, cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommonException(Throwable cause, int code) {
|
||||||
|
super(cause);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
public class DbException extends CommonException{
|
||||||
|
|
||||||
|
public DbException(String message) {
|
||||||
|
super(message, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbException(String message, Throwable cause) {
|
||||||
|
super(message, cause, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbException(Throwable cause) {
|
||||||
|
super(cause, 500);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
public class ForbiddenException extends CommonException{
|
||||||
|
|
||||||
|
public ForbiddenException(String message) {
|
||||||
|
super(message, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenException(String message, Throwable cause) {
|
||||||
|
super(message, cause, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenException(Throwable cause) {
|
||||||
|
super(cause, 403);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.common.exception;
|
||||||
|
|
||||||
|
public class UnauthorizedException extends CommonException{
|
||||||
|
|
||||||
|
public UnauthorizedException(String message) {
|
||||||
|
super(message, 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException(String message, Throwable cause) {
|
||||||
|
super(message, cause, 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException(Throwable cause) {
|
||||||
|
super(cause, 401);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 继承自 hutool 的BeanUtil,增加了bean转换时自定义转换器的功能
|
||||||
|
*/
|
||||||
|
public class BeanUtils extends BeanUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将原对象转换成目标对象,对于字段不匹配的字段可以使用转换器处理
|
||||||
|
*
|
||||||
|
* @param source 原对象
|
||||||
|
* @param clazz 目标对象的class
|
||||||
|
* @param convert 转换器
|
||||||
|
* @param <R> 原对象类型
|
||||||
|
* @param <T> 目标对象类型
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
public static <R, T> T copyBean(R source, Class<T> clazz, Convert<R, T> convert) {
|
||||||
|
T target = copyBean(source, clazz);
|
||||||
|
if (convert != null) {
|
||||||
|
convert.convert(source, target);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将原对象转换成目标对象,对于字段不匹配的字段可以使用转换器处理
|
||||||
|
*
|
||||||
|
* @param source 原对象
|
||||||
|
* @param clazz 目标对象的class
|
||||||
|
* @param <R> 原对象类型
|
||||||
|
* @param <T> 目标对象类型
|
||||||
|
* @return 目标对象
|
||||||
|
*/
|
||||||
|
public static <R, T> T copyBean(R source, Class<T> clazz){
|
||||||
|
if (source == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return toBean(source, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R, T> List<T> copyList(List<R> list, Class<T> clazz) {
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
return CollUtils.emptyList();
|
||||||
|
}
|
||||||
|
return copyToList(list, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R, T> List<T> copyList(List<R> list, Class<T> clazz, Convert<R, T> convert) {
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
return CollUtils.emptyList();
|
||||||
|
}
|
||||||
|
return list.stream().map(r -> copyBean(r, clazz, convert)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.collection.IterUtil;
|
||||||
|
import cn.hutool.core.util.NumberUtil;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 继承自 hutool 的集合工具类
|
||||||
|
*/
|
||||||
|
public class CollUtils extends CollectionUtil {
|
||||||
|
|
||||||
|
public static <T> List<T> emptyList() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Set<T> emptySet() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K,V> Map<K, V> emptyMap() {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Set<T> singletonSet(T t) {
|
||||||
|
return Collections.singleton(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> singletonList(T t) {
|
||||||
|
return Collections.singletonList(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Integer> convertToInteger(List<String> originList){
|
||||||
|
return CollUtils.isNotEmpty(originList) ? originList.stream().map(NumberUtil::parseInt).collect(Collectors.toList()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Long> convertToLong(List<String> originLIst){
|
||||||
|
return CollUtils.isNotEmpty(originLIst) ? originLIst.stream().map(NumberUtil::parseLong).collect(Collectors.toList()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以 conjunction 为分隔符将集合转换为字符串 如果集合元素为数组、Iterable或Iterator,则递归组合其为字符串
|
||||||
|
* @param collection 集合
|
||||||
|
* @param conjunction 分隔符
|
||||||
|
* @param <T> 集合元素类型
|
||||||
|
* @return 连接后的字符串
|
||||||
|
* See Also: IterUtil.join(Iterator, CharSequence)
|
||||||
|
*/
|
||||||
|
public static <T> String join(Collection<T> collection, CharSequence conjunction) {
|
||||||
|
if (null == collection || collection.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return IterUtil.join(collection.iterator(), conjunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> String joinIgnoreNull(Collection<T> collection, CharSequence conjunction) {
|
||||||
|
if (null == collection || collection.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (T t : collection) {
|
||||||
|
if(t == null) continue;
|
||||||
|
sb.append(t).append(",");
|
||||||
|
}
|
||||||
|
if(sb.length() <= 0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return sb.deleteCharAt(sb.length() - 1).toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对原对象进行计算,设置到目标对象中
|
||||||
|
**/
|
||||||
|
public interface Convert<R,T>{
|
||||||
|
void convert(R origin, T target);
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true, fluent = true)
|
||||||
|
public class CookieBuilder {
|
||||||
|
private Charset charset = StandardCharsets.UTF_8;
|
||||||
|
private int maxAge = -1;
|
||||||
|
private String path = "/";
|
||||||
|
private boolean httpOnly;
|
||||||
|
private String name;
|
||||||
|
private String value;
|
||||||
|
private String domain;
|
||||||
|
private final HttpServletRequest request;
|
||||||
|
private final HttpServletResponse response;
|
||||||
|
|
||||||
|
public CookieBuilder(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
this.request = request;
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建cookie,会对cookie值用UTF-8做URL编码,避免中文乱码
|
||||||
|
*/
|
||||||
|
public void build(){
|
||||||
|
if (response == null) {
|
||||||
|
log.error("response为null,无法写入cookie");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cookie cookie = new Cookie(name, URLEncoder.encode(value, charset));
|
||||||
|
if(StrUtil.isNotBlank(domain)) {
|
||||||
|
cookie.setDomain(domain);
|
||||||
|
}else if (request != null) {
|
||||||
|
String serverName = request.getServerName();
|
||||||
|
serverName = StrUtil.subAfter(serverName, ".", false);
|
||||||
|
cookie.setDomain("." + serverName);
|
||||||
|
}
|
||||||
|
cookie.setHttpOnly(httpOnly);
|
||||||
|
cookie.setMaxAge(maxAge);
|
||||||
|
cookie.setPath(path);
|
||||||
|
log.debug("生成cookie,编码方式:{},【{}={},domain:{};maxAge={};path={};httpOnly={}】",
|
||||||
|
charset.name(), name, value, domain, maxAge, path, httpOnly);
|
||||||
|
response.addCookie(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 利用UTF-8对cookie值解码,避免中文乱码问题
|
||||||
|
* @param cookieValue cookie原始值
|
||||||
|
* @return 解码后的值
|
||||||
|
*/
|
||||||
|
public String decode(String cookieValue){
|
||||||
|
return URLDecoder.decode(cookieValue, charset);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
public class UserContext {
|
||||||
|
private static final ThreadLocal<Long> tl = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存当前登录用户信息到ThreadLocal
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
public static void setUser(Long userId) {
|
||||||
|
tl.set(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前登录用户信息
|
||||||
|
* @return 用户id
|
||||||
|
*/
|
||||||
|
public static Long getUser() {
|
||||||
|
return tl.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除当前登录用户信息
|
||||||
|
*/
|
||||||
|
public static void removeUser(){
|
||||||
|
tl.remove();
|
||||||
|
}
|
||||||
|
}
|
151
hm-common/src/main/java/com/hmall/common/utils/WebUtils.java
Normal file
151
hm-common/src/main/java/com/hmall/common/utils/WebUtils.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package com.hmall.common.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class WebUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ServletRequestAttributes
|
||||||
|
*
|
||||||
|
* @return ServletRequestAttributes
|
||||||
|
*/
|
||||||
|
public static ServletRequestAttributes getServletRequestAttributes() {
|
||||||
|
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
|
||||||
|
if (ra == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (ServletRequestAttributes) ra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取request
|
||||||
|
*
|
||||||
|
* @return HttpServletRequest
|
||||||
|
*/
|
||||||
|
public static HttpServletRequest getRequest() {
|
||||||
|
ServletRequestAttributes servletRequestAttributes = getServletRequestAttributes();
|
||||||
|
return servletRequestAttributes == null ? null : servletRequestAttributes.getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取response
|
||||||
|
*
|
||||||
|
* @return HttpServletResponse
|
||||||
|
*/
|
||||||
|
public static HttpServletResponse getResponse() {
|
||||||
|
ServletRequestAttributes servletRequestAttributes = getServletRequestAttributes();
|
||||||
|
return servletRequestAttributes == null ? null : servletRequestAttributes.getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取request header中的内容
|
||||||
|
*
|
||||||
|
* @param headerName 请求头名称
|
||||||
|
* @return 请求头的值
|
||||||
|
*/
|
||||||
|
public static String getHeader(String headerName) {
|
||||||
|
HttpServletRequest request = getRequest();
|
||||||
|
if (request == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getRequest().getHeader(headerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setResponseHeader(String key, String value){
|
||||||
|
HttpServletResponse response = getResponse();
|
||||||
|
if (response == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setHeader(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSuccess() {
|
||||||
|
HttpServletResponse response = getResponse();
|
||||||
|
return response != null && response.getStatus() < 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求地址中的请求参数组装成 key1=value1&key2=value2
|
||||||
|
* 如果key对应多个值,中间使用逗号隔开例如 key1对应value1,key2对应value2,value3, key1=value1&key2=value2,value3
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @return 返回拼接字符串
|
||||||
|
*/
|
||||||
|
public static String getParameters(HttpServletRequest request) {
|
||||||
|
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||||
|
return getParameters(parameterMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求地址中的请求参数组装成 key1=value1&key2=value2
|
||||||
|
* 如果key对应多个值,中间使用逗号隔开例如 key1对应value1,key2对应value2,value3, key1=value1&key2=value2,value3
|
||||||
|
*
|
||||||
|
* @param queries
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> String getParameters(final Map<String, T> queries) {
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
for (Map.Entry<String, T> entry : queries.entrySet()) {
|
||||||
|
if(entry.getValue() instanceof String[]){
|
||||||
|
buffer.append(entry.getKey()).append(String.join(",", ((String[])entry.getValue())))
|
||||||
|
.append("&");
|
||||||
|
}else if(entry.getValue() instanceof Collection){
|
||||||
|
buffer.append(entry.getKey()).append(
|
||||||
|
CollUtil.join(((Collection<String>)entry.getValue()),",")
|
||||||
|
).append("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.length() > 0 ? buffer.substring(0, buffer.length() - 1) : StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求url中的uri
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String getUri(String url){
|
||||||
|
if(StringUtils.isEmpty(url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String uri = url;
|
||||||
|
//uri中去掉 http:// 或者https
|
||||||
|
if(uri.contains("http://") ){
|
||||||
|
uri = uri.replace("http://", StrUtil.EMPTY);
|
||||||
|
}else if(uri.contains("https://")){
|
||||||
|
uri = uri.replace("https://", StrUtil.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int endIndex = uri.length(); //uri 在url中的最后一个字符的序号+1
|
||||||
|
if(uri.contains("?")){
|
||||||
|
endIndex = uri.indexOf("?");
|
||||||
|
}
|
||||||
|
return uri.substring(uri.indexOf("/"), endIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRemoteAddr() {
|
||||||
|
HttpServletRequest request = getRequest();
|
||||||
|
if (request == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CookieBuilder cookieBuilder(){
|
||||||
|
return new CookieBuilder(getRequest(), getResponse());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "hm.db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.jwt",
|
||||||
|
"type": "com.hmall.config.SecurityConfig",
|
||||||
|
"sourceType": "com.hmall.config.JwtProperties"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.auth",
|
||||||
|
"type": "com.hmall.config.MvcConfig",
|
||||||
|
"sourceType": "com.hmall.config.AuthProperties"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "hm.mq.host",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "rabbitmq的地址",
|
||||||
|
"defaultValue": "192.168.150.101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.port",
|
||||||
|
"type": "java.lang.Integer",
|
||||||
|
"description": "rabbitmq的端口",
|
||||||
|
"defaultValue": "5672"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.vhost",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "rabbitmq的virtual-host地址",
|
||||||
|
"defaultValue": "/hmxt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.username",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "rabbitmq的用户名",
|
||||||
|
"defaultValue": "hmxt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "rabbitmq的密码",
|
||||||
|
"defaultValue": "123321"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.listener.retry.enable",
|
||||||
|
"type": "java.lang.Boolean",
|
||||||
|
"description": "是否开启rabbitmq的消费者重试机制",
|
||||||
|
"defaultValue": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.listener.retry.interval",
|
||||||
|
"type": "java.time.Duration",
|
||||||
|
"description": "消费者重试初始失败等待时长",
|
||||||
|
"defaultValue": "1000ms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.listener.retry.multiplier",
|
||||||
|
"type": "java.lang.Integer",
|
||||||
|
"description": "失败等待时长的递增倍数",
|
||||||
|
"defaultValue": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.listener.retry.max-attempts",
|
||||||
|
"type": "java.lang.Integer",
|
||||||
|
"description": "消费者重试最大重试次数",
|
||||||
|
"defaultValue": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.mq.listener.retry.stateless",
|
||||||
|
"type": "java.lang.Boolean",
|
||||||
|
"description": "是否是无状态,默认true",
|
||||||
|
"defaultValue": "true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.db.host",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "数据库地址",
|
||||||
|
"defaultValue": "192.168.150.101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.db.port",
|
||||||
|
"type": "java.lang.Integer",
|
||||||
|
"description": "数据库端口",
|
||||||
|
"defaultValue": "3306"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.db.database",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "数据库database名",
|
||||||
|
"defaultValue": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.db.un",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "数据库用户名",
|
||||||
|
"defaultValue": "root"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.db.pw",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "数据库密码",
|
||||||
|
"defaultValue": "123"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger.title",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "接口文档标题"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger.description",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "接口文档描述"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger.email",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "接口文档联系人邮箱"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger.concat",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "接口文档联系人"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.swagger.package",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "接口controller扫描包"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.jwt.location",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "秘钥存储地址"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.jwt.alias",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "秘钥别名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.jwt.password",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"description": "秘钥文件密码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.jwt.tokenTTL",
|
||||||
|
"type": "java.time.Duration",
|
||||||
|
"description": "登录有效期"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.auth.excludePaths",
|
||||||
|
"type": "java.util.List",
|
||||||
|
"description": "登录放行的路径"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hm.auth.includePaths",
|
||||||
|
"type": "java.util.List",
|
||||||
|
"description": "登录拦截的路径"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hints": []
|
||||||
|
}
|
3
hm-common/src/main/resources/META-INF/spring.factories
Normal file
3
hm-common/src/main/resources/META-INF/spring.factories
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
com.hmall.common.config.MyBatisConfig,\
|
||||||
|
com.hmall.common.config.JsonConfig
|
9
hm-service/Dockerfile
Normal file
9
hm-service/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# 基础镜像
|
||||||
|
FROM openjdk:11.0-jre-buster
|
||||||
|
# 设定时区
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
# 拷贝jar包
|
||||||
|
COPY hm-service.jar /app.jar
|
||||||
|
# 入口
|
||||||
|
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
71
hm-service/pom.xml
Normal file
71
hm-service/pom.xml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>hmall</artifactId>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>hm-service</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!--common-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.heima</groupId>
|
||||||
|
<artifactId>hm-common</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!--web-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--加密-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-crypto</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-rsa</artifactId>
|
||||||
|
<version>1.0.9.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<!--数据库-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--mybatis-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--单元测试-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!--redis-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
13
hm-service/src/main/java/com/hmall/HMallApplication.java
Normal file
13
hm-service/src/main/java/com/hmall/HMallApplication.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.hmall;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@MapperScan("com.hmall.mapper")
|
||||||
|
@SpringBootApplication
|
||||||
|
public class HMallApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(HMallApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.hmall.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "hm.auth")
|
||||||
|
public class AuthProperties {
|
||||||
|
private List<String> includePaths;
|
||||||
|
private List<String> excludePaths;
|
||||||
|
}
|
16
hm-service/src/main/java/com/hmall/config/JwtProperties.java
Normal file
16
hm-service/src/main/java/com/hmall/config/JwtProperties.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ConfigurationProperties(prefix = "hm.jwt")
|
||||||
|
public class JwtProperties {
|
||||||
|
private Resource location;
|
||||||
|
private String password;
|
||||||
|
private String alias;
|
||||||
|
private Duration tokenTTL = Duration.ofMinutes(10);
|
||||||
|
}
|
54
hm-service/src/main/java/com/hmall/config/MvcConfig.java
Normal file
54
hm-service/src/main/java/com/hmall/config/MvcConfig.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package com.hmall.config;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.hmall.interceptor.LoginInterceptor;
|
||||||
|
import com.hmall.utils.JwtTool;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@EnableConfigurationProperties(AuthProperties.class)
|
||||||
|
public class MvcConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
private final JwtTool jwtTool;
|
||||||
|
private final AuthProperties authProperties;
|
||||||
|
|
||||||
|
/* @Bean
|
||||||
|
public CommonExceptionAdvice commonExceptionAdvice(){
|
||||||
|
return new CommonExceptionAdvice();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
// 1.添加拦截器
|
||||||
|
LoginInterceptor loginInterceptor = new LoginInterceptor(jwtTool);
|
||||||
|
InterceptorRegistration registration = registry.addInterceptor(loginInterceptor);
|
||||||
|
// 2.配置拦截路径
|
||||||
|
List<String> includePaths = authProperties.getIncludePaths();
|
||||||
|
if (CollUtil.isNotEmpty(includePaths)) {
|
||||||
|
registration.addPathPatterns(includePaths);
|
||||||
|
}
|
||||||
|
// 3.配置放行路径
|
||||||
|
List<String> excludePaths = authProperties.getExcludePaths();
|
||||||
|
if (CollUtil.isNotEmpty(excludePaths)) {
|
||||||
|
registration.excludePathPatterns(excludePaths);
|
||||||
|
}
|
||||||
|
registration.excludePathPatterns(
|
||||||
|
"/error",
|
||||||
|
"/favicon.ico",
|
||||||
|
"/v2/**",
|
||||||
|
"/v3/**",
|
||||||
|
"/swagger-resources/**",
|
||||||
|
"/webjars/**",
|
||||||
|
"/doc.html"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.hmall.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
|
||||||
|
|
||||||
|
import java.security.KeyPair;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(JwtProperties.class)
|
||||||
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder(){
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public KeyPair keyPair(JwtProperties properties){
|
||||||
|
// 获取秘钥工厂
|
||||||
|
KeyStoreKeyFactory keyStoreKeyFactory =
|
||||||
|
new KeyStoreKeyFactory(
|
||||||
|
properties.getLocation(),
|
||||||
|
properties.getPassword().toCharArray());
|
||||||
|
//读取钥匙对
|
||||||
|
return keyStoreKeyFactory.getKeyPair(
|
||||||
|
properties.getAlias(),
|
||||||
|
properties.getPassword().toCharArray());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.hmall.common.exception.BadRequestException;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.common.utils.CollUtils;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.domain.dto.AddressDTO;
|
||||||
|
import com.hmall.domain.po.Address;
|
||||||
|
import com.hmall.service.IAddressService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 前端控制器
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/addresses")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Api(tags = "收货地址管理接口")
|
||||||
|
public class AddressController {
|
||||||
|
|
||||||
|
private final IAddressService addressService;
|
||||||
|
|
||||||
|
@ApiOperation("根据id查询地址")
|
||||||
|
@GetMapping("{addressId}")
|
||||||
|
public AddressDTO findAddressById(@ApiParam("地址id") @PathVariable("addressId") Long id) {
|
||||||
|
// 1.根据id查询
|
||||||
|
Address address = addressService.getById(id);
|
||||||
|
// 2.判断当前用户
|
||||||
|
Long userId = UserContext.getUser();
|
||||||
|
if(!address.getUserId().equals(userId)){
|
||||||
|
throw new BadRequestException("地址不属于当前登录用户");
|
||||||
|
}
|
||||||
|
return BeanUtils.copyBean(address, AddressDTO.class);
|
||||||
|
}
|
||||||
|
@ApiOperation("查询当前用户地址列表")
|
||||||
|
@GetMapping
|
||||||
|
public List<AddressDTO> findMyAddresses() {
|
||||||
|
// 1.查询列表
|
||||||
|
List<Address> list = addressService.query().eq("user_id", UserContext.getUser()).list();
|
||||||
|
// 2.判空
|
||||||
|
if (CollUtils.isEmpty(list)) {
|
||||||
|
return CollUtils.emptyList();
|
||||||
|
}
|
||||||
|
// 3.转vo
|
||||||
|
return BeanUtils.copyList(list, AddressDTO.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.domain.po.Cart;
|
||||||
|
import com.hmall.domain.vo.CartVO;
|
||||||
|
import com.hmall.service.ICartService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "购物车相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/carts")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CartController {
|
||||||
|
private final ICartService cartService;
|
||||||
|
|
||||||
|
@ApiOperation("添加商品到购物车")
|
||||||
|
@PostMapping
|
||||||
|
public void addItem2Cart(@Valid @RequestBody CartFormDTO cartFormDTO){
|
||||||
|
cartService.addItem2Cart(cartFormDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("更新购物车数据")
|
||||||
|
@PutMapping
|
||||||
|
public void updateCart(@RequestBody Cart cart){
|
||||||
|
cartService.updateById(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("删除购物车中商品")
|
||||||
|
@DeleteMapping("{id}")
|
||||||
|
public void deleteCartItem(@Param ("购物车条目id")@PathVariable("id") Long id){
|
||||||
|
cartService.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("查询购物车列表")
|
||||||
|
@GetMapping
|
||||||
|
public List<CartVO> queryMyCarts(){
|
||||||
|
return cartService.queryMyCarts();
|
||||||
|
}
|
||||||
|
@ApiOperation("批量删除购物车中商品")
|
||||||
|
@ApiImplicitParam(name = "ids", value = "购物车条目id集合")
|
||||||
|
@DeleteMapping
|
||||||
|
public void deleteCartItemByIds(@RequestParam("ids") List<Long> ids){
|
||||||
|
cartService.removeByItemIds(ids);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("hi")
|
||||||
|
public class HelloController {
|
||||||
|
|
||||||
|
private final Map<String, AtomicInteger> countMap = new HashMap<>();
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String hello(HttpServletRequest request) throws InterruptedException {
|
||||||
|
Thread.sleep(300);
|
||||||
|
String ip = request.getRemoteAddr();
|
||||||
|
AtomicInteger ai = countMap.get(ip);
|
||||||
|
if (ai == null) {
|
||||||
|
ai = new AtomicInteger(0);
|
||||||
|
countMap.put(ip, ai);
|
||||||
|
}
|
||||||
|
return String.format("<h5>欢迎访问黑马商城, 这是您第%d次访问<h5>", ai.incrementAndGet());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.hmall.common.domain.PageDTO;
|
||||||
|
import com.hmall.common.domain.PageQuery;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.dto.OrderDetailDTO;
|
||||||
|
import com.hmall.domain.po.Item;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Api(tags = "商品管理相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/items")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ItemController {
|
||||||
|
|
||||||
|
private final IItemService itemService;
|
||||||
|
|
||||||
|
@ApiOperation("分页查询商品")
|
||||||
|
@GetMapping("/page")
|
||||||
|
public PageDTO<ItemDTO> queryItemByPage(PageQuery query) {
|
||||||
|
// 1.分页查询
|
||||||
|
Page<Item> result = itemService.page(query.toMpPage("update_time", false));
|
||||||
|
// 2.封装并返回
|
||||||
|
return PageDTO.of(result, ItemDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据id批量查询商品")
|
||||||
|
@GetMapping
|
||||||
|
public List<ItemDTO> queryItemByIds(@RequestParam("ids") List<Long> ids){
|
||||||
|
return itemService.queryItemByIds(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据id查询商品")
|
||||||
|
@GetMapping("{id}")
|
||||||
|
public ItemDTO queryItemById(@PathVariable("id") Long id) {
|
||||||
|
return BeanUtils.copyBean(itemService.getById(id), ItemDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("新增商品")
|
||||||
|
@PostMapping
|
||||||
|
public void saveItem(@RequestBody ItemDTO item) {
|
||||||
|
// 新增
|
||||||
|
itemService.save(BeanUtils.copyBean(item, Item.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("更新商品状态")
|
||||||
|
@PutMapping("/status/{id}/{status}")
|
||||||
|
public void updateItemStatus(@PathVariable("id") Long id, @PathVariable("status") Integer status){
|
||||||
|
Item item = new Item();
|
||||||
|
item.setId(id);
|
||||||
|
item.setStatus(status);
|
||||||
|
itemService.updateById(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("更新商品")
|
||||||
|
@PutMapping
|
||||||
|
public void updateItem(@RequestBody ItemDTO item) {
|
||||||
|
// 不允许修改商品状态,所以强制设置为null,更新时,就会忽略该字段
|
||||||
|
item.setStatus(null);
|
||||||
|
// 更新
|
||||||
|
itemService.updateById(BeanUtils.copyBean(item, Item.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据id删除商品")
|
||||||
|
@DeleteMapping("{id}")
|
||||||
|
public void deleteItemById(@PathVariable("id") Long id) {
|
||||||
|
itemService.removeById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("批量扣减库存")
|
||||||
|
@PutMapping("/stock/deduct")
|
||||||
|
public void deductStock(@RequestBody List<OrderDetailDTO> items){
|
||||||
|
itemService.deductStock(items);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.domain.dto.OrderFormDTO;
|
||||||
|
import com.hmall.domain.vo.OrderVO;
|
||||||
|
import com.hmall.service.IOrderService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Api(tags = "订单管理接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/orders")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OrderController {
|
||||||
|
private final IOrderService orderService;
|
||||||
|
|
||||||
|
@ApiOperation("根据id查询订单")
|
||||||
|
@GetMapping("{id}")
|
||||||
|
public OrderVO queryOrderById(@Param ("订单id")@PathVariable("id") Long orderId) {
|
||||||
|
return BeanUtils.copyBean(orderService.getById(orderId), OrderVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("创建订单")
|
||||||
|
@PostMapping
|
||||||
|
public Long createOrder(@RequestBody OrderFormDTO orderFormDTO){
|
||||||
|
return orderService.createOrder(orderFormDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("标记订单已支付")
|
||||||
|
@ApiImplicitParam(name = "orderId", value = "订单id", paramType = "path")
|
||||||
|
@PutMapping("/{orderId}")
|
||||||
|
public void markOrderPaySuccess(@PathVariable("orderId") Long orderId) {
|
||||||
|
orderService.markOrderPaySuccess(orderId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.domain.dto.PayApplyDTO;
|
||||||
|
import com.hmall.domain.dto.PayOrderFormDTO;
|
||||||
|
import com.hmall.enums.PayType;
|
||||||
|
import com.hmall.service.IPayOrderService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Api(tags = "支付相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("pay-orders")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PayController {
|
||||||
|
|
||||||
|
private final IPayOrderService payOrderService;
|
||||||
|
|
||||||
|
@ApiOperation("生成支付单")
|
||||||
|
@PostMapping
|
||||||
|
public String applyPayOrder(@RequestBody PayApplyDTO applyDTO){
|
||||||
|
if(!PayType.BALANCE.equalsValue(applyDTO.getPayType())){
|
||||||
|
// 目前只支持余额支付
|
||||||
|
throw new BizIllegalException("抱歉,目前只支持余额支付");
|
||||||
|
}
|
||||||
|
return payOrderService.applyPayOrder(applyDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("尝试基于用户余额支付")
|
||||||
|
@ApiImplicitParam(value = "支付单id", name = "id")
|
||||||
|
@PostMapping("{id}")
|
||||||
|
public void tryPayOrderByBalance(@PathVariable("id") Long id, @RequestBody PayOrderFormDTO payOrderFormDTO){
|
||||||
|
payOrderFormDTO.setId(id);
|
||||||
|
payOrderService.tryPayOrderByBalance(payOrderFormDTO);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.hmall.common.domain.PageDTO;
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.po.Item;
|
||||||
|
import com.hmall.domain.query.ItemPageQuery;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Api(tags = "搜索相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/search")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SearchController {
|
||||||
|
|
||||||
|
private final IItemService itemService;
|
||||||
|
|
||||||
|
@ApiOperation("搜索商品")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public PageDTO<ItemDTO> search(ItemPageQuery query) {
|
||||||
|
// 分页查询
|
||||||
|
Page<Item> result = itemService.lambdaQuery()
|
||||||
|
.like(StrUtil.isNotBlank(query.getKey()), Item::getName, query.getKey())
|
||||||
|
.eq(StrUtil.isNotBlank(query.getBrand()), Item::getBrand, query.getBrand())
|
||||||
|
.eq(StrUtil.isNotBlank(query.getCategory()), Item::getCategory, query.getCategory())
|
||||||
|
.eq(Item::getStatus, 1)
|
||||||
|
.between(query.getMaxPrice() != null, Item::getPrice, query.getMinPrice(), query.getMaxPrice())
|
||||||
|
.page(query.toMpPage("update_time", false));
|
||||||
|
// 封装并返回
|
||||||
|
return PageDTO.of(result, ItemDTO.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.hmall.controller;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.LoginFormDTO;
|
||||||
|
import com.hmall.domain.vo.UserLoginVO;
|
||||||
|
import com.hmall.service.IUserService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Api(tags = "用户相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/users")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final IUserService userService;
|
||||||
|
|
||||||
|
@ApiOperation("用户登录接口")
|
||||||
|
@PostMapping("login")
|
||||||
|
public UserLoginVO login(@RequestBody @Validated LoginFormDTO loginFormDTO){
|
||||||
|
return userService.login(loginFormDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("扣减余额")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "pw", value = "支付密码"),
|
||||||
|
@ApiImplicitParam(name = "amount", value = "支付金额")
|
||||||
|
})
|
||||||
|
@PutMapping("/money/deduct")
|
||||||
|
public void deductMoney(@RequestParam("pw") String pw,@RequestParam("amount") Integer amount){
|
||||||
|
userService.deductMoney(pw, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "收货地址实体")
|
||||||
|
public class AddressDTO {
|
||||||
|
@ApiModelProperty("id")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("省")
|
||||||
|
private String province;
|
||||||
|
@ApiModelProperty("市")
|
||||||
|
private String city;
|
||||||
|
@ApiModelProperty("县/区")
|
||||||
|
private String town;
|
||||||
|
@ApiModelProperty("手机")
|
||||||
|
private String mobile;
|
||||||
|
@ApiModelProperty("详细地址")
|
||||||
|
private String street;
|
||||||
|
@ApiModelProperty("联系人")
|
||||||
|
private String contact;
|
||||||
|
@ApiModelProperty("是否是默认 1默认 0否")
|
||||||
|
private Integer isDefault;
|
||||||
|
@ApiModelProperty("备注")
|
||||||
|
private String notes;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "新增购物车商品表单实体")
|
||||||
|
public class CartFormDTO {
|
||||||
|
@ApiModelProperty("商品id")
|
||||||
|
private Long itemId;
|
||||||
|
@ApiModelProperty("商品标题")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty("商品动态属性键值集")
|
||||||
|
private String spec;
|
||||||
|
@ApiModelProperty("价格,单位:分")
|
||||||
|
private Integer price;
|
||||||
|
@ApiModelProperty("商品图片")
|
||||||
|
private String image;
|
||||||
|
}
|
34
hm-service/src/main/java/com/hmall/domain/dto/ItemDTO.java
Normal file
34
hm-service/src/main/java/com/hmall/domain/dto/ItemDTO.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "商品实体")
|
||||||
|
public class ItemDTO {
|
||||||
|
@ApiModelProperty("商品id")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("SKU名称")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty("价格(分)")
|
||||||
|
private Integer price;
|
||||||
|
@ApiModelProperty("库存数量")
|
||||||
|
private Integer stock;
|
||||||
|
@ApiModelProperty("商品图片")
|
||||||
|
private String image;
|
||||||
|
@ApiModelProperty("类目名称")
|
||||||
|
private String category;
|
||||||
|
@ApiModelProperty("品牌名称")
|
||||||
|
private String brand;
|
||||||
|
@ApiModelProperty("规格")
|
||||||
|
private String spec;
|
||||||
|
@ApiModelProperty("销量")
|
||||||
|
private Integer sold;
|
||||||
|
@ApiModelProperty("评论数")
|
||||||
|
private Integer commentCount;
|
||||||
|
@ApiModelProperty("是否是推广广告,true/false")
|
||||||
|
private Boolean isAD;
|
||||||
|
@ApiModelProperty("商品状态 1-正常,2-下架,3-删除")
|
||||||
|
private Integer status;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "登录表单实体")
|
||||||
|
public class LoginFormDTO {
|
||||||
|
@ApiModelProperty(value = "用户名", required = true)
|
||||||
|
@NotNull(message = "用户名不能为空")
|
||||||
|
private String username;
|
||||||
|
@NotNull(message = "密码不能为空")
|
||||||
|
@ApiModelProperty(value = "用户名", required = true)
|
||||||
|
private String password;
|
||||||
|
@ApiModelProperty(value = "是否记住我", required = false)
|
||||||
|
private Boolean rememberMe = false;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@ApiModel(description = "订单明细条目")
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class OrderDetailDTO {
|
||||||
|
@ApiModelProperty("商品id")
|
||||||
|
private Long itemId;
|
||||||
|
@ApiModelProperty("商品购买数量")
|
||||||
|
private Integer num;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "交易下单表单实体")
|
||||||
|
public class OrderFormDTO {
|
||||||
|
@ApiModelProperty("收货地址id")
|
||||||
|
private Long addressId;
|
||||||
|
@ApiModelProperty("支付类型")
|
||||||
|
private Integer paymentType;
|
||||||
|
@ApiModelProperty("下单商品列表")
|
||||||
|
private List<OrderDetailDTO> details;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@ApiModel(description = "支付下单表单实体")
|
||||||
|
public class PayApplyDTO {
|
||||||
|
@ApiModelProperty("业务订单id不能为空")
|
||||||
|
@NotNull(message = "业务订单id不能为空")
|
||||||
|
private Long bizOrderNo;
|
||||||
|
@ApiModelProperty("支付金额必须为正数")
|
||||||
|
@Min(value = 1, message = "支付金额必须为正数")
|
||||||
|
private Integer amount;
|
||||||
|
@ApiModelProperty("支付渠道编码不能为空")
|
||||||
|
@NotNull(message = "支付渠道编码不能为空")
|
||||||
|
private String payChannelCode;
|
||||||
|
@ApiModelProperty("支付方式不能为空")
|
||||||
|
@NotNull(message = "支付方式不能为空")
|
||||||
|
private Integer payType;
|
||||||
|
@ApiModelProperty("订单中的商品信息不能为空")
|
||||||
|
@NotNull(message = "订单中的商品信息不能为空")
|
||||||
|
private String orderInfo;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@ApiModel(description = "支付确认表单实体")
|
||||||
|
public class PayOrderFormDTO {
|
||||||
|
@ApiModelProperty("支付订单id不能为空")
|
||||||
|
@NotNull(message = "支付订单id不能为空")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("支付密码")
|
||||||
|
@NotNull(message = "支付密码")
|
||||||
|
private String pw;
|
||||||
|
}
|
77
hm-service/src/main/java/com/hmall/domain/po/Address.java
Normal file
77
hm-service/src/main/java/com/hmall/domain/po/Address.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("address")
|
||||||
|
public class Address implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 省
|
||||||
|
*/
|
||||||
|
private String province;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 市
|
||||||
|
*/
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 县/区
|
||||||
|
*/
|
||||||
|
private String town;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详细地址
|
||||||
|
*/
|
||||||
|
private String street;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系人
|
||||||
|
*/
|
||||||
|
private String contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是默认 1默认 0否
|
||||||
|
*/
|
||||||
|
private Integer isDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String notes;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
80
hm-service/src/main/java/com/hmall/domain/po/Cart.java
Normal file
80
hm-service/src/main/java/com/hmall/domain/po/Cart.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("cart")
|
||||||
|
public class Cart implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购物车条目id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sku商品id
|
||||||
|
*/
|
||||||
|
private Long itemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买数量
|
||||||
|
*/
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品标题
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品动态属性键值集
|
||||||
|
*/
|
||||||
|
private String spec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 价格,单位:分
|
||||||
|
*/
|
||||||
|
private Integer price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品图片
|
||||||
|
*/
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
113
hm-service/src/main/java/com/hmall/domain/po/Item.java
Normal file
113
hm-service/src/main/java/com/hmall/domain/po/Item.java
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 商品表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("item")
|
||||||
|
public class Item implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SKU名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 价格(分)
|
||||||
|
*/
|
||||||
|
private Integer price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存数量
|
||||||
|
*/
|
||||||
|
private Integer stock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品图片
|
||||||
|
*/
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类目名称
|
||||||
|
*/
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 品牌名称
|
||||||
|
*/
|
||||||
|
private String brand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规格
|
||||||
|
*/
|
||||||
|
private String spec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销量
|
||||||
|
*/
|
||||||
|
private Integer sold;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论数
|
||||||
|
*/
|
||||||
|
private Integer commentCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是推广广告,true/false
|
||||||
|
*/
|
||||||
|
@TableField("isAD")
|
||||||
|
private Boolean isAD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品状态 1-正常,2-下架,3-删除
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
private Long creater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改人
|
||||||
|
*/
|
||||||
|
private Long updater;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
91
hm-service/src/main/java/com/hmall/domain/po/Order.java
Normal file
91
hm-service/src/main/java/com/hmall/domain/po/Order.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("`order`")
|
||||||
|
public class Order implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总金额,单位为分
|
||||||
|
*/
|
||||||
|
private Integer totalFee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付类型,1、支付宝,2、微信,3、扣减余额
|
||||||
|
*/
|
||||||
|
private Integer paymentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime payTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发货时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime consignTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易完成时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 交易关闭时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime closeTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评价时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime commentTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("order_detail")
|
||||||
|
public class OrderDetail implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单详情id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单id
|
||||||
|
*/
|
||||||
|
private Long orderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sku商品id
|
||||||
|
*/
|
||||||
|
private Long itemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买数量
|
||||||
|
*/
|
||||||
|
private Integer num;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品标题
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品动态属性键值集
|
||||||
|
*/
|
||||||
|
private String spec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 价格,单位:分
|
||||||
|
*/
|
||||||
|
private Integer price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品图片
|
||||||
|
*/
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("order_logistics")
|
||||||
|
public class OrderLogistics implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单id,与订单表一对一
|
||||||
|
*/
|
||||||
|
@TableId(value = "order_id", type = IdType.INPUT)
|
||||||
|
private Long orderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物流单号
|
||||||
|
*/
|
||||||
|
private String logisticsNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物流公司名称
|
||||||
|
*/
|
||||||
|
private String logisticsCompany;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收件人
|
||||||
|
*/
|
||||||
|
private String contact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收件人手机号码
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 省
|
||||||
|
*/
|
||||||
|
private String province;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 市
|
||||||
|
*/
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区
|
||||||
|
*/
|
||||||
|
private String town;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 街道
|
||||||
|
*/
|
||||||
|
private String street;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
123
hm-service/src/main/java/com/hmall/domain/po/PayOrder.java
Normal file
123
hm-service/src/main/java/com/hmall/domain/po/PayOrder.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 支付订单
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("pay_order")
|
||||||
|
public class PayOrder implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务订单号
|
||||||
|
*/
|
||||||
|
private Long bizOrderNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付单号
|
||||||
|
*/
|
||||||
|
private Long payOrderNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付用户id
|
||||||
|
*/
|
||||||
|
private Long bizUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付渠道编码
|
||||||
|
*/
|
||||||
|
private String payChannelCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付金额,单位分
|
||||||
|
*/
|
||||||
|
private Integer amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付类型,1:h5,2:小程序,3:公众号,4:扫码,5:余额支付
|
||||||
|
*/
|
||||||
|
private Integer payType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付状态,0:待提交,1:待支付,2:支付超时或取消,3:支付成功
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拓展字段,用于传递不同渠道单独处理的字段
|
||||||
|
*/
|
||||||
|
private String expandJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方返回业务码
|
||||||
|
*/
|
||||||
|
private String resultCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方返回提示信息
|
||||||
|
*/
|
||||||
|
private String resultMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付成功时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime paySuccessTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付超时时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime payOverTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付二维码链接
|
||||||
|
*/
|
||||||
|
private String qrCodeUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人
|
||||||
|
*/
|
||||||
|
private Long creater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新人
|
||||||
|
*/
|
||||||
|
private Long updater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 逻辑删除
|
||||||
|
*/
|
||||||
|
private Boolean isDelete;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
66
hm-service/src/main/java/com/hmall/domain/po/User.java
Normal file
66
hm-service/src/main/java/com/hmall/domain/po/User.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package com.hmall.domain.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.hmall.enums.UserStatus;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("user")
|
||||||
|
public class User implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码,加密存储
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册手机号
|
||||||
|
*/
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用状态(1正常 2冻结)
|
||||||
|
*/
|
||||||
|
private UserStatus status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账户余额
|
||||||
|
*/
|
||||||
|
private Integer balance;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.hmall.domain.query;
|
||||||
|
|
||||||
|
import com.hmall.common.domain.PageQuery;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "商品分页查询条件")
|
||||||
|
public class ItemPageQuery extends PageQuery {
|
||||||
|
@ApiModelProperty("搜索关键字")
|
||||||
|
private String key;
|
||||||
|
@ApiModelProperty("商品分类")
|
||||||
|
private String category;
|
||||||
|
@ApiModelProperty("商品品牌")
|
||||||
|
private String brand;
|
||||||
|
@ApiModelProperty("价格最小值")
|
||||||
|
private Integer minPrice;
|
||||||
|
@ApiModelProperty("价格最大值")
|
||||||
|
private Integer maxPrice;
|
||||||
|
}
|
43
hm-service/src/main/java/com/hmall/domain/vo/CartVO.java
Normal file
43
hm-service/src/main/java/com/hmall/domain/vo/CartVO.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package com.hmall.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "购物车VO实体")
|
||||||
|
public class CartVO {
|
||||||
|
@ApiModelProperty("购物车条目id ")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("sku商品id")
|
||||||
|
private Long itemId;
|
||||||
|
@ApiModelProperty("购买数量")
|
||||||
|
private Integer num;
|
||||||
|
@ApiModelProperty("商品标题")
|
||||||
|
private String name;
|
||||||
|
@ApiModelProperty("商品动态属性键值集")
|
||||||
|
private String spec;
|
||||||
|
@ApiModelProperty("价格,单位:分")
|
||||||
|
private Integer price;
|
||||||
|
@ApiModelProperty("商品最新价格")
|
||||||
|
private Integer newPrice;
|
||||||
|
@ApiModelProperty("商品最新状态")
|
||||||
|
private Integer status = 1;
|
||||||
|
@ApiModelProperty("商品最新库存")
|
||||||
|
private Integer stock = 10;
|
||||||
|
@ApiModelProperty("商品图片")
|
||||||
|
private String image;
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
34
hm-service/src/main/java/com/hmall/domain/vo/OrderVO.java
Normal file
34
hm-service/src/main/java/com/hmall/domain/vo/OrderVO.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package com.hmall.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "订单页面VO")
|
||||||
|
public class OrderVO {
|
||||||
|
@ApiModelProperty("订单id")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("总金额,单位为分")
|
||||||
|
private Integer totalFee;
|
||||||
|
@ApiModelProperty("支付类型,1、支付宝,2、微信,3、扣减余额")
|
||||||
|
private Integer paymentType;
|
||||||
|
@ApiModelProperty("用户id")
|
||||||
|
private Long userId;
|
||||||
|
@ApiModelProperty("订单的状态,1、未付款 2、已付款,未发货 3、已发货,未确认 4、确认收货,交易成功 5、交易取消,订单关闭 6、交易结束,已评价")
|
||||||
|
private Integer status;
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
@ApiModelProperty("支付时间")
|
||||||
|
private LocalDateTime payTime;
|
||||||
|
@ApiModelProperty("发货时间")
|
||||||
|
private LocalDateTime consignTime;
|
||||||
|
@ApiModelProperty("交易完成时间")
|
||||||
|
private LocalDateTime endTime;
|
||||||
|
@ApiModelProperty("交易关闭时间")
|
||||||
|
private LocalDateTime closeTime;
|
||||||
|
@ApiModelProperty("评价时间")
|
||||||
|
private LocalDateTime commentTime;
|
||||||
|
}
|
49
hm-service/src/main/java/com/hmall/domain/vo/PayOrderVO.java
Normal file
49
hm-service/src/main/java/com/hmall/domain/vo/PayOrderVO.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package com.hmall.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 支付订单
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ApiModel(description = "支付单vo实体")
|
||||||
|
public class PayOrderVO {
|
||||||
|
@ApiModelProperty("id")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("业务订单号")
|
||||||
|
private Long bizOrderNo;
|
||||||
|
@ApiModelProperty("支付单号")
|
||||||
|
private Long payOrderNo;
|
||||||
|
@ApiModelProperty("支付用户id")
|
||||||
|
private Long bizUserId;
|
||||||
|
@ApiModelProperty("支付渠道编码")
|
||||||
|
private String payChannelCode;
|
||||||
|
@ApiModelProperty("支付金额,单位分")
|
||||||
|
private Integer amount;
|
||||||
|
@ApiModelProperty("付类型,1:h5,2:小程序,3:公众号,4:扫码,5:余额支付")
|
||||||
|
private Integer payType;
|
||||||
|
@ApiModelProperty("付状态,0:待提交,1:待支付,2:支付超时或取消,3:支付成功")
|
||||||
|
private Integer status;
|
||||||
|
@ApiModelProperty("拓展字段,用于传递不同渠道单独处理的字段")
|
||||||
|
private String expandJson;
|
||||||
|
@ApiModelProperty("第三方返回业务码")
|
||||||
|
private String resultCode;
|
||||||
|
@ApiModelProperty("第三方返回提示信息")
|
||||||
|
private String resultMsg;
|
||||||
|
@ApiModelProperty("支付成功时间")
|
||||||
|
private LocalDateTime paySuccessTime;
|
||||||
|
@ApiModelProperty("支付超时时间")
|
||||||
|
private LocalDateTime payOverTime;
|
||||||
|
@ApiModelProperty("支付二维码链接")
|
||||||
|
private String qrCodeUrl;
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
@ApiModelProperty("更新时间")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.hmall.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserLoginVO {
|
||||||
|
private String token;
|
||||||
|
private Long userId;
|
||||||
|
private String username;
|
||||||
|
private Integer balance;
|
||||||
|
}
|
25
hm-service/src/main/java/com/hmall/enums/PayChannel.java
Normal file
25
hm-service/src/main/java/com/hmall/enums/PayChannel.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package com.hmall.enums;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum PayChannel {
|
||||||
|
wxPay("微信支付"),
|
||||||
|
aliPay("支付宝支付"),
|
||||||
|
balance("余额支付"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
PayChannel(String desc) {
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String desc(String value){
|
||||||
|
if (StrUtil.isBlank(value)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return PayChannel.valueOf(value).getDesc();
|
||||||
|
}
|
||||||
|
}
|
27
hm-service/src/main/java/com/hmall/enums/PayStatus.java
Normal file
27
hm-service/src/main/java/com/hmall/enums/PayStatus.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.hmall.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum PayStatus {
|
||||||
|
NOT_COMMIT(0, "未提交"),
|
||||||
|
WAIT_BUYER_PAY(1, "待支付"),
|
||||||
|
TRADE_CLOSED(2, "已关闭"),
|
||||||
|
TRADE_SUCCESS(3, "支付成功"),
|
||||||
|
TRADE_FINISHED(3, "支付成功"),
|
||||||
|
;
|
||||||
|
private final int value;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
PayStatus(int value, String desc) {
|
||||||
|
this.value = value;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalsValue(Integer value){
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getValue() == value;
|
||||||
|
}
|
||||||
|
}
|
27
hm-service/src/main/java/com/hmall/enums/PayType.java
Normal file
27
hm-service/src/main/java/com/hmall/enums/PayType.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package com.hmall.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum PayType{
|
||||||
|
JSAPI(1, "网页支付JS"),
|
||||||
|
MINI_APP(2, "小程序支付"),
|
||||||
|
APP(3, "APP支付"),
|
||||||
|
NATIVE(4, "扫码支付"),
|
||||||
|
BALANCE(5, "余额支付"),
|
||||||
|
;
|
||||||
|
private final int value;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
PayType(int value, String desc) {
|
||||||
|
this.value = value;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equalsValue(Integer value){
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return getValue() == value;
|
||||||
|
}
|
||||||
|
}
|
30
hm-service/src/main/java/com/hmall/enums/UserStatus.java
Normal file
30
hm-service/src/main/java/com/hmall/enums/UserStatus.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.hmall.enums;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||||
|
import com.hmall.common.exception.BadRequestException;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum UserStatus {
|
||||||
|
FROZEN(0, "禁止使用"),
|
||||||
|
NORMAL(1, "已激活"),
|
||||||
|
;
|
||||||
|
@EnumValue
|
||||||
|
int value;
|
||||||
|
String desc;
|
||||||
|
|
||||||
|
UserStatus(Integer value, String desc) {
|
||||||
|
this.value = value;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserStatus of(int value) {
|
||||||
|
if (value == 0) {
|
||||||
|
return FROZEN;
|
||||||
|
}
|
||||||
|
if (value == 1) {
|
||||||
|
return NORMAL;
|
||||||
|
}
|
||||||
|
throw new BadRequestException("账户状态错误");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.hmall.interceptor;
|
||||||
|
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.utils.JwtTool;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LoginInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final JwtTool jwtTool;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
// 1.获取请求头中的 token
|
||||||
|
String token = request.getHeader("authorization");
|
||||||
|
// 2.校验token
|
||||||
|
Long userId = jwtTool.parseToken(token);
|
||||||
|
// 3.存入上下文
|
||||||
|
UserContext.setUser(userId);
|
||||||
|
// 4.放行
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
|
// 清理用户
|
||||||
|
UserContext.removeUser();
|
||||||
|
}
|
||||||
|
}
|
16
hm-service/src/main/java/com/hmall/mapper/AddressMapper.java
Normal file
16
hm-service/src/main/java/com/hmall/mapper/AddressMapper.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.Address;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface AddressMapper extends BaseMapper<Address> {
|
||||||
|
|
||||||
|
}
|
20
hm-service/src/main/java/com/hmall/mapper/CartMapper.java
Normal file
20
hm-service/src/main/java/com/hmall/mapper/CartMapper.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.Cart;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface CartMapper extends BaseMapper<Cart> {
|
||||||
|
|
||||||
|
@Update("UPDATE cart SET num = num + 1 WHERE user_id = #{userId} AND item_id = #{itemId}")
|
||||||
|
void updateNum(@Param("itemId") Long itemId, @Param("userId") Long userId);
|
||||||
|
}
|
21
hm-service/src/main/java/com/hmall/mapper/ItemMapper.java
Normal file
21
hm-service/src/main/java/com/hmall/mapper/ItemMapper.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.OrderDetailDTO;
|
||||||
|
import com.hmall.domain.po.Item;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 商品表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface ItemMapper extends BaseMapper<Item> {
|
||||||
|
|
||||||
|
@Update("UPDATE item SET stock = stock - #{num} WHERE id = #{itemId}")
|
||||||
|
void updateStock(OrderDetailDTO orderDetail);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderDetail;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface OrderDetailMapper extends BaseMapper<OrderDetail> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderLogistics;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface OrderLogisticsMapper extends BaseMapper<OrderLogistics> {
|
||||||
|
|
||||||
|
}
|
16
hm-service/src/main/java/com/hmall/mapper/OrderMapper.java
Normal file
16
hm-service/src/main/java/com/hmall/mapper/OrderMapper.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.Order;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface OrderMapper extends BaseMapper<Order> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.PayOrder;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 支付订单 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-16
|
||||||
|
*/
|
||||||
|
public interface PayOrderMapper extends BaseMapper<PayOrder> {
|
||||||
|
|
||||||
|
}
|
19
hm-service/src/main/java/com/hmall/mapper/UserMapper.java
Normal file
19
hm-service/src/main/java/com/hmall/mapper/UserMapper.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.hmall.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.hmall.domain.po.User;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface UserMapper extends BaseMapper<User> {
|
||||||
|
@Update("update user set balance = balance - ${totalFee} where id = #{userId}")
|
||||||
|
void updateMoney(@Param("userId") Long userId, @Param("totalFee") Integer totalFee);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.Address;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IAddressService extends IService<Address> {
|
||||||
|
|
||||||
|
}
|
26
hm-service/src/main/java/com/hmall/service/ICartService.java
Normal file
26
hm-service/src/main/java/com/hmall/service/ICartService.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hmall.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.domain.po.Cart;
|
||||||
|
import com.hmall.domain.vo.CartVO;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface ICartService extends IService<Cart> {
|
||||||
|
|
||||||
|
void addItem2Cart(CartFormDTO cartFormDTO);
|
||||||
|
|
||||||
|
List<CartVO> queryMyCarts();
|
||||||
|
|
||||||
|
void removeByItemIds(Collection<Long> itemIds);
|
||||||
|
}
|
24
hm-service/src/main/java/com/hmall/service/IItemService.java
Normal file
24
hm-service/src/main/java/com/hmall/service/IItemService.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.dto.OrderDetailDTO;
|
||||||
|
import com.hmall.domain.po.Item;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 商品表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IItemService extends IService<Item> {
|
||||||
|
|
||||||
|
void deductStock(List<OrderDetailDTO> items);
|
||||||
|
|
||||||
|
List<ItemDTO> queryItemByIds(Collection<Long> ids);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderDetail;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IOrderDetailService extends IService<OrderDetail> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderLogistics;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IOrderLogisticsService extends IService<OrderLogistics> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.OrderFormDTO;
|
||||||
|
import com.hmall.domain.po.Order;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IOrderService extends IService<Order> {
|
||||||
|
|
||||||
|
Long createOrder(OrderFormDTO orderFormDTO);
|
||||||
|
|
||||||
|
void markOrderPaySuccess(Long orderId);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.PayApplyDTO;
|
||||||
|
import com.hmall.domain.dto.PayOrderFormDTO;
|
||||||
|
import com.hmall.domain.po.PayOrder;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 支付订单 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-16
|
||||||
|
*/
|
||||||
|
public interface IPayOrderService extends IService<PayOrder> {
|
||||||
|
|
||||||
|
String applyPayOrder(PayApplyDTO applyDTO);
|
||||||
|
|
||||||
|
void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO);
|
||||||
|
}
|
21
hm-service/src/main/java/com/hmall/service/IUserService.java
Normal file
21
hm-service/src/main/java/com/hmall/service/IUserService.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.hmall.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hmall.domain.dto.LoginFormDTO;
|
||||||
|
import com.hmall.domain.po.User;
|
||||||
|
import com.hmall.domain.vo.UserLoginVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
public interface IUserService extends IService<User> {
|
||||||
|
|
||||||
|
UserLoginVO login(LoginFormDTO loginFormDTO);
|
||||||
|
|
||||||
|
void deductMoney(String pw, Integer totalFee);
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.Address;
|
||||||
|
import com.hmall.mapper.AddressMapper;
|
||||||
|
import com.hmall.service.IAddressService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements IAddressService {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.common.utils.CollUtils;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.domain.dto.CartFormDTO;
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.po.Cart;
|
||||||
|
import com.hmall.domain.vo.CartVO;
|
||||||
|
import com.hmall.mapper.CartMapper;
|
||||||
|
import com.hmall.service.ICartService;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {
|
||||||
|
|
||||||
|
private final IItemService itemService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addItem2Cart(CartFormDTO cartFormDTO) {
|
||||||
|
// 1.获取登录用户
|
||||||
|
Long userId = UserContext.getUser();
|
||||||
|
|
||||||
|
// 2.判断是否已经存在
|
||||||
|
if(checkItemExists(cartFormDTO.getItemId(), userId)){
|
||||||
|
// 2.1.存在,则更新数量
|
||||||
|
baseMapper.updateNum(cartFormDTO.getItemId(), userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2.2.不存在,判断是否超过购物车数量
|
||||||
|
checkCartsFull(userId);
|
||||||
|
|
||||||
|
// 3.新增购物车条目
|
||||||
|
// 3.1.转换PO
|
||||||
|
Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
|
||||||
|
// 3.2.保存当前用户
|
||||||
|
cart.setUserId(userId);
|
||||||
|
// 3.3.保存到数据库
|
||||||
|
save(cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CartVO> queryMyCarts() {
|
||||||
|
// 1.查询我的购物车列表
|
||||||
|
List<Cart> carts = lambdaQuery().eq(Cart::getUserId, UserContext.getUser()).list();
|
||||||
|
if (CollUtils.isEmpty(carts)) {
|
||||||
|
return CollUtils.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.转换VO
|
||||||
|
List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);
|
||||||
|
|
||||||
|
// 3.处理VO中的商品信息
|
||||||
|
handleCartItems(vos);
|
||||||
|
|
||||||
|
// 4.返回
|
||||||
|
return vos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCartItems(List<CartVO> vos) {
|
||||||
|
// 1.获取商品id
|
||||||
|
Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
|
||||||
|
// 2.查询商品
|
||||||
|
List<ItemDTO> items = itemService.queryItemByIds(itemIds);
|
||||||
|
if (CollUtils.isEmpty(items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 3.转为 id 到 item的map
|
||||||
|
Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
|
||||||
|
// 4.写入vo
|
||||||
|
for (CartVO v : vos) {
|
||||||
|
ItemDTO item = itemMap.get(v.getItemId());
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
v.setNewPrice(item.getPrice());
|
||||||
|
v.setStatus(item.getStatus());
|
||||||
|
v.setStock(item.getStock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeByItemIds(Collection<Long> itemIds) {
|
||||||
|
// 1.构建删除条件,userId和itemId
|
||||||
|
QueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();
|
||||||
|
queryWrapper.lambda()
|
||||||
|
.eq(Cart::getUserId, UserContext.getUser())
|
||||||
|
.in(Cart::getItemId, itemIds);
|
||||||
|
// 2.删除
|
||||||
|
remove(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCartsFull(Long userId) {
|
||||||
|
long count = lambdaQuery()
|
||||||
|
.eq(Cart::getUserId, userId)
|
||||||
|
.count(); // ← 这里返回 long
|
||||||
|
if (count >= 10) {
|
||||||
|
throw new BizIllegalException(
|
||||||
|
StrUtil.format("用户购物车课程不能超过{}", 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkItemExists(Long itemId, Long userId) {
|
||||||
|
long count = lambdaQuery()
|
||||||
|
.eq(Cart::getUserId, userId)
|
||||||
|
.eq(Cart::getItemId, itemId)
|
||||||
|
.count();
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.dto.OrderDetailDTO;
|
||||||
|
import com.hmall.domain.po.Item;
|
||||||
|
import com.hmall.mapper.ItemMapper;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 商品表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deductStock(List<OrderDetailDTO> items) {
|
||||||
|
String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
|
||||||
|
boolean r = false;
|
||||||
|
try {
|
||||||
|
r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BizIllegalException("更新库存异常,可能是库存不足!", e);
|
||||||
|
}
|
||||||
|
if (!r) {
|
||||||
|
throw new BizIllegalException("库存不足!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
|
||||||
|
return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderDetail;
|
||||||
|
import com.hmall.mapper.OrderDetailMapper;
|
||||||
|
import com.hmall.service.IOrderDetailService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 订单详情表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class OrderDetailServiceImpl extends ServiceImpl<OrderDetailMapper, OrderDetail> implements IOrderDetailService {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.hmall.domain.po.OrderLogistics;
|
||||||
|
import com.hmall.mapper.OrderLogisticsMapper;
|
||||||
|
import com.hmall.service.IOrderLogisticsService;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class OrderLogisticsServiceImpl extends ServiceImpl<OrderLogisticsMapper, OrderLogistics> implements IOrderLogisticsService {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.common.exception.BadRequestException;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.domain.dto.ItemDTO;
|
||||||
|
import com.hmall.domain.dto.OrderDetailDTO;
|
||||||
|
import com.hmall.domain.dto.OrderFormDTO;
|
||||||
|
import com.hmall.domain.po.Order;
|
||||||
|
import com.hmall.domain.po.OrderDetail;
|
||||||
|
import com.hmall.mapper.OrderMapper;
|
||||||
|
import com.hmall.service.ICartService;
|
||||||
|
import com.hmall.service.IItemService;
|
||||||
|
import com.hmall.service.IOrderDetailService;
|
||||||
|
import com.hmall.service.IOrderService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-05
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
|
||||||
|
|
||||||
|
private final IItemService itemService;
|
||||||
|
private final IOrderDetailService detailService;
|
||||||
|
private final ICartService cartService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public Long createOrder(OrderFormDTO orderFormDTO) {
|
||||||
|
// 1.订单数据
|
||||||
|
Order order = new Order();
|
||||||
|
// 1.1.查询商品
|
||||||
|
List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();
|
||||||
|
// 1.2.获取商品id和数量的Map
|
||||||
|
Map<Long, Integer> itemNumMap = detailDTOS.stream()
|
||||||
|
.collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));
|
||||||
|
Set<Long> itemIds = itemNumMap.keySet();
|
||||||
|
// 1.3.查询商品
|
||||||
|
List<ItemDTO> items = itemService.queryItemByIds(itemIds);
|
||||||
|
if (items == null || items.size() < itemIds.size()) {
|
||||||
|
throw new BadRequestException("商品不存在");
|
||||||
|
}
|
||||||
|
// 1.4.基于商品价格、购买数量计算商品总价:totalFee
|
||||||
|
int total = 0;
|
||||||
|
for (ItemDTO item : items) {
|
||||||
|
total += item.getPrice() * itemNumMap.get(item.getId());
|
||||||
|
}
|
||||||
|
order.setTotalFee(total);
|
||||||
|
// 1.5.其它属性
|
||||||
|
order.setPaymentType(orderFormDTO.getPaymentType());
|
||||||
|
order.setUserId(UserContext.getUser());
|
||||||
|
order.setStatus(1);
|
||||||
|
// 1.6.将Order写入数据库order表中
|
||||||
|
save(order);
|
||||||
|
|
||||||
|
// 2.保存订单详情
|
||||||
|
List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);
|
||||||
|
detailService.saveBatch(details);
|
||||||
|
|
||||||
|
// 3.清理购物车商品
|
||||||
|
cartService.removeByItemIds(itemIds);
|
||||||
|
|
||||||
|
// 4.扣减库存
|
||||||
|
try {
|
||||||
|
itemService.deductStock(detailDTOS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("库存不足!");
|
||||||
|
}
|
||||||
|
return order.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markOrderPaySuccess(Long orderId) {
|
||||||
|
Order order = new Order();
|
||||||
|
order.setId(orderId);
|
||||||
|
order.setStatus(2);
|
||||||
|
order.setPayTime(LocalDateTime.now());
|
||||||
|
updateById(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<OrderDetail> buildDetails(Long orderId, List<ItemDTO> items, Map<Long, Integer> numMap) {
|
||||||
|
List<OrderDetail> details = new ArrayList<>(items.size());
|
||||||
|
for (ItemDTO item : items) {
|
||||||
|
OrderDetail detail = new OrderDetail();
|
||||||
|
detail.setName(item.getName());
|
||||||
|
detail.setSpec(item.getSpec());
|
||||||
|
detail.setPrice(item.getPrice());
|
||||||
|
detail.setNum(numMap.get(item.getId()));
|
||||||
|
detail.setItemId(item.getId());
|
||||||
|
detail.setImage(item.getImage());
|
||||||
|
detail.setOrderId(orderId);
|
||||||
|
details.add(detail);
|
||||||
|
}
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.common.utils.BeanUtils;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.domain.dto.PayApplyDTO;
|
||||||
|
import com.hmall.domain.dto.PayOrderFormDTO;
|
||||||
|
import com.hmall.domain.po.Order;
|
||||||
|
import com.hmall.domain.po.PayOrder;
|
||||||
|
import com.hmall.enums.PayStatus;
|
||||||
|
import com.hmall.mapper.PayOrderMapper;
|
||||||
|
import com.hmall.service.IOrderService;
|
||||||
|
import com.hmall.service.IPayOrderService;
|
||||||
|
import com.hmall.service.IUserService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 支付订单 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
* @since 2023-05-16
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
|
||||||
|
|
||||||
|
private final IUserService userService;
|
||||||
|
|
||||||
|
private final IOrderService orderService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String applyPayOrder(PayApplyDTO applyDTO) {
|
||||||
|
// 1.幂等性校验
|
||||||
|
PayOrder payOrder = checkIdempotent(applyDTO);
|
||||||
|
// 2.返回结果
|
||||||
|
return payOrder.getId().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO) {
|
||||||
|
// 1.查询支付单
|
||||||
|
PayOrder po = getById(payOrderFormDTO.getId());
|
||||||
|
// 2.判断状态
|
||||||
|
if(!PayStatus.WAIT_BUYER_PAY.equalsValue(po.getStatus())){
|
||||||
|
// 订单不是未支付,状态异常
|
||||||
|
throw new BizIllegalException("交易已支付或关闭!");
|
||||||
|
}
|
||||||
|
// 3.尝试扣减余额
|
||||||
|
userService.deductMoney(payOrderFormDTO.getPw(), po.getAmount());
|
||||||
|
// 4.修改支付单状态
|
||||||
|
boolean success = markPayOrderSuccess(payOrderFormDTO.getId(), LocalDateTime.now());
|
||||||
|
if (!success) {
|
||||||
|
throw new BizIllegalException("交易已支付或关闭!");
|
||||||
|
}
|
||||||
|
// 5.修改订单状态
|
||||||
|
Order order = new Order();
|
||||||
|
order.setId(po.getBizOrderNo());
|
||||||
|
order.setStatus(2);
|
||||||
|
order.setPayTime(LocalDateTime.now());
|
||||||
|
orderService.updateById(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean markPayOrderSuccess(Long id, LocalDateTime successTime) {
|
||||||
|
return lambdaUpdate()
|
||||||
|
.set(PayOrder::getStatus, PayStatus.TRADE_SUCCESS.getValue())
|
||||||
|
.set(PayOrder::getPaySuccessTime, successTime)
|
||||||
|
.eq(PayOrder::getId, id)
|
||||||
|
// 支付状态的乐观锁判断
|
||||||
|
.in(PayOrder::getStatus, PayStatus.NOT_COMMIT.getValue(), PayStatus.WAIT_BUYER_PAY.getValue())
|
||||||
|
.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private PayOrder checkIdempotent(PayApplyDTO applyDTO) {
|
||||||
|
// 1.首先查询支付单
|
||||||
|
PayOrder oldOrder = queryByBizOrderNo(applyDTO.getBizOrderNo());
|
||||||
|
// 2.判断是否存在
|
||||||
|
if (oldOrder == null) {
|
||||||
|
// 不存在支付单,说明是第一次,写入新的支付单并返回
|
||||||
|
PayOrder payOrder = buildPayOrder(applyDTO);
|
||||||
|
payOrder.setPayOrderNo(IdWorker.getId());
|
||||||
|
save(payOrder);
|
||||||
|
return payOrder;
|
||||||
|
}
|
||||||
|
// 3.旧单已经存在,判断是否支付成功
|
||||||
|
if (PayStatus.TRADE_SUCCESS.equalsValue(oldOrder.getStatus())) {
|
||||||
|
// 已经支付成功,抛出异常
|
||||||
|
throw new BizIllegalException("订单已经支付!");
|
||||||
|
}
|
||||||
|
// 4.旧单已经存在,判断是否已经关闭
|
||||||
|
if (PayStatus.TRADE_CLOSED.equalsValue(oldOrder.getStatus())) {
|
||||||
|
// 已经关闭,抛出异常
|
||||||
|
throw new BizIllegalException("订单已关闭");
|
||||||
|
}
|
||||||
|
// 5.旧单已经存在,判断支付渠道是否一致
|
||||||
|
if (!StringUtils.equals(oldOrder.getPayChannelCode(), applyDTO.getPayChannelCode())) {
|
||||||
|
// 支付渠道不一致,需要重置数据,然后重新申请支付单
|
||||||
|
PayOrder payOrder = buildPayOrder(applyDTO);
|
||||||
|
payOrder.setId(oldOrder.getId());
|
||||||
|
payOrder.setQrCodeUrl("");
|
||||||
|
updateById(payOrder);
|
||||||
|
payOrder.setPayOrderNo(oldOrder.getPayOrderNo());
|
||||||
|
return payOrder;
|
||||||
|
}
|
||||||
|
// 6.旧单已经存在,且可能是未支付或未提交,且支付渠道一致,直接返回旧数据
|
||||||
|
return oldOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PayOrder buildPayOrder(PayApplyDTO payApplyDTO) {
|
||||||
|
// 1.数据转换
|
||||||
|
PayOrder payOrder = BeanUtils.toBean(payApplyDTO, PayOrder.class);
|
||||||
|
// 2.初始化数据
|
||||||
|
payOrder.setPayOverTime(LocalDateTime.now().plusMinutes(120L));
|
||||||
|
payOrder.setStatus(PayStatus.WAIT_BUYER_PAY.getValue());
|
||||||
|
payOrder.setBizUserId(UserContext.getUser());
|
||||||
|
return payOrder;
|
||||||
|
}
|
||||||
|
public PayOrder queryByBizOrderNo(Long bizOrderNo) {
|
||||||
|
return lambdaQuery()
|
||||||
|
.eq(PayOrder::getBizOrderNo, bizOrderNo)
|
||||||
|
.one();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.hmall.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hmall.common.exception.BadRequestException;
|
||||||
|
import com.hmall.common.exception.BizIllegalException;
|
||||||
|
import com.hmall.common.exception.ForbiddenException;
|
||||||
|
import com.hmall.common.utils.UserContext;
|
||||||
|
import com.hmall.config.JwtProperties;
|
||||||
|
import com.hmall.domain.dto.LoginFormDTO;
|
||||||
|
import com.hmall.domain.po.User;
|
||||||
|
import com.hmall.domain.vo.UserLoginVO;
|
||||||
|
import com.hmall.enums.UserStatus;
|
||||||
|
import com.hmall.mapper.UserMapper;
|
||||||
|
import com.hmall.service.IUserService;
|
||||||
|
import com.hmall.utils.JwtTool;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 虎哥
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
|
||||||
|
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
private final JwtTool jwtTool;
|
||||||
|
|
||||||
|
private final JwtProperties jwtProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserLoginVO login(LoginFormDTO loginDTO) {
|
||||||
|
// 1.数据校验
|
||||||
|
String username = loginDTO.getUsername();
|
||||||
|
String password = loginDTO.getPassword();
|
||||||
|
// 2.根据用户名或手机号查询
|
||||||
|
User user = lambdaQuery().eq(User::getUsername, username).one();
|
||||||
|
Assert.notNull(user, "用户名错误");
|
||||||
|
// 3.校验是否禁用
|
||||||
|
if (user.getStatus() == UserStatus.FROZEN) {
|
||||||
|
throw new ForbiddenException("用户被冻结");
|
||||||
|
}
|
||||||
|
// 4.校验密码
|
||||||
|
if (!passwordEncoder.matches(password, user.getPassword())) {
|
||||||
|
throw new BadRequestException("用户名或密码错误");
|
||||||
|
}
|
||||||
|
// 5.生成TOKEN
|
||||||
|
String token = jwtTool.createToken(user.getId(), jwtProperties.getTokenTTL());
|
||||||
|
// 6.封装VO返回
|
||||||
|
UserLoginVO vo = new UserLoginVO();
|
||||||
|
vo.setUserId(user.getId());
|
||||||
|
vo.setUsername(user.getUsername());
|
||||||
|
vo.setBalance(user.getBalance());
|
||||||
|
vo.setToken(token);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deductMoney(String pw, Integer totalFee) {
|
||||||
|
log.info("开始扣款");
|
||||||
|
// 1.校验密码
|
||||||
|
User user = getById(UserContext.getUser());
|
||||||
|
if(user == null || !passwordEncoder.matches(pw, user.getPassword())){
|
||||||
|
// 密码错误
|
||||||
|
throw new BizIllegalException("用户密码错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.尝试扣款
|
||||||
|
try {
|
||||||
|
baseMapper.updateMoney(UserContext.getUser(), totalFee);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("扣款失败,可能是余额不足!", e);
|
||||||
|
}
|
||||||
|
log.info("扣款成功");
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user