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

项目是一个资讯类的项目

你们项目的技术架构是怎样的?
项目架构:
最外层是nginx,通过nginx将请求转发到网关,用于项目有三个前端,所以设计了三个网关,通过网关路由到具体微服务。
微服务方面,由nacos管理微服务,和微服务中的配置,微服务与微服务之间的调用通过fegin来调用。
通过seata来解决分布式事务问题,通过xxljob来实现定时任务,通过RabbitMq来实现异步微服务之间的调用,通过elk来做分布式日志
数据库方面,mysql用来存储核心数据,比如用户信息等。
redis用来做热点缓存,比如热点新闻
MongoDB用来做评论之间的增删改查,文章的点赞、收藏之类的。
将所有文件存在了oss当中
es,把所有文章放在es一份,当搜索是使用es搜索,效率更高
文章的审核用到了阿里云的内容安全
实名认证审核用到了用友云
你们Springboot及SpringCloud使用的版本?
springboot2.3.9,springcloudHoxton.SR8
你是如何理解前后端分离开发的?
需求分析,梳理用户需求,分析业务流程
根据需求分析定义接口,定义出接口文档
前端通过前端技术,比如Node.js,Vue框架,webpack打包工具,饿了么ui框架等等,将页面搭建起来
后端提供每个微服务的接口
前后端通过APi文档进行对接
两者是并行开发的 ,
前后端都写完后,进行前后端联调
项目上线
你们后端接口是如何测试的?
1、单元测试
2、PostMan
3、knife4j
4、Swagger
SpringMVC接收参数的注解有哪些?
@RequestBody @RequestParam @PathVaribale
你们的接口文档是如何定义的:
根据业务需求,和前端进行讨论,后端通过swagger框架+knife4j框架生成的接口文档
你们项目的数据库设计情况? 你是否有独立设计过数据库?
根据不同的微服务设计了不同的数据库,不同的表,大概100来张。
目前还没有独立的设计过数据库,但是参与过。如果让我独立设计,我会先根据原型,梳理出具体的业务模块,根据业务模块之间的关系梳理出不同表之间的关系,在PowerDesigner上创建出对应的表 和 表字段。
能否说出SpringBoot的自动装配原理?
@SpringBootApplication注解由三个注解共同完成自动转配
@SpringBootConfiguration:声明启动类为配置类
@EnableAutoConfiguration通过 @Import 注解导入 AutoConfigurationImportSelector类,然后通过AutoConfigurationImportSelector 类的 selectImports 方法去读取需要被自动装配的组件依赖下的spring.factories文件配置的组件的类全名,并按照一定的规则过滤掉不符合要求的组件的类全名,将剩余读取到的各个组件的类全名集合返回给IOC容器并将这些组件注册为bean
@ComponentScan: 扫描启动类所在的包以及子包下所有标记为Bean的组件并注册到IOC容器中
项目中是否自定义过starter起步依赖,如何定义?
将需要定义为起步依赖的模块,在其resources下新建META-INF包,在包下新建spring.factories文件

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.heima.common.exception.ExceptionCatch //类的全路径名

项目中异常是怎么处理的?
设计了,全局异常处理类,使用@ControllerAdvice Springmvc 异常处理拦截注解标注,配合@ExceptionHandler注解,在该注解上指定异常类型。当controller层抛出对应的异常时,方法就会执行。可以在通用异常处理类中定义不同的异常,来处理不同的异常

项目中注册中心的作用?
1、注册服务
2、发现服务
3、服务的健康检测
4、服务中的配置管理
项目中api网关的作用?
可以对请求进行过滤、拦截,身份认证
通过路由规则,将请求分发到指定的服务中
还可以解决前后端跨域问题

filters: 

    stripPrefix: 去除前缀的过滤器   1

  http://localhost:6001/admin/api/v1/channel/list

  http://localhost:9001/admin/api/v1/channel/list
  ==> 去除前缀: /admin
  http://localhost:9001/api/v1/channel/list

1、接口版本规范说明:

随着业务的复杂,同一个接口可能出现多个版本,为了方便后期切换和AB测试,需要定义接口的版本号
在某一个微服务下访问controller的时候在包名下加一个版本号,如下

com.heima.article.controller.v1

访问具体的接口方法的url映射的时候也应该加上版本说明,如下:

@RequestMapping("/api/v1/article")

2、业务中需要的实体类
将这些类抽取出来单独放在一个模块中,在模块中分别建好没一个微服务的包,用来存储对应微服务的实体类,在微服务的父工程中引入依赖即可
image.png
在微服务的父工程中引入依赖:
image.png

Swagger介绍:

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。 它的主要作用是:

  1. 使得前后端分离开发更加方便,有利于团队协作
  2. 接口的文档在线自动生成,降低后端开发人员编写接口文档的负担
  3. 功能测试 Spring已经将Swagger纳入自身的标准,建立了Spring-swagger项目,现在叫Springfox。通过在项目中引入Springfox ,即可非常简单快捷的使用Swagger。

    使用步骤:

    在父工程中引入依赖:

                        <dependency>
                 <groupId>io.springfox</groupId>
                 <artifactId>springfox-swagger2</artifactId>
                 <version>2.9.2</version>
             </dependency>
             <dependency>
                 <groupId>io.springfox</groupId>
                 <artifactId>springfox-swagger-ui</artifactId>
                 <version>2.9.2</version>
             </dependency>
    

    在 heima-leadnews-model 模块中引入该依赖:

    <dependency>
     <groupId>io.springfox</groupId>
     <artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency>
     <groupId>io.springfox</groupId>
     <artifactId>springfox-swagger-ui</artifactId>
    </dependency>
    

    在具体的微服务工程的config包中添加一个配置类:

    @Configuration
    @EnableSwagger2
    public class SwaggerConfiguration {
    @Bean
    public Docket buildDocket() {
       return new Docket(DocumentationType.SWAGGER_2)
               .apiInfo(buildApiInfo())
               .select()
               // 要扫描的API(Controller)基础包
               .apis(RequestHandlerSelectors.basePackage("com.heima"))
               .paths(PathSelectors.any())
               .build();
    }
    private ApiInfo buildApiInfo() {
       Contact contact = new Contact("黑马程序员","","");
       return new ApiInfoBuilder()
               .title("黑马头条-平台管理API文档")
               .description("平台管理服务api")
               .contact(contact)
               .version("1.0.0").build();
    }
    }
    

    Swagger常用注解

    在Java类中添加Swagger的注解即可生成Swagger接口文档,常用Swagger注解如下:
    @Api:修饰整个类,描述Controller的作用
    @ApiOperation:描述一个类的一个方法,或者说一个接口
    @ApiParam:单个参数的描述信息
    @ApiModel:用对象来接收参数
    @ApiModelProperty:用对象接收参数时,描述对象的一个字段
    @ApiResponse:HTTP响应其中1个描述
    @ApiResponses:HTTP响应整体描述
    @ApiIgnore:使用该注解忽略这个API
    @ApiError :发生错误返回的信息
    @ApiImplicitParam:一个请求参数
    @ApiImplicitParams:多个请求参数的描述信息

    在Controller层上添加注解

    @RestController
    @RequestMapping("/api/v1/channel")
    @Api(value = "频道管理", tags = "频道管理", description = "频道管理API")
    public class AdChannelController {
     /**
      * 根据名称分页查询频道列表
      * @param dto
      * @return
      */
     @PostMapping("/list")
     @ApiOperation("频道分页列表查询")
     public ResponseResult findByNameAndPage(@RequestBody ChannelDTO dto) {
         return channelService.findByNameAndPage(dto);
     }
    }
    

    ChannelDTO:

    @Data
    public class ChannelDTO extends PageRequestDTO {
     /**
      * 频道名称
      */
     @ApiModelProperty("频道名称")
     private String name;
    }
    

    PageRequestDTO:

    @Data
    @Slf4j
    public class PageRequestDTO {
    
     @ApiModelProperty(value="当前页",required = true)
     protected Integer page;
     @ApiModelProperty(value="每页显示条数",required = true)
     protected Integer size;
    
     public void checkParam() {
         if (this.page == null || this.page < 0) {
             setPage(1);
         }
         if (this.size == null || this.size < 0 || this.size > 100) {
             setSize(10);
         }
     }
    }
    

    启动a微服务,访问地址:http://微服务ip:微服务端口/swagger-ui.html

    knife4j:

    knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!
    Swagger的注解在它上面也能用

    使用步骤:

    在heima-leadnews-basic 模块下,右键创建子工程 heima-knife4j-spring-boot-starter, 并引入依赖

    <dependencies>
    <dependency>
     <groupId>com.github.xiaoymin</groupId>
     <artifactId>knife4j-spring-boot-starter</artifactId>
    </dependency>
    </dependencies>
    

    在heima-leadnews-basic —> heima-knife4j-spring-boot-starter下 创建Swagger配置文件
    新建Swagger的配置文件SwaggerConfiguration.java文件,创建springfox提供的Docket分组对象,代码如下: ```java package com.heima.knife4j.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration @EnableSwagger2 @EnableKnife4j @Import(BeanValidatorPluginsConfiguration.class) public class Swagger2Configuration {

@Bean(value = "defaultApi2")
public Docket defaultApi2() {
    Docket docket=new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            //分组名称
            .groupName("1.0")
            .select()
            //这里指定Controller扫描包路径
            .apis(RequestHandlerSelectors.basePackage("com.heima"))
            .paths(PathSelectors.any())
            .build();
    return docket;
}
private ApiInfo apiInfo() {
    return new ApiInfoBuilder()
            .title("黑马头条API文档")
            .description("黑马头条API文档")
            .version("1.0")
            .build();
}

}

在heima-leadnews-basic --> heima-knife4j-spring-boot-starter 资源目录resources文件夹下添加<br />META-INF/spring.factories 文件,这样微服务引入依赖后,即可自动装配
```properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.heima.knife4j.config.Swagger2Configuration

heima-leadnews-services 下的pom中,加入该 knife4j通用配置依赖 ,所有的微服务即可使用api文档生成功能

<!-- 接口文档起步依赖starter  引入后可使用knife接口文档 -->
        <dependency>
            <artifactId>heima-knife4j-spring-boot-starter</artifactId>
            <groupId>com.heima</groupId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

http://host:port/doc.html:访问地址

项目全局异常处理

不可预知异常:

在heima-leadnews-basic模块下 新建heima-exception-spring-boot-starter 工程
(1) pom中引入依赖

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>com.heima</groupId>
    <artifactId>heima-leadnews-model</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>

(2) 创建通用异常处理类 com.heima.common.exception.ExceptionCatch

package com.heima.common.exception;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @Description:  目的是给用户提供友好的提示信息
 * @Version: V1.0
 */
@Slf4j
@Configuration
@RestControllerAdvice   // Springmvc 异常处理拦截注解
public class ExceptionCatch {
    /**
     * 解决项目中所有的异常拦截
     * @return
     */
    @ExceptionHandler(Exception.class)  // exception 所有子类
    public ResponseResult exception(Exception ex) {
        ex.printStackTrace();
        // 记录日志
        log.error("ExceptionCatch ex:{}", ex);
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "您的网络异常,请稍后重试");
    }
}

@ControllerAdvice 控制器增强注解
@ExceptionHandler 异常处理器 与上面注解一起使用,可以拦截指定的异常信息
在 META-INF/spring.factories 配置文件中添加:

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

(3) heima-leadnews-services服务聚合工程引入统一异常依赖

<!-- 统一异常处理依赖 引入后就不用在try catch异常啦 ~~ -->
        <dependency>
            <groupId>com.heima</groupId>
            <artifactId>heima-exception-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

8.2 可预知异常处理

package com.heima.common.exception;

import com.heima.model.common.enums.AppHttpCodeEnum;

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

配置到全局异常处理

package com.heima.common.exception;
/**
 * @Description:  目的是给用户提供友好的提示信息
 * @Version: V1.0
 */
@Slf4j
@RestControllerAdvice   // Springmvc 异常处理拦截注解
public class ExceptionCatch {
    /**
     * 解决项目中所有的异常拦截
     * @return
     */
    @ExceptionHandler(Exception.class)  // exception 所有子类
    public ResponseResult exception(Exception ex) {
        ex.printStackTrace();
        // 记录日志
        log.error("ExceptionCatch ex:{}", ex);
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "您的网络异常,请稍后重试");
    }

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

}