理解 Spring Boot Security + JWT Token 的简单应用

项目中有用到 Spring Security 来控制 API 的访问权限,但对于配置应用它基本上是照葫芦画瓢。至于为什么要调用方法

SecurityContextHolder.getContext().setAuthentication()

并且能从 HttpServletRequest 中得到 Authentication。还有,只要在 Controller 的方法中添加一个带 @AuthenticationPrincipal 注解的参数

public String sampleApi(@AuthenticationPrincipal DecodedJWT decodedJWT) {...}

之后,decodedJWT 便自动有了值,诸如此类的,此前一概模糊不清。

早先配置 spring-security-config 是通过继承 WebSecurityConfigurerAdapter, 覆盖它的 configure(HttpSecurity http) 来配置访问规则等。在 spring-security-config 5.7.x 开始不建议用 WebSecurityConfigurerAdapter, 而是借由 SecurityFilterChain 来配置 HttpSecurity 中的规则 ,或者通过 WebSecurityCustomizer 完成定制。 阅读全文 >>

RabbitMQ 初体验(安装,概念及应用)

之前工作中用过 JMS 的 IBM MQSeries, 自己试玩过 ActiveMQ, 再就是 Kafka, 再到 AWS 上的 SQS 等消息队列。打算调教一下 Python 的 Celery,它首推用 RabbitMQ 作为它的消息,当然也可选择 Redis 或 AWS 的 SQS,首先感觉有必要体验一下 RabbitMQ。

RabbitMQ 是一个 AMQP(Advanced Message Queuing Protocol) 的开源实现, 相关的实现产品还有 OpenAMQ, StormMQ, Apache Qpid, Red Hat Enterprise MRG, Microsoft Azure Service Bus 等,AMQP 与 JMS 还存在一些交集。

本文不打算介绍太多的 RabbitMQ 的一些概念,主要是体验一下如何安装,怎么发送和接受消息,初次体验就不直接上 Docker 了,用 Docker 根本不知道 RabbitMQ 是个什么东西,所以用一个 Ubuntu 20.04 虚拟机来一步步安装。

先用 Vagrant 准备一个虚拟机,Vagrantfile 文件内容如下 阅读全文 >>

Python async, await 的理解与使用

关于 Python 中 async, await 关键字的一些知识在去年的一篇 探索 Flask 对 asyncio 的支持 有讲到,一直没在实际上用过它们,所以基本上也就忘干净了。随着 Flask 2 加入了 async 的特性,以及 FastAPI 从一开始支持 async, 又觉得有必要重新温习一下 Python 中如何使用 async, await 关键字了。

注:由于 Flask 支持了 async, 号称 async 化 Flask 的  Quart 项目开始变得无足轻重了。

本文主要的学习材料是在 YouTube 上的一个视频 Fear and Awaiting in Async (Screencast), 其中用 Python REPL 以 Live 的形式展示,对 async, await 关键字循序渐进的讲解。

如今不少语言都支持 async, await 关键字,如 C#, JavaScript, Kotlin, Rust 等,还有今天的主角 Python。而 Java 仍然很重视函数返回值的意义,未支持 async, 只能显式的返回 Future/CompletableFuture, 而且自己控制如何在线程池中执行。 阅读全文 >>

Mockito 3.4.0 开始可 Mock 静态方法

Java 单元测试最趁手的 Mock 组件当属 Mockito,虽然它最初是基于继承来实现  Mock 的,所以对私有方法,私有属性,静态方法,final 类,final 方法,构造函数无能为力。于是有时不得不引入 JMockit 或 PowerMockit 来辅助。不过现在的 Mockito 功力有所增强。

首先是 Mockito 2.1.0 开始可以 Mock final 类和 final 方法,要在 classpath 下创建个文件 mockito-extensions/org.mockito.plugins.MockMaker, 内容为 mock-maker-inline。之前写过一篇介绍:Mockto 也能 Mock final 类和 final 方法了,其中也探索了它的实现细节,使用到了 ByteBuddy 修改字节码。

Mockito 3.4.0 通过类似的 mockto-extensions 扩展的方式,实现了对静态方法的 Mock。所有使用到的接口是 org.mockito.MockedStatic,它当前在 Mockito 3.7.7 中还是一个试验性方法 @Incubating,能拿来用就行。 阅读全文 >>

从 Notbook 到 JupyterLab, 再配上代码帮手 Kite

又一月有半未落下一个符号了,越来越喜爱用 Python 来高效的辅助日常工作了。先前在 Shell 下使用 Python 代码,因为 Vim 可以配置 Kite 进行代码的自动完成。很早就知道 Jupyter Notebook, 但觉得它还不够漂亮,又没代码提示,也就一直没理会它,后来看到 Kite 可以支持 JupyterLab, 一启动 JupyterLab 的那一瞬间,果然比 Notebook 高大上了许多。有了 Kite  加持,写代码更是顺畅的多,当然还飞不起来。Notebook  应该是一个更经典的工具,它的一系列插件还得稍稍移植到 JupyterLab 上去才能用。

本文快速体验一下 JupyterLab, 从自身到几个基本插件的安装。本人使用的操作系统是 Mac OS X, 刚开始用 python -m venv jupyterlab-venv 创建的虚拟环境中用 pip 来安装,后来发现不知何时在我的 Python 3.8 的 bin 目录中居然安装有 jupyter 和 jupyter-lab 命令,pip install jupyterlabjupyter-lab --version 和 jupyter lab --version 显示的是不同版本 阅读全文 >>

Vue.js 项目使用 vue-prism-editor 语法高亮与编辑器

记录一下在 Vue.js 项目中使用 vue-prism-editor 进行语法高亮显示代码,并兼具代码编辑功能。JavaScript 中有几个比较典型的语法高亮显示的代码库,例如 SHJS, SyntaxHighlighter, Rainbow,   highlight.js。本博客曾经使用过 SyntaxHighlighter 来显示日志中的示例代码,现今所采用的是基于 PHP 的 Crayon Syntax Highlighter。除了只为了高亮显示代码外,有时候还需处理在线编辑代码,许多年前试用过 CodeMirror, 而今天要上手 Prism.js 也能够支持代码编辑。 

官方 Demo: prism-editor.netlify.com
Codesandbox:  https://codesandbox.io/s/61yrlnlnmn

为了给 Vue.js 项目提供方便,有人专门做了一个 Vue.js 的插件 vue-prism-editor,本文直接使用该插件,而非直接使用 Prism.js。并且项目蓝本用 @vue/cli 4.4.6 的命令

$ vue create vue-prism-editor-demo

创建的,创建过程可参考 Flask 和 Vue.js 开发及整合部署实例创建 Vue 项目一节,此文简单些,就只选择 default (babel, eslint) 默认项来创建 阅读全文 >>

Mockito 的 anyString(), any(Foo.class) 等不能匹配 null 值

使用 Mockito Mock 方法式,一直以为可以用 anyString(), any(Foo.class) 等匹配 null 值,其实不行,null 值必须显式的用 null, 或 eq(null) 来匹配。anyString(), anyInt() 等只能匹配非 null 值,查看它们的返回值实际是 "" 和 0 等, 而更为特别的是 any(Foo.class) 看到的是 null, 仍然不能匹配 null 值。进一步用 Mockito.mockingDetails(mock).printInvocations() 打印出的内容,anyString(), any(Foo.class) 都会显示为 null 值。

说的有点罗嗦,看下面的例子, 被测试类 UserDao,sql 和 sqlArguments 由各自的 setter 方法来控制,默认它们都为 null 阅读全文 >>

转换 Iterator 为 Java 8 的 Stream

Java 中有关抽象的可遍历的对象有 Iterator, Iterable 和 Java 8 的 Stream, Iterable 可简单的用如下代码转换为 Stream

StreamSupport.stream(iterable.spliterator(), false)

再回过头来,为什么要把 Iterator 或 Iterable 转换为 Stream, 因为 Iterator 和 Iterable 只提供有限的遍历操作,如 Iterator 接口的全部四个方法

hasNext()
next()
forEachRemaining(consumer)
remove()

同样 Iterable 也只有 iterator(), forEach(consumer), 和 spliterator() 方法。而 Java 8 的 Stream 就大不一样的,带有大量的链式操作方法,如 filter, map, flatMap, collect 等。

因此如果我们已有一个 Iterator 类型,能够被转换为 Stream 类型的话将会大大简化后续的转换,处理操作。具体的从 Iterator 到 Stream 的转换方式有两种 阅读全文 >>

Python 版的 try-with-resources -- with 上下文管理器

作为一个  Java 为母语的程序员来讲,学习起其他新的语言就难免任何事都与 Java 进行横向对比。Java 7 引入了能省去许多重复代码的 try-with-resources 特性,不用每回 try/finally 来释放资源(不便之处有局部变量必须声明在  try 之前,finally 里还要嵌套 try/catch 来处理异常)。比如下面的  Java 代码

try(InputStream inputStream = new FileInputStream("abc.txt")) {
    System.out.println(inputStream.read());
} catch (Exception ex) {
}

它相应的不使用 try-with-resources 语法的代码就是 阅读全文 >>

Mockito 也能 Mock final 类和 final 方法了

以实际 Java 项目中的单元测试 Mock 框架基本是 Mockito 2 了,因为它有一个十分流畅的 API。Mockito  2也为 JUnit 5 配上了 MockitoExtension, 所以 JUnit 5 下使用 Mockito 2 的关节也打通了。但在我们享受 Mockito 2 便利的同时,与 JMockit 相比局限性就很明显,因为 Mockito 2 是通过创建匿名子类来进行 Mock 的,所以任何子类对父类无法突破的方面它都存在。譬如,final 类, final 方法, 私有方法, 静态方法, 构造函数都是无法通过子类型进行重写的。所以除非特别需要,在 Mockito 2 无法胜任时都求助于 JMockit,JMockit 借助于 javaagent 取得了 JVM 的高控制权才得已为所欲为。

当 Mockito 来到了 2.1.0 版本,它也觉得不能对以上所有的限制置若罔闻, 首先带给我们的突破是它也可以 Mock final 类和 final 方法,虽然仍处于孵化器中,但毕竟是应用在单元测试中,能用就很不错了,只要以后不被拿走就行。这是官方对它的介绍 Mock the unmockable: opt-in mocking of final classes/methods

下面我亲自操作一遍,并给出更全方位的测试样例 阅读全文 >>