简介
首先来说一下什么是jersey,他是实现了restful风格的其中一个框架,当然除了jersey还有其他的,例如
- apache axis2
- apache CXF
- spring mvc 也算上一个,但不是标准的
不过在平时在开发web下,目前流行的还是以spring mvc为主,但现在也有一些后起之秀,就例如
以笔者了解呢目前jersey用得还是蛮多的,最主要是体现在对外接口上面。
不说那么多了,送上看看怎么在jersey用freemarker
配置
maven
<dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>2.0.1</version></dependency><dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>2.2.4</version> </dependency><dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>2.23.1</version></dependency><dependency> <groupId>org.glassfish.web</groupId> <artifactId>javax.el</artifactId> <version>2.2.4</version></dependency><dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-mvc-mustache</artifactId> <version>2.23.1</version></dependency><dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-mvc-freemarker</artifactId> <version>2.23.1</version></dependency>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
简单说一下这个配置,最重要的还是最后那两个,是jersey做的扩展,当然,他肯定有依赖freemarker的
web.xml
<servlet> <servlet-name>restful</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value> com.example </param-value> </init-param> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value> com.example.MyApplication </param-value> </init-param></servlet><servlet-mapping> <servlet-name>restful</servlet-name> <url-pattern>/restful/*</url-pattern></servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
最重要的是配置那个扫描包(jersey.config.server.provider.packages
),和spring下的scan package一样的道理
另外还要让jersey识别我们的配置,那么还要写一个key为javax.ws.rs.Application
的配置
java 配置
public class MyApplication extends ResourceConfig { public MyApplication() { Map<String, Object> pro = new HashMap<String, Object>(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等等
Control
@Path("/views")public class ViewResource { @GET @Path("example") @Produces("text/html") public Viewable exampleView() { Map<String, String> data = new HashMap<String, String>(); data.put("text", "this is the ViewResource test text"); return new Viewable("/example", data); }}
最后这个java呢,其实就是配置一个控制器,最后通过访问/restful/views/example
就可以定位到这个控制器,最后找模板,这个配置的模板是在,/WEB-INF/freemarker/example.ftl
的
源码分析
FreemarkerMvcFeature.java
直接看源码config方法
public boolean configure(final FeatureContext context) { final Configuration config = context.getConfiguration(); if (!config.isRegistered(FreemarkerViewProcessor.class)) { context.register(FreemarkerViewProcessor.class); if (!config.isRegistered(MvcFeature.class)) { context.register(MvcFeature.class); } return true; } return false;}
我们平时要jersey支持web服务需要注册MvcFeature
,那么,现在看这里相当于FreemarkerMvcFeature
就依赖这个MvcFeature
,如果没有注册,他会帮我们注册,jersey这个点做得还是不错的
我们继续往下看看FreemarkerViewProcessor
是干嘛的
FreemarkerViewProcessor.java
@Overrideprotected Template resolve(final String templateReference, final Reader reader) throws Exception { return factory.getConfiguration().getTemplate(templateReference); }@Overridepublic void writeTo(final Template template, final Viewable viewable, final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream out) throws IOException { try { Object model = viewable.getModel(); if (!(model instanceof Map)) { model = new HashMap<String, Object>() {{ put("model", viewable.getModel()); }}; } Charset encoding = setContentType(mediaType, httpHeaders); template.process(model, new OutputStreamWriter(out, encoding)); } catch (TemplateException te) { throw new ContainerException(te); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
从resolve看出,其实这里算一个入口 ,他从freemarker的configuration中获取模板,然后直接从wirteTo进行写出,这里有个东西需要注意,
他把所有从Viewable中的数据如果是非Map,放到一个以model为key的Map当中,所以啊,我们开的时候,如果不是一个Map,需要从model中拿数据
另外,看看这个factory是如何产生的
this.factory = getTemplateObjectFactory(serviceLocator, FreemarkerConfigurationFactory.class, new Value<FreemarkerConfigurationFactory>() { @Override public FreemarkerConfigurationFactory get() { Configuration configuration = getTemplateObjectFactory(serviceLocator, Configuration.class, Values.<Configuration>empty()); if (configuration == null) { return new FreemarkerDefaultConfigurationFactory(servletContext); } else { return new FreemarkerSuppliedConfigurationFactory(configuration); } } });
哎呀,这个非常好啊,从这里创建这个Configuration,那么先不说getTemplateObjectFactory这个是干嘛,先说,下面FreemarkerDefaultConfigurationFactory
,这个就是采用web的加载器,其中包括模板加载器:WebappTemplateLoader
从web上下文加载、ClassTemplateLoader
累加载器加载,FileTemplateLoader
文件根目录加载
FreemarkerSuppliedConfigurationFactory这个就不说了,他其实就是直接返回上面拿到的configuration好了,我们下面分析一下getTemplateObjectFactory
getTemplateObjectFactory 自定义加载
先看源码
protected <F> F getTemplateObjectFactory(final ServiceLocator serviceLocator, final Class<F> type, final Value<F> defaultValue) { final Object objectFactoryProperty = config.getProperty(MvcFeature.TEMPLATE_OBJECT_FACTORY + suffix); if (objectFactoryProperty != null) { if (type.isAssignableFrom(objectFactoryProperty.getClass())) { return type.cast(objectFactoryProperty); } else { 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();}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
这下子明白了,jersey的配置工厂都可以自定义,细节的东西还是考虑的很周全的,那么如果需要扩展Freemarker
配置,如TemplateLoader
、自定义指令
等等的这些玩意我们都可以弄了,那么具体怎么弄呢,是程序员的,还是喜欢看代码比文字的要多点的
pro.put("jersey.config.server.mvc.factory.freemarker", obj);addProperties(pro);
那么最后完成我们的工作,其中包括怎么配置出jersey怎么输出freemarker模板,并且简单的分析了一下他的源码,以及怎么自定义配置freemarker
如有说得不好多多指教