Merge pull request #118 from TopCoderMyDream/dev

add: 加入nutzboot-starter-freemarker
This commit is contained in:
Wendal Chen 2018-02-04 22:12:30 +08:00 committed by GitHub
commit f41d015b2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 653 additions and 1 deletions

View File

@ -0,0 +1,38 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>nutzboot-demo-simple</artifactId>
<groupId>org.nutz</groupId>
<version>2.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nutzboot-demo-simple-freemarker</artifactId>
<packaging>jar</packaging>
<name>nutzboot-demo-simple-freemarker</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,22 @@
package io.nutz.demo.simple;
import org.nutz.boot.NbApp;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
public class MainLauncher {
@At
@Ok("fm:/index")
public Object index(){
return NutMap.NEW().setv("name","wendal").setv("age",18);
}
public static void main(String[] args) {
new NbApp().setPrintProcDoc(true).start();
}
}

View File

@ -0,0 +1,4 @@
server.port=8080
server.host=0.0.0.0
freemarker.suffix=.html

View File

@ -0,0 +1,8 @@
log4j.rootLogger=info,Console
log4j.logger.org.nutz.mvc=debug
log4j.logger.org.eclipse.jetty=info
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p [%t] --- %c{1}: %m%n

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>NB demo for Freemarker</title>
</head>
<body>
<div>
<h2>Context Path = ${obj.base!}</h2>
</div>
<div>
<h2>From Action name=<span> ${obj.name}</span>, age=${obj.age!}</span></h2>
</div>
</body>
</html>

View File

@ -42,7 +42,8 @@
<module>nutzboot-demo-simple-quartz</module>
<module>nutzboot-demo-simple-j2cache</module>
<module>nutzboot-demo-simple-dao-with-slave</module>
</modules>
<module>nutzboot-demo-simple-freemarker</module>
</modules>
<dependencies>
<dependency>

View File

@ -0,0 +1,63 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>nutzboot-starter</artifactId>
<groupId>org.nutz</groupId>
<version>2.2-SNAPSHOT</version>
</parent>
<artifactId>nutzboot-starter-freemarker</artifactId>
<packaging>jar</packaging>
<name>nutzboot-starter-freemarker</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<description>NutzBoot, micoservice base on Nutz</description>
<!--<url>http://nutzam.com</url>-->
<issueManagement>
<system>Github Issue</system>
<url>http://github.com/nutzam/nutzboot/issues</url>
</issueManagement>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<developers>
<developer>
<id>蛋蛋</id>
<name>王庆华</name>
<email>TopCoderMyDream@gmail.com</email>
<url>https://github.com/TopCoderMyDream</url>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/nutzam/nutzboot.git</connection>
<developerConnection>scm:git:git://github.com/nutzam/nutzboot.git</developerConnection>
<url>git://github.com/nutzam/nutzboot.git</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>nutzcn-snapshots</id>
<name>NutzCN snapshot repository</name>
<url>https://jfrog.nutz.cn/artifactory/snapshots</url>
</snapshotRepository>
<repository>
<id>sonatype-release-staging</id>
<name>Sonatype Nexus release repository</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>
</repository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,155 @@
package org.nutz.boot.starter.freemarker;
import freemarker.template.*;
import org.nutz.boot.annotation.PropDoc;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.IocContext;
import org.nutz.ioc.Iocs;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Streams;
import org.nutz.lang.Strings;
import org.nutz.lang.util.ClassTools;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import javax.servlet.ServletContext;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;
@IocBean(create = "init")
public class FreeMarkerConfigurer {
private final static Log log = Logs.get();
private Configuration configuration;
private String prefix;
private String suffix;
private FreemarkerDirectiveFactory freemarkerDirectiveFactory;
private Map<String, Object> tags = new HashMap<String, Object>();
public FreeMarkerConfigurer() {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_26);
Ioc ioc = Mvcs.ctx().getDefaultIoc();
PropertiesProxy conf = ioc.get(PropertiesProxy.class,"conf");
this.initp(configuration, Mvcs.getServletContext(), "template", conf.get(FreemarkerViewMaker.PROP_SUFFIX,".html"), new FreemarkerDirectiveFactory());
}
protected void initp(Configuration configuration, ServletContext sc, String prefix, String suffix, FreemarkerDirectiveFactory freemarkerDirectiveFactory) {
this.configuration = configuration;
URL url = ClassTools.getClassLoader().getResource(prefix);
String path = url.getPath();
this.prefix =path;
this.suffix = suffix;
this.freemarkerDirectiveFactory = freemarkerDirectiveFactory;
if (this.prefix == null)
this.prefix = sc.getRealPath("/") + prefix;
this.configuration.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);
this.configuration.setTemplateUpdateDelayMilliseconds(-1000);
this.configuration.setDefaultEncoding("UTF-8");
this.configuration.setURLEscapingCharset("UTF-8");
this.configuration.setLocale(Locale.CHINA);
this.configuration.setBooleanFormat("true,false");
this.configuration.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
this.configuration.setDateFormat("yyyy-MM-dd");
this.configuration.setTimeFormat("HH:mm:ss");
this.configuration.setNumberFormat("0.######");
this.configuration.setWhitespaceStripping(true);
}
public Configuration getConfiguration() {
return configuration;
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
public void init() {
try {
initFreeMarkerConfigurer();
Iterator<Entry<String, Object>> iterator = tags.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = iterator.next();
configuration.setSharedVariable(entry.getKey(), entry.getValue());
}
if (freemarkerDirectiveFactory == null)
return;
for (FreemarkerDirective freemarkerDirective : freemarkerDirectiveFactory.getList()) {
configuration.setSharedVariable(freemarkerDirective.getName(), freemarkerDirective.getTemplateDirectiveModel());
}
} catch (IOException e) {
log.error(e);
} catch (TemplateException e) {
log.error(e);
}
}
public String getSuffix() {
return Strings.isBlank(freemarkerDirectiveFactory.getSuffix()) ? this.suffix : freemarkerDirectiveFactory.getSuffix();
}
public String getPrefix() {
return prefix;
}
protected void initFreeMarkerConfigurer() throws IOException, TemplateException {
String path = freemarkerDirectiveFactory.getFreemarker();
File file = Files.findFile(path);
if (!Lang.isEmpty(file)) {
Properties p = new Properties();
p.load(Streams.fileIn(file));
configuration.setSettings(p);
}
File f = Files.findFile(prefix);
configuration.setDirectoryForTemplateLoading(f);
}
public void setTags(Map<String, Object> map) {
Iterator<Entry<String, Object>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = iterator.next();
String key = entry.getKey();
Object obj = entry.getValue();
tags.put(key, obj);
}
}
public FreeMarkerConfigurer setSuffix(String suffix) {
this.suffix = suffix;
return this;
}
public FreeMarkerConfigurer setPrefix(String prefix) {
this.prefix = prefix;
return this;
}
/**
*
* @param map
* @return
*
* mapTags : { factory : "$freeMarkerConfigurer#addTags", args : [ {
* 'abc' : 1, 'def' : 2 } ] }
*/
public FreeMarkerConfigurer addTags(Map<String, Object> map) {
if (map != null) {
try {
configuration.setAllSharedVariables(new SimpleHash(map, new DefaultObjectWrapper(Configuration.VERSION_2_3_26)));
} catch (TemplateModelException e) {
log.error(e);
}
}
return this;
}
}

View File

@ -0,0 +1,25 @@
package org.nutz.boot.starter.freemarker;
import freemarker.template.TemplateDirectiveModel;
/**
* @author 科技²º¹³
* 2014年1月1日 下午5:42:54
* http://www.rekoe.com
* QQ:5382211
*/
public class FreemarkerDirective {
private String name;
private TemplateDirectiveModel templateDirectiveModel;
public FreemarkerDirective(String name, TemplateDirectiveModel templateDirectiveModel) {
super();
this.name = name;
this.templateDirectiveModel = templateDirectiveModel;
}
public String getName() {
return name;
}
public TemplateDirectiveModel getTemplateDirectiveModel() {
return templateDirectiveModel;
}
}

View File

@ -0,0 +1,56 @@
package org.nutz.boot.starter.freemarker;
import org.nutz.lang.Lang;
import java.util.ArrayList;
import java.util.List;
public class FreemarkerDirectiveFactory {
private List<FreemarkerDirective> list = new ArrayList<FreemarkerDirective>();
private String freemarker;
private String suffix;
private FreemarkerDirective[] objs;
public FreemarkerDirectiveFactory() {
this.freemarker = "freemarker.properties";
}
public FreemarkerDirectiveFactory(FreemarkerDirective... objs) {
this.objs = objs;
}
public List<FreemarkerDirective> getList() {
return list;
}
public String getFreemarker() {
return freemarker;
}
public String getSuffix() {
return suffix;
}
public void init() {
if (Lang.isEmptyArray(objs)) {
return;
}
for (FreemarkerDirective freemarkerDirective : objs) {
list.add(freemarkerDirective);
}
}
public FreemarkerDirectiveFactory create(FreemarkerDirective... objs) {
if (Lang.isEmptyArray(objs)) {
return this;
}
for (FreemarkerDirective freemarkerDirective : objs) {
list.add(freemarkerDirective);
}
return this;
}
}

View File

@ -0,0 +1,154 @@
package org.nutz.boot.starter.freemarker;
import freemarker.ext.jsp.TaglibFactory;
import freemarker.ext.servlet.HttpRequestHashModel;
import freemarker.ext.servlet.HttpRequestParametersHashModel;
import freemarker.ext.servlet.HttpSessionHashModel;
import freemarker.ext.servlet.ServletContextHashModel;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateModel;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.view.AbstractPathView;
import javax.servlet.GenericServlet;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class FreemarkerView extends AbstractPathView {
private FreeMarkerConfigurer freeMarkerConfigurer;
private static final String ATTR_APPLICATION_MODEL = ".freemarker.Application";
private static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs";
private static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
private static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters";
private static final String KEY_APPLICATION = "Application";
private static final String KEY_REQUEST_MODEL = "Request";
private static final String KEY_SESSION_MODEL = "Session";
private static final String KEY_REQUEST_PARAMETER_MODEL = "Parameters";
private static final String KEY_EXCEPTION = "exception";
private static final String OBJ = "obj";
private static final String REQUEST = "request";
private static final String RESPONSE = "response";
private static final String SESSION = "session";
private static final String APPLICATION = "application";
private static final String KEY_JSP_TAGLIBS = "JspTaglibs";
public static final String PATH_BASE = "base";
public FreemarkerView(FreeMarkerConfigurer freeMarkerConfigurer, String path) {
super(path);
this.freeMarkerConfigurer = freeMarkerConfigurer;
}
public void render(HttpServletRequest request, HttpServletResponse response, Object value) throws Throwable {
String $temp = evalPath(request, value);
String path = getPath($temp);
ServletContext sc = request.getSession().getServletContext();
Configuration cfg = freeMarkerConfigurer.getConfiguration();
Map<String, Object> root = new HashMap<String, Object>();
root.put(OBJ, value);
root.put(REQUEST, request);
root.put(RESPONSE, response);
HttpSession session = request.getSession();
root.put(SESSION, session);
root.put(APPLICATION, sc);
root.put("props", System.getProperties());// .get("java.version")
Map<String, String> msgs = Mvcs.getMessages(request);
root.put("mvcs", msgs);
Enumeration<?> reqs = request.getAttributeNames();
while (reqs.hasMoreElements()) {
String strKey = (String) reqs.nextElement();
root.put(strKey, request.getAttribute(strKey));
}
jspTaglibs(sc, request, response, root, cfg.getObjectWrapper());
try {
Template template = cfg.getTemplate(path);
response.setContentType("text/html; charset=" + template.getEncoding());
template.process(root, response.getWriter());
} catch (Exception e) {
throw Lang.wrapThrow(e);
}
}
/**
* 子类可以覆盖这个方法给出自己特殊的后缀
*
* @return 后缀
*/
protected String getExt() {
return freeMarkerConfigurer.getSuffix();
}
private String getPath(String path) {
StringBuffer sb = new StringBuffer();
// 空路径采用默认规则
if (Strings.isBlank(path)) {
sb.append(Mvcs.getServletContext().getRealPath(freeMarkerConfigurer.getPrefix()));
sb.append((path.startsWith("/") ? "" : "/"));
sb.append(Files.renameSuffix(path, getExt()));
}
// 绝对路径 : '/' 开头的路径不增加 '/WEB-INF'
else if (path.charAt(0) == '/') {
String ext = getExt();
sb.append(path);
if (!path.toLowerCase().endsWith(ext))
sb.append(ext);
}
// 包名形式的路径
else {
sb.append(path.replace('.', '/'));
sb.append(getExt());
}
return sb.toString();
}
protected void jspTaglibs(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response, Map<String, Object> model, ObjectWrapper wrapper) {
synchronized (servletContext) {
ServletContextHashModel servletContextModel = (ServletContextHashModel) servletContext.getAttribute(ATTR_APPLICATION_MODEL);
if (Lang.isEmpty(servletContextModel)) {
GenericServlet servlet = JspSupportServlet.jspSupportServlet;
if (!Lang.isEmpty(servlet)) {
servletContextModel = new ServletContextHashModel(servlet, wrapper);
servletContext.setAttribute(ATTR_APPLICATION_MODEL, servletContextModel);
TaglibFactory taglibs = new TaglibFactory(servletContext);
servletContext.setAttribute(ATTR_JSP_TAGLIBS_MODEL, taglibs);
}
}
model.put(KEY_APPLICATION, servletContextModel);
TemplateModel tempModel = (TemplateModel) servletContext.getAttribute(ATTR_JSP_TAGLIBS_MODEL);
model.put(KEY_JSP_TAGLIBS, tempModel);
}
HttpSession session = request.getSession(false);
if (!Lang.isEmpty(session)) {
model.put(KEY_SESSION_MODEL, new HttpSessionHashModel(session, wrapper));
}
HttpRequestHashModel requestModel = (HttpRequestHashModel) request.getAttribute(ATTR_REQUEST_MODEL);
if (Lang.isEmpty(requestModel) || !Lang.equals(requestModel.getRequest(), request)) {
requestModel = new HttpRequestHashModel(request, response, wrapper);
request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
}
model.put(KEY_REQUEST_MODEL, requestModel);
HttpRequestParametersHashModel reqParametersModel = (HttpRequestParametersHashModel) request.getAttribute(ATTR_REQUEST_PARAMETERS_MODEL);
if (Lang.isEmpty(reqParametersModel) || !Lang.equals(requestModel.getRequest(), request)) {
reqParametersModel = new HttpRequestParametersHashModel(request);
request.setAttribute(ATTR_REQUEST_PARAMETERS_MODEL, reqParametersModel);
}
model.put(KEY_REQUEST_PARAMETER_MODEL, reqParametersModel);
Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");
if (Lang.isEmpty(exception)) {
exception = (Throwable) request.getAttribute("javax.servlet.error.JspException");
}
if (!Lang.isEmpty(exception)) {
model.put(KEY_EXCEPTION, exception);
}
}
}

View File

@ -0,0 +1,47 @@
package org.nutz.boot.starter.freemarker;
import org.nutz.boot.annotation.PropDoc;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.View;
import org.nutz.mvc.ViewMaker;
@IocBean(name="$views_freekmarker")
public class FreemarkerViewMaker implements ViewMaker {
protected FreeMarkerConfigurer freeMarkerConfigurer;
protected String iocName = "freeMarkerConfigurer";
protected static final String PRE = "freemarker.";
@PropDoc(group = "freemarker", value = "文件后缀",defaultValue = ".html")
public static final String PROP_SUFFIX = PRE + "suffix";
@Inject
PropertiesProxy conf;
public View make(Ioc ioc, String type, String value) {
if ("fm".equalsIgnoreCase(type) || "ftl".equalsIgnoreCase(type)) {
if (freeMarkerConfigurer == null) {
for (String name : ioc.getNames()) {
if (iocName.equals(name)) {
freeMarkerConfigurer = ioc.get(FreeMarkerConfigurer.class);
break;
}
}
if (freeMarkerConfigurer == null) {
freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.init();
}
}
return new FreemarkerView(freeMarkerConfigurer, value);
}
return null;
}
}

View File

@ -0,0 +1,17 @@
package org.nutz.boot.starter.freemarker;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
/**
*/
public class JspSupportServlet extends HttpServlet {
private static final long serialVersionUID = 8302309812391541933L;
public static JspSupportServlet jspSupportServlet;
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
jspSupportServlet = this;
}
}

View File

@ -0,0 +1,25 @@
package org.nutz.boot.starter.freemarker.directive;
import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import org.nutz.lang.Times;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
/**
* 执行时间标签
*
*/
public class CurrentTimeDirective implements TemplateDirectiveModel {
@SuppressWarnings({ "rawtypes" })
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
Writer out = env.getOut();
out.append(Times.format("yyyy-MM-dd HH:mm", Times.now()));
}
}

View File

@ -0,0 +1 @@
org.nutz.boot.starter.freemarker.FreemarkerViewMaker

View File

@ -0,0 +1,9 @@
#demo configure
url_escaping_charset=UTF-8
locale=zh_CN
boolean_format=true,false
datetime_format=yyyy-MM-dd HH:mm:ss
date_format=yyyy-MM-dd
time_format=HH:mm:ss
number_format=0.######
#auto_import=/ftl/pony/index.ftl as p,/ftl/spring.ftl as s

View File

@ -55,6 +55,7 @@
<module>nutzboot-starter-apollo-client</module>
<module>nutzboot-starter-config-client</module>
<module>nutzboot-starter-j2cache</module>
<module>nutzboot-starter-freemarker</module>
</modules>
<dependencies>
<dependency>

10
pom.xml
View File

@ -793,6 +793,16 @@
<artifactId>nutzboot-starter-j2cache</artifactId>
<version>${nutzboot.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.26-incubating</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-freemarker</artifactId>
<version>${nutzboot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>