首先来说一下什么是jersey,他是实现了restful风格的其中一个框架,当然除了jersey还有其他的,例如
不过在平时在开发web下,目前流行的还是以spring mvc为主,但现在也有一些后起之秀,就例如
以笔者了解呢目前jersey用得还是蛮多的,最主要是体现在对外接口上面。
不说那么多了,送上看看怎么在jersey用freemarker
<dependency>
<groupId>javax.ws.rsgroupId>
<artifactId>javax.ws.rs-apiartifactId>
<version>2.0.1version>
dependency>
<dependency>
<groupId>javax.elgroupId>
<artifactId>javax.el-apiartifactId>
<version>2.2.4version>
dependency>
<dependency>
<groupId>org.glassfish.jersey.containersgroupId>
<artifactId>jersey-container-servletartifactId>
<version>2.23.1version>
dependency>
<dependency>
<groupId>org.glassfish.webgroupId>
<artifactId>javax.elartifactId>
<version>2.2.4version>
dependency>
<dependency>
<groupId>org.glassfish.jersey.extgroupId>
<artifactId>jersey-mvc-mustacheartifactId>
<version>2.23.1version>
dependency>
<dependency>
<groupId>org.glassfish.jersey.extgroupId>
<artifactId>jersey-mvc-freemarkerartifactId>
<version>2.23.1version>
dependency>
简单说一下这个配置,最重要的还是最后那两个,是jersey做的扩展,当然,他肯定有依赖freemarker的
<servlet>
<servlet-name>restfulservlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainerservlet-class>
<init-param>
<param-name>jersey.config.server.provider.packagesparam-name>
<param-value>
com.example
param-value>
init-param>
<init-param>
<param-name>javax.ws.rs.Applicationparam-name>
<param-value>
com.example.MyApplication
param-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>restfulservlet-name>
<url-pattern>/restful/*url-pattern>
servlet-mapping>
最重要的是配置那个扫描包(jersey.config.server.provider.packages
),和spring下的scan package一样的道理
另外还要让jersey识别我们的配置,那么还要写一个key为javax.ws.rs.Application
的配置
public class MyApplication extends ResourceConfig {
public MyApplication() {
/*模板*/
Map pro = new HashMap(1);
//模板编码
pro.put("jersey.config.server.mvc.encoding.freemarker", "UTF-8");
//指定模板基础路径
pro.put("jersey.config.server.mvc.templateBasePath.freemarker", "WEB-INF/freemarker");
addProperties(pro).
register(FreemarkerMvcFeature.class);
}
}
这里主要注册一个让他支持freemarker的Feature,当然jersey支持了很多通过注册可以做的事情,包括Oauth、Filter、BeanValidata、Security、ContainerRequestFilter等等
@Path("/views")
public class ViewResource {
@GET
@Path("example")
@Produces("text/html")
public Viewable exampleView() {
Map data = new HashMap();
data.put("text", "this is the ViewResource test text");
//这里需要说明一下,前面有"/"和没有是很大区别的
//没有的话,jersey会在base路径下,加上当前类的路径在加上这个exmaple
return new Viewable("/example", data);
}
}
最后这个java呢,其实就是配置一个控制器,最后通过访问/restful/views/example
就可以定位到这个控制器,最后找模板,这个配置的模板是在,/WEB-INF/freemarker/example.ftl
的
直接看源码config方法
public boolean configure(final FeatureContext context) {
final Configuration config = context.getConfiguration();
if (!config.isRegistered(FreemarkerViewProcessor.class)) {
// Template Processor.
context.register(FreemarkerViewProcessor.class);
// MvcFeature.
if (!config.isRegistered(MvcFeature.class)) {
context.register(MvcFeature.class);
}
return true;
}
return false;
}
我们平时要jersey支持web服务需要注册MvcFeature
,那么,现在看这里相当于FreemarkerMvcFeature
就依赖这个MvcFeature
,如果没有注册,他会帮我们注册,jersey这个点做得还是不错的
我们继续往下看看FreemarkerViewProcessor
是干嘛的
@Override
protected Template resolve(final String templateReference, final Reader reader) throws Exception {
return factory.getConfiguration().getTemplate(templateReference);
}
@Override
public void writeTo(final Template template, final Viewable viewable, final MediaType mediaType,
final MultivaluedMap httpHeaders, final OutputStream out) throws IOException {
try {
Object model = viewable.getModel();
if (!(model instanceof Map)) {
model = new HashMap() {{
put("model", viewable.getModel());
}};
}
Charset encoding = setContentType(mediaType, httpHeaders);
template.process(model, new OutputStreamWriter(out, encoding));
} catch (TemplateException te) {
throw new ContainerException(te);
}
}
从resolve看出,其实这里算一个入口 ,他从freemarker的configuration中获取模板,然后直接从wirteTo进行写出,这里有个东西需要注意,
他把所有从Viewable中的数据如果是非Map,放到一个以model为key的Map当中,所以啊,我们开的时候,如果不是一个Map,需要从model中拿数据
另外,看看这个factory是如何产生的
this.factory = getTemplateObjectFactory(serviceLocator, FreemarkerConfigurationFactory.class,
new Value() {
@Override
public FreemarkerConfigurationFactory get() {
Configuration configuration =
getTemplateObjectFactory(serviceLocator, Configuration.class,
Values.empty());
if (configuration == null) {
return new FreemarkerDefaultConfigurationFactory(servletContext);
} else {
return new FreemarkerSuppliedConfigurationFactory(configuration);
}
}
});
哎呀,这个非常好啊,从这里创建这个Configuration,那么先不说getTemplateObjectFactory这个是干嘛,先说,下面FreemarkerDefaultConfigurationFactory
,这个就是采用web的加载器,其中包括模板加载器:WebappTemplateLoader
从web上下文加载、ClassTemplateLoader
累加载器加载,FileTemplateLoader
文件根目录加载
FreemarkerSuppliedConfigurationFactory这个就不说了,他其实就是直接返回上面拿到的configuration好了,我们下面分析一下getTemplateObjectFactory
先看源码
protected F getTemplateObjectFactory(final ServiceLocator serviceLocator,
final Class type, final Value defaultValue) {
//这个值为 jersey.config.server.mvc.factory.freemarker
final Object objectFactoryProperty =
config.getProperty(MvcFeature.TEMPLATE_OBJECT_FACTORY + suffix);
if (objectFactoryProperty != null) {
//如果是Configuration类型,直接转成对象并且返回
if (type.isAssignableFrom(objectFactoryProperty.getClass())) {
return type.cast(objectFactoryProperty);
} else {
//如果是String类型,直接new 出来并且进行返回
Class factoryClass = null;
if (objectFactoryProperty instanceof String) {
factoryClass = ReflectionHelper
.classForNamePA((String) objectFactoryProperty).run();
} else if (objectFactoryProperty instanceof Class) {
factoryClass = (Class) objectFactoryProperty;
}
if (factoryClass != null) {
if (type.isAssignableFrom(factoryClass)) {
return type.cast(serviceLocator.create(factoryClass));
} else {
LOGGER.log(Level.CONFIG,
LocalizationMessages.WRONG_TEMPLATE_OBJECT_FACTORY(factoryClass, type));
}
}
}
}
//否则返回空
return defaultValue.get();
}
这下子明白了,jersey的配置工厂都可以自定义,细节的东西还是考虑的很周全的,那么如果需要扩展Freemarker
配置,如TemplateLoader
、自定义指令
等等的这些玩意我们都可以弄了,那么具体怎么弄呢,是程序员的,还是喜欢看代码比文字的要多点的
//在jersey的Application中可以配置
//这个obj啊,做的事情可以是,一个类名,一个Configuration对象,一个Configuration的class
//这个就是Freemarker的配置
pro.put("jersey.config.server.mvc.factory.freemarker", obj);
//把你添加的信息告诉jersey
addProperties(pro);
那么最后完成我们的工作,其中包括怎么配置出jersey怎么输出freemarker模板,并且简单的分析了一下他的源码,以及怎么自定义配置freemarker
如有说得不好多多指教