如何在墙内反代 Gravatar 显示博客头像

生命不息,折腾不止

Gravatar 即全球通用头像 (Globally Recognized Avatar) 服务,用户只要在上面上传了自己的头像,那么在所有支持的网站上发帖时,只要提供与这个头像关联的 Email,就可以显示出自己的 Gravatar 头像。可以说是「一次上传,全网通用」~~

可惜国内的网络环境实在一言难尽,Gravatar 常年都处于无法访问的状态,所以本站一直都是用 v2ex 提供的 CDN 镜像,然而,就在前两周,v2ex 也被墙了,emm…. 因为不想再白嫖其他的国内镜像,因此开始考虑自己动手搭建。这个事情其实挺简单的,网上随便搜索一下就有答案,只要有一台墙外的 VPS,用 nginx 给 Gravatar 做个反向代理就好。

但是,如果你的主机在墙内呢,怎么办?

阅读全文 »

为 Ktorm 框架拓展 PostgreSQL 方言进行 Json 访问

本文转自 https://skyblond.info/archives/751.html

最近从滴滴辞职,为期 5 天的暑假正式开始了,寻思着做一点有意义的事情提升一下自己。遂决定自己写一套专门用于复杂查询的通联日志管理系统,数据库选用了 PostgreSQL,该数据库可以直接对 Json 类型的数据进行高级查询,然而 Ktorm 框架并不支持此功能,因此本文将记述为该框架进行拓展的过程。

阅读全文 »

谈谈 Java 代码的兼容性

最近踩了个坑,事情的经过是这样,我在做一个需求,要在某个实体类中加个字段,这个类的名字是 Banner

但是当我打开这个类的时候,看到的除了字段定义以外还有一大堆使用 idea 生成的 getter/setter 方法。甚至这些 getter/setter 方法占用的代码行数反而更多,严重干扰视线,阅读代码体验极差。

这时我就产生了重构的想法,思路是删掉这些没必要的 getter/setter 方法,改用 lombok 的 @Data 注解代替。因为 lombok 本来在项目中就有使用,所以应该不会有什么问题。改完之后,我测试了我正在做的这个功能,一切正常,代码部署到测试环境之后也运行良好。

但是万万没有想到,问题竟然出现在与这个功能看起来毫不相关的另一个模块。这个模块启动后抛出了一个 NoSuchMethodError

阅读全文 »

Ktorm - 让你的数据库操作更具 Kotlin 风味

在上篇文章中,我们介绍了 Ktorm 的基本使用方法。Ktorm 是一个专注于 Kotlin 的 ORM 框架,它提供的 SQL DSL 和序列 API 可以让我们方便地进行数据库操作。在这篇文章中,我们将学习到更多细节,了解 Ktorm 如何让我们的数据库操作更具 Kotlin 风味。

前文地址:你还在用 MyBatis 吗,Ktorm 了解一下?
Ktorm 官网:https://www.ktorm.org

在开始之前,我们先回顾一下上篇文章中的员工-部门表的例子,这次我们的示例也是基于这两个表。下面是使用 Ktorm 定义的这两个表的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Departments : Table<Nothing>("t_department") {
val id = int("id").primaryKey() // Column<Int>
val name = varchar("name") // Column<String>
val location = varchar("location") // Column<String>
}

object Employees : Table<Nothing>("t_employee") {
val id = int("id").primaryKey()
val name = varchar("name")
val job = varchar("job")
val managerId = int("manager_id")
val hireDate = date("hire_date")
val salary = long("salary")
val departmentId = int("department_id")
}
阅读全文 »

你还在用 MyBatis 吗,Ktorm 了解一下?

自从 Google 宣布 Kotlin 成为 Android 的官方语言,Kotlin 可以说是突然火了一波。其实不仅仅是 Android,在服务端开发的领域,Kotlin 也可以说是优势明显。由于其支持空安全、方法扩展、协程等众多的优良特性,以及与 Java 几乎完美的兼容性,选择 Kotlin 可以说是好处多多。

然而,切换到 Kotlin 之后,你还在用 MyBatis 吗?MyBatis 作为一个 Java 的 SQL 映射框架,虽然在国内使用人数众多,但是也受到了许多吐槽。使用 MyBatis,你必须要忍受在 XML 里写 SQL 这种奇怪的操作,以及在众多 XML 与 Java 接口文件之间跳来跳去的麻烦,以及往 XML 中传递多个参数时的一坨坨 @Param 注解(或者你使用 Map?那就更糟了,连基本的类型校验都没有,参数名也容易写错)。甚至,在与 Kotlin 共存的时候,还会出现一些奇怪的问题,比如: Kotlin 遇到 MyBatis:到底是 Int 的错,还是 data class 的错?

这时,你可能想要一款专属于 Kotlin 的 ORM 框架。它可以充分利用 Kotlin 的各种优良特性,让我们写出更加 Kotlin 的代码。它应该是轻量级的,只需要添加依赖即可直接使用,不需要各种麻烦的配置文件。它的 SQL 最好可以自动生成,不需要像 MyBatis 那样每条 SQL 都自己写,但是也给我们保留精确控制 SQL 的能力,不至于像 Hibernate 那样难以进行 SQL 调优。

如果你真的这么想的话,Ktorm 可能会适合你。Ktorm 是直接基于纯 JDBC 编写的高效简洁的 Kotlin ORM 框架,它提供了强类型而且灵活的 SQL DSL 和方便的序列 API,以减少我们操作数据库的重复劳动。当然,所有的 SQL 都是自动生成的。本文的目的就是对 Ktorm 进行介绍,帮助我们快速上手使用。

阅读全文 »

找到编译器的 bug 是种怎样的体验?

本文来自我的知乎回答:找到编译器的bug是种怎样的体验? - 知乎

emmm…这个问题下面真的是大佬云集,萌新感到好忐忑…

前段时间在使用 Kotlin 开发一个 ORM 框架(广告慎入,Ktorm:专注于 Kotlin 的 ORM 框架),当时我的代码大概是这样的,定义了一个 Foo 接口,在这个接口里面写了个默认实现的 bar() 方法:

1
2
3
4
5
6
7
8
9
10
11
interface Foo {
fun bar() {
val obj = object : Any() { }
println(obj.javaClass.simpleName)
}
}

fun main(args: Array<String>) {
val foo = object : Foo { }
foo.bar()
}

怎么样,看起来是不是稳如狗?然而,这段代码在运行的时候,却喷了我一脸异常:

阅读全文 »

绕过 Java 编译器检查,在任何地方抛出受检异常

这次我要写的内容也是一个黑科技,就是在实际工作中没卵用的那种。秉着实用主义至上的小伙伴们可以绕道,看了这篇文章也不会对您的工作有任何帮助。但是如果您喜欢抱着娱乐的精神钻研一下这些 tricks,我们就开始吧。

Java 异常简介

众所周知,Java 的所有异常都派生自 Throwable 类,在继承结构上,从 Throwable 派生出了 Error 和 Exception 两大类。其中,Error 表示系统级别的严重程序错误,一般由 JVM 抛出,我们也不应该捕获这类异常,用户自定义的异常一般都派生自 Exception 类。

从是否被编译器强制检查一点,异常又可分为受检异常(Checked Exception)和未受检异常(Unchecked Exception)。未受检异常派生自 Error 或者 RuntimeException,表示不可恢复的程序错误,典型例子有 AssertionError、NullPointerException 等,编译器不会强制我们捕获这类异常。受检异常则是除了 Error/RuntimeException 之外,派生自 Throwable 或者 Exception 的其他异常,比如 IOException、SQLException 等。如果一个方法声明自己可能抛出受检异常,那么编译器会强制它的调用者必须使用 try-catch 捕获此异常,或者在自己的方法中加上 throws 声明将异常继续传播给外界。

阅读全文 »

Java Comparable 接口的一个小「坑」 - 关于 compareTo() 和 equals() 的一致性的思考

Comparable 是 Java 中非常常用的一个接口,但是其中也有一些值得深究的细节。

我们以「德州扑克」游戏的业务场景为例进行说明。「德州扑克」是一款风靡世界的扑克游戏,要实现这个游戏,首先要对系统进行建模,我们可能会写出这样的一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public enum PokerSuit {
SPADE, HEART, DIAMOND, CLUB
}

public class PokerCard {
private final int number;
private final PokerSuit suit;

public PokerCard(int number, PokerSuit suit) {
if (number < 1 || number > 13) {
throw new IllegalArgumentException("number");
}
this.number = number;
this.suit = Objects.requireNonNull(suit);
}

public int getNumber() {
return number;
}

public PokerSuit getSuit() {
return suit;
}
}
阅读全文 »

逆天改命,Java 反射的黑科技

一个人的命运啊,当然要靠自我奋斗,但也要考虑到历史的进程。——长者。
众所周知,反射是 Java 的一大利器,它可以做到许多看起来不可思议的事情,但是用得不好也会给我们的系统挖下许多坑。下面就介绍一个反射的黑科技,请充分理解并消化里面的知识,并把这项技术用到实际的项目中去

在开始之前,我们先来念两句诗,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
recitePoems(false);
recitePoems(true);
}

private static void recitePoems(Boolean b) {
if (b) {
System.out.println("苟利国家生死以");
} else {
System.out.println("岂因祸福避趋之");
}
}
阅读全文 »

Java 动态代理机制分析及扩展,第 2 部分

点击查看原文
相信通过阅读“Java 动态代理机制分析和扩展,第 1 部分”,读者已经对 Java 动态代理机制有了一定的了解。本文将在上一篇的基础上,针对 Java 动态代理仅支持接口代理这一局限进行扩展,实现对类的代理。

本文希望将 Java 动态代理机制从接口扩展到类,使得类能够享有与接口类似的动态代理支持。

设计及特点

新扩展的类名为 ProxyEx,将直接继承于 java.lang.reflect.Proxy,也声明了与原 Proxy 类中同名的 public 静态方法,目的是保持与原代理机制在使用方法上的完全一致。
图 1. ProxyEx 类继承图

阅读全文 »