Project2_过渡2_基于SpringCloud的管理员模块实现

一、项目环境

  1. 后端技术栈:Mybatis, SpringBoot-2.2.5.RELEASE,SpringCloud(nacos+gateway)
  2. 数据库:mySql; Redis
  3. 软体:jdk1.8; IntelliJ IDEA2019; Centos7虚拟机; MobaXterm; RDM; Postman

二、文章主题

  1. 内容概述:为实现SpringCloud_Video项目,对其中P1~21部分内容进行复现。
  2. 项目源码:videoProject01_pub : dev02
  3. 功能展示:
    在这里插入图片描述
    在这里插入图片描述

三、文章内容

1. 后台管理系统的编写

  • Step1:虚拟机配置双网卡,使虚拟机网络ip稳定。
  • Step2:构建maven父项目 qs-admin: 用于维护依赖坐标的版本。
  • Step3:构建maven子公共项目 qs-commons: 用于维护公共工具类、代码、依赖
  • Step4:构建子微服务模块:qs-category, qs-users, qs-videos, qs-admins, qs-gateway
    注意:对于子微服务模块,在commons中引入springbootweb依赖,子微服务引入commons依赖;而gateway引commons依赖要排除commons中的springbootweb依赖,即gateway是特殊的springboot应用。
  • Step5:子微服务模块写配置yml文件,构建出springboot应用。
  • Step6:写docker-compose.yml,实现nacos注册中心:
version: "3.3"

networks:
  easywatch_network:

services:
  nacos:
    image: nacos/nacos-server:2.0.2
    ports:
      - "8848:8848"
    environment:
      - "JVM_XMS=256m"
      - "JVM_XMX=256m"
      - "MODE=standalone"
    networks:
      - easywatch_network

(1) 在虚拟机docker上启动nacos==>docker-compose up -d,此时外部可访问nacos注册中心(http://xxx.xxx.xxx.xxx:8848/nacos/#/login,用户名密码皆为nacos);
(2) 在commons中引入nacos依赖,由此全部子微服务就引入了nacos依赖,在全部子微服务的yml配置文件中配置nacos,重新run子微服务后即可全部注册到nacos。

  • Step7:每个子微服务写测试用的DemoController,而后写gateway微服务
    (1) gateway的作用是 rouer路由+filter过滤;
    (2) 由于所有后端接口的入口都是网关,所以在此处可以进行token身份认证;
    (3) 再次强调,网关是一种特殊的springboot微服务,不需要springweb依赖。
    (4) 测试时,先引网关依赖,再写网关配置yml文件即可。详见视频P3
    (5) predicates(断言),是前端请求进入网关之前的一个验证,满足条件即可进入,不满足便无法进入;但是在进入之后,在网关转发前端请求之前要加入filter过滤器,而后才能进入后端微服务。
    (6) 网关yml配置文件中还要加入允许跨域的配置。
  • Step8:配置docker-compose.yml,使得虚拟机通过docker接入数据库
volumes:
  data:
  
services:
  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    networks:
      - easywatch_network
    volumes:
      - data:/var/lib/mysql
      - ./easywatch.sql:/docker-entrypoint-initdb.d/easywatch.sql
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=easywatch"
  • Step9:写接口
    其中,docker-compose中配置redis的代码为:
volumes:
  redisdata:

services:
  redis:
    image: redis:5.0.10
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data
  • Step10:前端测试
    对于dist文件,执行 npm install -p anywhere(全局安装anywhere,anywhere是一个小型服务器,可在win环境下运行dist文件),而后执行anywhere -p xxxx。

2. 后台总结之redis的使用

  • 推荐使用的redis方式:在书写业务先关数据时一定要加入对应的业务key信息(一般是一个固定写死的常量),设计如下:
// 接口中的属性都是公开的静态的常量
public interface RedisPrefix {
    String TOKEN_KEY = "TOKEN:"; // 代表用户认证tokenkey
}
  • redisTemplate的使用:
    (1) 问题:1)redisTemplate操作对象时key和value都是对象,而我们往往需要key是String而value是对象;2)redisTemplate存放对象必须实现对象序列化。
    (2) 改造:1)key使用String序列化方法; 2)value放入的对象修改为json序列化方式。
    (3) 途径:构建ReidsTemplateConfig配置类:
package com.salieri.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

// 工厂在启动过程中会走这个配置类
// 工厂启动后这个配置类就做完了
@Configuration
public class RedisTemplateConfig {

    @Autowired // 这说明构造方法中要给这个类注入这个对象,但实际上此时没用到这个对象
    public RedisTemplateConfig(RedisTemplate redisTemplate) {
        //1.创建jackson序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
                Object.class);
        //2..创建object mapper
        ObjectMapper objectMapper = new ObjectMapper();

        // 3,4得redis中的json可被转换回来
        //3.允许访问对象中所有属性
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //4.转换json过程中保存类的信息
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.WRAPPER_ARRAY);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);




        //5.设置value的序列化规则和 key的序列化规则   //key String hashkey:String hashvalue: json序列化
        StringRedisSerializer stringKeySerializer = new StringRedisSerializer();


        redisTemplate.setKeySerializer(stringKeySerializer);
        //6.jackson2JsonRedisSerializer就是JSON序列号规则,
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);

        //6.5 设置hash类型key value 序列化方式 (hash-->   key:string + hashkey:string + hashvalue:json序列化)
        redisTemplate.setHashKeySerializer(stringKeySerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);


        //7工厂创建redisTemplate对象之后在进行配置
        redisTemplate.afterPropertiesSet();
    }
}

3. 后台总结之自定义FilterFactory

现有admin服务、users服务、category服务、videos服务,可见除了admin服务都需要进行权限保护,需要局部过滤来处理。即需要在网关中统一处理接口的权限认证。

  • Step1:自定义网关FilterFactory局部过滤
    已知springcloud gateway中默认提供filterFactory,其中GatewayFilterFactory是父接口。那么,我们可以自定义FilterFacotry:
    在这里插入图片描述
    代码如下:
// 自定义token工厂
@Component   // 代表在工厂中创建对象    // @configuration是配置的意思,这里推荐用轻量级Component
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.Config> {

    private static final Logger log = LoggerFactory.getLogger(TokenGatewayFilterFactory.class);
    
    @Autowired
    private RedisTemplate redisTemplate;

    
    
    public TokenGatewayFilterFactory() {
        super(Config.class);
    }
	
    // 重心
    @Override
    public GatewayFilter apply(Config config) {
        // 传统web模型: servlet的service方法 或 springmvc中 需要两个参数: httpServletRequest httpServletResponse
        // 新web模型:   springwebflux                      需要一个参数: ServerWebExchange exchange
        // 传统javaweb中的Filter需要参数: request response filterchain.dofilter(request,response)
        // 新web模型:   chian.filter(exchange)进行放行
        // 新web模型的使用: 在gateway的application.yml中在相应的微服务上编写 filters: -Token
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                log.info("进入filter");
                // 1. 获取token信息
                if(exchange.getRequest().getQueryParams().get("token") == null) throw new RuntimeException("非法令牌");
                String token = exchange.getRequest().getQueryParams().get("token").get(0);
                log.info("token:{}",token);
                // 2. 根据token信息获取redis
                if(!redisTemplate.hasKey(RedisPrefix.TOKEN_KEY+token)) throw new RuntimeException("不合法的令牌");
                return chain.filter(exchange);
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return null;
    }

    public static class Config {
    }
}

4. 后台总结之网关的异常处理

  • 已知后端传递给前端的应是json数据,现在报错信息是一张张html(web机制要的是页面,前后端分离机制要的是json)
    在这里插入图片描述
    在这里插入图片描述
  • 网关的异常处理机制-----webflux编程
    Step1:自定义类 gateway-> config.GlobalExceptionConfiguration:
// @Order   //order执行顺序: int代表多个异常处理时哪个先执行
@Override
public class GlobalExceptionConfiguration implements ErrorWebExceptionHandler {}

Step2:自定义异常 gateway -> exceptions.IllegalTokenException:

package com.salieri.exceptions;

// 自定义异常
public class IllegalTokenException extends RuntimeException {

    public IllegalTokenException(String message) {
        super(message);
    }
}
======================
而后在网关报异常时使用

Step3:在config.GlobalExceptionConfiguration中注意状态码的设置。

5. 微服务架构的部署分析

  • Step1:对现有微服务系统进行打包
    (1) maven聚合开发:打包时不能在单独某个module打包,必须在root根项目上打包,即所有module一次性全部打包。
    (2) springboot项目打包注意事项: 执行jar包出现这个错误: xxx-1.0-SNAPSHOT.jar中没有主清单属性。 解决方案:引入部署插件(只能放在springboot应用中)
<!-- 引入部署插件 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.salieri.AdminGatewayApplication</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>
  • Step2:打包完成后,在整个微服务架构中创建images文件夹
    在这里插入图片描述
    Dockerfile一例:
FROM openjdk:8-jre
ENV APP_PATH=/apps
WORKDIR $APP_PATH
COPY easywatch_category-1.0-SNAPSHOT.jar $APP_PATH/app.jar
EXPOSE 8981
ENTRYPOINT ["java","-jar"]
CMD ["app.jar"]
  • Step3:更改admin-dist->static->js->app.0ebddf58.js中的后端连接地址,编写最终的docker-compose.yml
    在这里插入图片描述
version: "3.3"

networks:
  easywatch_network:

volumes:
  data:
  redisdata:

services:
  nacos:
    image: nacos/nacos-server:2.0.2
    ports:
      - "8848:8848"
    environment:
      - "JVM_XMS=256m"
      - "JVM_XMX=256m"
      - "MODE=standalone"
    networks:
      - easywatch_network

  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    networks:
      - easywatch_network
    volumes:
      - data:/var/lib/mysql
      - ./easywatch.sql:/docker-entrypoint-initdb.d/easywatch.sql
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=easywatch"

  redis:
    image: redis:5.0.10
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

  admins:
    build:
      context: ./images/admins
      dockerfile: Dockerfile
    ports:
      - "8980:8980"
    depends_on:
      - mysql
      - nacos
      - redis

  admins01:
    build:
      context: ./images/admins
      dockerfile: Dockerfile
    ports:
      - "8988:8980"
    depends_on:
      - mysql
      - nacos
      - redis

  category:
    build:
      context: ./images/category
      dockerfile: Dockerfile
    ports:
      - "8981:8981"
    depends_on:
      - mysql
      - nacos
      - redis

  gateway:
    build:
      context: ./images/gateway
      dockerfile: Dockerfile
    ports:
      - "9999:9999"
    depends_on:
      - mysql
      - nacos
      - redis

  users:
    build:
      context: ./images/users
      dockerfile: Dockerfile
    ports:
      - "8982:8982"
    depends_on:
      - mysql
      - nacos
      - redis

  videos:
    build:
      context: ./images/videos
      dockerfile: Dockerfile
    ports:
      - "8983:8983"
    depends_on:
      - mysql
      - nacos
      - redis

  nginx:
    image: nginx:1.21.1
    ports:
      - "80:80"
    volumes:
      - ./admin-dist:/usr/share/nginx/html:ro
  • centos7虚拟机中的容器状态:
    在这里插入图片描述
  • nacos注册中心中的微服务状态:
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值