Skip to main content

Ant 项目构建(2)

上一篇介绍了一下Ant的产生和特点,在最后给大家看看了build.xml。其实Ant的核心就是build.xm。如何编写适合自己工程的build.xml是最重要的。

  • build.properties

tomcat.home=F:\\Java\\Tomcat 5.5
webapps.home=F:\\Java\\Tomcat 5.5\\webapps

build.properties文件是存储一些公共变量的,比如你机子上tomcat的绝对路径。
其实也用到了面向对象的原理,如果你的环境变了,只需要更改build.properties文件就可以了。而不用去更改build.xm里的相关属性。build.properties也可以加上你想加的东西,比如公共的jar文件。。

  • build.xml

project代表一个工程,有4个常见属性:
(1). default 表示默认的运行目标,是必须的
(2). basedir 表示工程的基准目录,”.”表示和build.xml所在的目录。
(3). name 表示工程的名字
(4).description 对工程的描述,可写可不写,写上更清楚对以后的debug

  • build.xml的target

每个build.xml只有个project,但是可以有多个target(目标).比如:

[xml]

<target name="compile" depends ="prepare">
<javac srcdir="${src.home}" destdir="${classes.home}" debug="yes">
<classpath refid = "compile.classpath"/>
</javac>
</target>

[/xml]

介绍完target,大家就会对build.xml有了一个更清楚的认识,更深地清楚了build.xml的框架.更详细的,可以去访问apache ant主页。

apache ant

ant手册

欢迎大家拍砖!

Ant 项目构建(1)

为了条理地介绍Ant,下面我分几部分来介绍Ant:

1.什么是Ant

Ant是一种基于java的build工具,理论上来说,有点类似与(liunx)种的make,但是修复了make的缺陷,使build更加好用,更加方便。
这里有必要介绍一下为什么会产生Ant这个工具?
既然已经有了make,gnumake,nmake,jam和其他的构建工具,为什么还有开发另外一个呢?这时因为那些工具都具有局限性,Ant的原作者(JamesDuncanDavidson)在开发跨平台软件时,并不能使用其中一个完成所有的任务,这就好像,在英语不是通用语言之前,你去那里,必须搞个翻译似的,降低了开发小绿绿,也急不利于大型软件开发的维护。已有的构建工具都是基于特定平台和听顶语言的,受到操作系统的限制太大。
更重要的是,makefile有天生的痼疾,任何在liunx下调试过C程序的都碰到过可恶的Tab问题。也许一个多余的空格,就会导致一个build不能运行?你说?这方便吗?
而Ant则在所有构建工具的基于上,开发出来了跨平台,跨语言的构建工具,已成为最优秀的构建工具,几乎所有的IDE都自带了Ant工具。

2. Ant的特点

  • 跨平台性,ant是基于java的,而java跨平台的性能是与庸置疑的,ant配置文件是基于XML的,而XML是格式最规范的数据格式。因而Ant跨平台的性能也不言而喻
  • 功能强大,从项目的编译,打包,发布,测试到版本的控制,Ant无所不能
  • 灵活方便
  • 可重用性高, Ant的配置文件Build.xml以一个project为开头,以不同的target为任务模块,彼此之间相互独立,但是模块之间又可以相互联系,因而耦合性和内聚性达到了完美的统一
  • 开源软件
3.Ant的配置
上边简单介绍了Ant,相信没有用过的,一定很想试试,那我告诉你,如果你试过了,一定会喜欢上她的,
下面介绍一下怎么配置
和JDK配置一下,先到apache主页上下载ant最新版本,具体网址可以google/baidu。
配置大家也可以搜索,很easy的。
4Ant如何运行呢?
和javac,java一样,直接在cmd下,输入ant就可以了,但是前提必须在该目录中有build.xml。
所以build.xml是最重要的,build.xml里详细地配置了ant如何运行和执行那些功能。
下面是我写的一个build.xml

[xml]
<project name="encrypt" default="help" basedir=".">
<!–
All properties should be defined in this section.Any host-specific properties should be defined
in the build.properties file.
In this app,the following properties are defined in build.properties:
1.tomcat.home === the home directory of your Tomcat installation
2.webapps.home === the place to copy the war file to deploy it.
–>
<property file="build.properties"/>
<property name="app.home" value="."/>
<property name="app.name" value="application"/>
<property name="javadoc.pkg.top" value="encrypt"/>

<property name="src.home" value="${app.home}/src"/>
<property name="lib.home" value="${app.home}/lib"/>
<property name="classes.home" value="${app.home}/classes"/>
<property name="deploy.home" value="${app.home}/deploy"/>
<property name="doc.home" value="${app.home}/doc"/>
<property name="web.home" value="${app.home}/WebRoot"/>

<property name="build.home" value="${app.home}/build"/>
<property name="build.classes" value="${build.home}/WEB-INF/classes"/>
<property name="build.lib" value="${build.home}/WEB-INF/lib"/>

<!–Compilatin Classpath–>
<!– This section creates the classpath for compilation–>
<path id="compile.classpath">
<!–The lib files for this application–>
<fileset dir="${lib.home}">
<include name="*.jar"/>
<include name="*.zip"/>
</fileset>

<!–All files/jars that Tomcat makes available–>
<fileset dir="${tomcat.home}/common/lib">
<include name="*.jar"/>
</fileset>
<pathelement location="${tomcat.home}/common/classes"/>
</path>
<!–==========help targe==========–>
<!–This is the default ant target executed if no target is specified.
This helps avoid user just typed ‘ant’ and runing a default target
that may not do what they are anticipating
–>
<target name="help">
<echo message="Please specify a target![usage:ant <targetname>]"/>
<echo message="Here is a list of possible targets:"/>
<echo message=" clean-all …..Delete all dir,all.class and war files"/>
<echo message=" prepare …..Create directories if required"/>
<echo message=" compile …..Compiles source file"/>
<echo message=" build …..Build war file form.class and other files"/>
<echo message=" deploy …..Copy war files to the webapps directory"/>
<echo message=" javadoc …..Generates javadoc for this application"/>
</target>

<!–=========="clean-all" target==========–>
<target name="clean">
<delete dir="${build.home}"/>
<delete dir="${classes.home}"/>
<delete dir="${deploy.home}"/>

<!–cannot delete directory if tomcat is runing–>
<delete dir="${webapps.home}/${app.home}" failonerror="false"/>
<delete dir="${webapps.home}/S{app.name}.war"/>

<!–delete javadoc–>
<delete dir="${doc.home}"/>
</target>
<!—==========="prepare" target===========–>
<!– This target is executed prior to any of the later targets
to make sure the directories exist.It only creates them if
they need to be created…
Other,similar,preparation steps can be placed here
–>
<target name="prepare">
<echo message="Tomcat Home =${tomcat.home}"/>
<echo message = "webapps Home = ${webapps.home}"/>

<mkdir dir="${classes.home}"/>
<mkdir dir="${deploy.home}"/>
<mkdir dir="${doc.home}"/>
<mkdir dir="${doc.home}/api"/>

<mkdir dir="${build.home}"/>
<mkdir dir="${build.home}/WEB-INF"/>
<mkdir dir="${build.home}/WEB-INF/classes"/>
<mkdir dir="${build.home}/WEB-INF/lib"/>
</target>

<!–=========="compile" target==========–>
<!–This only compiles java files that are newer
than their corresponing.class files
–>
<target name="compile" depends ="prepare">
<javac srcdir="${src.home}" destdir="${classes.home}" debug="yes">
<classpath refid = "compile.classpath"/>
</javac>
</target>

<!–============"build" target=============–>
<!–This target builds the war file for the application by
first building the directory structure of the application
in ${build.home} and then creating the war file using the
ant <war> task
–>
<target name="build" depends="compile">
<!–Copy all the wabapp content(jsp’s,html,tld’s,xml,etc…–>
<copy todir="${build.home}">
<fileset dir="${web.home}"/>
</copy>

<!–copy all java class files–>
<copy todir="${build.home}/WEB-INF/classes">
<fileset dir="${classes.home}"/>
</copy>

<!–Now, copy all the properties files,etc that go on the classpath–>
<copy todir="${build.home}/WEB-INF/classes">
<fileset dir="${src.home}">
<include name="**/*.properties"/>
<include name="**/*.prop"/>
</fileset>
</copy>

<!–Now,copy all the jar files we need–>
<copy todir="${build.home}/WEB-INF/lib">
<fileset dir="${lib.home}"/>
</copy>

<!–create the <war> file–>
<jar jarfile="${deploy.home}/${app.name}.war" basedir="${build.home}"/>
</target>
<!–================"deploy" target============–>
<!– This target simply copies the war file from the deploy
directory into the Tomcat webapps directory.
–>
<target name="deploy" depends="build">

<!–copy the contents of the build directory–>
<copy todir="${webapps.home}" file="${deploy.home}/${app.name}.war"/>
</target>

<!–================="doc" target=========–>
<!– This task create javadoc.It is dependent upon only the ‘compile’ target
it is not executed in a normal build.As a result,the target needs to
be run on its own.
–>
<target name="javadoc" depends="compile">
<javadoc sourcepath="${src.home}" destdir="${doc.home}/api"
packagenames="${javadoc.pkg.top}.*"/>
</target>
</project>
[/xml]

下边是build.properties的文件内容:
tomcat.home=F:\\Java\\Tomcat 5.5
webapps.home=F:\\Java\\Tomcat 5.5\\webapps
大家如果仔细看了build.xml,会发现build.xml只有个project,下边会有几个target。确实是这样,每个build.xml只有一个project,属性default必须的。而每个target执行不同的功能,具体的语法,大家可以看apace ant的介绍。

Jsch 深入浅出(二)

在上面一个帖子里就简单介绍了如何基于jsch实现ssh.

下面就简单介绍一下如何实现FTP的功能通过JSCH.

[java]

public class JftpHandler extends JschHandler {
private static final Logger log = LoggerFactory
.getLogger(JftpHandler.class);

private ChannelSftp sftp = null;

public JftpHandler(String username, String host, int port, String identity) {
super(username, host, port, identity);
}

public JftpHandler(String username, String host, int port, UserInfo userInfo) {
super(username, host, port, userInfo);
}

@Override
public void init() throws JSchException {
super.init();
sftp = (ChannelSftp) session.openChannel(SFTP_PROTOCAL);//sftp
sftp.connect();
log.info("Jftp connection success.");
}

@Override
public void destory() {
if (sftp != null) {
sftp.quit();
sftp.disconnect();
}
super.destory();

log.info("Jftp destory success.");
}

public void cd(String path) throws SftpException {
sftp.cd(path);
}

public void lcd(String path) throws SftpException {
sftp.lcd(path);
}

public String lpwd() {
return sftp.lpwd();
}

public String pwd() throws SftpException {
return sftp.pwd();
}

public void mkdir(String path) throws SftpException {
sftp.mkdir(path);
}

public void rm(String path) throws SftpException {
sftp.rm(path);
}

public void quit() {
sftp.quit();
}

public void rmdir(String path) throws SftpException {
sftp.rmdir(path);
}

public void exit() {
sftp.exit();
}

public void put(String src, String dst, int mode) throws SftpException {
sftp.put(src, dst, mode);
}

public void put(String src, String dst) throws SftpException {
put(src, dst, 0);
}

public void put(String dst) throws SftpException {
put(dst, ".");
}

public void get(String src, String dst) throws SftpException {
sftp.get(src, dst);
}

public void get(String src) throws SftpException {
get(src, ".");
}

/**
* Changes the permissions of one or several remote files.
*
* @param permissions
* @param path
* @throws SftpException
*/
public void chmod(int permissions, String path) throws SftpException {
sftp.chmod(permissions, path);
}

/**
* @returns the protocol version number supported by this client
*/
public String version() {
return sftp.version();
}

}

[/java]

上面的代码只是对JSCH的简单包装,也是对JSCH的抛砖引玉。希望对大家有点用处。。。

Jsch 深入浅出(一)

如果大家熟悉Linux的话,一定对ssh,sftp,scp等命令非常熟悉。ssh是一个安全协议,用来在不同系统或者服务器之间进行安全连接。ssh 在连接和传送的过程中会加密所有的数据。具体的解释,大家可以参考百度百科的文档。地址为:http://baike.baidu.com/view/16184.htm

但是SSH一般是基于客户端的或者Linux命令行的。比如客户端的工具:OpenSSH,putty,SSH Tectia;在linux上大家可以通过ssh username@host连接到所要想连接的主机。但是如果在J2EE中,如何实现SSH呢?进而可以实现SCP,SFTP的功能呢?下面介绍的JSCH就可以实现下边的功能。

JSCH是一个纯粹的用java实现SSH功能的java  library. 官方地址为:http://www.jcraft.com/jsch/

GitHub 地址为:https://github.com/vngx/vngx-jsch

mvn 配置如下:

<dependency>

<groupId>com.jcraft</groupId>

<artifactId>jsch</artifactId>

<version>0.1.46</version>

</dependency>

 

下面简单介绍下JSCH的特点:

1.基于DSA和RSA加密。

2.可以实现4中认证机制。分别是:

  1. password
  2. publickey(DSA,RSA)
  3. keyboard-interactive
  4. gss-api-with-mic

3.生成public/private key pair.

4.执行bash script 等脚本

5.可以通过HTTP/SOCK5 proxy

6.支持常见SSH1协议和SSH2协议

我们日常用到的JSCH主要是基于是密码认证和private key 认证。

基于密码认证的比较简单。简单代码如下:

[java]

public class JschHandler {
private static final Logger log = LoggerFactory.getLogger(JschHandler.class);

public static final String SFTP_PROTOCAL = "sftp";
private String username;
private String host;
private int port;
private String identity;
private UserInfo userInfo;

private JSch jsch = null;
protected Session session = null;
private boolean firstInit = false;
private int authType = -1;

/**
* Private/public key authorization
* @param username user account
* @param host server host
* @param port ssh port
* @param identity the path of private key file.
* @see http://www.jcraft.com/jsch/
*/
public JschHandler(String username,String host,int port,String identity){
this.username = username;
this.host = host;
this.port = port;
this.identity = identity;

firstInit = false;
jsch = new JSch();

authType = 0 ;
}

/**
* Password authorization
* @param username
* @param host
* @param port
* @param userInfo User information for authorization
* @see com.jcraft.jsch.UserInfo
* @see http://www.jcraft.com/jsch/
*/
public JschHandler(String username,String host,int port,UserInfo userInfo){
this.username = username;
this.host = host;
this.port = port;
this.userInfo = userInfo;

firstInit = false;
jsch = new JSch();
authType = 1;
}
/**
*
* Initialize SSH session.
* When the parameters is not right, It will throw an JSchException.
* @throws MessageServicerException
* @see com.jcraft.jsch.JSch
*/
@SuppressWarnings("static-access")
protected void init() throws JSchException{
try {
validate();
log.info("JSCH identity:"+identity);
jsch.setLogger(new JschLogger());
jsch.setConfig("StrictHostKeyChecking", "no");

if(authType==0) jsch.addIdentity(identity);
session = jsch.getSession(username, host, port);

if(authType==1) session.setUserInfo(userInfo);
session.connect();

log.info("JSCH session connect success.");
} catch (JSchException e) {
log.error(e.getMessage());
throw e;
}
}

/**
* Validate parameters
* @throws JSchException
*/
private void validate() throws JSchException{
if(firstInit) return;
if(username==null||username.isEmpty()){
throw new JSchException("Parameter:username is empty.");
}
if(host==null||host.isEmpty()){
throw new JSchException("Parameter:host is empty.");
}else{
try {
InetAddress inet = InetAddress.getByName(host);
host = inet.getHostAddress();
log.info("JSCH connection address:"+host);
} catch (UnknownHostException e) {
throw new JSchException(e.getMessage(),e);
}
}

if(authType==0&&(identity==null||identity.isEmpty())){
throw new JSchException("Parameter:identity is empty.");
}

if(authType==1&&(userInfo==null)){
throw new JSchException("Parameter:userInfo is empty.");
}

firstInit = true;
}

/**
* release connections.
* @author
*/
protected void destory(){
if(session!=null) session.disconnect();
log.info("JSCH session destory");
}
private static class JschLogger implements com.jcraft.jsch.Logger{

@Override
public boolean isEnabled(int level) {
return true;
}

@Override
public void log(int level, String message) {
System.out.println(String.format("[JSCH –> %s]", message));
}
}

public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
}

[/java]

Client

[java]

public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {
public String getPassword() {
return null;
}

public boolean promptYesNo(String str) {
Object[] options = { "yes", "no" };
int foo = JOptionPane.showOptionDialog(null, str, "Warning",
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
return foo == 0;
}

String passphrase;
JTextField passphraseField = (JTextField) new JPasswordField(20);

public String getPassphrase() {
return passphrase;
}

public boolean promptPassphrase(String message) {
Object[] ob = { passphraseField };
int result = JOptionPane.showConfirmDialog(null, ob, message,
JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
passphrase = passphraseField.getText();
return true;
} else {
return false;
}
}

public boolean promptPassword(String message) {
return true;
}

public void showMessage(String message) {
JOptionPane.showMessageDialog(null, message);
}

final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1,
GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0);
private Container panel;

public String[] promptKeyboardInteractive(String destination,
String name, String instruction, String[] prompt, boolean[] echo) {
panel = new JPanel();
panel.setLayout(new GridBagLayout());

gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 0;
panel.add(new JLabel(instruction), gbc);
gbc.gridy++;

gbc.gridwidth = GridBagConstraints.RELATIVE;

JTextField[] texts = new JTextField[prompt.length];
for (int i = 0; i < prompt.length; i++) {
gbc.fill = GridBagConstraints.NONE;
gbc.gridx = 0;
gbc.weightx = 1;
panel.add(new JLabel(prompt[i]), gbc);

gbc.gridx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weighty = 1;
if (echo[i]) {
texts[i] = new JTextField(20);
} else {
texts[i] = new JPasswordField(20);
}
panel.add(texts[i], gbc);
gbc.gridy++;
}

if (JOptionPane.showConfirmDialog(null, panel, destination + ": "
+ name, JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
String[] response = new String[prompt.length];
for (int i = 0; i < prompt.length; i++) {
response[i] = texts[i].getText();
}
return response;
} else {
return null; // cancel
}
}
}

[/java]

测试类

[java]

public void testSftp() throws JSchException{
UserInfo userInfo = new MyUserInfo();
JftpHandler jhandler = new JftpHandler("username","hostname",22,userInfo);
try {
jhandler.init();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String pwd = null;
try {
pwd = jhandler.pwd();
} catch (SftpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(pwd);
// jhandler.destory();
}

[/java]

基于private key 认证的有点费时。关于如何配置private/public key认证,大家通过google来配置。简单流程如下:

1.在linux 下执行ssh-keygen -t dsa /ssh-keygen -t rsa.这样就会成一对对应的public key 和private key.比如id_dsa_1024,id_dsa_1024.pub.

2. 把public key(id_dsa_1024.pub)复制到想要连接的服务器上,放到对应用户的.ssh目录下。

3.

cd ~/.ssh

#将Client的公钥放入Server的信任列表

cat id_dsa_1024.pub >> authorized_keys

#更新权限,很重要

chmod 0600 *从此以后Client SSH登录Server就不要手工输入密码了

配置完成以后,重新登录一下,就可以发现不用输入密码就可以实现远程登录了。

由于现在基于SSH协议的算法很多,加密和解密的算法也不一样。目前Jsch只支持OpenSSH和SSH 1生成的private/public key.

所以当你们发现不能通过private/public key认证的时候,不是jsch的问题,而是不能识别的问题。

简单代码如下:

[java]

@Test
public void testSftp() throws JSchException{
JftpHandler jhandler = new JftpHandler("username","hostname",22,"C:\\data\\id_dsa_2048_a");
try {
jhandler.init();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String pwd = null;
try {
pwd = jhandler.pwd();
} catch (SftpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(pwd);
// jhandler.destory();
}

[/java]

上面只是对JSCH的简单介绍,希望对大家有所用户。。。。

 

wordpress 中文标题/标签 404

搭建WordPress,版本4.3, 发现点击中文标题和中文标签的固定连接都会报页面找不到的错误,google/baidu了很久,大部分的解决方法都是改下边的代码:

打开wp-include中的classes.php文件

[php]
//$pathinfo = $_SERVER[‘PATH_INFO’];
$pathinfo = mb_convert_encoding($_SERVER[‘PATH_INFO’], "UTF-8", "GBK");

//$req_uri = $_SERVER[‘REQUEST_URI’];
$req_uri = mb_convert_encoding($_SERVER[‘REQUEST_URI’], "UTF-8", "GBK");
[/php]

但是经过测试,我发现并没有解决问题,于是从源代码入手,debug我发现我的文章(地址是:http://localhost/index.php/2016/03/14/%E6%B5%8B%E8%AF%95/),

PATH_INFO=”/2016/03/14/测试/”,但是REQUEST_URI=”/index.php/2016/03/14/%e6%b5%8b%e8%af%95/”,

说明编码是UTF8格式,但是REQUEST_URI并没有经过编码,而是进行了URL encode,通过下边的网址可以证明。

UrlEncode编码/解码

找到原因,就很好解决了。下边是需要改的代码:

classes.php文件

[php]
list ( $req_uri ) = explode ( ‘?’, urldecode ( $_SERVER [‘REQUEST_URI’] ) );
[/php]