原创

Java-执行sh文件脚本-cmd命令-查找并复制so库文件到jdk库文件夹-复制sh脚本文件到当前jar包路径-判断指定目录下是否有某个文件

注意:相对项目有新增,下次不可以直接全部复制

package cn.jiangjiesheng.fst.service.impl;

import cn.jiangjiesheng.fst.config.BizzConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 1、命令行重启 libreoffice
 * 2、复制jpeg,so到jdk库文件路径
 *
 * https://blog.51cto.com/stefanxfy/5083542
 * https://blog.csdn.net/m0_37298500/article/details/125780155
 *
 * 执行cmd命令的示例:
 * 1、killAndDeleteLibreOfficeTmp()
 * 2、if(isLinuxOS()){
 *     Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "chmod +x " + file.getAbsolutePath()}).waitFor();
 *    }
 *
 * 关键方法:
 * 1、killAndDeleteLibreOfficeTmp 执行sh文件脚本
 * 2、justRestartLibreOffice 执行cmd命令
 * 3、writeJpegSoToLibAmd64Path 往jdk的库文件安装路径复制jpeg.so
 * 4、writeCloseLibreOfficeShell 往jar包(idea环境是项目代码的目录)所在目录复制脚本
 * 5、getCloseLibreOfficePath 往jar包(idea环境是项目代码的目录)所在目录路径
 * 6、isLinuxOS 是否是linux系统
 * 7、getJavaInstallLibAmd64Path 获取jdk的库文件安装路径
 * 8、hasFile 判断指定目录下是否有某个文件(注意目录使用File.separatorChar处理过)
 *
 * 更多文件类操作见《Java-JFileUtil-文件类操作-创建多级目录-创建临时文件-查找临时文件夹路径-删除指定关键字的文件》
 */
@Service("fstStatusCheckService")
@Slf4j
@Order(value = 1)
public class FstStatusCheckService {

    private static boolean hasWriteJpegSoToLibAmd64Path = false;

    @Value(value = "${jodconverter.local.office-home}")
    private String officeHome;
    @Value("#{'${jodconverter.local.portNumbers:2002,2003}'.split(',')}")
    private List<Integer> portNumbers;

    @Autowired
    private BizzConfig bizzConfig;

    //这些批量再通过 justRestartLibreOffice 实现不知道行不行,以后可以尝试,目前是killAndDeleteLibreOfficeTmp这个方法执行的
    private static List<String> RESTART_LIBRE_OFFICE_CMD_4_LINUX = new ArrayList<String>() {
        {
            add("kill -9 `ps -ef|grep libreoffice|grep -v grep|awk '{print $2}'`");
            add("rm -rf /tmp/.jodconverter*");
            add("kill -9 `ps -ef|grep libreoffice|grep -v grep|awk '{print $2}'`");
        }
    };

    /**
     *  killAndDeleteLibreOfficeTmp 弃用
     *  先关闭再重启[justRestartLibreOffice 启动进程后也不能使用]
     *
     *  最终使用以下方法控制关闭和启动
     *  OfficeConverter.closeLibreOffice();
     *
     *  if(!officeManager.isRunning()){
     *    this.init();
     *  }
     *
     * 这里只关 进程,和rm tmp下的文件,justRestartLibreOffice 注释掉
     * 每次定时任务完成后并在下次任务开始前执行,见 convertThreadEntry() # needRestartLibreOfficeAfterThisScheduleTask
     * 定时任务执行过程过如果出现转码失败,也会立即执行
     *
     */
    public void killAndDeleteLibreOfficeTmp(boolean checkConfigSwitch) {

        if(!bizzConfig.getEnableKillAndDeleteLibreOfficeTmp()){
            log.info("FstStatusCheckService#不执行kill libreOffice进程脚本,enable.killAndDeleteLibreOfficeTmp={}",bizzConfig.getEnableKillAndDeleteLibreOfficeTmp());
            return;
        }
        //记录下,fstStatusCheckService.killAndDeleteLibreOfficeTmp(true);执行时,这个判断条件不满足而放行时,转码服务稳定。
        //也就是如果当前版本有问题,可以把enable.KillAndDeleteLibreOfficeTmpAfterThisScheduleTask改成true,每轮有文档的定时任务都会执行这个kill和rm的脚本,会有一些日志。
        if(checkConfigSwitch && !bizzConfig.getEnableKillAndDeleteLibreOfficeTmpAfterThisScheduleTask()){
            log.info("FstStatusCheckService#不执行kill libreOffice进程脚本,enable.killAndDeleteLibreOfficeTmpAfterThisScheduleTask={}",bizzConfig.getEnableKillAndDeleteLibreOfficeTmpAfterThisScheduleTask());
           return;
        }

        log.info("FstStatusCheckService#即将执行kill libreOffice进程脚本");

        if (isLinuxOS()) {
            //https://blog.csdn.net/m0_37298500/article/details/125780155
            try{
                String targetFilePath = getCloseLibreOfficePath();

                Process process = Runtime.getRuntime().exec("sh "+targetFilePath);
                InputStreamReader ips = new InputStreamReader(process.getInputStream());
                BufferedReader br = new BufferedReader(ips);
                String line;
                while ((line = br.readLine()) != null) {
                    // 这个返回值对命令执行,不知道是不是也很关键
                    log.info("FstStatusCheckService#执行kill libreOffice进程脚本文件:{},返回值:{}", targetFilePath, line);
                }
            } catch (Exception e) {
                log.warn("FstStatusCheckService#即将执行kill libreOffice进程脚本出现异常:{}", e);
            }
            // justRestartLibreOffice();
        } else {
            log.info("FstStatusCheckService#当前非linux环境,不即将执行kill libreOffice进程脚本");
        }
    }


    /**
     * 重启libreOffice [命令可以生效,进程可以生成,但是进程仍然不工作]
     * 关键词 端口 8100
     */
    @Deprecated
    public void justRestartLibreOffice(){
    // 这个之前的8100的端口的,不行
    // nohup /opt/libreoffice6.4/program/soffice --headless --accept="socket,host=127.0.0.1,port=22413;urp;" --nofirststartwizard &
    // fst 自己启动的是这样的,
    // nohup /opt/libreoffice6.4/program/soffice.bin --accept=socket,host=127.0.0.1,port=22412,tcpNoDelay=1;urp;StarOffice.ServiceManager --headless --invisible --nocrashreport --nodefault --nofirststartwizard --nolockcheck --nologo --norestore -env:UserInstallation=file:///tmp/.jodconverter_socket_host-127.0.0.1_port-22412_tcpNoDelay-1 &
     //需要加""
    // nohup /opt/libreoffice6.4/program/soffice --accept="socket,host=127.0.0.1,port=22412,tcpNoDelay=1;urp;StarOffice.ServiceManager" --headless --invisible --nocrashreport --nodefault --nofirststartwizard --nolockcheck --nologo --norestore -env:UserInstallation=file:///tmp/.jodconverter_socket_host-127.0.0.1_port-22412_tcpNoDelay-1 &
        log.info("FstStatusCheckService#即将执行startlibreOffice进程脚本开始");
        if(!officeHome.endsWith("/")){
            officeHome = officeHome+"/";
        }
        for (Integer portNumber : portNumbers) {
           // String cmd = "nohup "+ officeHome + "program/soffice --headless --accept=\"socket,host=127.0.0.1,port=" + portNumber + ";urp;\" --nofirststartwizard &";
            String cmd = "nohup "+ officeHome + "program/soffice --headless --accept=\"socket,host=127.0.0.1,port=" + portNumber + ",tcpNoDelay=1;urp;StarOffice.ServiceManager\"  --headless --invisible --nocrashreport --nodefault --nofirststartwizard --nolockcheck --nologo --norestore -env:UserInstallation=file:///tmp/.jodconverter_socket_host-127.0.0.1_port-"+portNumber+"_tcpNoDelay-1 &";
            try {
                int execValue = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd}).waitFor();
                log.info("FstStatusCheckService#执行startlibreOffice进程脚本完成: cmd:{},返回值execValue:{}", cmd, execValue);
            } catch (Exception e) {
                log.info("FstStatusCheckService#执行startlibreOffice进程脚本出现异常,cmd:{},异常:{}", cmd, e);
            }
        }
    }

    //执行复制
    //往jdk的库文件安装路径复制jpeg.so (/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/amd64)
    public void writeJpegSoToLibAmd64Path(boolean mustRetry) {
        try {
            if(mustRetry){
                hasWriteJpegSoToLibAmd64Path = false;
            }
            if (hasWriteJpegSoToLibAmd64Path) {
                return;
            }
            //结尾带/
            String libAmd64Path = getJavaInstallLibAmd64Path();
            if (StringUtils.isBlank(libAmd64Path)) {
                hasWriteJpegSoToLibAmd64Path = true;
                log.info("FstStatusCheckService#writeJpegSoToLibAmd64Path:获取libAmd64Path为空,不执行写jpeg.so");
                return;
            }
            //linux是libjpeg.so
            //windows是jpeg.dll
            boolean hasFile = hasFile(libAmd64Path, "libjpeg.so");
            if (hasFile) {
                hasWriteJpegSoToLibAmd64Path = true;
                log.info("FstStatusCheckService#writeJpegSoToLibAmd64Path:路径下已有文件,不执行写jpeg.so");
                return;
            }
            InputStream inputStream = this.getClass().getResourceAsStream("/libRes/libjpeg.so");
            try {
                File soFile = null;
                if (libAmd64Path.endsWith("/")) {
                    soFile = new File(libAmd64Path + "libjpeg.so");
                } else {
                    soFile = new File(libAmd64Path + "/libjpeg.so");
                }

            //         没有执行这个,也写入成功了
            //         file.createNewFile();
            //         file.setWritable(true);


                FileUtils.copyInputStreamToFile(inputStream, soFile);
                hasWriteJpegSoToLibAmd64Path = true;
                hasFile = hasFile(libAmd64Path, "libjpeg.so");
                if (hasFile) {
                    log.info("FstStatusCheckService#writeJpegSoToLibAmd64Path:执行写jpeg.so 成功");
                    String cmd = "chmod +x " + soFile.getAbsolutePath();
                    try {
                        //Runtime.getRuntime().exec("chmod +x " + soFile.getAbsolutePath());
                        Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "chmod +x " + soFile.getAbsolutePath()}).waitFor();
                        log.info("FstStatusCheckService#writeJpegSoToLibAmd64Path:执行修复jpeg.so可执行权限 成功");
                    } catch (Exception e) {
                        log.warn("FstStatusCheckService#writeJpegSoToLibAmd64Path 写可执行权限出现异常,cmd:{},异常:{}", cmd, e);
                    }
                } else {
                    log.info("FstStatusCheckService#writeJpegSoToLibAmd64Path:执行写jpeg.so失败,写入后没有找到,去确认下,可能已经写了");
                }
            } catch (IOException e) {
                hasWriteJpegSoToLibAmd64Path = true;
                log.warn("FstStatusCheckService#writeJpegSoToLibAmd64Path 写文件出现异常,异常:{}", e);
            }
        } catch (Exception e) {
            log.warn("FstStatusCheckService#writeJpegSoToLibAmd64Path 写文件出现异常,异常:{}", e);
        }
    }

    public void writeCloseLibreOfficeShell() {
        try {
            String targetFilePath = getCloseLibreOfficePath();
            File file = new File(targetFilePath);
            if (!file.exists()) {
                file.createNewFile();
            }
            file.setWritable(true);

            InputStream inputStream = this.getClass().getResourceAsStream("/libRes/closeLibreOffice.sh");
            FileUtils.copyInputStreamToFile(inputStream, file);
            log.info("FstStatusCheckService#closeLibreOffice.sh 已写入到jar包当前文件夹下");
            // Runtime.getRuntime().exec("chmod +x " + file.getAbsolutePath());
            if (isLinuxOS()) {
                try {
                    Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "chmod +x " + file.getAbsolutePath()}).waitFor();
                } catch (InterruptedException e) {
                    log.error("FstStatusCheckService#closeLibreOffice.sh 写入到jar包当前文件夹出现异常 waitFor异常:{}", e);
                }
            }
        } catch (IOException e) {
            log.error("FstStatusCheckService#closeLibreOffice.sh 写入到jar包当前文件夹出现异常,异常:{}", e);
        }
    }

    private String getCloseLibreOfficePath(){
        String targetFile = "." + File.separatorChar + "closeLibreOffice.sh";
        targetFile = "closeLibreOffice.sh";
        return targetFile;
    }

    private boolean isLinuxOS() {
        Properties properties = System.getProperties();
        //判断是否是linux
        String os = properties.getProperty("os.name");
        log.info("isLinuxOS:{}",os);
        return os != null && os.toLowerCase().contains("linux");
    }

    /**
     * 期望获取 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/amd64
     *
     * @return
     */
    private String getJavaInstallLibAmd64Path() {
        String libAmd64Path = null;
        if (isLinuxOS()) {
            try {
                Process exec = Runtime.getRuntime().exec("ls -lrt /etc/alternatives/java");
                InputStream inputStream = exec.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "gb2312"));
                String line;
                //一般只要读第一行,
                while ((line = br.readLine()) != null) {
                    log.info("FstStatusCheckService#getJavaInstallLibAmd64Path#执行命令的结果:{}", line);
                    if (StringUtils.isNotBlank(line)) {
                        //lrwxrwxrwx. 1 root root 73 5月  31  2022 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/bin/java
                        // /jre/lib/amd64
                        String[] str = line.split(" ");
                        log.info("FstStatusCheckService#getJavaInstallLibAmd64Path#执行结果分割:{}", (Object) str);
                        if (str.length > 1) {
                            String path = str[str.length - 1];
                            if (path != null && path.contains("jre/bin/java")) {
                                libAmd64Path = path.replace("jre/bin/java", "jre/lib/amd64");
                                log.info("FstStatusCheckService#getJavaInstallLibAmd64Path#获取到libAmd64Path:{}", libAmd64Path);

                                //libAmd64Path = "/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/amd64";
                                String[] split = libAmd64Path.split("/");

                                //TODO 关注:重新处理这个路径,非常关键,不然linux下的new File会有空指针
                                StringBuilder filePath = new StringBuilder(File.separator);
                                for (String folder : split) {
                                    if(StringUtils.isNotBlank(folder)){
                                        filePath.append(folder).append(File.separator);
                                    }
                                }
                                return filePath.toString();
                            }
                        }
                    }
                }
            } catch (IOException e) {
                log.warn("FstStatusCheckService#getJavaInstallLibAmd64Path出现异常:{}", e);
            }
        } else {
            log.info("FstStatusCheckService#getJavaInstallLibAmd64Path#当前非linux环境,不获取libAmd64Path");
        }
        log.info("FstStatusCheckService#getJavaInstallLibAmd64Path#获取到libAmd64Path失败:{}", libAmd64Path);
        return libAmd64Path;
    }

//    public static void main(String[] args) {
//        String  libAmd64Path =    "/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/amd64";
//        String[] split = libAmd64Path.split("/");
//        StringBuilder filePath = new StringBuilder(File.separator);
//        for (String folder : split) {
//            if(StringUtils.isNotBlank(folder)){
//                filePath.append(folder).append(File.separator);
//            }
//        }
//        System.out.println(filePath.toString());
//    }

    /**
     * 判断指定目录下是否有某个文件(注意目录使用File.separatorChar处理过)
     * @param path
     * @param fileName
     * @return
     */
    public boolean hasFile(String path, String fileName) {
        log.info("FstStatusCheckService#hasFile入参:path:{},fileName:{}", path, fileName);
        try {
            if (isLinuxOS()) {
//                String[] split = path.split("/");
//                String filePath = File.separator;
//                for (String folder : split) {
//                    filePath = folder + File.separator;
//                }
                String filePath = path + fileName;
                File tmpdir = new File(filePath);
                return tmpdir.exists();
            } else {
                //window ,其实还有mac
                File tmpdir = new File(path);
                //listFiles还有其他的方法,比如listFiles(FilenameFilter filter)根据名字模糊查询
                File[] listFiles = tmpdir.listFiles((dir, name) -> name.equals(fileName));
                return listFiles != null && listFiles.length > 0;
            }
        } catch (Exception e) {
            log.warn("FstStatusCheckService#hasFile出现异常,默认为false,异常:{}", e);
            return false;
        }

//        File tmpdir = new File(path);
//        File[] listFiles = tmpdir.listFiles((dir, name) -> name.equals(keyword));
//        return listFiles != null && listFiles.length > 0;
        //这个true 是为了 业务需要不去重复执行

//        FstStatusCheckService#hasFile入参:path:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/amd64,keyword:libjpeg.so
//        2023-02-07 15:06:35.376 [main] INFO  cn.jiangjiesheng.fst.service.impl.FstStatusCheckService.hasFile:173 - FstStatusCheckService#FstStatusCheckService#hasFile 判断是否有执行的问题件
//        java.lang.NullPointerException: null
//        at java.io.File.<init>(File.java:279)
//        at cn.jiangjiesheng.fst.service.impl.FstStatusCheckService.hasFile(FstStatusCheckService.java:169)
//        at cn.jiangjiesheng.fst.service.impl.FstStatusCheckService.writeJpegSoToLibAmd64Path(FstStatusCheckService.java:79)
//        at cn.jiangjiesheng.fst.FstApplication.main(FstApplication.java:31)
//        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
//        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//        at java.lang.reflect.Method.invoke(Method.java:498)
//        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
//        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
//        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
//        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)

    }
}
正文到此结束
本文目录