1.请简单介绍一下你们的项目?

    黑马头条项目采用当下最火热的微服务+大数据技术架构实现。是对在线教育平台业务进行大数据统计分析的系统。碎片化、切换频繁、社交化和个性化现如今成为人们阅读行为的标签。黑马头条对海量信息进行搜集,通过系统计算分类,分析用户的兴趣进行推送从而满足用户的需求。
    APP端
    平台管理端
    自媒体端

    补充:咨询 新闻 头条 面向互联网用户 类似于今日头条,通过微服务的技术 为用户提供最新 最热点的热门资讯
    2.你们项目的技术架构是怎样的?

    项目框架:基于Spring+SpringMVC+MybatisPlus框架
    包括前端(Weex、Vue、Echarts、WS)、网关(GateWay)、DevOps(单元测试、代码规范)
    服务层中包括中间件(Kafka)、索引、微服务、大数据存储等重难点技术image.png
    image.png
    补充:
    nginx: 接收用户请求 将请求反向代理到网关

    gateway: api网关,将请求路由到微服务

    nacos: 注册中心、配置中心

    feign: 服务调用

    ribbon: 负载均衡器

    sentinel、hystrix: 微服务保护

    SSM: Spring SpringMVC mybatisPlus

    mysql、mongoDB、redis、oss、elasticsearch

    分布式事务seata 分布式锁redisson 分布式调度xxljob 消息队列rabbitmq 分布式日志:ELK

    3.你们Springboot及SpringCloud使用的版本?

    Springboot 2.3.9版本 SpringCloud H开头的版本(Hoxton.SR8)

    4.你是如何理解前后端分离开发的?

    前后端分离架构总体上包括前端和服务端,通常是多人协作开发。

    • 对于后端java工程师:把精力放在设计模式,spring+springmvc,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构,弹性计算架构,微服务架构,java性能优化,以及相关的项目管理等等。
    • 对于前端工程师:把精力放在html5,css3,vuejs,webpack,nodejs,Google V8引擎,javascript多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等等。

    image.png
    前后端开发流程:

    1. 需求分析

    梳理用户的需求,分析业务流程

    1. 接口定义

    根据需求分析定义接口,定义出接口文档

    1. 服务端和前端并行开发

    服务端:依据接口文档进行服务端接口开发
    前端:根据用户需求开发操作界面,并根据接口文档制作mock数据,进行测试

    1. 前后端集成接口联调

    最终前端调用服务端接口完成业务

    1. 项目开发上线测试

    补充:
    1. 前后后端根据需求梳理业务,产出API接口文档

    1. 前后端基于接口文档 ==> 并行开发
      2.1 前端 基于接口文档生成mock数据,按照需求实现页面效果

      2.2 后端 基于接口文档,提供接口实现,使用postman测试接口

      3. 前后端联调
      前端将调用地址改为后端网关地址,实现后台真实数据的调用

      测试整体功能

      出现问题,谁的问题谁去改

    5.你们后端接口是如何测试的?

    使用knife4j进行口端接口测试,knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案

    补充:
    Postman进行接口测试

    Swagger

    Knife4j

    6.SpringMVC接收参数的注解有哪些?

    @RequestBody 接收前端传来的json格式的参数
    @RequestParam 接收在请求中传入的是 (key=value 格式)
    @PathVaribale 接收在请求中传入参数在路径上 (/user/101)

    7.你们的接口文档是如何定义的
    前后端根据需求分析,定义接口,定义出接口文档
    使用knife4j的核心功能:文档说明 根据Swagger的规范说明,详细列出接口文档的说明,包括接口地址、类型、请求示例、请求参数、响应示例、响应参数、响应码等信息。

    补充:
    接口描述:
    请求路径:
    请求方式:
    请求参数类型:
    请求参数:

    响应参数类型: application/json
    响应参数:
    {
    code: 状态码
    msg: 提示信息
    data: 数据
    }
    8.你们项目的数据库设计情况? 你是否有独立设计过数据库?

    黑马头条项目采用的分库分表设计,每一个数据库解决的是一个业务点,非常接近与实际项目设计。

    6个数据库 , 70张表

    9.能否说出SpringBoot的自动装配原理?

    META-INF/spring.factories

    key:EnableAutoConfiguration

    1. 去重
      2. 排除指定配置
      3. 按照条件注解筛选配置

    @ConditionalOnClass(rabbitTemplate.class)

    10.项目中是否自定义过starter起步依赖,如何定义?

    全局异常的统一配置

    小刀文档的统一配置

    11.项目中异常是怎么处理的?
    对项目中的一场进行全局异常处理,异常信息不能直接返回给会用。全局异常包括不可预知异常和可预知异常两种。

    不可预知异常:代码发生系统异常而导致的
    image.png
    1.添加配置类

    1. /**
    2. * @Description: 目的是给用户提供友好的提示信息
    3. * @Version: V1.0
    4. */
    5. @Slf4j
    6. @Configuration
    7. @RestControllerAdvice // Springmvc 异常处理拦截注解
    8. public class ExceptionCatch {
    9. /**
    10. * 解决项目中所有的异常拦截
    11. * @return
    12. */
    13. @ExceptionHandler(Exception.class) // exception 所有子类
    14. public ResponseResult exception(Exception ex) {
    15. ex.printStackTrace();
    16. // 记录日志
    17. log.error("ExceptionCatch ex:{}", ex);
    18. return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "您的网络异常,请稍后重试");
    19. }
    20. }

    @ControllerAdvice 控制器增强注解
    @ExceptionHandler 异常处理器 与上面注解一起使用,可以拦截指定的异常信息

    2.在 META-INF/spring.factories 配置文件中添加:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      com.heima.common.exception.ExceptionCatch
    

    3.项目聚合工程引入统一异常依赖

    可预知异常:程序员在代码中手动抛出本系统定义的特定异常类型,由于是程序员抛出的异常,通常异常信息比较齐全,程序员在抛出时会指定错误代码及错误信息,获取异常信息也比较方便。

    image.png
    1.自定义异常

    public class CustomException extends RuntimeException {
    
        // 异常处理的枚举
        private AppHttpCodeEnum appHttpCodeEnum;
    
        public CustomException(AppHttpCodeEnum appHttpCodeEnum) {
            this.appHttpCodeEnum = appHttpCodeEnum;
        }
        public CustomException(AppHttpCodeEnum appHttpCodeEnum,String msg) {
            appHttpCodeEnum.setErrorMessage(msg);
            this.appHttpCodeEnum = appHttpCodeEnum;
        }
        public AppHttpCodeEnum getAppHttpCodeEnum() {
            return appHttpCodeEnum;
        }
    }
    

    2.添加到异常配置类

     /**
         * 拦截自定义异常
         * @return
         */
        @ExceptionHandler(CustomException.class)
        public ResponseResult custException(CustomException ex) {
            ex.printStackTrace();
            log.error("CustomException ex:{}", ex);
            AppHttpCodeEnum codeEnum = ex.getAppHttpCodeEnum();
            return ResponseResult.errorResult(codeEnum);
        }
    

    12.项目中注册中心的作用?

    Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理。 Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。Nacos 是构建以“服务”为中心的现代应用架构的服务基础设施。
    主要提供四大功能:
    1.服务发现与服务健康检查:Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务,Nacos还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。
    2.动态配置管理:动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新部署应用程序,这使配置的更改更加高效和灵活。
    3.动态DNS服务:Nacos提供基于DNS 协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端点,让三方应用方便的查阅及发现。
    4.服务和元数据管理:Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略。

    补充:
    共享配置:
    多个微服务需要相同的配置 可以单独创建一个配置文件微服务
    如: data-id: share-feign.yml

    其它微服务想用这个共享配置:
    share-configs: 引入共享配置
    - data-id: share-feign.yml
    group: DEFAULT_GROUP
    refresh: 是否热更新
    13.配置中心中如何实现共享配置?

    很多微服务有一些相同的配置,可以将这些共享的配置 放到一个配置文件中,通过nacos的设置可以共享这些配置
    1.在配置中心nacos中 创建配置share-feign.yml
    2.在微服务yml文件中添加共享配置(数组 可以有多个共享配置)

    shared-configs: # 共享配置
              - data-id: share-feign.yml
                group: DEFAULT_GROUP
                refresh: false
    

    14.项目中api网关的作用?

    网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性。
    微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。
    image.png

    补充:
    filters:

    stripPrefix: 去除前缀的过滤器   1<br />    <br />  [http://localhost:6001/admin/api/v1/channel/list](http://localhost:6001/admin/api/v1/channel/list)<br />  <br />  [http://localhost:9001/admin/api/v1/channel/list](http://localhost:9001/admin/api/v1/channel/list)<br />  ==> 去除前缀: /admin<br />  [http://localhost:9001/api/v1/channel/list](http://localhost:9001/api/v1/channel/list)