首先,我们针对Linux下的部分命令进行Windows系统的对应实现
ls————cmd /c dir/b
rm————cmd /c del
mv————cmd /c move
pwd————cmd /c chdir
注:cmd /c是执行完命令后关闭命令行窗口、cmd /k是执行完命令后不关闭命令行窗口、cmd /c start是会打开新窗口,关闭旧窗口、cmd /c start是会打开新窗口,不关闭旧窗口
也可以将上述命令做成bat文件,放到Windows/System32目录下,例如,如下文件命名为ls.bat,放到对应目录下,cmd执行ls命令
@echo off
dir
接下来,全局安装JAVASCRIPT_OBFUSCATOR
,需要提前准备好Node环境
#安装
npm install javascript-obfuscator -g
#检查是否安装成功
javascript-obfuscator -v
然后在系统环境变量指定path,我这里是npm安装,因此,找到npm路径,在系统用户变量的path里,例如C:\Users\zy_ys\AppData\Roaming\npm
加到系统变量的path里
还需要准备YUI压缩使用的jar包,这里使用2.4.8版本,下载地址,提取码qc1j
,接下来,对应本地项目,改造如下代码,具体改造内容为项目路径、jar包路径、压缩文件路径等,完整代码如下
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 通过压缩JS文件、更改日期工具类* 需要系统 MacOS* 需要安装的软件* yui compressor:安装方式 下载jar包 使用时指定包所在路径使用命令即可* uglifyJs: npm 或者 brew 安装* javascript-obfuscator npm安装** @author zwf* @date 20190703*/
public class CompressCommand {private static final String encoding = "utf-8";private static final String[] SUFFIXARRAY = {".js", ".css"};private static final String[] JS_SUFFIXARRAY = {".js"};private static final String TEMP = ".temp";/*** YUI_PATH 压缩使用的jar包路径*/private static final String YUI_PATH = "C:\\Users\\zy_ys\\Desktop\\yuicompressor-2.4.8.jar";/*** JAVASCRIPT_OBFUSCATOR 命令所在路径*/private static final String JAVASCRIPT_OBFUSCATOR_CMD = "javascript-obfuscator";/*** 项目根路径开始的js路径*/private static final String RESOURCES_PATH = "project\\src\\main\\resources\\static\\";/*** 项目根路径开始的HTML路径*/private static final String RESOURCES_HTML_PATH = "project\\src\\main\\resources\\templates\\";/*** JS的文件夹名称*/private static final String[] CSS_JS_DIRECTION = {"js\\aaa", "js\\bbb", "js\\ccc","js\\login","js\\ddd", "js\\eee", "js\\fff", "js\\ggg", "css"};/*** HTML的文件夹名称*/private static final String[] DIRECTION_HTML = {"aaa", "download", "error", "ccc", "ddd", "bbb", "eee", "fff"};/****/private static final String DATE_STAMP = System.currentTimeMillis() + "";/*** 所有未压缩JS的集合*/private static List<String> RESOURCE_LIST = new ArrayList<>();/*** 所有的中间文件HTML*/private static List<String> TEMP_HTML_LIST = new ArrayList<>();/*** 项目跟路径*/private static String PROJECT_PATH = "";private static String CSS_COMPRESS_ONLY = "NO";static {Runtime runtime = Runtime.getRuntime();BufferedReader bufferedReader = null;try {Process process = runtime.exec("cmd /c chdir");if (process.waitFor() == 0) {bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));PROJECT_PATH = bufferedReader.readLine();System.out.println(PROJECT_PATH);}if (StringUtils.isBlank(PROJECT_PATH)) {System.err.println("获取当前项目路径操作失败, 停止操作!");System.exit(-1);}} catch (Exception ex) {ex.printStackTrace();} finally {if (null != bufferedReader) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}}enum STEP {/*** 第一步:删除 min.js 文件*/STEP_ONE_RM_OLD_MIN_JS,/*** 第二步:生成新的 min.js 文件*/STEP_TWO_CREATE_NEW_MIN_JS,/*** 第三步: 生成htm中间文件*/STEP_THREE_CREATE_COPY_TEMPLATE,/*** 第四步: 替换中间文件的min.js*/STEP_FOUR_REPLACE_MIN_JS,/*** 第五步: 还原html文件*/STEP_FIVE_DELETE_TEMPLATE,}enum CompressObfuscator {YUI_COMPRESSOR,UGLIFY_JS,JAVASCRIPT_OBFUSCATOR}enum EVN {DEBUG,PUBLISH,}public static void main(String[] args) throws Exception {EVN evn = EVN.DEBUG;//DEBUG是初始化,PUBLISH是混淆压缩System.out.println(" 请输入你需要操作的模式? DEBUG 或者 PUBLISH ");Scanner scanner = new Scanner(System.in);String command = scanner.nextLine();if ("debug".equalsIgnoreCase(command)) {evn = EVN.DEBUG;} else if ("publish".equalsIgnoreCase(command)) {evn = EVN.PUBLISH;} else {System.exit(0);}switch (evn) {case DEBUG:// 还原html文件中的js文件devOps();break;case PUBLISH:masterOps();break;}}enum DevStep {RM_MIN_JS,RP_TEMPLATE_COPY,RM_TEMPLATE,}private static void devOps() throws Exception {// 第一步: 删除min.jsList<String> commandList = initRmJsCommandList();execDevCommand(commandList, DevStep.RM_MIN_JS);// 第二步: 生成中间文件List<String> commandList1 = initTempLateCommandList();execDevCommand(commandList1, DevStep.RP_TEMPLATE_COPY);// 第三步: 替换jsreverseReplaceJsInHtml();// 第四步: 删除html中间文件List<String> backCommand = initDelTemplateList();execDevCommand(backCommand, DevStep.RM_TEMPLATE);}private static void execDevCommand(List<String> commandList, DevStep devStep) {switch (devStep) {case RM_MIN_JS:System.out.println("开始删除min.js文件-----");execute(commandList);System.out.println("结束删除min.js文件-----");break;case RP_TEMPLATE_COPY:System.out.println("开始生成HTML中间文件-----");execute(commandList);System.out.println("结束生成HTML中间文件-----");case RM_TEMPLATE:System.out.println("开始删除html中间文件");execute(commandList);System.out.println("结束删除html中间文件");break;}}private static void masterOps() throws Exception {// step 1 :初始化min.js删除命令集合List<String> rmCmdList = initRmJsCommandList();execCommand(rmCmdList, STEP.STEP_ONE_RM_OLD_MIN_JS);//step 2: 压缩文件,生成新的min.js文件, 如使用yui压缩, 注释掉第一行compressJSCommandListList<String> compressJSCommandList = getCompressCommandList(CompressObfuscator.JAVASCRIPT_OBFUSCATOR);List<String> compressCssCommandList = getCompressCommandList(CompressObfuscator.YUI_COMPRESSOR);execCommand(compressJSCommandList, STEP.STEP_TWO_CREATE_NEW_MIN_JS);execCommand(compressCssCommandList, STEP.STEP_TWO_CREATE_NEW_MIN_JS);//step 3: 生成html中间文件List<String> tempTempLateCommandList = initTempLateCommandList();execCommand(tempTempLateCommandList, STEP.STEP_THREE_CREATE_COPY_TEMPLATE);//step 4: 替换中间文件的min.jsreplaceJsInHtml();//step 5: 恢复HTML文件List<String> backCommand = initDelTemplateList();execCommand(backCommand, STEP.STEP_FIVE_DELETE_TEMPLATE);}private static List<String> getCompressCommandList(CompressObfuscator javascriptObfuscator) throws Exception {switch (javascriptObfuscator) {case YUI_COMPRESSOR:return initCommandList(YUI_PATH);case UGLIFY_JS:CSS_COMPRESS_ONLY = "YES";return initUglifyJsCommandList();case JAVASCRIPT_OBFUSCATOR:CSS_COMPRESS_ONLY = "YES";return initJavascriptObfuscatorCommandList();default:throw new RuntimeException("出错了,停止吧!");}}private static void execCommand(List<String> commandList, STEP step) throws Exception {switch (step) {case STEP_ONE_RM_OLD_MIN_JS:System.out.println("开始清理旧的min.js文件---");execute(commandList);System.out.println("清理旧的min.js文件结束");break;case STEP_TWO_CREATE_NEW_MIN_JS:System.out.println("开始生成新的min.js文件--");execute(commandList);System.out.println("结束生成新的min.js文件--");break;case STEP_THREE_CREATE_COPY_TEMPLATE:System.out.println("开始生成新的html中间文件--");execute(commandList);System.out.println("结束生成新的html中间文件--");break;case STEP_FIVE_DELETE_TEMPLATE:System.out.println("开始还原html文件--");execute(commandList);System.out.println("结束还原html文件--");break;default:}}private static List<String> initUglifyJsCommandList() throws Exception {List<String> cmdList = new ArrayList<>();for (String directionJ : CSS_JS_DIRECTION) {String lsCmd = "ls " + PROJECT_PATH + "/" + RESOURCES_PATH + directionJ;Process process = Runtime.getRuntime().exec(lsCmd);InputStream inputStream = null;BufferedReader bufferedReader = null;if (process.waitFor() == 0) {inputStream = process.getInputStream();bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {String suffix = line.substring(line.lastIndexOf("."));List<String> suffixList = Arrays.asList(JS_SUFFIXARRAY);if (suffixList.contains(suffix) && !line.endsWith("-min" + suffix)) {StringBuffer _path = new StringBuffer();_path.append(PROJECT_PATH).append("/");_path.append(RESOURCES_PATH).append(directionJ).append("/").append(line).append(" ");RESOURCE_LIST.add(_path.toString());StringBuffer sb = new StringBuffer();sb.append("uglifyjs ");sb.append(_path.toString()).append(" ");sb.append("-c ");sb.append("--ie8 ");sb.append("-m ");sb.append("-o").append(" ");sb.append(PROJECT_PATH).append("/");sb.append(RESOURCES_PATH).append(directionJ).append("/").append(line.replace(suffix, "-" + DATE_STAMP + "-min" + suffix));cmdList.add(sb.toString());}}}}System.out.println("初始化压缩命令成功");return cmdList;}private static List<String> initJavascriptObfuscatorCommandList() throws Exception {List<String> cmdList = new ArrayList<>();for (String directionJ : CSS_JS_DIRECTION) {String lsCmd = "cmd /c dir/b " + PROJECT_PATH + "\\" + RESOURCES_PATH + directionJ;Process process = Runtime.getRuntime().exec(lsCmd);InputStream inputStream = null;BufferedReader bufferedReader = null;if (process.waitFor() == 0) {inputStream = process.getInputStream();bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {String suffix = line.substring(line.lastIndexOf("."));List<String> suffixList = Arrays.asList(JS_SUFFIXARRAY);if (suffixList.contains(suffix) && !line.endsWith("-min" + suffix)) {StringBuffer _path = new StringBuffer();_path.append(PROJECT_PATH).append("\\");_path.append(RESOURCES_PATH).append(directionJ).append("\\").append(line).append(" ");RESOURCE_LIST.add(_path.toString());StringBuffer sb = new StringBuffer();sb.append(" cmd /c ");sb.append(JAVASCRIPT_OBFUSCATOR_CMD).append(" ");sb.append(_path.toString()).append(" ");sb.append("--output").append(" ");sb.append(PROJECT_PATH).append("\\");sb.append(RESOURCES_PATH).append(directionJ).append("\\").append(line.replace(suffix, "-" + DATE_STAMP + "-min" + suffix));cmdList.add(sb.toString());}}}}System.out.println("初始化压缩命令成功");return cmdList;}private static List<String> initDelTemplateList() throws Exception {List<String> cmdList = new ArrayList<>();for (String htmlFilePath : TEMP_HTML_LIST) {StringBuffer sb = new StringBuffer();sb.append("cmd /c del ").append(" ");sb.append(htmlFilePath).append(" ");cmdList.add(sb.toString());}return cmdList;}private static List<String> initTempLateCommandList() throws Exception {List<String> cmdList = new ArrayList<>();for (String directionH : DIRECTION_HTML) {String lsCmd = "cmd /c dir/b " + PROJECT_PATH + "\\" + RESOURCES_HTML_PATH + directionH;Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(lsCmd);if (process.waitFor() == 0) {InputStream inputStream = null;BufferedReader bufferedReader = null;try {inputStream = process.getInputStream();bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {if (line.endsWith(".html")) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("cmd /c move").append(" ");stringBuilder.append(PROJECT_PATH).append("\\");stringBuilder.append(RESOURCES_HTML_PATH).append(directionH).append("\\").append(line).append(" ");StringBuffer stringBuffer = new StringBuffer();stringBuffer.append(PROJECT_PATH).append("\\");stringBuffer.append(RESOURCES_HTML_PATH).append(directionH).append("\\").append(line).append(TEMP).append(" ");TEMP_HTML_LIST.add(stringBuffer.toString());cmdList.add(stringBuilder.append(stringBuffer.toString()).toString());}}} catch (Exception ex) {ex.printStackTrace();} finally {if (inputStream != null) {inputStream.close();}if (bufferedReader != null) {bufferedReader.close();}}}}return cmdList;}private static synchronized void execute(List<String> commandList) {long beginTime = System.currentTimeMillis();int count = 0;//这里实际定义的是环境变量的地址,我们配置了path,可以忽略String[] envp = new String[] {"PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"};for (String command : commandList) {try {Runtime runtime = Runtime.getRuntime();// Process process = runtime.exec(command, envp);Process process = runtime.exec(command);System.out.println(command);// 如js无法进行压缩打印命令报错信息BufferedInputStream bis = new BufferedInputStream(process.getErrorStream());BufferedReader br = new BufferedReader(new InputStreamReader(bis,"GB2312"));String line;while ((line = br.readLine()) != null) {System.out.println(line);}bis.close();br.close();if (process.waitFor() == 0) {count++;}} catch (Exception ex) {ex.printStackTrace();}}long endTime = System.currentTimeMillis();System.out.println("操作执行完成:共花费 " + (endTime - beginTime) + " ms, 共执行了 " + count + " 个文件");}private static List<String> initRmJsCommandList() throws Exception {List<String> cmdList = new ArrayList<>();for (String directionJ : CSS_JS_DIRECTION) {String lsCmd = "cmd /c dir/b " + PROJECT_PATH + "\\" + RESOURCES_PATH + directionJ;Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(lsCmd);if (process.waitFor() == 0) {InputStream inputStream = null;BufferedReader bufferedReader = null;try {inputStream = process.getInputStream();bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {if (line.endsWith("-min.js") || line.endsWith("-min.css")) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("cmd /c del").append(" ").append(" ").append(PROJECT_PATH).append("\\").append(RESOURCES_PATH).append(directionJ).append("\\").append(line);System.out.println("cmd:-->"+stringBuilder.toString());cmdList.add(stringBuilder.toString());}}} catch (Exception ex) {ex.printStackTrace();} finally {if (inputStream != null) {inputStream.close();}if (bufferedReader != null) {bufferedReader.close();}}}}return cmdList;}private static void replaceJsInHtml() throws Exception {for (String directionHtml : DIRECTION_HTML) {String absoluteDir = PROJECT_PATH + "\\" + RESOURCES_HTML_PATH + directionHtml;System.out.println("absoluteDir:--->"+absoluteDir);File htmlFile = new File(absoluteDir);File[] htmlFiles = htmlFile.listFiles();for (File hFile : htmlFiles) {BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {String newFilePath = hFile.getAbsolutePath().substring(0, hFile.getAbsolutePath().indexOf(TEMP));bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(hFile)));bufferedWriter = new BufferedWriter((new OutputStreamWriter(new FileOutputStream(new File(newFilePath)))));String line = null;while ((line = bufferedReader.readLine()) != null) {if (line.trim().contains("script") && line.trim().contains("src")) {Attribute srcAttribute = null;Document document = Jsoup.parse(line.trim());Iterator<Element> iterator = document.select("script").iterator();while (iterator.hasNext()) {Element next = iterator.next();Attributes attributes = next.attributes();for (Attribute attribute : attributes) {if ("src".equals(attribute.getKey())) {srcAttribute = attribute;break;}}break;}boolean w = false;if (srcAttribute != null) {for (String absolutePathName : RESOURCE_LIST) {if (!absolutePathName.trim().endsWith(".js")) {continue;}// 获取js路径上的上一级和js名称String[] split = absolutePathName.split("\\\\");String jsDirName = split[split.length - 2];String jsName = split[split.length - 1];String jsPreName = jsName.substring(0, jsName.indexOf(".js"));String[] srcSpilt = srcAttribute.getValue().split("\\/");String srcJsName = srcSpilt[srcSpilt.length - 1];String srcJsDirName = srcSpilt[srcSpilt.length - 2];if (!absolutePathName.contains("min.js") && jsDirName.equals(srcJsDirName) && srcJsName.contains(jsPreName)) {String newSrc = srcAttribute.getValue().substring(0, srcAttribute.getValue().indexOf(srcJsDirName + "/" + srcJsName));int startIndex = line.indexOf(jsDirName + "/" + jsPreName);int endIndex = line.indexOf(".js\"");String oldJsName = line.substring(startIndex, endIndex);String newLine = line.replace(oldJsName, jsDirName + "/" + jsPreName + "-" + DATE_STAMP + "-min");// 包含当前js文件,替换bufferedWriter.write(newLine + "\n");w = true;}}}if (!w) {bufferedWriter.write(line + "\n");}} else if (line.trim().contains("link") && line.trim().contains("href") && line.trim().contains("css")) {Attribute srcAttribute = null;Document document = Jsoup.parse(line.trim());Iterator<Element> iterator = document.select("link").iterator();while (iterator.hasNext()) {Element next = iterator.next();Attributes attributes = next.attributes();for (Attribute attribute : attributes) {if ("href".equals(attribute.getKey())) {srcAttribute = attribute;break;}}break;}boolean w = false;if (srcAttribute != null) {for (String absolutePathName : RESOURCE_LIST) {if (!absolutePathName.trim().endsWith(".css")) {continue;}// 获取css路径上的上一级和css名称String[] split = absolutePathName.split("\\\\");String cssDirName = split[split.length - 2];String cssName = split[split.length - 1];//System.out.println(cssName);String cssPreName = cssName.substring(0, cssName.indexOf(".css"));String[] srcSpilt = srcAttribute.getValue().split("\\/");String srcJsName = srcSpilt[srcSpilt.length - 1];String srcJsDirName = srcSpilt[srcSpilt.length - 2];if (!absolutePathName.contains("min.css") && cssDirName.equals(srcJsDirName) && srcJsName.contains(cssPreName)) {int startIndex = line.indexOf(cssDirName + "/" + cssPreName);int endIndex = line.indexOf(".css\"");String oldJsName = line.substring(startIndex, endIndex);String newLine = line.replace(oldJsName, cssDirName + "/" + cssPreName + "-" + DATE_STAMP + "-min");// 包含当前css文件,替换bufferedWriter.write(newLine + "\n");w = true;}}}if (!w) {bufferedWriter.write(line + "\n");}} else {bufferedWriter.write(line + "\n");}bufferedWriter.flush();}} catch (Exception ex) {ex.printStackTrace();} finally {if (null != bufferedReader) {bufferedReader.close();}if (null != bufferedWriter) {bufferedWriter.close();}}}}}private static void reverseReplaceJsInHtml() throws Exception {for (String directionHtml : DIRECTION_HTML) {String absoluteDir = PROJECT_PATH + "\\" + RESOURCES_HTML_PATH + directionHtml;File htmlFile = new File(absoluteDir);File[] htmlFiles = htmlFile.listFiles();for (File hFile : htmlFiles) {BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;try {String newFilePath = hFile.getAbsolutePath().substring(0, hFile.getAbsolutePath().indexOf(TEMP));bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(hFile)));bufferedWriter = new BufferedWriter((new OutputStreamWriter(new FileOutputStream(new File(newFilePath)))));String line = null;while ((line = bufferedReader.readLine()) != null) {String regex = "-[0-9]{13}-min";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(line.trim());String datestamp_min_js = null;while (matcher.find()) {datestamp_min_js = matcher.group();}if(StringUtils.isNotBlank(datestamp_min_js)){String newLine = line.replace(datestamp_min_js, "");bufferedWriter.write(newLine + "\n");}else {bufferedWriter.write(line + "\n");}bufferedWriter.flush();}} catch (Exception ex) {ex.printStackTrace();} finally {if (null != bufferedReader) {bufferedReader.close();}if (null != bufferedWriter) {bufferedWriter.close();}}}}}/*** 初始化压缩命令** @param yuiPath*/private static List<String> initCommandList(String yuiPath) throws Exception {List<String> cmdList = new ArrayList<>();String[] cssOnly = {".css"};String[] thisSuffixArray = SUFFIXARRAY;if ("YES".equals(CSS_COMPRESS_ONLY)) {thisSuffixArray = cssOnly;}for (String directionJ : CSS_JS_DIRECTION) {String lsCmd = "cmd /c dir/b " + PROJECT_PATH + "\\" + RESOURCES_PATH + directionJ;Process process = Runtime.getRuntime().exec(lsCmd);InputStream inputStream = null;BufferedReader bufferedReader = null;if (process.waitFor() == 0) {inputStream = process.getInputStream();bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {String suffix = line.substring(line.lastIndexOf("."));List<String> suffixList = Arrays.asList(thisSuffixArray);if (suffixList.contains(suffix) && !line.endsWith("-min" + suffix)) {StringBuffer sb = new StringBuffer();sb.append(" cmd /c");sb.append(" ");sb.append("java -jar ");sb.append(yuiPath);sb.append(" --type ");sb.append(suffix.substring(suffix.indexOf(".") + 1));sb.append(" --charset ");sb.append(encoding).append(" ");sb.append(" --preserve-semi ");StringBuffer _path = new StringBuffer();_path.append(PROJECT_PATH).append("\\");_path.append(RESOURCES_PATH).append(directionJ).append("\\").append(line).append(" ");RESOURCE_LIST.add(_path.toString());sb.append(_path);sb.append(">").append(" ");sb.append(PROJECT_PATH).append("\\");sb.append(RESOURCES_PATH).append(directionJ).append("\\").append(line.replace(suffix, "-" + DATE_STAMP + "-min" + suffix));cmdList.add(sb.toString());}}}}System.out.println("初始化压缩命令成功");return cmdList;}
}
如果遇到问题,可以debug看下是否配置了正确的执行路径、项目路径等,如果要压缩混淆的文件很少,也可以配置好上述内容后,执行如下命令
javascript-obfuscator D:\project\src\main\resources\static\js\login\login.js --output D:\project\src\main\resources\static\js\login\login-1689667293081-min.js
这里login.js
是我们要压缩混淆的文件,login-1689667293081-min.js
是压缩混淆后的代码,挂上具体时间戳,然后,将其名称覆盖到对应的html页面即可