Spring-Boot 经典微服务架构基础搭建-全过程--前期

正准备开始做的项目,说大不大,说小不小,所以纠结了好久的架构搭建方式。有的过于注重分布式,配置也较为繁琐;有的过于简单,模块之间耦合极高,不符合微服务的要求。于是再三思考下,采用了一种这样的搭建方式,可能不是最好的,不过目前暂时这样决定,不合适再继续修改。

本文的主要搭建过程分为以下几个方面。(以一个初始的用户模块,进行相关的整合)

  • 0x01.技术栈
  • 0x02.原始工程的创建及依赖的导入
  • 0x03.service微服务模块的创建
  • 0x04.common公共微服务模块的创建
  • 0x05.service-user的配置及代码生成
  • 0x06.Swagger2配置
  • 0x07.全局json格式的统一
  • 0x08.全局日志处理
  • 0x09.全局异常处理
  • 0x0A.一些简单controller的代码

0x01.技术栈

作为一个前后端完全分离开发的项目来说,这个项目的主要技术栈如下。

  • Spring Boot + Spring Cloud - 微服务模式
  • GateWay - 分布式微服务网关
  • Nginx- 反向代理
  • Swagger2 - API文档及前后端测试
  • Mybatis-Plus - 持久层框架
  • MySQL - 持久层数据库
  • Redis - 缓存数据库
  • RabbitMQ - 消息中间件
  • Spring Security - 权限控制
  • Logback-slfj - 日志处理
  • 阿里云oss - 云存储服务
  • JWT - 认证规范
  • Oatuh2 - 第三方令牌

主要的技术栈是这些,本文只包含几个基本的前期整合,其它整合等到开发到一定的程度的时候再继续进行整合。

0x02.原始工程的创建及依赖的导入

  • 创建一个简单的maven工程。(不使用任何骨架)
  • 删除src目录。
  • 修改打包方式为pom包。
  • 添加spring-boot-starter-parent为父工程。
  • 进行公共依赖版本控制。
  • 导入公共依赖。
  • 导入公共插件。
  • 最终pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.atfwusgroupId>
    <artifactId>guli-school-parentartifactId>
    
    <packaging>pompackaging>
    <version>0.0.1-SNAPSHOTversion>
    <name>guli-school-parentname>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.1.RELEASEversion>
        <relativePath/> 
    parent>
    <description> project for Spring Bootdescription>

    <properties>
        <java.version>1.8java.version>
        <guli.version>0.0.1-SNAPSHOTguli.version>
        <mybatis-plus.version>3.0.5mybatis-plus.version>
        <velocity.version>2.0velocity.version>
        <swagger.version>2.7.0swagger.version>
        <aliyun.oss.version>2.8.3aliyun.oss.version>
        <jodatime.version>2.10.1jodatime.version>
        <poi.version>3.17poi.version>
        <commons-fileupload.version>1.3.1commons-fileupload.version>
        <commons-io.version>2.6commons-io.version>
        <httpclient.version>4.5.1httpclient.version>
        <jwt.version>0.7.0jwt.version>
        <aliyun-java-sdk-core.version>4.3.3aliyun-java-sdk-core.version>
        <aliyun-sdk-oss.version>3.1.0aliyun-sdk-oss.version>
        <aliyun-java-sdk-vod.version>2.15.2aliyun-java-sdk-vod.version>
        <aliyun-java-vod-upload.version>1.4.11aliyun-java-vod-upload.version>
        <aliyun-sdk-vod-upload.version>1.4.11aliyun-sdk-vod-upload.version>
        <fastjson.version>1.2.28fastjson.version>
        <gson.version>2.8.2gson.version>
        <json.version>20170516json.version>
        <commons-dbutils.version>1.7commons-dbutils.version>
        <canal.client.version>1.1.0canal.client.version>
        <docker.image.prefix>zxdocker.image.prefix>
        <cloud-alibaba.version>0.2.2.RELEASEcloud-alibaba.version>
    properties>

    <dependencyManagement>
        <dependencies>
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>Hoxton.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-alibaba-dependenciesartifactId>
                <version>${cloud-alibaba.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
            
            <dependency>
                <groupId>com.baomidougroupId>
                <artifactId>mybatis-plus-boot-starterartifactId>
                <version>${mybatis-plus.version}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.velocitygroupId>
                <artifactId>velocity-engine-coreartifactId>
                <version>${velocity.version}version>
            dependency>
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger2artifactId>
                <version>${swagger.version}version>
            dependency>
            
            <dependency>
                <groupId>io.springfoxgroupId>
                <artifactId>springfox-swagger-uiartifactId>
                <version>${swagger.version}version>
            dependency>
            
            <dependency>
                <groupId>com.aliyun.ossgroupId>
                <artifactId>aliyun-sdk-ossartifactId>
                <version>${aliyun.oss.version}version>
            dependency>
            
            <dependency>
                <groupId>joda-timegroupId>
                <artifactId>joda-timeartifactId>
                <version>${jodatime.version}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poiartifactId>
                <version>${poi.version}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.poigroupId>
                <artifactId>poi-ooxmlartifactId>
                <version>${poi.version}version>
            dependency>
            
            <dependency>
                <groupId>commons-fileuploadgroupId>
                <artifactId>commons-fileuploadartifactId>
                <version>${commons-fileupload.version}version>
            dependency>
            
            <dependency>
                <groupId>commons-iogroupId>
                <artifactId>commons-ioartifactId>
                <version>${commons-io.version}version>
            dependency>
            
            <dependency>
                <groupId>org.apache.httpcomponentsgroupId>
                <artifactId>httpclientartifactId>
                <version>${httpclient.version}version>
            dependency>
            <dependency>
                <groupId>com.google.code.gsongroupId>
                <artifactId>gsonartifactId>
                <version>${gson.version}version>
            dependency>
            
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwtartifactId>
                <version>${jwt.version}version>
            dependency>
            
            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-sdk-coreartifactId>
                <version>${aliyun-java-sdk-core.version}version>
            dependency>
            <dependency>
                <groupId>com.aliyun.ossgroupId>
                <artifactId>aliyun-sdk-ossartifactId>
                <version>${aliyun-sdk-oss.version}version>
            dependency>
            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-sdk-vodartifactId>
                <version>${aliyun-java-sdk-vod.version}version>
            dependency>
            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-java-vod-uploadartifactId>
                <version>${aliyun-java-vod-upload.version}version>
            dependency>
            <dependency>
                <groupId>com.aliyungroupId>
                <artifactId>aliyun-sdk-vod-uploadartifactId>
                <version>${aliyun-sdk-vod-upload.version}version>
            dependency>
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>${fastjson.version}version>
            dependency>
            <dependency>
                <groupId>org.jsongroupId>
                <artifactId>jsonartifactId>
                <version>${json.version}version>
            dependency>
            <dependency>
                <groupId>commons-dbutilsgroupId>
                <artifactId>commons-dbutilsartifactId>
                <version>${commons-dbutils.version}version>
            dependency>
            <dependency>
                <groupId>com.alibaba.ottergroupId>
                <artifactId>canal.clientartifactId>
                <version>${canal.client.version}version>
            dependency>
        dependencies>
    dependencyManagement>




    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

0x03.service微服务模块的创建

  • 在原始工程上创建普通maven子模块。
  • 删除src目录。
  • 修改打包方式为pom包。
  • 导入相关依赖。
  • 暂时注释掉服务调用的相关依赖,后续再进行整合配置。
  • pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>gfbbsartifactId>
        <groupId>org.gfbbsgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>
    
    <packaging>pompackaging>
    <artifactId>serviceartifactId>

    <dependencies>
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
        
        <dependency>
            <groupId>org.apache.velocitygroupId>
            <artifactId>velocity-engine-coreartifactId>
        dependency>
        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>
        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poiartifactId>
        dependency>
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
        dependency>
        <dependency>
            <groupId>commons-fileuploadgroupId>
            <artifactId>commons-fileuploadartifactId>
        dependency>
        
        <dependency>
            <groupId>org.apache.httpcomponentsgroupId>
            <artifactId>httpclientartifactId>
        dependency>
        
        <dependency>
            <groupId>commons-iogroupId>
            <artifactId>commons-ioartifactId>
        dependency>
        
        <dependency>
            <groupId>com.google.code.gsongroupId>
            <artifactId>gsonartifactId>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
    dependencies>

project>
  • 创建真正的服务模块 - user。
  • pom文件暂时不需要改动。

0x04.common公共微服务模块的创建

  • 该模块主要是一些能公共抽取的代码。
  • 同样是原始工程的子模块。
  • 删除src目录。
  • 修改打包方式为pom包。
  • 导入相关依赖。
  • 注释common-pool2部分依赖。
  • pon文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>gfbbsartifactId>
        <groupId>org.gfbbsgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>commonartifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger2artifactId>
            <scope>provided scope>
        dependency>
        <dependency>
            <groupId>io.springfoxgroupId>
            <artifactId>springfox-swagger-uiartifactId>
            <scope>provided scope>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

        
    dependencies>
project>
  • 创建common-utils,service-base子模块备用。
  • 统一创建包 com.gfbbs。
  • 项目结构如下:

Spring-Boot 经典微服务架构基础搭建-全过程--前期_第1张图片

0x05.service-user的配置及代码生成

  • 在source文件夹中添加application.properties配置。
  • 暂时简单的配置一下端口,环境,数据源,json格式。
# 服务端口
server.port=8001
# 服务名
spring.application.name=service-edu

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=****
spring.datasource.username=root
spring.datasource.password=*****

#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
  • 测试文件夹中,编写MyBties-Plus的代码生成器:
/**
 * @author ATFWUS
 * @since 2020/07/30
 */
public class CodeGenerator {

    @Test
    public void run() {

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");//输出目录

        gc.setAuthor("ATFWUS");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖

        gc.setServiceName("%sService");	//去掉Service接口的首字母I

        gc.setIdType(IdType.AUTO); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://****:3306/gfbbs_dev?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("***");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("userService"); //模块名
        pc.setParent("com.gfbbs");//包名
        pc.setController("controller");
        pc.setEntity("bean");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");//表名称
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        //strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();
    }
}

  • 编写测试用的controller:
@RestController
@RequestMapping("/userService/user")
public class UserController {

    @Autowired
    private UserService userService;

    //1.查询所有用户
    @GetMapping("findAll")
    public List findAllTeacher(){
        List<User> list = userService.list(null);
        return list;
    }
}
  • 编写MyBtis-Plus配置类,添加开发环境的性能测试插件:
@Configuration
@EnableTransactionManagement
@MapperScan("com.gfbbs.userService.mapper")
public class MyBatisPlusConfig {
    /**
     * SQL 执行性能分析插件
     * 开发环境使用,线上不推荐。 maxTime 指的是 sql 最大执行时长
     */
    @Bean
    @Profile({"dev","test"})// 设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000);//ms,超过此处设置的ms则sql不执行
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }
}
  • 编写Spring-Boot启动类:
@SpringBootApplication
@ComponentScan(basePackages = {"com.gfbbs"})
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}
  • 启动测试,成功取到json数据。

Spring-Boot 经典微服务架构基础搭建-全过程--前期_第2张图片

0x06.Swagger2配置

  • 在common包下的service-base创建配置类SwaggerConfig:
public class SwaggerConfig {

    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("GFBBS-API")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.not(PathSelectors.regex("/admin/.*")))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();

    }

    private ApiInfo webApiInfo(){

        return new ApiInfoBuilder()
                .title("智能化校内小型论坛-GFBBS-API文档")
                .description("本文档描述了用户的微服务接口定义")
                .version("1.0")
                .contact(new Contact("java", "", "[email protected]"))
                .build();
    }
}
  • 在service模块中引入service-base。
		<dependency>
            <groupId>org.gfbbsgroupId>
            <artifactId>service-baseartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
  • 在Controller中使用相关的Swagger2注解。
  • 浏览器访问http://localhost:8001/swagger-ui.html。
  • 成功看到Swagger界面。

Spring-Boot 经典微服务架构基础搭建-全过程--前期_第3张图片

0x07.全局json格式的统一

  • 全局json格式统一为:
{
  "success": 布尔, //响应是否成功
  "code": 数字, //响应码
  "message": 字符串, //返回消息
  "data": HashMap //返回数据,放在键值对中
}
  • 在ccommon-utils中编写结果类和返回码:
//统一返回结果的类
@Data
public class R {

    @ApiModelProperty(value = "是否成功")
    private Boolean success;

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();

    //把构造方法私有
    private R() {}

    //成功静态方法
    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    //失败静态方法
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    //对链式编程的支持

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}
public class ResultCode {

    public static Integer SUCCESS = 10000;

    public static Integer ERROR = 10001;

}
  • service里添加依赖:
		<dependency>
            <groupId>org.gfbbsgroupId>
            <artifactId>common-utilsartifactId>
            <version>1.0-SNAPSHOTversion>
        dependency>
  • 修改返回结果为链式编程形式:
@Api(description="用户管理")
@RestController
@RequestMapping("/userService/user")
public class UserController {

    @Autowired
    private UserService userService;

    //1.查询所有用户
    @ApiOperation(value = "所有用户列表")
    @GetMapping("findAll")
    public R findAllTeacher(){
        List<User> list = userService.list(null);
        return R.ok().data("items", list);
    }
}
  • 测试,得到标准格式的json数据:

Spring-Boot 经典微服务架构基础搭建-全过程--前期_第4张图片

0x08.全局日志处理

  • 自定义LogBack的配置文件logback-spring.xml,放在resource文件夹中。
  • 里面包含了所有日志的有关配置。

<configuration  scan="true" scanPeriod="10 seconds">
    
    
    
    

    <contextName>logbackcontextName>
    
    <property name="log.path" value="D:/DeskTop/智能化校内小型论坛/log" />

    
    
    
    
    
    
    
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>


    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        
        
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFOlevel>
        filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}Pattern>
            
            <charset>UTF-8charset>
        encoder>
    appender>


    

    
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_info.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset>
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFOlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_warn.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warnlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>


    
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        
        <file>${log.path}/log_error.logfile>
        
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
            <charset>UTF-8charset> 
        encoder>
        
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MBmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
            
            <maxHistory>15maxHistory>
        rollingPolicy>
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERRORlevel>
            <onMatch>ACCEPTonMatch>
            <onMismatch>DENYonMismatch>
        filter>
    appender>

    
    
    
    <springProfile name="dev">
        
        <logger name="com.guli" level="INFO" />

        
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        root>
    springProfile>


    
    <springProfile name="pro">

        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
        root>
    springProfile>

configuration>

0x09.全局异常处理

  • 在service-base中,添加全局,特定,自定义异常处理。需要导入common-utils的依赖。
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    //指定出现什么异常执行这个方法
    @ExceptionHandler(Exception.class)
    @ResponseBody //为了返回数据
    public com.gfbbs.commonutils.R error(Exception e) {
        e.printStackTrace();
        return R.error().message("全局异常");
    }

    //特定异常
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody //为了返回数据
    public R error(ArithmeticException e) {
        e.printStackTrace();
        return R.error().message("ArithmeticException异常处理");
    }

    //自定义异常
    @ExceptionHandler(GfbbsException.class)
    @ResponseBody //为了返回数据
    public R error(GfbbsException e) {
        log.error(e.getMessage());
        e.printStackTrace();

        return R.error().code(e.getCode()).message(e.getMsg());
    }
}
@Data
@AllArgsConstructor  //生成有参数构造方法
@NoArgsConstructor   //生成无参数构造
public class GfbbsException extends RuntimeException {
    private Integer code;//状态码
    private String msg;//异常信息
}
  • 在common-utils中创建异常工具类:
public class ExceptionUtil {
    public static String getMessage(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 将出错的栈信息输出到printWriter中
            e.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }
}
  • 将异常写入日志的语句:
log.error(ExceptionUtil.getMessage(e));

0x0A.一些简单controller的代码

@Api(description="用户管理")
@RestController
@RequestMapping("/userService/user")
public class UserController {

    @Autowired
    private UserService userService;

    //查询所有用户
    @ApiOperation(value = "所有用户列表")
    @GetMapping("findAll")
    public R findAllTeacher(){
        List<User> list = userService.list(null);
        return R.ok().data("items", list);
    }

    //根据用户id进行查询
    @ApiOperation(value = "根据id查询用户信息")
    @GetMapping("user/{id}")
    public R getUser(@PathVariable String id) {
        User user=userService.getById(id);
        return R.ok().data("user",user);
    }

    //添加用户接口的方法
    @ApiOperation(value = "添加用户")
    @PostMapping("addUser")
    public R addUser(@RequestBody User user) {
        boolean save = userService.save(user);
        if(save) {
            return R.ok();
        } else {
            return R.error();
        }
    }
}
  • 在service-base中添加MyBtis-Plus的自动填充配置:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        //属性名称,不是字段名称
        this.setFieldValByName("gmtCreate", new Date(), metaObject);
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified", new Date(), metaObject);
    }
}

整体结构图:

Spring-Boot 经典微服务架构基础搭建-全过程--前期_第5张图片

你可能感兴趣的:(项目实战技巧篇,springboot,springcloud,微服务,架构,环境配置)