使用jersey mvc和jsp,所有对html或js文件的请求都是通过@Template或Viewable完成的。
例;
@GET
@Path(JS_URL + "{type}")
@Template(name = "grid")
@Produces("application/javascript")
public Response buildJSGrid(@DefaultValue("") @PathParam("type") String type) {
Grid grid = new Grid(type);
....
return Response.ok(grid).build();
}
其中grid是带有纯javascript的grid.jsp文件
<%@ page contentType="application/javascript;charset=UTF-8" language="java" %>
.....
例如html和js的其他可能变体;
@GET
@Path(FORM_URL + "{type}")
@Template(name = "form")
@Produces(MediaType.TEXT_HTML)
public Response buildAccountForm(@DefaultValue("") @PathParam("type") String type) {
Form form = new Form(type);
....
return Response.ok(form).build();
}
其中form是form.jsp,其中
<script>
.. </script>
中带有html和js<%@ page contentType="text/html;charset=UTF-8" language="java" %>
...
我需要将结果js和html / js最小化,然后再发送给客户端,我尝试使用https://code.google.com/archive/p/htmlcompressor/ lib,但是需要将String传递给htmlCompressor.compress(input);
尝试使用WriterInterceptor
public class MinifyJsInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
final OutputStream outputStream = context.getOutputStream();
// here need to convert outputStream to InputStream and after to String ?
// result string to htmlCompressor.compress(resultString);
// after that convert result minify string back to resultOutputStream and set to context ?
context.setOutputStream(new GZIPOutputStream(resultOutputStream));
这是正确的方法吗?我不能将输出流转换为字符串
谢谢
-更新
回答问题;
html + js意味着在某些jsp中是html标记和js代码
<div id="form" style="width: 500px; display: none">
<div class="w2ui-page page-0">
<div class="w2ui-field">
</div>....
<script type="text/javascript">
var uiElement = (function () {
var config = {
onOpen: function (event) {
event.onComplete = function () {
$('#formContainer').w2render('form');
}
...
}());
</script>
在客户端上请求的文件
$('#tempContainer').load('that file name - also dynamic', function (data, status, xhr) {
uiElement.init();
w2ui[layout].content(layout_main, w2ui[uiElement.name]);
});
您是否真的在资源方法中返回了js文件?
some js and html + js files are dynamic build, example;
grid.jsp contains inside
<%@ page contentType="application/javascript;charset=UTF-8" language="java" %>
var uiElement = (function () {
var config = {
grid: {
name: ${it.name},
listUrl:'${it.entityListUrl}',
formUrl:'${it.entityFormUrl}',
columns: ${it.columns},
records: ${it.records},
}}
资源方法中有来自el表达式和设置的$ {it ..}值
@GET
@Path(JS_URL + "{type}")
@Template(name = "grid")
@Produces("application/javascript")
public Response buildJSGrid(@DefaultValue("") @PathParam("type") String type) {
Grid grid = new Grid(type);
....
return Response.ok(grid).build();
}}
并从客户端调用js“文件”
$.getScript('dynamic js file name' - it is dynamic too).done(function (script, status, xhr) {
//console.log(xhr.responseText);
uiElement.init();
w2ui[layout].content(layout_main, w2ui[uiElement.name]);
});
also some html blocks build dynamic
{
<c:if test="${it.recid != 0}">
<div class="w2ui-field">
<label>active:</label>
<div>
<input name="active" type="checkbox"/>
</div>
</div>
</c:if>
}
-更新说明,
网格生成器;
一种资源和一个模板来构建任何网格,
@GET
@Path(GRID + "{type}")
@Template(name = W2UI_VIEW_PREFIX + "grid/grid")
@Produces(MEDIA_TYPE_APPLICATION_JAVASCRIPT)
public Response buildGrid(@DefaultValue("") @PathParam("type") String type) {
for (W2UI ui : W2UI.values()) {
if (type.equals(ui.getName())) {
W2UIElement grid = ui.getUI();
return Response.ok(grid).build();
}
}
return Response.noContent().build();
}
也可以通过Viewable(模板,模型)使用不同的模板(jsp文件)
menu.jsp模板的菜单构建器中的某处
List<MenuItem> items..
MenuItem item1 = new MenuItem(W2UI.TASK_GRID, W2UIService.GRID);
items.add(item1);
哪里
W2UIService.GRID is string url for client js request and for server method resource @Path() anno.
和
public enum W2UI {
TASK_GRID("task_grid", "tasks", Type.SCRIPT){
@Override
public W2UIElement getUI() {
return new TaskGrid(getName());
}
},
.....
}
TaskGrid使用js代码填充了grid.jsp模板的模型,因此可以轻松添加具有不同数据集和按钮集的任何类型的网格。
$ .getScript()在客户端上处理的组件(Type.SCRIPT)的类型,$('#tempContainer')。load()在Type.HTML上进行处理
---更新工厂和供应商;
@Provider
@Priority(200)
@HtmlMinify
public class HtmlMinifyInterceptor implements WriterInterceptor {
@Inject private HtmlCompressor compressor;
...
public class HtmlMinifierFactory implements Factory<HtmlCompressor> {
private HtmlCompressor compressor;
@Override
public HtmlCompressor provide() {
if (null == compressor) compressor = new HtmlCompressor();
ClosureJavaScriptCompressor jsCompressor = new ClosureJavaScriptCompressor();
jsCompressor.setCompilationLevel(CompilationLevel.SIMPLE_OPTIMIZATIONS);
..
@ApplicationPath("/")
public class MainRsConfig extends ResourceConfig {
public MainRsConfig() {
..
register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(HtmlMinifierFactory.class).to(HtmlCompressor.class).in(Singleton.class);
}
});
..
最佳答案
您可以使用ByteArrayOutputStream的自定义实现作为OutputStream
的WriterInterceptorContext
的包装:
import com.googlecode.htmlcompressor.compressor.Compressor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class HtmlMinifyOutputStream extends ByteArrayOutputStream {
private OutputStream origOut;
private Compressor compressor;
public HtmlMinifyOutputStream(OutputStream origOut, Compressor compressor) {
this.origOut = origOut;
this.compressor = compressor;
}
public void close() throws IOException {
super.close();
String compressedBody = compressor.compress(new String(this.buf));
this.origOut.write(compressedBody.getBytes());
this.origOut.close();
}
}
HtmlMinifyOutputStream
可以在WriterInterceptor
实现中使用。 HtmlCompressor
实例被注入:import com.googlecode.htmlcompressor.compressor.Compressor;
import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;
import java.io.*;
@Provider
@HtmlMinify
public class MinifyHtmlInterceptor implements WriterInterceptor {
@Inject
private Compressor compressor;
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new HtmlMinifyOutputStream(outputStream, compressor));
context.proceed();
}
}
@HtmlMinify
是NameBinding注释,用于在特定资源方法上激活MinifyHtmlInterceptor
。 (请参见https://jersey.java.net/documentation/latest/filters-and-interceptors.html#d0e9988):import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@NameBinding
@Retention(value = RetentionPolicy.RUNTIME)
public @interface HtmlMinify {}
HtmlCompressor
每个应用程序只能创建一次,并且可以同时使用,因为:HtmlCompressor和XmlCompressor类被认为是线程安全的*,可以在多线程环境(https://code.google.com/archive/p/htmlcompressor/)中使用
这是一个HK2工厂(请参见:Implementing Custom Injection Provider),该工厂创建压缩程序实例并启用内联css和javascript压缩:
import com.googlecode.htmlcompressor.compressor.Compressor;
import com.googlecode.htmlcompressor.compressor.HtmlCompressor;
import org.glassfish.hk2.api.Factory;
public class HtmlCompressorFactory implements Factory<Compressor> {
private HtmlCompressor compressor;
@Override
public Compressor provide() {
if(compressor == null) {
compressor = new HtmlCompressor();
}
compressor.setCompressJavaScript(true);
compressor.setCompressCss(true);
return compressor;
}
@Override
public void dispose(Compressor compressor) {}
}
工厂是registered with an AbstractBinder:
final ResourceConfig rc = new ResourceConfig().packages("com.example");
rc.register(new AbstractBinder() {
@Override
protected void configure() {
bindFactory(HtmlCompressorFactory.class).to(Compressor.class).in(Singleton.class);
}
});
如果启用了内联JavaScript或内联CSS压缩:
具有默认设置的HTML压缩器不需要任何依赖关系。内联CSS压缩需要YUI compressor库。内联JavaScript压缩需要YUI compressor库(默认情况下)或Google Closure Compiler库。 (https://code.google.com/archive/p/htmlcompressor/)
我使用maven,因此我将此依赖项添加到了pom.xml中:
<dependency>
<groupId>com.yahoo.platform.yui</groupId>
<artifactId>yuicompressor</artifactId>
<version>2.4.8</version>
</dependency>
如果要使用
Google Closure Compiler
,请使用以下依赖项:<dependency>
<groupId>com.google.javascript</groupId>
<artifactId>closure-compiler</artifactId>
<version>r2388</version>
</dependency>
并激活它:
compressor.setJavaScriptCompressor(new ClosureJavaScriptCompressor());
compressor.setCompressJavaScript(true);
compressor.setCssCompressor(new YuiCssCompressor());
compressor.setCompressCss(true);
return compressor;
如果要压缩纯JavaScript或CSS文件,则不能使用
htmlcompressor
。该库仅支持带有内联CSS / JS的HTML文件。但是您可以实现MinifyJsInterceptor
或MinifyCssInterceptor
类似的MinifyHtmlInterceptor
类似物,它们直接使用YUI-Compressor和/或Google Closure库。对于gzip压缩,您应该实现另一个拦截器。因此可以分别配置缩小和压缩。如果激活多个拦截器,请使用
javax.annotation.Priority
控制执行顺序。 (请参阅:https://jersey.java.net/documentation/latest/filters-and-interceptors.html#d0e9927)