月度记录-2023-8月

109 阅读11分钟

1. log4j怎么实现只打印指定级别,例如只打印info,不打印error

可以使用LevelRangeFilter来实现。LevelRangeFilter允许你定义一个范围,只接受在这个范围内的日志级别,而拒绝超出范围的日志级别。

<Appenders>
    <Console name="Console" target="SYSTEM_OUT">
       <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
       <!-- 添加 LevelRangeFilter,只接受 INFO 级别的日志 -->
       <LevelRangeFilter levelMin="INFO" levelMax="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
    </Console>
</Appenders>

2. nohup.out 文件

@C

Unix/Linux 环境下用于保存后台运行程序输出的特殊文件,它不适用于 Windows。nohup.out 是一个特殊的输出文件,用于存储在后台运行的程序的标准输出(stdout)和标准错误流(stderr)的内容。当你使用 nohup 命令在后台运行一个程序时,如果程序产生输出,这些输出将会被重定向到 nohup.out 文件中。

nohup.out 文件不会自动删除,它会持续保存在文件系统中,直到你手动删除它或者清空内容。每次你使用 nohup 命令在后台运行一个程序,并且该程序产生输出时,输出会被追加到现有的 nohup.out 文件中,而不会覆盖原有的内容。

在 Windows 上,如果你在后台运行程序,并且该程序产生输出,输出通常会显示在标准输出(stdout)和标准错误流(stderr)中。但在 Windows 上,这些输出通常不会被保存到一个特定的文件中,而是直接输出到命令提示符(Command Prompt)或控制台窗口。

3. log4j2,RollingFile滚动文件注意文件名

这个细节一定要注意,log4j是通过文件名来实现滚动和删除的,如果设置的是只有十个文件滚动,文件名称按照年月日来命名,那么其实就变成了每天十个。

4. 异步日志

异步日志开启很简单,只需要再包一层就行了

<Configuration status="WARN">
    <Appenders>
        <RollingFile name="RollingFileInfo" fileName="xxxx/log.log"
                     filePattern="xxxx/log-%d{yyyy-MM-dd}-%i.log.gz">                     
                   <!-- 省略配置文件,此处只是为了展示异步日志 -->
        </RollingFile>
        <!-- 声明一个异步Appender,并将RollingFileAppender包含在其中 -->
        <Async name="AsyncRollingFileAppender">
            <AppenderRef ref="RollingFileInfo" />
        </Async>
    </Appenders>
    <Loggers>
        <!-- 设置Root Logger,将日志输出到异步Appender -->
        <Root level="info">
            <AppenderRef ref="AsyncRollingFileAppender" />
        </Root>
    </Loggers>
</Configuration>

5. log4j的rollingFile

他这个滚动,是删除最旧的文件,比如触发滚动之前编号123的三个文件,触发滚动后2其实就变成1了,如此滚动(让我想到了滑动窗口)

6. log4j2过滤某个组件所有级别的日志,配置文件该怎么写

7. es索引信息解释

@C

"sex":{ "type": "text","fields": { "keyword":{ "ignore_above": 256, "type": "keyword" } } }

  1. "sex"

: 这是字段的名称,它表示这个字段在索引中的标识符。

  1. "type": "text"

: 这表示字段的数据类型为"text",这意味着它可以存储文本类型的数据。文本类型的字段通常用于存储全文本搜索的内容。

  1. "fields"

: 这是一个嵌套对象,用于定义字段的子字段或多字段。

  1. "keyword"

: 这是一个子字段的名称,表示一个新的子字段,它用于存储原始文本数据的未经分析的版本。这种类型的子字段通常被用于精确匹配和聚合操作。

  1. "ignore_above": 256

: 这是一个参数,表示在分析文本数据时,如果文本的长度超过256个字符,就不会进行分析。这可以用来避免创建过多的分析词条,节省存储空间。

  1. "type": "keyword"

: 这是子字段的数据类型,表示它是一个"keyword"类型的字段。"keyword"类型的字段会将数据以未经分析的方式存储,适合用于精确匹配和聚合。

综合起来,这段配置定义了一个名为"sex"的字段,其中包含一个"text"类型的主字段,以及一个"keyword"类型的子字段,用于存储原始文本数据的未经分析版本,并限制了分析词条的长度以节省存储空间。这种配置在全文本搜索和精确匹配或者聚合操作中可能会很有用。

8. es @Field(type=FieldType.Auto)

@Document 自动创建索引,不支持对Text类型的字段添加关联的keyword属性,所以才设置为AUTO了

在Elasticsearch中,使用Spring Data Elasticsearch库时,如果在Java类中的字段上使用了@Field注解,并将type属性设置为AUTO,则表示让Spring Data Elasticsearch根据字段的数据类型自动推断对应的Elasticsearch字段类型。

今天上午遇到问题,如果es里面没有索引,项目启动会创建索引,但是创建的索引只有text,没有keyword,这就导致精确匹配用不了。但是如果删除索引,再插入数据,那么是可以的。 这是为什么呢?第一时间就想到是检查索引信息,经过检查,果然不同方式创建的索引,索引结构根本不一致。继续研究为什么不一致,发现启动项目的时候创建的会根据type设置对应的数据类型,而在插入数据过程中创建好像会自动推断类型,为了尽快解决问腿,本来想设置@Document(createindex = false),但是项目经理没选。最后选择了把每个字段类型都设置为auto。至此问题暂时解决,es不怎么了解,希望以后能有更深入的理解。

9. es排序

其实soeasy,只需要加一个sort,然后把sort作为参数传入PageRequest.of

Sort sort = Sort.by(Sort.Order.asc("要排序的es字段"))); Pageable pageable = PageRequest.of(page, size, sort);

10. es报错-exception [type=search_phase_execution_exception, reason=all shards failed]

我经过排查发现是因为排序字段在es中不存在,es实体类字段上设置的AUTO,导致如果插入的数据没有这个排序字段,就不会在es中创建这个字段。

解决方案用的比较捞,没有的话会给一个默认数据,我用的Integer.MaxValue,可以解决但甚是丑陋,对es理解不够,忙完这段研究研究。

11. es String和Integer区别

@C

在Elasticsearch中,数据类型 String 和 Integer 有以下区别:

  1. 数据类型:
  • String:表示文本字符串,可以包含任意字符,如文本、数字、特殊字符等。字符串字段可以用于存储各种类型的文本数据。
  • Integer:表示整数类型,用于存储整数值,包括正整数、负整数和零。
  1. 存储格式:
  • String:文本字符串以 Unicode 编码存储。
  • Integer:整数字段以紧凑的二进制格式存储,这有助于提高存储效率和搜索性能。
  1. 搜索和排序:
  • String:文本字符串可以进行全文搜索、前缀搜索和模糊搜索等操作。但在排序时,可能会出现不符合期望的结果,因为字符串排序是基于 Unicode 码点的排序。
  • Integer:整数字段可以进行范围查询、精确匹配和排序,因为整数值的大小是明确定义的。
  1. 聚合和统计:
  • String:对于文本字符串,可以进行词项统计、分桶和聚合,例如词项出现频率、词项分布等。
  • Integer:对整数字段,可以进行数值范围聚合、数值统计等操作,如求和、平均值、最大值、最小值等。
  1. 索引大小和性能:
  • String:由于字符串是以 Unicode 编码存储,索引大小可能较大,但可以通过设置合适的分析器来控制索引大小。
  • Integer:整数字段以紧凑的二进制格式存储,通常会占用较小的索引空间,有助于提高性能。
  1. 类型映射:
  • 在 Elasticsearch 中,字段的数据类型是在索引创建过程中定义的。根据您的需求,可以将字段映射为 String 或 Integer 类型。

一般来说,如果需要进行数值操作、排序和范围查询,应该选择 Integer 数据类型。如果您需要进行全文搜索或需要存储任意文本信息,可以选择 String 数据类型。同时,也要根据数据的特点和用途来决定如何正确地分析和映射字段,以便在搜索和分析中获得最佳性能和准确性。

12. es是unicode编码吗

@C

在 Elasticsearch 中,文本字段默认以 Unicode 编码进行存储和索引。这意味着您可以存储和搜索来自不同语言、符号和字符集的文本数据,无论是英语、中文、阿拉伯语还是其他任何语言,都可以得到正确的处理。

然而,需要注意的是,Unicode 编码可能会对索引大小和存储效率产生影响,特别是对于一些具有大量文本内容的索引。为了控制索引大小和性能,您可以使用 Elasticsearch 提供的分析器(Analyzer)来进行文本处理,例如分词、移除停用词、转换为小写等操作。这有助于在索引过程中优化文本数据的存储和搜索效率

13. ES 使用@Document在项目启动的时候创建索引,但是只有@Field设置为FieldType.Text类型的会自动创建,为什么?

@C

在 Spring Data Elasticsearch 中,使用 @Document 注解在项目启动时创建索引的过程叫做 "Index Creation"。当您在实体类上添加了 @Document 注解后,Spring Data Elasticsearch 会自动根据该注解的配置创建相应的索引,并根据 @Field 注解配置的字段属性来创建字段映射。

关于您提到的只有 @Field 设置为 FieldType.Text 类型的字段会自动创建索引的问题,这是因为 Elasticsearch 的索引结构和映射与字段类型相关。在 Elasticsearch 中,文本字段和其他字段类型(如整数、日期等)的映射方式有一些不同之处。

  1. 文本字段和全文搜索:

FieldType.Text 类型的字段通常用于全文搜索,它们会被分析器处理,以便将文本内容分割成词项(terms)以供搜索。全文搜索需要索引中包含单词的位置信息、频率等,所以这类字段的映射涉及较复杂的分析和索引结构。因此,当您使用 @Document 和 @Field 定义一个文本字段时,Spring Data Elasticsearch 会默认进行相应的处理,包括自动创建索引和映射。

  1. 其他字段类型:

对于其他字段类型(如整数、日期等),它们的映射和索引结构相对较简单。这些字段类型通常不需要分析过程,而是直接映射到 Elasticsearch 的字段类型。因此,对于这些字段类型,Spring Data Elasticsearch 不会自动创建索引,而是等待实际数据插入时再根据字段映射情况创建索引。

综上所述,@Document 和 @Field 注解在 Spring Data Elasticsearch 中是用于定义数据模型和索引映射的工具,而自动索引创建的机制在某些情况下与字段类型相关。如果您想要在项目启动时自动创建索引,但又不是文本字段,您可以考虑通过手动执行索引创建操作来实现。这可以在应用的初始化过程中调用相应的 Elasticsearch 客户端 API 或使用 Spring Data Elasticsearch 提供的 ElasticsearchRestTemplate 进行操作。

14. Java8使用Comparator.comparing().thenComparing()导致lambda表达式报错

一开始是这么写的:User::getAge,报的错误是:String is not a functional interface,没解决了,于是想换种写法。

然后这么些(o)-> o.getAge(),发现找不到方法,因为o是Object,没有自动推断出来类型,(User o)-> o.getAge(),这样就ok了。

15. List分组

这个没什么复杂的,只是简单记录一下,以后用到直接CV(这个里面没有对参数做校验,只保留了必要的代码,真正用要加校验)

// members每组几个元素
private static List<List<String>> listGroup(List<String> originalList, int members) {
        // 元素总数
        int size = originalList.size();
        // 组数
        int groupSize = size / members;
        // 余数
        int remainder = size % members;
        // 分组结果
        List<List<String>> groupedLists = new ArrayList<>();
        // 初始化分组结果
        for (int i = 0; i < groupSize; i++) {
            groupedLists.add(new ArrayList<>());
        }
        // 把数据添加进对应的分组
        for (int i = 0; i < size - remainder; i++) {
            groupedLists.get(i % groupSize).add(originalList.get(i));
        }
        // 处理余数,添加到最后一个集合中
        if (remainder > 0) {
            for (int i = size - remainder; i < size; i++) {
                groupedLists.get(groupSize - 1).add(originalList.get(i));
            }
        }
        return groupedLists;
    }

16. Java中的subList方法

Java中的subList方法会返回一个视图(view),而不是创建一个新的集合。这意味着子列表实际上是原始列表的一个部分视图,对子列表的操作会反映在原始列表上,反之亦然。

17. 全局异常处理

@RestControllerAdvice 加到全局异常处理类上

@ExceptionHandler(Exception.class) 加到异常对应的处理方法上

如果controller方法内加了try catch Exception,全局里的Exception就不会再生效了,不用担心打印两次

18. @ControllerAdvice与@RestControllerAdvice区别

@C

@ControllerAdvice和@RestControllerAdvice是Spring框架中用于创建全局异常处理器类的注解。它们之间的主要区别在于返回类型。

  1. @ControllerAdvice:这个注解用于创建全局异常处理器类,可以在应用程序中捕获抛出的异常,并提供自定义的异常处理逻辑。使用@ControllerAdvice注解的类通常返回一个ModelAndView对象,它可以包含视图名称和模型数据,用于渲染错误页面。
  2. @RestControllerAdvice:这个注解也用于创建全局异常处理器类,但是与@ControllerAdvice不同的是,使用@RestControllerAdvice注解的类将异常处理结果直接作为响应返回给客户端。它会将返回值序列化为JSON或其他格式,并将其作为HTTP响应的主体发送给客户端。因此,使用@RestControllerAdvice注解的类通常返回一个对象或实体类,而不是视图。

总结来说,@ControllerAdvice适用于传统的MVC应用程序,它返回ModelAndView对象用于渲染错误页面。而@RestControllerAdvice适用于RESTful API应用程序,它直接返回处理结果作为响应,通常是一个对象或实体类。

19. HttpServletRequest的getRequestURI()方法

getRequestURI()方法返回一个字符串,表示当前请求的URI。例如,如果请求的URL为example.com/myapp/user/…,那么getRequestURI()方法将返回/myapp/user/profile。

需要注意的是,getRequestURI()方法返回的是相对于Servlet容器的上下文路径的URI。如果应用程序部署在根路径下,那么返回的URI将以斜杠/开头。如果应用程序部署在上下文路径为/myapp下,那么返回的URI将以/myapp开头。

20. 记一次无聊的bug

老项目中有个hql,hql中使用了DATE_FORMAT函数,做的时候使用MySQL,一切正常。直到换了DM,这个查询能不能查询出结果就变成了概率事件,有时候能查出来,有时候查不出来。

找了一圈原因,有的说DM不支持这个函数。那怎么还能查出来?我使用达梦管理工具,确实也可以用这个函数,真奇了怪了。希望以后能找到原因。

21. spring mvc HandlerExceptionResolver接口

创建一个类并实现HandlerExceptionResolver接口。在该类中,实现resolveException方法。然后注册为一个Bean来使用。这个方法接收三个参数:HttpServletRequest对象、HttpServletResponse对象和抛出的异常。可以在这个方法中编写逻辑来处理异常并返回适当的响应。

也是一种全局捕获异常的方法,和使用@ControllerAdvice注解我感觉差别不大。

22. 网络:长连接 、短连接、心跳机制与断线重连

23. JS document.cookie

JavaScript中的document.cookie属性用于读取和设置浏览器中的cookie。

Cookie是一种存储在用户计算机上的小型文本文件,用于跟踪和存储有关用户的信息。浏览器在每次向服务器发送请求时都会将cookie发送给服务器,以便服务器可以识别用户并提供个性化的体验。

通过document.cookie属性只能访问和设置当前页面的cookie。如果您想操作其他域或子域的cookie,可能需要使用服务器端脚本或一些其他技术。此外,cookie的操作受到浏览器的安全策略的限制,例如同源策略和cookie的域限制。

同源策略的原则是,只有当两个网页具有相同的协议(HTTP或HTTPS)、主机名和端口号时,它们才被认为是同源的。换句话说,如果两个网页的协议、主机名或端口号之一不同,它们被视为不同源,那么它们之间的交互将受到限制。

24. 怎么用idea把项目推到码云

  1. 安装git
  2. 在idea中配置git,配置为第一步安装的git
  3. 创建项目,创建的时候选择创建git仓库
  4. idea安装gitee
  5. 找到gitee,选择share project on gitee,授权,然后share

25. XXL-Job

@C

开源的分布式任务调度框架,用于解决大规模分布式任务调度问题。

XXL-Job的主要特点和功能包括:

  1. 分布式任务调度:XXL-Job可以将任务分发到不同的执行器节点上执行,实现分布式任务调度,提高任务执行效率和可靠性。
  2. 调度中心:XXL-Job提供一个Web界面的调度中心,用于管理和监控任务。用户可以在调度中心上创建、编辑和删除任务,设置任务的触发条件和执行策略,查看任务执行情况和日志等。
  3. 执行器:XXL-Job的执行器是任务的具体执行单元,可以部署在不同的节点上。执行器接收调度中心分发的任务,并按照任务的要求执行相应的业务逻辑。
  4. 支持多种任务类型:XXL-Job支持多种任务类型,包括Shell任务、Java任务、Python任务等。用户可以根据自己的需求选择合适的任务类型。
  5. 弹性扩展:XXL-Job支持动态扩展执行器节点,可以根据任务负载的变化自动添加或删除执行器节点,实现任务的弹性扩展。

26. @ConfigurationProperties(prefix = "xxx") 配置

@ConfigurationProperties是Spring框架中的一个注解,用于将配置文件中的属性值映射到Java对象的属性上。

  1. 在Spring Boot应用的配置类或者Bean类上添加@ConfigurationProperties注解。

    @ConfigurationProperties(prefix = "myapp") @Configuration @Data public class MyAppProperties { private String name; private int version; }

  2. 在配置文件(如application.properties或application.yml)中定义属性。

    myapp.name=MyApp myapp.version=1

  3. 在Spring Boot应用的入口类上添加@EnableConfigurationProperties注解,以启用@ConfigurationProperties注解,也就是启动配置属性绑定功能。

    @SpringBootApplication @EnableConfigurationProperties(MyAppProperties.class) public class MyAppApplication { public static void main(String[] args) { SpringApplication.run(MyAppApplication.class, args); } }

  4. 在需要使用配置属性的地方注入@ConfigurationProperties注解标记的类。

    @Service public class MyService { private final MyAppProperties myAppProperties;

    public MyService(MyAppProperties myAppProperties) {
        this.myAppProperties = myAppProperties;
    }
    
    public void doSomething() {
        String appName = myAppProperties.getName();
        int appVersion = myAppProperties.getVersion();
        // 使用配置属性进行操作
    }
    

    }

27. minio

MinIO是一个开源的对象存储服务器,它兼容Amazon S3 API。它提供了一个简单而高效的方式来存储和检索大量的数据,可以用于构建私有云存储、备份和归档、大数据分析等应用。

下面是一些关于MinIO的主要特点和功能:

  1. 对象存储:MinIO以对象的形式存储数据,每个对象由唯一的键(Key)来标识,可以存储任意类型的数据,如图片、视频、文档等。
  2. 分布式架构:MinIO可以在多个服务器上进行部署,形成一个分布式存储集群。这使得它能够处理大规模的数据,并提供高可用性和容错性。
  3. 高性能:MinIO使用了一些优化技术,如并行上传和下载、多线程处理等,以实现高性能的数据存储和检索。
  4. 数据安全:MinIO支持数据加密,可以对存储的对象进行加密,保护数据的安全性。此外,它还支持访问控制策略,可以对存储桶和对象进行权限管理。
  5. 兼容S3 API:MinIO的API与Amazon S3兼容,这意味着您可以使用现有的S3工具和库与MinIO进行交互,无需修改代码。
  6. 可扩展性:MinIO的存储集群可以根据需要进行水平扩展,通过添加更多的服务器节点来增加存储容量和吞吐量。
  7. 轻量级部署:MinIO的部署和配置非常简单,可以在几分钟内完成。它可以在物理服务器、虚拟机、容器等各种环境中运行。

minio文件名最长多少? 255字节

bucket名称长度限制多少?3到63字符

28. lombok的@Slf4j 注解

@Slf4j是Lombok库中的一个注解,用于自动生成日志相关的代码。

import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MyClass {
    public void myMethod() {
        log.info("This is a log message");
    }
}

使用@Slf4j注解后,Lombok会自动为该类生成一个名为"log"的静态final字段,这个字段是一个Logger对象,可以直接在类中使用。

29. java String 占多少字节

UTF-8编码一个中文字符占3个字节,一个英文字符占1个字节。

GBK编码一个中文字符占2个字节,一个英文字符占1个字节。

30. static和spring注入的顺序

static最先执行,然后是@Constructor(构造方法)->@Autowired(依赖注入)->@PostConstruct注解的方法

31. Knife4j

Knife4j是一个基于Swagger构建的,为Java开发者提供API文档在线生成、测试和管理的开源工具。它提供了一套简单易用的界面,可以帮助开发者快速生成美观、易读的API文档,并支持在线测试API接口

其实就是swagger的升级版,界面更好看,操作更人性化,用起来挺爽的,以后在公司项目也可以用。

32. mybatis-plus的IdentifierGenerator

public class CustomIdentifierGenerator implements IdentifierGenerator {
    @Override
    public Serializable nextId(Object entity) {
        // 返回id
        return SnowFlakeUtil.getNumberId();
    }
}
// 在mybatisplusconfig中配置Mybatis-Plus的全局配置对象GlobalConfig中设置主键生成器
globalConfig.setIdentifierGenerator(new CustomIdentifierGenerator());

// 实体类id使用@TableId注解
public class User {
    @TableId(type = IdType.ASSIGN_ID, generator = CustomIdentifierGenerator.class)
    private Long id;
 
}

按照上面配置,之后再新建数据就不需要设置id了,妙哉

33. mybatis的MetaObjectHandler

可以帮助我们在插入和更新操作时自动填充一些字段的值,例如创建时间、更新时间等。

  1. 创建一个实现了MetaObjectHandler接口的类,并实现其中的方法。主要包括insertFill和updateFill方法。insertFill方法用于在插入操作时填充字段的值,updateFill方法用于在更新操作时填充字段的值。

  2. 在实体类中使用@TableField注解,指定需要填充值的字段。例如:

    @TableField(fill = FieldFill.INSERT) private Date createTime;

    @TableField(fill = FieldFill.UPDATE) private Date updateTime;在mybatisplusconfig中配置Mybatis-Plus的全局配置对象GlobalConfig中配置,其中,autoInjectHandler自己实现的MetaObjectHandler接口的实现类。globalConfig.setMetaObjectHandler(autoInjectHandler);

完成以上步骤后,当进行插入和更新操作时,MetaObjectHandler会自动调用相应的方法来填充字段的值,无需手动处理。(没有详细些,用的时候要再看看)