美文网首页python
Java 操作 Linux 服务器 上传文件并执行脚本

Java 操作 Linux 服务器 上传文件并执行脚本

作者: 王疏蔬 | 来源:发表于2021-07-27 12:21 被阅读0次

    一、本项目核心目的

    (目前支持.sql 和 .py脚本,.java脚本跟.py脚本大同小异,只是命令不同)

    • 1.从A服务器获取脚本文件
    • 2.上传到B服务器指定文件夹
    • 3.通过命令执行上传后得脚本文件
    • 4.返回执行结果

    二、核心jar包

    <!--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

    四、pom.xml 文件

    <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/
    

    相关文章

      网友评论

        本文标题:Java 操作 Linux 服务器 上传文件并执行脚本

        本文链接:https://www.haomeiwen.com/subject/fvtomltx.html