您的位置:首页 > 移动开发

乐优商城:笔记(十一):用户微服务:LyUserApplication

2019-06-04 22:40 1071 查看
版权声明:转载请说明 https://blog.csdn.net/sinat_38570489/article/details/90778414

文章目录

  • 2 后台功能实现
  • 2.2 实现发送短信功能
  • 2.3 实现注册功能
  • 2.4 根据用户名和密码查询用户
  • 1 创建用户中心

    用户搜索到自己心仪的商品,接下来就要去购买,但是购买必须先登录。所以接下来我们编写用户中心,实现用户的登录注册功能。因为用户中心的服务其它微服务也会调用,因此这里我们做聚合:

    • ly-user:父工程,包含2个子工程: ly-user-interface:实体及接口
    • ly-user-service:业务和服务

    1.1 创建ly-user-interface

    <?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>ly-user</artifactId>
    <groupId>com.leyou.service</groupId>
    <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.leyou.service</groupId>
    <artifactId>ly-user-interface</artifactId>
    
    <dependencies>
    <dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-core</artifactId>
    <version>1.0.4</version>
    </dependency><dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.0</version>
    </dependency>
    <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    </dependency><dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.0.8.RELEASE</version>
    </dependency>
    </dependencies>
    </project>

    1.2 创建ly-user-service

    1.2.1 引入依赖

    <?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>ly-user</artifactId>
    <groupId>com.leyou.service</groupId>
    <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.leyou.service</groupId>
    <artifactId>ly-user-service</artifactId>
    
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- mybatis启动器 -->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
    </dependency>
    <!-- 通用Mapper启动器 -->
    <dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
    <groupId>com.leyou.service</groupId>
    <artifactId>ly-user-interface</artifactId>
    <version>${leyou.latest.version}</version>
    </dependency>
    <dependency>
    <groupId>com.leyou.common</groupId>
    <artifactId>ly-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    </dependency>
    <dependency>
    <groupId>com.leyou.service</groupId>
    <artifactId>ly-auth-common</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    </dependency>
    </dependencies>
    </project>

    1.2.2 配置文件

    server:
    port: 8085
    spring:
    application:
    name: user-service
    datasource:
    url: jdbc:mysql://localhost:3306/yun6
    username: root
    password: 123
    driver-class-name: com.mysql.jdbc.Driver
    rabbitmq:
    host: 192.168.124.128
    username: leyou
    password: leyou
    virtual-host: /leyou
    redis:
    host: 192.168.124.128
    eureka:
    client:
    service-url:
    defaultZone: http://127.0.0.1:10086/eureka
    instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1
    mybatis:
    type-aliases-package: com.leyou.user.pojo

    1.2.3 启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    @MapperScan("com.leyou.user.mapper")
    public class LyUserService {
    public static void main(String[] args) {
    SpringApplication.run(LyUserService.class,args);
    }
    }

    1.2.4 添加路由

    2 后台功能实现

    2.1 数据校验

    2.1.1 实体类

    @Table(name = "tb_user")
    public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String username;// 用户名
    
    @JsonIgnore
    private String password;// 密码
    
    private String phone;// 电话
    private Date created;// 创建时间
    
    @JsonIgnore
    private String salt;// 密码的盐值
    }

    注意:为了安全考虑。这里对password和salt添加了注解@JsonIgnore,这样在json序列化时,就不会把password和salt返回。

    2.1.2 mapper

    public interface UserMapper extends Mapper<User> {
    }

    2.1.3 controller

    功能说明

    实现用户数据的校验,主要包括对:手机号、用户名的唯一性校验。

    接口路径

    GET /check/{data}/{type}

    参数说明:

    参数 说明 是否必须 数据类型 默认值
    data 要校验的数据 String
    type 要校验的数据类型:1,用户名;2,手机; Integer

    返回结果:

    返回布尔类型结果:

    • true:可用
    • false:不可用

    状态码:

    • 200:校验成功
    • 400:参数有误
    • 500:服务器内部异常
    @GetMapping("check/{data}/{type}")
    public ResponseEntity<Boolean> checkData(
    @PathVariable("data") String data,
    @PathVariable("type") Integer type){
    
    return ResponseEntity.ok(userService.checkData(data, type));
    }

    2.1.4 service

    //校验登录数据
    public Boolean checkData(String data, Integer type) {
    User record = new User();
    switch (type){
    case 1:
    record.setUsername(data);
    break;
    case 2:
    record.setPhone(data);
    break;
    default:
    throw new LyException(ExceptionEnum.INVALID_USER_DATA_TYPE);
    }
    return userMapper.selectCount(record) == 0;//为0说明该手机号或者用户名可用,因为用户名或者手机号必须唯一
    }

    2.2 实现发送短信功能

    短信微服务已经准备好,我们就可以继续编写用户中心接口了。

    功能说明

    根据用户输入的手机号,生成随机验证码,长度为6位,纯数字。并且调用短信服务,发送验证码到用户手机。

    接口路径

    POST /code

    参数说明:

    参数 说明 是否必须 数据类型 默认值
    phone 用户的手机号码 String

    返回结果:

    状态码:

    • 204:请求已接收
    • 400:参数有误
    • 500:服务器内部异常

    2.2.1 controller

    @PostMapping("code")
    public ResponseEntity<Void> sendCode(@RequestParam("phone") String phone){
    userService.sendCode(phone);
    return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
    }

    2.2.2 service

    这里的逻辑会稍微复杂:

    • 生成随机验证码
    • 将验证码保存到Redis中,用来在注册的时候验证
    • 发送验证码到
      ly-sms-service
      服务,发送短信
    // 发送短信验证码
    public void sendCode(String phone) {
    // 生成key
    String key = KEY_PREFIX + phone;
    // 生成验证码
    String code = NumberUtils.generateCode(6);
    
    Map<String, String> msg = new HashMap<>();
    msg.put("phone", phone);
    msg.put("code", code);
    // 发送验证码
    amqpTemplate.convertAndSend("ly.sms.exchange","sms.verify.code",msg);
    
    // 保存验证码到redis中 以供后续验证
    redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
    }

    注意:要设置短信验证码在Redis的缓存时间为5分钟

    2.3 实现注册功能

    功能说明

    先对用户输入的短信验证码进行校验,随后实现用户注册功能,对用户密码进行加密存储,使用MD5加密,加密过程中使用随机码作为salt加盐。

    接口路径

    POST /register

    参数说明:

    form表单格式

    参数 说明 是否必须 数据类型 默认值
    username 用户名,格式为4~30位字母、数字、下划线 String
    password 用户密码,格式为4~30位字母、数字、下划线 String
    phone 手机号码 String
    code 短信验证码 String

    返回结果:

    无返回值。

    状态码:

    • 201:注册成功
    • 400:参数有误,注册失败
    • 500:服务器内部异常,注册失败

    2.3.1 controller

    @PostMapping("register")
    public ResponseEntity<Void> register(User user, @RequestParam("code") String code) {
    Boolean boo = this.userService.register(user, code);
    if (boo == null || !boo) {
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
    }
    return new ResponseEntity<>(HttpStatus.CREATED);
    }
    • @RequestParam

      get和post请求传的参数会自动转换赋值到
      @RequestParam
      所注解的变量上
      @RequestParam
      org.springframework.web.bind.annotation.RequestParam
      )用于将指定的请求参数赋值给方法中的形参。

    2.3.2 service

    基本逻辑:

    • 1)校验短信验证码
    • 2)生成盐
    • 3)对密码加密
    • 4)写入数据库
    // 用户注册
    public void register(@Valid User user, String code) {
    
    // 校验验证码:redis中的验证码和页面的验证码进行比较
    String cacheCode = redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone());
    if(!StringUtils.equals(cacheCode, code)){
    throw new LyException(ExceptionEnum.INVALID_VERIFY_CODE);
    }
    
    // 对密码进行加密
    String salt = CodecUtils.generateSalt();
    user.setSalt(salt);
    user.setPassword(CodecUtils.md5Hex(user.getPassword() , salt));
    
    // 写入数据库
    user.setCreated(new Date());
    userMapper.insert(user);
    }

    2.3.3 服务端数据校验

    刚才虽然实现了注册,但是服务端并没有进行数据校验,而前端的校验是很容易被有心人绕过的。所以我们必须在后台添加数据校验功能:

    我们这里会使用

    Hibernate-Validator
    框架完成数据校验:

    而SpringBoot的web启动器中已经集成了相关依赖:

    什么是Hibernate Validator

    Hibernate Validator
    Hibernate
    提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验。

    hibernate Validator

    Bean Validation
    的参考实现 。

    Hibernate Validator
    提供了 JSR 303 规范中所有内置
    constraint
    (约束) 的实现,除此之外还有一些附加的 constraint。

    在日常开发中,

    Hibernate Validator
    经常用来验证bean的字段,基于注解,方便快捷高效。

    给User添加校验

    我们在

    ly-user-interface
    中添加
    Hibernate-Validator
    依赖:

    <dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    </dependency>

    在User对象的部分属性上添加注解:

    @Data
    @Table(name = "tb_user")
    public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotEmpty(message = "用户名不能为空!")
    @Length(min = 4, max = 32, message = "用户名长度必须在4~32位之间")
    private String username;// 用户名
    
    @Length(min = 4, max = 32, message = "密码长度必须在4~32位之间")
    @JsonIgnore
    private String password;// 密码
    
    @Pattern(regexp = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$", message = "手机号码格式有误!")
    private String phone;// 电话
    
    private Date created;// 创建时间
    
    @JsonIgnore
    private String salt;// 密码的盐值
    }

    在controller上进行控制

    要想校验生效,需要在controller上添加注解,

    @Valid


    如果输入的参数不符合规范,SpringMVC会自动返回错误信息。

    可以看出所有错误信息的详细信息都被展示出来了,但是看着太繁琐了,我们想自己处理,怎么办呢?改造controller如下(这部分可以不做):

    2.4 根据用户名和密码查询用户

    功能说明

    查询功能,根据参数中的用户名和密码查询指定用户

    接口路径

    GET /query

    参数说明:

    form表单格式

    参数 说明 是否必须 数据类型 默认值
    username 用户名,格式为4~30位字母、数字、下划线 String
    password 用户密码,格式为4~30位字母、数字、下划线 String

    返回结果:

    用户的json格式数据

    {
    "id": 6572312,
    "username":"test",
    "phone":"13688886666",
    "created": 1342432424
    }

    状态码:

    • 200:注册成功
    • 400:用户名或密码错误
    • 500:服务器内部异常,注册失败

    2.4.1 controller

    @GetMapping("query")
    public ResponseEntity<User> queryUsernameAndPassword(
    @RequestParam("username") String username,
    @RequestParam("password") String password){
    
    return ResponseEntity.ok(userService.queryUsernameAndPassword(username,password));
    }

    2.4.2 service

    public User queryUsernameAndPassword(String username, String password) {
    
    User record = new User();
    record.setUsername(username);
    // 根据用户名查询用户
    User user = userMapper.selectOne(record);
    // 校验用户名
    if(user == null){
    throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
    }
    // 校验密码
    if(! StringUtils.equals(user.getPassword(), CodecUtils.md5Hex(password , user.getSalt()))){
    throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
    }
    
    return user;
    }

    说明:我们查询的时候只根据用户名来查,因为我们在设计数据库时给用户名这个字段添加了索引,加了索引之后,极大提升了查询的效率,但是如果使用用户名和密码来查询,索引就变得形同虚设

    做完了以上几步,在注册页点击注册,可以跳转到登录页,同时数据库中可以查询得到用户信息~

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐