my blog my blog

Category: 建站心得
Ubuntu安装Node.js教程

 

在Ubuntu服务器中端中执行如下命令可以安装4.x版本的node.js

  1. curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - 
  2. sudo apt-get install -y nodejs 

如果想安装5.x版本的node.js可以执行

  1. curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash - 
  2. sudo apt-get install -y nodejs 

编译安装就不介绍了。

Nginx反向代理网站conf配置

 

编辑vhost的conf文件

  1. server { 
  2.     listen 80; 
  3.     server_name nenew.net www.nenew.net;   
  4.      
  5.     location / {  
  6.     proxy_pass http://localhost:1337;  
  7.     }  

这样就可以让Nginx反向代理本地端口运行的网站来共享Nginx的80端口了。

Nginx服务器配置多域名指向同服务器

 

当我们用Nginx服务器添加新的虚拟主机的时候,都会生成一个vhost的conf文件,当我们把同一个域名的@和www两个地址都直接A解析到Nginx服务器的时候,会发现只有我们添加的vhost里面的那个域名会被正常解析,如果我们想把@和www两个地址都直接解析到这个vhost上,我们可以这样做。

  1. vim /usr/local/nginx/conf/vhost/www.nenew.net.conf 
  2. 修改字段server_name,比如如下方式 
  3. server_name nenew.net www.nenew.net; 

这样子可以直接将nenew.net和www.nenew.net都指向到这个vhost而不用什么301 302那种跳转,好久不搞linux了,奶牛打算弄个新站,重新拾起web。

设置完成后重启Nginx就搞定了。

Nginx为网站目录设置密码保护

 

在Nginx的nginx.conf里面有如下的字段

  1. server
  2.     {
  3.         listen 80 default_server;
  4.         #listen [::]:80 default_server ipv6only=on;
  5.         server_name www.nenew.net;
  6.         index index.html index.htm index.php;
  7.         root  /home/wwwroot/default;
  8.         #error_page   404   /404.html;
  9.         include enable-php.conf;
  10.         location /nginx_status
  11.         {
  12.             stub_status on;
  13.             access_log   off;
  14.         }
  15.         location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
  16.         {
  17.             expires      30d;
  18.         }
  19.         location ~ .*\.(js|css)?$
  20.         {
  21.             expires      12h;
  22.         }
  23.         location ~ /\.
  24.         {
  25.             deny all;
  26.         }
  27.         access_log  /home/wwwlogs/access.log  access;
  28.     }
  29. include vhost/*.conf;
  30. }

如果我们想在默认的目录添加密码保护,只保护对目录的访问,也就是登陆这个目录就会输入密码,则我们这样设置

  1. server
  2.     {
  3.         listen 80 default_server;
  4.         #listen [::]:80 default_server ipv6only=on;
  5.         server_name www.nenew.net;
  6.         index index.html index.htm index.php;
  7.         root  /home/wwwroot/default;
  8.         #error_page   404   /404.html;
  9.         include enable-php.conf;
  10.         location /nginx_status
  11.         {
  12.             stub_status on;
  13.             access_log   off;
  14.         }
  15.         location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
  16.         {
  17.             expires      30d;
  18.         }
  19.         location ~ .*\.(js|css)?$
  20.         {
  21.             expires      12h;
  22.         }
  23.         location ~ /\.
  24.         {
  25.             deny all;
  26.         }
  27.         location / 
  28.         {        
  29.   auth_basic “Restricted”;
  30. auth_basic_user_file pass_file;
  31. }
  32.         access_log  /home/wwwlogs/access.log  access;
  33.     }
  34. include vhost/*.conf;
  35. }

其中pass_file是密码文件的绝对路径,密码文件是由用户名和函数 crypt加密的密码组成,可以使htpasswd -c -d pass_file username 来生成。

Ubuntu下shadowsocks多用户后端manyuser+前端sspanel搭建教程

 

好吧,很多东西还是有个前端管理起来比较方便,奶牛今天也配了个,写下过程记录下。

安装shadowsocks支持

  1. apt-get install python-pip python-m2crypto
  2. pip install cymysql

安装LNMP

  1. wget -c http://soft.vpser.net/lnmp/lnmp1.2-full.tar.gz && tar zxf lnmp1.2-full.tar.gz && cd lnmp1.2-full && ./install.sh lnmp

后端安装配置

  1. git clone -b manyuser https://github.com/mengskysama/shadowsocks.git 
  2. cd ./shadowsocks/shadowsocks 
  3. vim Config.py 
  4.     #Config 
  5.     MYSQL_HOST = 'localhost' #这一行是服务器IP,127.0.0.1表示本机 
  6.     MYSQL_PORT = 3306 #数据库端口号 
  7.     MYSQL_USER = 'nenew' #数据库用户名 
  8.     MYSQL_PASS = 'nenew' #数据库密码 
  9.     MYSQL_DB = 'shadowsocks' #数据库名称 
  10.  
  11.     MANAGE_PASS = 'ss233333333' 
  12.     #if you want manage in other server you should set this value to global ip 
  13.     MANAGE_BIND_IP = '127.0.0.1' 
  14.     #make sure this port is idle 
  15.     MANAGE_PORT = 23333 
  16.  
  17. python server.py 

在mysql数据库中新建数据库shadowsocks,并添加用户nenew,导入manyuser中的sql文件,然后执行python server.py。如果没有异常,则表示已经安装成功后端。

前端安装:

  1. lnmp vhost add 

添加虚拟主机,然后进入虚拟主机目录

  1. wget https://github.com/orvice/ss-panel/archive/master.zip 
  2. unzip master.zip 
  3. rm master.zip 
  4. mv -f ss-panel-master/* ./ 
  5. mv lib/config-simple.php lib/config.php 
  6. vim lib/config.php 

编辑配置信息,然后将lib文件夹下的sql文件都导入到nenew数据库中。

添加守护进程supervisor:

  1. apt-get install supervisor 
  2. echo_supervisord_conf > /etc/supervisor/supervisord.conf 
  3. vim /etc/supervisor/supervisord.conf 

将文件最后添加

  1. [program:shadowsocks] 
  2. command=python /root/shadowsocks/shadowsocks/server.py -c /root/shadowsocks/shadowsocks/config.json 
  3. autorestart=true 
  4. user=root 

其中的目录自己根据实际情况设置,重启即可。

前端github:https://github.com/orvice/ss-panel

后端github:https://github.com/mengskysama/shadowsocks

顺带广告,ss服务器150元每年,需要者联系,联系方式见杂货铺。

PPTP VPN之日志功能实现【记录登陆用户、登陆时间、登陆IP、在线时间、流量统计等信息】

 

其实以前也搞过PPTP VPN的配置,但是当时都是存在于建立,很多细节的方面并没有做好。今天来搞下这个日志系统吧,主要实现是通过ip-up 和ip-down两个脚本来实现的。这里说下原理吧,原理是通过pptp建立连接的时候都会执行ip-up,然后断线会执行ip-down。首先看看man pppd里面的一些内容:

  1. SCRIPTS 
  2.        Pppd  invokes  scripts at various stages in its processing which can be 
  3.        used to perform site-specific ancillary processing.  These scripts  are 
  4.        usually  shell  scripts,  but  could  be executable code files instead. 
  5.        Pppd does not wait for the scripts to finish (except for the  ip-pre-up 
  6.        script).  The scripts are executed as root (with the real and effective 
  7.        user-id set to 0), so that they can do things such  as  update  routing 
  8.        tables  or  run  privileged  daemons.   Be careful that the contents of 
  9.        these scripts do not compromise your system's security.  Pppd runs  the 
  10.        scripts  with standard input, output and error redirected to /dev/null, 
  11.        and with an environment that is empty except for some environment vari- 
  12.        ables  that give information about the link.  The environment variables 
  13.        that pppd sets are: 
  14.  
  15.        DEVICE The name of the serial tty device being used. 
  16.  
  17.        IFNAME The name of the network interface being used. 
  18.  
  19.        IPLOCAL 
  20.               The IP address for the local end of the link.  This is only  set 
  21.               when IPCP has come up. 
  22.  
  23.        IPREMOTE 
  24.               The IP address for the remote end of the link.  This is only set 
  25.               when IPCP has come up. 
  26.  
  27.        PEERNAME 
  28.               The authenticated name of the peer.  This is  only  set  if  the 
  29.               peer authenticates itself. 
  30.  
  31.        SPEED  The baud rate of the tty device. 
  32.  
  33.        ORIG_UID 
  34.               The real user-id of the user who invoked pppd. 
  35.  
  36.        PPPLOGNAME 
  37.               The  username  of  the  real  user-id that invoked pppd. This is 
  38.               always set. 
  39.  
  40.        For the ip-down and auth-down scripts, pppd  also  sets  the  following 
  41.        variables giving statistics for the connection: 
  42.  
  43.        CONNECT_TIME 
  44.               The  number  of  seconds  from  when the PPP negotiation started 
  45.               until the connection was terminated. 
  46.  
  47.        BYTES_SENT 
  48.               The number of bytes sent (at the level of the serial port)  dur- 
  49.               ing the connection. 
  50.  
  51.        BYTES_RCVD 
  52.               The  number  of bytes received (at the level of the serial port) 
  53.               during the connection. 
  54.  
  55.        LINKNAME 
  56.               The logical name of the link, set with the linkname option. 
  57.  
  58.        CALL_FILE 
  59.               The value of the call option. 
  60.  
  61.        DNS1   If the peer supplies DNS server addresses, this variable is  set 
  62.               to the first DNS server address supplied. 
  63.  
  64.        DNS2   If  the peer supplies DNS server addresses, this variable is set 
  65.               to the second DNS server address supplied. 
  66.  
  67.        Pppd invokes the following scripts, if they exist.  It is not an  error 
  68.        if they don't exist. 
  69.  
  70.        /etc/ppp/auth-up 
  71.               A  program  or  script which is executed after the remote system 
  72.               successfully authenticates itself.   It  is  executed  with  the 
  73.               parameters 
  74.  
  75.               interface-name peer-name user-name tty-device speed 
  76.  
  77.               Note  that  this  script  is  not  executed  if the peer doesn't 
  78.               authenticate itself, for example when the noauth option is used. 
  79.  
  80.        /etc/ppp/auth-down 
  81.               A program or script which is executed when the link  goes  down, 
  82.               if  /etc/ppp/auth-up was previously executed.  It is executed in 
  83.               the same manner with the same parameters as /etc/ppp/auth-up. 
  84.  
  85.        /etc/ppp/ip-pre-up 
  86.               A program or script which is executed just before the  ppp  net- 
  87.               work  interface  is  brought  up.   It is executed with the same 
  88.               parameters as the ip-up  script  (below).   At  this  point  the 
  89.               interface  exists  and  has  IP  addresses assigned but is still 
  90.               down.  This can be used to add  firewall  rules  before  any  IP 
  91.               traffic can pass through the interface.  Pppd will wait for this 
  92.               script to finish before  bringing  the  interface  up,  so  this 
  93.               script should run quickly. 
  94.  
  95.        /etc/ppp/ip-up 
  96.               A program or script which is executed when the link is available 
  97.               for sending and receiving IP packets (that  is,  IPCP  has  come 
  98.               up).  It is executed with the parameters 
  99.  
  100.               interface-name       tty-device      speed      local-IP-address 
  101.               remote-IP-address ipparam 
  102.  
  103.        /etc/ppp/ip-down 
  104.               A program or script which is executed when the link is no longer 
  105.               available for sending and receiving IP packets.  This script can 
  106.               be used for  undoing  the  effects  of  the  /etc/ppp/ip-up  and 
  107.               /etc/ppp/ip-pre-up  scripts.   It  is invoked in the same manner 
  108.               and with the same parameters as the ip-up script. 
  109.  
  110.        /etc/ppp/ipv6-up 
  111.               Like /etc/ppp/ip-up, except that it is executed when the link is 
  112.               available for sending and receiving IPv6 packets. It is executed 
  113.               with the parameters 
  114.  
  115.               interface-name   tty-device    speed    local-link-local-address 
  116.               remote-link-local-address ipparam 
  117.  
  118.        /etc/ppp/ipv6-down 
  119.               Similar  to /etc/ppp/ip-down, but it is executed when IPv6 pack- 
  120.               ets can no longer be transmitted on the  link.  It  is  executed 
  121.               with the same parameters as the ipv6-up script. 
  122.  
  123.        /etc/ppp/ipx-up 
  124.               A program or script which is executed when the link is available 
  125.               for sending and receiving IPX packets (that is, IPXCP  has  come 
  126.               up).  It is executed with the parameters 
  127.  
  128.               interface-name       tty-device       speed       network-number 
  129.               local-IPX-node-address  remote-IPX-node-address  local-IPX-rout- 
  130.               ing-protocol  remote-IPX-routing-protocol  local-IPX-router-name 
  131.               remote-IPX-router-name ipparam pppd-pid 
  132.  
  133.               The local-IPX-routing-protocol  and  remote-IPX-routing-protocol 
  134.               field may be one of the following: 
  135.  
  136.               NONE      to indicate that there is no routing protocol 
  137.               RIP       to indicate that RIP/SAP should be used 
  138.               NLSP      to indicate that Novell NLSP should be used 
  139.               RIP NLSP  to indicate that both RIP/SAP and NLSP should be used 
  140.  
  141.        /etc/ppp/ipx-down 
  142.               A program or script which is executed when the link is no longer 
  143.               available for sending and receiving IPX  packets.   This  script 
  144.               can  be  used  for  undoing  the  effects of the /etc/ppp/ipx-up 
  145.               script.  It is invoked in the same  manner  and  with  the  same 
  146.               parameters as the ipx-up script. 

这就是ppp的脚本内容,里面当然有变量咯,这些变量就是我们需要的。

好了,那么开始进行日志整理吧,首先是ip-up

  1. vim /etc/ppp/ip-up 
  2. #!/bin/sh 
  3. # This script is run by the pppd after the link is established. 
  4. # It uses run-parts to run scripts in /etc/ppp/ip-up.d, so to add routes, 
  5. # set IP address, run the mailq etc. you should create script(s) there. 
  6. # Be aware that other packages may include /etc/ppp/ip-up.d scripts (named 
  7. # after that package), so choose local script names with that in mind. 
  8. # This script is called with the following arguments: 
  9. #    Arg  Name                          Example 
  10. #    $1   Interface name                ppp0 
  11. #    $2   The tty                       ttyS1 
  12. #    $3   The link speed                38400 
  13. #    $4   Local IP number               12.34.56.78 
  14. #    $5   Peer  IP number               12.34.56.99 
  15. #    $6   Optional ``ipparam'' value    foo 
  16.  
  17. # The  environment is cleared before executing this script 
  18. # so the path must be reset 
  19. PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin 
  20. export PATH 
  21.  
  22. # These variables are for the use of the scripts run by run-parts 
  23. PPP_IFACE="$1" 
  24. PPP_TTY="$2" 
  25. PPP_SPEED="$3" 
  26. PPP_LOCAL="$4" 
  27. PPP_REMOTE="$5" 
  28. PPP_IPPARAM="$6" 
  29. export PPP_IFACE PPP_TTY PPP_SPEED PPP_LOCAL PPP_REMOTE PPP_IPPARAM 
  30.  
  31. # as an additional convenience, $PPP_TTYNAME is set to the tty name, 
  32. # stripped of /dev/ (if present) for easier matching. 
  33. PPP_TTYNAME=`/usr/bin/basename "$2"` 
  34. export PPP_TTYNAME 
  35.  
  36. # If /var/log/ppp-ipupdown.log exists use it for logging. 
  37. if [ -e /var/log/ppp-ipupdown.log ]; then 
  38.   exec > /var/log/ppp-ipupdown.log 2>&1 
  39.   echo $0 $@ 
  40.   echo 
  41. fi 
  42.  
  43. # This script can be used to override the .d files supplied by other packages. 
  44. if [ -x /etc/ppp/ip-up.local ]; then 
  45.   exec /etc/ppp/ip-up.local "$@" 
  46. fi 
  47.  
  48. run-parts /etc/ppp/ip-up.d \ 
  49.   --arg="$1" --arg="$2" --arg="$3" --arg="$4" --arg="$5" --arg="$6" 
  50.  
  51. # if pon was called with the "quick" argument, stop pppd 
  52. if [ -e /var/run/ppp-quick ]; then 
  53.   rm /var/run/ppp-quick 
  54.   wait 
  55.   kill $PPPD_PID 
  56. fi 
  57.  
  58. /sbin/iptables -t nat -A POSTROUTING -s  172.16.36.0/24 -j SNAT --to-source "serverip" 这里设置每次登陆时候都设定一次路由转发,避免失效。 
  59.  
  60. echo "****************************************************" > /var/log/pptpd-${1}.log 将所有内容导入到pptpd-${1}.log,以防多用户登陆时候造成日志混乱 
  61. echo "username: $PEERNAME" >> /var/log/pptpd-${1}.log 
  62. echo "clientIP: $6" >> /var/log/pptpd-${1}.log 
  63. echo "device: $1" >> /var/log/pptpd-${1}.log 
  64. echo "vpnIP: $4" >> /var/log/pptpd-${1}.log 
  65. echo "assignIP: $5" >> /var/log/pptpd-${1}.log 
  66. echo "logintime: `date -d today +%F_%T`" >> /var/log/pptpd-${1}.log 

然后是ip-up的处理:

  1. vim /etc/ppp/ip-down 
  2. #!/bin/sh 
  3. # This script is run by the pppd _after_ the link is brought down. 
  4. # It uses run-parts to run scripts in /etc/ppp/ip-down.d, so to delete 
  5. # routes, unset IP addresses etc. you should create script(s) there. 
  6. # Be aware that other packages may include /etc/ppp/ip-down.d scripts (named 
  7. # after that package), so choose local script names with that in mind. 
  8. # This script is called with the following arguments: 
  9. #    Arg  Name                          Example 
  10. #    $1   Interface name                ppp0 
  11. #    $2   The tty                       ttyS1 
  12. #    $3   The link speed                38400 
  13. #    $4   Local IP number               12.34.56.78 
  14. #    $5   Peer  IP number               12.34.56.99 
  15. #    $6   Optional ``ipparam'' value    foo 
  16.  
  17. # The  environment is cleared before executing this script 
  18. # so the path must be reset 
  19. PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin 
  20. export PATH 
  21.  
  22. # These variables are for the use of the scripts run by run-parts 
  23. PPP_IFACE="$1" 
  24. PPP_TTY="$2" 
  25. PPP_SPEED="$3" 
  26. PPP_LOCAL="$4" 
  27. PPP_REMOTE="$5" 
  28. PPP_IPPARAM="$6" 
  29. export PPP_IFACE PPP_TTY PPP_SPEED PPP_LOCAL PPP_REMOTE PPP_IPPARAM 
  30.  
  31. # as an additional convenience, $PPP_TTYNAME is set to the tty name, 
  32. # stripped of /dev/ (if present) for easier matching. 
  33. PPP_TTYNAME=`/usr/bin/basename "$2"` 
  34. export PPP_TTYNAME 
  35.  
  36. # If /var/log/ppp-ipupdown.log exists use it for logging. 
  37. if [ -e /var/log/ppp-ipupdown.log ]; then 
  38.   exec >> /var/log/ppp-ipupdown.log 2>&1 
  39.   echo $0 $@ 
  40.   echo 
  41. fi 
  42.  
  43.  
  44. echo "downtime: `date -d today +%F_%T`" >> /var/log/pptpd-${1}.log 
  45. echo "bytes sent: $BYTES_SENT" >> /var/log/pptpd-${1}.log 
  46. echo "bytes received: $BYTES_RCVD" >> /var/log/pptpd-${1}.log 
  47. echo "connect time: $CONNECT_TIME" >> /var/log/pptpd-${1}.log 
  48. echo "****************************************************" >> /var/log/pptpd-${1}.log 
  49. cat /var/log/pptpd-${1}.log >> /var/log/pptpd.log
  50.  
  51.  
  52.  
  53. # This script can be used to override the .d files supplied by other packages. 
  54. if [ -x /etc/ppp/ip-down.local ]; then 
  55.   exec /etc/ppp/ip-down.local "$@" 
  56. fi 
  57.  
  58. run-parts /etc/ppp/ip-down.d \ 
  59.   --arg="$1" --arg="$2" --arg="$3" --arg="$4" --arg="$5" --arg="$6" 

最后就可以通过/var/log/pptpd.log文件进行查看PPTP VPN日志了。日志形式如下,需要更美观的自行修改代码:

  1. **************************************************** 
  2. username: nenew 
  3. clientIP: XXX.XXX.XXX.XXX 
  4. device: ppp0 
  5. vpnIP: 172.16.36.1 
  6. assignIP: 172.16.36.2 
  7. logintime: 2015-08-03_17:06:05 
  8. downtime: 2015-08-03_17:06:23 
  9. bytes sent: 164143 
  10. bytes received: 51606 
  11. connect time: 18 
  12. **************************************************** 
linux下命令行上传下载测速

 

好吧,最近搞了个香港服务器,但是香港带宽限制比较严格,当然不能吃亏了,测速,必须测速。

今天主角出场speedtest-cli,它工作在Python 2.4-3.4

安装:

  1. pip / easy_install 
  2.  
  3. pip install speedtest-cli 
  4.  
  5. or 
  6.  
  7. easy_install speedtest-cli 
  8.  
  9. Github 
  10.  
  11. pip install git+https://github.com/sivel/speedtest-cli.git 
  12.  
  13. or 
  14.  
  15. git clone https://github.com/sivel/speedtest-cli.git 
  16. python speedtest-cli/setup.py install 
  17.  
  18. Just download (Like the way it used to be) 
  19.  
  20. wget -O speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest_cli.py 
  21. chmod +x speedtest-cli 
  22.  
  23. or 
  24.  
  25. curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest_cli.py 
  26. chmod +x speedtest-cli 

功能和使用:

  1. $ speedtest-cli -h 
  2. usage: speedtest-cli [-h] [--bytes] [--share] [--simple] [--list] 
  3.                      [--server SERVER] [--mini MINI] [--source SOURCE] 
  4.                      [--timeout TIMEOUT] [--version] 
  5.  
  6. Command line interface for testing internet bandwidth using speedtest.net. 
  7. -------------------------------------------------------------------------- 
  8. https://github.com/sivel/speedtest-cli 
  9.  
  10. optional arguments: 
  11.   -h, --help         show this help message and exit 
  12.   --bytes            Display values in bytes instead of bits. Does not affect 
  13.                      the image generated by --share 
  14.   --share            Generate and provide a URL to the speedtest.net share 
  15.                      results image 
  16.   --simple           Suppress verbose output, only show basic information 
  17.   --list             Display a list of speedtest.net servers sorted by 
  18.                      distance 
  19.   --server SERVER    Specify a server ID to test against 
  20.   --mini MINI        URL of the Speedtest Mini server 
  21.   --source SOURCE    Source IP address to bind to 
  22.   --timeout TIMEOUT  HTTP timeout in seconds. Default 10 
  23.   --version          Show the version number and exit 

简单测速,奶牛是在ubuntu下进行的测试:

  1. apt-get install python-pip 
  2. pip install speedtest-cli 

安装完成后执行:

  1. speedtest 

测试结果如下:

  1. root@gameserver1:~# speedtest  
  2. Retrieving speedtest.net configuration...  
  3. Retrieving speedtest.net server list...  
  4. Testing from Shanghai Anchnet Network Technology (XXX.XXX.XXX.XXX)...  
  5. Selecting best server based on latency...  
  6. Hosted by Shanghai Branch, China Unicom (Shanghai) [19.64 km]: 29.249 ms  
  7. Testing download speed........................................  
  8. Download: 18.84 Mbit/s  
  9. Testing upload speed..................................................  
  10. Upload: 1.51 Mbit/s  

 

Emmet For Notepad++的安装方法教程

按照官方的方法教程,安装方法有两种。

第一种:用插件管理器安装,打开插件—插件管理器—显示插件下找到emmet插件安装

第二种:手动方法。

先安装Python Script插件,官方教程上说可以在插件管理器里面安装。下载EmmetNPP 插件,解压缩到 C:\Program Files\Notepad++\plugins 安装目录,启动notepad++就可以看到Emmet插件了。

官方建议是将快捷键Abbreviation设置为tab

但是,奶牛在安装的过程中发现上面的方法不可行,因为插件根本不工作。有Unknown exception和python script plugin did not accept the script错误提示,环境是win8.1 x64位系统,找到解决方法是Python Script插件问题,下载Python Script插件重新安装解决了此问题。

php的preg_match_all函数手册

 

preg_match_all

(PHP 4, PHP 5)

preg_match_all执行一个全局正则表达式匹配

说明

int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )

搜索subject中所有匹配pattern给定正则表达式 的匹配结果并且将它们以flag指定顺序输出到matches中.

在第一个匹配找到后, 子序列继续从最后一次匹配位置搜索.

参数

pattern

要搜索的模式,字符串形式。

subject

输入字符串。

matches

多维数组,作为输出参数输出所有匹配结果, 数组排序通过flags指定。

flags

可以结合下面标记使用(注意不能同时使用PREG_PATTERN_ORDERPREG_SET_ORDER):

PREG_PATTERN_ORDER

结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。

<?php
preg_match_all
("|<[^>]+>(.*)</[^>]+>|U",
    
"<b>example: </b><div align=left>this is a test</div>",
    
$outPREG_PATTERN_ORDER);
echo 
$out[0][0] . ", " $out[0][1] . "\n";
echo 
$out[1][0] . ", " $out[1][1] . "\n";
?>

以上例程会输出:

<b>example: </b>, <div align=left>this is a test</div>
example: , this is a test

因此, $out[0]是包含匹配完整模式的字符串的数组, $out[1]是包含闭合标签内的字符串的数组。

PREG_SET_ORDER

结果排序为$matches[0]包含第一次匹配得到的所有匹配(包含子组), $matches[1]是包含第二次匹配到的所有匹配(包含子组)的数组,以此类推。

<?php
preg_match_all
("|<[^>]+>(.*)</[^>]+>|U",
    
"<b>example: </b><div align=\"left\">this is a test</div>",
    
$outPREG_SET_ORDER);
echo 
$out[0][0] . ", " $out[0][1] . "\n";
echo 
$out[1][0] . ", " $out[1][1] . "\n";
?>

以上例程会输出:

<b>example: </b>, example:
<div align="left">this is a test</div>, this is a test
PREG_OFFSET_CAPTURE

如果这个标记被传递,每个发现的匹配返回时会增加它相对目标字符串的偏移量。 注意这会改变matches中的每一个匹配结果字符串元素,使其 成为一个第0个元素为匹配结果字符串,第1个元素为 匹配结果字符串在subject中的偏移量。

如果没有给定排序标记,假定设置为PREG_PATTERN_ORDER

offset

通常, 查找时从目标字符串的开始位置开始。可选参数offset用于 从目标字符串中指定位置开始搜索(单位是字节)。

Note:

使用 offset 参数不同于传递 substr($subject, $offset) 的 结果到 preg_match_all() 作为目标字符串,因为 pattern 可以包含断言比如^$ 或者 (?<=x) 。 示例查看 preg_match()

返回值

返回完整匹配次数(可能是0),或者如果发生错误返回FALSE

更新日志

版本说明
5.4.0参数matches成为可选的。
5.3.6如果 offset 大于 subject 的程度,将返回 FALSE
5.2.2子命名分组语法可以接受(?<name>)(?’name’)以及 (?P<name>)了。 之前版本仅接受(?P<name>)方式。
4.3.3增加了offset参数。
4.3.0增加了PREG_OFFSET_CAPTURE标记。

范例

Example #1 查找所有文本中的电话号码。

<?php
preg_match_all
("/\(?  (\d{3})?  \)?  (?(1)  [\-\s] ) \d{3}-\d{4}/x",
                
"Call 555-1212 or 1-800-555-1212"$phones);
?>

Example #2 查找匹配的HTML标签(贪婪)

<?php
//\\2是一个后向引用的示例. 这会告诉pcre它必须匹配正则表达式中第二个圆括号(这里是([\w]+))
//匹配到的结果. 这里使用两个反斜线是因为这里使用了双引号.
$html "<b>bold text</b><a href=howdy.html>click me</a>";

 

preg_match_all("/(<([\w]+)[^>]*>)(.*?)(<\/\\2>)/"$html$matchesPREG_SET_ORDER);

foreach ($matches as $val) {
    echo 
"matched: " $val[0] . "\n";
    echo 
"part 1: " $val[1] . "\n";
    echo 
"part 2: " $val[2] . "\n";
    echo 
"part 3: " $val[3] . "\n";
    echo 
"part 4: " $val[4] . "\n\n";
}
?>

以上例程会输出:

matched: <b>bold text</b>
part 1: <b>
part 2: b
part 3: bold text
part 4: </b>

matched: <a href=howdy.html>click me</a>
part 1: <a href=howdy.html>
part 2: a
part 3: click me
part 4: </a>

Example #3 使用子命名组

<?php

 

$str = <<<FOO
a: 1
b: 2
c: 3
FOO;

preg_match_all('/(?P<name>\w+): (?P<digit>\d+)/'$str$matches);

/* 下面代码在php 5.2.2(pcre 7.0)或更高版本下工作, 不过, 为了向后兼容
 * 推荐使用上面的方式. */
// preg_match_all('/(?<name>\w+): (?<digit>\d+)/', $str, $matches);

print_r($matches);

?>

以上例程会输出:

Array
(
    [0] => Array
        (
            [0] => a: 1
            [1] => b: 2
            [2] => c: 3
        )

    [name] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

    [1] => Array
        (
            [0] => a
            [1] => b
            [2] => c
        )

    [digit] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

    [2] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

)
RSS的一些原理介绍

 

1.   令网络跳动的力量
1.1.RSS
最近在浏览许多新闻网站时,用户都会惊奇的发现一些写有 “XML”字样的桔黄色图标频繁出现。如果使用普通浏览器的用户点击后只能看到一个写满了天书的页面。这是一种最近十分流行的网络技术,被称为 RSS(Really Simple Syndication)。通过专用的RSS阅读工具,用户能够快速浏览大量的网页内容,如新闻或者网络日志。最初RSS主要是应用在民间的网络日志之 中。但由于其易用性迅速受到了欢迎。如今Businessweek、Forbes和New York Times等著名传统媒体的网站中,也都添加了RSS功能。
使用RSS阅读工具的用户可以订阅自己关注的网站的内容,点击那个桔黄色的图标便可以得到RSS种子并且保存到阅读工具中。RSS阅读工具会自动连接那些网站检查并显示更新内容的标题和摘要内容。
看起来时髦、新奇的RSS技术其实早在1997年左右就 已经开发出来,但直到今天才焕发光彩。这其中一个很大的原因是数百万网络日志的出现造成了用户的阅读困难。越来越多的公司开始关注RSS技术,除了那些开 发RSS阅读软件的厂商外,苹果公司的Safari浏览器就内置了RSS阅读工具。而且微软也计划在未来版本的IE浏览器中支持RSS阅读。而另一些 RSS服务提供商则支持在线RSS阅读功能,Bloglines是它们中最有名的家伙。
1.2.Tag
同RSS技术类似,Tag也是用来对付越来越多的网络信 息的。而它的功能则主要是内容分类。用过Gmail的用户应该熟悉Tag,在信箱中用户可以为每封邮件添加多个关键字分类信息,比如工作、广告、计划书、 已完成等随心所欲的分类。而检索时可以按照其中任何一个或者几个Tag关键字进行搜索。这极大丰富了检索信息的方法和结果的准确性。
例如我曾经在某个网站上看到了一篇关于效力于NBA骑士 队的立陶宛球星伊尔戈斯卡斯讲述他家乡的故事,而当我想再次阅读这篇文章时却无法记起这个立陶宛人拗口的名字,而对他的家乡是哪儿也毫无印象。我如何搜索 得到这篇文章呢?Tag就能够帮助我解决这个问题,当我看到这篇文章的时候,可以把它的链接保存在del.icio.us等网络书签中,然后为其添加一个 NBA的Tag。这样日后当我检索的时候就能够轻松的把它找到。忘掉那些存储文件夹吧!
Yahoo公司目前十分重视Tag技术,因为它代表了一 种新的组织和管理在线信息的方式。它不同于传统的、针对文件本身的关键字检索,而是一种模糊化、智能化的分类。这更加符合用户使用的顺滑感和提高检索结果 的相似程度,将会极大的促进用户查询数字文件的能力,照片、视频等多媒体数字文件都可以打上Tag的标签进行管理。Tag本身绝对无法取代Yahoo和 Google这样的搜索引擎,但如果日后Tag的应用逐渐增长,那么搜索引擎的使用量一定会减少。
1.3.Wiki
几乎所有人了解Wiki都是从网络上开放百科全书Wikipedia,开始的,在这之前没有人见过这样一个任何人都可以动手修改的网站。从2001年开始,成千上万名志愿者以50种语言完成了这部网络百科全书中500万篇文章,这一切都得感谢Wiki!
Wiki一词来源于夏威夷语的“wee kee wee kee”,原本是“快点快点”的意思。沃德·坎宁安在1995年创建了Wiki的概念和相应的服务系统。这套系统允许那些对编程语言一无所知的人们随意对一个网站内容进行添加、修改。
而如今有软件开发商根据Wiki的理论和机制开发出了协 同工作软件。IBM公司的Lotus Notes就属于同类产品。TWiki公司开发的开放源代码Wiki软件自2001年至今已有3.5万人次下载。而这些被下载的程序有2/3用于商业用 途,使用者包括迪斯尼、SAP和摩托罗拉这样声名赫赫的公司。
2.   什么是RSS?
也许大家是第一次听到RSS这个概念,那什么是RSS呢?RSS是站点用来和其他站点之间共享内容的一种简易方式(也叫聚合内容),通常被用于新闻和其他按顺序排列的网站,例如Blog。
一段项目的介绍可能包含新闻的全部介绍等。或者仅仅是额外的内容或者简短的介绍。这些项目的链接通常都能链接到全部的内容。网络用户可以在客户端借助于支持RSS的新闻聚合工具软件,在不打开网站内容页面的情况下阅读支持RSS输出的网站内容。
说得更加简单一点,RSS就是一种用来分发和汇集网页内容的XML格式!如果你还是不太明白,没有关系,RSS是什么其实基本就不重要,重要的是RSS可以做什么,下面我们就来了解一下,RSS能给我们带来什么?
2.1.小知识
  BLOG:BLOG是Web Log的简称。在国内,人们通常称它为博客。它是一种作者与读者以日记风格进行交互的中介。在软件社区,人们以博客形式来共享观念与思想变得越来越流行,人们开始以博客的形式互相学习,博客已经成了一个技术交流的场所!如:http://blogs.msdn.com 就是MSDN上的一个blogging。而在国内博客中国也已经越来越有名。http://www.blogchina.com
  XML:XML是Extensible Markup Language的简写,一种扩展性标识语言。
3.   可以干什么?RSS
1.       订阅BLOG(BLOG上,你可以订阅你工作中所需的技术文章;也可以订阅与你有共同爱好的作者的日志,总之,BLOG上你对什么感兴趣你就可以订什么)。
2.       订阅新闻(无论是奇闻怪事、明星消息、体坛风云,只要你想知道的,都可以订阅)。
你再也不用一个网站一个网站,一个网页一个网页去逛了。只要这将你需要的内容订阅在一个RSS阅读器中,这些内容就会自动出现你的阅读器里,你也不必为了一个急切想知道的消息而不断的刷新网页,因为一旦有了更新,RSS阅读器就会自己通知你!
4.   怎样发布RSS内容
首先你需要理解一点支持RSS的技术。
1.RSS是包含你要发布的信息(标题、简介、内容等信息)的标准的XML文件。它遵循所谓的RSS技术规范定义的格式。
2.RSS文件本身定义的是内容,并没有定义内容的显示方式。通常要通过RSS阅读器来解析内容,并显示出来。看天下RSS阅读器就是用来解读RSS内容的。
3.由于Blog等的发展,使得创建RSS文件变得很容易。
怎样让更多的人接收到你的RSS?到目前为止,大多数人并不对RSS很熟悉。但由于RSS避免了无用的广告和垃圾信息,这种方式在逐渐地普及开来。
那么你在采用RSS的时候,就应该尽可能地给你的用户讲解什么是RSS,以及它有哪些优点。
5.   RSS阅读器
目前,RSS阅读器基本可以分为两类。
第一类大多数阅读器是运行在计算机桌面上的单机应用程序,通过所订阅网站和博客(blog) 中的新闻供应,可自动、定时地更新新闻标题。在该类阅读器中,有Awasu、FeedDemon和RSSReader这三款流行的单机版阅读器都提供免费 试用版和付费高级版,另外,新华网在不久前也推出了一款RSS阅读器,它不仅是完全是中文界面,而且目前还是完全的免费软件!(后面我们就将以这款软件为 例,为大家介绍怎样来使用RSS阅读器)。
第二类新闻阅读器通常是内嵌于已在计算机中运行的应用程序中。例如,NewsGator内嵌在微软的Outlook中,所订阅的新闻标题位于Outlook的收件箱文件夹中。另外,Pluck内嵌在Internet Explorer浏览器中!
6.   推” 技术远胜于电子邮件的推广模式RSS“
几乎每一个内容提供者都有过用一个长长的电子邮件地址簿 发布新信息的经验。RSS“推”技术将从此改变这个现状。利用RSS阅读器接收“推”来的新信息不仅消除了“垃圾邮件”充斥邮箱的烦恼,而且使内容接收者 更方便地阅读和管理信息。因此,尽管利用电子邮件的推广方式还将在很长时间内存在,用户将越来越偏好使用RSS“推” 技术的内容提供商。
RSS优于电子邮件还体现在网络安全上。由于没有不速之客的“垃圾邮件”,也没有邮件提供商(象YAHOO,MSN)的“强力过滤”,用户将有十分的信心他们看到的就是他们订阅的,不多也不少。
不仅如此,即使到达用户信箱中的合法推广信息也还有一大 部分由于与少数“漏网”的垃圾邮件和众多其它邮件的混合而被用户忽视甚至直接删除。更不用说当用户因为信箱装满了垃圾而转用新地址时,绝大多数情况下是想 不起来在所有内容提供者那里更新地址的。这些无疑都是对内容提供者来说巨大的浪费!
我的朋友们有很多是网上内容发布者,他们都发现新用户注册后不出几个月,这些邮件地址就失效了,而他们也就永远失去了和这些用户联络的渠道。所以,我建议所有内容提供者都认真地考虑利用RSS“推” 技术来与用户建立持久稳定的关系,这在长期来讲是绝对有利的。
最后,RSS优于电子邮件还在于目前的一些RSS内容聚 合商(如看天下www.kantianxia.com)帮助支持RSS“推”技术的内容提供者向用户作宣传。如看天下的“RSS内容源索引”就是一个使用 户发现并接受新内容源的增值平台 – 这与搜索引擎把内容聚合起来向用户作推广是一个概念。
目前,越来越多的用户已经开始认识并接受RSS技术。我衷心希望所有的内容提供者都能顺应这个潮流,在这个新的平台上取得更好的成绩。
7.   认识RSS
以下内容是为了让大家更加了解RSS,如果你对其不感兴趣,完全可以不看,它不会对你使用RSS阅读产生多大的影响。
7.1.Feed(提要)
博客以RSS文档形式为其内容提供一个提要,该RSS文档可以通过众所周知的URL获得。RSS文档是一个XML文件,它包含大量离散的新闻项,如某个博客中的入口项。由于RSS是XML格式文件,所以它很容易被其它程序所使用。
RSS聚合器是一个读取RSS文档并显示新闻项的程序。大多数聚合器只要输入RSS的URL,使得预定提要成为可能。
RSS使阅读博客便得容易。大多数经常阅读博客的开发人员都使用某种类型的聚合器来帮助他们有效地筛选提要内容。聚合器使得阅读博客的感觉就象是在阅读电子邮件,因为它们突出新闻项并将新闻项进行缓冲处理以便离线阅读。
还有一些在线RSS聚合器将RSS提要捆绑到某个单独的网站。其优点是易于设置并且可以从任何计算机存取你的提要内容。当然,其缺点也是显而易见的,那就是在阅读时必须始终保持连接。
RSS是博客成为一种强大的新型信息交流形式之根本所在。在网志出现之前,大多数开发人员为了要查找到需要的内容,通常要花大量时间来筛选掉那些令人讨厌的无关的信息。
博客通过让读者选择所要阅读的提要,将控制权交给读者,从而有效地构建自己的个性化内容流。
7.2.RSS版本
RSS的版本有很多个,0.90、 0.91、0.92、0.93、0.94、1.0 和 2.0。要理解它们需要了解一些有关它们的历史背景。最初Netscape创建了RSS的最初版本0.90,起初的名字是“RDF Site Summary”或者“Rich Site Summary”(规范中说前者是正式名称)。Netscape创建RSS0.90用于其Web门户,这个时候,其他人看到了RSS的使用潜力。 Userland Software是第一个开始将 RSS 用于其网志商业产品者之一。
版本 0.90 在很大程度上基于 W3C 的 Resource Description Framework (RDF)。许多人都认为 RDF 过于复杂,因此都建议出一个免费的简化版本 0.91。这个任务恰好就给了 Userland Software。Userland Software 便继续发展 RSS 的简化版本,随后出台的版本包括:0.92、0.93 和 0.94。为了强调其所做的简化工作,他们将 RSS 的全称定为“Really Simple Syndication”。
正当Userland Software继续专注于其简化工作时,另外一组开发人员在复兴最初的RDF版本(0.90),因为RSS号称自己更灵活。他们最终发布了一个RSS 1.0的版本,其正式名称还是“RDF Site Summary”。由于使用RDF,这个版本完全不同于 Userland Software所控制的版本。Userland Software当然不太愿意看到RSS 1.0似乎要取代其0.94版本的事实,于是出了一个新版本,并将版本号一下子跳到了2.0。
这就是今天的这种局面,形成了两个主要的竞争版本:一个基于RDF1.0, 而另一个则是由Userland Software所开发的2.0,由于它们两个都共用相同的名字。就成为一种可怕的混乱,因为版本号导致人们误认为2.0是1.0的改进版本,而实际上它 们是两个目标完全不同的规范。现在,另一组开发人员已经下狠心着手解决这种混乱问题,通过定义新的摘要(syndication)规范来与 RSS名字的随意性决裂。这个解决方案称为 Atom(原子)项目。
7.3.Atom(原子)
Atom是一个项目的名字,主要是开发一个新的博客摘要格式以解决目前RSS存在的问题(混乱的版本号,不是一个真正的开放标准,表示方法的不一致,定义贫乏等等)。Atom 希望提供一个清晰的版本以解决每个人的需要,其设计完全不依赖于供货商,任何人都可以对之进行自由扩展,完整详细说明。
除了定义新的摘要格式之外,Atom还希望定义一个标准的档案文件格式和一个标准的博客编辑API(Atom API)。
其实RSS1.0和2.0格式所包含的核心信息是相同的,只是其结构不一样罢了,这里我们不再继续深入的讨论这个问题,有兴趣的朋友可以去博客中国里了解相关知识!
7.4.blogroll
blogroll是博客页面提要的集合,大多数博客在其个人页面上都提供blogroll。这就允许读者连接到其他趣味和写作风格相投的人的网页上。Blogroll方便了网络上的沟通。通过使用Outline Processor Markup Language(OPML),人们可以用XML 格式文件交换blogroll。
大多数网志引擎都自己管理blogroll,每当读者请求blogroll时都自己产生相应的XML格式。同样,大多数聚合器(RSS阅读器)都能导入blogroll并自动预定所包含的摘要。
8.   RSS 2.0
8.1.RSS2.0新特性
RSS 2.0 建立在 RSS 0.91 规范的基础上。它是向后兼容的,因此任何处理 RSS 2.0 的工具应该也能够处理 0.91 提要。升级后的规范增加了少量元素,比如 <cloud> 和 <guid>。
它也去掉了一些限制。在过去,<link> 和 <url> 元素只能是 http 或 ftp,现在可以使用任何有效的 URI。在 RSS 0.91 中,每个频道只能包含 15 个项,而且元素的长度也有限制,现在这些限制都取消了。不过仍然应该小心使用较大的值,因为它们可能对老的应用程序造成问题。
不过更大的变化是能够使用名称空间扩展这种格式。RSS 2.0 支持名称空间,一种增加规范中没有的元素的标准方法。只要定义在一个名称空间中,提要可以包含新的元素。
8.2.RSS 2.0 概述
RSS 是一种 XML 方言,用于连锁 Web 内容和元数据。RSS 0.91 是几种可用版本中最常用的一种。对于新的 RSS 提要,更好的办法是使用 2.0 版,因为这是现行的规范,而且如前所述,它与 0.91 向后兼容。
Dave Winer 编写了规范的 2.0 版。规范的修改可能变得难以使用,或者损害已有的应用程序,他有意识地避免了这种情况。Winer 总结了他的思想:“保持简单。这就是 RSS 的价值所在。任何稍微了解 HTML 的人都能够理解 RSS。这一点极其重要!”
该规范在 Creative Commons 许可下发布(请参阅参考资料)。这意味着您可以免费复制和分发该规范,并进行衍生工作,而且可以自由地用于商业工作。一个咨询委员会负责更新规范、推广规范和编写文档。
8.3.发现 RSS 提要
可以使用搜索引擎查找 RSS 格式的内容。比方说使用 Google 时,您可以在查找中增加“filetype:rss”以搜索 .rss 文件中的查找项。
专门的搜索引擎使内容搜索更加容易。Feedster 监视 weblog 并允许您通过一个日志项索引查找,按照相关性、日期、等级(logrank)查看。当您在搜索时,Feedster 按照您的要求创建一个 RSS 提要。这个提要可以增加到您的新闻阅读器中,以便您能够看到所有与搜索请求有关的最新活动,您甚至不需要离开新闻阅读器。
DayPop 搜索新闻、blog 和 RSS 提要。它让您在 weblog 世界跟踪流行的新闻。它提供了目前最流行的 40 个 weblog 链接。这是全世界最流行文章的链接。它创建了一个 weblog 中所用最热门词汇的列表。它还根据引用对 weblog 评级,提供最受其他 weblogger 欢迎的 weblog 列表。您也可以自定义搜索。评级列表和自定义搜索都有 RSS 提要形式,可以导入您的新闻阅读器。
8.4.RSS 文件形式
RSS 文件由一个 <channel> 元素及其子元素组成。除了频道内容本身之外,<channel> 还以项的形式包含表示频道元数据的元素 —— 比如 <title>、<link> 和 <description>。项通常是频道的主要部分,包含经常变化的内容。
8.4.1.    频道
频道一般有三个元素,提供关于频道本身的信息:
<title>:频道或提要的名称。
<link>:与该频道关联的 Web 站点或者站点区域的 URL。
<description>:简要介绍该频道是做什么的。
许多频道子元素都是可选的。常用的 <image> 元素包含三个必需的子元素:
<url>:表示该频道的 GIF、JPEG 或 PNG 图像的 URL。
<title>:图象的描述。当频道以 HTML 呈现时,用作 HTML <image> 标签的 ALT 属性。
<link>:站点的 URL。如果频道以 HTML 呈现,该图像作为到这个站点的链接。
<image> 还有三个可选的子元素:
<width>:数字,表示图象的像素宽度,最大值是 188,默认值为 88。
<height>:数字,表示图象的像素高度。最大值是 400,默认值为 31。
<description>:包含文本,在呈现时可以作为围绕着该图像形成的链接元素的 title 属性。
此外还可以使用许多其他可选的频道元素。多数都是不言自明的:
<language>:en-us
<copyright>:Copyright 2003, James Lewin
<managingEditor>:dan@spam_me.com (Dan Deletekey)
<webMaster>:dan@spam_me.com (Dan Deletekey)
<pubDate>:Sat, 15 Nov 2003 0:00:01 GMT
<lastBuildDate>:Sat, 15 Nov 2003 0:00:01 GMT
<category>:ebusiness
<generator>:Your CMS 2.0
<docs>:http://blogs.law.harvard.edu/tech/rss
<cloud>:允许进程注册为“cloud”,频道更新时通知它,为 RSS 提要实现了一种轻量级的发布-订阅协议。
<ttl>:存活时间 是一个数字,表示提要在刷新之前缓冲的分钟数。
<rating>:关于该频道的 PICS 评价。
<textInput>:定义可与频道一起显示的输入框。
<skipHours>:告诉聚集器哪些小时的更新可以忽略。
<skipDays>:告诉聚集器那一天的更新可以忽略。
8.4.2.   
项通常是提要中最重要的部分。每个项都可以关于某个 weblog、完整文档、电影评论、分类广告或者任何希望与频道连锁的内容的记录。频道中的其他元素可能不变,但项经常发生变化。
您可以有任意多个项。以前的规范限值为 15 个项,如果要保持向后兼容这仍然是一个很好的上限。
8.4.3.    新闻项的元素
每个项通常包含三个元素:
<title>:这是项的名称,在标准应用中被转换成 HTML 中的标题。
<link>:这是该项的 URL。title 通常作为一个链接,指向包含在 <link> 元素中的 URL。
<description>:通常作为 link 中所指向的 URL 的摘要或者补充。
所有的元素都是可选的,但是一个项至少要么 包含一个 <title>,要么包含一个 <description>。
项还有其他一些可选的元素:
<author>:作者的 e-mail 地址。
<category>:支持有组织的记录。
<comments>:关于项的注释页的 URL。
<enclosure>:支持和该项有关的媒体对象。
<guid>:唯一与该项联系在一起的永久性链接。
<pubDate>:该项是什么时候发布的。
<source>:该项来自哪个 RSS 频道,当把项聚合在一起时非常有用。
清单 1 是一个 RSS 2.0 文件的例子。注意,频道包含在 <rss version="2.0"> 中。这是一个非常基本的例子,说明了项和图像如何包含在频道中。所示的元素都是最常用的频道子元素。
清单 1. 示例 RSS 2.0 文件
<?xml version="1.0"?>
<rss version="2.0">
   <channel>
   <title>The channel’s name goes here</title>
   <link>http://www.urlofthechannel.com/</link>
   <description>This channel is an example channel for an article.
   </description>
   <language>en-us</language>
   <image>
     <title>The image title goes here</title>
     <url>http://www.urlofthechannel.com/images/logo.gif</url>
     <link>http://www.urlofthechannel.com/</link>
   </image>
   <item>
     <title>The Future of content</title>
     <link>http://www.itworld.com/nl/ecom_in_act/11122003/</link>
     <description> The issue of people distributing and reusing
     digital media is a problem for many businesses. It may also be
     a hidden opportunity. Just as open source licensing has opened
     up new possibilities in the world of technology, it promises to do
     the same in the area of creative content.</description>
   </item>
   <item>
     <title>Online Music Services – Better than free?</title>
     <link>http://www.itworld.com/nl/ecom_in_act/08202003/</link>
     <description>More people than ever are downloading music from
     the Internet. Many use person-to-person file sharing programs like
     Kazaa to share and download music in MP3 format, paying nothing.
     This has made it difficult for companies to setup online music
     businesses. How can companies compete against free?</description>
   </item>
 </channel>
</rss>
8.5.相关工具
由于 RSS 的普及,出现了许多工具,使您能够基本上在任何环境中使用这些文件:
Java 技术:可在 Sun 站点上找到的一个 RSS Utilities Package,支持在 JavaServer Pages 中使用 Tag Library。它还包括一个 RSS 解析器。
Perl:已经有几种 Perl 工具处理 RSS。XML::RSS 提供了创建和维护 RSS 文件的一个框架。它支持在常用版本之间的转换。
Python:RSS.py 是一组通过 Python 使用 RSS 频道的类。
此外,许多内容管理和 weblog 工具也直接支持 RSS。多数 weblog 工具,包括 Movable Type、Blogger 和 Radio Userland 都支持 RSS。一些内容管理系统,包括 Zope 和 CityDesk 现在也支持它了。
8.6.扩展 RSS
RSS 2.0 有许多可选元素,包括多数频道都需要的那些元素。但是它还支持扩展性,因此您可以使用规范中没有的元素。不过,RSS 2.0 规范并没有花费多少时间定义如何实现扩展。关于扩展性,规范中总结为:“RSS 提要可以包含本页中没有描述的元素,只要这些元素定义在一个名称空间中。”
这就留下了很大的想像空间!所幸的是,规范中包含一个例子,您可以参考目前使用的几个例子。
基本的思想是您可以增加需要的标签 —— 但是,增加带有多种含义的元素太容易了。使用您的频道的人们可能并不知道某个标签是什么含义。比如,如果我要在一个频道中使用 <analog> 标签,它的含义就不很清楚。Web 专家可能认为这个标签指的是 Analog,它是最流行的 Web log 文件分析器。科幻迷可能认为这个标签是关于 Analog 的,一本经典的科幻杂志。音乐家可能认为它指的是流行的合成器类型,生物学家认为这是一种器官,电子工程师认为是一种电路。含糊性使人们很难理解标签的含 义。
因此,RSS 允许您增加所喜欢的任何标签,但是要求必须和名称空间一起使用。这样有助于澄清标签的含义。
再回到 <analog> 的例子,我可能希望创建一组关于电子商务的标签,并让 <analog> 标签作为一个“e-business”元素。为此,我增加如下的名称空间:
xmlns:ebusiness="http://www.lewingroup.com/ebusinessChannel"
这就创建了一个名为“ebusiness”的名称空间, 并表明这个名称空间的文档在我的站点上。为了使用 <analog> 标签,我可以使用这种格式:<ebusiness:analog>。这样就能与其他类似的含义中区分开来,比如 <sciencefiction:analog> 或 <synthesizers:analog>。
关于扩展性,一个更实际的例子可以在 RSS 2.0 规范的示例文件中找到:
清单 2. RSS 2.0 规范示例文件中的名称空间
<?xml version="1.0"?>
<!– RSS generated by Radio UserLand v8.0.5 on 9/30/2002; 4:00:00 AM Pacific –>
<rss version="2.0" xmlns:blogChannel="http://backend.userland.com/blogChannelModule">
 <channel>
   <title>Scripting News</title>
   <link>http://www.scripting.com/</link>
   <description>A weblog about scripting and stuff like that.</description>
   <language>en-us</language>
   <blogChannel:blogRoll>
     http://radio.weblogs.com/0001015/userland/scriptingNewsLeftLinks.opml
   </blogChannel:blogRoll>
     <item>
     <description>Joshua Allen:
     <a href="http://www.netcrucible.com/blog/2002/09/29.html#a243">
     Who loves namespaces?</a></description>
     <pubDate>Sun, 29 Sep 2002 19:59:01 GMT</pubDate>
     <guid>
     http://scriptingnews.userland.com/backissues/2002/09/29#When:12:59:01PM
     </guid>
     </item>
 </channel>
</rss>
在这个例子中,定义了一个称为 blogChannel 的名称空间。它指向一个文档,该文档解释了几种常见于 weblog 的新元素的用法。其中之一是 <blogroll>。文档说明,blogroll 是 weblog 中的一个链接集合,指向与您的 weblog 内容相关的站点。
<blogChannel:blogRoll> 标签提供了用户或软件所需要的信息,知道 blogRoll 是一个定义在 blogChannel 名称空间中的元素,而且可以找到这个文档的位置。
同样,RSS 2.0 只对不 属于规范的元素要求名称空间。所有的基本标签都假定在 RSS 2.0 名称空间中。这使得这种格式更容易使用,因为除非需要扩展 RSS,否则您完全不需要知道名称空间。
8.7.RSS2.0标记手册
注:英文原版请参见http://blogs.law.harvard.edu/tech/rss
RSS是 Really Simple Syndication的缩写(对rss2.0而言,是这三个词的缩写,对rss1.0而言则是RDF Site Summary的缩写,1.0与2.0走的是两个体系)
RSS 基于XML,所有的 RSS 必须遵循w3c网站上公布的XML 1.0 规范。
在一个RSS文档中,根元素是<rss>,带有一个必备属性version,用以指明该文档遵循的rss规范,如果rss文档遵循本规范,则version值必须是2.0。
<rss>元素只有一个子元素,包含关于频道的一些信息。频道(channel)是整个blog,项(item)指一篇文章或日志(也有称这为post)。
8.7.1.    元素channel的子元素列表RSS2.0
元素(Element)
描述(Description)
值域
重要性
举例(Example)
title
频道名称
 
必备
GoUpstate.com News Headlines
link
频道的URL
 
必备
http://www.goupstate.com/
Description
频道的描述
 
必备
The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site.
 
 
 
 
 
language
频道文章所用语言,
可用netscape或w3c推荐的列表
可选
en-us
copyright
频道内容的版权说明
 
可选
Copyright 2002, Spartanburg Herald-Journal
managingEditor
责任编辑的email
 
可选
[email protected] (George Matesky)
webMaster
负责频道技术事务的网站管理员email
 
可选
[email protected] (Betty Guernsey)
pubDate
频道内容发布日期,格式遵循RFC822格式(年份可为2们或4位)
 
可选
Sat, 07 Sep 2002 00:00:01 GMT
lastBuildDate
频道内容最后的修改日期
 
可选
Sat, 07 Sep 2002 09:42:31 GMT
category
指定频道所属的一个或几个类别
 
可选
<category>Newspapers</category>
generator
生成该频道的程序名
 
可选
MightyInHouse Content System v2.3
docs
指向该RSS文件所用格式说明的URL
 
可选
http://blogs.law.harvard.edu/tech/rss
cloud
Allows processes to register with a cloud to be notified of updates to the channel, implementing a lightweight publish-subscribe protocol for RSS feeds. More info here.
 
可选
<cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="pingMe" protocol="soap"/>
ttl
有效期,用以指明该频道可被缓存的最长时间
分钟为单位
可选
<ttl>60</ttl>
image
指定一个 GIF或JPEG或PNG图片,用以与频道一起显示
 
可选
 
rating
这个频道的分级(主要指成人、限制、儿童等)
 
可选
 
textInput
指定一个text输入框供用户输入,具体信息及功能未定。
 
可选
 
skipHours
提示新闻聚合器,那些小时时段它可以跳过。
 
可选
 
skipDays
提示新闻聚合器,那些天它可以跳过。
 
可选
 
8.7.2.    元素channel的子元素image的子元素列表RSS2.0
元素(Element)
描述(Description)
值域
重要性
举例(Example)
url
图片的url
 
必备
 
title
图片的标题,用于http的alt属性
 
必备
 
link
网站的url(实际中常以频道的url代替)
 
必备
 
width
图片的宽度(象素为单位)
最大144,默认88
可选
 
height
图片的高度(象素为单位)
最大400,默认31
可选
 
description
用于link的title属性
 
可选
 
8.7.3.    元素channel的子元素cloud的子元素列表RSS2.0
元素(Element)
描述(Description)
值域
重要性
举例(Example)
domain
Cloud程序所在机器的域名或IP地址
 
 
radio.xmlstoragesystem.com
port
访问clound程序所通过的端口
 
 
80
path
程序所在路径(不一定是真实路径)
 
 
/RPC2
registerProcedure
注册的可提供的服务或过程
 
 
xmlStorageSystem.rssPleaseNotify
protocol
协议
xml-rpc, soap , http-post 之一
 
xml-rpc
8.7.4.    元素channel的子元素textInput的子元素列表RSS2.0
元素(Element)
描述(Description)
值域
重要性
举例(Example)
title
Submit按钮的标签
 
必备
 
description
解释text输入区
 
必备
 
name
Text area对象的名字
 
必备
 
link
处理提交的请求的cgi程序
 
必备
 
8.7.5.    开发RSS2.0接口注意:时间字段必须是rfc 822格式
最早开发WebLucene时:RSS 2.0数据输出的时间字段是ISO格式:2004-12-25 21:48:09 因此有的RSS解析会出错。正确的应该是这种格式:
<pubDate>Sun, 26 Dec 2004 21:48:09 +0800</pubDate>
查了一下,原来这种时间格式是:rfc822标准,例如 Thu, 21 Dec 2000 16:01:07 +0200
9.   开发教程RSS
RSS(Really Simple Syndication,真正简单的连锁)是一种 Web 内容连锁格式。RSS 成为通过 Web 连锁新闻内容的标准格式。作为最近与 Sun Microsystems 签署合同的一部分,我负责开发任何懂得 RSS、JavaServer Pages 和 HTML 的人便可以使用的“JSP 标签库”。taglib 主要面向用 RSS 收集新闻内容的 Web 站点的非技术性编辑人员。我的目标是开发在 Web 页中将简化使用 RSS 内容(0.91、0.92 和 2.0 版本)的 JSP 标签库。
RSS Utilities Package 是该项目的结果。它包括一套自定义 JSP 标签,这些标签弥补了 RSS Utilities Tag library 和灵活的 RSS 语法分析器。该文档说明了如何使用该语法分析器和 RSS Utilities Package 提供的库。在这里单击便可以下载第一个版本。该 zip 文件包含一个 jar 文件 rssutils.jar(该文件包含使用该工具所需的类)和一个 tld 文件(该文件定义从 RSS 文档中提取信息的 JSP 自定义标签)。
安装 taglib
 
尽管使用标签库很容易,但在安装时要求您了解 Web 服务器的工作原理和如何去配置它。第一步是下载并解压包。一旦 zip 文件已经解压了,在 Web 应用程序的 /WEB-INF/lib 目录中放置一份 rssutils.jar 和 rsstaglib.tld 的副本。将下面的 taglib 定义添加至 Web 应用程序的 /WEB-INF/web.xml 文件:
<taglib>
<taglib-uri>/WEB-INF/rssutils.tld</taglib-uri>
<taglib-location>/WEB-INF/rssutils.tld</taglib-location>
</taglib>
9.1.使用taglib
一旦 taglib 已经安装在 Web 应用程序中,按照以下步骤便可以在 JSP 页面中使用 taglib。首先,将下面一行添加至 JSP 页面的顶部:
<%@ taglib uri="/WEB-INF/rssutils.tld" prefix="rss" %>
其次,使用 feed 标签将 RSS feed 添加至 JSP 页面,如下例所示:
<rss:feed url="http://servlet.java.sun.com/syndication/rss_java_highlights-10.xml" feedId="javaSunCom"/>
"feed" 标签的 url 属性必须包含到 RSS 文档的 URL。"feed" 标签的 feedId 属性是任意的,可以设置为任何值。然而,我们建议该属性在标识 RSS feed 时要直观。如果应用程序在防火墙后面,可以使用名为 proxyAddress 和 proxyPort 的 "feed" 标签代理属性来设置代理属性。如果不知道代理服务器地址代理端口,请与网络管理员联系。下面是一个例子:
<rss:feed url="http://servlet.java.sun.com/syndication/rss_java_highlights-10.xml" feedId="example1" proxyAddress="129.149.246.4" proxyPort="8080"/>
一旦将一个或多个 RSS feed 添加到页面,您应能使用剩余的一套标签来从 feed 中提取几乎任何信息。下面是一个例子,说明如何提取在上面添加的 RSS feed 频道的标题:
<rss:channelTitle feedId="javaSunCom"/>
9.2.Taglib 示例
9.2.1.    例 1 (RSS 0.91):
<rss:feed
url="http://servlet.java.sun.com/syndication/rss_java_highlights-XYZCompany-10.xml"
feedId="example1"/>
<b>Image: </b><rss:channelImage feedId="example1" asLink="true"/><br>
<b>Title: </b><rss:channelTitle feedId="example1"/><br>
<b>Link: </b><rss:channelLink feedId="example1" asLink="true"/><br>
<b>Description: </b><rss:channelDescription feedId="example1"/><br>
<ul>
<li><rss:itemTitle feedId="example1" index="0"/><br>
<rss:itemDescription feedId="example1" index="0"/><br><br>
<li><rss:itemTitle feedId="example1" index="1"/><br>
<rss:itemDescription feedId="example1" index="1"/><br>
</ul>
9.2.2.    例 2 (RSS 0.92):
<rss:feed
url="http://static.userland.com/gems/backend/gratefulDead.xml" feedId="example2"/>
<b>Image: </b><rss:channelImage feedId="example2"/><br>
<b>Title: </b><rss:channelTitle feedId="example2"/><br>
<b>Link: </b><rss:channelLink feedId="example2" asLink="true"/><br>
<b>Description: </b><rss:channelDescription feedId="example2"/><br>
<ul>
<rss:forEachItem feedId="example2">
<li><rss:itemDescription feedId="example2"/><br><br>
</rss:forEachItem>
</ul>
9.2.3.    例 3 (RSS 2.0):
<rss:feed
url="http://static.userland.com/gems/backend/rssTwoExample2.xml"
feedId="example3"/>
<b>Image: </b><rss:channelImage feedId="example3"/><br>
<b>Title: </b><rss:channelTitle feedId="example3"/><br>
<b>Link: </b><rss:channelLink feedId="example3" asLink="true"/><br>
<b>Description: </b><rss:channelDescription feedId="example3"/><br>
<b>Copyright: </b><rss:channelCopyright feedId="example3"/><br>
<b>Docs: </b><rss:channelDocs feedId="example3"/><br>
<b>Generator: </b><rss:channelGenerator feedId="example3"/><br>
<b>Language: </b><rss:channelLanguage feedId="example3"/><br>
<b>Last Build Date: </b><rss:channelLastBuildDate
X-Virus: 1
feedId="example3"/><br>
<b>Managing Editor: </b><rss:channelManagingEditor
feedId="example3"/><br>
<b>Pub Date: </b><rss:channelPubDate feedId="example3"/><br>
X-Virus: 1
<b>Skip Days: </b><rss:channelSkipDays feedId="example3"/><br>
<b>Skip Hours: </b><rss:channelSkipHours feedId="example3"/><br>
<b>TTL: </b><rss:channelTTL feedId="example3"/><br>
<ul>
<rss:forEachItem feedId="example3" startIndex="2" endIndex="4">
<li><rss:itemDescription feedId="example3"/><br><br>
</rss:forEachItem>
</ul>
9.3.如何使用 RssParser?
从某种程度上看,语法分析器是该项目的副产品。尽管语法 分析器是用标签库来开发的,但是它完全是自包含的,它可以在 Java 应用程序中使用。然而,要做到这一点,显然您至少需要了解如何编写基本的 Java 代码。(如果您了解如何用 Java 语言编写 Hello World,就没什么问题了。)
首先下载并解压包。一旦将 rssutils.jar 添加至您的类路径,就请使用 RssParserFactory 创建 RssParser 接口的实例:
RssParser parser = RssParserFactory.createDefault();
Rss rss = parser.parse(new URL("http://mydomain.com/document.rss"));
语法分析器生成的 RSS 对象是位于提供的 URL 中的 RSS 文档的 Java 对象表示。使用 RSS 对象提供的方法以获得其它 RSS 对象的句柄,如 Channels 和 Items。RssParser 也能够分析 File 对象和 InputStream 对象。
9.4.使用RSSLibJ进行RSS开发
RSS是一个标准的XML文件,Rss阅读器可以读取这 个XML文件获得文章的信息,使用户可以通过Rss阅读器而非浏览器阅读Blog,我们只要动态生成这个XML文件便可以了。RSSLibJ是一个专门读 取和生成RSS的小巧实用的Java库,大小仅25k,可以从http://sourceforge.net/projects/rsslibj/下载 rsslibj-1_0RC2.jar和它需要的EXMLjar两个文件,然后复制到web/WEB-INF/lib/下。
使用RSSLibJ异常简单,我们先设置好HttpServletResponse的Header,然后通过RSSLibJ输出XML即可:
import com.rsslibj.elements.Channel;
 
public class Writer {
    public static void main(String[] args)
            throws InstantiationException, ClassNotFoundException,
            IllegalAccessException {
        Channel channel=new Channel();
        channel.setDescription("This is my sample channel.");
        channel.setLink("http://localhost/");
        channel.setTitle("My Channel");
        channel.setImage("http://localhost/",
                "The Channel Image",
                "http://localhost/foo.jpg");
        channel.setTextInput("http://localhost/search",
                "Search The Channel Image",
                "The Channel Image",
                "s");
        channel.addItem("http://localhost/item1",
                "The First Item covers details on the first item>",
                "The First Item")
                .setDcContributor("Joseph B. Ottinger");
        channel.addItem("http://localhost/item2",
                "The Second Item covers details on the second item",
                "The Second Item")
                .setDcCreator("Jason Bell");
        System.out.println("The feed in RDF: "+channel.getFeed("rdf"));
    }
}
9.5.JDOM生成RSS方式
package music;
 
 
import org.jdom.*;
import org.jdom.output.*;
import org.jdom.input.*;
import java.io.*;
import java.util.*;
import java.text.DateFormat;
public class RSSCreater
{
    AlbumDto dto=null;
    public RSSCreater(AlbumDto dto,String dir)
    {
        Date date=new Date();
        this.dto=dto;
        String albumName=dto.getAlbumName();
        String artistName=dto.getArtistName();
        DateFormat format=DateFormat.getDateTimeInstance();
        String time=format.format(date);
        int albumId=dto.getAlbumId().intValue();
        String id=String.valueOf(albumId);
        String url="http://localhost:8080/musicWeb/getSongAction.do?categoryId="+id;
        System.out.println("现在时间是:"+time);
        String atitle=artistName+"的新专辑– "+albumName+"–已经到达本站,欢迎查看";
        try
        {
            String truePath=dir+"/"+"index.xml";
            SAXBuilder sb = new SAXBuilder();
            Document doc = sb.build(new FileInputStream(truePath));
            Element root = doc.getRootElement();
            java.util.List books = root.getChildren("channel");
            Element item=(Element)books.get(0);
 
            Element it=new Element("item");
            Element title=new Element("title").setText(atitle);
            Element lint=new Element("link").setText(url);
            Element datetime=new Element("pubDate").setText(time);
            Element guid=new Element("guid").setText(url);
 
            it.addContent(title);
            it.addContent(lint);
            it.addContent(guid);
            it.addContent(datetime);
            item.addContent(it);
 
             File files=new File(truePath);
            Writer xmlwriter=new FileWriter(files);
            FileOutputStream outstream=new FileOutputStream(files);
            XMLOutputter fmt=new XMLOutputter();
            fmt.output(doc,xmlwriter);
            fmt.output(doc,outstream);
 
 
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }
}
9.6.使用FreeMarker/Jsp(WebWork2)生成静态/动态RSS文件(RSS2.0)
在计划生成RSS文件的时候,顺便搜索了一下JIRA和Confluence的程序,发现它们分别是用模板方式和JSP动态页面来展示的.于是我也想到两种方式:
1.用FreeMarker生成静态文件,适用于更新不是很频繁的内容.
2.用JSP动态展示,适合更新频率高,种类繁多的内容.
使用rsslibj库!
还是以本站的新闻举例,其中的新闻信息类参考 http://www.jscud.com/srun/news/viewhtml/3_2005_8/76.htm此处不在列出. ,
9.6.1.    先说FreeMarker方式
根据RSS的规范,得到模板如下:
<?xml version="1.0" encoding="UTF-8" ?>
 <rss version="2.0">
 <channel>
  <title>JScud Develop</title>
 <link>http://www.jscud.com/</link>
 <language>zh-cn</language>
 <description >JScud Develop By Scud</description>
 <webMaster>[email protected](scud)</webMaster>
 <lastBuildDate>${rssutil.formatRssDate(now)}</lastBuildDate>
  
   <#list newslist as onenews>
 <item>
   <title>${onenews.title?xml}</title>
   <link>http://www.jscud.com/srun/news/viewhtml/${onenews.htmlFilePath}/${onenews.nid}.htm</link>
   <pubDate>${rssutil.formatRssDate(onenews.addtime)}</pubDate>
   <description><![CDATA[
 ${rssutil.formatRssCData(onenews.showContent)}
   ]]>
   </description>
   </item>
 </#list>
 </channel>
 </rss>
其中的网址和网站名称可以根据自己的实际情况修改.
我每次取出最新的20条文章来生成RSS,不过内容比较多,生成的RSS文件比较大,看到有的网站的description只是放了文章摘要的内容,这样文件就小多了.总之是根据自己的需求设计吧.
其中用到的RssUtil函数库的函数如下(日期的函数参考上一篇文章):
    /**
     * 把]]>替换为]]&gt;
     * @param content 内容
     * @return 格式化后的内容
     */
    public static String formatRssCData(String content)
    {
        String result = StringFunc.replace(content,"//]//]>","]]&gt;");
       
        return result;
    }
   
    /**
     * 格式化为xml需要的字符串
     * @param field 内容
     * @return 格式化后的串
     */
    public static String formatString2XML(String field)
    {
        return StringFunc.str2TextXML(field);
    }
   
    public static String getNowDateTime()
    {
        return formatRssDate(DateTime.getNowTimestamp());
    }
 
利用FreeMarker生成静态文件的代码如下:
 private Configuration freemarker_cfg = null;
 
    protected Configuration getFreeMarkerCFG()
    {
        if (null == freemarker_cfg)
        {
            // Initialize the FreeMarker configuration;
            // – Create a configuration instance
            freemarker_cfg = new Configuration();
 
            freemarker_cfg.setClassForTemplateLoading(this.getClass(), "/htmlskin");
 
            freemarker_cfg.setDefaultEncoding("GBK");
        }
 
        return freemarker_cfg;
    }
 
    public boolean geneFileByFreeMarker(String templateFileName, Map propMap, String filePath,
                    String fileName, String encode)
    {
        try
        {
            Template t = getFreeMarkerCFG().getTemplate(templateFileName);
 
            File afile = new File(filePath + "/" + fileName);
 
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(afile),
                            encode));
 
            propMap.put("baseurl", PropSet.getStringProp("url.root"));
 
            t.process(propMap, out);
        }
        catch (TemplateException e)
        {
            LogMan.error("Error while processing FreeMarker template " + templateFileName, e);
            return false;
        }
        catch (IOException e)
        {
            LogMan.error("Error while generate File " + fileName, e);
            return false;
        }
 
        return true;
    }
 
新闻系统中调用重新生成RSS文件的代码如下:
 
    /**
     * 重新生成RSS文件.
     *
     * @param nid 更新的新闻的id,如果不包含在最新的新闻里,则不更新RSS.nid <1则更新
     *
     * @return 是否成功
     */
    private boolean renewRSS(int nid)
    {
        List newsList = 装载新闻的代码
 
        boolean shouldUpdate = false;
        if (nid > 0)
        {
            for (int i = 0; i < newsList.size(); i++)
            {
                NewsItem aNews = (NewsItem) newsList.get(i);
                if (aNews.getNid() == nid)
                {
                    shouldUpdate = true;
                    break;
                }
            }
        }
        else
        {
            shouldUpdate = true;
        }
 
        //不更新,则返回
        if (!shouldUpdate)
        {
            return true;
        }
 
        Map root = new HashMap();
       
        root.put("rssutil",new RSSUtil());
 
        root.put("newslist", newsList);
       
        root.put("now",DateTime.getNowTimestamp());
 
        geneFileByFreeMarker("/news/rss.ftl", root, PropSet.getStringProp("rss.rssdir"), PropSet
                        .getStringProp("rss.rssfile"), "UTF-8");
 
        return true;
    }
在增加或者更新/删除新闻的地方需要调用这个renewRSS函数.
 
9.6.2.    动态方式JSP
相对静态方式而言,简单的多,不过效率上可能就不太好了.
webwork2的Action代码如下:
        newsList = 装载新闻代码
        return SUCCESS;
视图Jsp如下:
<%@ page contentType="text/xml; charset=UTF-8"%>
<%@ taglib uri="jscud" prefix="jscud" %>
<%@ taglib uri="webwork" prefix="ww" %>
<ww:bean name="’com.jscud.www.util.RSSUtil’" id="rssUtil" />
<?xml version="1.0" encoding="UTF-8" ?>
 <rss version="2.0">
 <channel>
 <title>JScud Develop</title>
 <link>http://www.jscud.com/</link>
 <language>zh-cn</language>
 <description >JScud Develop By Scud</description>
 <webMaster>[email protected](scud)</webMaster>
 <lastBuildDate><ww:property value="#rssUtil.nowDateTime" /></lastBuildDate>
  
   <ww:iterator value="newsList">
 <item>
   <title><ww:property value="#rssUtil.formatString2XML(title)"/></title>
   <link>http://www.jscud.com/srun/news/viewhtml/<ww:property value="htmlFilePath" />/<ww:property value="nid" />.htm</link>
   <pubDate><ww:property value="#rssUtil.formatRssDate(addtime)" /></pubDate>
   <description><![CDATA[
 <ww:property value="#rssUtil.formatRssCData(showContent)"/>
   ]]>
   </description>
   </item>
 </ww:iterator>
 </channel>
 </rss>
jsp的方式简单多了,上面的jsp里面还演示了ww:bean的使用 🙂
附录
附录1:语言编码
Afrikaans: af
Albanian: sq
Basque: eu
Belarusian: be
Bulgarian: bg
Catalan: ca
Chinese (Simplified): zh-cn
Chinese (Traditional): zh-tw
Croatian: hr
Czech: cs
Danish: da
Dutch: nl
Dutch (Belgium): nl-be
Dutch (Netherlands): nl-nl
English: en
English (Australia): en-au
English (Belize): en-bz
English (Canada): en-ca
English (Ireland): en-ie
English (Jamaica): en-jm
English (New Zealand): en-nz
English (Phillipines): en-ph
English (South Africa): en-za
English (Trinidad): en-tt
English (United Kingdom): en-gb
English (United States): en-us
English (Zimbabwe): en-zw
Estonian: et
Faeroese: fo
Finnish: fi
French: fr
French (Belgium): fr-be
French (Canada): fr-ca
French (France): fr-fr
French (Luxembourg): fr-lu
French (Monaco): fr-mc
French (Switzerland): fr-ch
Galician: gl
Gaelic: gd
German: de
German (Austria): de-at
German (Germany): de-de
German (Liechtenstein): de-li
German (Luxembourg): de-lu
German (Switzerland): de-ch
Greek: el
Hawaiian: haw
Hungarian: hu
Icelandic: is
Indonesian: in
Irish: ga
Italian: it
Italian (Italy): it-it