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

本文介绍如何在Java项目中集成Lombok、knife4j、fastjson和logback等工具,涵盖代码简化、API文档生成、JSON处理及日志管理等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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记录结构化日志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值