欢迎光临散文网 会员登陆 & 注册

第二章 引入必备依赖(LomBok、Swagger、fastjon、logback、ELK)

2023-04-25 18:55 作者:游戏理想国  | 我要投稿

1、整合Lombok 。 

<!--Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。  自动生成get set 方法-->

<dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

</dependency>


2、 引入依赖knife4j(swagger)

 


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


 



<!-- 1. swagger-bootstrap-ui 目前改名为 knife4j -->

<!-- 2. 实现 swagger-bootstrap-ui 的自动化配置 -->

<!-- 3. 因为 knife4j-spring 已经引入 Swagger 依赖,所以无需重复引入 -->

<!--    knife4j knife4j是为Java MVC框架生成Api文档的增强解决方案。-->

<dependency>

    <groupId>com.github.xiaoymin</groupId>

    <artifactId>knife4j-spring</artifactId>

    <version>2.0.4</version>

</dependency>

<dependency>

    <groupId>com.github.xiaoymin</groupId>

    <artifactId>knife4j-spring-ui</artifactId>

    <version>2.0.4</version>

</dependency>


 


 


配置文件

新建Swagger的配置文件SwaggerConfiguration.java文件,创建springfox提供的Docket分组对象,代码如下:


@Configuration


@EnableSwagger2


@EnableKnife4j


@Import(BeanValidatorPluginsConfiguration.class)


public class SwaggerConfiguration {


    @Bean(value = "defaultApi2")


    public Docket defaultApi2() {


        Docket docket=new Docket(DocumentationType.SWAGGER_2)


                .apiInfo(apiInfo())


                //分组名称


                .groupName("2.X版本")


                .select()


                //这里指定Controller扫描包路径


                .apis(RequestHandlerSelectors.basePackage("com.swagger.bootstrap.ui.demo.new2"))


                .paths(PathSelectors.any())


                .build();


        return docket;


    }


}


以上有两个注解需要特别说明,如下表:


注解


说明


@EnableSwagger2


该注解是Springfox-swagger框架提供的使用Swagger注解,该注解必须加。


@EnableKnife4j


该注解是knife4j提供的增强注解,Ui提供了例如动态参数、参数过滤、接口排序等增强功能,如果你想使用这些增强功能就必须加该注解,否则可以不用加。


增强功能

 


1、给接口添加作者。


添加作者需要使用knife4j提供的增强注解@ApiOperationSupport


 


接口代码示例如下:


@ApiOperationSupport(author = "xiaoymin@foxmail.com")@ApiOperation(value = "写文档注释我是认真的")@GetMapping("/getRealDoc")public Rest<RealDescription> getRealDoc(){


    Rest<RealDescription> r=new Rest<>();


    try {


        TimeUnit.SECONDS.sleep(1);


    } catch (InterruptedException e) {


        e.printStackTrace();


    }


    r.setData(new RealDescription());


    return r;}


 


在文档中显示效果如下:




 


在2.0.3版本中,收到开发者反馈希望能在Controller上增加作者的注解


2、显示自定义的MD文档。(意义不大)


 


3、正式使用环境,屏蔽掉swagger。


 


knife4j.production=true



 


4、接口排序。


 


目前提供的排序规则主要有2种,分别是:


Controller之间的tags分组排序


Controller下的接口排序


 


Controller之间的排序主要有两种方式,排序的规则是倒序,但是排序的最小值必须大于0


 


推荐第一种


第一种,使用@ApiSupport注解中的属性order,代码示例如下:


@Api(tags = "2.0.3版本-20200312")@ApiSupport(order = 284)@RestController@RequestMapping("/api/nxew203")public class Api203Constroller {


    }


 


第二种情况,使用knife4j提供的增强注解@ApiSort,代码示例如下:


@Api(tags = "2.0.2版本-20200226")@ApiSort(286)@RestController@RequestMapping("/api/nxew202")public class Api202Controller {


    


    }


第三种,使用注解@Api中的属性position,代码示例如下:


@Api(tags = "2.0.2版本-20200226",position = 286)@RestController@RequestMapping("/api/nxew202")public class Api202Controller {


    


    }



tag下接口排序


针对Controller下的具体接口,排序规则是使用Knife4j提供的增强注解@ApiOperationSupport中的order字段,代码示例如下:


 


@ApiOperationSupport(order = 33)@ApiOperation(value = "忽略参数值-Form类型")@PostMapping("/ex")public Rest<LongUser> findAll(LongUser longUser) {


    Rest<LongUser> r=new Rest<>();


    r.setData(longUser);


    return r;}


 


5、开启调试动态请求参数


个性化设置功能里,可以开启对参数的动态调试,可以手动添加参数。


6、解决参数排序的问题


由于springfox-swagger2的实现的问题,程序只能配置为按照英文字母排序。不过我们可以通过编写插件实现字段按类变量定义顺序排序。


 


package com.example.demo.config;


import static springfox.documentation.schema.Annotations.findPropertyAnnotation;

import static springfox.documentation.swagger.schema.ApiModelProperties.findApiModePropertyAnnotation;

import java.lang.reflect.Field;

import org.apache.commons.lang3.ArrayUtils;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.introspect.AnnotatedField;

import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;

import com.google.common.base.Optional;

import io.swagger.annotations.ApiModelProperty;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;

import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

import springfox.documentation.swagger.common.SwaggerPluginSupport;



/*

由于springfox-swagger2的实现的问题,程序只能配置为按照英文字母排序。不过我们可以通过编写插件实现字段按类变量定义顺序排序。

yzw 2020-10-27

 */

@Component

public class CustomApiModelPropertyPositionBuilder implements ModelPropertyBuilderPlugin {

    private Log log = LogFactory.getLog(getClass());


    @Override

    public boolean supports(DocumentationType delimiter) {

        return SwaggerPluginSupport.pluginDoesApply(delimiter);

    }


    @Override

    public void apply(ModelPropertyContext context) {


        Optional<BeanPropertyDefinition> beanPropertyDefinitionOpt = context.getBeanPropertyDefinition();

        Optional<ApiModelProperty> annotation = Optional.absent();

        if (context.getAnnotatedElement().isPresent()) {

        annotation = annotation.or(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));

        }


        if (context.getBeanPropertyDefinition().isPresent()) {

        annotation = annotation.or(findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelProperty.class));

        }


        if (beanPropertyDefinitionOpt.isPresent()) {

                BeanPropertyDefinition beanPropertyDefinition = beanPropertyDefinitionOpt.get();

                if (annotation.isPresent() && annotation.get().position() != 0) {

                return;

                }


                AnnotatedField field = beanPropertyDefinition.getField();

                Class<?> clazz = field.getDeclaringClass();

                Field[] declaredFields = clazz.getDeclaredFields();

                Field declaredField;

                try {

                declaredField = clazz.getDeclaredField(field.getName());

                } catch (NoSuchFieldException | SecurityException e) {

                log.error("", e);

                return;

                }


                int indexOf = ArrayUtils.indexOf(declaredFields, declaredField);

                if (indexOf != -1) {

                context.getBuilder().position(indexOf);

                }

         }

    }

}


 


 


3、 引入依赖fastjson

2.3.1 引入依赖

<!--阿里巴巴 fastjson-->

      <dependency>

         <groupId>com.alibaba</groupId>

         <artifactId>fastjson</artifactId>

         <version>1.2.62</version>

      </dependency>



最新版本 v1.2.72  修复AutoType 的安全问题。


2.3.2 实现功能

实现 javaBean、 jsonString、jsonObject、jsonArray、javalist数组之间转换。


 


4、引入依赖logback

 


spring已经引入logback2.3.1 不需要再次引入依赖。 


关于日志文件是否应该存储到数据库进行结构化分析的问题,建议采用ELK解决。


添加配置文件

在resources下添加  logback-spring.xml 


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

<configuration> <!--

 说明:

 1、日志级别及文件

 日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中

 例如:error级别记录到log_error_xxx.log或log_error.log(该文件为当前记录的日志文件),而log_error_xxx.log为归档日志,

 日志文件按日期记录,同一天内,若日志文件大小等于或大于2M,则按0、1、2...顺序分别命名

 例如log-level-2013-12-21.0.log

 其它级别的日志也是如此。

 2、文件路径

 若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹,以相对路径../logs。

 若部署到Tomcat下,则在Tomcat下的logs文件中

 3、Appender

 FILEERROR对应error级别,文件名以log-error-xxx.log形式命名

 FILEWARN对应warn级别,文件名以log-warn-xxx.log形式命名

 FILEINFO对应info级别,文件名以log-info-xxx.log形式命名

 FILEDEBUG对应debug级别,文件名以log-debug-xxx.log形式命名

 stdout将日志信息输出到控制上,为方便开发测试使用

 -->

 <contextName>logback</contextName>

    <!--生成日志目录,dubug模式生成在项目根目录,运行jar模式生成目录在jar的同级目录-->

 <property name="LOG_PATH" value="logs" />

    <!-- 日志记录器,日期滚动记录 -->

 <appender name="FILEERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

 <file>${LOG_PATH}/log_error.log</file>

        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->

 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。

 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->

 <fileNamePattern>${LOG_PATH}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,

 命名日志文件,例如log-error-2013-12-21.0.log -->

 <timeBasedFileNamingAndTriggeringPolicy

 class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

                <maxFileSize>2MB</maxFileSize>

            </timeBasedFileNamingAndTriggeringPolicy>

            <!--只保留最近n天的日志-->

 <maxHistory>7</maxHistory>

            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->

 <totalSizeCap>1GB</totalSizeCap>

            <!--启动清除超过上限的历史日志-->

 <cleanHistoryOnStart>true</cleanHistoryOnStart>

        </rollingPolicy>

        <!-- 追加方式记录日志 -->

 <append>true</append>

        <!-- 日志文件的格式 -->

 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>

            <charset>utf-8</charset>

        </encoder>

        <!-- 此日志文件只记录info级别的 -->

 <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>error</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <!-- 日志记录器,日期滚动记录 -->

 <appender name="FILEWARN" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

 <file>${LOG_PATH}/log_warn.log</file>

        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->

 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。

 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->

 <fileNamePattern>${LOG_PATH}/warn/log-warn-%d{yyyy-MM-dd}.%i.log

            </fileNamePattern>

            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,

 命名日志文件,例如log-error-2013-12-21.0.log -->

 <timeBasedFileNamingAndTriggeringPolicy

 class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

                <maxFileSize>2MB</maxFileSize>

            </timeBasedFileNamingAndTriggeringPolicy>

            <!--只保留最近n天的日志-->

 <maxHistory>7</maxHistory>

            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->

 <totalSizeCap>1GB</totalSizeCap>

            <!--启动清除超过上限的历史日志-->

 <cleanHistoryOnStart>true</cleanHistoryOnStart>

        </rollingPolicy>

        <!-- 追加方式记录日志 -->

 <append>true</append>

        <!-- 日志文件的格式 -->

 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>

            <charset>utf-8</charset>

        </encoder> <!-- 此日志文件只记录info级别的 -->

 <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>warn</level>

            <level>debug</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <!-- 日志记录器,日期滚动记录 -->

 <appender name="FILEINFO" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

 <file>${LOG_PATH}/log_info.log</file>

        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->

 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

            <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。

 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->

 <fileNamePattern>${LOG_PATH}/info/log-info-%d{yyyy-MM-dd}.%i.log

            </fileNamePattern>

            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,

 命名日志文件,例如log-error-2013-12-21.0.log -->

 <timeBasedFileNamingAndTriggeringPolicy

 class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

                <maxFileSize>2MB</maxFileSize>

            </timeBasedFileNamingAndTriggeringPolicy>

            <!--只保留最近n天的日志-->

 <maxHistory>7</maxHistory>

            <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->

 <totalSizeCap>1GB</totalSizeCap>

            <!--启动清除超过上限的历史日志-->

 <cleanHistoryOnStart>true</cleanHistoryOnStart>

        </rollingPolicy>

        <!-- 追加方式记录日志 -->

 <append>true</append>

        <!-- 日志文件的格式 -->

 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>

            <charset>utf-8</charset>

        </encoder>

        <!-- 此日志文件只记录info级别的 -->

 <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>info</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

        <!--encoder 默认配置为PatternLayoutEncoder-->

 <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>

            <charset>utf-8</charset>

        </encoder>

        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->

 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">

            <level>debug</level>

        </filter>

    </appender>

    <logger name="org.springframework" level="WARN" />

    <logger name="org.hibernate" level="WARN" />


    <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>

    <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="TRACE"/>

    <logger name="org.hibernate.SQL" level="DEBUG"/>

    <logger name="org.hibernate.engine.QueryParameters" level="DEBUG"/>

    <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG"/>



    <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->

 <root level="INFO">

        <appender-ref ref="FILEERROR" />

        <appender-ref ref="FILEWARN" />

        <appender-ref ref="FILEINFO" />

        <!-- 生产环境将请stdout,testfile去掉 -->

 <appender-ref ref="STDOUT" />

    </root>

</configuration>

 


5、AOP统一处理切面日志

 


 


6、ELK记录结构化日志


第二章 引入必备依赖(LomBok、Swagger、fastjon、logback、ELK)的评论 (共 条)

分享到微博请遵守国家法律