diff --git a/cart-service/pom.xml b/cart-service/pom.xml
index 99e8c61..4a58ef4 100644
--- a/cart-service/pom.xml
+++ b/cart-service/pom.xml
@@ -10,6 +10,7 @@
4.0.0
cart-service
+ 1.0.0
17
@@ -44,7 +45,11 @@
1.0.0
compile
-
+
+ com.heima
+ hm-api
+ 1.0.0
+
${project.artifactId}
diff --git a/cart-service/src/main/java/com/hmall/cart/CartApplication.java b/cart-service/src/main/java/com/hmall/cart/CartApplication.java
index 502a1e7..3177507 100644
--- a/cart-service/src/main/java/com/hmall/cart/CartApplication.java
+++ b/cart-service/src/main/java/com/hmall/cart/CartApplication.java
@@ -3,8 +3,10 @@ package com.hmall.cart;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.hmall.cart.mapper")
+@EnableFeignClients(basePackages= "com.hmall.api.client")
@SpringBootApplication
public class CartApplication {
public static void main(String[] args) {
diff --git a/cart-service/src/main/java/com/hmall/cart/service/impl/CartServiceImpl.java b/cart-service/src/main/java/com/hmall/cart/service/impl/CartServiceImpl.java
index ccdec09..4aeefad 100644
--- a/cart-service/src/main/java/com/hmall/cart/service/impl/CartServiceImpl.java
+++ b/cart-service/src/main/java/com/hmall/cart/service/impl/CartServiceImpl.java
@@ -3,6 +3,9 @@ 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.api.client.ItemClient;
+import com.hmall.api.dto.ItemDTO;
import com.hmall.cart.domain.dto.CartFormDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
@@ -12,9 +15,6 @@ 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;
@@ -37,7 +37,8 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl implements ICartService {
-// private final IItemService itemService;
+ private final ItemClient itemClient; //@RequiredArgsConstructor会为final字段生成构造器
+
@Override
public void addItem2Cart(CartFormDTO cartFormDTO) {
@@ -81,25 +82,25 @@ public class CartServiceImpl extends ServiceImpl implements IC
}
private void handleCartItems(List vos) {
-// // 1.获取商品id
-// Set itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
-// // 2.查询商品
-// List items = itemService.queryItemByIds(itemIds);
-// if (CollUtils.isEmpty(items)) {
-// return;
-// }
-// // 3.转为 id 到 item的map
-// Map 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());
-// }
+ // 1.获取商品id
+ Set itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
+ // 2.查询商品
+ List items = itemClient.queryItemByIds(itemIds);
+ if (CollUtils.isEmpty(items)) {
+ return;
+ }
+ // 3.转为 id 到 item的map
+ Map 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
diff --git a/cart-service/src/main/resources/application-local.yaml b/cart-service/src/main/resources/application-local.yaml
index 707fb24..e310359 100644
--- a/cart-service/src/main/resources/application-local.yaml
+++ b/cart-service/src/main/resources/application-local.yaml
@@ -1,4 +1,4 @@
hm:
db:
- host: localhost # 修改为你自己的虚拟机IP地址
+ host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
pw: 123456 # 修改为docker中的MySQL密码
\ No newline at end of file
diff --git a/cart-service/src/main/resources/application.yaml b/cart-service/src/main/resources/application.yaml
index 78d6525..b8320b9 100644
--- a/cart-service/src/main/resources/application.yaml
+++ b/cart-service/src/main/resources/application.yaml
@@ -40,4 +40,8 @@ knife4j:
api-rule-resources:
- com.hmall.cart.controller
+feign:
+ httpclient:
+ enabled: true # 使用 Apache HttpClient(默认关闭)
+
# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
\ No newline at end of file
diff --git a/hm-api/pom.xml b/hm-api/pom.xml
new file mode 100644
index 0000000..556f683
--- /dev/null
+++ b/hm-api/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+ hmall
+ com.heima
+ 1.0.0
+
+ 4.0.0
+
+ hm-api
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+ io.github.openfeign
+ feign-httpclient
+
+
+ io.swagger
+ swagger-annotations
+ 1.6.6
+ compile
+
+
+
+ 17
+ 17
+
+
+
\ No newline at end of file
diff --git a/hm-api/src/main/java/com/hmall/api/client/ItemClient.java b/hm-api/src/main/java/com/hmall/api/client/ItemClient.java
new file mode 100644
index 0000000..c4369f4
--- /dev/null
+++ b/hm-api/src/main/java/com/hmall/api/client/ItemClient.java
@@ -0,0 +1,16 @@
+package com.hmall.api.client;
+
+import com.hmall.api.dto.ItemDTO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Collection;
+import java.util.List;
+
+@FeignClient("item-service")
+public interface ItemClient {
+
+ @GetMapping("/items")
+ List queryItemByIds(@RequestParam("ids") Collection ids);
+}
diff --git a/hm-api/src/main/java/com/hmall/api/dto/ItemDTO.java b/hm-api/src/main/java/com/hmall/api/dto/ItemDTO.java
new file mode 100644
index 0000000..74417bb
--- /dev/null
+++ b/hm-api/src/main/java/com/hmall/api/dto/ItemDTO.java
@@ -0,0 +1,34 @@
+package com.hmall.api.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;
+}
diff --git a/hm-service/src/main/resources/application-local.yaml b/hm-service/src/main/resources/application-local.yaml
index 707fb24..e310359 100644
--- a/hm-service/src/main/resources/application-local.yaml
+++ b/hm-service/src/main/resources/application-local.yaml
@@ -1,4 +1,4 @@
hm:
db:
- host: localhost # 修改为你自己的虚拟机IP地址
+ host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
pw: 123456 # 修改为docker中的MySQL密码
\ No newline at end of file
diff --git a/item-service/pom.xml b/item-service/pom.xml
index eb305e1..2ce3832 100644
--- a/item-service/pom.xml
+++ b/item-service/pom.xml
@@ -44,7 +44,11 @@
1.0.0
compile
-
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
${project.artifactId}
diff --git a/item-service/src/main/resources/application-local.yaml b/item-service/src/main/resources/application-local.yaml
index 707fb24..e310359 100644
--- a/item-service/src/main/resources/application-local.yaml
+++ b/item-service/src/main/resources/application-local.yaml
@@ -1,4 +1,4 @@
hm:
db:
- host: localhost # 修改为你自己的虚拟机IP地址
+ host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
pw: 123456 # 修改为docker中的MySQL密码
\ No newline at end of file
diff --git a/item-service/src/main/resources/application.yaml b/item-service/src/main/resources/application.yaml
index b564328..73ef548 100644
--- a/item-service/src/main/resources/application.yaml
+++ b/item-service/src/main/resources/application.yaml
@@ -3,6 +3,10 @@ server:
spring:
application:
name: item-service
+ cloud:
+ nacos:
+ server-addr: 124.71.159.195:8848 # nacos地址
+
profiles:
active: local
datasource:
diff --git a/pom.xml b/pom.xml
index cb6c1c0..e3e704b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,7 @@
item-service
cart-service
user-service
+ hm-api
diff --git a/user-service/pom.xml b/user-service/pom.xml
index 4629c82..c7c5cb8 100644
--- a/user-service/pom.xml
+++ b/user-service/pom.xml
@@ -15,5 +15,53 @@
17
17
+
+
+ com.heima
+ hm-api
+ 1.0.0
+
+
+
+ com.heima
+ hm-common
+ 1.0.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+
+
+ com.heima
+ hm-service
+ 1.0.0
+ compile
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
\ No newline at end of file
diff --git a/user-service/src/main/java/com/hmall/user/UserApplication.java b/user-service/src/main/java/com/hmall/user/UserApplication.java
new file mode 100644
index 0000000..2dc4197
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/UserApplication.java
@@ -0,0 +1,16 @@
+package com.hmall.user;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@MapperScan("com.hmall.user.mapper")
+@EnableFeignClients(basePackages= "com.hmall.api.client")
+@SpringBootApplication
+public class UserApplication {
+ public static void main(String[] args) {
+
+ SpringApplication.run(UserApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/hmall/user/config/JwtProperties.java b/user-service/src/main/java/com/hmall/user/config/JwtProperties.java
new file mode 100644
index 0000000..7ab2ac6
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/config/JwtProperties.java
@@ -0,0 +1,16 @@
+package com.hmall.user.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);
+}
diff --git a/user-service/src/main/java/com/hmall/user/config/SecurityConfig.java b/user-service/src/main/java/com/hmall/user/config/SecurityConfig.java
new file mode 100644
index 0000000..28ddb3b
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/config/SecurityConfig.java
@@ -0,0 +1,33 @@
+package com.hmall.user.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());
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/hmall/user/controller/AddressController.java b/user-service/src/main/java/com/hmall/user/controller/AddressController.java
new file mode 100644
index 0000000..bc19559
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/controller/AddressController.java
@@ -0,0 +1,61 @@
+package com.hmall.user.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.user.domain.po.Address;
+
+import com.hmall.user.domain.dto.AddressDTO;
+import com.hmall.user.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;
+
+/**
+ *
+ * 前端控制器
+ *
+ *
+ * @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 findMyAddresses() {
+ // 1.查询列表
+ List 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);
+ }
+}
diff --git a/user-service/src/main/java/com/hmall/user/controller/UserController.java b/user-service/src/main/java/com/hmall/user/controller/UserController.java
new file mode 100644
index 0000000..9b49be3
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/controller/UserController.java
@@ -0,0 +1,39 @@
+package com.hmall.user.controller;
+
+
+import com.hmall.user.domain.dto.LoginFormDTO;
+import com.hmall.user.domain.vo.UserLoginVO;
+import com.hmall.user.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);
+ }
+}
+
diff --git a/user-service/src/main/java/com/hmall/user/domain/dto/AddressDTO.java b/user-service/src/main/java/com/hmall/user/domain/dto/AddressDTO.java
new file mode 100644
index 0000000..d21b7d0
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/domain/dto/AddressDTO.java
@@ -0,0 +1,28 @@
+package com.hmall.user.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;
+}
diff --git a/user-service/src/main/java/com/hmall/user/domain/dto/LoginFormDTO.java b/user-service/src/main/java/com/hmall/user/domain/dto/LoginFormDTO.java
new file mode 100644
index 0000000..a1b6122
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/domain/dto/LoginFormDTO.java
@@ -0,0 +1,20 @@
+package com.hmall.user.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;
+}
diff --git a/user-service/src/main/java/com/hmall/user/domain/po/Address.java b/user-service/src/main/java/com/hmall/user/domain/po/Address.java
new file mode 100644
index 0000000..2e1728c
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/domain/po/Address.java
@@ -0,0 +1,77 @@
+package com.hmall.user.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;
+
+/**
+ *
+ *
+ *
+ *
+ * @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;
+
+
+}
diff --git a/user-service/src/main/java/com/hmall/user/domain/po/User.java b/user-service/src/main/java/com/hmall/user/domain/po/User.java
new file mode 100644
index 0000000..5880699
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/domain/po/User.java
@@ -0,0 +1,67 @@
+package com.hmall.user.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import com.hmall.user.enums.UserStatus;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ *
+ * 用户表
+ *
+ *
+ * @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;
+
+
+}
diff --git a/user-service/src/main/java/com/hmall/user/domain/vo/UserLoginVO.java b/user-service/src/main/java/com/hmall/user/domain/vo/UserLoginVO.java
new file mode 100644
index 0000000..d1dbcfa
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/domain/vo/UserLoginVO.java
@@ -0,0 +1,11 @@
+package com.hmall.user.domain.vo;
+
+import lombok.Data;
+
+@Data
+public class UserLoginVO {
+ private String token;
+ private Long userId;
+ private String username;
+ private Integer balance;
+}
diff --git a/user-service/src/main/java/com/hmall/user/enums/UserStatus.java b/user-service/src/main/java/com/hmall/user/enums/UserStatus.java
new file mode 100644
index 0000000..ad7f526
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/enums/UserStatus.java
@@ -0,0 +1,30 @@
+package com.hmall.user.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("账户状态错误");
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/java/com/hmall/user/mapper/AddressMapper.java b/user-service/src/main/java/com/hmall/user/mapper/AddressMapper.java
new file mode 100644
index 0000000..7ad8a5a
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/mapper/AddressMapper.java
@@ -0,0 +1,17 @@
+package com.hmall.user.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.hmall.user.domain.po.Address;
+
+
+/**
+ *
+ * Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2023-05-05
+ */
+public interface AddressMapper extends BaseMapper {
+
+}
diff --git a/user-service/src/main/java/com/hmall/user/mapper/UserMapper.java b/user-service/src/main/java/com/hmall/user/mapper/UserMapper.java
new file mode 100644
index 0000000..afc55e7
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/mapper/UserMapper.java
@@ -0,0 +1,20 @@
+package com.hmall.user.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.hmall.user.domain.po.User;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ *
+ * 用户表 Mapper 接口
+ *
+ *
+ * @author 虎哥
+ * @since 2023-05-05
+ */
+public interface UserMapper extends BaseMapper {
+ @Update("update user set balance = balance - ${totalFee} where id = #{userId}")
+ void updateMoney(@Param("userId") Long userId, @Param("totalFee") Integer totalFee);
+}
diff --git a/user-service/src/main/java/com/hmall/user/service/IAddressService.java b/user-service/src/main/java/com/hmall/user/service/IAddressService.java
new file mode 100644
index 0000000..a62ca76
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/service/IAddressService.java
@@ -0,0 +1,17 @@
+package com.hmall.user.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.hmall.user.domain.po.Address;
+
+
+/**
+ *
+ * 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2023-05-05
+ */
+public interface IAddressService extends IService {
+
+}
diff --git a/user-service/src/main/java/com/hmall/user/service/IUserService.java b/user-service/src/main/java/com/hmall/user/service/IUserService.java
new file mode 100644
index 0000000..9b46bf6
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/service/IUserService.java
@@ -0,0 +1,22 @@
+package com.hmall.user.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.hmall.user.domain.dto.LoginFormDTO;
+import com.hmall.user.domain.po.User;
+import com.hmall.user.domain.vo.UserLoginVO;
+
+
+/**
+ *
+ * 用户表 服务类
+ *
+ *
+ * @author 虎哥
+ * @since 2023-05-05
+ */
+public interface IUserService extends IService {
+
+ UserLoginVO login(LoginFormDTO loginFormDTO);
+
+ void deductMoney(String pw, Integer totalFee);
+}
diff --git a/user-service/src/main/java/com/hmall/user/service/impl/AddressServiceImpl.java b/user-service/src/main/java/com/hmall/user/service/impl/AddressServiceImpl.java
new file mode 100644
index 0000000..61e19b5
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/service/impl/AddressServiceImpl.java
@@ -0,0 +1,21 @@
+package com.hmall.user.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.hmall.user.domain.po.Address;
+import com.hmall.user.mapper.AddressMapper;
+import com.hmall.user.service.IAddressService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * 服务实现类
+ *
+ *
+ * @author 虎哥
+ * @since 2023-05-05
+ */
+@Service
+public class AddressServiceImpl extends ServiceImpl implements IAddressService {
+
+}
diff --git a/user-service/src/main/java/com/hmall/user/service/impl/UserServiceImpl.java b/user-service/src/main/java/com/hmall/user/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..b8e55df
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/service/impl/UserServiceImpl.java
@@ -0,0 +1,86 @@
+package com.hmall.user.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.user.config.JwtProperties;
+import com.hmall.user.domain.dto.LoginFormDTO;
+import com.hmall.user.domain.po.User;
+import com.hmall.user.domain.vo.UserLoginVO;
+import com.hmall.user.enums.UserStatus;
+import com.hmall.user.mapper.UserMapper;
+import com.hmall.user.service.IUserService;
+import com.hmall.user.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;
+
+/**
+ *
+ * 用户表 服务实现类
+ *
+ *
+ * @author 虎哥
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class UserServiceImpl extends ServiceImpl 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("扣款成功");
+ }
+}
diff --git a/user-service/src/main/java/com/hmall/user/utils/JwtTool.java b/user-service/src/main/java/com/hmall/user/utils/JwtTool.java
new file mode 100644
index 0000000..be364e4
--- /dev/null
+++ b/user-service/src/main/java/com/hmall/user/utils/JwtTool.java
@@ -0,0 +1,81 @@
+package com.hmall.user.utils;
+
+import cn.hutool.core.exceptions.ValidateException;
+import cn.hutool.jwt.JWT;
+import cn.hutool.jwt.JWTValidator;
+import cn.hutool.jwt.signers.JWTSigner;
+import cn.hutool.jwt.signers.JWTSignerUtil;
+import com.hmall.common.exception.UnauthorizedException;
+import org.springframework.stereotype.Component;
+
+import java.security.KeyPair;
+import java.time.Duration;
+import java.util.Date;
+
+@Component
+public class JwtTool {
+ private final JWTSigner jwtSigner;
+
+ public JwtTool(KeyPair keyPair) {
+ this.jwtSigner = JWTSignerUtil.createSigner("rs256", keyPair);
+ }
+
+ /**
+ * 创建 access-token
+ *
+ * @return access-token
+ */
+ public String createToken(Long userId, Duration ttl) {
+ // 1.生成jws
+ return JWT.create()
+ .setPayload("user", userId)
+ .setExpiresAt(new Date(System.currentTimeMillis() + ttl.toMillis()))
+ .setSigner(jwtSigner)
+ .sign();
+ }
+
+ /**
+ * 解析token
+ *
+ * @param token token
+ * @return 解析刷新token得到的用户信息
+ */
+ public Long parseToken(String token) {
+ // 1.校验token是否为空
+ if (token == null) {
+ throw new UnauthorizedException("未登录");
+ }
+ // 2.校验并解析jwt
+ JWT jwt;
+ try {
+ jwt = JWT.of(token).setSigner(jwtSigner);
+ } catch (Exception e) {
+ throw new UnauthorizedException("无效的token", e);
+ }
+ // 2.校验jwt是否有效
+ if (!jwt.verify()) {
+ // 验证失败
+ throw new UnauthorizedException("无效的token");
+ }
+ // 3.校验是否过期
+ try {
+ JWTValidator.of(jwt).validateDate();
+ } catch (ValidateException e) {
+ throw new UnauthorizedException("token已经过期");
+ }
+ // 4.数据格式校验
+ Object userPayload = jwt.getPayload("user");
+ if (userPayload == null) {
+ // 数据为空
+ throw new UnauthorizedException("无效的token");
+ }
+
+ // 5.数据解析
+ try {
+ return Long.valueOf(userPayload.toString());
+ } catch (RuntimeException e) {
+ // 数据格式有误
+ throw new UnauthorizedException("无效的token");
+ }
+ }
+}
\ No newline at end of file
diff --git a/user-service/src/main/resources/application-dev.yaml b/user-service/src/main/resources/application-dev.yaml
new file mode 100644
index 0000000..a6fa71e
--- /dev/null
+++ b/user-service/src/main/resources/application-dev.yaml
@@ -0,0 +1,4 @@
+hm:
+ db:
+ host: mysql
+ pw: 123
\ No newline at end of file
diff --git a/user-service/src/main/resources/application-local.yaml b/user-service/src/main/resources/application-local.yaml
new file mode 100644
index 0000000..e310359
--- /dev/null
+++ b/user-service/src/main/resources/application-local.yaml
@@ -0,0 +1,4 @@
+hm:
+ db:
+ host: 124.71.159.195 # 修改为你自己的虚拟机IP地址
+ pw: 123456 # 修改为docker中的MySQL密码
\ No newline at end of file
diff --git a/user-service/src/main/resources/application.yaml b/user-service/src/main/resources/application.yaml
new file mode 100644
index 0000000..c63315f
--- /dev/null
+++ b/user-service/src/main/resources/application.yaml
@@ -0,0 +1,57 @@
+server:
+ port: 8084
+spring:
+ application:
+ name: user-service
+ cloud:
+ nacos:
+ server-addr: 124.71.159.195:8848 # nacos地址
+ profiles:
+ active: local
+ datasource:
+ url: jdbc:mysql://${hm.db.host}:3306/hm-user?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.user.controller
+
+feign:
+ httpclient:
+ enabled: true # 使用 Apache HttpClient(默认关闭)
+
+hm:
+ jwt:
+ location: classpath:hmall.jks
+ alias: hmall
+ password: hmall123
+ tokenTTL: 30m
+
+# keytool -genkeypair -alias hmall -keyalg RSA -keypass hmall123 -keystore hmall.jks -storepass hmall123
\ No newline at end of file
diff --git a/user-service/src/main/resources/hmall.jks b/user-service/src/main/resources/hmall.jks
new file mode 100644
index 0000000..a34bd33
Binary files /dev/null and b/user-service/src/main/resources/hmall.jks differ