现在很多编译器和软件都开始要求使用 JDK 11 了。 因此我们希望在 CentOS 上安装 JDK 11。 运行下面的命令: yum install java-11-openjdk-devel 如果你的系统中还装有不同版本的 JDK 的话。你需要运行: alternatives --config java 来选择默认的 JDK。 随后你就可以验证安装的 JDK 了。 https://www.ossez.com/t/centos-7-jdk-11/637
现在很多编译器和软件都开始要求使用 JDK 11 了。 因此我们希望在 CentOS 上安装 JDK 11。 运行下面的命令: yum install java-11-openjdk-devel 如果你的系统中还装有不同版本的 JDK 的话。你需要运行: alternatives --config java 来选择默认的 JDK。 随后你就可以验证安装的 JDK 了。 https://www.ossez.com/t/centos-7-jdk-11/637
使用下面的方法: logger.debug("Current DateTime in milliseconds - [{}]", new DateTime().getMillis()); 上面的代码输出的内容是: 15:01:51.331 [main] DEBUG c.i.s.c.t.utilities.CodecUtilsTest - Current DateTime in milliseconds - [1603998111331] 获得当前日期时间的毫秒数,这个毫秒数是从 1970-01-01T00:00:00Z 开始计算的。 1970年, Unix正式诞生,在第一版《Unix Programmer’s Manual》中把“1971年11月3日”定义为“自1970年1月1日0时0分0秒以来以1/60秒为单位的时间”。 此后,这个定义由于可定义的时间范围,时区,闰秒等问题被重新定义。 https://www.ossez.com/t/java-datetime-unix/623
有时候我们需要知道一个文件的大小。 我们可以使用一些方法,比如说将文件读取成 InputStream,然后再使用 available() 获得长度就可以了。 我们也可以使用 FileUtils 来获得。 使用的方法是: FileUtils.sizeOf(localFileCache) localFileCache 中定义的是文件对象。 关于 sizeOf 的使用为:返回指定的文件或者文件夹的大小。如果你的 File 对象为一个文件的话,这个方法将会返回文件的大小。 如果你的 File 对象为一个目录的话,那么上面的方法将会返回这个文件夹的大小。这个文件夹的大小将会包含这个文件夹中所有子文件夹的内容。换句话说,这个方法是进行递归大小查询的。 但是,如果一个文件夹或者子文件夹有安全限制,不允许访问的话,那么这个方法将不会将上面的文件夹的内容进行计算。 https://www.ossez.com/t/java/620
在 Azure 上传文件的时候遇到了一个下面的异常: java.io.IOException: mark/reset not supported at java.base/java.io.InputStream.reset(InputStream.java:655) at com.azure.storage.common.Utility.lambda$convertStreamToByteBuffer$4(Utility.java:236) at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:46) at reactor.core.publisher.Mono.subscribe(Mono.java:4213) 问题解决 当给定的流不支持 mark 和 reset 就会报这个错误。 我们用的代码是: blobClient.upload(inputStream , inputStream.available()); InputStream 是不支持 mark 和 reset 的。 BufferedInputStream继承于FilterInputStream,提供缓冲输入流功能。 缓冲输入流相对于普通输入流的优势是,它提供了一个缓冲数组,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(例如你指定的文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容部分或全部返回给用户。 由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快。 Azure 使用上面的方法来尽量保障数据能够上传到存储中。 解决方案是用 BufferedInputStream 再把原来的流包装一层。 什么时候会出现这种错误呢,当你获得一个 InputStream 流,这个流是不允许读写头来回移动,也就不允许 mark/reset 机制。 所以上面的代码修改为: blobClient.upload(new BufferedInputStream(inputStream) , inputStream.available()); 然后再重试,你就会看到文件上传上去了。 登录控制台查看上传的文件。 https://www.ossez.com/t/java-io-ioexception-mark-reset-not-supported/617/2
在文件上传到服务器的时候,我们希望能够获得文件的指纹以确定文件没有被篡改过。 常用的算法最开始使用的是 MD5,随后随着技术的发展,MD5 算法已经被确定是不安全的了。 目前可能使用更多的是 HSA3_256 哈希算法。 哈希算法通常有以下几个特点: 正像快速:原始数据可以快速计算出哈希值 逆向困难:通过哈希值基本不可能推导出原始数据 输入敏感:原始数据只要有一点变动,得到的哈希值差别很大 冲突避免:很难找到不同的原始数据得到相同的哈希值 哈希算法主要有MD4、MD5、SHA。 MD4 1990年 输出128位 (已经不安全) MD5 1991年 输出128位 (已经不安全) SHA-0 1993年 输出160位 (发布之后很快就被NSA撤回,是SHA-1的前身) SHA-1 1995年 输出160位 (已经不安全) SHA-2包括SHA-224、SHA-256、SHA-384,和 SHA-512,分别输出224、256、384、512位。 (目前安全) 在 Java 中,可以使用 Apache 提供的 Apache Commons Codec,非常容易的获得文件的哈希字符串指纹。 方法也非常简单,第一步就是需要将文件读取为 InputStream。 如果自己写的话,可能这一步有点代码。 你可以使用 Apache 提供的 FileUtils.openInputStream 就可以直接将文件读取为 InputStream 了。 考察下面的代码: InputStream is = FileUtils.openInputStream(new File(SCOConstants.PATH_DATA_EXCHANGE + "Estimated vs Original Manual (JIRA) 10-23-20.csv")); MD5 哈希 在文件读取后,你只需要使用 Apache Commons Codec 提供的 DigestUtils 方法就可以了。 /** * Test to get file's MD5 Hash * * @throws Exception */ @Test public void fileMD5Test() throws Exception { String md5 = StringUtils.EMPTY; try { InputStream is = FileUtils.openInputStream(new File(SCOConstants.PATH_DATA_EXCHANGE + "Estimated vs Original Manual (JIRA) 10-23-20.csv")); md5 = DigestUtils.md5Hex(is); } catch (Exception e) { e.printStackTrace(); } logger.debug("MD5 for File: {}", md5); } 上面的代码就可以直接获得 InputStream 的 MD5 哈希。 程序的输出为: 09:32:31.522 [main] DEBUG c.i.s.c.t.utilities.CodecUtilsTest - MD5 for File: 1ec6473fc1bd50a982767f555734af64 SHA3 256 与 MD5 哈希算法是一致的。 你需要首先也将文件读取为 InputStream ,然后使用 Apache 提供的 DigestUtils.sha3_256Hex(is); 就可以了。 考察下面的代码: /** * Test to get file's SHA3_256Hex Hash * * @throws Exception */ @Test public void fileSHA3_256HexTest() throws Exception { String sha3Hex256 = StringUtils.EMPTY; try { InputStream is = FileUtils.openInputStream(new File(SCOConstants.PATH_DATA_EXCHANGE + "Estimated vs Original Manual (JIRA) 10-23-20.csv")); sha3Hex256 = DigestUtils.sha3_256Hex(is); } catch (Exception e) { e.printStackTrace(); } logger.debug("SHA3_256Hex for File: {}", sha3Hex256); } 运行程序的输出为: 09:35:48.093 [main] DEBUG c.i.s.c.t.utilities.CodecUtilsTest - SHA3_256Hex for File: https://www.ossez.com/t/java/615
很多公司都在做这方面的转型。 尤其是在公司达到一定运营规模后,PHP 的问题会让公司花费更多的时间去部署排查问题。当时公司选择 PHP 的主要原因,就是因为开发简单,框架也还不错,部署也比较快。持续集成的问题可能没有太多的问题。 如果一开始要上 Java 的话,很多时候需要面临从框架,数据库,ORM,CI,DevOps 各个不同方面的技术协调和沟通,对不是财大气粗的公司来说,这个负担还是比较重的。毕竟人力成本还在那里摆着。 相对以前来说,现在 Java 世界也保持比较开放的态度,有 Spring 全家桶,基本上能够帮你解决很多快速部署的问题,采取微服务可以前台和后台分离,采取混合云架构,可以将一些网络和存储压力转移。 其实不管选何种语言都差不多,可能你们公司在使用 PHP 的时候已经达到了 PHP 的性能瓶颈和极限了,转型 Java 再正常不过了。也有用 .NET 的,很多公司不会考虑,主要是版权问题和微软绑定的问题。 另外,如果你搜索在互联网世界中有多少个网站使用 Java 有多少网站使用 PHP 的,这个其实是没有任何意义的。因为一个 WordPress 就能碾压很多网站了。 PHP 的优势在于快速部署,没有多少人愿意花费几天时间去安装数据库,部署应用,调试 Log ,并且界面还不好调整。 使用 PHP 能够飞速部署一些小应用,对个人,初创公司,想利用一些已有的框架的时候就非常方便了。 https://www.ossez.com/t/php-java/592
在 Hibernate 或者 ORM 映射中,我们可能会存在 1 对多的情况。 在这个时候,如果你使用 Jackson 将对象序列化的时候,就会出现双向引用导致的无限递归(infinite recursion)的情况。 @JsonManagedReference 和 @JsonBackReference 注解就是为了避免这个双向引用的情况。 @JsonBackReference 和 @JsonManagedReference:这两个标注通常配对使用,通常用在父子关系中。 假设我们有 2 个对象。 一个对象是 QIndex 和 QTitle 一个 QIndex 可能对应有多个 QTitle。 那么在 JPA 中的对应关系的 QIndex 应该定义为: @OneToMany(mappedBy = "qIndex", cascade = CascadeType.ALL, orphanRemoval = true) @OrderBy("questionNumber ASC") @JsonManagedReference private List<QTitle> qTitleList = new ArrayList<>(); 在 JPA 的 QTitle 中应该定义为: @ManyToOne() @JsonBackReference private QIndex qIndex; 在序列化的时候,@JsonManagedReference 注解的属性则会被序列化,@JsonBackReference 的注解将会被忽略。 @JsonManagedReference 注解,通常说明这个字段是一个双向引用的字段,这个字段在这个双向引用中的角色为 “父”,与这个字段对应的引用需要注解为 @JsonBackReference。 @JsonBackReference 注解,通常说明这个字段是关联的一个双向引用字段,这个字段在这个双向引用的角色是 “孩子”。这个字段的值只能是对象(Bean),不能是 集合(Collection),图(Map),数组(Array)和枚举类型(enumeration)。 总结 @JsonManagedReference 和 @JsonBackReference 总是成对出现的 @JsonManagedReference 定义在父级角色 @JsonBackReference 定义在孩子级角色 @JsonBackReference 不能使用任何集合和数组等多的数据结构 有了上面的解释,应该比较容易的理解为了避免双向引用导致无限递归而出现的问题的。 https://www.ossez.com/t/jackson-jsonmanagedreference-jsonbackreference/574
不需要。直接修改环境变量就可以了。 根据使用的操作系统不同,不同的操作系统可能有所不同。 Windows 的话 PATH 看一下 指向的 JDK 是哪个路径。 如果你要CMD 查看的话,你需要关闭 CMD 窗口,然后重新打开。
你可用使用 Guava 的 Longs 进行转换。 例如,你希望将 917525L 转换为二进制数组,可用使用下面的语句。 上面的方法可用直接使用。 同时你需要 import from Guava import com.google.common.primitives.Longs; 上面就可以转换为二进制数组了。 https://www.ossez.com/t/java-long-bytearray/213
lib 管理,Maven 项目使用 POM 管理你的约束,你也可以将你的 Lib 发布到仓库中供其他人使用。 使用版本号,Package 进行管理,极大的方便了 Java 项目。