从今年4月26日起,美国永久居民/绿卡持有人进入加拿大不再需要事先申请eTA。 只需要持护照以及绿卡即可通过所有交通方式入境加拿大。 如果你曾经申请过 eTA 的话,你将会收到下面的电子邮件。 上面的电子邮件会通知所有申请过 eTA 的人。 https://www.usreio.com/t/topic/216
从今年4月26日起,美国永久居民/绿卡持有人进入加拿大不再需要事先申请eTA。 只需要持护照以及绿卡即可通过所有交通方式入境加拿大。 如果你曾经申请过 eTA 的话,你将会收到下面的电子邮件。 上面的电子邮件会通知所有申请过 eTA 的人。 https://www.usreio.com/t/topic/216
虽然 Apache 的 httpd 也可以做反向代理。 但是在效率和配置上确实不如 nginx,因此我们也将我们的反向代理服务换成了 nginx。 在选择版本的时候遇到了:到底是选择 Nginx 还是 Nginx Plus 的问题。 简单来说就是: Nginx Plus 相当于付费版本的 Nginx。 提供了更多的功能,针对企业需要的一些服务进行了优化。 有关功能的比较页面,请参考: Compare Models - NGINX 上面的内容。 结论 对于一般的网站,一天也就几千个 IP 的这种,用不用 Plus 都差不多。 对于复杂网站和自己的网站或者 API 已经有比较明显的性能问题的话,还是可以考虑使用官方 Plus 提供的相关服务的。 https://www.ossez.com/t/nginx-nginx-plus/13950
我们都知道,如果希望将 http 的访问自动切换到 https ,其实有多种方法可以去做。 比如说在 DNS 服务器上直接配置。 主要目的就是让网站只支持 https 的方法。 Nginx 的配置方法 在 Nginx 的虚拟主机配置文件中,只需要下面的 2 句话就可以了。 server { listen 80; server_name src.ossez.com; return 301 https://$host$request_uri; } 如上图的几句话就能够完成 http 到 https 的重定向了。 Listen 80: 这个定义的是将所有的 HTTP 80 端口的流量进行转换 Server_name _;:这个将会是针对所有的主机名,你也可以指定特定的主机名 Return 301::这个告诉浏览器或者搜索引擎这个重定向是永久的重定向。 https://$host$request_uri: 这个参数配置的是重定向的的目标地址,如果你只是希望换行协议的话,就直接使用上面的配置就行。 https://www.ossez.com/t/nginx-http-https/13949
如果你的 IntelliJ IDEA 在调试的时候越来越慢,那么时候需要增加 IntelliJ IDEA 使用的内存了。 通过 Help | Edit Custom VM Options 路径来打开 VM 的选项。 IJ 将会使用自己的编辑器打开 .vmoptions 文件。 在这个文件中,你需要调整 -Xmx 参数,然后保存重启就可以了。 正常来说 IntelliJ IDEA 应该需要分配至少 4G 的内存。 如果你配置的参数不够的话,那么就增加这个内存配置。 https://www.ossez.com/t/intellij-idea/13947
Gitea 安装成功后,我们希望在部署 Gitea 网站上使用访问跟踪代码,或者其他的一些 JS 脚本的话,这个只能通过自定义模板来实现。 配置路径 首先需要访问 Gitea 的站点管理界面,然后找到 Custom File Root Path 配置属性。 然后的路径就是你需要设置模板的路径,然后在这个路径下面新建 2 个文件夹 templates/custom。 所以完整的路径为: /var/lib/gitea/custom/templates/custom 文件 创建一个 vi header.tmpl 一个文件,然后将需要使用的 JS 跟踪代码放置到这个文件中。 重启 然后重启 Gitea 服务就可以完成针对所有页面的跟踪代码插入了。 校验安装 在完成上面的步骤后,单击右键查看网站源代码。 如果能够看到插入的源代码,那就说明配置已经成功了。 https://www.ossez.com/t/gitea/13944
概述 在这篇文章中,我们对 Java 如何逆向遍历一个 List 进行了一些简单的描述。 主要的思路就是从正向遍历使用的 i++ 变成 i– 如果使用了迭代器 Iterator 的话,可以使用迭代器的逆向迭代 你还可以直接对 List 进行逆向 Java 中的迭代器 Java Iterator 是在 Java Collections 框架中的一个接口:Iterator (Java SE 11 & JDK 11 ) 在 Java 的 Collections 框架中,允许使用 Iterator 来对 List 中的元素进行遍历。 Iterator 是在 Java 1.2 的版本中推出的,用于替代 JDK 中的 Enumeration。 当然在当前的 JDK 中,你还是能够看到 Enumeration 的影子的。 使用原生 Java 进行逆向迭代 使用 Loop 这种就是最简单的思路的,将正向遍历使用的 i++ 变成 i–。 因为我们使用 i 来表示 List 中元素的下标,如果将 i 的查找方式从前往后变成从后往前,就能够完成 List 的逆向遍历了。 for (int i = list.size(); i-- > 0; ) { System.out.println(list.get(i)); } ListIterator 迭代器 迭代器 中还有一个 ListIterator 迭代器,在这个 ListIterator 迭代器中,如果你为迭代器提供了 List 的长度的话,这个 ListIterator 迭代器将会将 List 的指针指向到 List 最后的一个元素。 ListIterator listIterator = list.listIterator(list.size()); 然后使用 ListIterator 提供的 hasPrevious 方法,从后往前进行迭代。 while (listIterator.hasPrevious()) { System.out.println(listIterator.previous()); } Collections.reverse() 方法 Collections 是 JDK 提供的一个类,在这个类中,有一个静态 reverse 方法。 使用这个方法将会对你提供的 List 进行逆向排序。 Collections.reverse(list); 对重新排序后的 List,你可以使用正常的迭代器从前往后进行迭代查找。 for (String item : list) { System.out.println(item); } 需要注意的是,这个方法将会对输入的 List 顺序进行修改,在很多时候,这个可能是你在编程时候并不希望出现的情况。 many cases. 使用 Apache 的 ReverseListIterator Apache Commons Collections 工具类中,提供了 ReverseListIterator 类,使用这个类,将会返回逆向 List 的迭代器。 这个方法只会返回逆向迭代器,并不会对输入的 List 进行修改,因此你不需要担心原始输入 List 中元素进行改变的情况。 在使用 Apache Collections 工具类之前,你需要在你的 pom 文件中添加下面的内容: <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.1</version> </dependency> 你可以通过在 ReverseListIterator 构造方法中,传入一个原始的 List,然后获得 ReverseListIterator 的迭代器实例。 ReverseListIterator reverseListIterator = new ReverseListIterator(list); 在获得这个迭代器实例后,就可以使用正常的迭代方法对元素进行遍历和输出了: while (reverseListIterator.hasNext()) { System.out.println(reverseListIterator.next()); } 使用 Guava’s 的 Lists.reverse() 你还可以简单的使用 Google 提供的 Guava 库中的静态 reverse() 方法,这个方法将会返回一个输入 List 的逆向视图。 使用最新的 Guava 依赖: <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency> 然后对原始的 List 进行逆向视图,使用下面的方法将会返回一个逆向的 List 视图。 List<String> reversedList = Lists.reverse(list); 返回后的逆向视图,将可以使用迭代器进行迭代后遍历: for (String item : reversedList) { System.out.println(item); } 这个方法将会返回一个新逆向后的 List,原始 List 的顺序是不会改变的。 结论 在本篇文章中,我们对如何将一个 List 进行逆向进行了一些说明和演示。 将一个原始 List 逆向输出的方法比较简单,通常使用上面 3 个思路就可以完成逆向元素的输出了。 https://www.ossez.com/t/java-list/13943
概述 本文章主要为了帮助你了解如何在 Java 的 List 中快速清除掉重复的元素。 我们将会使用下面的 3 种方法来进行演示: 纯 Java Guava Java 8 Lambda 表达式 在 Java 中删除 List 中重复元素的主要思路就是将 List 转换为 Set。 因为 Set 中是不允许重复元素的,那这样就可以完成重复元素的删除了。 使用纯 Java 来删除 List 中的重复元素 我们可以使用 Java 的标准 集合(Collections)来完成操作。 List 和 Set 都是属于 集合(Collections)中的一种。 @Test public void givenListContainsDuplicates_whenRemovingDuplicatesWithPlainJava_thenCorrect() { final List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); final List<Integer> listWithoutDuplicates = new ArrayList<>(new HashSet<>(listWithDuplicates)); assertThat(listWithoutDuplicates, hasSize(5)); assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2)); } 考察上面的代码,上面的代码我们使用了 HashSet 来包装的实现,并且重新返回了 ArrayList。 同时我们注意到,上面的代码会保持需要处理的 List 中的内容不变。 有关顺序的问题,因为我们知道 HashSet 中的元素是无序的,正是因为这个特性,那么我们转换成功后的 List 数据有可能和输入的 List 数据的顺序不一致。 因为无序的关系,List 中的 Hash 值可能在重新计算后不一样。 如果我们希望将 List 中重复数据删除后的 List 数据和原始输入 List 数据的排序一致的话,我们可以使用 LinkedHashSet 来替代 HashSet 。 请考察下面的代码: @Test public void givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithPlainJava_thenCorrect() { final List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); final List<Integer> listWithoutDuplicates = new ArrayList<>(new LinkedHashSet<>(listWithDuplicates)); assertThat(listWithoutDuplicates, hasSize(5)); assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2)); } 上面的代码在将重复删除后还是会保持顺序不变的。 使用 Guava 删除重复元素 我们可以使用 Guava 完成上面一样的操作: @Test public void givenListContainsDuplicates_whenRemovingDuplicatesWithGuava_thenCorrect() { final List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); final List<Integer> listWithoutDuplicates = Lists.newArrayList(Sets.newHashSet(listWithDuplicates)); assertThat(listWithoutDuplicates, hasSize(5)); assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2)); } 上面我们使用的是 Guava 的代码。 在这个代码中我们使用了 Sets,Sets 是 Guava 使用的一个类,然后用这个类的 newHashSet 来实现包装。 同样的,如果希望顺序保持不变的话,你需要使用 LinkedHashSet 的实现才可以。 @Test public void givenListContainsDuplicates_whenRemovingDuplicatesPreservingOrderWithGuava_thenCorrect() { final List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); final List<Integer> listWithoutDuplicates = Lists.newArrayList(Sets.newLinkedHashSet(listWithDuplicates)); assertThat(listWithoutDuplicates, hasSize(5)); assertThat(listWithoutDuplicates, containsInRelativeOrder(5, 0, 3, 1, 2)); } 上面的代码将会保持清理后的 List 中元素的顺序不变。 使用 Java 8 Lambdas 表达式 现在,我们来开始使用 Java 8 Lambdas 表达式的实现方式。 在这个实现中,我们使用 Stream API 的 distinct() 方法,这个方法将会返回一个 stream ,这个 stream 将会 distinct 元素。 另外,针对这种删除方式的处理中的元素是稳定的,意思是在删除重复的时候元素的排序是按照这个元素第一次出现的位置来保持顺序的。 @Test public void givenListContainsDuplicates_whenRemovingDuplicatesWithJava8_thenCorrect() { final List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); final List<Integer> listWithoutDuplicates =…
概述 本文章主要是为了展示如何从一个 List 列表中删除所有的 null 元素。 在本文中,我们使用了下面的几个实现: 纯 Java Guava Apache Commons Collections Java 8 提供的 lambda 表达式 使用纯 Java 来将 List 中的 null 元素删除 Java 中的 Collections 框架提供了一个简单的解决方案: 基于使用 while 循环将 List 列表中的所有空元素进行删除。 @Test public void givenListContainsNulls_whenRemovingNullsWithPlainJava_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, null); while (list.remove(null)); assertThat(list, hasSize(1)); } 可选的,我们可以使用一个更加简单的方法,使用 list 中使用 removeAll 的方法来将 null 删除。 @Test public void givenListContainsNulls_whenRemovingNullsWithPlainJavaAlternative_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, null); list.removeAll(Collections.singleton(null)); assertThat(list, hasSize(1)); } 需要注意的是,上面 2 个方法将会对输入的 List 进行修改。 在删除后得到的 list 是修改后的list 使用 Guava 我们还可以使用 Guava 的方法来进行 null 的查询和处理,这个需要通过 Java 的 predicates。 @Test public void givenListContainsNulls_whenRemovingNullsWithGuavaV1_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, null); Iterables.removeIf(list, Predicates.isNull()); assertThat(list, hasSize(1)); } 如上面使用的代码,首先需要对 List 进行遍历,Iterables。List 对 Guava 来说是 Iterables。 然后使用 Predicates.isNull() 来进行判读。 如果为 NULL 就删除。 如果你不希望对输入的 List 进行修改的话,你可以使用 Guava 提供的 Iterables.filter 方法来进行遍历和处理。 如下面的代码,只需要将 removeIf 换成 filter 就可以了。 @Test final List<Integer> list = Lists.newArrayList(null, 1, null, 2, 3); final List<Integer> listWithoutNulls = Lists.newArrayList(Iterables.filter(list, Predicates.notNull())); assertThat(listWithoutNulls, hasSize(3)); } 使用 Apache Commons Collections Apache Commons Collections 的使用和 Guava 的使用是类似的。 虽然 Apache Commons Collections 使用了 filter 方法,但是需要注意的,上面的方法会对输入的 List 进行修改。 @Test public void givenListContainsNulls_whenRemovingNullsWithCommonsCollections_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, 2, null, 3, null); CollectionUtils.filter(list, PredicateUtils.notNullPredicate()); assertThat(list, hasSize(3)); } Java 8 Lambdas 表达式 Java 8 提供了 Lambdas 表达式来对 null 进行处理。 这个处理可以是并行的,也可以是序列进行的。 请查看下面的代码: @Test public void givenListContainsNulls_whenFilteringParallel_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, 2, null, 3, null); final List<Integer> listWithoutNulls = list.parallelStream().filter(Objects::nonNull).collect(Collectors.toList()); assertThat(listWithoutNulls, hasSize(3)); } @Test public void givenListContainsNulls_whenFilteringSerial_thenCorrect() { final List<Integer> list = Lists.newArrayList(null, 1, 2, null, 3, null); final List<Integer> listWithoutNulls = list.stream().filter(Objects::nonNull).collect(Collectors.toList()); assertThat(listWithoutNulls, hasSize(3)); } @Test public void givenListContainsNulls_whenRemovingNullsWithRemoveIf_thenCorrect() { final List<Integer> listWithoutNulls =…
Gitea 是一款使用 Golang 编写的可自运营的代码管理工具。 在这个领域,名气最响的应该是 Gitlab。 但实际使用中Gitlab也有点问题,首先就是资源占用。Gitlab 是使用 ruby 编写的,好几年之前刚出来的时候,一台1G内存的虚拟主机连安装运行都做不到,着实震惊。 时至今日都已经发展到了以docker镜 像分发,gitlab 仍旧会有体积和运行时资源占用的问题。另一点就是功能,对于一般标准团队来说,gitlab的功能太过于丰富,这是往好的地方说,往坏的地方说就是它包含了太多不需要的东西,而这些东西还占用磁盘和运行时资源。 同时 Gitlab 的许可证政策对新的用户也不是非常友好,主要在于与其他平台的同步上面。 例如有一个下面的场景:你将代码提交到自己的服务器上后,如果希望能够自动同步到其他的平台上,比如 GitHub 或者从其他平台上镜像回来,Gitlab 的社区版本是做不到的。 你需要使用企业版本,企业办法的收费是一个用户 5 美元,就算用户不再提交代码了,或者你的员工已经离职了,这个许可证也没有办法收回。 于是着手查看开源的可选方案,很快就找到了golang 研发的gitea。 使用golang研发的软件分发都很容易,体积小,安装使用简单,运行时占用资源少。 且gitea的功能很完备。 Gitea 和 Gogs 的关系 Gitea 其实是 Gogs 的一个分支。 这 2 个都有国人的参与,只是 Gogs 可能开发理念和 Gitea 有所不同,感觉社区上面的参与度不高。 同时 Gogs 更新速度较慢,因此可能选择 Gitea 会多一些。 我们也选择使用了 Gitea 。 Gitea 与其它 Git 托管工具的横向对比 这里列出了 Gitea 与其它一些 Git 托管工具之间的异同,以便确认 Gitea 是否能够满足您的需求。 请注意,此列表中的某些表项可能已经过时,因为我们并没有定期检查其它产品的功能是否有所更改。 使用界面 使用界面的情况如下: 你可以直接对你的代码库进行提交。 https://www.ossez.com/t/gitea/13938
Postman 删除工作空间的地方比较隐蔽。 在你打开工作空间后,选择工作空间的设置。 在后续的页面中,将会提示你是否选择删除这个工作空间。 在随后的页面中,提示你输入工作空间的名字,然后单击确定删除即可。 https://www.ossez.com/t/postman/13936