Content Table

Gradle Deploy

项目打包后一般可以按照以下几个步骤进行部署:

  1. 选择正确的环境打包: 测试环境、线上环境等
  2. 把 war 包上传到服务器(使用 FTP、scp 等)
  3. 停止 tomcat: <tomcat>/bin/shutdown.sh
  4. 删除服务器上的项目文件: rm -rf <project_path>
  5. 解压 war 包到项目路径下: unzip project.war -d <project_path>
  6. 启动 tomcat: <tomcat>/bin/startup.sh
  7. 删除上传的 war 包
  8. 如果有 N 个服务器,就需要重复 2 到 7 共 N 次

每次部署都要手动重复这么多步骤,效率很低不说,还容易疏忽出错,为了解决这些问题,借助 Gradle 的 deploy 插件,一条命令 gradle deploy 就完成上面的这些事了。

实现 Steps 路径样式

如下图使用多个 步骤 表示一个过程:

这样的组件 Qt 没有提供,需要我们自己实现,可以用下面几种方式实现:

  • 使用 QPainter 绘图:计算每一个步骤的图形(可以使用 QPainterPath)和位置,然后在 QPainterPath 上填充背景和文字

  • QPushButton + QSS Border-Image + 绝对坐标定位:因为 QPushButton 之间有重叠,而不是一个紧挨着一个的排列,所以需要计算每个步骤的坐标进行定位,使用 PS 设计步骤在不同状态时的背景图,需要 6 张图片:

    • 当前步骤:第一个位置的图、中间的图、最后一个位置的图

    • 非当前步骤:第一个位置的图、中间的图、最后一个位置的图

    • 每个图是步骤的完整背景图,例如

      优点:直观

      缺点:需要手动计算坐标

  • QPushButton + QSS Border-Image + QHBoxLayout:使用 Layout 把 QPushButton 一个紧挨着一个的排列,使用 PS 设计步骤在不同状态时的背景图,需要 5 张图片:

    • 当前步骤:当前步骤前一个步骤的图、最后一个位置的图

    • 非当前步骤:第一个位置的图、中间的图、最后一个位置的图

    • 每个图都不是步骤的完整背景图,例如

      优点:能够使用 Layout 进行布局,不需要手动计算坐标

      缺点:不够直观,不过,在步骤之间加一点空隙,估计大家都明白怎么做了:每一个步骤的背景都有一部分在它的前一个步骤上:

Nginx + Tomcat 使用 Https

Nginx 作为前端反向代理或者负载均衡,Tomcat 不需要自己处理 https,https 由 Nginx 处理:

  • 用户首先和 Nginx 建立连接,完成 SSL 握手
  • 而后 Nginx 作为代理以 http 协议将请求转发给 Tomcat 处理
  • Nginx 再把 Tomcat 的输出通过 SSL 加密发回给用户

Tomcat 只是在处理 http 请求而已 (默认监听 8080 端口)。因此,这种情况下不需要配置 Tomcat 的 SSL,只需要配置 Nginx 的 SSL,Tomcat 和 Nginx 需要配置以下几项:

  • Nginx 中启用 https:

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    http {
    include mime.types;
    default_type text/html;
    gzip on;
    gzip_types text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon;
    sendfile on;

    # Tomcat 服务器集群
    upstream app_server {
    server 127.0.0.1:8080 weight=4;
    server 127.0.0.1:8081 weight=2;
    server 127.0.0.1:8082 weight=1;
    }

    server {
    listen 443 ssl; # https 的默认端口是 443
    charset utf-8;
    server_name www.xtuer.com; # host_name of URL

    # 启用 https
    ssl_certificate /Users/Biao/Desktop/cert/server.crt;
    ssl_certificate_key /Users/Biao/Desktop/cert/server.key;

    location / {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 把 https 的协议告知 Tomcat,否则 Tomcat 可能认为是 http 的请求
    proxy_set_header X-Forwarded-Proto $scheme;

    # 请求转发给 Tomcat 集群处理
    proxy_pass http://app_server;
    }
    }
    }

    关键是以下几项:

    • listen port ssl
    • ssl_certificate
    • ssl_certificate_key
    • X-Forwarded-Proto
  • Tomcat 的 server.xml 的 Host 中配置 Valve:

    1
    2
    3
    <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
    <Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" protocolHeaderHttpsValue="https"/>
    </Host>
    • X-Forwarded-Proto 是为了正确地识别实际用户发出的协议是 http 还是 https
    • X-Forwarded-For 是为了获得实际用户的 IP
    • 如果不配置它们,则在 redirect 的时候仍然会使用 http 而不是 https
  • 注意: 当使用非 443 端口,如 9443 时,需要修改 2 个地方:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Nginx: Host 中增加 $server_port
    listen 9443 ssl;
    proxy_set_header Host $host:$server_port;

    Tomcat: 必须配置 httpsServerPort,否则 request.getServerPort() 仍然返回 443
    <Valve className="org.apache.catalina.valves.RemoteIpValve"
    remoteIpHeader="X-Forwarded-For"
    protocolHeader="X-Forwarded-Proto"
    protocolHeaderHttpsValue="https"
    httpsServerPort="9443"
    />

Vue 自定义组件

Vue 提供了自定义组件的功能,可以定义全局组件,也可以定义局部组件:

  • 全局组件: 使用 Vue.component() 来注册
  • 局部组件: 使用 Vue 对象的 components 属性来注册

下面先介绍全局组件的自定义,然后再简要的介绍局部组件的自定义。

QtCreator 中重构 Widget 的名字

QtCreator 中创建的 Qt Designer Form Class 包含三个文件: .h, .cpp, .ui,例如我们创建了一个 Form Class Widget,则包含下面三个文件:Widget.h, Widget.cpp, Widget.ui,其中的类名为 Widget,如果想要把其重命名为 MyWidget,则可以按照下面几步进行:

  • 文件重命名:
    • Widget.h -> MyWidget.h
    • Widget.cpp -> MyWidget.cpp
    • Widget.ui -> MyWidget.ui
  • 修改 MyWidget.ui 中的 objectName 为 MyWidget
  • 重构 MyWidget.h 中的类名:
    • Ui::MyWidget -> Ui::Widget
    • MyWidget -> Widget
  • 修改 MyWidget.h 中 #ifndef 的名字: WIDGET_H -> MYWIDGET_H
  • 修改 MyWidget.cpp 中的 #include "ui_Widget.h" -> #include "ui_MyWidget.h"

签名验证

签名验证

签名验证涉及到客户端(比如一个 Web 应用)和服务器端,每个客户端在服务器上有一个对应的 app_idapp_key,大致步骤如下:

  1. 客户端使用 app_id + app_key + 其他参数 生成签名字符串 sign1

  2. 把 app_id、其他参数sign1 一起发送给服务器 (app_key 不发送)

  3. 服务器接收到请求后,根据参数中的 app_id 查找到对应的 app_key,然后根据签名算法生成签名字符串 sign2

    客户端和服务器端使用同样的签名算法生成签名字符串: app_id + app_key + 其他参数

  4. 服务器端比较参数中的 sign1 和服务器生成的 sign2,如果相等则签名没问题,放行访问,否则签名无效,拒绝访问

自定义随机函数

JavaScript 已经自带了随机数生成函数,为什么我们还需要弄一个随机数的生成工具呢?

例如 Web 的考试系统里,加载试卷后,需要把试卷的题目顺序打乱,如果用 JS 的随机数函数的话,每次打乱的顺序都是不一样的,因为每次生成的随机数序列都不一样。问题出现了,同一个学员刷新试卷后,题目的顺序和上一次的竟然不一样,这不符合实际要求,应该是不同学员的题目顺序不一样,但是同一个学员的题目顺序永远是一样的。这样就不能使用直接使用原生的随机函数了,下面定义一个随机数生成函数,随机数种子是一个字符串,这样就可以用学员的编码来作为随机数种子生成随机数打乱题目的顺序了,因为每次刷新时同一个学员的编码都是一样的,所以生成的随机数序列都相同,就保证了同一个学员的试卷题目顺序一直都是一样的。

Velocity 语法

Velocity 比较接近脚本语言,例如 JS

1
2
3
4
5
6
7
8
9
#if ($foo < 10)
...
#elseif ($foo == 10)
...
#elseif ($foo == 12)
...
#else
...
#end

比较一下 Freemarker

1
2
3
4
5
6
7
8
9
<#if foo < 10> 
...
<#elseif foo == 10>
...
<#elseif foo == 12>
...
<#else>
...
</#if>

使用 Velocity 生成静态页面

Velocity 可以作为 SpringMVC 的 View 使用,也可以用来生成邮件,静态页面等。

Velocity 模版中可以直接调用对象的方法,这点比 Freemarker 好用,if else foreach 等语句也更舒服。

Gradle 依赖

1
2
compile 'org.apache.velocity:velocity:1.7'
compile 'org.apache.velocity:velocity-tools:2.0'

集成 Velocity

JSP 和 Velocity 都用于显示层,但是都有自己的优缺点。

Velocity 比 Freemarker 快,而且语法也更舒服。

Velocity 的优点:
  1. 不能编写 Java 代码,可以实现严格的 MVC 分离,可维护性好
  2. 性能不错,比 JSP 快
  3. 对 JSP 标签支持良好
  4. 内置大量常用函数
  5. 宏定义非常简单(类似 JSP 标签)
  6. 使用表达式语言
  7. 美工和技术的工作分离(例如命名为 .htm 的格式,不需要经过 Server 就能在浏览器里看到效果,JSP 这一点不太方便)
Velocity 的缺点:
  1. 不是官方标准
  2. 用户群体和第三方标签库没有 JSP 多