Fork me on GitHub
kwdfmzhu's blog

The World is Full of Shit


  • Startseite

  • Über

  • Archiv

  • Tags

Valid使用注解

Veröffentlicht am 2018-05-04 |

Controller 做表单提交时,对参数进行验证

注解 说明
@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

spring配置动态数据源

Veröffentlicht am 2017-12-25 |

基本思路

运用spring的AbstractRoutingDataSource接口,实现determineCurrentLookupKey方法。

实现过程

  1. 配置多数据源
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
<bean id="dataSource1" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
...
</bean>
<bean id="dataSource2" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
...
</bean>
<bean id="dataSource" class="com.xx.xx.xx.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource1" value-ref="dataSource1"/>
<entry key="dataSource2" value-ref="dataSource2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource1"/> <!-- 默认使用数据源 -->
</bean>

其中真正使用的数据源为dataSource,设置key-value来切换dataSource1和dataSource2

  1. 实现DynamicDataSource类
1
2
3
4
5
6
public class XADynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return "";//return dataSource1/dataSource2
}
}

determineCurrentLookupKey的返回值就是上述xml配置中的key,做到切换数据源

应用场景

  1. 读写分离
  2. 不同类型数据源(如XA和普通数据源)切换
  3. 等等…

后语

这里只是提供一种比较简单的数据源切换实现过程,至于外部如何实现,有很多种方法如: 增加注解,通过SQL方法区分等等都可以。

freeswitch 配置连接sip服务器

Veröffentlicht am 2017-12-21 |

目标

  1. 部署freeswitch(以下简称fs), 实现软交换电话互通
  2. 配置fs连接sip服务器,实现外部电话连通
  3. 通过sipjs的webRTC实现浏览器拨打外部电话

安装过程

安装fs

在mac上有两种方式:

  1. 直接brew install freeswitch
  2. 源码安装,官网地址,下载源码后根据README提示安装即可(中途make时会需要安装很多依赖)
    快速推荐使用方式1.

PS: centos6.5安装时用fs1.4版本(用1.6会提示依赖版本不够)

启动fs

命令行中输入freeswitch,待输出一堆信息后,出现蓝色背景的提示既是成功.

安装配置软交换电话软件

Mac OS上安装X-Lite,ios上安装Zoiper,在软交换中配置对应分机号(fs默认开放了1000至1019的分机号使用,初始密码是1234)
下图是X-Lite的配置,Zoiper同理
1.jpg

拨打电话

直接打开X-Lite拨打其他已经设置的分机号即可

到此目标1步骤完成

fs配置sip服务器

前提: 已经有现成的sip服务器已经对应的账号

  1. 在fs的etc/freeswitch/sip_profiles/external路径下,新建文件名为sipprovider.xml, 内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <include>
    <gateway name="sipprovider">
    <param name="username" value="8009"/>
    <param name="password" value="123456"/>
    <param name="realm" value="192.168.5.201"/>
    <param name="proxy" value="192.168.5.201"/>
    <param name="register" value="true"/>
    <param name="expire-seconds" value="600"/>
    <param name="ping" value="30" />
    <param name="sip-trace" value="true" />
    </gateway>
    </include>
  2. 重启fs或者在fs_cli中输入“sofia profile external restart”, 看到终端如下就是生效

Added gateway ‘sipprovider’ to profile ‘external

fs配置sip服务到extension

  1. etc/freeswitch/dialplan/default新建00_rout_to_sipprovier.xml(用00开头是为了让fs优先读取这个配置,防止被默认配置覆盖)
  2. 内容如下
1
2
3
4
5
6
7
8
<include>
<extension name="5_201 sipprovider Gateway">
<condition field="destination_number"expression="^(((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8})$">
<action application="set" data="dialed_extension=$1"/>
<action application="bridge"data="sofia/gateway/sipprovider/$1"/>
</condition>
</extension>
</include>
  1. fs_cli 输入 reloadxml重启配置
  2. 如果需要增加录音功能,那么继续添加xml内容中的action标签。详见这里
1
2
3
4
5
6
7
8
<action application="set" data="RECORD_TITLE=Recording ${destination_number} ${caller_id_number} ${strftime(%Y-%m-%d %H:%M)}"/>
     <action application="set" data="RECORD_COPYRIGHT=(c) 1980 Factory Records, Inc."/>
     <action application="set" data="RECORD_SOFTWARE=FreeSWITCH"/>
     <action application="set" data="RECORD_ARTIST=Ian Curtis"/>
     <action application="set" data="RECORD_COMMENT=Love will tear us apart"/>
     <action application="set" data="RECORD_DATE=${strftime(%Y-%m-%d %H:%M)}"/>
     <action application="set" data="RECORD_STEREO=true"/>
     <action application="record_session" data="$${recordings_dir}/${strftime(%Y-%m-%d-%H-%M-%S)}_${destination_number}_${caller_id_number}.wav"/>

拨打电话

在X-Lite上输入外网电话即可,如我的手机1508860XXXX

到此目标2步骤完成

开启fs的websocket端口

在sip_profiles/internal.xml中开启ws-binding和wss-binding

1
2
3
4
5
6
<!-- for sip over websocket support -->
<param name="ws-binding" value=":5066"/>
<!-- for sip over secure websocket support -->
<!-- You need wss.pem in $${certs_dir} for wss or one will be created for you -->
<param name="wss-binding" value=":7443"/>

使用SipJS实现

  1. 查看sipjs官网,根据文档实现
  2. 我使用demo地址

mysql 5.7 无法插入0000-00-00 00:00:00的数据

Veröffentlicht am 2017-10-20 |

起因:
由于CRM的用户属性添加上要经过一个洗数的过程,因此online时间作为比较重要的时间戳需要保存下来。设置DEFAULT为”0000-00-00 00:00:00”。但是程序却报错

1
java.sql.SQLException: Cannot convert value '0000-00-00 00:00:00' from column XX to TIMESTAMP

解决办法:
错误提示的很明显,但是以前做过类似的数据设计,是没有问题的。故查了以下发现mysql从5.6.X开始后,不再支持类似”0000-00-00”这种数据。如果想要规避此类问题,有几个方案

  1. 修改mysql配置文件的sql_mode,去掉 NO_ZERO_IN_DATE, NO_ZERO_DATE 两个选项。(不建议)
  2. 在数据库链接地址后加zeroDateTimeBehavior=convertToNull, 如: jdbc:mysql://192.168.5.241:3306/acrm-usercenter?zeroDateTimeBehavior=convertToNull

    zeroDateTimeBehavior可设置的值有三个:

  3. exception, 既为默认选项,就是抛出上述错误
  4. convertToNull, 转成NULL值
  5. round, 转成最近的日期”0001-01-01”

结论:
根据需求,如果是新建的表,那么此类日期default可以设置为NULL;如果是数据库升级了,考虑到程序兼容性,可加zeroDateTimeBehavior=convertToNull

记一次django部署时遇到的问题总结

Veröffentlicht am 2017-10-16 |

一. 大概情况
就是说有一个django服务需要部署到centos的apache上去。但是呢该centos内核版本较低,自带的python版本较低。需要自己编译一个python2.7的版本替换掉系统的。然后就开展了一场与各种配置的艰苦斗争。。。

篇幅短长,大家就当作看一个故事吧。重点的呢会加黑一下,同时也写在结论处的。

二. 斗争过程
2.1. 刚拿到这个任务时,我登陆centos找apache服务。但是居然没有找到/etc/apache2(以前接触的机器都是ubuntu和debian, 没有接触过redhat和centos),我困惑了。。。然后查了一下才知道centos上的httpd就是apache,也就是/etc/httpd就是我要找的apache目录。

2.2. 知道apache目录后,我首先试着跑了一下django,采用本地启动的方式,验证采用wget ${URL}的方式,发现程序是OK的。那么就可以部署到apache上去了。apache中的conf/httpd.conf中已经有了对应的wsgi配置(已有前人的肩膀可以踩了,很happy),看了一下WSGIScriptAlias 配置路径,没有问题。那么我就尝试启动了apache,启动方式为 service httpd restart。但此时查看apache的error_log,现在提示找不到site.py错误。

2.3. 查找相关的资料,我怀疑可能是mod_wsgi版本过低导致的。通过ldd modules/mod_wsgi.so 看到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
linux-vdso.so.1 => (0x00007ffff3300000)
libpython2.6.so.1.0 => /usr/lib64/libpython2.6.so.1.0 (0x00007f48fb4e6000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f48fb2c9000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f48fb0c4000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f48faec1000)
libm.so.6 => /lib64/libm.so.6 (0x00007f48fac3d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f48fa8a8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f48fbab9000)
```
其中很明显libpython是2.6版本的,和我自装的2.7版本对不上。此时有两种方式
1. 修改link so文件,也就是把/usr/lib64/libpython2.6.so.1.0 做成一个软连接,link到python2.7.so上
2. 重现编译mod_wsgi
考虑到尽量少走歪路,采用比较保险的第2中方案。
2.4. 下载mod_wsgi源码,开始编译。然后就很顺利的报错了,出错如下
```bash
/usr/bin/ld: /usr/local/lib/libpython2.7.a(abstract.o): relocation R_X86_64_32 against `.rodata.str1.8‘ can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libpython2.7.a: could not read symbols: Bad value
collect2: ld returned 1 exit status
apxs:Error: Command failed with rc=65536

提示还是比较明显的,程序在做link libpython2.7.a 的时候找到的是静态库(.a)不是动态库(.so),当时看到这个错误时感觉崩溃了,这说明需要重新编译python程序啊。。。蹲墙角哭了一会,回来默默的把python删掉,重新下载python源码,./configure时带上–enable-shared; make; make install。后再编译mod_wsgi 就可以了。替换掉modules/mod_wsgi.so。

PS: 关于mod_wsgi,有兴趣可以看一下: http://modwsgi.readthedocs.io/en/develop/

2.5. 安装完mod_wsgi,先喝口水缓一缓,因为我相信apache的环境应该是不会有问题了,我只要service httpd restart就ok了。果然,现实给我了一记响亮的耳光,error_log 中出现了如下错误

1
2
3
4
5
6
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] mod_wsgi (pid=4017): Target WSGI script '/var/www/html/attence/wsgi.py' cannot be loaded as Python module.
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] mod_wsgi (pid=4017): Exception occurred processing WSGI script '/var/www/html/attence/wsgi.py'.
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] Traceback (most recent call last):
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] File "/var/www/html/attence/wsgi.py", line 23, in <module>
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] from django.core.wsgi import get_wsgi_application
[Fri Oct 13 13:49:42 2017] [error] [client 192.168.5.102] ImportError: No module named django.core.wsgi

口中的水差点吐在屏幕上。。。怎么django没有了。。。我突然间意识到我重装了python。。。然后开始了重装各种依赖的漫漫长路。(装完一个后,重启apache,根据错误提示No module named XXX,找对应依赖的下载地址即可)。

2.6. 安装完django的依赖后,error_log出现了一个诡异的错误

1
2
3
4
5
[Sun Oct 15 19:11:02 2017] [error] [client 127.0.0.1] mod_wsgi (pid=880): Target WSGI script '/var/www/html/attence/wsgi.py' cannot be loaded as Python module.
[Sun Oct 15 19:11:02 2017] [error] [client 127.0.0.1] mod_wsgi (pid=880): Exception occurred processing WSGI script '/var/www/html/attence/wsgi.py'.
//.... 省略掉中间很多错误日志
[Sun Oct 15 19:11:02 2017] [error] [client 127.0.0.1] __import__(name)
[Sun Oct 15 19:11:02 2017] [error] [client 127.0.0.1] ImportError: No module named attence.settings

attence.settings是我的DJANGO_SETTINGS_MODULE,如果说找不到这个module,那么就说明整个路径配置有问题了。在这个地方我想了很久,也查了很多资料,都没什么结果。有时间就是会有灵光一现,我突然间意识到如果我手动跑/var/www/html/attence/wsgi.py这个文件会怎么样(因为我相信apache也是去运行这个文件的)。果然,也提示相同的错误,哈哈,那就方便多了呀,打开wsgi.py文件, 中间的一行代码引起了我的注意:

1
2
root = os.path.dirname(__file__))
sys.path.insert(0, os.path.join(root,'site-packages'))

很诡异的代码,我猜想可能以前的人是把工程文件放在python lib 的 site-packages下的吧。将此段代码稍作修改

1
2
root = os.path.dirname(os.path.realpath(__file__))
sys.path.append(root)

此时,再运行wsgi文件,没有再提示错误,重启apache,不再提示这个错误,而是提示其他的依赖ImportError, 如 ImportError: No module named tablib,然后又开始了装依赖的漫漫长路。

2.7. 终于,重启apache, wget ${URL} 不再报错了,说明终于配完了,我欣喜若狂。打开浏览器,输入URL,然后页面提示: 无法访问此网站。我的心又碎了了。。。这又是为啥呢,后来发现是防火墙启动了,只开放了8080端口。。。然后我就把果断把防火墙关掉, service iptables stop。

2.8. 终于的终于,我在浏览器上看到了我想要的页面。我的眼泪也终于流下来了。。。。

三. 总结:
整个过程花了我挺久时间的,有自己不小心走的弯路,也有学习到自己不知道的技术。
3.1. centos下的apache叫httpd, 其他一样
3.2. WSGI相关的知识点需要再重新学习一下,其中很多地方有点印象,但又不确定,导致查询资料花费挺长时间的
3.3. django作为python最火热之一的web框架,应该能够熟练应用。
3.4. 内网正常,外网无法访问的情况下,一般看一下防火墙或者nginx的配置
3.5. 熟悉linux下的源码安装方式,包括C程序的make以及python的setup
3.6. 还有其他linux下的一些快捷方式,如通过CTRL+R来查找历史命令,很简单,但很实用,能够极大加快调查问题的速度。

有些问题事后想来还是很简单的,但当时的确困扰了我好久。但总的来说,花的时间非常值得。

如何用C写python库

Veröffentlicht am 2017-06-03 |

还是比较简单的,这次就权当入个门吧

  1. 写好一个C函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include<stdio.h>
    #include<python2.7/Python.h> //默认python版本就是#include<Python.h>
    static PyObject *hellozkw(PyObject *self, PyObject *args) {
    int num;
    //解析参数
    if (!PyArg_ParseTuple(args, "i", &num)) {
    return Py_BuildValue("i", -1);
    }
    printf("hello zkw %d\n", num);
    return Py_BuildValue("i", NULL);
    }
    static PyMethodDef HMethods[] = {
    //方法名,导出函数,参数传递方式,方法描述。
    {"hellozkw", hellozkw, METH_VARARGS, "hahahaha.... from zkw's hello"},
    {NULL, NULL, 0, NULL}
    };
    void inithello(void) {
    (void) Py_InitModule("hello", HMethods);
    }
  2. 准备一个setup文件

    1
    2
    3
    4
    5
    6
    7
    8
    #!/usr/bin/env python
    # coding=utf-8
    from distutils.core import setup, Extension
    module = Extension('hello', sources = ['hello.c'])
    setup(name = 'hello test', version = '1.0', ext_modules = [module])
  3. Makefile文件

    1
    2
    3
    publish:
    python setup.py build
    python setup.py install
  4. 运行make publush

  5. 运行即可
    1
    2
    3
    4
    5
    >>> import hello
    >>> ret = hello.hellozkw(123)
    hello zkw 123
    >>> ret
    0

Mybatis 动态传入表名进行sql查询

Veröffentlicht am 2017-05-13 |

网上也有相关的方法,基本都为

  1. 添加属性statementType=”STATEMENT”
  2. 用${}代替#{}。如此一来就会有sql注入的危险。

今天自己尝试了一种新的方法,如下:

基本思路

利用org.apache.ibatis.annotations.Param的注解,在xml中判断传入的参数:表名用${},值用#{}。

实现过程

  • 定义一个mapper
1
2
3
4
public interface TestMapper{
//统计userId的对应的数据总数
int countByUserId(@Param("tableName") String tableName, @Param("userId") Integer userId);
}
  • 定义xml
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="TestMapper对应路径">
<select id="countByUserId" parameterType="hashmap" resultType="java.lang.Integer">
SELECT
COUNT(1)
FROM
${tableName}
WHERE
userId = #{userId}
</select>
</mapper>

如此配置,即可以实现表名的动态传入,又可以防止sql注入的危险。传入库名或者字段名同理可得。

Java native关键字

Veröffentlicht am 2016-07-03 |

前言

在Java的Object类中的函数定义如hasCode()函数如下:

1
public native int hasCode();

看了之后觉得很奇怪,为什么会有native呢?今天稍微来了解一下

什么是native

native就是本地的意思,Java中native是一个关键字,用来修饰函数定义,表明该函数是由非Java写的。(类似C++调用C的extern C告知编译器去调用一个C函数)

“A native method is a Java method whose implementation is provided by non-java code.”

定义一个native函数时,并不提供实现题(有点类似于Java的Interface定义),原因就是函数的具体实现是由非Java语言在外面实现的。下面给出一些native函数的定义示例:

1
2
3
4
5
6
public class IHaveNatives {
native public void Native1(int x);
native static public long Native2();
native synchronized private float Native3(Object o);
native void Native4(int[] ary) throws Exception;
}

很显然,native可以修饰几乎所有类型的函数以及返回所有类型的返回值,当然很明显的一点就是不能修饰abstract类型的函数,原因也很明显:native表示该函数有外部的具体实现,而abstract表示该函数没有具体的实现。这里说明一点,如果带native的函数被继承后可以用java重写(带final的不能被重写)。

为什么要有native

  1. 与java环境外交互:
    有时java应用需要与java外面的环境交互。这是本地方法存在的主要原因,你可以想想java需要与一些底层系统如操作系统或某些硬件交换信息时的情况。本地方法正是这样一种交流机制:它为我们提供了一个非常简洁的接口,而且我们无需去了解java应用之外的繁琐的细节。
  2. 与操作系统交互:
    JVM支持着java语言本身和运行时库,它是java程序赖以生存的平台,它由一个解释器(解释字节码)和一些连接到本地代码的库组成。然而不管怎样,它毕竟不是一个完整的系统,它经常依赖于一些底层(underneath在下面的)系统的支持。这些底层系统常常是强大的操作系统。通过使用本地方法,我们得以用java实现了jre的与底层系统的交互,甚至JVM的一些部分就是用C写的,还有,如果我们要使用一些java语言本身没有提供封装的操作系统的特性时,我们也需要使用本地方法。
  3. Sun’s Java:
    Sun的解释器是用C实现的,这使得它能像一些普通的C一样与外部交互。jre大部分是用java实现的,它也通过一些本地方法与外界交互。例如:类java.lang.Thread 的 setPriority()方法是用java实现的,但是它实现调用的是该类里的本地方法setPriority0()。这个本地方法是用C实现的,并被植入JVM内部,在Windows95的平台上,这个本地方法最终将调用Win32 SetPriority() API。这是一个本地方法的具体实现由JVM直接提供,更多的情况是本地方法由外部的动态链接库(external dynamic link library)提供,然后被JVM调用。

怎么样使用native

  1. 首先创建一个native的类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class HelloNative
    {
    static
    {
    System.loadLibrary("HelloNative");
    }
    public static native void sayHello();
    @SuppressWarnings("static-access")
    public static void main(String[] args)
    {
    new HelloNative().sayHello();
    }
    }
  2. 运行生成javah,等到头文件

    1
    2
    javac HelloNative.java
    javah HelloNative

就可以等到如下的HelloNative.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloNative */
#ifndef _Included_HelloNative
#define _Included_HelloNative
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloNative
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloNative_sayHello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

  1. 根据头文件实现一个本地方法

    1
    2
    3
    4
    5
    6
    7
    #include "HelloNative.h"
    #include <stdio.h>
    JNIEXPORT void JNICALL Java_HelloNative_sayHello
    {
    printf("Hello,JNI");
    }
  2. 用GCC生成库文件

  3. 运行即可
    1
    2
    3
    java HelloNative
    Hello,JNI

使用pelican和github搭建个人blog

Veröffentlicht am 2016-04-13 |

前几日浏览网页时无意中看到Pelican,于是心血来潮想要搭建个人博客玩玩。联想到github已经提供个人域名,一切都顺利成章。简单写点用做留念

1.搭建环境准备

本人属于重度Linux患者,环境为Ubuntu 14.04LTS,其他环境应该类似

2.涉及相关技术

  • Python2.7 及其相关
  • Pelican
  • Github
  • Markdown
  • And so on …

    2.1. Pelican

  • Pelican是一个用Python语言编写的静态网站生成器,支持使用restructuredText和Markdown写文章,配置灵活,扩展性强。同时有很多主题可以使用。
  • Pelican的github地址: https://github.com/getpelican/pelican
  • Pelican 主题的github地址: https://github.com/getpelican/pelican-themes

3. 使用Pelican 搭建个人静态博客

3.1. 安装pelican

1
aptitude install python-pelican

python2.7 以及相关其他依赖不做介绍

3.2. 开始搭建

输入如下命令

1
2
3
mkdir blog
cd blog
pelican-quickstart

pelican-quickstart 是pelican 自带命令,根据提示一步步输入相应的配置项,不知道如何设置的接受默认即可,后续可以通过编辑pelicanconf.py文件更改配置

结束后生成目录如下

1
2
3
4
5
6
7
blog/
├── content # 存放输入的Markdown文件夹
├── output # 生成的输出文件
├── develop_server.sh # 开启测试服务器脚本
├── Makefile # 管理博客的Makefile
├── pelicanconf.py # 主配置文件
└── publishconf.py # 主发布文件

####3.3. 写博客内容

  • 进入到content 目录下,用Markdown 开始编写内容。Markdown语法简单,Google即可
  • Markdown 在线编辑器推荐使用马克飞象,个人使用不错。本地编辑器使用ReText。
  • 切记在每个文件前四行输入如下
    1
    2
    3
    4
    Title: 文章标题
    Date: 2013-04-18
    Category: 文章类别
    Tag: 标签1, 标签2

####3.4. 预览博客
输入以下命令

1
2
make publish
make serve

打开浏览器,输入127.0.0.1:8000 即可看到博客

####3.5. 选择主题
pelican-themes 上有很多主题, git clone后可以使用如下命令安装任一主题

1
pelican-themes -i XXXXXX

安装完成后在pelicanconf.py文件中修改THEME 容,如安装了pelican-bootstrap3主题,那么修改THEME =”pelican-bootstrap3”,重启即可看到主题修改

####3.6. 设置favicon.ico
favicon.ico 即Favorites Icon的缩写,其可以让浏览器除显示相应的标题外,还以图标的方式区别不同的网站。

  1. 选择图片,生成.ico文件(可直接使用网站生成如 在线制作ico图标)
  2. 将图片命名成favicon.ico,放置到与Makefile同级目录
  3. 修改Makefile,添加移动favicon.ico功能
    1
    2
    3
    4
    5
    FAVICONICO=$(BASEDIR)/favicon.ico
    publish: clean
    $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
    cp $(FAVICONICO) $(OUTPUTDIR)

####3.7. 设置评论系统
在Disqus上申请一个站点,记牢Shortname。 在pelicanconf.py添加

1
DISQUS_SITENAME = Shortname

设置后可以在每个blog下出现如此评论系统
disqus_comments

####3.8. 添加图片图床
前两天一直在找一个简单易用的图床,终于找到一个推荐的围脖是个好图床

  1. 进入网站,选择对应的浏览器安装插件(本人安装了Chrome插件)
  2. 安装完成后,打开插件,会出现提示对话框,将图片拖入即可生成对应的图片URL了

####3.X. 其他功能
其他还有很多功能如评论系统,分析系统,站内搜索可以添加,后续会更新

4. 使用github发布博客

原理: Github为每一个用户分配了一个二级域名username.github.io,用户为自己的二级域名创建主页很简单,只需要在Github下创建一个名为username.github.io的版本库,并向其master分支提交网站静态页面即可。

  1. 登陆Github,创建一个名为username.github.io的版本库(必须如此格式)
  2. 将blog/output 下的内容git到username.github.io下
  3. 少等片刻,登陆http://username.github.io,会发现自己的个人博客已经生成

如此一来,一个具有Geek风格的个人博客搭建完毕。可以出去装X了…

杭州违章处理吐槽

Veröffentlicht am 2016-03-15 |

买车一年半,行驶1万5公里,不算多,平时开得也比较小心,但还是吃了三张罚单,其中在火车东站就被double kill了。这几天去处理了一下,过程曲折,不得不吐槽一下

  1. 滨江周日处理点只有一处(鉴于党国国情,已是喜出望外),但不能当场交钱,需要自己去银行或者支付宝支付。
  2. 支付宝支付只能根据违章号一个个处理,重复操作太多。
  3. 在火车东站的两张罚单只能到绍兴路64号(杭州铁路公安局交警支队机动大队),全杭州只此一家,且只有工作日上班。
  4. 铁路交警只能现场交现金,不支持刷卡和支付宝。或者可自己去环城东路2号 中国工商银行(杭州城站广场支行),全杭州又只此一家,两者距离4公里


    screenshot.jpg

  5. 违章人多处理人少自不必说了,排队半个小是以上是妥妥的。

回来查了一下,如果在机场违章就必须要去机场处理!!!! 所以切记开车一定要遵守教规!!!

12
kwdfmzhu

kwdfmzhu

The World is Full of Shit

11 Artikel
18 Tags
RSS
© 2018 kwdfmzhu
Erstellt mit Hexo
Theme - NexT.Muse