作者归档:Shelwee

Processing 播放透明通道视频

1.前言

Processing 是一种基于 Java 且简化了语法的编程语言,拥有丰富的第三方库,开发者也能非常容易的扩展开发出满足自己独特需求的库。因此在一些交互场景项目中,Processing 通常是我首选的工具。

2.需求

实际项目中,往往需要加入一些效果好的动效。

比如在原来的背景上,加入一个酷炫的动画。通常可以使用 gif 图来解决,但有时 gif 图会出现锯齿,效果不理想,又或者需要加入声音,那么就只能采用带透明通道的视频来解决了。

假设现在的需求如下:在原来的视频之上叠加一个类似摄像机在录制的一个动画,如下图:

3.分析

正常情况下,两个相同分辨率的视频叠加处理如下:

import processing.video.*;

Movie v1, v2;

void setup() {
  size(640, 480);
  v1 = new Movie(this, "1.mov");
  v1.loop();
  v2 = new Movie(this, "2.mov");
  v2.loop();
}

void draw() {
  background(255);
  image(v1, 0, 0, width, height);
  image(v2, 0, 0, width, height);
}

void movieEvent(Movie m) {
  m.read();
}

但是这样 v2 会直接把 v1 覆盖掉,透明通道并没有生效。效果如下:

正确处理透明通道代码如下:

import processing.video.*;

Movie v1, v2;

void setup() {
  size(640, 480, P2D);
  //如果需要全屏的话, 把 size(640, 480, P2D) 换成 fullScreen(P2D) 即可
  //fullScreen(P2D);
  v1 = new Movie(this, "1.mov");
  v1.loop();
  v2 = new Movie(this, "2.mov");
  v2.loop();
}

void draw() {
  background(255);
  image(v1, 0, 0, width, height);
  image(v2, 0, 0, width, height);
}

void movieEvent(Movie m) {
  m.read();
}

相信你已经看出来了,关键就在于有没有 P2D,但实际上如果把 P2D 改成 P3D 也是可以的。而缺省值则代表 JAVA2D,这个是不支持透明通道视频的。

附:

size(width, height, renderer)
fullScreen(renderer)

Parameters
renderer	String: the renderer to use, e.g. P2D, P3D, JAVA2D (default)

Tomcat 多实例部署

1.前言

最近遇到一个 Tomcat 部署的问题:多个项目均部署在一个 Tomcat 实例上,也就是说一台服务器上只运行一个 Tomcat,而这个 Tomcat 上部署着多个项目,这就意味着只要其中一个项目重新部署需要重启 Tomcat,就会导致其他所有项目也会出现暂时无法访问的状态。

2.准备

  • 假设已下载 Apche Tomcat 压缩包,并且已经解压到 D 盘,路径为:D:\apache-tomcat。
  • 假设有两个 Web 项目,分别是 project1、project2。

3.配置

1.在 D:\apache-tomcat 下新建 project1、project2 目录(也可以是其他任意目录)。

2.将 D:\apache-tomcat 下的 conf、logs、temp、webapps、work 目录移动到 project1、project2 这两个目录, D:\apache-tomcat 只保留 bin、lib 这两个目录。

3.在两个项目的根目录下创建启动批处理脚本 startup.bat

@echo off

SET CATALINA_BASE=%CD%
SET CATALINA_HOME=D:\apache-tomcat

%CATALINA_HOME%\bin\catalina.bat start

4.在两个项目的根目录下创建服务批处理脚本 service.bat(非必须。将项目的 tomcat 启动程序注册为 windows 服务,桌面上就不会产生一个命令行窗口)

@echo off
SET CATALINA_BASE=%CD%
SET CATALINA_HOME=D:\apache-tomcat

if "%1%" == "install" goto gotInstall
if "%1%" == "remove" goto gotRemove
:gotInstall
%CATALINA_HOME%\bin\service.bat install "%2%"
:gotRemove
%CATALINA_HOME%\bin\service.bat remove "%2%"

5.修改端口:将 D:\apache-tomcat\project1\conf\server.xml 的 Server port 改为 8001,Connector port 改为 8081

<Server port="8001" shutdown="SHUTDOWN">

<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

6.修改端口:将 D:\apache-tomcat\project2\conf\server.xml 的 Server port 改为 8002,Connector port 改为 8082

<Server port="8002" shutdown="SHUTDOWN">

<Connector port="8082" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

4.部署

将 project1 的项目代码部署到 D:\apache-tomcat\project1\webapps 下, project2 的项目代码部署到 D:\apache-tomcat\project2\webapps 下,配置完后的目录树如下图:

5.运行

分别启动两个项目的 startup.bat ,然后就可以通过 http://localhost:8081、http://localhost:8082 访问对应的项目。

注:service.bat 使用说明

以 project1 为例说明。打开 cmd,切换到 D:\apache-tomcat\project1,输入

  • 注册服务
service install tomcat-project1
  • 删除服务
service remove tomcat-project1

注册服务完后,即可在 Windows 服务中进行启动、停止等操作。

Apache 代理转发 Tomcat 请求

1.前言

Web 服务器配置时常常会遇到这么个问题:80 端口已经被 Apache 或者 Tomcat 其中之一占用了,另一个怎么使用80端口? 最常见的解决方案是使用 Nginx 作为代理应用服务器,所以本文主要谈的并不是使用 Nginx 来解决这个问题,而是直接使用 Apache 作为代理应用服务器来解决。

2.背景介绍

  • 服务器上原本已经有多个 PHP 站点部署在 Apache 下,使用 80 端口;
  • 现在新增了一个 Java Web 项目,部署在 Tomcat 下, 使用 8080 端口;
  • 两者各自在不同的端口均能正常访问,现在要求 Java Web 项目也要使用 80 端口。

3.Tomcat 配置

Tomcat 无需额外配置,只要如下配置,保证在 IP + port 能正常访问的情况下即可:

Tomcat Server.xml 部分相关配置

<!-- 默认配置,无需修改,检查一下即可 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 
<Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    
    <!-- docBase 配置项目所在绝对路径 -->
    <Context docBase="D:\project\test" path="" reloadable="true" source="org.eclipse.jst.jee.server:test"/>
    
</Host> 

4.Apache 配置

Apache httpd.conf 模块加载

#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

# 找到上面三个模块,去掉 # 开启模块
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

Apache httpd-vhosts.conf 配置

<VirtualHost *:80>
    ServerName test.shelwee.com
    ProxyPass / ajp://127.0.0.1:8009/ 
    ProxyPassReverse / ajp://127.0.0.1:8009/
    ErrorLog "logs/test.shelwee.com.log"  
    CustomLog "logs/test.shelwee.com.log" combined  
</VirtualHost>

配置完毕后,重启 Apache 服务器,然后开启 Tomcat 服务器。

5.代理过程说明

用户通过浏览器访问 test.shelwee.com 之后,Apache 会接收到这个请求,然后通过 AJP 协议转发到本地 8009 端口上,请求数据就能被 Tomcat 处理后返回。

UpdateHelper 1.0版本发布

本来预计14号便可将 UpdateHelper 收尾,结果由于临时有事,推迟到昨晚才将代码推送到 Github,然后今晚发出这篇。

不知不觉 UpdateHelper 这个项目已经在 Github 发布了两年多,至今收获 Star 121Fork 60(码云上收获了Star 84, Fork 35)。令我感到高兴的是,期间有不少开发者朋友提了 Issues 给我,以至于现在还能更新。

感谢的同时也欢迎 Pull request。

1

UpdateHelper 近期做了许多重要的更新,所以目前直接将这个版本定为 1.0。这个版本的改动主要有:

  •  从 ADT 转换成 Android Studio 项目
  • 优化部分代码实现逻辑
  • 网络部分全部改为 HttpURLConnection 实现
  • 修复下载过程与通知栏进度条卡顿情况
  • 提示文字全部提取到 strings.xml,方便国际化操作
  • 新增强制升级功能,通过后台接口 JSON 返回 forceUpgrade:true / false

UpdateHelper 1.0 从 ADT 转换成了 Android Studio 项目,因为目前 Android Studio 是开发 Android 的最好开发工具,且 Google 官方也已经不再支持 ADT。

UpdateHelper 从 1.0 开始已适配 Android 6.0 动态权限申请(只对存储权限做适配),但 UpdateHelper 只是简单的实现,起辅助作用,只有当检查到没有存储权限的时候才会弹出权限调用申请。

强烈建议开发者在 APP 中适配动态权限,因为用户有可能误操作拒绝后,而不知道怎么开启,这时就需要开发者引导如何再次开启权限。

权限应当由 APP 主程序配置引导,而不应该依靠任何第三方 Library。

2

UpdateHelper 会持续改善,目前制定的下一步开发计划主要有:

  • 下载过程可控制
  • 支持灰度测试

UpdateHelper 是我业余时间维护的一个开源项目,所以会不定期更新。项目也许还存在许多不足之处,希望开发者朋友们能加以体谅,同时也能加以鞭策。

也再次欢迎大家提交 Issuses,Pull request。

2017你好,2016再见

故事的开头往往是先从过去讲起,2016 即将成为过去,这一年对我来说是充实的,是我人生当中一个重要的转折点。

婚姻

2016,正如我开头所说的,是的!我结婚了,一辈子一次的那种。一直以为,婚姻对我来说相当遥远,没想到这一天这么快已经过去了。

2017 及余下的人生就是等待与另一半共同书写,一起慢慢变老。

运动

2016,我尝试过多种不同的运动,包括有氧运动跟无氧运动:

  • 骑行
  • 跑步
  • 哑铃
  • 篮球
  • 羽毛球
  • 俯卧撑 / 仰卧起坐

上述种种运动,却只有骑行是我唯一坚持一年多的运动,除了下雨没骑外,几乎每个工作日上下班都是骑车。

粗略算了一下,一天平均 8 公里,一年单单骑车就可以绕地球 1/20 圈,这样想想还是蛮惊人的。

而坚持骑行给我带来的好处也很明显,有氧运动把我多余的脂肪都燃烧了,现在我的体重、体脂率都很稳定的停留在标准水平,我坚信好处不只如此。

2017,我计划继续骑行,继续健身,继续保持有氧+无氧运动结合的方式运动,等下一次体检的时候希望没有一点问题。

足迹

2016,我走过了中国的 5 个城市,不论因公因私,这都丰富了我的视野。

对我来说印象最为深刻的就是《从你的全世界路过》拍摄地——重庆。重庆的地形很有趣,坡地很多,很多地方都是明显的高低起伏,公路上几乎看不到自行车,不由自主地脑补了一下在这里骑车的场景,想想都觉得好累。还有一个就是吃,基本都是面,基本都是麻辣,简直就是麻辣爱好者的天堂。

2017,我计划去更多没去过的城市。

成长

2016,我阅读了几本书,听了几次直播课程,也订阅了几个「得到」专栏,还有无数次的碎片化阅读。不能说这些行为能改变我什么,但至少有在潜移默化的影响我,对我是有帮助的,学习的过程总是在短期内看不到效果,而长期来说又是有助于个人成长的一种行为

2017,我计划继续大量的阅读并输出。

目前我的阅读方式主要为数字化阅读,数字化阅读意味着我经常盯着屏幕看,而且内容不比纸质来的系统。所以之后至少保证一年读 12 本的纸质图书,除了减少盯屏幕的时间外,还能保证系统性阅读。

输出则是为了证明自己已经理解了知识,并且对于所阅读的东西有自己的见解。我的输出渠道则是公众号(现代晓说)、博客简书

总结中的总结

2017 代表着明天,对于明天我永远保持着憧憬。

我的 2017 小目标:

  1. 至少阅读 12 本纸质书籍
  2. 规律的写作,一周写一篇
  3. 运动,一周至少三次
  4. 至少去一个没去过的城市
  5. 给自己的职业生涯做一份规划

WordPress在线升级失败后导致页面空白

1

WordPress 4.7 正式版前几天发布了,今天登录后台提示有新版本,点击「现在更新」后,页面加载一段时间后变空白,再次点击「现在更新」后,提示:另一更新正在进行。

这个问题已经不是第一次遇到了,上一个版本升级的时候也遇到了。那时以为是个偶然问题就没多花心思去找原因,直接下载最新版手动升级了。但这次是第二次遇到了,就没法对它视而不见了。

2

打开 Chrome DevTools 对这个升级过程进行多次分析,发现 update-core.php?action=do-core-upgrade 这个请求每次均在加载30秒左右后停止。说明 WordPress 在发起下载安装包请求后,在30秒后仍未下载完成导致请求连接中断。
解决方法也很简单,无非是以下几种:

    1. 加大带宽
    2. 减小更新包体积
    3. 加大请求响应时间

由于前两种方法适用性不是很广,所以下面的解决方案是针对第三种方法:加大请求响应时间

3

去除提示:另一更新正在进行

WordPress 在执行更新的时候数据库会生成一条记录用于防止同一时间重复更新,因此需要先把这条记录删除后下次才能在线更新。

如果用 SSH 登录服务器操作的话,执行以下命令登录 MySQL :

mysql -uroot -p //输入 MySQL root 账户密码

选择数据库,找到那条记录并删除,例如我找到的记录 option_id 是40301,那就执行:

use database;   // database 替换为你的WP数据库
select * from wp_options where option_name like '%lock%';
delete from wp_options where option_id = 40301;

加大请求响应时间

request_terminate_timeout 是 php-fpm.conf 中的一个参数,用于控制单个请求的超时中止时间,默认值30秒。

通过加大 request_terminate_timeout 的值,就可以彻底解决。执行以下命令修改:

sudo vi /etc/php5/fpm/pool.d/www.conf;  //通过 vi 编辑你的 php-fpm 配置文件

在 www.conf 找到 request_terminate_timeout 30s 这一行,值修改为300s

request_terminate_timeout 300s 

重启 php5-fpm 后配置生效

sudo service php5-fpm restart 

最后点击「现在更新」,耗时3分钟左右终于更新完毕,问题至此解决。

微信技巧:用新申请的QQ登录微信

引言

看到标题可能你会想:“我一直都是用QQ号登录微信的啊,这算什么技巧?”但我要说的是不用另外新买手机号即可用未绑定微信账号的QQ号码直接登录。
众所周知,微信现在注册只能用手机号注册,但是在微信版本5.0以前,除了用手机号注册外还可以用QQ直接登录微信。但从微信版本5.0以后就取消了这个功能,也就是说只要你在5.0版本之前没用QQ登录过微信,那就不能用QQ号直接登录,必须经过以下三步才行:

  1. 先用手机号注册一个微信
  2. 登录微信
  3. 绑定QQ号

1.准备工作

下载「阿里小号」,然后领取一个临时小号。
阿里小号每个月可免费提供一个临时手机号给你用,不过有效期只有一天。有了这个手机号之后就可以下一步了。

2.过程操作

利用申请的小号去注册微信,然后登录微信 -> 我的 -> 账号与安全 —> QQ号 -> 绑定

3.总结

  1. 借助阿里小号,申请一个临时手机号
  2. 用这个临时手机号注册微信
  3. 注册完成后登录微信绑定QQ号

4.风险提示

阿里临时小号有效期只有一天,第二天这个手机号就有可能被别人申请走,虽然在新手机上登录微信都会有安全验证防止这个情况出现,但还是存在一定的风险。而要解绑这个手机号,必须在15天后才能进行。所以对安全性要求较高的朋友,请谨慎操作。

给自己的大脑编程

引言

最近看完了李笑来老师的《把时间当作朋友》,这本书集结了李笑来老师多年的经验,涵盖了许多提升自我的方法,从而帮助你开启你的「心智」。书中的许多观点都能让人产生共鸣,更能引发人的思考与自省。

1.适当「跨域」

每个人都有一块难以走出的舒适区,在这个区域内你会很自在,而一旦走出你就会感觉浑身不舒服,甚至产生抗拒。例如,一般情况下,大部分职场白领业余时间经常会用来玩游戏或者看各类综艺影视之类的节目。当然这无可厚非,这就是你的舒适区,你可以继续「任性」,亦可尝试改变。

作为程序员,至少要拿出一半的时间用在其他地方,比如:读书,运动,公开课,或者编程。在这个不进则退的时代,虽说这会减少我们的娱乐时间,但同时也会使我们的生活更加积极,无形中就获得了更多的知识,谈资,健康,甚至更多。万能的上帝总是会在关上一扇门的同时打开一扇窗。

2.给自己写一个「死循环」

都说一个习惯的养成需要21天,我想说一个兴趣的培养也至少需要21天。当你走出自己的舒适区后,考验你的就是时间。如果你能连续21天以上重复做一件事,也许你还没养成习惯,那么至少你已经能控制自己的大脑了。

一个人如果没有什么兴趣爱好,那无论做任何事情都会索然无味,缺乏激情。编程理应是程序员的一种兴趣爱好,否则从事软件开发这个行业就会异常痛苦,以至于没有目标,不够深入。归纳起来就是一定要让自己进入一个「死循环」的状态,直至兴趣养成。

3.立即「执行」

种一棵树最好的时间是十年前,其次是现在。

程序写完想要得到预期结果,最快的方法是什么?就是立即编译执行。虽说在大脑里像计算机一样思考运行一遍也很快,但这种方式并不总是可靠,所以通过计算机编译->链接->执行程序来印证结果是既快又稳妥的办法。同理,我们想要知道自己做一件事之后的预期结果,最好的方式就是立即执行。

小结

以上就是我想时刻鞭策自己的。简言之:
从现在就开始控制自己的大脑,只有自己才能决定这个大脑运行程序的执行过程与结果。

谈谈网络拓扑结构遇到的坑

引言

现在大部分场所(家庭、小型公司等,下同)宽带或光纤接入后,都是通过「Modem」再转接路由器组成一个小型局域网,此时手机、PC等便可以上网。如果此时网络规模需要扩大,比如办公区域扩增,那么已有的网络已经无法满足了,此时正常的做法就是添加交换机了。

但很多人遇到这个问题可能就直接使用路由器了,完全没考虑使用交换机。这样就很容易出现一个使用误区,本文就这种情况下使用路由器可能遇到的问题进行说明。

常见的网络拓扑

引言中的第一句话提到的网络拓扑结构见下图,这是最常见的一种拓扑结构之一。

small-network-topology

而当规模需要扩大时,可能很多人都是采取下面的网络拓扑结构:

enlarge-network-topology

接路由器可能出现的问题

当用以上方法接路由器时,将使得整个局域网内部网络变复杂,也就是说内部已经分为两个「子网」了。路由器1的接法相当于主路由器对路由器1及主机2来说就是外网,这也将导致主机2无法直接与连接主路由器的主机0、主机1等设备所处的内部网络直接通信。

可能有人会想我就是有这个需求,就是要再建一个内网,那么这个拓扑结构就没有问题。但假如你就是简单的想让主机2接入网络,那么这种接法就不推荐了,因为它很容易就让你遇到上文提到的问题

推荐的解决方案

  1. 买一个交换机替换路由器1,问题即可解决;
  2. 将路由器1配置为交换机,即将路由器当交换机用,适合已经购买路由器的人。

附录:

简单说说路由器配置为交换机步骤:

  1. 将主路由器「LAN口」的网线接到路由器1的「LAN口」,不接「WAN口」;
  2. 禁用路由器1的DHCP服务;
  3. 路由器1「WAN口」配置忽略,修改「LAN口」地址为主路由器内网任一未被占用的IP地址;
  4. 重启路由器1。

从数据结构的角度看ArrayList与LinkedList

数组应该是大部分开发者最常用的数据结构,而链表使用频率则相对小一些。对于Java开发者而言,数组和链表这两种数据结构分别对应Java集合类中ArrayList和LinkedList。对我而言,至少在Java开发中,我99%以上都是使用ArrayList。
为了避免上述的情况,就从数据结构的角度来分析一下这两者的优缺点以及使用场景。

数组

数组很简单,就是一段相同类型的元素的集合。用ArrayList简单的创建一个集合:

ArrayList<Integer> arrays = new ArrayList<Integer>();
arrays.add(2);
arrays.add(4);
arrays.add(6);
arrays.add(8);

它在内部的数据结构即为数组,类似下面:

int[] arrays = {2,4,6,8};

此时,如果我们想要在索引为2的位置插入一个元素5,使数组变成{2,4,5,6,8}。如下图:

arraylist

Java中对应操作为:

arrays.add(2, 5);

这时ArrayList内部其实做了下面这些事情:

  1. 动态扩大数组;
  2. 将原来数组索引为2及其后面所有的元素向后移动;
  3. 插入新元素5到索引为2的位置。

对于删除某个元素也是类似的操作,所以现在应该可以看出数组的随机访问速度应该是不错的,而随机存储效率比较低。

链表

链表有单向链表、双向链表和循环链表,LinkedList使用的是非循环双向链表。双向链表的每一个元素为一个节点,每个节点都有一个直接前驱,数据域,直接后继。同样用LinkedList简单创建一个集合:

LinkedList<Integer> linkedList = new LinkedList<Integer>();
linkedList.add(2);
linkedList.add(4);
linkedList.add(6);
linkedList.add(8);

它在内部的数据结构即为链表,同样如果想要在索引为2的位置添加一个5,对应的图如下:

linkedlist

 

Java中对应操作为:

linkedList.add(2, 5);

这时LinkedList内部其实做了下面这些事情:

  1. 同样先检查是否超出边界;
  2. 对半查找出原来索引为2的节点将其前驱改为新增节点5;
  3. 将新增节点5的前驱改为4,后继改为6;
  4. 节点4的后继改为5。

同样对于链表中节点的删除也是如此,只要修改指针指向即可,而不必像数组那样大费周章的移动。由此可见链表的优点是随机存储效率高,而缺点就是随机访问效率较低。

总结

比较完数组与链表的优缺点,现在对于它们各自的使用场景应该更清楚了。
数组适合在大量随机访问集合的情况下使用,而链表更适合在大量随机存储,即大量的添加删除时使用。