java调用shell脚本实现文件上传(Java操作Linux)
java调用shell脚本实现文件上传(Java操作Linux)
一、本项目核心目的(目前支持.sql 和 .py脚本,.java脚本跟.py脚本大同小异,只是命令不同)
- 1.从A服务器获取脚本文件
- 2.上传到B服务器指定文件夹
- 3.通过命令执行上传后得脚本文件
- 4.返回执行结果
<!--sftp文件上传-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
<!--ssh执行-->
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
三、Spring Boot 与 nacos 版本不对应时会报错,当前Spring Boot版本为2.3.9.RELEASE
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.7</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<!--sftp文件上传-->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
</dependencies>
五、RemoteCommandConfig(服务器调用)
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@Slf4j
@Component
public class RemoteCommandConfig {
/**
* 只是用来测试,无其他用处
*/
public static void main(String[] args) {
Connection conn = login("这里填服务器IP地址" "账号" "密码");
JSONObject execute = execute(conn "cd /script/ &&mysql -vvv -uadmin -p123456 spring_data < 测试.sql");
System.out.println(execute.toString());
}
private static String DEFAULTCHART = "UTF-8";
/**
* @return 登录成功返回true,否则返回false
* @描述 登录主机
*/
public static Connection login(String ip String username String password) {
boolean flg;
Connection conn = null;
try {
conn = new Connection(ip);
conn.connect();//连接
flg = conn.authenticateWithPassword(username password);//认证
if (flg) {
return conn;
}
} catch (IOException e) {
log.error("脚本执行登录服务器失败 error={}" e.getMessage());
e.printStackTrace();
}
return conn;
}
/**
* @param cmd 即将执行的命令
* @return 命令执行完后返回的结果值
* @描述 远程执行shll脚本或者命令
*/
public static JSONObject execute(Connection conn String cmd) {
JSONObject result = new JSONObject();
result.put("code" 200);
String str = "";
try {
if (conn != null) {
session session = conn.openSession();//打开一个会话
session.execCommand(cmd);//执行命令
str = processStdout(session.getStdout() DEFAULTCHART);
//如果为得到标准输出为空,说明脚本执行出错了
if (StringUtils.isBlank(str)) {
result.put("code" 400);
result.put("msg" "得到标准输出为空 链接conn:" conn " 执行的命令:" cmd);
str = processStdout(session.getStderr() DEFAULTCHART);
} else {
result.put("msg" 200);
result.put("msg" "执行命令成功 链接conn:" conn " 执行的命令:" cmd);
}
conn.close();
session.close();
}
} catch (IOException e) {
log.info("执行命令失败 链接conn:" conn " 执行的命令:" cmd " error={}" e.getMessage());
}
result.put("data" str);
return result;
}
/**
* @param in 输入流对象
* @param charset 编码
* @return 以纯文本的格式返回
* @描述 解析脚本执行返回的结果集
*/
private static String processStdout(InputStream in String charset) {
InputStream stdout = new StreamGobbler(in);
StringBuffer buffer = new StringBuffer();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(stdout charset));
String line;
while ((line = br.readLine()) != null) {
buffer.append(line "\n");
}
} catch (Exception e) {
log.error("解析脚本出错 error={}" e.getMessage());
e.printStackTrace();
}
return buffer.toString();
}
六、RestTemplateConfig防止项目因为RestTemplate启动失败
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder.build();
}
}
七、ScriptDealWithController (方法整合)
import ch.ethz.ssh2.Connection;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.sd.config.RemoteCommandConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.*;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
//nacos实时动态参数获取
@RefreshScope
@RestController
@RequestMapping("/script")
public class ScriptDealWithController {
/**
* 本项目所在服务器地址
*/
@NacosValue(value = "${gyyh_login.ip}")
private String gyyhIP;//登录获取ip
@NacosValue(value = "${gyyh_login.username}")
private String gyyhUsername;//系统账号
@NacosValue(value = "${gyyh_login.password}")
private String gyyhPassword;//系统密码
/**
* MySQL服务器地址
*/
@NacosValue(value = "${mysql_script.ip}")
private String myIp;//MySQL所在ip
@NacosValue(value = "${mysql_script.username}")
private String myUsername;//MySQL所在ip账号
@NacosValue(value = "${mysql_script.password}")
private String myPassword;//MySQL所在ip密码
@NacosValue(value = "${mysql_script.command}")
private String myCommand;//MySQL脚本执行命令
@NacosValue(value = "${mysql_script.file_path}")
private String myFilePath;//文件保存路径
/**
* pythonL服务器地址
*/
@NacosValue(value = "${python_script.ip}")
private String pyIp;//MySQL所在ip
@NacosValue(value = "${python_script.username}")
private String pyUsername;//MySQL所在ip账号
@NacosValue(value = "${python_script.password}")
private String pyPassword;//MySQL所在ip密码
@NacosValue(value = "${python_script.command}")
private String pyCommand;//MySQL脚本执行命令
@NacosValue(value = "${python_script.file_path}")
private String pyFilePath;//文件保存路径
@Autowired
private RestTemplate restTemplate;
/**
* @描述 获取平台登录token
* @参数 []
* @返回值 java.lang.String
* @创建时间 2021/7/23
*/
public String getToken() {
String url = gyyhIP "/获取token地址";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String String> params = new LinkedMultiValueMap<>();
params.add("username" gyyhUsername);
params.add("password" gyyhPassword);
HttpEntity<MultiValueMap<String String>> requestEntity = new HttpEntity<>(params headers);
ResponseEntity<String> response = restTemplate.exchange(url HttpMethod.POST requestEntity String.class);
JSONObject body = JSON.parseObject(response.getBody());
JSONObject data = body.getJSONObject("data");
if (CollectionUtils.isEmpty(data)) {
throw new RuntimeException("token获取失败");
}
return data.getString("token");
}
/**
* @描述 调用平台文件下载接口获取文件流
* @参数 [body]
* @返回值 byte[]
* @创建时间 2021/7/23
*/
public byte[] download(String token String type String downloadId) {
String url = gyyhIP "文件下载接口地址";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization" token);
Map<String String> params = new HashMap<>();
params.put("type" type);
params.put("downloadId" downloadId);
HttpEntity<Map<String String>> requestEntity = new HttpEntity<>(params headers);
ResponseEntity<byte[]> response = restTemplate.postForEntity(url requestEntity byte[].class);
return response.getBody();
}
/**
* @描述 写入文件到指定目录下
* @参数 [bfile filePath fileName]
* @返回值 void
* @创建时间 2021/7/23
*/
public void upload(byte[] bfile String ip String username String password String filePath String fileName) throws Exception {
//服务器端口 默认22
int port = 22;
Session session = null;
Channel channel = null;
JSch jsch = new JSch();
if (port <= 0) {
//连接服务器,采用默认端口
session = jsch.getSession(username myIp);
} else {
//采用指定的端口连接服务器
session = jsch.getSession(username ip port);
}
//如果服务器连接不上,则抛出异常
if (session == null) {
throw new Exception("session is null");
}
//设置登陆主机的密码
session.setPassword(password);//设置密码
//设置第一次登陆的时候提示,可选值:(ask | yes | no)
session.setConfig("StrictHostKeyChecking" "no");
//设置登陆超时时间
session.connect(30000);
OutputStream outstream = null;
try {
//创建sftp通信通道
channel = session.openChannel("sftp");
channel.connect(1000);
ChannelSftp sftp = (ChannelSftp) channel;
//进入服务器指定的文件夹
sftp.cd(filePath);
//以下代码实现从本地上传一个文件到服务器,如果要实现下载,对换以下流就可以了
outstream = sftp.put(fileName);
outstream.write(bfile);
} catch (Exception e) {
e.printStackTrace();
} finally {
//关流操作
if (outstream != null) {
outstream.flush();
outstream.close();
}
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
}
/**
* @描述 脚本执行
* @参数 [body]
* @返回值 java.lang.String
* @创建时间 2021/7/27
*/
@PostMapping("/execute")
public JSONObject execute(@RequestBody JSONObject body) throws Exception {
String fileName = "";
String type = body.getString("type");
String downloadId = body.getString("downloadId");
//脚本类型 sql 、python
String languageType = body.getString("languageType");
Connection conn = null;
//执行脚本
String cmd = "";
//获取平台登录token
String token = getToken();
//调用平台文件下载接口获取文件流
byte[] download = download(token type downloadId);
if (StringUtils.equals("sql" languageType)) {
cmd = myCommand;
fileName = new Date().getTime() ".sql";
conn = RemoteCommandConfig.login(myIp myUsername myPassword);
//写入文件到sql服务器指定目录下
upload(download myIp myUsername myPassword myFilePath fileName);
} else if (StringUtils.equals("python" languageType)) {
cmd = pyCommand;
fileName = new Date().getTime() ".py";
conn = RemoteCommandConfig.login(pyIp pyUsername pyPassword);
//写入文件到py服务器指定目录下
upload(download pyIp pyUsername pyPassword pyFilePath fileName);
}
//执行脚本
return RemoteCommandConfig.execute(conn cmd fileName);
}
}
八、启动类
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@NacosPropertySource(dataId = "script_****" type = ConfigType.YAML groupId = "DEFAULT_GROUP" autoRefreshed = true)
public class ScriptDealWithApplication {
public static void main(String[] args) {
SpringApplication.run(ScriptDealWithApplication.class args);
}
}
九、application.yml配置
server:
port: 8001
nacos:
config:
server-addr: 101.***.**.**:8848 #Nacos 链接地址
namespace: 55572fea-***-********************* #Nacos 命名空间ID
十、nacos配置
gyyh_login:
ip: http://101.***.***.***:8088/
username: admin
password: 123456
mysql_script:
ip: 192.168.**.***
username: root
password: vagrant
file_path: /usr/local/script/
command: cd /usr/local/script/ &&mysql -vvv -uroot -p123456 spring_data <
python_script:
ip: 192.168.**.***
username: root
password: vagrant
file_path: /usr/local/script/
command: python /usr/local/script/