学习JDK的动态代理前需要了解静态代理的实现,假设我们有一个接口Moveable,一个类BMW,通过静态代理的方式获取汽车行驶的时间。

一、静态代理

(1)Moveable接口,有个move()方法

package guoli.proxy;

/**
 * @author zhangguoli.cn
 * @date 2018/2/9
 */
public interface Moveable {
    void move();
}

(2)类BMW实现了Moveable接口

package guoli.proxy;

import java.util.Random;

/**
 * @author zhangguoli.cn
 * @date 2018/2/9
 */
public class BMW implements Moveable {
    @Override
    public void move() {
        try {
            System.out.print("汽车行驶中...");
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

(3) TimeCar实现了对BMW行驶的时间记录

package guoli.proxy;

/**
 * @author zhangguoli.cn
 * @date 2018/2/9
 */
public class TimeCar extends BMW {

    @Override
    public void move() {
        System.out.println("汽车开始行驶");
        Long startTime = System.currentTimeMillis();
        super.move();//调用被代理类BMW的move()方法
        Long endTime = System.currentTimeMillis();
        System.out.println("汽车行驶结束... 用时:" + (endTime-startTime) + "毫秒!");
    }
}

(4) 测试类BMWTest

package guoli.proxy;

/**
 * @author zhangguoli.cn
 * @date 2018/2/9
 */
public class BMWTest {
    public static void main(String[] args) {
        TimeCar timeCar = new TimeCar();
        timeCar.move();
    }
}

输出结果大致如下:

汽车开始行驶
汽车行驶中...
汽车行驶结束... 用时:768毫秒!

如果后来Ford也需要记录行驶时间,就需要增加一个FordTime记录Ford的行驶时间;如果需要增加对车行驶距离的记录,还需要增加Distance类记录相关信息。


二、动态代理

JDK动态代理 只能代理实现了某些接口的类。

代理模式的UML类图:

来源网络,侵删

- 阅读剩余部分 -

java.sql下的StatementPreparedStatementCallableStatement是用来执行SQL查询的API。其中Statement用于执行普通查询,PreparedStatement用于执行参数化查询,CallableStatement则用于存储过程。他们之间的继承关系:PreparedStatement extends StatementCallableStatement extends PreparedStatement

本文主要介绍的是PreparedStatement的简单使用、相比Statement的优势,以及PreparedStatement的局限性。

PreparedStatement示例

String url = "jdbc:mysql://127.0.0.1:3306/dbname";
//获取一个连接
Connection conn = DriverManager.getConnection(url, "username", "password");
//PreparedStatement 为预编译对象
PreparedStatement pst = conn.prepareStatement("select uuid from test limit ?");
pst.setInt(1, 1);
//结果对象
ResultSet result = pst.executeQuery();
while (result.next()) {
    System.out.println(result.getString("uuid"));
}
//依次关闭
result.close();
pst.close();
connection.close();

PreparedStatement优势

- 阅读剩余部分 -

本文基于:CentOS release 6.5 (Final)

注意SMTP使用默认端口25和加密端口465在配置上的区别

安装

yum -y install mailx

配置发送人信息

vim /etc/mail.rc 在最后增加:

set from=yourEmailAddress
set smtp=smtpAddress
set smtp-auth-user=yourEmailAddress
set smtp-auth-password=youPassword
set smtp-auth=login

使用三种方式发送邮件

  • 命令行: mail -s "theme" addressee,回车后输入内容按Ctrl+D发送邮件.
  • 管道符: echo "mail main content" | mail -s "theme" addressee
  • 文件内容作为邮件内容: mail -s "theme" addressee < /tmp/t.txt

thme是邮件标题,addressee收件人地址


在搜索CentOS上发送邮件时,大部分都是上面的流程,的确在部分机器是测试成功的,唯独ECS不成功,后来了解到ECS默认关闭25端口。


使用SSL的方式发送邮件

  • 修改/etc/mail.rc增加如下关于SSL的配置
    set nss-config-dir=/etc/mail.rc_ssl.crt
    set smtp-user-starttls
    set ssl-verify=ignore
  • 修改 set smtp=smtps://xxxx.xxxx:465
  • /etc/mail.rc_ssl.crt目录下增加Firefox浏览器*.db文件(cert8.db、key3.db、secmod.db)以支持SSL的方式发送邮件

如果你的电脑上装有Firefox,windows可以在 %userProfile%\AppData\Roaming\Mozilla\Firefox\Profiles\xxx.default,Linux~/.mozilla/firefox/xxx.default目录下获取*.db文件,或者直接从这类下载:https://dn-zhangguoli.qbox.me/mail.rc_ssl.crt.zip

  • 发送邮件,注意增加 -v 参数,否则报错.echo "email main content" | mail -v -s "theme" addressee

需求:自动备份网站数据文件到七牛

    os      : CentOS release 6.5 (Final)
    website : /opt/website
    MySQL   : /opt/mysql
    backup  : /opt/backup
    qshell  : /opt/qshell

备份网站文件

vim /opt/website.sh

#!/bin/sh
# tar /opt/website to /opt/backup/website

mkdir -p /opt/backup/website
t=`date +"%Y%m%d_%H%M%s"`
tar -zcvf /opt/backup/website/$t.tar.gz /opt/website

chmod u+x website.sh

备份MySQL文件

vim /opt/mysql.sh

#!/bin/bash

# use mysqldump backup mysql to /opt/backup/mysql

mkdir -p /opt/backup/mysql
t=`date +%Y%m%d_%H%M%S`
/opt/mysql/bin/mysqldump -P port -u userName -ppassword database > /opt/backup/mysql/$t.sql

port是MySQL端口,默认3306,userName是MySQL用户名,password是密码,database是要备份的数据库
因为密码是直接明文写在脚本中的,执行的时候会提示Using a password on the command line interface can be insecure.

chmod u+x mysql.sh

上传到七牛

qshell说明文档 : https://developer.qiniu.com/kodo/tools/1302/qshell
dircache说明文档:https://github.com/qiniu/qshell/blob/master/docs/dircache.md
qupload说明文档 :https://github.com/qiniu/qshell/blob/master/docs/qupload.md

  • 注册 七牛 账号并登录
  • 个人中心->密钥管理,创建密钥(AccessKey/SecretKey)
  • 选择自己的平台下载qshell并重命名为qshell,此处下载linux x64:
    wget https://dn-devtools.qbox.me/2.1.5/qshell-linux-x64
  • 设置密钥: ./qshell account AccessKeyValus SecretKeyValues
  • 生成要上传文件的列表upload.list.txt:vim /opt/qshell/cache.sh
    #!/bin/bash

    # auto create dircache upload.list.txt

    /opt/qshell/qshell dircache /opt/backup /opt/qshell/upload.list.txt
  • chmod u+x cache.sh
  • 配置qupload的支持文件: vim /opt/qshell/upload.conf
    {
      "src_dir" : "/opt/backup",
      "bucket" : "xxx",
      "log_file": "/opt/qshell/upload.log",
      "file_list": "/opt/qshell/upload.list.txt",
      "rescan_local": true,
      "check_exists": true
}
  • 使用qshell上传:vim /opt/qshell/qsyn.sh
    #!/bin/bash

    # syn /opt/backup/ to qiniu bucket/xxx

    /opt/qshell/qshell qupload /opt/qshell/upload.conf                                                        
  • chmod u+x qsyn.sh

添加定时任务

crontab -e

00 02 * * *  /opt/website.sh
05 02 * * *  /opt/mysql.sh
10 02 * * *  /opt/qshell/cache.sh
15 02 * * *  /opt/qshell/qsyn.sh

系统会在早上2点之后陆续执行上述任务将/opt/backup下的文件上传到七牛空间。

OAuth2.0是一个开放授权(open authorization)标准,允许用户让第三方应用获取其在其他网站的授权码,而无需提供给第三方应用在某网站的账号与密码。

OAuth2.0授权流程

假设第三方应用为zhangguoli.cn,服务器提供商为example.com/,授权服务器、认证服务器和资源服务器可以是一个服务器。

- 阅读剩余部分 -

CentOS release 6.5 (Final)
Oracle Release 11.2.0.4.0

  • 使用ssh连接到服务器
  • 切换到Oracle用户: su - oracle
  • 连接到Oracle:sqlplus /nolog
  • 使用管理员身份登录数据库: conn sys/sys as dba
  • 修改密码:ALTER USER user_name IDENTIFIED BY new_password;

需求:默认情况下Typecho安装完后文章链接是http://zhangguoli.cn/index.php/xxx.html这样的,强迫症是在受不了中间多了个index.php,于是想修改为:http://zhangguoli.cn/xxx.html

本文环境:
CentOS release 6.5 (Final)
Apache 2.4.29
PHP 5.6.32

Apache的安装路径: /opt/apache
网站站点文件位置: /opt/www/zhangguoli

1. 开启Apache的Rewrite模块

vi /opt/apache/conf/httpd.conf

查找httpd.conf中是否包含LoadModule rewrite_module modules/mod_rewrite.so,如果被#注释则去掉或新增。

增加配置如下:

<Directory "/opt/www/zhangguoli"> 
    Order allow,deny
    Allow from all
    AllowOverride All
</Directory>

2. 增加RewriteRule规则

- 阅读剩余部分 -

说明:本文基于CentOS release 6.5 (Final),是工作过程中记录的一些随笔,内容未做详细考究.


  • 设置DNS服务器

  vi /etc/resolv.conf
  nameserver 114.114.114.114
  • 查看Linux版本
    lsb_release -a
LSB Version:    :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID:    CentOS
Description:    CentOS release 6.5 (Final)
Release:    6.5
Codename:    Final

. 当前目录
..上级目录

../上级目录
/根目录


  • pwd 显示当前目录

         实例:
              (1)pwd 显示当前目录
  • ls 显示当前文件(夹)

llls -l的一个别名

         解释:list的缩写
         格式: ls [参数] [目录]
         参数:-l 除文件名外其他的文件信息
         实例:
              (1) ls 显示当前目录的下的文件和目录
              (2) ls -l 详细显示当前目录的下的文件和目录  
              (3) ll 详细显示当前目录的下的文件和目录  
  • mv 文件(夹)移动/重命名

         格式: mv [参数] [源文件/目录] [目标文件/目录]
         参数:
               -f force 强制,如果目标文件已经存在则不会询问而直接覆盖
               -i  目标文件已经存在的话会询问是否覆盖
         实例:
              (1) mv test.zip /opt/test 移动test.zip文件到/opt/test目录
              (2) mv test.zip /opt/test/1.zip 移动test.zip文件到/opt/test目录下,并重命名文件为1.zip


- 阅读剩余部分 -

通过implements ServletContextListener实现监听器Linstener

package cn.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/*
* Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent事件
* 
* ServletContext对象是一个为整个Web应用提供共享的内存,任何请求都可以获取里面的内容
* 实现ServletContextListener时通过ServletContext.setAttribute(key,value)将内容提交到内存中
* 其他地方通过ServletContext.getAttribute(key)获取内容(HelloWorld#doPost)
* 
* 官方对于ServletContextEvent的介绍:
* This is the event class for notifications about changes to the servlet context of a web application.
*/

public class MyLinstener implements ServletContextListener {

    /**
     * ① Servlet启动时先调用contextInitialized方法, 之后再对Filter和需要被初始化的Servlet初始化
     */
    @Override
    public void contextInitialized(ServletContextEvent paramServletContextEvent) {
        ServletContext context = paramServletContextEvent.getServletContext();
        context.setAttribute("linstener", "fromContextInitialized");
        System.out.println("...    contextInitialized    ... ");
    }

    /**
     * ② Servlet停止时先销毁所有的Servlet和Filter, 再调用contextDestroyed方法
     */
    @Override
    public void contextDestroyed(ServletContextEvent paramServletContextEvent) {
        ServletContext dest = paramServletContextEvent.getServletContext();
        System.out.println("contextDestroyed... " + dest.getAttribute("linstener"));
    }

}

web.xml配置监听器

- 阅读剩余部分 -