Content Table

Hexo 跳过指定文件的渲染

Hexo 博客中所见文章都是经由渲染的静态网页,而静态网页的样式都直接由 Hexo 的主题控制,所以 Hexo 博客大部分都呈现出一种高度的统一化与规范化。不过 Hexo 提供了跳过渲染功能,使得我们可以直接在博客中放入自定义网页: 在 _config.yml 配置中配置 skip_render:

如果要跳过 source 文件夹下的test.html,可以这样配置:

1
2
skip_render: test.html

注意,千万不要加上个/写成/test.html,这里只能填相对于 source 文件夹的相对路径

如果要忽略 source 下的 test 文件夹下所有文件,可以这样配置:

1
2
skip_render: test/*

如果要忽略 source 下的 test 文件夹下.html文件,可以这样配置:

1
2
skip_render: test/*.html

如果要忽略 source 下的 test 文件夹内所有文件包括子文件夹以及子文件夹内的文件,可以这样配置:

1
2
skip_render: test/**

如果要忽略多个路径的文件或目录,可以这样配置:

1
2
3
skip_render:
- test.html
- test/*

参考:

九宫格绘图

很多时候都会使用图片作为 widget 的背景,如果图片和 widget 一样大的话那就没什么好说的,背景效果和图片的效果看上去一样,可更多的时候我们会面临图片和 widget 不一样大,如果把图片简单的缩放到和 widget 一样大作为背景的话,背景常常会变形、有锯齿等,如下面的背景图大小为 128 x 108,要作为 300 x 200 大小的背景,直接缩放绘制的效果很不好,如若使用接下来将要介绍的九宫格绘图技术来绘制背景的话,效果正是我们期望的:

  • 左边是直接缩放绘制的效果,背景发虚,有锯齿,圆角被放大
  • 右边是九宫格技术绘制的效果,圆角和背景的圆角一样

Spring Security QQ 登陆

Spring Security 中实现 QQ 登陆,可以在 FORM_LOGIN_FILTER 前插入一个 filter 用于拦截 QQ 登陆成功后的回调,进行身份认证。

开发前需要准备一个 QQ 互联账号和修改 hosts,按照下面的说明操作即可。

要点: Spring Security 中身份认证成功的标志很简单,只要用用户信息创建一个 Authentication 对象,保存到 SecurityContextHolder 就可以了。

Spring Security 发现 SecurityContextHolder 中有 Authentication 后,就认为用户已经通过了身份认证,对访问的资源进行权限验证时调用 Authentication.getAuthorities() 获取用户的权限进行验证。

注册 QQ 互联账号

  1. 在开发前,需要在 QQ 互联 注册一个开发者账号: https://connect.qq.com
  2. 然后点击 应用管理: https://connect.qq.com/manage.html
  3. 创建 网站应用,里面有开发需要的 APP IDAPP Key

修改 hosts

例如我们在 QQ 互联中填写的回调 URL 为 http://open.qtdebug.com:8080/oauth/qq/callback,很显然 QQ 服务器是不能访问这个地址的,因为这个地址不存在,为了在 QQ 登陆成功后 QQ 服务器能访问这个地址,需要在系统的 hosts 文件里添加 127.0.0.1 open.qtdebug.com

还有另一种方式是使用如 Ngrok 把本地映射为外网可访问。

Spring Boot Start

Spring Boot 创建入门级 RESTful Web 项目简单到令人发指,下面就来看看怎么用吧(如果想知道 Spring Boot 是啥,搜索即可):

  1. 创建项目的骨架
  2. 添加 RestController
  3. 启动项目: gradle bootRun
  4. 打包项目: gradle build

创建项目的骨架

  1. 访问 http://start.spring.io
  2. 选择 Gradle 项目,Spring Boot 2.x
  3. 填写 Group (项目的包名,例如 com.xtuer) 和 Artifact (可不填)
  4. Search for dependencies 输入 web
  5. 点击 Generate Project,会自动下载项目骨架 demo.zip
  6. 解压,如果不需要里面的 gradlew,删除即可

Spring Security JWT + Token 认证

Spring Security Session + Token 认证 中介绍了 Token 相关的身份验证,但是怎么验证 token 和使用 token 获取用户信息没有进行介绍,可以把 token 存储到 Redis、数据库等,下面介绍另一种 token 实现方法 JWT(Json Web Token),这种 token 不需要存储到服务器,自身就能进行验证。

JWT 中存储了 token 的签名,用户信息,还可以存储 token 的签发时间用于服务器验证 token 的有效期,并且这些信息如果被篡改了的话就会导致 token 失效,JWT 的理论请参考 http://www.jianshu.com/p/576dbf44b2ae

为了在 Spring Security 中使用 JWT,需要修改下面 3 个类:

  • TokenAuthenticationFilter
  • TokenService
  • JwtUtils

Spring Security 权限继承

如下面层级结构的权限:

1
2
3
ROLE_ADMIN > ROLE_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST

A user who is authenticated with ROLE_ADMIN, will behave as if they have all four roles, as well the user will have the authorities ROLE_USER and ROLE_GUEST who is authenticated with ROLE_USER请参考帮助文档

Spring Security 里通过 RoleHierarchyVoter 实现权限继承(只需要配置,不需要写代码)。

注意:

<http> 需要设置 use-expressions 为 false,禁用 SpEL 表达式进行权限判断,因为它为 true 时 Spring Security 使用 WebExpressionConfigAttribute,它的 getAttribute() 总是返回 null,导致 RoleVoter.supports() 总是返回 false,于是权限校验失败,为 false 时使用的是 SecurityConfig,这时就没问题了,可以在 RoleVoter.vote() 中打断点进行验证。

坑爹的是,Spring Security 的帮助文档里没说这个,走了不少弯路。

微信企业号开发

微信企业号主要是为了链接组织和内部员工的,通过提供通讯录、组织新闻公告、活动、投票、调研、论坛 BBS、意见建议墙、招聘、考勤、流程审批、任务管理等一系列功能和服务,提高组织运作效率。微信企业号是微信为企业客户提供的移动服务,旨在提供企业移动应用入口。

微信企业号,有以下一些特点:

  • 关注更安全

    只有企业通讯录的成员才能关注企业号,分级管理员、保密消息等各种特性确保企业内部信息的安全

  • 应用可配置

    企业可自行在企业号中配置多个服务号,可以连接不同的企业应用系统,只有授权的企业成员才能使用相应的服务号

  • 消息无限制

    发送消息无限制,并提供完善的管理接口及微信原生能力,以适应企业复杂、个性化的应用场景

  • 使用更便捷

    企业号在微信中有统一的消息入口,用户可以更方便地管理企业号消息。微信通讯录也可以直接访问企业号中的应用

Spring Security Session + Token 认证

前面通过表单进行登陆,会为用户创建一个 session 保存在服务器端,session id 保存在 cookie 中,每次访问服务器的时候服务器端从 cookie 中读取 session id 然后找到用户的 session,就能知道当前用户的信息。但是对于移动端来说,传递 cookie 不是很方便,一般都会使用 token 来进行验证。

Token 就是一个字符串(可以使用 uuid),验证时使用的 token 可以理解为和 session id 的功能差不多:

  1. 用户申请 token 时,可以把 token 作为 key,用户信息的对象作为 value 保存到 Redis 中,把 token 返回给移动端
  2. 移动端保存 token,有很多种方式,例如保存到文件中,sqlite 里都可以
  3. 每次访问的时候把 token 放到请求的 header 中
  4. 服务器端从 header 中读取 token,然后用 token 作为 key 去 Redis 中去读用户数据
  5. 如果读取到的用户数据有效,则说明用户是合法的,认证通过,继续访问,否则返回错误,终止请求

使用纯 token 验证,不支持 session,这样的应用一般都是用来提供纯数据服务(应用中没有网页,很多微服务就是这样的),以下叫 DSA(Data Service Application),但是数据也是需要后台功能来管理的,大多都会使用 Web 应用,叫 DMA(Data Management Application),Web 应用需要使用 session,也就是说 DSA 和 DMA 是独立的 2 个应用,不能共存,因为 DSA 中不支持 session,而 DMA 中需要 session。这种设计的好处是 DSA 很轻量级,只关心数据服务,能够降低开发的复杂度,还有其它比如每个服务都很简单,只关注于一个业务功能,每个微服务可以由不同的团队独立开发,微服务是松散耦合的等等。但是也有缺点,比如有可能对资源的访问需要重复实现,例如一个电子图书馆程序,读取图书信息的 API /api/books/{bookId} 在 DSA 中需要实现,在 DMA 中也要提供实现,因为 DMA 中也需要读取图书信息进行管理,就算用分布式服务使用 dubbo 负责服务治理,由 DMA 提供访问数据的逻辑,但是 DSA 和 DMA 里都至少也要各自有个 Controller 来处理这个 URL 吧。

本文的目的,是要实现一个 Web 应用即支持 session,同时又能支持使用 token 进行身份验证时不生成 session:

  • 浏览器访问 /api/books/{bookId} 时,从 cookie 中读取 session id 找到对应的 session,获取当前用户,如果没有登陆则跳转到登陆页面进行登陆,登陆成功会创建 session
  • 移动端访问 /api/books/{bookId} 时,从 header 中读取 token 找到对应的用户,如果没有 token 或者 token 过期、用户信息无效则返回错误提示未登陆认证(token 可以事先请求保存起来),整个过程不会产生 session

Qt 程序简单打包

程序在开发工具例如 Qt Creator 中运行没有问题,不少同学开发好后就直接把 xxx.exe 给用户使用,用户双击 xxx.exe 后提示错误,打开程序失败。很是奇怪: 程序在我的电脑里打开好好的,为什么到其他电脑上就不行了呢,是不是他的电脑有问题?不知道此同学有没有在自己电脑上双击过这个程序!

例如双击下面的 Gui.exe,提示找不到 libgcc_s_dw2-1.dll,那是因为 Qt 的程序运行的时候除了需要可执行程序本身外,还需要依赖一些其他的 dll,需要把这些 dll 一起打包给用户才行:

Qt 程序打包一般有 2 种方式,纯手动打包和半自动打包,下面以 Windows 中打包 Qt 程序 Gui.exe 为例进行介绍,环境如下:

  • 安装 MinGW 的 Qt 5.9.1 到 F
  • DLL 目录: F:\Qt\Qt5.9.1\5.9.1\mingw53_32\bin
  • Qt 的插件目录: F:\Qt\Qt5.9.1\5.9.1\mingw53_32\plugins

GitBook 入门

GitBook 是一个使用 Markdown 文件,用来写书、说明文档等的工具,它的官网已经有 5 万多本使用 GitBook 写的书了,现在不少公司都开始用 GitBook 来写项目文档、使用手册等。下面就简要的介绍怎么使用 GitBook,首先需要安装下面这些软件:

  1. 安装 Git
  2. 安装 Nodejs
  3. 安装 GitBook: npm install gitbook -g
  4. 安装 GitBook-Cli: npm install gitbook-cli -g

本地搭建 GitBook

本地搭建 GitBook 的好处是我们可以自己管理文件的存储,例如可以放到公司的 Git 私服上:

  1. 创建目录例如 Pandora 用于存放书的文件,进入目录

  2. 创建文件 README.md 和 SUMMARY.md,它们是 GitBook 最重要的 2 个文件,README.md 对书进行介绍,在 SUMMARY.md 中描述书的目录结构,其内容可参考如下:

    README.md:

    1
    本书用于介绍 Pandora 项目的使用说明

    SUMMARY.md:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Summary

    * [简介](README.md)
    * [第一章](chapter1/README.md)
    * [第一节](chapter1/section1.md)
    * [第二节](chapter1/section2.md)
    * [第二章](chapter2/README.md)
    * [第一节](chapter2/section1.md)
    * [第二节](chapter2/section2.md)
    * [结束](end/README.md)
  3. 执行 gitbook init:

    会自动创建 SUMMARY.md 中描述的目录结构对应的文件夹和文件,每次执行这个命令都会创建还没有还不存在的文件和文件夹,但是不会影响已经创建的,所以不用担心多次执行 gitbook init 导致数据丢失

  4. 编辑书的 Markdown 文件,例如 section1.md 等

  5. 安装插件 gitbook install

  6. 执行 gitbook serve,在浏览器里访问 http://localhost:4000 就可以看到上面写的书了,以后常用的也是这个命令,当文件变化后可以在网页中及时看到新的变化

    Bug: Windows 中 gitbook serve 运行后,当文件发生变化时不是自动更新网页而是退出,可以使用下面的脚本来运行 gitbook serve 解决这个问题:

    1
    2
    3
    4
    @Echo off
    :Start
    call gitbook serve
    goto Start

    把上面的文件保存为 gs.bat 放到 GitBook 目录中,运行 gs.bat 就可以了。