黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)

Nacos注册发现、网关

    • a. 项目介绍
    • b. app登录
      • 1) 需求分析
      • 2) 表结构分析
      • 3) 手动加密(md5+随机字符串)
      • 4) 用户端微服务搭建
      • 5) 功能实现
      • 6) app网关
      • 7) 网关校验jwt
      • 8) 前端集成, 配置nginx

a. 项目介绍

业务说明

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第1张图片

技术栈说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k5BDy2q4-1691417838766)(C:\Users\captaindeng\AppData\Roaming\Typora\typora-user-images\image-20230807140029623.png)]

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第2张图片

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第3张图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yOvDt0kS-1691417838767)(C:\Users\captaindeng\AppData\Roaming\Typora\typora-user-images\image-20230807141737685.png)]

b. app登录

1) 需求分析

  • 用户点击开始使用: 登录后的用户权限较大,可以查看,也可以操作(点赞,关注,评论)
  • 用户点击不登录,先看看: 游客只有查看的权限

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第4张图片

2) 表结构分析

关于app端用户相关的内容较多,可以单独设置一个库leadnews_user

表名称 说明
ap_user APP用户信息表
ap_user_fan APP用户粉丝信息表
ap_user_follow APP用户关注信息表
ap_user_realname APP实名认证信息表

app_user表对应的实体类如下:

/**
 * @author Kyle
 * @date 2023/8/7 14:35
 *
 * App用户信息表
 */
@Data
@TableName("ap_user")
public class ApUser implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 密码、通信等加密盐
     */
    @TableField("salt")
    private String salt;

    /**
     * 用户名
     */
    @TableField("name")
    private String name;

    /**
     * 密码,md5加密
     */
    @TableField("password")
    private String password;

    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;

    /**
     * 头像
     */
    @TableField("image")
    private String image;

    /**
     * 0 男
            1 女
            2 未知
     */
    @TableField("sex")
    private Boolean sex;

    /**
     * 0 未
            1 是
     */
    @TableField("is_certification")
    private Boolean certification;

    /**
     * 是否身份认证
     */
    @TableField("is_identity_authentication")
    private Boolean identityAuthentication;

    /**
     * 0正常
            1锁定
     */
    @TableField("status")
    private Boolean status;

    /**
     * 0 普通用户
            1 自媒体人
            2 大V
     */
    @TableField("flag")
    private Short flag;

    /**
     * 注册时间
     */
    @TableField("created_time")
    private Date createdTime;

}

3) 手动加密(md5+随机字符串)

md5是不可逆加密,md5相同的密码每次加密都一样,不太安全。在md5的基础上手动加盐(salt)处理

注册->生成盐

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第5张图片

登录->使用盐来配合验证

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第6张图片

4) 用户端微服务搭建

在heima-leadnews-service下创建名为heima-leadnews-user的module

在com.heima.user下创建UserApplication

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

创建resources/bookstrap.yml

server:
  port: 51801
spring:
  application:
    name: leadnews-user
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
      config:
        server-addr: 192.168.200.130:8848
        file-extension: yml

在nacos网站中创建配置文件

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第7张图片

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.user.pojos

创建resources/logback.xml



<configuration>
    
    <property name="LOG_HOME" value="e:/logs"/>

    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%npattern>
            <charset>utf8charset>
        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}.logfileNamePattern>
        rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%npattern>
        encoder>
    appender>

    
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        
        <discardingThreshold>0discardingThreshold>
        
        <queueSize>512queueSize>
        
        <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="debug"/>
    <root level="info">
        
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    root>
configuration>

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第8张图片

5) 功能实现

  • 1.用户输入了用户名和密码进行登录,校验成功后返回jwt(基于当前用户的id生成)
  • 2.用户游客登录,生成jwt返回(基于默认值0生成)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4bv6u47-1691417838767)(C:\Users\captaindeng\AppData\Roaming\Typora\typora-user-images\image-20230807153653965.png)]

接口定义

说明
接口路径 /api/v1/login/login_auth
请求方式 POST
参数 LoginDto
响应结果 ResponseResult

实现步骤

0.在model层下创建user.dtos的LoginDto

@Data
public class LoginDto {
    /**
     * 手机号
     */
    private String phone;

    /**
     * 密码
     */
    private String password;
}

1.在controller.v1下创建ApUserLoginController,接口定义

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
    
    @Autowired
    private ApUserService apUserService;

    @PostMapping("/login_auth")
    public ResponseResult login(@RequestBody LoginDto loginDto){
        return apUserService.login(loginDto);
    }

}

2.持久层mapper下创建ApUserMapper

@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}

3.业务层service

public interface ApUserService extends IService<ApUser> {
    /**
     * App端登录功能
     * @param loginDto
     * @return
     */
    public ResponseResult login(LoginDto loginDto);
}

4.实现类

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {

    /**
     * App端登录功能
     * @param loginDto
     * @return
     */
    @Override
    public ResponseResult login(LoginDto loginDto) {
        // 1.正常登录:用户名和密码
        // 1.1 根据手机号查询用户信息
        if (StringUtils.isNotBlank(loginDto.getPhone()) && StringUtils.isNotBlank(loginDto.getPassword())){
            ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, loginDto.getPhone()));
            if (dbUser == null){
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在");
            }

            // 1.2 比对密码
            String salt = dbUser.getSalt();
            String password = loginDto.getPassword();
            String pwsd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
            if (!pwsd.equals(dbUser.getPassword())){
                // 密码错误
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
            }

            // 1.3 返回数据 jwt user
            String token = AppJwtUtil.getToken(dbUser.getId().longValue());

            Map<String, Object> map = new HashMap<>();
            map.put("token", token);
            dbUser.setSalt("");
            dbUser.setPassword("");
            map.put("user", dbUser);
            
            return ResponseResult.okResult(map);
        }else {
            // 2.游客登录
            Map<String, Object> map = new HashMap<>();
            map.put("token", AppJwtUtil.getToken(0L));

            return ResponseResult.okResult(map);
        }
    }
}

6) app网关

网关概述

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第9张图片

1.在heima-leadnews-gateway导入以下依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
         <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
            dependency>
        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwtartifactId>
        dependency>
    dependencies>

(2)在heima-leadnews-gateway下创建heima-leadnews-app-gateway微服务

引导类:

@SpringBootApplication
@EnableDiscoveryClient  //开启注册中心
public class AppGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppGatewayApplication.class,args);
    }
}

bootstrap.yml

server:
  port: 51601
spring:
  application:
    name: leadnews-app-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
      config:
        server-addr: 192.168.200.130:8848
        file-extension: yml

在nacos的配置中心创建dataid为leadnews-app-gateway的yml配置

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第10张图片

spring:
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION
      routes:
        # 平台管理
        - id: user
          uri: lb://leadnews-user
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix= 1

7) 网关校验jwt

黑马头条项目学习--Day1: 环境搭建、SpringCloud微服务(注册发现、网关)_第11张图片

具体实现:

第一:

​ 在认证过滤器中需要用到jwt的解析,所以需要把工具类拷贝一份到网关微服务

第二:

在网关微服务中新建全局过滤器:在gateway/fliter下创建

@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 2.判断是否是登录
        if (request.getURI().getPath().contains("/login")){
            // 放行
            return chain.filter(exchange);
        }

        // 3.获取token
        String token = request.getHeaders().getFirst("token");

        // 4.判断token是否存在
        if (StringUtils.isNotBlank(token)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 5.判断token是否有效
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            // 判断是否过期
            int result = AppJwtUtil.verifyToken(claimsBody);
            if (result == 1 || result == 2) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

        }catch (Exception e){
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 6.放行
        return chain.filter(exchange);
    }

    /**
     * 优先级设置 值越小 优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

8) 前端集成, 配置nginx

①:解压资料文件夹中的压缩包nginx-1.18.0.zip

②:解压资料文件夹中的前端项目app-web.zip

③:配置nginx.conf文件

在nginx安装的conf目录下新建一个文件夹leadnews.conf,在当前文件夹中新建heima-leadnews-app.conf文件

heima-leadnews-app.conf配置如下:

upstream  heima-app-gateway{
    server localhost:51601;
}

server {
	listen 8801;
	location / {
		root D:/workspace/app-web/;
		index index.html;
	}
	
	location ~/app/(.*) {
		proxy_pass http://heima-app-gateway/$1;
		proxy_set_header HOST $host;  # 不改变源请求头的值
		proxy_pass_request_body on;  #开启获取请求体
		proxy_pass_request_headers on;  #开启获取请求头
		proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IP
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息
	}
}

nginx.conf 把里面注释的内容和静态资源配置相关删除,引入heima-leadnews-app.conf文件加载

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
	# 引入自定义配置文件
	include leadnews.conf/*.conf;
}

④ :启动nginx

​ 在nginx安装包中使用命令提示符打开,输入命令nginx启动项目

​ 可查看进程,检查nginx是否启动

​ 重新加载配置文件:nginx -s reload

⑤:打开前端项目进行测试 – > http://localhost:8801

​ 用谷歌浏览器打开,调试移动端模式进行访问

你可能感兴趣的:(黑马头条开发笔记,学习,spring,cloud,微服务,java,spring,spring,boot)