美文网首页安全技术JavaWeb
【JinJava】一个Java使用的Jinja模板

【JinJava】一个Java使用的Jinja模板

作者: crossous | 来源:发表于2018-09-29 14:01 被阅读236次
jinjava logo

一、前言

  从我过去的文章可以看出,我更喜欢使用Python,但作为一个一半技术在Web上的程序员,JavaWeb也是无法全部逃过的。
  学过JSP、Servlet,看得懂代码,但自己写很慢,需要查不少资料,同时无比想念写flask时用的Jinja2模板,于是上网搜Java有没有封装Jinja,百度没查到,但Google立刻就搜到了。
Jinjava github
Jinjava doc
  不得不佩服这起名的巧妙,Jinja与Java拼接成为了Jinjava,话不多说,让我们具体使用一下吧。

二、使用

  Jinja模板是通过模板语言,将变量代入模板生成文本,用于生成HTML是最常用的操作,Python Flask中的render_template函数就是将模板与变量合成生成Response对象。
  在Servlet中,Servlet类并非是返回Response对象,而是将通过改变参数传递进来的Response对象改变返回响应结果。
  在此之前,让我们先准备一个Maven+Servlet项目,可以参考我之前的文章【JavaWeb】IDEA创建Maven项目,配置Web项目
  然后在pom文件中引入Jinjava,将下面的依赖放在project>dependencies标签下,其中,com.hubspot.jinjava是本体,后面两个是jinjava用于记录日志的依赖,最后的com.google.guava是google的java开源库,里面有很多实用的方法。

<dependency>
  <groupId>com.hubspot.jinjava</groupId>
  <artifactId>jinjava</artifactId>
  <version>2.4.8</version>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.7</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-jdk14</artifactId>
  <version>1.7.8</version>
</dependency>

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>18.0</version>
</dependency>

  根据我上个文章配完的在com.demo目录下新建一个类,如果没看过上个文章也没关系,在java目录下新建一个包,我命名为com.demo,并在下面新建两个servlet类,分别命名为HelloWorld和JinjavaHello

项目结构
  webapp>source>jsp下的jsppage.jsp是测试用的,可以不用新建
  打出HelloWorld页面基础,是一个普通的Servlet类,在HelloWorld.java中打出下面的页面:
package com.demo;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


public class HelloWorld extends javax.servlet.http.HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        response.setContentType("text/html");
        response.getWriter().print("Servlet project create is success!");
    }
}

  此时可以先配置web.xml文件测试,我先继续下一步,编辑JinJavaHello.java,同样先打出最简单的框架:

import com.hubspot.jinjava.*;

// guava工具类
import com.google.common.collect.Maps; // 新建map工具(类似python中的dict)
import com.google.common.io.Resources; //读取文件工具 
import com.google.common.base.Charsets; //字符集工具
import com.google.common.collect.ImmutableMap; //初始化map工具
import com.google.common.collect.ImmutableList; //初始化list工具

import java.util.*; // java标准库中的map

//servlet类
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class JinJavaHello extends javax.servlet.http.HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

    }
}

  然后我们去一个编写模板(命名为person.html,并放到Resources目录下):

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>{{ name }}的个人页面</title>
</head>
<body>
<b>你好,{{ name }}</b><br>
<div>您的倒霉同学们又来看你了
    <ul>
        <li>{{201601}}:{{students.get("201601")}}</li>
        <li>{{201602}}:{{students.get("201602")}}</li>
        <li>{{201603}}:{{students.get("201603")}}</li>
    </ul>
</div>
<div>
    您还有太多的任务没做
    <ul>
        {% for task in tasks %}
            {% if task != '炼金术'%}
                <li>{{ task if task != '丢人' else task+'!'}}</li>
            {% endif %}
        {% endfor %}
        <li>...</li>
    </ul>
    <a href="{{url_for('HelloWorld')}}">转去首页</a>
</div>
</body>
<script>
</script>
</html>

  这里我们希望像flask的render_template方法一样,通过这个模板,传递三个参数:name是用户的名称;students是一个字典表(dict),结构:key是学号字符串,value是姓名字符串;tasks是任务列表,结构类似python中的列表,如果是在python flask中,我们会这样编写:

@route('/person')
def Person():
#    name = session.get('name')
    name = '黑暗大法师'
    students = {'201601' : 王大锤, '201602' : 李铁华, '201603' : '崔大建'}
    tasks = ['炼金术', '魔造学', '圣光术', '冲锋', '丢人']
    return render_template('person.html', name=name, students=students, tasks=tasks)  

@route('/hello')
def HelloWorld():
    return 'Servlet project create is success!'
然后在运行后显示出:

  在点击链接后我们可以跳往首页,那么在java中如何编写呢?让我们先构造java中的list与dict(map)类型:

Map<String, String> students = ImmutableMap.<String, String>builder().
        put("201601", "王大锤").
        put("201602", "李铁华").
        put("201603", "崔大建").build();
List<String> tasks = ImmutableList.<String>builder()
        .add("炼金术")
        .add("魔造学")
        .add("圣光术")
        .add("冲锋")
        .add("丢人").build();

在python中,多余参数都会变为**kwargs,类型为字典,key和value都是可以获取的,而在java中,这个kwargs就要我们自己去构建了,下面程序中的context就相当于kwargs:

map<String, Object> context = Maps.newHashMap();
context.put("name", "黑暗大法师");
context.put("students", students);
context.put("tasks", tasks);

  构造jinjava对象,读取资源,并呈现页面:

Jinjava jinjava = new Jinjava();
String template = Resources.toString(Resources.getResource("person.html"), Charsets.UTF_8);
String renderedTemplate = jinjava.render(template, context);

  可以看出,得到的呈现结果是String类型,实际上,flask也是对jinja2模板做出了封装才能使得返回结果自动为response,因此在java中我们操作response对象就可改变返回结果,不过再此之前还要改变下编码格式:

response.setContentType("text/html;charset=utf-8");
response.setHeader("Content-type", "text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");

response.getWriter().print(renderedTemplate);

  是时候测试一下了,更改webapp>WEB-INFO下的web.xml:

<web-app>
  <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>com.demo.HelloWorld</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>jsppage</servlet-name>
        <jsp-file>/source/jsp/jsppage.jsp</jsp-file>
    </servlet>
    <servlet>
        <servlet-name>jinjavahello</servlet-name>
        <servlet-class>com.demo.JinJavaHello</servlet-class>
    </servlet>


    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>jsppage</servlet-name>
        <url-pattern>/giligili</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>jinjavahello</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
</web-app>

  同样,jsppage的映射是用于测试的,可以不用加
  我们运行下Tomcat服务器,并访问:http://localhost:8080/person,结果却并非我们想要的:

  
500意思是服务器的程序运行出错,信息为:不能解析方法:url_for
  想想也是,在flask中,我们用url_for的目的是:假如我们有一个需求,想要改变访问的路径,但网页不需要改变,如果路径是写死的,那么之前所有网页的路径都需要改变,但是方法的名字不会改变。这时我们用方法名作为终结点endpoint(蓝图注册时可自定义),将终结点传入url_for,以及一系列参数,自动生成相关路径。但是java中的“终结点”是什么呢?Servlet类名吗?如何通过类名获取路径(pattern)?
  或许Servlet有现成方法,但我暂时只找到一个:
ServletContext servletContext = getServletContext();
Map<String, ? extends ServletRegistration> registrations =
        servletContext.getServletRegistrations();

String path = new ArrayList<String>(registrations.get("HelloWorld").getMappings()).get(0);

  通过上面的方法,获取注册信息[ServletContextAPI],其中registrations的键(key)是我们在web.xml中注册的servlet-name,值(value)是org.apache.catalina.core.ApplicationServletRegistration对象,通过操控这个对象可以获取注册信息,例如:getMapping就能获取路径,getClassName返回类名的字符串。
  上面的将getMappings的结果传递到列表中,是因为getMapping返回的是HashSet类型,我想要获取到第一个路径,就要先转换为list并得到第一个值,结果就是path;然后我们将这个path传递给context:

context.put("HelloWorldPath", path);

并将jinja模板相应地点改为:

<a href="{{HelloWorldPath}}">转去首页</a>

  重启Tomcat服务器,并访问http://localhost:8080/person,就会发现页面正常呈现,并且跳转链接也可以做到了。

三、总结

  此时我们已经完成了链接获取的功能,但还不能完全代替url_for,以及一些地址栏规则,我们可以封装一些函数,用正则替换来实现这个功能。
  或许jinjava也集成了这些功能,只是我还没找到。
  试验了一些东西,发现jinjava对jinja的还原还是不错的,例如extend base页面,单引号字符串,if else三元表达式、过滤器等等。
  更多的功能期待各位自己去挖掘。

相关文章

  • 【JinJava】一个Java使用的Jinja模板

    一、前言   从我过去的文章可以看出,我更喜欢使用Python,但作为一个一半技术在Web上的程序员,JavaWe...

  • Ansible之Jinja2模板—5

    jinja2的基本概述jinja2模板与ansible的关系Ansible使用jinja2模板jinja2 模板A...

  • Python Web框架--框架Flask--模板Jinja(三

    一、模板简介 Jinja 模板的使用方法。 模板标签  其实Jinja 模板和其他语言和框架的模板类似,反正都是通...

  • templates(模板)

    jinja2 Flask中使用jinja2模板引擎jinja2是由Flask作者开发,模仿Django的模板引擎 ...

  • HTML入门

    博主在使用Flask过程,预在项目中使用中Jinja模板。学习Jinja模板离不开基础的HTML的知识。本文是学习...

  • 4.2 模板的制作:Jinja2模板中的递归

    学习目标 使用jinja2模板的递归方法重构报告生成模板 前期设置 初始化document 定义直接显示jinja...

  • Templates 2018-08-28

    1. jinja2 Flask中使用jinja2模板引擎 jinja2是由Flask作者开发,模仿Django的模...

  • flask.pocoo.org/docs/0.12/templa

    原文链接 模板 Flask 使用 Jinja2 作为默认模板引擎。你完全可以使用其它模板引擎。但是不管你使用 哪种...

  • Jinja2 模板用法

    1. 语法 在jinja2中,存在三种语法: 控制结构 {% %} 变量取值 {{ }} jinja2模板中使用 ...

  • flask-模板

    一、模板的定义 二、模板引擎 flask使用jinja2作为默认模板引擎 2-1:默认配置 template_fo...

网友评论

    本文标题:【JinJava】一个Java使用的Jinja模板

    本文链接:https://www.haomeiwen.com/subject/aaumoftx.html