当前位置: 首页 > news >正文

Jersey采用模板Freemarker输出

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

简介

首先来说一下什么是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

@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<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);
//把你添加的信息告诉jersey
addProperties(pro);

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

转载于:https://my.oschina.net/u/1983041/blog/737473

相关文章:

  • hadoop连接hdfs报错Call From master/172.27.0.5 to master:8020 failed on connection exception: 问题的解决
  • Linux命令手册
  • kernel:NMI watchdog: BUG: soft lockup - CPU#6 stuck for 28s! CentOS7linux中内核被锁死
  • reactjs服务器端渲染——node搭建简易服务器
  • java后台接收前端对象数组
  • MyBatis 中if 标签 判断字符串不生效
  • 开源大数据周刊-第20期
  • Linux新建Oracle用户和数据库并导入sql文件
  • layui 数据表格内嵌上传按钮,并在上传中增加所在行的id或其他属性
  • 重启oracle的方法
  • ios中屏幕旋转的控制
  • 已有实例创建新的数据库空间和用户,并授权
  • 关于margin和padding的总结
  • 关于kafka发送消息过大导致的异常的解决方式
  • PHP利用Curl实现多线程抓取网页和下载文件
  • egg(89)--egg之redis的发布和订阅
  • python 装饰器(一)
  • Python学习笔记 字符串拼接
  • SQLServer插入数据
  • Vue UI框架库开发介绍
  • 开源地图数据可视化库——mapnik
  • #AngularJS#$sce.trustAsResourceUrl
  • (007)XHTML文档之标题——h1~h6
  • (zhuan) 一些RL的文献(及笔记)
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二十四)Flask之flask-session组件
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (简单) HDU 2612 Find a way,BFS。
  • (十八)SpringBoot之发送QQ邮件
  • (一)UDP基本编程步骤
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)setTimeout 和 setInterval 的区别
  • ..回顾17,展望18
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .NET 命令行参数包含应用程序路径吗?
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET中GET与SET的用法
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • @AliasFor注解
  • @JsonFormat与@DateTimeFormat注解的使用
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [100天算法】-二叉树剪枝(day 48)
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [Android Pro] Notification的使用
  • [CSS]CSS 字体属性