Jersey采用模板Freemarker输出

来源:互联网 发布:网络维护实训周报 编辑:程序博客网 时间:2024/05/20 01:38

简介

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

  • apache axis2
  • apache CXF
  • spring mvc 也算上一个,但不是标准的

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

  • JFinal
  • Spring boot

以笔者了解呢目前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>

简单说一下这个配置,最重要的还是最后那两个,是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>

最重要的是配置那个扫描包(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");        //这里需要说明一下,前面有"/"和没有是很大区别的        //没有的话,jersey会在base路径下,加上当前类的路径在加上这个exmaple        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)) {        // 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是干嘛的


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);    }}

从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) {    //这个值为 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);//把你添加的信息告诉jerseyaddProperties(pro);

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

0 0
原创粉丝点击