目前项目中CMS管理系统会将静态资源比如CSS、JS或者Image推送到静态Web服务器(DFS文件系统),而把动态模板或者静态html片段推送到动态Web服务器。这个CMS是基于PHP的,对JS和CSS要做一层过滤,即合并、替换、压缩。合并和替换都没问题,压缩的时候在选择工具的时候考虑了Google Closure Compiler和YUI Compressor,目前还在测试中,先决定使用YUI Compressor(现在JQuery 1.4使用了Google Closure Compiler来压缩),可是CMS在使用的时候如果基于命令行,那么针对不同的平台就要执行不同的脚本,而且方式也不对,CMS在读取文件对内容执行了合并和替换后获得的就是内容,难道再输出到一个临时文件执行命令行?这样做不是很好的方式,上网搜了下资料,基本都是用命令行直接压缩的。我就看了下源码,参照com.yahoo.platform.yui.compressor.YUICompressor写了个工具类,以基于Hessian的Web程序的方式发布了一个服务(考虑到以后可能还会添加服务,就没有直接简单的用输出流的方式输出字符串),然后CMS调用这个服务获得压缩后的文本。代码如下:
接口
public interface ICompressorService { /** * JS或CSS压缩服务 * 为了和CMS系统相一致,这里在压缩后的文本内容加的第一个标识字符为0时表示是返回正常的压缩后的文本信息,为1则是返回异常信息 * * @param type 压缩的类型(js/css) 类型:String * @param content js/css的文本内容 类型:String * @return 压缩后的结果(返回类型+压缩后的文本内容 0 压缩后的文本信息;1 异常信息) 类型:String */ public String compress(String type, String content);
实现类
public class CompressorServiceImpl implements ICompressorService { //记录JS校验错误 private StringBuffer errs = null; @Override public String compress(String type, String content) { Reader in = null; Writer out = null; ByteArrayOutputStream byteOut = null; ByteArrayInputStream byteIn = null; String dcontent = null; try { String charset = "UTF-8"; if (type == null) { return "1"+"type can not be null"; } if (!type.equalsIgnoreCase("js") && !type.equalsIgnoreCase("css")) { return "1"+"type can only be 'js' or 'css'"; } byteIn = new ByteArrayInputStream(URLDecoder.decode(content,"UTF-8").getBytes("UTF-8")); in = new InputStreamReader(byteIn,"UTF-8"); int linebreakpos = -1; byteOut = new ByteArrayOutputStream(1024000); if (type.equalsIgnoreCase("js")) { //只在压缩JS的时候才实例化 errs = new StringBuffer(); try { JavaScriptCompressor compressor = new JavaScriptCompressor(in, new ErrorReporter() { public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) { if (line < 0) { logErr("\n[WARNING] " + message); } else { logErr("\n[WARNING] " + line + ':' + lineOffset + ':' + message); } } public void error(String message, String sourceName, int line, String lineSource, int lineOffset) { if (line < 0) { logErr("\n[ERROR] " + message); } else { logErr("\n[ERROR] " + line + ':' + lineOffset + ':' + message); } } public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource, int lineOffset) { error(message, sourceName, line, lineSource, lineOffset); return new EvaluatorException(message); } }); out = new OutputStreamWriter(byteOut, charset); boolean munge = true; boolean preserveAllSemiColons = false; boolean disableOptimizations = false; compressor.compress(out, linebreakpos, munge, false, preserveAllSemiColons, disableOptimizations); out.flush(); dcontent = URLEncoder.encode(byteOut.toString("UTF-8"),"UTF-8"); } catch (EvaluatorException e) { e.printStackTrace(); return "1"+(errs==null?"":errs.toString())+e.getMessage(); } } else if (type.equalsIgnoreCase("css")) { CssCompressor compressor = new CssCompressor(in); out = new OutputStreamWriter(byteOut, charset); compressor.compress(out, linebreakpos); out.flush(); dcontent = URLEncoder.encode(byteOut.toString("UTF-8"),"UTF-8"); } } catch (IOException e) { e.printStackTrace(); return "1"+e.getMessage(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); return "1"+e.getMessage(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); return "1"+e.getMessage(); } } if(byteIn != null){ try { byteIn.close(); } catch (IOException e) { e.printStackTrace(); return "1"+e.getMessage(); } } if(byteOut != null){ try { byteOut.close(); } catch (IOException e) { e.printStackTrace(); return "1"+e.getMessage(); } } } return "0"+dcontent; } private void logErr(String msg){ System.err.println(msg); if(errs != null){ errs.append(msg); } } }