windows7使用Docker编译运行java文件,伪oj

ps:

需要实现一个简单的oj功能,想到在java项目中运行cmd命令直接编译、运行java文件,测试类运行正常,然而项目运行起来,编译正常,运行Main文件就提示无法加载类,应该是SpringMVC的类加载机制问题,不会搞,有知道大佬可以留个言。

后来想到用Docker容器运行,果然可行,而且也保证了代码运行的安全性。

一、首先去官网下载Docker Toolbox

https://docs.docker.com/toolbox/

二、下载完后运行安装包直接一直点击下一步

ps:如果电脑安装过git这一步可以不勾选

三、安装完成打开Docker QuickstartTerminal,如果上一步没有勾选git,需要手动选择git的bash.exe路径

四、第一次打开需要进行虚拟机初始化,稍等一会。

出现下面界面即启动成功

五、运行Docker run -it -u root openjdk:8 /bin/bash 安装openjdk环境

六、将本地文件挂载共享到容器(使用默认的C:/Users可跳过该步骤)

双击打开

打开设置-》共享文件夹-》右上角添加,选择本地路径、填写共享名称,后面代码要用到该名称(即下图的c/Users、share)

设置完成后最好将虚拟机关机,然后打开Docekr QuickStart完成重新加载。

七、测试一下

在共享文件夹目录下(以默认C:/Users为例),放一个Main.java文件,输出helloworld。

public class Main {
    public static void main(String[] args){
        System.out.println("HelloWorld!");
   }
}

在该文件目录下打开cmd,输入

Docker run --rm -u root -v /c/Users/OnlineJudge:/c/Users/OnlineJudge openjdk:8 /bin/sh -c cd /c/Users/OnlineJudge&&javac Main.java

其中--rm运行完即删除容器

-v /c/Users/OnlineJudge:/c/Users/OnlineJudge 是挂载命令,将本地文件C:/Users/OnlineJudge挂载到容器中的/c/Users/OnlineJudge下

/bin/sh -c cd /c/Users/OnlineJudge&&javac Main.java是容器运行后输入的命令,cd到挂载的文件目录并且运行命令javac Main.java编译,运行成功无任何回应,文件夹目录下多出Main.class文件

这时候再输入

Docker run --rm -u root -v /c/Users/OnlineJudge:/c/Users/OnlineJudge openjdk:8 /bin/sh -c cd /c/Users/OnlineJudge&&java Main

运行Main,输出Helloworld,至此工作正常。

八、代码编写

需要在java项目中运行cmd命令,这里用到CMDUtil,网上copy。

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * CMD工具类
 */
public class CMDUtil {
	
    private CMDUtil() {

    }
    /**
     * 
     * 执行CMD命令
     * @param
     * @return String
     * @throws
     * 
     * *cmd /c dir 是执行完dir命令后关闭命令窗口
		cmd /k dir 是执行完dir命令后不关闭命令窗口
		cmd /c start dir  会打开一个新窗口后执行dir命令,原窗口会关闭
		cmd /k start dir  会打开一个新窗口后执行dir命令,原窗口不会关闭
		cmd /?  查看帮助信息
		使用标准输出流读不到数据,错误输出流有数据
		进程使用这些流来提供到子进程的输入和获得从子进程的输出。因为有些本机平台仅针对标准输入和输出流提供有限的缓冲区大小,
		如果读写子进程的输出流或输入流迅速出现失败,则可能导致子进程阻塞,甚至产生死锁,需要异步清空流
     */
    public static String exec(String command) {
        String executeCommand ="cmd /c "+command;
        String rs = "";
        Process cmdProcess = null;
        try {
        	
            cmdProcess = Runtime.getRuntime().exec(executeCommand);
            int waitFor = cmdProcess.waitFor();
            //把标准的输出流和错误流都输出出来
            rs += CmdExecuteResultInfo(cmdProcess.getInputStream());
            rs = CmdExecuteResultInfo(cmdProcess.getErrorStream());
            cmdProcess.getOutputStream().close();
            
        } catch (IOException e) {
        	
            e.printStackTrace();
            
        } catch (InterruptedException e) {

        	e.printStackTrace();
		}finally{
        	
        	clearInBackground(cmdProcess.getInputStream());
        	clearInBackground(cmdProcess.getErrorStream());
        }
        return rs;
    }
    
    /**
     *采用ProcessBuilder来管理进程,会自动清空  builder.redirectErrorStream(true);流 
     @date 2018年9月12日 下午10:59:36
     @email 940945444@qq.com
     @return
     @param
     */
    public static String execProcessBuider(String... command) {
        String rs = "";
        //指定读取出来的数据编码,如果是
        String charset = "UTF-8";
        try {
            List cmdList = new ArrayList();
            for (int i=1;i<command.length;i++){
                cmdList.add(command[i]);
            }
            ProcessBuilder builder = new ProcessBuilder(cmdList);
            builder.directory(new File(command[0]));
            builder.redirectErrorStream(true);
            Process cmdProcess = builder.start();
            rs = CmdExecuteResultInfo(cmdProcess.getInputStream());
            cmdProcess.getOutputStream().close();
        } catch (IOException e) {

            e.printStackTrace();
        }
        return rs;
    }
    
    /**
     * 
     * cmd返回的信息
     * @param
     * @return String
     * @throws
     */
    private static String CmdExecuteResultInfo(InputStream inputStream) {

    	
        StringBuilder builder = new StringBuilder();
        BufferedReader cmdExecuteInfoReader = null;
        try {

            cmdExecuteInfoReader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
            String cmdExecuteInfoLine;
            while ((cmdExecuteInfoLine = cmdExecuteInfoReader.readLine()) != null) {
                
            	builder.append(cmdExecuteInfoLine);
            	builder.append("\n");
            }
            
            return builder.toString();

        } catch (Exception e) {
        	
            e.printStackTrace();
            
        }finally{
			try {
				if (cmdExecuteInfoReader != null) {

					cmdExecuteInfoReader.close();

				}
			} catch (IOException e) {

				e.printStackTrace();
			}
        }
        return null;
    }
    /**
     *清空流,必须要使用异步来清空
     @Author Winston.Wang
     @date 2018年9月12日 下午10:58:53
     @email 940945444@qq.com
     @return
     @param
     */
    static void clearInBackground(final InputStream is) {  
        new Thread(new Runnable(){  
            public void run(){  
                try{
                	is.close();
                } catch(IOException e){
                	e.printStackTrace();
                }  
            }  
        }).start();  
    }
}

另外再编写JavaComplie.java运行Docker命令

package com.fh.util.OlineJudge;

import com.fh.util.FileUtil;
import com.fh.util.PropUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class JavaCompile {
    private static String ONLINE_JUDGE_DIR = PropUtil.getONLINE_JUDGE_DIR();
    private static String ONLINE_JUDGE_SHARE = PropUtil.getONLINE_JUDGE_SHARE();

    public static String compile(String id,String writeStr,String path) throws IOException {
        writeStr ="import java.io.IOException;import java.io.FileInputStream;"+writeStr;
        writeStr = writeStr.replaceAll("(String\\[\\] args\\))(.*)(\\{)","String[] args) throws Exception {");
        writeStr = writeStr.replaceAll("(throws Exception \\{)","throws Exception{\n FileInputStream fis=new FileInputStream(\""+path+"\");\n System.setIn(fis);");

        String filePath =ONLINE_JUDGE_DIR+id+"\\Main.java";
        FileUtil.writeFile(filePath, writeStr);
        CMDUtil.execProcessBuider(ONLINE_JUDGE_DIR+id+"\\","Docker","run","--rm","-u","root","-v",String.format("%s:%s",ONLINE_JUDGE_SHARE,ONLINE_JUDGE_SHARE),"openjdk:8","/bin/sh","-c",String.format("cd %s&&javac Main.java",ONLINE_JUDGE_SHARE+"tempJava/"+id));
        String exec = CMDUtil.execProcessBuider(ONLINE_JUDGE_DIR+id,"Docker","run","--rm","-i","-u","root","-v",String.format("%s:%s",ONLINE_JUDGE_SHARE,ONLINE_JUDGE_SHARE),"openjdk:8","/bin/sh","-c",String.format("cd %s&&java Main",ONLINE_JUDGE_SHARE+"tempJava/"+id),"TIMEOUT /T 3");
        new File(filePath).delete();
        new File(filePath.replace(".java",".class")).delete();
        new File(ONLINE_JUDGE_DIR+id).delete();
        return exec.replaceAll("[\b\r\n\t]*", "");
    }
}

主要是两行调用CMDUtil的代码,第一个参数为cmd运行目录,必须是要编译java的所在目录,是本地目录形式(如C:/User/OnlineJudge)后面的命令就是之前Docker编译运行java的命令。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿S先森丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值