上传文件到linux或执行服务器端命令行

什么是Jsch ?

JSch 是SSH2的一个纯Java实现。它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文件传输等等。你可以将它的功能集成到你自己的 程序中。同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器。

本文目的 ?

由于工作的原因涉及到从本地上传多个文件到远程服务器上,上传之后并执行远程服务器上的脚本,为了实现这些步骤的自动化,所以做了些技术尝试。

如何实现?

很简单 贴代码。

1. 创建Maven项目,导入相关依赖。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.XXX.rapid.deploy</groupId>
  <artifactId>rapid-deploy</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>rapid-deploy</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>
    <dependency>
	  <groupId>com.jcraft</groupId>
	  <artifactId>jsch</artifactId>
	  <version>0.1.48</version>
	</dependency>
  </dependencies>
</project>

2. 用TDD的方式开发,我们先写一个连接服务器的测试。

package com.XXX.rapid.deploy;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

import com.jcraft.jsch.Session;

public class SSHSessionTest {

	private SSHSession sshSession;

	@Before
	public void setUp() {
		sshSession = new SSHSession();
	}

	@Test
	public void shouldAcceptIfUserLoinInfoIsCorrect() throws Exception {

		// When
		Session session = sshSession.openSession("wenhao", "1qaz!QAZ",
				"10.0.0.6", 22);

		// Then
		assertThat(session.isConnected(), is(true));
	}

	@Test
	public void shouldRejectIfUserLoginInfoIsWrong() throws Exception {
		// When
		Session session = sshSession.openSession("Wrong Username", "password",
				"host", 0);

		// Then
		assertThat(session, nullValue());
	}

}

3. 它的实现类。

package com.XXX.rapid.deploy;

import java.util.Properties;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class SSHSession {

	private static final int TIMEOUT = 3000;

	public Session openSession(String username, String password, String host,
			int port) {
		Session session = null;
		try {
			session = connect(username, password, host, port);
		} catch (JSchException e) {
			System.out.println("[ERROR] " + e.getMessage()
					+ ", check your username and password.");
		}
		return session;
	}

	private Session connect(String username, String password, String host,
			int port) throws JSchException {
		Session session = new JSch().getSession(username, host, port);
		session = skipHostKeyChecking(session);
		session.setPassword(password);
		session.connect(TIMEOUT);
		return session;
	}

	private Session skipHostKeyChecking(Session session) {
		Properties config = new Properties();
		config.put("StrictHostKeyChecking", "no");
		session.setConfig(config);
		return session;
	}

}

4. 测试执行命令行。

package com.XXX.rapid.deploy;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

import com.jcraft.jsch.Session;

public class ShellExecuterTest {

	private SSHSession sshSession;
	private ShellExecuter shellExecuter;

	@Before
	public void setUp() {
		sshSession = new SSHSession();
		Session session = sshSession.openSession("wenhao", "1qaz!QAZ",
				"10.0.0.6", 22);
		shellExecuter = new ShellExecuter(session);
	}

	@Test
	public void shouldAcceptWhenExecuteCommand() throws Exception {
		// Given
		String command = "cd upload;sh deploy.sh";

		// When

		String result = shellExecuter.execute(command);
		System.out.println(result);

		// Then
		assertThat(result.trim(), is("This is a bash script"));
	}
}

5. 执行命令行实现类。

package com.XXX.rapid.deploy;

import java.io.IOException;
import java.io.InputStream;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class ShellExecuter {

	private static final int BLOCK_SIZE = 1024;
	private Session session;

	public ShellExecuter(Session session) {
		this.session = session;
	}

	private ChannelExec openChannelExec(Session session) {
		ChannelExec channelExec = null;
		try {
			Channel channel = session.openChannel("exec");
			channelExec = (ChannelExec) channel;
		} catch (JSchException e) {
			e.printStackTrace();
		}
		return channelExec;
	}

	public String execute(String command) throws IOException, JSchException {
		ChannelExec channelExec = openChannelExec(session);
		StringBuffer buffer = executeCommand(command, channelExec);
		closeChannelExec(channelExec);
		return buffer.toString();
	}

	private StringBuffer executeCommand(String command, ChannelExec channelExec)
			throws IOException, JSchException {
		InputStream result = channelExec.getInputStream();
		channelExec.setCommand(command);
		channelExec.connect();
		StringBuffer buffer = generateResult(result);
		return buffer;
	}

	private StringBuffer generateResult(InputStream inputStream)
			throws IOException {
		StringBuffer buffer = new StringBuffer();
		byte[] bytes = new byte[BLOCK_SIZE];
		while (inputStream.read(bytes) > 0) {
			buffer.append(new String(bytes));
		}
		return buffer;
	}

	private void closeChannelExec(ChannelExec channelExec) {
		channelExec.disconnect();
	}

}

6. 测试文件上传。

package com.XXX.rapid.deploy;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.io.File;

import org.junit.Before;
import org.junit.Test;

import com.jcraft.jsch.Session;

public class FileSenderTest {

	private SSHSession sshSession;
	private FileSender fileSender;

	@Before
	public void setUp() {
		sshSession = new SSHSession();
		Session session = sshSession.openSession("wenhao", "1qaz!QAZ",
				"10.0.0.6", 22);
		fileSender = new FileSender(session);
	}

	@Test
	public void shouldAcceptWhenUploadFileToRemoteServer() throws Exception {
		// Given

		// When
		boolean isUploaded = fileSender.upload("/home/wenhao", new File(
				"demo.txt"));
		boolean isFileUploaded = fileSender.upload(
				"/home/wenhao/upload", new File("demo.txt"));

		// Then
		assertThat(isUploaded, is(true));
		assertThat(isFileUploaded, is(true));
	}

	@Test
	public void shouldRejectIfUserDontHaveWritePremissionOnRemoteDirectory()
			throws Exception {
		// Given

		// When
		boolean isFileUploaded = fileSender.upload("/home", new File(
				"demo.txt"));

		// Then
		assertThat(isFileUploaded, is(false));
	}

	@Test
	public void shouldRejectIfLoaclFileIsNotExist() throws Exception {
		// When
		boolean isUploaded = fileSender.upload("/home/wenhao", new File(
				"demo2.txt"));

		// Then
		assertThat(isUploaded, is(false));
	}

	@Test
	public void shouldRejectIfRemoteDirectoryIsNotExist() throws Exception {
		// When
		boolean isUploaded = fileSender.upload(
				"/home/wenhao/notexitstdir", new File("demo.txt"));

		// Then
		assertThat(isUploaded, is(false));
	}
}

7. 文件上传的实现类。

package com.XXX.rapid.deploy;

import java.io.File;
import java.io.FileInputStream;
import java.util.Vector;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

public class FileSender {

	private Session session;

	public FileSender(Session session) {
		this.session = session;
	}

	public ChannelSftp openChannelSftp(Session session) {
		ChannelSftp channelSftp = null;
		try {
			Channel channel = session.openChannel("sftp");
			channel.connect();
			channelSftp = (ChannelSftp) channel;
		} catch (JSchException e) {
			e.printStackTrace();
		}
		return channelSftp;
	}

	public boolean isChangeedDirectory(String path, ChannelSftp channelSftp) {
		try {
			channelSftp.cd(path);
			return true;
		} catch (Exception e) {
			System.out.println("[ERROR] " + path + ": No such directory");
		}
		return false;
	}

	public boolean upload(String directory, File uploadFile) {
		boolean isUploaded = false;
		ChannelSftp channelSftp = openChannelSftp(session);
		if (isChangeedDirectory(directory, channelSftp)) {
			isUploaded = uploadFile(directory, uploadFile, channelSftp);
		}
		return isUploaded;
	}

	private boolean uploadFile(String directory, File uploadFile,
			ChannelSftp channelSftp) {
		boolean isUploadedFile = false;
		try {
			channelSftp.put(new FileInputStream(uploadFile),
					uploadFile.getName());
			isUploadedFile = isFileUploaded(directory, uploadFile, channelSftp);
		} catch (Exception e) {
			System.out.println("[ERROR] " + e.getMessage());
		}
		return isUploadedFile;
	}

	@SuppressWarnings("unchecked")
	private boolean isFileUploaded(String directory, File uploadFile,
			ChannelSftp channelSftp) throws SftpException {
		boolean isFileUploaded = false;
		Vector<LsEntry> files = channelSftp.ls(directory);
		for (LsEntry file : files) {
			isFileUploaded |= isFileExist(uploadFile, file);
		}
		return isFileUploaded;
	}

	private boolean isFileExist(File uploadFile, LsEntry file) {
		return uploadFile.getName().equals(file.getFilename()) ? true : false;
	}

}

 使用Groovy就会简单很多:

class SSHClient
{
    def ant
    def SSHClient()
    {
        ant = new AntBuilder()
    }

    def uploadFile(localFile, remoteTodir, certificate)
    {
        ant.scp (
            file: localFile,
            todir: certificate+":"+remoteTodir,
            verbodr: true,
            trust: true
        )
    }

    def uploadDir(localDir, remoteTodir, certificate)
    {
        ant.scp (
            todir: certificate+":"+remoteTodir,
            verbodr: true,
            trust: true
        ){
            fileset(dir: localDir)
        }
    }

    def executeCmd(command, host, username, password)
    {
        ant.sshexec (
            host: host,
            port: 22,
            username: username,
            password: password,
            command: command,
            trust: true,
            outputproperty: 'result'
        )
        return ant.project.properties.'result'
    }
}


用Jsch比较方便的一点就是平台独立性,适用于不同的操作系统,而且也相当的简单。但是还有更简单的方法,第一种就是使用ant脚本,ant只是jsch;第二种使用gradle脚本,其实也是调用的ant;第三种是用Groovy语言写,groovy集成了ant功能,但是毕竟是动态语言灵活性比较好,推荐使用。本人代码水平不高,还望看客多给意见,有问题请mail我devhup@gmail.com.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值