开发杂记

作为个小白,开发过程中总会遇到一些困扰,也会有许多小惊喜,此日志作为一个杂乱文档,随缘记录,暂不整理

使用一个list接收一个字符串表示的列表,以","分隔

statusList = new ArrayList(Splitter.on(SeparatorConstant.COMMA).omitEmptyStrings().splitToList(request.getStatus())

fastjson使用技巧

可以使用下列代码获取一个json串中的name对应的value的值

Object name = JSONPath.eval(data, "$.name")

解决idea中打开jar包源码,源码注释中文乱码问题

代码中鼠标右键,File Encoding-->选择对应编码-->点击Reload

java中的标签


错误: 找不到或无法加载主类

idea 2020版
解决方案:

为什么在静态方法中无法调用非静态方法?

静态方法也可是说是类方法,是类这个层级的,在类被加载的时候就分配内存空间了。而非静态方法只有属于对象这个层级的,只有当对象被调用的时候才会为其分配内存。就是说静态方法分配内存的时间早于非静态方法,在静态方法中调用非静态方法就相当于在已存在的方法中调一个未存在的方法,那自然是不行的。

解释器与编译器的区别

解释器和编译器区别是:1、解释器是直接执行用编程语言编写的指令的程序,而编译器是把源代码转换成即翻译低级语言的程序;2、编译器生成一个独立的程序,而解释的程序总是需要解释器来运行。

参考资料:
https://www.php.cn/faq/415948.html
https://baijiahao.baidu.com/s?id=1731688399218820886&wfr=spider&for=pc

使用框架生成toString()重写方法

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

取数据库大字段中json键值对中的值

    public String getxxxFromExtInfo(String extInfo) {

        Map<String, String> extMap = FlGsonUtil.fromJson(extInfo,
                new com.google.common.reflect.TypeToken<Map<String, String>>() {}.getType());
        String type = extMap.get("type");
        if (StringUtil.isNotBlank(type) && “YES”.equals(type)) {
            return "YES”_xxx";
        }
        return "NO_xxx";
    }

InitializingBean的作用

通过实现InitializingBean接口实现Bean注入到Spring容器且初始化后,执行特定业务化的操作

参考资料:https://blog.csdn.net/goodjava2007/article/details/122245457

简化new一个hashmap的写法

偶然发现的代码

    /**
     * 策略map
     */
    private final static Map<String, AbstractxxxxxxServiceProcessor> processors = Maps.newHashMap();

与我们熟悉的

Map<String, Object> result = new HashMap<String,Object>();

相比

Map<String, Object> result = Maps.newHashMap()

这种是google的guava.jar提供的写法,好处是不用再写一遍泛型了

equal方法忽略比较字符的大小写

String str="";
"".equalsIgnoreCase(str)

java.lang.IllegalStateException: endPosTable already set

事件描述:本地启动一个应用,之前能启动的,但是最近本地启动发现maven编译就报错。事情比较急,想先解决问题,查了网上的资料以及在"Bug Database (http://bugs.java.com)"上看后,发现可能需要更换jdk版本,但是考虑到之前可以启动,以及内心有点抗拒更新jdk版本后,仔细回忆了一下之前的启动方式,发现是idea版本的原因,因为公司一些旧的开发插件不兼容新版本idea,所以我本地其实有两个版本idea,之前本地启动成功使用的是idea2018.3,现在使用的是2020.1。

报错信息


编译器 (1.8.0_291) 中出现异常错误。如果在 Bug Database (http://bugs.java.com) 中没有找到该错误, 请通过 Java Bug 报告页 (http://bugreport.java.com) 建立该 Java 编译器 Bug。请在报告中附上您的程序和以下诊断信息。谢谢。
java.lang.IllegalStateException: endPosTable already set
[INFO] -------------------------------------------------------------
  at com.sun.tools.javac.util.DiagnosticSource.setEndPosTable(DiagnosticSource.java:136)
[ERROR] COMPILATION ERROR : 
  at com.sun.tools.javac.util.Log.setEndPosTable(Log.java:350)
[INFO] -------------------------------------------------------------
  at com.sun.tools.javac.main.JavaCompiler.parse(JavaCompiler.java:667)
  at com.sun.tools.javac.main.JavaCompiler.parseFiles(JavaCompiler.java:950)
  at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.<init>(JavacProcessingEnvironment.java:892)
[ERROR] An unknown compilation problem occurred
  at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.next(JavacProcessingEnvironment.java:921)
[INFO] 1 error
  at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1187)
[INFO] -------------------------------------------------------------
  at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
  at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)

在注解中插入类的链接

使用场景:
调用一个接口的请求中包含一个状态字段,但是查看代码无法知晓有哪些状态,可以使用此方式在注释中链接枚举类

    /**
     * xxx状态{@link xxxStatusEnum}
     *
     * @param 
     */

返回一个不可修改的list

场景:查看一个购物车内有什么商品

我们可以通过Java提供的Collections.unmodifiableList()方法,让getter方法返回一个不可被修改的UnmodifiableList集合容器,而这个容器类重写了List容器中跟修改数据相关的方法,比如add()、clear()等方法。一旦我们调用这些修改数据的方法,代码就会抛出UnsupportedOperationException异常,这样就避免了容器中的数据被修改

public class ShoppingCart {
  // ...省略其他代码...
  public List<ShoppingCartItem> getItems() {
    return Collections.unmodifiableList(this.items);
  }
}

public class UnmodifiableList<E> extends UnmodifiableCollection<E>
                          implements List<E> {
  public boolean add(E e) {
    throw new UnsupportedOperationException();
  }
  public void clear() {
    throw new UnsupportedOperationException();
  }
  // ...省略其他代码...
}

ShoppingCart cart = new ShoppingCart();
List<ShoppingCartItem> items = cart.getItems();
items.clear();//抛出UnsupportedOperationException异常

鉴权系统设计思路

1、给每个允许访问的服务调用方派发一个ID(如果有多项服务应用,可以像支付宝开放平台一样叫应用id、AppId)和一个对应的密码(密钥)
2、将调用方的请求接口的url跟appid、密码、时间戳拼接,对业务参数进行加密(可以是SHA算法啥的),生成一个token,请求接口的时候将这些一起传给服务方

(1)生成token
SHA加密(http://www.xxx.com/user?id=2233&appid=123&pwd=asdasdf&time=20230426151301)

(2)生成新的url
http://www.xxx.com/user?id=2233&appid=123&pwd=asdasdf&time=20230426151301&token=xxxxxxxxxxxx

3、服务方收到调用方接口请求后,解析业务参数。先校验时间戳是否为当前时间的一分钟内(时间自定义),如果不是报token过期,拒绝请求。如果token未过期,使用同样的算法加密业务参数生成token,对照是否与传递过来的token一致,不一致说明业务参数被篡改

见识到的一些繁琐的交互方式实现

平台方(服务端)

提供一个SM2公钥给数据调用方
提供一个固定token给数据调用方

数据调用方(客户端)

每次调用需要生成一个sm4公钥

请求示例

{
  "data": "88a79fd2e8a9bfd66acb5b7f65bf3895b083381fe35ff99a099dd45f1344xxxx",
  "key": "MDQ5NkY5MUI2QjJENTk0NDcyQzVDRTcwMDlBMjFDMjFBMzQ0NDk5MzY4MTBDMTY5RTdBRTg0N0NBQTFGRjB-COTczQzA1N0FGRDhGMjBFQjk3MkQ1N0RGNzBFODUwNTI1RUMwQ0VGNkJENjFBOTA3NTM4QjBGMkJCMjA2REVEN0E1NUVEQjA0RTVBN0Y3NTVGNUY1MzgwMEFFOEZGQUE0MTYxMjQ3NjZBODM2MjkwQ0E5NTBDOUQ0RjI1MDE3MTFBMEMyRDk5ODJCQUZFNzI0Nzc4NDI1Q0Q2RkEXXXXXXXXXXX==",
  "mac": "107de424e0ed4ed8520acc1e60cae72a2d745bee3b0277a3eba5978cxxxxxxxx"
}


data:加密后的业务参数(如"{"身份证号":"330328xxxxxxxxxxxx"}")
key:使用base64编码的sm4工作密钥
mac:根据data的值使用PBOC算法计算mac值

响应示例

{
	"code": 200,
	"data": "7c6337b445287437c749c9c848ddb496623febbf28dd3a47f5a513160e15e52ecb937e58e12f3467962a33001b2d6889a1b5436c7f6644b1b6fe5a97781e278c07039fdd56ae8e3176949b160e25dbb76079a497f5e93e61684b12fb2e03d8e6a6d993f5c7a36121dc525f5d4dd2554ead02657d049cbc64bf9741dbd52803a17ce77561e6f5db912ed18ea2142f0924f2a248f71e8265726f5059bc497a530f97b631716795fa9de2c98da0868a56fd7388a9db5f8b0e77565f63b5ef783c3c3c7ea65205c84e4399cabe00f36fdb6a72e497aa39b5e726a745ac8eee921345db710d6667b880eb81176cae1d7730710fa7667df155050c85d4327b559df178a7c553c686916b1e78c62d6f354452611b3e0b1e502ca519d229a677b33e5a47936f95d2af56586fb8b36cf2826a20bafe99f5846c0ea7f8be675d0c31480fd9b2c53cae6dcb1dfa1f7011b434f997f5e3f4ca41c7fb379e27c9fa040d26447b429b5ff9c5bb023c4815313b6a7a02de2bdc7e02e156d459af149e9fc6832cd78c7cc7efb8eb5259d8f07e986d51658b158478a8abe7fd4b66ccdc55918df45574153cf8d66a624bd61569c0dd0189d926f6c59de2ae8a008160fbb09d4ad583e58a531ee1f31fe4690351135c9588c3627606036c7b1b143621cb1f0731bf1680185d46f6923c78d6e1ad3eef99dc166f249db0764c977e6a3d2778e047641b33e6cc6b47d6d25630ba986b806f5dfedf60332969561ec37053eff58aec1999aabba0d2cf925f6123a94b320ba52e036011d1e7303d8d7990d79009eb53c7b9658df6ded7effa28f371c9eb493ec6d02bbce87269ee12a4c27ae7b50ea6f95aea7139b7005ded1a23f3d2cb3ed6a41bf6d5d004a08c6a6b7fa69fc8112fe11238e167605777979a66c0f264b514f258fef75ead1b2a8851d68652a1667594c6ffc711dbd894925df4c9d55cbae69f977e181f78bd143e3c6af8bfd4c74776f4c711afa02be614b21f105724713e8a42d87bb5fa4d0fcb592fe1a7f66c814ee9544c3e2b6a946995120a68a2ad5a37896dad4a69b21e7a58b675546214b8851e11b3c12c1a3ee5fcc6bc5e314c44c280e0c8733c55f9a4c43e6b809729f80a3adaf80052f0c3c56a2b46709da7317cdc751e4ab64ffe35d75bfc9b171c7df85e6011d1e7303d8d7990d79009eb53c7b94fbf5a3cdae527df72688a4097a5c085658df6ded7effa28f371c9eb493ec6d0bccfb398adef73575e2e3896075452ea39c2bb1302f4fd5837be13a8f175db1ff680f89191b7e01ee8df1a52xxxxxxxx",
	"message": "操作成功",
	"mac": "44845cbb0c2088f79f95e90fdf0fd1ac86a402061d0b1ed92e9f93abxxxxxxxx"
}

流程:
1、数据调用方每次请求生成一个sm4密钥
2、使用平台方提供的sm2公钥作为SM2加密算法的密钥对sm4密钥加密后进行base64编码,放入key的值中,key=base64(SM2加密算法(加密内容:sm4密钥,加密密钥:sm2公钥))
3、数据调用方使用SM4加密算法,将sm4密钥作为算法密钥加密业务数据,调用平台方提供的接口,data=SM4加密算法(data的明文如:"{"身份证号":"330328xxxxxxxxxxxx"}",加密密钥:sm4密钥)
4、平台方使用sm2私钥(注意是私钥,与公钥是一对,但是没有给数据调用方,自己保存),解密出key的值,即获取到数据调用方此次调用生成的sm4密钥
5、平台方使用获取到的sm4密钥对业务参数data解密获取到明文,使用相同的PBOC算法将sm4密钥作为算法密钥计算mac值,将计算出的mac值与请求中的mac值比对校验数据是否有被篡改,mac=PBOC算法(data的值:"{"身份证号":"3303xxxxxxxxxxxxxx"}",加密密钥:sm4密钥)
6、平台方使用查询到数据调用方所需数据后,使用解密到的数据调用方生成的sm4密钥,作为SM4加密算法的密钥,加密数据返回给数据调用方
7、数据调用方接收到返回后使用sm4密钥解密获取明文

数据调用者维度

请求的加密方式:
data:SM4加密算法(data的明文如:"{"身份证号":"330328xxxxxxxxxxxx"}",加密密钥:sm4密钥)
key:base64(SM2加密算法(加密内容:sm4密钥,加密密钥:sm2公钥))
mac:PBOC算法(data的值:"{"身份证号":"330328xxxxxxxxxxxx"}",加密密钥:sm4密钥)

响应的解密方式:
data:SM4解密算法(平台方返回的data值,解密密钥:sm4密钥)

其他交互方式:
也可以参考一下支付宝开放平台的交互方式
文档参考:https://opensupport.alipay.com/support/helpcenter/192/201602472199?ant_source=zsearch#anchor__2&ant_source=manual&recommend=59b572a236a0a3a342f413e3c8f21ea0

System.currentTimeMillis()方法与Instant.now().toEpochMilli()生成的时间戳有什么不同吗?

System.currentTimeMillis()方法返回当前时间与UTC时间1970年1月1日00:00:00之间的毫秒数,即System.currentTimeMillis()返回的时间戳是基于系统时钟的。而Instant.now().toEpochMilli()返回的时间戳是基于协调世界时(UTC)的。这意味着,如果计算机的系统时钟被调整了(例如,由于夏令时调整),那么System.currentTimeMillis()返回的时间戳将会受到影响,而Instant.now().toEpochMilli()返回的时间戳不会受到影响。另外,Instant.now().toEpochMilli()返回的时间戳精确到毫秒级别,而System.currentTimeMillis()返回的时间戳的精确性取决于系统时钟的精度和操作系统的实现。

curl命令测试目标地址是否能成功连接并显示耗时

curl -o /dev/null -s -w 'DNS解析时长:%{time_namelookup}\n建立tcp时长:%{time_connect}\n客户端到服务器时长:%{time_starttransfer}\n从开始到结束时长:%{time_total}\n下载速度:%{speed_download}\n' -X POST https://www.xxxxxxxxxx.com/api/notify -H "Content-type: application/json" -H "token:xxxxxxxxxx"  -d'{"data":"xxxxxxxxxx","key":"xxxxxxxxxx==","mac":"xxxxxxxxxx"}'

使用jsonfast时,JSONObject().fluentPut()与JSONObject().put()的区别

起因是我写了一段代码

        actCaseDTO.setExtendInfo((request.getTuneType() == null) ?
                "" : JSON.toJSONString(new JSONObject().put("tuneType", request.getTuneType())));

我这段代码中request.getTuneType()有值且为"INTERFACE_TUNE"但是最终actCaseDTO中extendInfo的值为"null",百思不得其解,Dbug也看不出来,我一度以为是不是这里不能new JSONObject()直接put

直到我不简化代码发现又是正常的

        String extendInfo;
        if (request.getTuneType() != null){
            JSONObject jsonObject=new JSONObject();
            jsonObject.put("tuneType", request.getTuneType());
            extendInfo=jsonObject.toJSONString();
        }

于是我让ChatGPT帮我简化一下代码,我发现它使用的是.fluentPut()方法,这是啥?

String extendInfo = (request.getTuneType() != null) ?
        new JSONObject().fluentPut("tuneType", request.getTuneType()).toJSONString() : "";

网上搜了一圈两个方法的区别,楞是内容太杂,或者还是CSDN的付费文章,我直接就是再问一下ChatGPT,果然ChatGPT是真好使

在 Fastjson 中,putfluentPut 都是用于向 JSONObject 中添加键值对的方法,它们的主要区别在于返回值。

  1. put 方法:

    • put 方法是普通的添加键值对的方法,它会修改原来的 JSONObject 对象,并且返回值是 void,因此无法进行链式调用。
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("key1", "value1");
    jsonObject.put("key2", 123);
    
  2. fluentPut 方法:

    • fluentPut 方法返回的是当前 JSONObject 对象本身,因此可以进行链式调用,实现连续添加键值对的操作。
    JSONObject jsonObject = new JSONObject();
    jsonObject.fluentPut("key1", "value1").fluentPut("key2", 123);
    

因此,如果您需要在一行代码中进行多次添加键值对的操作,并且希望代码更加简洁,可以使用 fluentPut 方法。如果只需要简单地添加键值对,可以使用普通的 put 方法。

maven打包

mac打包四五分钟的东西,我windows要打包7-15分钟,不能忍

# 使用一个核心 -T 2.0C 表示使用两个核心
#-DskipTests=true,跳过测试模块

mvn clean install -T 1C -DskipTests=true

windows右键菜单栏快捷使用相应应用打开文件(以HBuilderX为例)

公司不让用notepad++,卸了之后想了想替代软件,要不用HBuilderX吧,但是右键打开一个文件不能直接用HBuilderX打开,有点小难受,问了一下ChatGPT有没有啥解决方案,你还别说,挺好使的

要在 Windows 或 macOS 中实现右键菜单选项,让你可以使用 HBuilderX 打开文件,可以通过以下几步来设置:

在 Windows 中:
手动修改注册表:
打开“运行”(Windows 键 + R),输入 regedit 并回车,进入注册表编辑器。
导航到 HKEY_CLASSES_ROOT*\shell。
右键点击 shell 目录,选择“新建 > 项”,命名为 Open with HBuilderX。
在新建的 Open with HBuilderX 项上,右键选择“新建 > 项”,命名为 command。
选择新建的 command 项,在右侧双击默认值,并输入 HBuilderX 的可执行文件路径。例如:

"C:\Path\To\HBuilderX.exe" "%1"

确保将 C:\Path\To\HBuilderX.exe 替换为你实际安装 HBuilderX 的路径。

  1. 使用第三方工具:

如果不想手动修改注册表,可以使用第三方工具,例如 Context Menu Manager 或 FileMenu Tools 等,来简化这个过程。

在 macOS 中:
使用 Automator 创建服务:
打开 Automator(通过 Spotlight 或从应用程序中找到它)。
选择“服务”类型的新文件。
在“服务接受的类型”中,从下拉菜单选择“文件或文件夹”。
在左侧的“库”中,选择“实用工具”并拖拽“运行 Shell 脚本”操作到工作区。
在“运行 Shell 脚本”中,选择 /bin/bash 作为脚本,然后输入以下内容:

open -a "HBuilderX" "$@"

保存这个 Automator 服务,命名为 Open with HBuilderX。

使用右键点击服务:

现在,当你右键点击一个文件或文件夹时,选择“服务”选项,你会看到 Open with HBuilderX,选择它即可用 HBuilderX 打开所选文件。

通过以上步骤,你可以在 Windows 和 macOS 系统中实现右键菜单直接使用 HBuilderX 打开文件的功能。

写枚举类的时候可以使用@AllArgsConstructor注解,简化代码

for update锁的使用

如果我想进行查询之后更新内容的操作,可以在查询语句的后面加入"for update nowait",如

    <select id="selectForUpdate"
            resultMap="com.xxx.common.dal.mybatis.mapper.sharding.base.BaseAwtBeneUserVoucherMapper.BaseResultMap">
        select
        <include refid="com.xxx.common.dal.mybatis.mapper.sharding.base.BaseAwtBeneUserVoucherMapper.Base_Column_List" />
        from awt_bene_user_voucher
        where id = #{id,jdbcType=VARCHAR}
        for update nowait
    </select>

并且将查询和更新操作在同一个事务中执行,如此,当执行查询语句后,就会对查询出的结果集进行上锁,查询出2条记录就对这2条记录进行上锁,这时候其他数据库操作在锁没释放前无法操作这2条记录,这就是行锁,只有当这个事务结束(执行完更新操作后),才会释放锁。

posted @ 2023-01-06 11:20  AzureSky_X  阅读(969)  评论(0)    收藏  举报