Jersey采用模板Freemarker输出

简介

首先来说一下什么是jersey,他是实现了restful风格的其中一个框架,当然除了jersey还有其他的,例如

不过在平时在开发web下,目前流行的还是以spring mvc为主,但现在也有一些后起之秀,就例如

  • JFinal
  • Spring boot

以笔者了解呢目前jersey用得还是蛮多的,最主要是体现在对外接口上面。

不说那么多了,送上看看怎么在jersey用freemarker


配置

maven

1<dependency> 2 <groupId>javax.ws.rs</groupId> 3 <artifactId>javax.ws.rs-api</artifactId> 4 <version>2.0.1</version> 5</dependency> 6<dependency> 7 <groupId>javax.el</groupId> 8 <artifactId>javax.el-api</artifactId> 9 <version>2.2.4</version> 10 </dependency> 11<dependency> 12 <groupId>org.glassfish.jersey.containers</groupId> 13 <artifactId>jersey-container-servlet</artifactId> 14 <version>2.23.1</version> 15</dependency> 16<dependency> 17 <groupId>org.glassfish.web</groupId> 18 <artifactId>javax.el</artifactId> 19 <version>2.2.4</version> 20</dependency> 21<dependency> 22 <groupId>org.glassfish.jersey.ext</groupId> 23 <artifactId>jersey-mvc-mustache</artifactId> 24 <version>2.23.1</version> 25</dependency> 26<dependency> 27 <groupId>org.glassfish.jersey.ext</groupId> 28 <artifactId>jersey-mvc-freemarker</artifactId> 29 <version>2.23.1</version> 30</dependency>

简单说一下这个配置,最重要的还是最后那两个,是jersey做的扩展,当然,他肯定有依赖freemarker的


web.xml

1<servlet> 2 <servlet-name>restful</servlet-name> 3 <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> 4 <init-param> 5 <param-name>jersey.config.server.provider.packages</param-name> 6 <param-value> 7 com.example 8 </param-value> 9 </init-param> 10 <init-param> 11 <param-name>javax.ws.rs.Application</param-name> 12 <param-value> 13 com.example.MyApplication 14 </param-value> 15 </init-param> 16</servlet> 17<servlet-mapping> 18 <servlet-name>restful</servlet-name> 19 <url-pattern>/restful/*</url-pattern> 20</servlet-mapping>

最重要的是配置那个扫描包(jersey.config.server.provider.packages),和spring下的scan package一样的道理 另外还要让jersey识别我们的配置,那么还要写一个key为javax.ws.rs.Application的配置


java 配置

1public class MyApplication extends ResourceConfig { 2 public MyApplication() { 3 /*模板*/ 4 Map<String, Object> pro = new HashMap<String, Object>(1); 5 //模板编码 6 pro.put("jersey.config.server.mvc.encoding.freemarker", "UTF-8"); 7 //指定模板基础路径 8 pro.put("jersey.config.server.mvc.templateBasePath.freemarker", "WEB-INF/freemarker"); 9 10 addProperties(pro). 11 register(FreemarkerMvcFeature.class); 12 } 13}

这里主要注册一个让他支持freemarker的Feature,当然jersey支持了很多通过注册可以做的事情,包括Oauth、Filter、BeanValidata、Security、ContainerRequestFilter等等


Control

1@Path("/views") 2public class ViewResource { 3 4 @GET 5 @Path("example") 6 @Produces("text/html") 7 public Viewable exampleView() { 8 Map<String, String> data = new HashMap<String, String>(); 9 data.put("text", "this is the ViewResource test text"); 10 //这里需要说明一下,前面有"/"和没有是很大区别的 11 //没有的话,jersey会在base路径下,加上当前类的路径在加上这个exmaple 12 return new Viewable("/example", data); 13 } 14}

最后这个java呢,其实就是配置一个控制器,最后通过访问/restful/views/example 就可以定位到这个控制器,最后找模板,这个配置的模板是在,/WEB-INF/freemarker/example.ftl


源码分析

FreemarkerMvcFeature.java

直接看源码config方法

1public boolean configure(final FeatureContext context) { 2 final Configuration config = context.getConfiguration(); 3 4 if (!config.isRegistered(FreemarkerViewProcessor.class)) { 5 // Template Processor. 6 context.register(FreemarkerViewProcessor.class); 7 8 // MvcFeature. 9 if (!config.isRegistered(MvcFeature.class)) { 10 context.register(MvcFeature.class); 11 } 12 return true; 13 } 14 return false; 15}

我们平时要jersey支持web服务需要注册MvcFeature,那么,现在看这里相当于FreemarkerMvcFeature就依赖这个MvcFeature,如果没有注册,他会帮我们注册,jersey这个点做得还是不错的 我们继续往下看看FreemarkerViewProcessor是干嘛的


FreemarkerViewProcessor.java

1@Override 2protected Template resolve(final String templateReference, final Reader reader) throws Exception { 3 return factory.getConfiguration().getTemplate(templateReference); 4 } 5 6@Override 7public void writeTo(final Template template, final Viewable viewable, final MediaType mediaType, 8 final MultivaluedMap<String, Object> httpHeaders, final OutputStream out) throws IOException { 9 try { 10 Object model = viewable.getModel(); 11 if (!(model instanceof Map)) { 12 model = new HashMap<String, Object>() {{ 13 put("model", viewable.getModel()); 14 }}; 15 } 16 Charset encoding = setContentType(mediaType, httpHeaders); 17 template.process(model, new OutputStreamWriter(out, encoding)); 18 } catch (TemplateException te) { 19 throw new ContainerException(te); 20 } 21}

从resolve看出,其实这里算一个入口 ,他从freemarker的configuration中获取模板,然后直接从wirteTo进行写出,这里有个东西需要注意, 他把所有从Viewable中的数据如果是非Map,放到一个以model为key的Map当中,所以啊,我们开的时候,如果不是一个Map,需要从model中拿数据

另外,看看这个factory是如何产生的

1this.factory = getTemplateObjectFactory(serviceLocator, FreemarkerConfigurationFactory.class, 2 new Value<FreemarkerConfigurationFactory>() { 3 @Override 4 public FreemarkerConfigurationFactory get() { 5 Configuration configuration = 6 getTemplateObjectFactory(serviceLocator, Configuration.class, 7 Values.<Configuration>empty()); 8 if (configuration == null) { 9 return new FreemarkerDefaultConfigurationFactory(servletContext); 10 } else { 11 return new FreemarkerSuppliedConfigurationFactory(configuration); 12 } 13 } 14 });

哎呀,这个非常好啊,从这里创建这个Configuration,那么先不说getTemplateObjectFactory这个是干嘛,先说,下面FreemarkerDefaultConfigurationFactory,这个就是采用web的加载器,其中包括模板加载器:WebappTemplateLoader从web上下文加载、ClassTemplateLoader累加载器加载,FileTemplateLoader文件根目录加载 _FreemarkerSuppliedConfigurationFactory_这个就不说了,他其实就是直接返回上面拿到的configuration好了,我们下面分析一下getTemplateObjectFactory


getTemplateObjectFactory 自定义加载

先看源码

1protected <F> F getTemplateObjectFactory(final ServiceLocator serviceLocator, 2 final Class<F> type, final Value<F> defaultValue) { 3 //这个值为 jersey.config.server.mvc.factory.freemarker 4 final Object objectFactoryProperty = 5 config.getProperty(MvcFeature.TEMPLATE_OBJECT_FACTORY + suffix); 6 7 if (objectFactoryProperty != null) { 8 //如果是Configuration类型,直接转成对象并且返回 9 if (type.isAssignableFrom(objectFactoryProperty.getClass())) { 10 return type.cast(objectFactoryProperty); 11 } else { 12 //如果是String类型,直接new 出来并且进行返回 13 Class<?> factoryClass = null; 14 if (objectFactoryProperty instanceof String) { 15 factoryClass = ReflectionHelper 16 .classForNamePA((String) objectFactoryProperty).run(); 17 } else if (objectFactoryProperty instanceof Class<?>) { 18 factoryClass = (Class<?>) objectFactoryProperty; 19 } 20 if (factoryClass != null) { 21 if (type.isAssignableFrom(factoryClass)) { 22 return type.cast(serviceLocator.create(factoryClass)); 23 } else { 24 LOGGER.log(Level.CONFIG, 25 LocalizationMessages.WRONG_TEMPLATE_OBJECT_FACTORY(factoryClass, type)); 26 } 27 } 28 } 29 } 30 //否则返回空 31 return defaultValue.get(); 32}

这下子明白了,jersey的配置工厂都可以自定义,细节的东西还是考虑的很周全的,那么如果需要_扩展_Freemarker配置,如TemplateLoader自定义指令等等的这些玩意我们都可以弄了,那么具体怎么弄呢,是程序员的,还是喜欢看代码比文字的要多点的

1//在jersey的Application中可以配置 2//这个obj啊,做的事情可以是,一个类名,一个Configuration对象,一个Configuration的class 3//这个就是Freemarker的配置 4pro.put("jersey.config.server.mvc.factory.freemarker", obj); 5//把你添加的信息告诉jersey 6addProperties(pro);

那么最后完成我们的工作,其中包括怎么配置出jersey怎么输出freemarker模板,并且简单的分析了一下他的源码,以及怎么自定义配置freemarker 如有说得不好多多指教

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Opencv中Mat矩阵相乘——点乘、dot、mul运算详解

Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593