上传文件到linux或执行服务器端命令行
什么是Jsch ?JSch 是SSH2的一个纯Java实现。它允许你连接到一个sshd 服务器,使用端口转发,X11转发,文件传输等等。你可以将它的功能集成到你自己的 程序中。同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器。本文目的 ?由于工作的原因涉及到从本地上传多个文件到远程服务器上,上传之后并执行远程服务器上的脚本,为了实现这些步骤的自动化,所以做了些
什么是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.
更多推荐
所有评论(0)