Content Table

HTML5 播放器 Video.js

Video.js 是一个简洁、漂亮的 HTML5 播放器,支持字幕,还可支持 Flash(不支持 HTML5 时自动切换到 Flash),使用很简单,也能自定义插件:

Video.js is a JavaScript and CSS library that makes it easier to work with and build on HTML5 video. This is also known as an HTML5 Video Player. Video.js provides a common controls skin built in HTML/CSS, fixes cross-browser inconsistencies, adds additional features like fullscreen and subtitles, manages the fallback to Flash or other playback technologies when HTML5 video isn’t supported, and also provides a consistent JavaScript API for interacting with the video.

事件的坐标

JS 的事件有几个重要的坐标:

  • (offsetX, offsetY): 事件触发点在事件源元素的坐标系统中的坐标(相对于元素的左上角,左上角坐标为 (0, 0))
  • (pageX, pageY): 事件触发点相对于整个页面左上角的坐标,包括了滚动条隐藏的部分
  • (clientX, clientY): 事件触发点相对于页面可视部分(客户区)左上角的坐标,不包括滚动条隐藏的部分
  • (screenX, screenY): 事件触发点相对于屏幕左上角的坐标

限制同一个账号的登陆用户

有时希望限制同一个账号同时只能有 1 个用户登陆,通常为后一次登录将使前一次登录失效。Spring Security 的 session-management为我们提供了这种限制:

  1. 在 web.xml 中定义监听器 HttpSessionEventPublisher

    1
    2
    3
    <listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>
  2. 通过 concurrency-control 来限制账号登陆数

    1
    2
    3
    4
    5
    6
    <http auto-config="true">
    ...
    <session-management>
    <concurrency-control max-sessions="1"/>
    </session-management>
    </http>

测试 ThreadLocal

每个 Thread 都有一个 ThreadLocalMap 的对象,存储时以 ThreadLocal 变量为 key,set() 的参数作为 value,这样同一个 ThreadLocal 变量在不同的线程中就可以存储不同的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ThreadLocalTest {
private static ThreadLocal<String> foo = new ThreadLocal<>();

public static void main(String[] args) throws Exception {
new Thread(() -> {
await(300);
System.out.println(Thread.currentThread().getName() + ": " + foo.get()); // [2] 输出: Thread-1: null
foo.set("1"); // [3]

await(1000);
System.out.println(Thread.currentThread().getName() + ": " + foo.get()); // [5] 输出: Thread-1: 1
}, "Thread-1").start();

new Thread(() -> {
foo.set("2"); // [1]

await(600);
System.out.println(Thread.currentThread().getName() + ": " + foo.get()); //[4] 输出: Thread-2: 2
}, "Thread-2").start();
}

public static void await(long timeout) {
try { Thread.sleep(timeout); } catch (InterruptedException e) {}
}
}

输出:

1
2
3
Thread-1: null
Thread-2: 2
Thread-1: 1

ThreadLocal 的变量一般定义为 private static 的。

截取 Canvas 绘制的图形

使用 canvas 绘图时,很多时候在 canvas 上绘制的图像只占 canvas 的一部分,如果把整个 canvas 的图像发送到服务器就比较浪费空间和带宽,所以保存真正绘制的图像部分是有必要的。

下图的上部分为一个的 canvas,绘制的图像大概只占它的四分之一,我们的目的是把 canvas 中多余的部分去掉,得到真正绘制的图像,如下部分显示:

MySQL 命令行客户端 MyCLI

MyCLI 是一个 MySQL 的命令行客户端,可以实现自动补全(auto-completion)和语法高亮,具体特性如下:

  • 智能补全
  • SQL 语法高亮显示
  • 自动完成输入 SQL关键字以及数据库列表
  • SELECT * FROM <tab> 只显示表名
  • SELECT * FROM users WHERE <tab> 只显示列名
  • 支持 tab 自动补全
  • MySQL 的输出会通过 less 命令进行格式化输出
  • 支持 ssl 连接

Qt 调用摄像头

可以使用 OpenCV 来操作摄像头,不过 Qt5 已经自带了调用系统摄像头的功能,在 .pro 文件中增加下面的模块:

1
QT += multimedia multimediawidgets

主要是使用下面 3 个类,使用起来很方便:

  • QCamera
  • QCameraViewfinder
  • QCameraImageCapture

下面代码的效果为

Thymeleaf 语法

Thymeleaf 使用 HTML 元素的属性获取 model 中的数据,属性的前缀是 th:,例如 th:text, th:src

变量访问

1
2
3
4
5
6
7
<!-- 使用属性的方式访问变量 -->
<span th:text="${name}">Thymeleaf 解析后会被覆盖</span>
<span th:text="|Welcome ${name}|">Thymeleaf 解析后会被覆盖</span>
<span th:text="'Welcome ' + ${name}">Thymeleaf 解析后会被覆盖</span>

<!-- 非属性的方式访问变量 -->
<span>[[${name}]]</span>

字符串拼接时 |...| 的方式更简洁,但是里面不能包含表达式,第三种方式功能强大,可以包含表达式。

变量访问也可以使用级联的方式: ${user.name}

null 处理

表达式 ${foo}? 当 foo 为 null 时返回 false;级联调用时变量访问前先用 ? 进行判断可以减少一个一个的条件判断

1
2
<div th:text="${foo}?'Alt'"></div>
<div th:text="${foo?.bar?.fix}"></div>

使用 URL

1
<a th:href="@{/login}" th:if="${session.user == null}">Login</a>

使用 th:href="@{/uri}" 引入 URL,/ 开头时会在 URI 前面加上项目的 context path

Thymeleaf 集成

有了 Freemarker,Velocity 等模版后,为什么要选择 Thymeleaf?

  • Freemarker 的模版还是有一些非 HTML 的标签在里面,对于前端来说需要学习相关语法
  • Velocity 虽然也很好,但是已经很久不更新了,Spring 5 已经官方宣布不支持 Velocity 了
  • Thymeleaf 的语法就是 HTML 的语法,动态内容部分使用 HTML 的属性来实现,属性部分不会影响 HTML 的设计,前后端可以很好的分离

软件开发流程

第一步: 我们要确定一个可行的设计方案: 第二步: 我们要开始把框架搭好 第三步: 我们开始一个模块一个模块的完成
第四步: 可以拿去给测试们看了(白盒黑盒都有) 第五步: 产品经过测试通过可以拿去给安全组检查了 最后: 我们的产品就可以上线了

I make things.