将 onemall 老代码,统一到归档目录,后续不断迁移移除

This commit is contained in:
YunaiV
2022-06-16 09:06:44 +08:00
parent 64c478a45b
commit 71930d492e
1095 changed files with 0 additions and 16 deletions

View File

@@ -0,0 +1,108 @@
<?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>user-service-project</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service-app</artifactId>
<dependencies>
<!-- RPC 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-dubbo</artifactId>
</dependency>
<dependency>
<!-- 系统服务 -->
<groupId>cn.iocoder.mall</groupId>
<artifactId>system-service-api</artifactId>
</dependency>
<dependency>
<!-- 用户服务 -->
<groupId>cn.iocoder.mall</groupId>
<artifactId>user-service-api</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <!-- 需要开启 Web 容器,因为 Actuator 需要使用到 -->
</dependency>
<!-- Registry 和 Config 相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-mybatis</artifactId>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
</dependency>
</dependencies>
<build>
<!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName>
<!-- 使用 spring-boot-maven-plugin 插件打包 -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,17 @@
package cn.iocoder.mall.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients(basePackages = {"cn.iocoder.mall.systemservice.rpc"})
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,54 @@
package cn.iocoder.mall.userservice.controller;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.userservice.manager.address.UserAddressManager;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressCreateReqDTO;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressRespDTO;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressUpdateReqDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static cn.iocoder.common.framework.vo.CommonResult.success;
@RestController
@RequestMapping("/user/address")
public class UserAddressController {
@Autowired
private UserAddressManager userAddressManager;
@PostMapping("createUserAddress")
public CommonResult<Integer> createUserAddress(@RequestBody UserAddressCreateReqDTO createDTO) {
return success(userAddressManager.createUserAddress(createDTO));
}
@PostMapping("updateUserAddress")
public CommonResult<Boolean> updateUserAddress(@RequestBody UserAddressUpdateReqDTO updateDTO) {
userAddressManager.updateUserAddress(updateDTO);
return success(true);
}
@GetMapping("deleteUserAddress")
public CommonResult<Boolean> deleteUserAddress(@RequestParam("userAddressId") Integer userAddressId) {
userAddressManager.deleteUserAddress(userAddressId);
return success(true);
}
@GetMapping("getUserAddress")
public CommonResult<UserAddressRespDTO> getUserAddress(@RequestParam("userAddressId")Integer userAddressId) {
return success(userAddressManager.getUserAddress(userAddressId));
}
@GetMapping("listUserAddressesByIds")
public CommonResult<List<UserAddressRespDTO>> listUserAddresses(@RequestParam("userAddressIds")List<Integer> userAddressIds) {
return success(userAddressManager.listUserAddresses(userAddressIds));
}
@GetMapping("listUserAddresses")
public CommonResult<List<UserAddressRespDTO>> listUserAddresses(@RequestParam("userId")Integer userId, @RequestParam("type")Integer type) {
return success(userAddressManager.listUserAddresses(userId, type));
}
}

View File

@@ -0,0 +1,50 @@
package cn.iocoder.mall.userservice.controller;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.userservice.manager.user.UserManager;
import cn.iocoder.mall.userservice.rpc.user.dto.UserCreateReqDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserPageReqDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserRespDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserUpdateReqDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static cn.iocoder.common.framework.vo.CommonResult.success;
@RestController
@RequestMapping("/user/manage")
public class UserManageController {
@Autowired
private UserManager userManager;
@GetMapping("getUser")
public CommonResult<UserRespDTO> getUser(@RequestParam("id") Integer id) {
return success(userManager.getUser(id));
}
@GetMapping("listUsers")
public CommonResult<List<UserRespDTO>> listUsers(@RequestParam("userIds") List<Integer> userIds) {
return success(userManager.listUsers(userIds));
}
@PostMapping("createUserIfAbsent")
public CommonResult<UserRespDTO> createUserIfAbsent(@RequestBody UserCreateReqDTO createDTO) {
return success(userManager.createUserIfAbsent(createDTO));
}
@PostMapping("updateUser")
public CommonResult<Boolean> updateUser(@RequestBody UserUpdateReqDTO updateDTO) {
userManager.updateUser(updateDTO);
return success(true);
}
@PostMapping("pageUser")
public CommonResult<PageResult<UserRespDTO>> pageUser(@RequestBody UserPageReqDTO pageDTO) {
return success(userManager.pageUser(pageDTO));
}
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.mall.userservice.dal.mysql.dataobject.address;
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
import cn.iocoder.mall.userservice.enums.address.UserAddressType;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 用户收件地址
*
* idx_userId 索引:基于 {@link #userId} 字段
*
* @author Sin
* @time 2019-04-06 13:22
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName("user_address")
public class UserAddressDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 用户编号
*/
private Integer userId;
/**
* 收件人名称
*/
private String name;
/**
* 收件手机号
*/
private String mobile;
/**
* 地区编码
*/
private Integer areaCode;
/**
* 收件详细地址
*/
private String detailAddress;
/**
* 地址类型,主要分为默认地址,和普通地址
*
* 外键 {@link UserAddressType}
*/
private Integer type;
}

View File

@@ -0,0 +1,62 @@
package cn.iocoder.mall.userservice.dal.mysql.dataobject.sms;
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
import cn.iocoder.mall.userservice.enums.sms.UserSmsSceneEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 手机验证码 DO
*
* idx_mobile 索引:基于 {@link #mobile} 字段
*/
@TableName("user_sms_code")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class UserSmsCodeDO extends BaseDO {
/**
* 编号
*/
private Integer id;
/**
* 手机号
*/
private String mobile;
/**
* 验证码
*/
private String code;
/**
* 发送场景
*
* 外键 {@link UserSmsSceneEnum}
*/
private Integer scene;
/**
* 创建 IP
*/
private String createIp;
/**
* 今日发送的第几条
*/
private Integer todayIndex;
/**
* 是否使用
*/
private Boolean used;
/**
* 使用时间
*/
private Date usedTime;
/**
* 使用 IP
*/
private String usedIp;
}

View File

@@ -0,0 +1,57 @@
package cn.iocoder.mall.userservice.dal.mysql.dataobject.user;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 用户实体
*
* uk_mobile 索引:基于 {@link #mobile} 字段
*/
@TableName(value = "users")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class UserDO extends BaseDO {
/**
* 用户编号
*/
private Integer id;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
/**
* 用户状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 手机
*/
private String mobile;
/**
* 经过加密的密码串
*/
private String password;
/**
* {@link #password} 的盐
*/
private String passwordSalt;
/**
* 注册 IP
*/
private String createIp;
}

View File

@@ -0,0 +1,73 @@
package cn.iocoder.mall.userservice.dal.mysql.dataobject.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 用户三方开放平台授权例如QQ / 微博 / 微信等等。
*
* TODO 优化点:需要在改改
*/
@Data
@Accessors(chain = true)
public class UserThirdAuthDO {
/**
* 用户编号
*
* 外键 {@link UserDO#uid}
*/
private Long uid;
// ========== 授权相关字段
/**
* 用户的唯一标识
*/
private String openid;
/**
* 开放平台
*
* @see cn.iocoder.mall.user.api.constant.ThirdPlatformConstant
*/
private Integer platform;
/**
* 访问令牌
*/
private Date accessToken;
/**
* 过期时间
*/
private Date expireTime;
/**
* 刷新令牌
*/
private Date refreshToken;
/**
* 授权范围。一般情况下,使用逗号分隔
*/
private String scopes;
// ========== 基础信息
/**
* 用户昵称
*/
private String nickname;
/**
* 性别
*
* TODO 芋艿找地方统一枚举。0-未知1-男2-女
*/
private Integer gender;
// TODO https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
// TODO 芋艿,其他字段,国家/省份/城市/地区等
// TODO 芋艿,头像
// TODO 芋艿,微信独有 unionid
/**
* 统一存储基础信息,使用 JSON 格式化,避免未有效解析的情况。
*/
private String extras;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.mall.userservice.dal.mysql.mapper.address;
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.address.UserAddressDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
import javax.annotation.Nullable;
import java.util.List;
@Repository
public interface UserAddressMapper extends BaseMapper<UserAddressDO> {
default List<UserAddressDO> selectListByUserIdAndType(Integer userId, @Nullable Integer type) {
return selectList(new QueryWrapperX<UserAddressDO>().eq("user_id", userId)
.eqIfPresent("type", type));
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.mall.userservice.dal.mysql.mapper.sms;
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.sms.UserSmsCodeDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
@Repository
public interface UserSmsCodeMapper extends BaseMapper<UserSmsCodeDO> {
/**
* 获得手机号的最后一个手机验证码
*
* @param mobile 手机号
* @param scene 发送场景,选填
* @return 手机验证码
*/
default UserSmsCodeDO selectLastByMobile(String mobile, Integer scene) {
QueryWrapperX<UserSmsCodeDO> query = new QueryWrapperX<UserSmsCodeDO>()
.eq("mobile", mobile)
.eqIfPresent("scene", scene)
.orderByDesc("id")
.last("limit 1");
return selectOne(query);
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.mall.userservice.dal.mysql.mapper.user;
import cn.iocoder.mall.mybatis.core.query.QueryWrapperX;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.user.UserDO;
import cn.iocoder.mall.userservice.service.user.bo.UserPageBO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<UserDO> {
default UserDO selectByMobile(String mobile) {
return selectOne(new QueryWrapper<UserDO>()
.eq("mobile", mobile)
);
}
default IPage<UserDO> selectPage(UserPageBO pageBO) {
return selectPage(new Page<>(pageBO.getPageNo(), pageBO.getPageSize()),
new QueryWrapperX<UserDO>().likeIfPresent("nickname", pageBO.getNickname())
.eqIfPresent("status", pageBO.getStatus()));
}
}

View File

@@ -0,0 +1,86 @@
package cn.iocoder.mall.userservice.manager.address;
import cn.iocoder.mall.userservice.convert.address.UserAddressConvert;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressCreateReqDTO;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressRespDTO;
import cn.iocoder.mall.userservice.rpc.address.dto.UserAddressUpdateReqDTO;
import cn.iocoder.mall.userservice.service.address.UserAddressService;
import cn.iocoder.mall.userservice.service.address.bo.UserAddressBO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 用户收件地址 Manager
*/
@Service
public class UserAddressManager {
@Autowired
private UserAddressService userAddressService;
/**
* 创建用户收件地址
*
* @param createDTO 创建用户收件地址 DTO
* @return 用户收件地址
*/
public Integer createUserAddress(UserAddressCreateReqDTO createDTO) {
UserAddressBO userAddressBO = userAddressService.createUserAddress(UserAddressConvert.INSTANCE.convert(createDTO));
return userAddressBO.getId();
}
/**
* 更新用户收件地址
*
* @param updateDTO 更新用户收件地址 DTO
*/
public void updateUserAddress(UserAddressUpdateReqDTO updateDTO) {
userAddressService.updateUserAddress(UserAddressConvert.INSTANCE.convert(updateDTO));
}
/**
* 删除用户收件地址
*
* @param userAddressId 用户收件地址编号
*/
public void deleteUserAddress(Integer userAddressId) {
userAddressService.deleteUserAddress(userAddressId);
}
/**
* 获得用户收件地址
*
* @param userAddressId 用户收件地址编号
* @return 用户收件地址
*/
public UserAddressRespDTO getUserAddress(Integer userAddressId) {
UserAddressBO userAddressBO = userAddressService.getUserAddress(userAddressId);
return UserAddressConvert.INSTANCE.convert(userAddressBO);
}
/**
* 获得用户收件地址列表
*
* @param userAddressIds 用户收件地址编号列表
* @return 用户收件地址列表
*/
public List<UserAddressRespDTO> listUserAddresses(List<Integer> userAddressIds) {
List<UserAddressBO> userAddressBOs = userAddressService.listUserAddresses(userAddressIds);
return UserAddressConvert.INSTANCE.convertList02(userAddressBOs);
}
/**
* 获取指定用户的收件地址列表
*
* @param userId 用户编号
* @param type 地址类型
* @return 收件地址列表
*/
public List<UserAddressRespDTO> listUserAddresses(Integer userId, Integer type) {
List<UserAddressBO> userAddressBOs = userAddressService.listUserAddresses(userId, type);
return UserAddressConvert.INSTANCE.convertList02(userAddressBOs);
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.mall.userservice.manager.sms;
import cn.iocoder.mall.userservice.rpc.sms.dto.UserSendSmsCodeReqDTO;
import cn.iocoder.mall.userservice.rpc.sms.dto.UserVerifySmsCodeReqDTO;
import cn.iocoder.mall.userservice.service.sms.UserSmsCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserSmsCodeManager {
@Autowired
private UserSmsCodeService userSmsCodeService;
public void sendSmsCode(UserSendSmsCodeReqDTO sendSmsCodeDTO) {
// 生成短信验证码
String smsCode = userSmsCodeService.createSmsCode(sendSmsCodeDTO.getMobile(),
sendSmsCodeDTO.getScene(), sendSmsCodeDTO.getIp());
// TODO 调用发送验证码
}
public void verifySmsCode(UserVerifySmsCodeReqDTO verifySmsCodeDTO) {
userSmsCodeService.verifySmsCode(verifySmsCodeDTO.getMobile(), verifySmsCodeDTO.getCode(),
verifySmsCodeDTO.getScene(), verifySmsCodeDTO.getIp());
}
}

View File

@@ -0,0 +1,91 @@
package cn.iocoder.mall.userservice.manager.user;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.enums.UserTypeEnum;
import cn.iocoder.common.framework.util.StringUtils;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.systemservice.rpc.oauth.OAuthFeign;
import cn.iocoder.mall.systemservice.rpc.oauth.dto.OAuth2RemoveTokenByUserReqDTO;
import cn.iocoder.mall.userservice.convert.user.UserConvert;
import cn.iocoder.mall.userservice.rpc.user.dto.UserCreateReqDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserPageReqDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserRespDTO;
import cn.iocoder.mall.userservice.rpc.user.dto.UserUpdateReqDTO;
import cn.iocoder.mall.userservice.service.user.UserService;
import cn.iocoder.mall.userservice.service.user.bo.UserBO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserManager {
@Autowired
private UserService userService;
@Autowired
private OAuthFeign oAuthFeign;
public UserRespDTO createUserIfAbsent(UserCreateReqDTO createDTO) {
// 用户已经存在
UserBO userBO = userService.getUser(createDTO.getMobile());
if (userBO != null) {
return UserConvert.INSTANCE.convert(userBO);
}
// 用户不存在,则进行创建
userBO = userService.createUser(UserConvert.INSTANCE.convert(createDTO));
return UserConvert.INSTANCE.convert(userBO);
}
/**
* 更新用户
*
* @param updateDTO 更新用户 DTO
*/
public void updateUser(UserUpdateReqDTO updateDTO) {
// 更新管理员信息
userService.updateUser(UserConvert.INSTANCE.convert(updateDTO));
// 如果修改密码,或者禁用管理员
if (StringUtils.hasText(updateDTO.getPassword())
|| CommonStatusEnum.DISABLE.getValue().equals(updateDTO.getStatus())) {
oAuthFeign.removeToken(new OAuth2RemoveTokenByUserReqDTO().setUserId(updateDTO.getId())
.setUserType(UserTypeEnum.ADMIN.getValue()));
}
}
/**
* 获得用户
*
* @param userId 用户编号
* @return 用户
*/
public UserRespDTO getUser(Integer userId) {
UserBO userBO = userService.getUser(userId);
return UserConvert.INSTANCE.convert(userBO);
}
/**
* 获得用户列表
*
* @param userIds 用户编号列表
* @return 用户列表
*/
public List<UserRespDTO> listUsers(List<Integer> userIds) {
List<UserBO> userBOs = userService.listUsers(userIds);
return UserConvert.INSTANCE.convertList02(userBOs);
}
/**
* 获得用户分页
*
* @param pageDTO 用户分页查询
* @return 用户分页结果
*/
public PageResult<UserRespDTO> pageUser(UserPageReqDTO pageDTO) {
PageResult<UserBO> pageResultBO = userService.pageUser(UserConvert.INSTANCE.convert(pageDTO));
return UserConvert.INSTANCE.convertPage(pageResultBO);
}
}

View File

@@ -0,0 +1,130 @@
package cn.iocoder.mall.userservice.service.address;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.CollectionUtils;
import cn.iocoder.mall.userservice.convert.address.UserAddressConvert;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.address.UserAddressDO;
import cn.iocoder.mall.userservice.dal.mysql.mapper.address.UserAddressMapper;
import cn.iocoder.mall.userservice.enums.address.UserAddressType;
import cn.iocoder.mall.userservice.service.address.bo.UserAddressBO;
import cn.iocoder.mall.userservice.service.address.bo.UserAddressCreateBO;
import cn.iocoder.mall.userservice.service.address.bo.UserAddressUpdateBO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.mall.userservice.enums.UserErrorCodeConstants.USER_ADDRESS_NOT_FOUND;
/**
* 用户收件地址 Service
*/
@Service
@Validated
public class UserAddressService {
@Autowired
private UserAddressMapper userAddressMapper;
/**
* 创建用户收件地址
*
* @param createBO 创建用户收件地址 BO
* @return 用户收件地址
*/
@Transactional
public UserAddressBO createUserAddress(@Valid UserAddressCreateBO createBO) {
// 如果添加的是默认收件地址,则将原默认地址修改为非默认
if (UserAddressType.DEFAULT.getType().equals(createBO.getType())) {
List<UserAddressDO> addressDOs = userAddressMapper.selectListByUserIdAndType(
createBO.getUserId(), UserAddressType.DEFAULT.getType());
if (!CollectionUtils.isEmpty(addressDOs)) {
addressDOs.forEach(userAddressDO -> userAddressMapper.updateById(new UserAddressDO()
.setId(userAddressDO.getId()).setType(UserAddressType.DEFAULT.getType())));
}
}
// 插入到数据库
UserAddressDO userAddressDO = UserAddressConvert.INSTANCE.convert(createBO);
userAddressMapper.insert(userAddressDO);
// 返回
return UserAddressConvert.INSTANCE.convert(userAddressDO);
}
/**
* 更新用户收件地址
*
* @param updateBO 更新用户收件地址 BO
*/
@Transactional
public void updateUserAddress(@Valid UserAddressUpdateBO updateBO) {
// 校验更新的用户收件地址是否存在
if (userAddressMapper.selectById(updateBO.getId()) == null) {
throw ServiceExceptionUtil.exception(USER_ADDRESS_NOT_FOUND);
}
// 如果修改的是默认收件地址,则将原默认地址修改为非默认
if (UserAddressType.DEFAULT.getType().equals(updateBO.getType())) {
List<UserAddressDO> addressDOs = userAddressMapper.selectListByUserIdAndType(
updateBO.getUserId(), UserAddressType.DEFAULT.getType());
if (!CollectionUtils.isEmpty(addressDOs)) {
addressDOs.stream().filter(userAddressDO -> userAddressDO.getId().equals(updateBO.getId())) // 过滤掉更新的收件地址
.forEach(userAddressDO -> userAddressMapper.updateById(new UserAddressDO()
.setId(userAddressDO.getId()).setType(UserAddressType.DEFAULT.getType())));
}
}
// 更新到数据库
UserAddressDO updateObject = UserAddressConvert.INSTANCE.convert(updateBO);
userAddressMapper.updateById(updateObject);
}
/**
* 删除用户收件地址
*
* @param userAddressId 用户收件地址编号
*/
public void deleteUserAddress(Integer userAddressId) {
// 校验删除的用户收件地址是否存在
if (userAddressMapper.selectById(userAddressId) == null) {
throw ServiceExceptionUtil.exception(USER_ADDRESS_NOT_FOUND);
}
// 标记删除
userAddressMapper.deleteById(userAddressId);
}
/**
* 获得用户收件地址
*
* @param userAddressId 用户收件地址编号
* @return 用户收件地址
*/
public UserAddressBO getUserAddress(Integer userAddressId) {
UserAddressDO userAddressDO = userAddressMapper.selectById(userAddressId);
return UserAddressConvert.INSTANCE.convert(userAddressDO);
}
/**
* 获得用户收件地址列表
*
* @param userAddressIds 用户收件地址编号列表
* @return 用户收件地址列表
*/
public List<UserAddressBO> listUserAddresses(List<Integer> userAddressIds) {
List<UserAddressDO> userAddressDOs = userAddressMapper.selectBatchIds(userAddressIds);
return UserAddressConvert.INSTANCE.convertList(userAddressDOs);
}
/**
* 获取指定用户的收件地址列表
*
* @param userId 用户编号
* @param type 地址类型
* @return 收件地址列表
*/
public List<UserAddressBO> listUserAddresses(Integer userId, Integer type) {
List<UserAddressDO> userAddressDOs = userAddressMapper.selectListByUserIdAndType(userId, type);
return UserAddressConvert.INSTANCE.convertList(userAddressDOs);
}
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.mall.userservice.service.address.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 用户收件地址 BO
*/
@Data
@Accessors(chain = true)
public class UserAddressBO {
/**
* 收件地址编号
*/
private Integer id;
/**
* 用户编号
*/
private Integer userId;
/**
* 收件人名称
*/
private String name;
/**
* 手机号
*/
private String mobile;
/**
* 地区编码
*/
private Integer areaCode;
/**
* 收件详细地址
*/
private String detailAddress;
/**
* 地址类型
*/
private Integer type;
/**
* 创建时间
*/
private Date createTime;
}

View File

@@ -0,0 +1,49 @@
package cn.iocoder.mall.userservice.service.address.bo;
import cn.iocoder.common.framework.validator.Mobile;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 用户收件地址创建 BO
*/
@Data
@Accessors(chain = true)
public class UserAddressCreateBO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Integer userId;
/**
* 收件人名称
*/
@NotEmpty(message = "收件人名称不能为空")
private String name;
/**
* 手机号
*/
@NotEmpty(message = "手机号不能为空")
@Mobile
private String mobile;
/**
* 地区编码
*/
@NotNull(message = "地区编码不能为空")
private Integer areaCode;
/**
* 收件详细地址
*/
@NotEmpty(message = "收件详细地址不能为空")
private String detailAddress;
/**
* 地址类型
*/
@NotNull(message = "地址类型不能为空")
private Integer type;
}

View File

@@ -0,0 +1,52 @@
package cn.iocoder.mall.userservice.service.address.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 用户收件地址更新 BO
*/
@Data
@Accessors(chain = true)
public class UserAddressUpdateBO {
/**
* 收件地址编号
*/
@NotNull(message = "收件地址编号不能为空")
private Integer id;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Integer userId;
/**
* 收件人名称
*/
@NotEmpty(message = "收件人名称不能为空")
private String name;
/**
* 手机号
*/
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 地区编码
*/
@NotNull(message = "地区编码不能为空")
private Integer areaCode;
/**
* 收件详细地址
*/
@NotEmpty(message = "收件详细地址不能为空")
private String detailAddress;
/**
* 地址类型
*/
@NotNull(message = "地址类型不能为空")
private Integer type;
}

View File

@@ -0,0 +1,105 @@
package cn.iocoder.mall.userservice.service.sms;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.validator.Mobile;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.sms.UserSmsCodeDO;
import cn.iocoder.mall.userservice.dal.mysql.mapper.sms.UserSmsCodeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Date;
import static cn.iocoder.mall.userservice.enums.UserErrorCodeConstants.*;
@Service
@Validated
public class UserSmsCodeService {
/**
* 每条验证码的过期时间,单位:毫秒
*/
@Value("${modules.user-sms-code-service.code-expire-time-millis}")
private int codeExpireTimes;
/**
* 每日发送最大数量
*/
@Value("${modules.user-sms-code-service.send-maximum-quantity-per-day}")
private int sendMaximumQuantityPerDay;
/**
* 短信发送频率,单位:毫秒
*/
@Value("${modules.user-sms-code-service.send-frequency}")
private int sendFrequency;
@Autowired
private UserSmsCodeMapper userSmsCodeMapper;
/**
* 创建短信验证码,并返回它
*
* 注意,不包括发送逻辑
*
* @param mobile 手机号
* @param scene 发送场景
* @param ip IP
* @return 短信验证码
*/
public String createSmsCode(@Mobile String mobile, Integer scene, String ip) {
// 校验是否可以发送验证码,不用筛选场景
UserSmsCodeDO lastUserSmsCodeDO = userSmsCodeMapper.selectLastByMobile(mobile, null);
if (lastUserSmsCodeDO != null) {
if (lastUserSmsCodeDO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
}
if (System.currentTimeMillis() - lastUserSmsCodeDO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
throw ServiceExceptionUtil.exception(USER_SMS_CODE_SEND_TOO_FAST);
}
// TODO 提升,每个 IP 每天可发送数量
// TODO 提升,每个 IP 每小时可发送数量
}
// 创建验证码记录
UserSmsCodeDO newMobileCodePO = new UserSmsCodeDO().setMobile(mobile)
.setCode("9999") // TODO 芋艿,随机 4 位验证码 or 6 位验证码
.setScene(scene)
.setTodayIndex(lastUserSmsCodeDO != null ? lastUserSmsCodeDO.getTodayIndex() : 1)
.setCreateIp(ip).setUsed(false);
newMobileCodePO.setCreateTime(new Date());
userSmsCodeMapper.insert(newMobileCodePO);
return newMobileCodePO.getCode();
}
/**
* 验证短信验证码是否正确。
* 如果正确,则将验证码标记成已使用
* 如果错误,则抛出 {@link ServiceException} 异常
*
* @param mobile 手机号
* @param code 验证码
* @param scene 发送场景
* @param ip IP
*/
public void verifySmsCode(String mobile, String code, Integer scene, String ip) {
// 校验验证码
UserSmsCodeDO mobileCodeDO = userSmsCodeMapper.selectLastByMobile(mobile, scene);
if (mobileCodeDO == null) { // 若验证码不存在,抛出异常
throw ServiceExceptionUtil.exception(USER_SMS_CODE_NOT_FOUND);
}
if (System.currentTimeMillis() - mobileCodeDO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期
throw ServiceExceptionUtil.exception(USER_SMS_CODE_EXPIRED);
}
if (mobileCodeDO.getUsed()) { // 验证码已使用
throw ServiceExceptionUtil.exception(USER_SMS_CODE_USED);
}
if (!mobileCodeDO.getCode().equals(code)) {
throw ServiceExceptionUtil.exception(USER_SMS_CODE_NOT_CORRECT);
}
// 使用验证码
UserSmsCodeDO updateObj = new UserSmsCodeDO().setId(mobileCodeDO.getId())
.setUsed(true).setUsedTime(new Date()).setUsedIp(ip);
userSmsCodeMapper.updateById(updateObj);
}
}

View File

@@ -0,0 +1,117 @@
package cn.iocoder.mall.userservice.service.user;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.DigestUtils;
import cn.iocoder.common.framework.util.StringUtils;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.userservice.convert.user.UserConvert;
import cn.iocoder.mall.userservice.dal.mysql.dataobject.user.UserDO;
import cn.iocoder.mall.userservice.dal.mysql.mapper.user.UserMapper;
import cn.iocoder.mall.userservice.service.user.bo.UserBO;
import cn.iocoder.mall.userservice.service.user.bo.UserCreateBO;
import cn.iocoder.mall.userservice.service.user.bo.UserPageBO;
import cn.iocoder.mall.userservice.service.user.bo.UserUpdateBO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import static cn.iocoder.mall.userservice.enums.UserErrorCodeConstants.*;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public UserBO getUser(Integer id) {
UserDO userDO = userMapper.selectById(id);
return UserConvert.INSTANCE.convert(userDO);
}
/**
* 获得用户列表
*
* @param userIds 用户编号列表
* @return 用户列表
*/
public List<UserBO> listUsers(List<Integer> userIds) {
List<UserDO> userDOs = userMapper.selectBatchIds(userIds);
return UserConvert.INSTANCE.convertList(userDOs);
}
public UserBO getUser(String mobile) {
UserDO userDO = userMapper.selectByMobile(mobile);
return UserConvert.INSTANCE.convert(userDO);
}
public UserBO createUser(UserCreateBO createBO) {
UserDO userDO = UserConvert.INSTANCE.convert(createBO)
.setStatus(CommonStatusEnum.ENABLE.getValue());
// 加密密码
String passwordSalt = genPasswordSalt();
String password = createBO.getPassword();
if (!StringUtils.hasText(password)) {
password = genPassword();
}
password = encodePassword(password, passwordSalt);
userDO.setPassword(password).setPasswordSalt(passwordSalt);
// 保存用户
userMapper.insert(userDO);
return UserConvert.INSTANCE.convert(userDO);
}
public void updateUser(UserUpdateBO updateBO) {
// 校验用户存在
UserDO userDO = userMapper.selectById(updateBO.getId());
if (userDO == null) {
throw ServiceExceptionUtil.exception(USER_NOT_EXISTS);
}
// 校验手机唯一
if (StringUtils.hasText(updateBO.getMobile())) {
UserDO mobileAdmin = userMapper.selectByMobile(updateBO.getMobile());
if (mobileAdmin != null && !mobileAdmin.getId().equals(updateBO.getId())) {
throw ServiceExceptionUtil.exception(USER_MOBILE_EXISTS);
}
}
// 如果有更新状态,则校验是否已经是该状态
if (updateBO.getStatus() != null && updateBO.getStatus().equals(userDO.getStatus())) {
throw ServiceExceptionUtil.exception(USER_STATUS_EQUALS);
}
// 更新到数据库
UserDO updateUser = UserConvert.INSTANCE.convert(updateBO);
// 如果更新密码,需要特殊加密
if (StringUtils.hasText(updateBO.getPassword())) {
String passwordSalt = genPasswordSalt();
String password = encodePassword(updateBO.getPassword(), passwordSalt);
updateUser.setPassword(password).setPasswordSalt(passwordSalt);
}
userMapper.updateById(updateUser);
}
/**
* 获得用户分页
*
* @param pageBO 用户分页查询
* @return 用户分页结果
*/
public PageResult<UserBO> pageUser(UserPageBO pageBO) {
IPage<UserDO> userDOPage = userMapper.selectPage(pageBO);
return UserConvert.INSTANCE.convertPage(userDOPage);
}
private String genPasswordSalt() {
return DigestUtils.genBcryptSalt();
}
private String genPassword() {
return StringUtils.uuid(true);
}
private String encodePassword(String password, String salt) {
return DigestUtils.bcrypt(password, salt);
}
}

View File

@@ -0,0 +1,51 @@
package cn.iocoder.mall.userservice.service.user.bo;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 用户信息
*/
@Data
@Accessors(chain = true)
public class UserBO {
/**
* 用户编号
*/
private Integer id;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
/**
* 用户状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 手机
*/
private String mobile;
/**
* 经过加密的密码串
*/
private String password;
/**
* {@link #password} 的盐
*/
private String passwordSalt;
/**
* 注册时间
*/
private Date createTime;
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.mall.userservice.service.user.bo;
import cn.iocoder.common.framework.validator.Mobile;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* 用户创建 BO
*/
@Data
@Accessors(chain = true)
public class UserCreateBO {
/**
* 昵称,允许空
*/
private String nickname;
/**
* 头像,允许空
*/
private String avatar;
/**
* 手机
*/
@NotNull(message = "手机号不能为空")
@Mobile
private String mobile;
/**
* 原始密码,允许空
*
* 当为空时,会自动进行生成
*/
private String password;
/**
* IP 地址
*/
private String createIp;
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.mall.userservice.service.user.bo;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.common.framework.vo.PageParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 用户分页 BO
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class UserPageBO extends PageParam {
/**
* 昵称
*
* 模糊
*/
private String nickname;
/**
* 状态
*/
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
}

View File

@@ -0,0 +1,46 @@
package cn.iocoder.mall.userservice.service.user.bo;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.common.framework.validator.Mobile;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* 用户更新 BO
*/
@Data
@Accessors(chain = true)
public class UserUpdateBO {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Integer id;
/**
* 昵称
*/
private String nickname;
/**
* 头像
*/
private String avatar;
/**
* 状态
*/
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status;
/**
* 手机号
*/
@Mobile
private String mobile;
/**
* 密码
*/
private String password;
}

View File

@@ -0,0 +1,21 @@
spring:
# 数据源配置项
datasource:
url: jdbc:mysql://localhost:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: zhuyang
# Spring Cloud 配置项
cloud:
nacos:
# Spring Cloud Nacos Discovery 配置项
discovery:
server-addr: localhost:8848 # Nacos 服务器地址
namespace: dev # Nacos 命名空间
# Dubbo 配置项
dubbo:
# Dubbo 注册中心
registry:
# address: spring-cloud://localhost:8848 # 指定 Dubbo 服务注册中心的地址
address: nacos://localhost:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址

View File

@@ -0,0 +1,24 @@
spring:
# 数据源配置项
datasource:
url: jdbc:mysql://localhost:3306/mall_user?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
driver-class-name: com.mysql.jdbc.Driver
username: root
password: zhuyang
# Spring Cloud 配置项
cloud:
nacos:
# Spring Cloud Nacos Discovery 配置项
discovery:
server-addr: localhost:8848 # Nacos 服务器地址
namespace: dev # Nacos 命名空间
# Dubbo 配置项
dubbo:
# Dubbo 注册中心
registry:
# address: spring-cloud://localhost:8848 # 指定 Dubbo 服务注册中心的地址
address: nacos://localhost:8848?namespace=dev # 指定 Dubbo 服务注册中心的地址
# Dubbo 服务提供者的配置
provider:
tag: ${DUBBO_TAG} # Dubbo 路由分组

View File

@@ -0,0 +1,5 @@
##################### 业务模块 #####################
## UserSmsCodeService
modules.user-sms-code-service.code-expire-time-millis = 600000
modules.user-sms-code-service.send-maximum-quantity-per-day = 10
modules.user-sms-code-service.send-frequency = 60000

View File

@@ -0,0 +1,52 @@
spring:
# Application 的配置项
application:
name: user-service
# Profile 的配置项
profiles:
active: local
# MyBatis Plus 配置项
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
id-type: auto
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: cn.iocoder.mall.userservice.dal.mysql.dataobject
# Dubbo 配置项
dubbo:
# Spring Cloud Alibaba Dubbo 专属配置
cloud:
subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用
# Dubbo 提供者的协议
protocol:
name: dubbo
port: -1
# Dubbo 提供服务的扫描基础包
scan:
base-packages: cn.iocoder.mall.userservice.rpc
# Dubbo 服务提供者的配置
provider:
filter: -exception
validation: true # 开启 Provider 参数校验
UserRpc:
version: 1.0.0
UserSmsCodeRpc:
version: 1.0.0
UserAddressRpc:
version: 1.0.0
# Dubbo 服务消费者的配置
consumer:
OAuth2Rpc:
version: 1.0.0
# Actuator 监控配置项
management:
server.port: 38081 # 独立端口,避免被暴露出去
endpoints.web.exposure.include: '*' # 暴露所有监控端点
server.port: ${management.server.port} # 设置使用 Actuator 的服务器端口,因为 RPC 服务不需要 Web 端口

View File

@@ -0,0 +1,15 @@
-- ----------------------------
-- Table structure for users
-- ----------------------------
INSERT INTO `mall_user`.`users`(`id`, `nickname`, `avatar`, `status`, `mobile`, `password`, `password_salt`, `create_ip`, `create_time`, `update_time`) VALUES (243, '芋艿X', 'http://www.iocoder.cn/images/common/zsxq/02.png', 2, '15601691340', '$2a$10$oBHjsjw57u3/g.g47kUAV.Q3i/TrMm62fobwFjGEjNGKUcqfgs2em', '$2a$10$oBHjsjw57u3/g.g47kUAV.', '127.0.0.1', '2020-07-03 20:41:57', '2020-07-26 00:51:38');
-- ----------------------------
-- Table structure for user_sms_code
-- ----------------------------
-- ----------------------------
-- Table structure for user_sms_code
-- ----------------------------

View File

@@ -0,0 +1,57 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for users
-- ----------------------------
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户编号',
`nickname` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '昵称',
`avatar` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '头像',
`status` tinyint(4) NOT NULL COMMENT '状态',
`mobile` varchar(11) COLLATE utf8mb4_bin NOT NULL COMMENT '手机号',
`password` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '加密后的密码',
`password_salt` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '密码的盐',
`create_ip` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '注册 IP',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uk_mobile` (`mobile`) USING BTREE COMMENT '手机号'
) ENGINE=InnoDB AUTO_INCREMENT=245 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户';
-- ----------------------------
-- Table structure for user_sms_code
-- ----------------------------
CREATE TABLE `user_sms_code` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`mobile` varchar(11) NOT NULL COMMENT '手机号',
`code` varchar(6) NOT NULL COMMENT '验证码',
`create_ip` varchar(15) NOT NULL COMMENT '创建 IP',
`scene` tinyint(4) NOT NULL COMMENT '发送场景',
`today_index` tinyint(4) NOT NULL COMMENT '今日发送的第几条',
`used` tinyint(4) NOT NULL COMMENT '是否使用',
`used_time` datetime DEFAULT NULL COMMENT '使用时间',
`used_ip` varchar(255) DEFAULT NULL COMMENT '使用 IP',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_mobile` (`mobile`) USING BTREE COMMENT '手机号'
) ENGINE=InnoDB AUTO_INCREMENT=445 DEFAULT CHARSET=utf8mb4 COMMENT='手机验证码';
-- ----------------------------
-- Table structure for user_sms_code
-- ----------------------------
CREATE TABLE `user_address` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '收件地址编号',
`user_id` int(11) NOT NULL COMMENT '用户编号',
`name` varchar(10) COLLATE utf8mb4_bin NOT NULL COMMENT '收件人名称',
`mobile` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '手机号',
`area_code` int(11) NOT NULL COMMENT '地区编码',
`detail_address` varchar(250) COLLATE utf8mb4_bin NOT NULL COMMENT '收件详细地址',
`type` tinyint(4) NOT NULL COMMENT '地址类型',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '删除状态',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_userId` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户收件地址';