【黑马头条】-day01环境搭建SpringBoot-Cloud-Nacos

news2025/1/15 23:45:06

文章目录

  • 1 环境搭建及简介
  • 2 项目介绍
    • 2.1 应用
    • 2.2 业务说明
    • 2.3 技术栈
    • 2.4 收获
    • 2.5 大纲
  • 3 Nacos准备
    • 3.1 安装Nacos
  • 4 初始工程搭建
    • 4.1 环境准备
      • 4.1.1 导入项目
      • 4.1.2 设置本地仓库
      • 4.1.3 设置项目编码格式
    • 4.2 全局异常
      • 4.2.1 自动装配
    • 4.3 工程主体结构
  • 5 登录功能开发
    • 5.1 需求分析
      • 5.1.1 表结构分析
      • 5.1.2 实体类ApUser的导入
      • 5.1.3 表结构中salt的解释
        • 5.1.3.1 注册过程
        • 5.1.3.2 登录过程
  • 6 用户端微服务的搭建
    • 6.1 service模块的依赖说明
    • 6.2 创建用户微服务模块
      • 6.2.1 创建引导类
      • 6.2.2 创建controller.v1、service、mapper、config
      • 6.2.3 创建resources的配置文件
        • 6.2.3.1 bootstrap.yml
        • 6.2.3.2 logback.xml
    • 6.3 整体用户端框架
  • 7 登录接口实现
    • 7.1 app登录-接口定义
      • 7.1.1 DTO的LoginDto类
      • 7.1.2 Controller层ApUserLoginController类
      • 7.1.3 Mapper层ApUserMapper接口
      • 7.1.4 Service层ApUserService接口
      • 7.1.5 实现ApUserService接口
      • 7.1.6 完善业务层接口
    • 7.2 登录思路分析
      • 7.2.1 业务层登录实现
      • 7.2.2 Controller注入
      • 7.2.3 测试
  • 8 App端网关
    • 8.1 导入依赖
    • 8.2 微服务创建网关
      • 8.2.1 AppGateway
      • 8.2.2 创建配置文件bootstrap.yml
      • 8.2.3 在Nacos中创建配置中心
  • 9 认证过滤器
    • 9.1 全局过滤器
    • 9.2 测试
  • 10 app前端项目集成
    • 10.1 Nginx反向代理和静态资源配置


1 环境搭建及简介

在这里插入图片描述

在这里插入图片描述

2 项目介绍

2.1 应用

在这里插入图片描述

2.2 业务说明

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.3 技术栈

前端
在这里插入图片描述

后端

在这里插入图片描述

2.4 收获

在这里插入图片描述

2.5 大纲

在这里插入图片描述

3 Nacos准备

3.1 安装Nacos

在这里插入图片描述

1)拉取镜像

docker pull nacos/nacos-server:1.2.0

2)创建容器

docker run --env MODE=standalone --name nacos --restart=always -d -p 8848:8848 nacos/nacos-server:1.2.0

3)查看日志

docker logs -f nacos

在这里插入图片描述

4)访问当前Nacos

http://192.168.204.129:8848/nacos

4 初始工程搭建

4.1 环境准备

4.1.1 导入项目

在这里插入图片描述

解压heima-leadnews.zip,并且导入idea,设置jdk为1.8
在这里插入图片描述

4.1.2 设置本地仓库

respository_new.zip解压到本地仓库文件夹

打开idea-settings设置本地仓库
在这里插入图片描述

修改为
在这里插入图片描述

4.1.3 设置项目编码格式

在这里插入图片描述

4.2 全局异常

在这里插入图片描述

heima-leadnews-common模块下的com.heima.common.exception包下自定义异常类CustomException,如果我们手动抛出异常就需要抛出CustomException类

public class CustomException extends RuntimeException {

    private AppHttpCodeEnum appHttpCodeEnum;

    public CustomException(AppHttpCodeEnum appHttpCodeEnum){
        this.appHttpCodeEnum = appHttpCodeEnum;
    }

    public AppHttpCodeEnum getAppHttpCodeEnum() {
        return appHttpCodeEnum;
    }
}

另外一个类ExceptionCatch类,全局异常拦截类

注解@ControllerAdvice:ControllerAdvice本质上是一个Component,因此也会被当成组件扫描,一视同仁,扫扫扫。

  • 这个类是为那些声明了(@ExceptionHandler、@InitBinder 或 @ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。
@ControllerAdvice  //控制器增强类
@Slf4j
public class ExceptionCatch {

    /**
     * 处理不可控异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult exception(Exception e){
        e.printStackTrace();
        log.error("catch exception:{}",e.getMessage());

        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }

    /**
     * 处理可控异常  自定义异常
     * @param e
     * @return
     */
    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult exception(CustomException e){
        log.error("catch exception:{}",e);
        return ResponseResult.errorResult(e.getAppHttpCodeEnum());
    }
}

在heima-leadnews-model模块下的com.heima.model包下的common包下的enums包下有个枚举类AppHttpCodeEnum,用来存放对异常的说明

public enum AppHttpCodeEnum {

    // 成功段0
    SUCCESS(200,"操作成功"),
    // 登录段1~50
    NEED_LOGIN(1,"需要登录后操作"),
    LOGIN_PASSWORD_ERROR(2,"密码错误"),
    // TOKEN50~100
    TOKEN_INVALID(50,"无效的TOKEN"),
    TOKEN_EXPIRE(51,"TOKEN已过期"),
    TOKEN_REQUIRE(52,"TOKEN是必须的"),
    // SIGN验签 100~120
    SIGN_INVALID(100,"无效的SIGN"),
    SIG_TIMEOUT(101,"SIGN已过期"),
    // 参数错误 500~1000
    PARAM_REQUIRE(500,"缺少参数"),
    PARAM_INVALID(501,"无效参数"),
    PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),
    SERVER_ERROR(503,"服务器内部错误"),
    // 数据错误 1000~2000
    DATA_EXIST(1000,"数据已经存在"),
    AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"),
    DATA_NOT_EXIST(1002,"数据不存在"),
    // 数据错误 3000~3500
    NO_OPERATOR_AUTH(3000,"无权限操作"),
    NEED_ADMIND(3001,"需要管理员权限");

    int code;
    String errorMessage;

    AppHttpCodeEnum(int code, String errorMessage){
        this.code = code;
        this.errorMessage = errorMessage;
    }

    public int getCode() {
        return code;
    }

    public String getErrorMessage() {
        return errorMessage;
    }
}

4.2.1 自动装配

resource下META-INF有spring.factories,只有有微服务引用了heima-leadnews-common,服务器初始化spring容器的时候就会找到spring.factories,把spring.factories中需要自动配置的文件加载到当前微服务的容器中,也就能用全局处理器了。

在这里插入图片描述

4.3 工程主体结构

在这里插入图片描述

5 登录功能开发

5.1 需求分析

在这里插入图片描述

5.1.1 表结构分析

打开本地sql工具,引入sql脚本,创建leadnews_user,有四张表

在这里插入图片描述

在这里插入图片描述

5.1.2 实体类ApUser的导入

在heima-leadnews-model模块下创建com.heima.model.user.pojos包下创建实体类ApUser

@TableName("ap_user"):表的映射

@TableId(value = "id", type = IdType.AUTO):主键的映射

@TableField("name"):其他字段的映射

@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;

}

5.1.3 表结构中salt的解释

salt:密码、通信等加密盐

5.1.3.1 注册过程

在这里插入图片描述

5.1.3.2 登录过程

在这里插入图片描述

6 用户端微服务的搭建

heima-leadnews-service模块是管理其他所有微服务模块

6.1 service模块的依赖说明

在这里插入图片描述

6.2 创建用户微服务模块

在heima-leadnews-service下创建模块

在这里插入图片描述

6.2.1 创建引导类

然后创建一个包com.heima.user,再创建一个引导类UserApplication

@SpringBootApplication: 启动类注解

@EnableDiscoveryClient :集成当前的注册中心,加入注册中心

@MapperScan("com.heima.user.mapper") :继承MybatisPlus,扫描Mapper接口,没有就在com.heima.user下创建mapper包

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

6.2.2 创建controller.v1、service、mapper、config

controller.v1是不同版本的controller

在这里插入图片描述

6.2.3 创建resources的配置文件

6.2.3.1 bootstrap.yml

若application.yml 和bootstrap.yml在同一目录下:bootstrap.yml 先加载 application.yml后加载,application.yml会覆盖

创建bootstrap.yml

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

这里面暂时只有Nacos的配置,关于数据库的等等都需要在Nacos的配置中心进行配置

在这里插入图片描述

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


发布查看

6.2.3.2 logback.xml

创建日志文件logback.xml

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

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="D:\Code\JavaCode\HeimaToutiao\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="debug"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

6.3 整体用户端框架

在这里插入图片描述

7 登录接口实现

7.1 app登录-接口定义

在这里插入图片描述

7.1.1 DTO的LoginDto类

heima-leadnews-model模块下的com.heima.model.user.pojos.dtos包下创建LoginDto类

@Data
public class LoginDto {
    private String phone;
    private String password;
}

7.1.2 Controller层ApUserLoginController类

再在heima-leadnews-service模块下的com.heima.user.controller.v1下创建ApUserLoginController类

POST请求采用@RequestBody

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
    @PostMapping("/login_auth")
    public ResponseResult login(@RequestBody(required=false) LoginDto dto) {
        return null;
    }
}

7.1.3 Mapper层ApUserMapper接口

使用mybatisplus

在com.heima.user.mapper创建ApUserMapper接口

@Mapper
public interface ApUsermapper extends BaseMapper<ApUser> {

}

7.1.4 Service层ApUserService接口

public interface ApUserService extends IService<ApUser>{
}

7.1.5 实现ApUserService接口

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

@Service标注业务层实现

@Transactional标注事务

7.1.6 完善业务层接口

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

实现方法

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUsermapper, ApUser> implements ApUserService {
    @Override
    public ResponseResult login(LoginDto dto) {
        return null;
    }
}

7.2 登录思路分析

7.2.1 业务层登录实现

在这里插入图片描述

在ApUserServiceImpl类中实现思路

@Service
@Transactional
@Slf4j
public class ApUserServiceImpl extends ServiceImpl<ApUsermapper, ApUser> implements ApUserService {
    @Override
    public ResponseResult login(LoginDto dto) {
        //1.正常登录 用户名、密码
        if(StringUtils.isNotBlank(dto.getPhone()) && StringUtils.isNotBlank(dto.getPassword())) {
            //1.1 查询用户信息,根据手机号查询用户信息
            ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
            if(dbUser == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST, "用户不存在");
            }
            //1.2 比对密码
            String salt = dbUser.getSalt();
            String password = dto.getPassword();
            String pwd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
            if(!pwd.equals(dbUser.getPassword())) {
                return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, "密码错误");
            }
            //1.3 没问题的话,返回数据,生成jwt
            String token = AppJwtUtil.getToken(dbUser.getId().longValue());
            Map<String,Object> map=new HashMap<>();
            map.put("token",token);
            //清空敏感信息,前端只要id,手机号,昵称
            ApUser userVO=new ApUser();
            userVO.setId(dbUser.getId());
            userVO.setPhone(dbUser.getPhone());
            userVO.setName(dbUser.getName());
            map.put("user",userVO);
            return ResponseResult.okResult(map);
        }else{
            //2.游客登录
            Map<String,Object> map=new HashMap<>();
            map.put("token",AppJwtUtil.getToken(0L));
            return ResponseResult.okResult(map);
        }
    }
}

加密采用DigestUtils.md5DigestAsHex传入字节流

生成JWT令牌是使用heima-leadnews-utils模块下的com.heima.utils.common包下的AppJWTUtil

public class AppJwtUtil {

    // TOKEN的有效期一天(S)
    private static final int TOKEN_TIME_OUT = 3_600;
    // 加密KEY
    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
    // 最小刷新间隔(S)
    private static final int REFRESH_TIME = 300;

    // 生产ID
    public static String getToken(Long id){
        Map<String, Object> claimMaps = new HashMap<>();
        claimMaps.put("id",id);
        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))  //签发时间
                .setSubject("system")  //说明
                .setIssuer("heima") //签发者信息
                .setAudience("app")  //接收用户
                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                .signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳
                .addClaims(claimMaps) //cla信息
                .compact();
    }

    /**
     * 获取token中的claims信息
     *
     * @param token
     * @return
     */
    private static Jws<Claims> getJws(String token) {
            return Jwts.parser()
                    .setSigningKey(generalKey())
                    .parseClaimsJws(token);
    }

    /**
     * 获取payload body信息
     *
     * @param token
     * @return
     */
    public static Claims getClaimsBody(String token) {
        try {
            return getJws(token).getBody();
        }catch (ExpiredJwtException e){
            return null;
        }
    }

    /**
     * 获取hearder body信息
     *
     * @param token
     * @return
     */
    public static JwsHeader getHeaderBody(String token) {
        return getJws(token).getHeader();
    }

    /**
     * 是否过期
     *
     * @param claims
     * @return -1:有效,0:有效,1:过期,2:过期
     */
    public static int verifyToken(Claims claims) {
        if(claims==null){
            return 1;
        }
        try {
            claims.getExpiration()
                    .before(new Date());
            // 需要自动刷新TOKEN
            if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){
                return -1;
            }else {
                return 0;
            }
        } catch (ExpiredJwtException ex) {
            return 1;
        }catch (Exception e){
            return 2;
        }
    }

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    public static void main(String[] args) {
       /* Map map = new HashMap();
        map.put("id","11");*/
        System.out.println(AppJwtUtil.getToken(1102L));
        Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA");
        Claims claims = jws.getBody();
        System.out.println(claims.get("id"));

    }

}

7.2.2 Controller注入

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
    @Autowired
    private ApUserService apUserService;
    
    @PostMapping("/login_auth")
    public ResponseResult login(@RequestBody LoginDto dto) {
        return apUserService.login(dto);
    }
}

7.2.3 测试

启动redis报错

修改bootstrap.yml文件,添加redis地址

redis:
  host: 127.0.0.1
  port: 6379
  database: 0

启动,Nacos的服务管理中有leadnews-user

访问http://localhost:51801/api/v1/login/login_auth

在这里插入图片描述

8 App端网关

在这里插入图片描述
在这里插入图片描述

8.1 导入依赖

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

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
     <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
    </dependency>
</dependencies>

8.2 微服务创建网关

8.2.1 AppGateway

针对各个微服务创建相应的网关

在这里插入图片描述

创建引导类com.heima.app.gateway.AppGatewayApplication

@SpringBootApplication
@EnableDiscoveryClient
public class AppGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppGatewayApplication.class, args);

    }
}

8.2.2 创建配置文件bootstrap.yml

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

8.2.3 在Nacos中创建配置中心

在这里插入图片描述

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
  • id: user: 这是此路由的唯一标识符。
  • uri: lb://leadnews-user: 当请求匹配到该路由时,它会被路由到"leadnews-user"服务的实例。URI的前缀"lb://"表示路由到负载均衡器。
  • predicates: 定义了路由的匹配规则。在这种情况下,请求路径必须以"/user/"开头才会匹配到此路由。
  • filters: 定义了路由的过滤器。在这里,使用了"StripPrefix"过滤器,该过滤器会将请求的路径中的一层前缀移除。具体来说,这里是将路径中的第一层"/user"移除,以便在转发请求到"leadnews-user"服务时去除不必要的前缀。

访问http://localhost:51601/user/api/v1/login/login_auth

在这里插入图片描述

9 认证过滤器

在这里插入图片描述

9.1 全局过滤器

要实现这个功能,要实现一个全局的过滤器

在heima-leadnews-gateway模块下创建com.heima.app.gateway.filter.AuthorizeFilter类用作全局过滤器

@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.isBlank(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //5.判断token是否有效
        //5.1 解析token
        try{
            Claims body = AppJwtUtil.getClaimsBody(token);
            //5.2 判断token是否有效
            int result = AppJwtUtil.verifyToken(body);
            if(result == 1||result == 2) {
                //5.3 token过期
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }
        }catch (Exception e) {
            e.printStackTrace();
            //5.4 token无效
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //6.放行
        return chain.filter(exchange);
    }

    /**
     * 过滤器的执行顺序,返回值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

把AppJwtUtil放入gateway的工具包中

在这里插入图片描述

9.2 测试

包含/login直接放行

在这里插入图片描述

10 app前端项目集成

10.1 Nginx反向代理和静态资源配置

在这里插入图片描述

在这里插入图片描述

访问http://localhost:80

在这里插入图片描述

将静态资源和nginx都放在工作目录下

在nginx的conf目录下创建文件夹leadnews.conf,新建文件heimi-leadnews-app.conf

nginx端口8801然后转发到gateway端口51601,gateway添加user路径后通过Nacos路由到leadnews-user也就是端口51801完成访问

静态资源存放在D:/Code/JavaCode/HeimaToutiao/app-web/展示其目录下的index.html

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

server {
	listen 8801;
	location / {
        root D:/Code/JavaCode/HeimaToutiao/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中引入

#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;
}

访问http://localhost:8801

在这里插入图片描述

访问成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1530712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于《动手学深度学习》找不到d2l.......和#@save的思考

在运行书上的代码时&#xff0c;会出现报错。 最后通过简单粗暴的方法解决了这个问题&#xff0c;在此记录一下。 一、#save是什么 # 表明是注释&#xff0c;所以这句话对代码没有影响&#xff0c;只是一个“标识”&#xff0c;表明在d2l文档中&#xff0c;作者已经写好了这…

实用翻译英语的Chrome插件

工作中&#xff0c;时常需要阅读网页技术文档&#xff0c;阅读英语技术论文&#xff0c;对翻译的需求很迫切&#xff1b; Chrome默认的翻译比较呆板&#xff1b; 这边推介更加智能的双语翻译&#xff0c;同时支持pdf翻译&#xff0c;下载地址&#xff1a; https://chrome.goo…

设计模式之简单工厂模式详解

简单工厂模式 工厂模式&#xff1a;工厂方法模式&#xff1b; 低阶&#xff1a;简单工厂模式&#xff1b; 高阶&#xff1a;抽象工厂模式&#xff1b; 1&#xff09;概述 定义一个工厂类&#xff0c;根据参数的不同返回不同类的实例&#xff0c;被创建的实例通常都具有共同…

设备安全与设备管理系统的融合发展之路

随着企业运营的不断复杂化和市场竞争的加剧&#xff0c;设备安全与设备管理系统的融合发展已经成为企业追求卓越运营、实现持续发展的必经之路。这种融合不仅提升了设备的安全性&#xff0c;更提高了设备管理的效率与精准度&#xff0c;为企业的整体运营奠定了坚实基础。 一、设…

华为机试真题练习汇总(81~90)

华为机试真题练习汇总&#xff08;81~90&#xff09; 华为机试真题练习汇总&#xff08;81~90&#xff09;HJ81 字符串字符匹配** HJ82 将真分数分解为埃及分数HJ83 二维数组操作HJ84 统计大写字母个数HJ85 最长回文子串HJ86 求最大连续bit数HJ87 密码强度等级* HJ88 扑克牌大小…

Go语言实战:深入掌握标准库flag的强大用法

Go语言实战&#xff1a;深入掌握标准库flag的强大用法 引言flag库基础命令行参数的基本概念使用flag库定义和解析命令行参数处理非选项命令行参数小结 高级用法自定义Flag的解析命令行参数的分组和嵌套小结 实战技巧组织复杂命令行应用的参数错误处理和用户帮助信息调试命令行应…

PHP 服务实现监控可观测性最佳实践

前言 本次实践主要是介绍 PHP 服务通过无侵入的方式接入观测云进行全面的可观测。 环境信息 主机环境&#xff1a;CentOS 7.8PHP&#xff1a;7.4.33MySQL&#xff1a;5.7 接入方案 准备工作 安装 DataKit # 需要把token 改成观测云空间的实际token值&#xff08;可在观测…

G*T、文心一言微信 AI 机器人的时代已经来临!

前言 在当今的科技时代&#xff0c;人工智能&#xff08;AI&#xff09;的发展速度可谓是日新月异。其中&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域的模型&#xff0c;如 G*T、文心一言等&#xff0c;已经成为了 AI 领域的主流。不仅如此&#xff0c;将 AI 接入…

铸铁平台制造工艺有多精细你知道吗——河北北重

铸铁平台的制造工艺要求相对较高&#xff0c;需要经过以下精细工艺&#xff1a; 材料选择&#xff1a;铸铁平台通常使用灰口铸铁&#xff0c;其具有良好的耐磨性和强度。材料的选择要考虑到使用环境和平台的功能需求。 模具制造&#xff1a;根据设计要求制作模具&#xff0c;模…

算法---二分查找练习-3(山脉数组的顶峰索引)

山脉数组的顶峰索引 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 初始化两个指针 left 和 right&#xff0c;分别指向数组的起始位置和结束位置。 进入循环&#xff0c;循环条件为 left < right。 在每次循环中&…

全平台(淘宝1688京东)商品详情API接口(item_get-获得全平台商品详情接口)

全平台商品详情API接口&#xff08;item_get-获得全平台商品详情接口&#xff09;&#xff0c;全平台API接口可获取到商品链接&#xff0c;商品ID&#xff0c;商品标题&#xff0c;商品价格&#xff0c;品牌名称&#xff0c;店铺昵称&#xff0c;sku规格&#xff0c;sku属性&am…

自注意力机制的理解

一、自注意力要解决什么问题 循环神经网络由于信息传递的容量以及梯度消失问题&#xff0c;只能建立短距离依赖关系。为了建立长距离的依赖关系&#xff0c;可以增加网络的层数或者使用全连接网络。但是全连接网络无法处理变长的输入序列&#xff0c;另外&#xff0c;不同的输…

【Android】【Bluetooth Stack】蓝牙电话本协议之同步通讯录分析(超详细)

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】专栏会持续更新中.....敬请期待&#xff01; 目录 1. 协议简述 1.1 PBAP…

【十二】【算法分析与设计】滑动窗口(3)

30. 串联所有单词的子串 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff…

【Godot4.2】 基于SurfaceTool的3D网格生成与体素网格探索

概述 说明&#xff1a;本文基础内容写于2023年6月&#xff0c;由三五篇文章汇总而成&#xff0c;因为当时写的比较潦草&#xff0c;过去时间也比较久了&#xff0c;我自己都得重新阅读和理解一番&#xff0c;才能知道自己说了什么&#xff0c;才有可能重新优化整理。 因为我对…

使用WordPress在US Domain Center上建立摄影网站的详细教程

第一部分&#xff1a;介绍摄影网站 摄影网站是摄影师展示作品、分享经验、提供服务的在线平台。在摄影网站上&#xff0c;摄影师可以展示自己的摄影作品、发布摄影日志、接受客户预约等。使用WordPress搭建摄影网站具有灵活性和可扩展性&#xff0c;可以通过选择适合的主题和插…

视频转文字怎么转?这几个转换方法收藏一下

视频转文字怎么转&#xff1f;在信息爆炸的时代&#xff0c;视频内容日益丰富&#xff0c;但如何快速、准确地提取视频中的关键信息却成为了一个挑战。本文将为你详细介绍视频转文字的方法&#xff0c;让你轻松提取视频内容&#xff0c;提高信息获取效率。 方法一&#xff1a;清…

【赠书第21期】游戏力:竞技游戏设计实战教程

文章目录 前言 1 竞技游戏设计的核心要素 1.1 游戏机制 1.2 角色与技能 1.3 地图与环境 2 竞技游戏设计的策略与方法 2.1 以玩家为中心 2.2 不断迭代与优化 2.3 营造竞技氛围与社区文化 3 实战案例分析 4 结语 5 推荐图书 6 粉丝福利 前言 在数字化时代的浪潮中&…

IO多分复用

#include<myhead.h> #define SER_PORT 8888 //服务器端口号 #define SER_IP "192.168.65.131" //服务器IPint main(int argc, const char *argv[]) {//1、创建一个套接字int sfd -1;sfd socket(AF_INET, SOCK_STREAM, 0); //参数1&#xff1a;…

win10共享了连接打印机报错提示0000011B

在Windows 10系统中&#xff0c;当用户尝试连接共享打印机时遇到错误代码0x0000011B&#xff0c;通常表示存在与打印机驱动程序或系统更新相关的兼容性问题。以下是针对这个问题的一些解决方案&#xff1a; 卸载特定系统更新&#xff1a; 根据多个来源的信息&#xff0c;错误0x…