2022年开发踩坑记录

20220106

乐观锁
额外增加字段,时间戳,版本号之类的标志,取数据时要带着版本号
更新数据时,如果库内版本号与传入一致,则更新,否则不更新

悲观锁
查询出要更新的数据,然后加for update ,这样不提交,其他也无法修改
select…for update

20220109 nginx反向代理端口丢失

情况如下:
源主机Aip地址为:10.0.0.1:30001

代理B主机地址为: 120.0.0.1:30002
现在在B主机上使用nginx代理A主机的30001端口
直接访问B主机的30002端口,可访问到被代理的主机A的30001端口
但刷新浏览器之后,代理端口丢失了,就会跳向B主机的30001端口
导致访问异常,代理配置均无问题,其他几十台代理端口均正常
唯有代理出来的A不正常,怀疑是代理端口丢失
只能保证源端口和代理端口一致
具体原因未明。

20220215 日志文件太大无法直接查看处理

今天遇到一个问题,需要看日志文件才能定位到具体原因
但是一看日志,有七八个G。。。。使用常用的tail -n 或-f无法定位到
但是整个文件又太大,操作起来很不方便,无法快速定位到异常
可以使用下面的组合命令,导出自己想要的大概日志范围
查看日志文件有多少行:wc -l 文件名
将目标文件指定行数导入到新文件(p为参数,必选):sed -n “开始行,结束行p” 目标文件 > 输出文件

20220222 记一次数据采集延时导致数据丢失问题问题

问题:
现有A,B,C,D四个平台的api日志信息需要采集到es中;
入库es后,定时任务采集统计调用信息,入库mysql;
但运行一段时间后发现,mysql中统计的数据量远远小于es中存储的数据条数;
且采集程序与统计程序均无异常日志;
经排查后发现是数据延时问题:
现象如下:

A 批数据 入库时间字段为14:00   真实入库时间为14:00
B 批数据 入库时间字段为13:53   真实入库时间为13:53
C 批数据 入库时间字段为14:03   真实入库时间为14:06  存在延迟
D 批数据 入库时间字段为14:04   真实入库时间为14:04  

1、定时任务开始统计上面的数据,入库mysql,并记录最新入库时间到redis,
2、作为下一次查询es的开始时间范围
3、当A,B,D的数据被查询统计时,C的数据还没有入库,但入库时间字段为14:03
4、统计程序记录的最新入库时间字段已经是14:04了,那么C的数据就会丢失;
5、长久以往,丢失数据会很可观,
解决方式:
延迟统计时间(如果对实时性要求不高),
若定时任务五分钟统计一次,如14:00开始查询es统计入库mysql,统计延时十分钟;
查询es的入库时间范围就是 13:45:00 ~ 13:50:00
这样就可以尽可能避免延时区域过小导致的数据丢失问题

20220224 Jenkins接口调用

1、首先需要在用户管理-》用户设置-》生成api token;
2、然后系统管理-》全局安全配置-》关闭CSRF Protection选项(防止跨站点请求伪造)
3、然后去项目配置-》Build Triggers-》Trigger builds remotely (e.g., from scripts)-》填入token名称
4、postman中调用方式为http://登录用户名:3中的apitoken@ip:port/需要调用的api接口

20220301 mybatis-plus重载异常

傻叉错误,好久没遇到了,自己把自己坑死了
mapper中有如下俩方法
findAllByDate(Page page,Integer status)
findAllByDate(Page page,Integer status,String content)
调用的时候,没有问题,点击的时候也是会跳到相应的方法
但是,有且只有一个查询方法生效,另一个改的天花乱坠都不会生效
目前发现最终执行的方法为第二个,即顺序执行最后一个

20220303 Jenkins接口调用403异常

最近业务需要对Jenkins进行一些操作,JenkinsServer可以对Jenkins进行一些操作
但是功能不适用,只能自己进行接口封装,去进行接口调用
但是有这样一个现象,使用postman可以对目标接口调用,curl也可以对目标接口调用
一使用代码去请求接口时,就是403,返回未认证,使用JenkinsServer,就正常,但是不满足业务需求
那么为什么JenkinsServer包装的就行,自己写的就不行?
解决思路:
1、先查询一下有没有人遇到相似的问题,发现都是基于修改Jenkins配置,此时修改了也解决不了,换思路;
2、开始看JenkinsServer的认证过程,一层层往里走,发现了它的认证方式,也是http请求,奇了怪了,为啥我的就不行
一点点看源码,终于理了出来,顺序如下:

最外层的认证:
JenkinsServer jenkinsServer = new JenkinsServer(new URI(rul), username, passwordOrapiToken);
往里一点,发现用的是JenkinsHttpClient,整一个出来,继续往里走,是下面这样:
JenkinsHttpClient jenkinsHttpClient = new JenkinsHttpClient(new URI(rul), username, passwordOrapiToken);
在往里走,用了个this(uri, HttpClientBuilder.create(), username, password);
继续往下走,发现了猫腻,在下面的方法他进行了一次认证,还加了一个BasicHttpContext;
这俩缺一个都不行,继续往下走,看是怎么认证的:
public JenkinsHttpClient(URI uri, HttpClientBuilder builder, String username, String password) {
	this(uri, addAuthentication(builder, uri, username, password));
	if (StringUtils.isNotBlank(username)) {
		this.localContext = new BasicHttpContext();
		this.localContext.setAttribute("preemptive-auth", new BasicScheme());
	}
}
就是这个:
    protected static HttpClientBuilder addAuthentication(HttpClientBuilder builder, URI uri, String username, String password) {
        if (StringUtils.isNotBlank(username)) {
            CredentialsProvider provider = new BasicCredentialsProvider();
            AuthScope scope = new AuthScope(uri.getHost(), uri.getPort(), "realm");
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
            provider.setCredentials(scope, credentials);
            builder.setDefaultCredentialsProvider(provider);
            builder.addInterceptorFirst(new PreemptiveAuth());
        }
        return builder;
    }

整了半天才发现,它进行了basic认证。。。。
知道怎么处理的就简单了,把上边的方法整出来,放到自己写的请求代码中,同时设置BasicHttpContext,就ok了,附代码如下

package com.eastcom.zmcc.kasswebide.service;

import com.eastcom.zmcc.kasswebide.core.common.constant.JenkinsConstants;
import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.client.JenkinsHttpClient;
import com.offbytwo.jenkins.client.PreemptiveAuth;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;


/**
 * Author by huyuxiang
 * Date on 2022/3/3 11:00
 *
 * @author hyx
 */
@Service
public class JenkinsService {

    @Value("${jenkins.username}")
    String username;

    @Value("${jenkins.password}")
    String password;

    @Value("${jenkins.url}")
    String requestIp;

    private static final Logger logger = LoggerFactory.getLogger(JenkinsService.class);

    /**
     * 此方法为接口认证方法,此处适用于Jenkins中进行接口校验
     * 否则Jenkins接口无法,均为403
     */
    protected HttpClientBuilder addAuthentication(HttpClientBuilder builder, URI uri, String username, String password) {
        if (StringUtils.isNotBlank(username)) {
            CredentialsProvider provider = new BasicCredentialsProvider();
            AuthScope scope = new AuthScope(uri.getHost(), uri.getPort(), "realm");
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
            provider.setCredentials(scope, credentials);
            builder.setDefaultCredentialsProvider(provider);
            builder.addInterceptorFirst(new PreemptiveAuth());
        }
        return builder;
    }


    protected String doGetWithAuth(String url, HashMap<String, String> param, HashMap<String, String> header) throws URISyntaxException {
        HttpClientBuilder build = HttpClientBuilder.create();
        build = this.addAuthentication(build, new URI(requestIp), username, password);
        HttpClient httpclient = build.build();
        //这一步非常重要!还是403
        BasicHttpContext localContext = new BasicHttpContext();
        localContext.setAttribute("preemptive-auth", new BasicScheme());
        String resultString = "";
        HttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            if (header != null && header.size() > 0) {
                for (String key : header.keySet()) {
                    httpGet.setHeader(key, header.get(key));
                }
            }
            // 执行请求
            response = httpclient.execute(httpGet, localContext);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
                return resultString;
            }
        } catch (Exception e) {
            logger.error("[error] 请求异常",e.getMessage(),e);
        }
        return "";
    }

    protected String doPostWithAuth(String url, String json,HashMap<String, String> param, HashMap<String, String> header) throws URISyntaxException {
        HttpClientBuilder build = HttpClientBuilder.create();
        build = this.addAuthentication(build, new URI(requestIp), username, password);
        HttpClient httpclient = build.build();
        //这一步非常重要!还是403
        BasicHttpContext localContext = new BasicHttpContext();
        localContext.setAttribute("preemptive-auth", new BasicScheme());
        String resultString = "";
        HttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http post请求
            HttpPost httpPost = new HttpPost(uri);
            if (header != null && header.size() > 0) {
                for (String key : header.keySet()) {
                    httpPost.setHeader(key, header.get(key));
                }
            }
            //第三步:给httpPost设置JSON格式的参数
            if(StringUtils.isNotEmpty(json)){
                StringEntity requestEntity = new StringEntity(json, "utf-8");
                httpPost.setEntity(requestEntity);
            }
            // 执行请求
            response = httpclient.execute(httpPost, localContext);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
                return resultString;
            }
        } catch (Exception e) {
            logger.error("[error] 请求异常",e.getMessage(),e);
        }
        return "";
    }
}

20220422 maven打包异常

使用下面命令抛出异常:
mvn package -Dmaven.test.skip=true
/Unknown lifecycle phase “.test.skip=true”./
改为:
mvn clean install package ‘-Dmaven.test.skip=true’
/根本原因是使用了shell,而不是cmd去执行命令/

20220426 swagger集成异常

现象:swagger-ui.html无法访问 抛静态资源异常
v2/api可以返回json,但是json格式不正确,经过了转义
处理:springboot 2.0后fastJson不生效,需增加以下代码
但是之前并未遇到该现象,为什么产生该现象,暂时不明

    //时间格式化
    static String DATE_TIME_STR = "yyyy-MM-dd HH:mm:ss";
    static DateTimeFormatter DATE_TIME_FORMATTER;
    static String TIME_STR = "HH:mm:ss";
    static DateTimeFormatter TIME_FORMATTER;
    static {
        DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_STR);
        TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_STR);
    }   
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //springboot 2.0后fastJson不生效,需增加以下代码
        converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
        //自定义配置
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
            if (source == null) {
                return "";
            }
            if (source instanceof LocalDateTime) {
                String format = DATE_TIME_FORMATTER.format((LocalDateTime)source);
                return format;
            }else if(source instanceof LocalTime) {
                return TIME_FORMATTER.format((LocalTime)source);
            }
            return source;
        });
        // 处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(fastConverter);
    }

20220426 ffmpeg截取3gp视频异常

异常如下:写的比较清楚,当前安装的ffmpeg不支持3gp文件截取
需要为已安装好的工具重新添加插件,或者直接更新,使用新版本
Automatic encoder selection failed for output stream #0:1.
Default encoder for format 3gp (codec amr_nb) is probably disabled. Please choose an encoder manually.
可以参考下面的方式处理:
https://blog.csdn.net/weixin_35649605/article/details/117344981

20220428可运行的jar包,和给别人用的依赖jar包,哪里不同?

1、pom中不同,可运行jar包会有build标签,依赖jar包则没有

20220505 nacos配置读取异常

使用了nacos作为配置中心,IDEA中运行正常
打包后本地运行异常,项目启动时没有去读取nacos中的配置
分析原因,nacos读取配置文件默认使用UTF-8,通过cmd启动项目,项目默认编码格式为GBK,导致问题出现
解决办法:添加启动参数-Dfile.encoding=utf-8 ,则能正常启动并读取远程配置
原文链接:https://blog.csdn.net/qq_43437874/article/details/108625707

20220520 k8s容器日志中文异常

打包好的jarbao,linux服务器上运行正常,日志没有中文乱码
打包为镜像,部署至k8s时,日志输出异常,中文显示为问号
解决办法:
打包镜像时添加如下语句即可解决
ENV LANG C.UTF-8

20220525 quartz调度任务无法执行异常

启动的时候,调度器得名字必须的和之前一样
如果名字不一样,那么之前建好的调度任务将无法执行

20220526 IDEA 命令行异常,系统cmd命令行可以正常执行

换了个电脑,重新装了IDEA,运行mvn命令的时候发现,以前的命令都不能用了

找了很多方法,发现了这种方式
以前的命令
mvn package -Dmaven.test.skip=true
新的命令
mvn package ‘-Dmaven.test.skip=true’
虽然一时解决了,但后续其他的maven命令又不行了

今天突然发现:IDEA命令行的最前面有PS 前缀,
原来是IDEA用了PowerShell 作为命令行执行,整了个大无语

可用以下方式改为cmd

setting->Tools->Treminal->shell path 选择cmd就行了

202200602 fastjson版本更新至1.2.83导致异常

老版本的fastjson出现反序列化bug,涉及项目需要升级版本

但是,升级完之后,调别人接口返回的json数据,不能解析了,会抛出json格式异常

回退老版本就又可以了

感觉像是将返回的json字符串自动转义了一次,toString了一下,再转就ok了

20200602 mysql时间类型数据,自动更新后,少8小时

数据库连接也配置了时区
字段也配置了时间格式
拦截器什么的也都设置了时间格式

但是库里更新的数据,总少8小时。。。
查来查去,发现那个字段是自动根据当前时间戳更新
也就是它的值和mysql本身的时间有关系,和服务的时间没关系
查了下数据库的时间,发现数据库就少八小时。。。。
改改数据库配置就可以了

20220610 ffmpeg命令行执行异常 No such filter

在使用ffmpeg对视频进行多个水印添加和移除操作时,出现了以下情况

##命令如下

添加水印

ffmpeg -i input.mp4 -i img.png -i img2.png -filter_complex “overlay=20:80,overlay=200:80,overlay=150:150” out.mp4

移除水印

ffmpeg -i input.mp4 -vf “delogo=x=1:y=2:w=3:h=4:show=0,delogo=x=1:y=2:w=3:h=4:show=0” out.mp4

上面俩命令

Windows下命令行可以执行,没有异常
linux下命令行执行,也没有异常

但是使用以下Java代码执行命令时,ffmpeg出现了filter发现不了的异常
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);

异常排查:

1、怀疑是代码中符合编码问题,代码中输出执行的命令,复制到命令行中,也可以正常执行
2、把双引号换成单引号,也不行,命令行中直接无法执行
3、直接去掉双引号和单引号,命令可以执行了。。。

其他ffmpeg命令均未出现类似的问题,Windows和linux编码均正常,jar包服务编码也正常

且改情况只有服务执行时才会出现,目前服务无法远程调试,待后续排查具体原因

20220615 fastjson序列化异常

维护已有业务时,接口返回参数与定义参数名称不一样

定义为isSuccess,最后结果输出时返回success

使用fastjson后,定义变量不能以is开头,否则会序列化异常

会主动去掉is

可为对应is开头的参数添加get、set方法,可以解决上面出现的问题

后续规范,尽量避免使用is开头定义变量

20220616 windows查找占用端口

netstat -ano |findstr “port”

20220628 ffmepg把视频截图

ffmpeg -i 2.mp4 -s 1280x1024 -vf fps=fps=1/1 %09d.jpg

20220628 IDEA 远程调试

首先启动项目的时候,命令如下

java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9005,suspend=n -jar /usr/local/big-screen.jar

核心在这里,使用端口为9005
-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=9005

这样配置好之后IDEA中添加remote配置,然后运行,调用部署在服务器上的接口
就可以远程调试了

20220703 GPRC序列化异常

使用阉割版的jdk容器环境,会抛出类找不到的异常
原因是有些jdk环境会缺少jre,导致序列化的时候抛出类找不到的异常

20220703 maven使用技巧

1、为别人提供公共模块的依赖的jar包中,pom中没有packaging这个属性
2、父工程中使用dependencyManagement,子工程中若不引入dependencyManagement的依赖
则不会对项目包大小产生影响

20220703 arthas 服务监控,链路追踪

可以监控java项目的内存使用情况,GC情况
每一个方法的消耗时长等情况

20220704 @Async默认线程数不够,导致业务无法正常执行

@Async异步方法默认使用Spring创建ThreadPoolTaskExecutor。
默认核心线程数:8,最大线程数:Integet.MAX_VALUE,
队列使用LinkedBlockingQueue,
容量是:Integet.MAX_VALUE,
空闲线程保留时间:60s,
线程池拒绝策略:AbortPolicy
@Async默认线程数为8,且线程拒绝策略为等待

@async默认线程数为8,且线程拒绝策略为等待

20220707 @Transactional锁(lock or dead lock)异常

场景 服务A 服务B 为同一个服务,使用同一个数据库

服务A先运行,更新a表,服务B再运行更新a表

此时服务B会抛出异常,表a被锁,服务B的业务无法正常进行,服务A正常

其他使用了事务的方法全部回滚,相应方法不能继续执行

根本原因是mysql在Update带有子查询的时候,子查询的表会锁住,导致该表无法使用

20220707 @Transactional事务传播级别

若某一个类上使用了@Transactional事务注解,那么该类下的所有方法默认全部使用事务
spring 的事务传播级别默认为require,即若使用了事务注解,那么子方法均会使用事务
若该类的某个方法不想使用事务,修改事务传播级别为Propagation.NOT_SUPPORTED(不支持事务)即可
是有七种传播级别

20220707 FastJson转换list时,转换的json出现$ref引用异常

场景,先new俩个ArrayList(),a,b
然后循环a,把a中的实例类添加到b中,再使用fastjson把b转为json
异常就会出现

因为fastjson默认开启引用检测将相同的对象写成引用的形式,引用是通过"$ref"来表示的

上面的场景就是重复引用了,循环引用也会产生这种情况

重复引用的解决方法;

1.单个关闭 JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);

2.全局配置关闭 JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

循环引用的解决方法:

1.如果你前端用不到这个属性在该属性的get方法上加上注解@JSONField(serialize=false),

2.这样该属性就不会被序列化出来,这个也可以解决重复引用

3.修改表结构,出现循环引用了就是一个很失败的结构了,不然准备迎接StackOverflowError异常

20220715 旧代码if(){} else if(){} 坑

原有业务逻辑大概是这样,猛一看上去,逻辑好像没啥问题,
但仔细看就会发现,他想执行完if里面的东西,若为fals的时候,再去执行else if里的东西,不满足再去执行
else的东西。。。。。直接整麻了
在这里插入图片描述
若使用这个逻辑去跑,最终结果是这样的
在这里插入图片描述

20220714 redis过期时间设置异常 ERR invalid expire time in setex

该异常为更新redis值时,同时获取到相应key的过期时间,更新时也更新过期时间
但是当过期时间为0或者小于0时就会出现该异常ERR invalid expire time in sete

20220715 docker 容器网络ip分配冲突导致无法调用指定服务器接口

问题如下:

在一次常规的docker服务部署时,之前突然可以调用的接口无法调用了
本地调用也没有任何异常,服务器上却提示网络不可搭,找不到该路由

开始排查,排查过程如下

1、 先与运维沟通,是否有动过网络,沟通后
沟通后后发现该服务器网络与目标口服务器网络没有做任何改动
即不可能是服务器之间的网络问题

2、然后开始排查docker容器的网络分配,突然发现有一个容器的ip是 192.168.0.1
然而服务需要调用的接口地址为 192.168.0.32
而在调用接口的时候,先去查了docker的服务路由,然后走服务器的路由
这就导致容器里的服务先找到了docker的路由,没有去走服务器的路由
然后就无法调用接口了。。。

解决

查看索引容器分配的ip

docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

查看某一个容器的具体分配信息

docker inspect 容器id

关闭对应docker容器
相应docker的yml文件中加入如下内容,重启即可解决

version: '2'
services:
  java-server:
    image: java-server
    ports:
          - '10000:10000'
    restart: always
    volumes:
          -  ./config:/usr/local/config
    container_name: java-server
    privileged: true
    networks:
      - java-server

networks:
  java-server:
    driver: bridge

20220801 spring事务传播导致业务逻辑无法执行

方法A中使用了事务,去做数据库删除操作
方法B需要查询方法A删除的数据,然后做后续操作
方法A执行完删除后调用方法B,事务未提交,方法B也在事务中
查询不到删除的数据,导致了方法B的业务逻辑出现问题
此处需要修改事务传播级别,方法B中不使用事务

1、propagation-requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,则加入到这个事务中,这个是默认选项。
2、propagation-supports:如果当前有事务,则支持当前事务,如果当前没有事务,就以非事务方法执行。
3、propagation-mandatory:如果当前有事务,则使用当前的事务,如果没有当前事务,就抛出异常。
4、propagation-required_new:无论当前有没有事务,都要新建事务,如果当前存在事务,把当前事务挂起。
5、propagation-not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、propagation-never:以非事务方式执行操作,如果当前事务存在则抛出异常。
7、propagation-nested:如果当前存在事务,则作为子事务在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作

20220802 float类型取整异常

如下代码-0.5f向上取整是-0.0,不是0
向下取整,为-1.0

    public static void main(String[] args) {
        float d = -0.5f;
        System.out.println(Math.ceil(d));
        System.out.println(Math.floor(d));

    }

20220802 使用Java代码在windows10中调用exe可执行文件异常

场景如下

cmd命令行执行exe文件时,exe文件可正常执行
将相同语句使用Java代码执行时,会抛出exe需要文件无法找到的异常

原因

是因为使用java执行cmd命令时,执行命令的目录会默认为当前java程序执行目录
而不是exe文件所在目录
可以理解为在当前程序目录下面,执行了exe,导致exe找不到需要的文件
这就需要执行cmd命令的时候,指定cmd命令在哪里执行

参考代码如下

    /**
     * @param exePath exe文件路径
	 * @param sampleFilePath exe文件所在目录
     */
    private void excuteExe(String exePath,String sampleFilePath) {
        try {
            //调用exe
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec("cmd /c " + exePath + "", null, new File(sampleFilePath));
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
            //读取执行结果
			            String line;
            while ((line = bufferedReader.readLine()) != null) {
                log.info("----开始执行exe;line={}", line);
            }

        }catch (Exception e){

        }
    }

20220803 字符串操作技巧

String,StringBuffer,StringBuilder 进行大量字符串修改时
StringBuffer,StringBuilder要优于String
50w的字符串拼接操作,String需要1分30s
StringBuffer,StringBuilder只需要几十毫秒

原因就是每次对String字符串就行修改时,都是新建一个字符串,50w拼接
相当于new了50w次(不是很准确,大概就是这个意思,因为不一定new50w次,字符串也有缓存)

20220804 阿里云oss java sdk下载文件异常,提示NoSuchBucket

bucketName为test
文件目录为tmp/20220804/test.zip
下载文件时,抛出异常NoSuchBucket,tmp
但在请求oss时,设置的bucketName为test,也就是说在发生请求时
阿里云oss提供的sdk把tmp当做了bucketName
目前使用的是sdk版本是2.2.3
更新版本为3.15.0后问题修复

20221019 logback配置不生效-覆盖问题排查 耗时3天

1、问题描述

项目提供了统一的logback日志配置模块,其他项目输出日志时都需要依赖该模块
但目前有这样一个现象,有多个子项目归属同一个父项目,父项目依赖了改日志配置模块
但是子项目在运行时,有些子项目输出的日志符合依赖的日志模块,有些子项目输出的日志模块不符合

2、问题排查

1:检查日志不生效的子模块,是否存在依其他模块依赖logback,导致覆盖了独立日志模块的配置
排查后,没有发现logback.xml相关的配置
2:是否没有读取到独立日志模块的配置文件,使用配置文件配置logback路径后,依然不生效

3:尝试网上提供的解决方法,均无法解决,重新整理思路,观察日志问题
此时发现一个现象,在IDEA中,项目启动的前半程时,日志中的INFO,ERROR在控制台是没有颜色的
在后半程时,输出的日志突然开始有了颜色,并开始有颜色的上一行日志中,抛出了如下异常
No context given for c.q.l.core.rolling.SizeAndTimeBasedRollingPolicy
但是在独立的日志模块中,该配置是配置了的,就不应该抛出该异常
抛出了,即说明没有去走项目中的配置,走了其他地方的配置
且其他地方的配置级别,要远远高于自定义的配置
给人的感觉像是项目启动后,才去加载的日志配置

3、问题解决

顺着上面2.3中的思路,先去找出spring boot加载日志模块的代码,
参考了下面这篇博客
https://blog.csdn.net/weixin_44646065/article/details/125314449
通过这个博客,在源码中找到了加载日志模块的方法,然后开始debug
在一步步的debug中,突然发现在走完spring boot的log加载后
走到了一个自定义logback配置类中
该类中用@PostConstruct注解,在项目启动后,使用类的方式,初始化了logback的配置
即没有走logback.xml配置,而是通过java类的方式,去初始化logback配置
至此,问题已经定位到,去除改自定义配置类后,日志输出正常

20221008 feign请求返回值反序列异常-LocalDateTime类型无法转换导致

1、问题描述
在开发Feign接口时,结果返回的最后一步时,rpc接口的提供方突然抛出一个异常
无法将定义好的包装类转化,即序列化异常,其他feing接口均正常

2、问题排查
1:先排除rpc接口的实现业务逻辑,检查是包装类型依赖是否引入错误
检查后没有
2:再排除业务逻辑,检查是否有数据返回,检查后数据均正常
3:检查包装类型中的变量,此时看到了LocalDateTime类型
但此时没有发现是该原因

3、尝试解决
1:此时自定义的包装类型不行,那么之间返回Object是否可以?
之间返回了Object,异常消失了,可以正常调用
但是接收起来需要在调用方进行json对象解析,还是比较麻烦
2:那为什么自定义包装类型可以,自定义的类型不行
返回结果的时候一步步的debug,发现当自定义变量类型LocalDateTime时
会抛出该异常,也就是当前无法序列化LocalDateTime,导致了异常发生
有俩种方法,都需要引入下面的依赖

		<dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>${jackson.version}</version>
        </dependency>
    //一种是在LocalDateTime类型的变量上面使用注解指定序列化方式
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
	//一种是重写ObjectMapper
	当新项目时,推荐使用ObjectMapper
	老项目时,还是使用注解比较好,比较序列化的改变可能会导致其他不受控因素发生

20221101 this事务或异步失效解决办法

1:自己依赖自己
   即在service类里使用自己
2:在自身方法里使用代理获取到自己的对象
   然后使用异步或事务方法
3:失效原因好像是事务或异步都是通过代理实现,之间使用this是使用的自己当前的对象,没有使用
   代理获取到对象,也就失效了,大概是这个意思,详细的原因可以自行查询。   
@Service
public class TestService{

    @Autowired
    private ApplicationContext context;
	
    @Autowired
	@Lazy
    private TestService testService;	
	
	public void testFunction(){
	
		//方法1
        testService.testAsync();

	    //方法2
		TestService proxySelf = context.getBean(TestService.class);
		proxySelf.testAsync();
		
	}


	@Async
	public void testAsync(){
       //todo 业务逻辑
	}
}
  

20221114 Feign内部服务接口调用时请求头问题

1、问题场景:
场景如下:前端通过浏览器或APP调用服务A接口,服务A内部Feign调用服务B接口
此时服务A可正常使用请求头参数,服务B也需要使用这些请求头参数,
获取时无法获取

2、问题排查与解决:
代码无异常抛出,只是获取不到对应请求头的值,那么在服务B中进行日志打印,打印请求头
发现没有该值,服务A中是有该值的,那么请求头默认是不会传递的吗?
后经查询后发现,默认配置下,请求头的确不会传递,若在Feign调用过程中进行请求头的传递
有俩种方法:
1:增加feign配置,可以传递请求头;
2:在最外层捕捉到需要用的请求头,将其添加为feign接口参数
推荐使用第二种,避免请求头传递带来的安全风险

20221114 spring boot打包部署后,无法正常获取resource中的静态文件

1、问题场景:
在开发excel模板下载功能时,需要将指定模板返回给前端,不能动态生成,
便将其放入resource目录下,在本地测试时没有问题,但部署在容器中后,便无法正常获取文件,
提示获取文件异常

2、问题排查:
第一次遇到该问题,在本地环境中、Linux服务器中部署服务均未遇到该问题,但是在容器化部署时,遇到了该问题
经查询后发现是资源文件获取的方式有问题
刚开始使用的获取方式如下
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + filename).toString();
修改为如下方式即可正常获取
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(“template/filename”);

3、问题原因:
没打包之前,文件是真实存在与文件系统中的,
一旦打成jar包后,使用File是访问不到资源的内容的,推荐使用getInputStream()的方法

20221207 feign内部Get接口请求参数过长导致400异常

1、问题场景
业务正常的feign接口调用,突然抛出400异常,且对应服务上下游业务都没有抛出异常
且只对某条数据出现400,其他数据均正常

2、问题排查
1、怀疑参数没有判空导致,于是加了判空逻辑和日志,打印请求参数
发现请求参数并不为空,只是很多,那么就是定义的内部接口有问题
2、看到定义的feign接口请求类型为GET,复制出请求参数后,发现请求参数过长
接口请求改为post,参数接收使用请求体接收后,该问题消失

3、问题原因:
feign内部调用其实也是转为http调用,自然会存在http接口调用类似的问题;
此处就是get请求中,url最大长度超出限制,导致了无法正常传入参数,接收方没有接到参数
抛出400,参数没有传递的异常

20221207 由于业务采用纯数值id过长,导致解析为Long类型是超出Long类型最大值

用户分为两部分,A,B
俩用户分表存,一个唯一主键为Long类型
一个唯一主键为字符串类型,且长度很长,在业务逻辑中,俩种主键对应的业务含义一样,
均为用户唯一标志
在一张业务主表中,用户标志字段会存在A、B俩种id值
这就导致查询去A模块查询A用户信息时,出现Long解析异常,因为B的长度太长了

此处应根据业务主表的类型,去分类用户id查询,避免出现该异常

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无名一小卒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值