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