黑马头条项目(一):APP用户登录

一. 项目概述

1. 项目结构

2. 项目技术栈

 3. 项目模块介绍

二. 项目知识点总结

1.  @EnableDiscoveryClient注解

@SpringBootApplication
@EnableDiscoveryClient // 将服务注册到服务注册中心
@MapperScan("com.heima.wemedia.mapper")
public class WemediaApplication {

    public static void main(String[] args) {
        SpringApplication.run(WemediaApplication.class, args);
    }

}

SpringCloud中的注解,用于开启应用程序的服务发现功能,可以让应用程序变为一个服务注册中心的客户端。项目中使用Nacos,如果在yml中配置了Nacos相关信息,并且引入了对应的服务发现依赖,此注解可以省略不写。

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2. 日志文件logback.xml的配置

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="e:/logs"/>

    <!-- Console 输出设置 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 异步输出 -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE"/>
    </appender>


    <logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <logger name="org.springframework.boot" level="info"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

启动对应服务时,对于控制台输出的日志程度,可以通过修改Level="debug",将debug修改为info或其他日志输出等级,来改变控制台日志的输出详细程度。

<logger name="org.springframework.boot" level="debug"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>

3. APP用户登录功能

业务层代码如下:

@Override
    public ResponseResult login(LoginDto loginDto) {
        // 用于存储构造的返回值
        Map<String, Object> result = new HashMap<>();

        // 如果传入的手机号不为空,则和数据库中的手机号开始比对
        if (!StringUtils.isBlank(loginDto.getPhone())) {
            // getOne方法会返回满足条件的一个对象,多条数据满足条件时,则返回第一条
            // eq方法第一个参数为要对比的实体属性,第二个参数为比较的值
            // ::用来创建方法引用,引用ApUser类的getPhone()方法
            ApUser apUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, loginDto.getPhone()));
            if (apUser == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
            }

            // 若比对到了正确的手机号,则校验密码
            // 加密盐:盐值随机生成,与密码组合后进行加密运算,即使不同用户密码相同,密文也会不同
            String salt = apUser.getSalt();
            String pwd = loginDto.getPassword();
            pwd = DigestUtils.md5DigestAsHex((pwd + salt).getBytes());
            if (!pwd.equals(apUser.getPassword())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
            }

            // 生成Token
            result.put("token", AppJwtUtil.getToken(apUser.getId().longValue()));
            apUser.setPassword("");
            apUser.setSalt("");
            result.put("user", apUser);
        } else {
            // 游客登录,以账号”0“生成token,返回给客户端
            result.put("token",AppJwtUtil.getToken(0L));
        }
        return ResponseResult.okResult(result);
    }

请求数据实体类LoginDTO:

@Data
public class LoginDto {

    // 手机号
    @ApiModelProperty(value = "手机号", required = true)
    private String phone;

    // 密码
    @ApiModelProperty(value = "密码", required = true)
    private String password;

}

(1)isEmpty 和 isBlank 的区别:

if (!StringUtils.isBlank(loginDto.getPhone()))

isEmpty 方法用于判断字符串是否为空,在判断时会忽略字符串中的空格符

isBlank  方法用于判断字符串是否为空或者只包含空格符

String str1 = "";
String str2 = " ";
String str3 = null;

System.out.println(str1.isEmpty()); // true
System.out.println(str2.isEmpty()); // false
System.out.println(str3.isEmpty()); // NullPointerException

System.out.println(str1.isBlank()); // true
System.out.println(str2.isBlank()); // true
System.out.println(str3.isBlank()); // NullPointerException

(2)getOne方法,eq方法:

ApUser apUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone,loginDto.getPhone()));

if (apUser == null) {
    return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
}

对于getOne方法,如果满足条件,方法会返回一个对象,不满足则返回null。当多条数据都满足条件时,会返回第一条数据。

对于eq方法,有两个参数,第一个参数为想要对比的实体属性,第二个参数为比较的值。

ApUser实体类对应的是数据库中的ap_user表,代码中的含义就是通过创建方法引用,将前端请求数据中的phone值设置为条件,查询数据库ap_user表中where phone = # {loginDto.getPhone}的数据行,封装为对象并返回。

(3)Token生成注意事项:

// 生成Token
result.put("token", AppJwtUtil.getToken(apUser.getId().longValue()));
apUser.setPassword("");
apUser.setSalt("");
result.put("user", apUser);

给前端返回的token令牌中,应该抹除password以及salt盐值,确保用户的密码安全。

4. 网关校验

spring:
  cloud:
    gateway:
      # 配置路由
      routes:
        # 配置用户微服务
        - id: user
          uri: lb://leadnews-user
          predicates:
            - Path=/user/**
          # 设置过滤器,将传入请求的前缀的第一个路径段去除
          filters:
            - StripPrefix= 1

APP发送请求时,会在请求路径前添加/user/,所以我们需要在网关配置yml时,添加过滤器添加StripPrefix属性,去除第一个路径段,使请求路径变为我们Controller层中的实际路径。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值