[analysis]添加HtmlTplDashboardWidgetHtmlRenderer,用于支持使用原生HTML渲染看板

This commit is contained in:
datagear 2019-12-26 22:02:59 +08:00
parent 7895ea3a43
commit 295421ae12
13 changed files with 2315 additions and 747 deletions

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.Serializable;
/**
* HTML看板导入项
*
* @author datagear@163.com
*
*/
public class HtmlDashboardImport implements Serializable
{
private static final long serialVersionUID = 1L;
/** 名称 */
private String name;
/** 内容 */
private String content;
public HtmlDashboardImport()
{
super();
}
public HtmlDashboardImport(String name, String content)
{
super();
this.name = name;
this.content = content;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
@Override
public String toString()
{
return getClass().getSimpleName() + " [name=" + name + ", content=" + content + "]";
}
}

View File

@ -0,0 +1,681 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.datagear.analysis.ChartTheme;
import org.datagear.analysis.DashboardTheme;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.RenderException;
import org.datagear.analysis.Theme;
import org.datagear.analysis.support.ChartWidgetSource;
import org.datagear.analysis.support.DashboardWidgetResManager;
import org.datagear.util.StringUtil;
import freemarker.core.Environment;
import freemarker.ext.util.WrapperTemplateModel;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
/**
* 使用Freemarker作为模板的{@linkplain HtmlTplDashboardWidget}渲染器
* <p>
* 此类可渲染由{@linkplain DashboardWidgetResManager}管理模板的{@linkplain HtmlTplDashboardWidget}
* 其中{@linkplain HtmlTplDashboardWidget#getTemplate()}应该是可以通过{@linkplain DashboardWidgetResManager#getFile(String, String)}找到的模板文件名
* </p>
* <p>
* 此类需要手动调用{@linkplain #init()}方法进行初始化
* </p>
* <p>
* 支持的模板格式如下
* </p>
* <code>
* <pre>
* ...
* &lt;@import /&gt;
* ...
* &lt;@theme /&gt;
* ...
* &lt;@dashboard var="..." listener="..."&gt;
* ...
* <@chart widget="..." var="..." elementId="..." /&gt;
* ...
* <@chart widget="..." var="..." elementId="..." /&gt;
* ...
* &lt;/@dashboard&gt;
* </pre>
* </code>
* <p>
* &lt;@import /&gt;引入内置JSCSS等HTML资源
* </p>
* <p>
* &lt;@theme /&gt;引入内置CSS主题样式
* </p>
* <p>
* &lt;@dashboard&gt;定义看板var自定义看板JS变量名可不填listener自定义看板JS监听器可不填
* </p>
* <p>
* &lt;@chart
* /&gt;定义图表widget{@linkplain HtmlChartWidget#getId()}必填var自定义图表JS变量名可不填elementId自定义图表HTML元素ID可不填
* </p>
*
* @author datagear@163.com
*
* @param <T>
*/
public class HtmlTplDashboardWidgetFmkRenderer<T extends HtmlRenderContext> extends HtmlTplDashboardWidgetRenderer<T>
{
public static final String DIRECTIVE_IMPORT = "import";
public static final String DIRECTIVE_THEME = "theme";
public static final String DIRECTIVE_DASHBOARD = "dashboard";
public static final String DIRECTIVE_CHART = "chart";
public static final String DASHBOARD_ELEMENT_STYLE_NAME = "dashboard";
public static final String CHART_ELEMENT_WRAPPER_STYLE_NAME = "chart-wrapper";
private boolean ignoreDashboardStyleBorderWidth = true;
private Configuration _configuration;
public HtmlTplDashboardWidgetFmkRenderer()
{
super();
}
public HtmlTplDashboardWidgetFmkRenderer(DashboardWidgetResManager dashboardWidgetResManager,
ChartWidgetSource chartWidgetSource)
{
super(dashboardWidgetResManager, chartWidgetSource);
}
public boolean isIgnoreDashboardStyleBorderWidth()
{
return ignoreDashboardStyleBorderWidth;
}
public void setIgnoreDashboardStyleBorderWidth(boolean ignoreDashboardStyleBorderWidth)
{
this.ignoreDashboardStyleBorderWidth = ignoreDashboardStyleBorderWidth;
}
/**
* 初始化
*
* @throws IOException
*/
public void init() throws IOException
{
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
cfg.setDirectoryForTemplateLoading(getDashboardWidgetResManager().getRootDirectory());
cfg.setDefaultEncoding(getTemplateEncoding());
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setSharedVariable(DIRECTIVE_IMPORT, new ImportTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_THEME, new ThemeTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_DASHBOARD, new DashboardTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_CHART, new ChartTemplateDirectiveModel());
setConfiguration(cfg);
}
@Override
protected void renderHtmlDashboard(T renderContext, HtmlDashboard dashboard) throws Exception
{
HtmlDashboardRenderDataModel dataModel = new HtmlDashboardRenderDataModel(dashboard,
renderContext.getContextPath());
Template template = getTemplate((HtmlTplDashboardWidget<?>) dashboard.getWidget());
try
{
template.process(buildHtmlDashboardRenderDataModel(dataModel), renderContext.getWriter());
}
catch (Throwable t)
{
throw new RenderException(t);
}
}
/**
* 获取{@linkplain HtmlTplDashboardWidget#getId()}的指定模板对象
*
* @param dashboardWidget
* @return
* @throws RenderException
*/
protected Template getTemplate(HtmlTplDashboardWidget<?> dashboardWidget) throws RenderException
{
String path = getDashboardWidgetResManager().getRelativePath(dashboardWidget.getId(),
dashboardWidget.getTemplate());
try
{
return getConfiguration().getTemplate(path);
}
catch (Throwable t)
{
throw new RenderException(t);
}
}
protected Configuration getConfiguration()
{
return _configuration;
}
protected void setConfiguration(Configuration _configuration)
{
this._configuration = _configuration;
}
protected Object buildHtmlDashboardRenderDataModel(HtmlDashboardRenderDataModel dataModel)
{
Map<String, Object> map = new HashMap<String, Object>();
map.put(KEY_HTML_DASHBOARD_RENDER_DATA_MODEL, dataModel);
return map;
}
protected HtmlDashboardRenderDataModel getHtmlDashboardRenderDataModel(Environment env)
throws TemplateModelException
{
TemplateHashModel templateHashModel = env.getDataModel();
HtmlDashboardRenderDataModel dataModel = (HtmlDashboardRenderDataModel) templateHashModel
.get(KEY_HTML_DASHBOARD_RENDER_DATA_MODEL);
return dataModel;
}
/**
* HTML看板渲染数据模型
*
* @author datagear@163.com
*
*/
protected static class HtmlDashboardRenderDataModel implements WrapperTemplateModel
{
private HtmlDashboard htmlDashboard;
private String contextPath = "";
public HtmlDashboardRenderDataModel()
{
super();
}
public HtmlDashboardRenderDataModel(HtmlDashboard htmlDashboard, String contextPath)
{
super();
this.htmlDashboard = htmlDashboard;
this.contextPath = contextPath;
}
public HtmlDashboard getHtmlDashboard()
{
return htmlDashboard;
}
public void setHtmlDashboard(HtmlDashboard htmlDashboard)
{
this.htmlDashboard = htmlDashboard;
}
public String getContextPath()
{
return contextPath;
}
public void setContextPath(String contextPath)
{
this.contextPath = contextPath;
}
@Override
public Object getWrappedObject()
{
return this.htmlDashboard;
}
}
protected abstract class AbstractTemplateDirectiveModel implements TemplateDirectiveModel
{
public AbstractTemplateDirectiveModel()
{
super();
}
/**
* 获取字符串参数值
*
* @param params
* @param key
* @return
* @throws TemplateModelException
*/
protected String getStringParamValue(Map<?, ?> params, String key) throws TemplateModelException
{
Object value = params.get(key);
if (value == null)
return null;
else if (value instanceof String)
return (String) value;
else if (value instanceof TemplateScalarModel)
return ((TemplateScalarModel) value).getAsString();
else
throw new TemplateModelException(
"Can not get string from [" + value.getClass().getName() + "] instance");
}
}
/**
* @import指令
*
* @author datagear@163.com
*
*/
protected class ImportTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public ImportTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlDashboard dashboard = dataModel.getHtmlDashboard();
HtmlRenderContext renderContext = dashboard.getRenderContext();
Writer out = env.getOut();
out.write("<meta charset=\"" + getWriterEncoding() + "\">");
writeDashboardImport(renderContext, dashboard, "");
}
}
/**
* @theme指令
*
* @author datagear@163.com
*
*/
protected class ThemeTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public ThemeTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlRenderContext renderContext = dataModel.getHtmlDashboard().getRenderContext();
Writer out = env.getOut();
DashboardTheme dashboardTheme = getDashboardTheme(renderContext);
writeDashboardTheme(out, dashboardTheme);
}
protected DashboardTheme getDashboardTheme(RenderContext renderContext)
{
DashboardTheme dashboardTheme = HtmlRenderAttributes.getDashboardTheme(renderContext);
return dashboardTheme;
}
protected void writeDashboardTheme(Writer out, DashboardTheme dashboardTheme) throws IOException
{
ChartTheme chartTheme = (dashboardTheme == null ? null : dashboardTheme.getChartTheme());
out.write("<style type=\"text/css\">");
writeNewLine(out);
out.write("body{");
writeNewLine(out);
out.write(" padding: 0px 0px;");
writeNewLine(out);
out.write(" margin: 0px 0px;");
writeNewLine(out);
if (dashboardTheme != null)
{
out.write(" background-color: " + dashboardTheme.getBackgroundColor() + ";");
writeNewLine(out);
out.write(" color: " + dashboardTheme.getForegroundColor() + ";");
writeNewLine(out);
}
out.write("}");
writeNewLine(out);
out.write("." + DASHBOARD_ELEMENT_STYLE_NAME + "{");
writeNewLine(out);
writeThemeCssAttrs(out, dashboardTheme);
writeBorderBoxCssAttrs(out);
if (isIgnoreDashboardStyleBorderWidth())
{
out.write(" border-width: 0px;");
writeNewLine(out);
}
out.write("}");
writeNewLine(out);
out.write("." + CHART_ELEMENT_WRAPPER_STYLE_NAME + "{");
writeNewLine(out);
out.write(" position: relative;");
writeNewLine(out);
writeThemeCssAttrs(out, chartTheme);
writeBorderBoxCssAttrs(out);
out.write("}");
writeNewLine(out);
out.write("." + HtmlChartPlugin.BUILTIN_CHART_ELEMENT_STYLE_NAME + "{");
writeNewLine(out);
writeFillParentCssAttrs(out);
writeBorderBoxCssAttrs(out);
out.write("}");
writeNewLine(out);
out.write("</style>");
writeNewLine(out);
}
protected void writeThemeCssAttrs(Writer out, Theme theme) throws IOException
{
if (theme != null)
{
String borderWidth = theme.getBorderWidth();
if (borderWidth == null)
borderWidth = "0";
out.write(" color: " + theme.getForegroundColor() + ";");
writeNewLine(out);
out.write(" background-color: " + theme.getBackgroundColor() + ";");
writeNewLine(out);
out.write(" border-color: " + theme.getBorderColor() + ";");
writeNewLine(out);
out.write(" border-width: " + theme.getBorderWidth() + ";");
writeNewLine(out);
out.write(" border-style: solid;");
writeNewLine(out);
}
}
protected void writeFillParentCssAttrs(Writer out) throws IOException
{
out.write(" position: absolute;");
writeNewLine(out);
out.write(" top: 0px;");
writeNewLine(out);
out.write(" bottom: 0px;");
writeNewLine(out);
out.write(" left: 0px;");
writeNewLine(out);
out.write(" right: 0px;");
writeNewLine(out);
}
protected void writeBorderBoxCssAttrs(Writer out) throws IOException
{
out.write(" box-sizing: border-box;");
writeNewLine(out);
out.write(" -moz-box-sizing: border-box;");
writeNewLine(out);
out.write(" -webkit-box-sizing: border-box;");
writeNewLine(out);
}
}
/**
* @dashboard指令
*
* @author datagear@163.com
*
*/
protected class DashboardTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public DashboardTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
String varName = getStringParamValue(params, "var");
String listener = getStringParamValue(params, "listener");
boolean hasListener = !StringUtil.isEmpty(listener);
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlDashboard dashboard = dataModel.getHtmlDashboard();
HtmlRenderContext renderContext = dashboard.getRenderContext();
int nextSequence = -1;
if (StringUtil.isEmpty(varName))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
varName = HtmlRenderAttributes.generateDashboardVarName(nextSequence);
}
dashboard.setVarName(varName);
Writer out = env.getOut();
writeScriptStartTag(out);
writeNewLine(out);
out.write("var ");
out.write(varName);
out.write("=");
writeNewLine(out);
writeHtmlDashboardScriptObject(out, dashboard, true);
out.write(";");
writeNewLine(out);
writeScriptEndTag(out);
writeNewLine(out);
HtmlRenderAttributes.setChartRenderContextVarName(renderContext, varName + ".renderContext");
if (body != null)
body.render(out);
writeScriptStartTag(out);
writeNewLine(out);
String tmpRenderContextVar = HtmlRenderAttributes.generateRenderContextVarName(nextSequence);
// 移除内部设置的属性
HtmlRenderAttributes.removeChartRenderContextVarName(renderContext);
HtmlRenderAttributes.removeChartNotRenderScriptTag(renderContext);
HtmlRenderAttributes.removeChartScriptNotInvokeRender(renderContext);
HtmlRenderAttributes.removeChartVarName(renderContext);
HtmlRenderAttributes.removeChartElementId(renderContext);
renderContext.removeAttribute(RENDER_ATTR_NAME_FOR_NOT_FOUND_SCRIPT);
out.write("var ");
out.write(tmpRenderContextVar);
out.write("=");
writeNewLine(out);
writeRenderContextScriptObject(out, renderContext);
out.write(";");
writeNewLine(out);
out.write(varName + ".renderContext.attributes = " + tmpRenderContextVar + ".attributes;");
writeNewLine(out);
List<? extends HtmlChart> charts = dashboard.getCharts();
if (charts != null)
{
for (HtmlChart chart : charts)
{
out.write(varName + ".charts.push(" + chart.getVarName() + ");");
writeNewLine(out);
}
}
out.write(varName + ".render = function(){");
writeNewLine(out);
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].render(); }");
writeNewLine(out);
out.write("};");
writeNewLine(out);
out.write(varName + ".update = function(){");
writeNewLine(out);
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].update(); }");
writeNewLine(out);
out.write("};");
writeNewLine(out);
if (hasListener)
{
out.write(varName + ".listener = window[\"" + listener + "\"];");
writeNewLine(out);
}
out.write("window.onload = function(){");
writeNewLine(out);
out.write("var doRender = true;");
writeNewLine(out);
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.onRender)");
writeNewLine(out);
out.write(" doRender=" + varName + ".listener.onRender(" + varName + "); ");
writeNewLine(out);
}
out.write("if(doRender != false)");
writeNewLine(out);
out.write(" " + varName + ".render();");
writeNewLine(out);
out.write("var doUpdate = true;");
writeNewLine(out);
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.onUpdate)");
writeNewLine(out);
out.write(" doUpdate=" + varName + ".listener.onUpdate(" + varName + "); ");
writeNewLine(out);
}
out.write("if(doUpdate != false)");
writeNewLine(out);
out.write(" " + varName + ".update();");
writeNewLine(out);
out.write("};");
writeNewLine(out);
writeScriptEndTag(out);
writeNewLine(out);
}
protected void writeHtmlDashboardScriptObject(Writer out, HtmlDashboard dashboard, boolean renderContextEmpty)
throws IOException
{
getHtmlDashboardScriptObjectWriter().write(out, dashboard, renderContextEmpty);
}
protected void writeRenderContextScriptObject(Writer out, RenderContext renderContext) throws IOException
{
getHtmlDashboardScriptObjectWriter().writeRenderContext(out, renderContext, true);
}
}
/**
* @chart指令
*
* @author datagear@163.com
*
*/
protected class ChartTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public ChartTemplateDirectiveModel()
{
super();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
String widget = getStringParamValue(params, "widget");
String var = getStringParamValue(params, "var");
String elementId = getStringParamValue(params, "elementId");
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlDashboard htmlDashboard = dataModel.getHtmlDashboard();
HtmlRenderContext renderContext = htmlDashboard.getRenderContext();
int nextSequence = -1;
HtmlChartWidget<HtmlRenderContext> chartWidget = getHtmlChartWidgetForRender(renderContext, widget);
if (StringUtil.isEmpty(var))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
var = HtmlRenderAttributes.generateChartVarName(nextSequence);
}
if (StringUtil.isEmpty(elementId))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
elementId = HtmlRenderAttributes.generateChartElementId(nextSequence);
}
HtmlRenderAttributes.setChartNotRenderScriptTag(renderContext, false);
HtmlRenderAttributes.setChartScriptNotInvokeRender(renderContext, true);
HtmlRenderAttributes.setChartVarName(renderContext, var);
HtmlRenderAttributes.setChartElementId(renderContext, elementId);
HtmlChart chart = chartWidget.render(renderContext);
List<HtmlChart> charts = (List<HtmlChart>) htmlDashboard.getCharts();
if (charts == null)
{
charts = new ArrayList<HtmlChart>();
htmlDashboard.setCharts(charts);
}
charts.add(chart);
}
}
}

View File

@ -12,9 +12,7 @@ import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.datagear.analysis.Chart;
import org.datagear.analysis.ChartTheme;
@ -24,90 +22,26 @@ import org.datagear.analysis.DashboardThemeSource;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.RenderException;
import org.datagear.analysis.RenderStyle;
import org.datagear.analysis.Theme;
import org.datagear.analysis.support.ChartWidget;
import org.datagear.analysis.support.ChartWidgetSource;
import org.datagear.analysis.support.DashboardWidgetResManager;
import org.datagear.analysis.support.SimpleDashboardThemeSource;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetFmkRenderer.HtmlDashboardRenderDataModel;
import org.datagear.util.Global;
import org.datagear.util.IDUtil;
import org.datagear.util.IOUtil;
import org.datagear.util.StringUtil;
import freemarker.core.Environment;
import freemarker.ext.util.WrapperTemplateModel;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
/**
* {@linkplain HtmlTplDashboardWidget}渲染器
* <p>
* 此类可渲染由{@linkplain DashboardWidgetResManager}管理模板的{@linkplain HtmlTplDashboardWidget}
* 其中{@linkplain HtmlTplDashboardWidget#getTemplate()}应该是可以通过{@linkplain DashboardWidgetResManager#getFile(String, String)}找到的模板文件名
* </p>
* <p>
* 此类需要手动调用{@linkplain #init()}方法进行初始化
* </p>
* <p>
* 支持的模板格式如下
* </p>
* <code>
* <pre>
* ...
* &lt;@import /&gt;
* ...
* &lt;@theme /&gt;
* ...
* &lt;@dashboard var="..." listener="..."&gt;
* ...
* <@chart widget="..." var="..." elementId="..." /&gt;
* ...
* <@chart widget="..." var="..." elementId="..." /&gt;
* ...
* &lt;/@dashboard&gt;
* </pre>
* </code>
* <p>
* &lt;@import /&gt;引入内置JSCSS等HTML资源
* </p>
* <p>
* &lt;@theme /&gt;引入内置CSS主题样式
* </p>
* <p>
* &lt;@dashboard&gt;定义看板var自定义看板JS变量名可不填listener自定义看板JS监听器可不填
* </p>
* <p>
* &lt;@chart
* /&gt;定义图表widget{@linkplain HtmlChartWidget#getId()}必填var自定义图表JS变量名可不填elementId自定义图表HTML元素ID可不填
* </p>
* 抽象{@linkplain HtmlTplDashboardWidget}渲染器
*
* @author datagear@163.com
*
* @param <T>
*/
public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
{
public static final String DIRECTIVE_IMPORT = "import";
public static final String DIRECTIVE_THEME = "theme";
public static final String DIRECTIVE_DASHBOARD = "dashboard";
public static final String DIRECTIVE_CHART = "chart";
public static final String DASHBOARD_ELEMENT_STYLE_NAME = "dashboard";
public static final String CHART_ELEMENT_WRAPPER_STYLE_NAME = "chart-wrapper";
public static final String DEFAULT_IMPORT_CONTEXT_PATH_PLACE_HOLDER = "$CONTEXTPATH";
public static final String DEFAULT_CONTEXT_PATH_PLACE_HOLDER = "$CONTEXTPATH";
protected static final String KEY_HTML_DASHBOARD_RENDER_DATA_MODEL = HtmlDashboardRenderDataModel.class
.getSimpleName();
@ -115,11 +49,11 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
protected static final String RENDER_ATTR_NAME_FOR_NOT_FOUND_SCRIPT = StringUtil
.firstLowerCase(Global.PRODUCT_NAME_EN) + "RenderValueForNotFound";
/** "@import"指令的输出内容 */
private String importContent;
/** 内置导入内容 */
private List<HtmlDashboardImport> htmlDashboardImports;
/** "@import"指令的输出内容需要替换的上下文路径占位符 */
private String importContentContextPathPlaceholder = DEFAULT_IMPORT_CONTEXT_PATH_PLACE_HOLDER;
/** 上下文路径占位符 */
private String contextPathPlaceholder = DEFAULT_CONTEXT_PATH_PLACE_HOLDER;
private DashboardWidgetResManager dashboardWidgetResManager;
@ -142,42 +76,37 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
/** 换行符 */
private String newLine = "\r\n";
private boolean ignoreDashboardStyleBorderWidth = true;
private Configuration _configuration;
public HtmlTplDashboardWidgetRenderer()
{
super();
}
public HtmlTplDashboardWidgetRenderer(String importContent, DashboardWidgetResManager dashboardWidgetResManager,
public HtmlTplDashboardWidgetRenderer(DashboardWidgetResManager dashboardWidgetResManager,
ChartWidgetSource chartWidgetSource)
{
super();
this.importContent = importContent;
this.dashboardWidgetResManager = dashboardWidgetResManager;
this.chartWidgetSource = chartWidgetSource;
}
public String getImportContent()
public List<HtmlDashboardImport> getHtmlDashboardImports()
{
return importContent;
return htmlDashboardImports;
}
public void setImportContent(String importContent)
public void setHtmlDashboardImports(List<HtmlDashboardImport> htmlDashboardImports)
{
this.importContent = importContent;
this.htmlDashboardImports = htmlDashboardImports;
}
public String getImportContentContextPathPlaceholder()
public String getContextPathPlaceholder()
{
return importContentContextPathPlaceholder;
return contextPathPlaceholder;
}
public void setImportContentContextPathPlaceholder(String importContentContextPathPlaceholder)
public void setContextPathPlaceholder(String contextPathPlaceholder)
{
this.importContentContextPathPlaceholder = importContentContextPathPlaceholder;
this.contextPathPlaceholder = contextPathPlaceholder;
}
public DashboardWidgetResManager getDashboardWidgetResManager()
@ -260,38 +189,6 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
this.newLine = newLine;
}
public boolean isIgnoreDashboardStyleBorderWidth()
{
return ignoreDashboardStyleBorderWidth;
}
public void setIgnoreDashboardStyleBorderWidth(boolean ignoreDashboardStyleBorderWidth)
{
this.ignoreDashboardStyleBorderWidth = ignoreDashboardStyleBorderWidth;
}
/**
* 初始化
*
* @throws IOException
*/
public void init() throws IOException
{
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
cfg.setDirectoryForTemplateLoading(this.dashboardWidgetResManager.getRootDirectory());
cfg.setDefaultEncoding(this.templateEncoding);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setSharedVariable(DIRECTIVE_IMPORT, new ImportTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_THEME, new ThemeTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_DASHBOARD, new DashboardTemplateDirectiveModel());
cfg.setSharedVariable(DIRECTIVE_CHART, new ChartTemplateDirectiveModel());
setConfiguration(cfg);
}
/**
* 渲染{@linkplain Dashboard}
*
@ -304,21 +201,15 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
{
inflateThemes(renderContext);
Template template = getTemplate(dashboardWidget);
HtmlDashboard dashboard = new HtmlDashboard();
dashboard.setId(IDUtil.uuid());
dashboard.setWidget(dashboardWidget);
dashboard.setRenderContext(renderContext);
dashboard.setCharts(new ArrayList<Chart>());
HtmlDashboardRenderDataModel dataModel = new HtmlDashboardRenderDataModel(dashboard,
renderContext.getContextPath());
HtmlDashboard dashboard = createHtmlDashboard(renderContext, dashboardWidget);
try
{
template.process(buildHtmlDashboardRenderDataModel(dataModel), renderContext.getWriter());
renderHtmlDashboard(renderContext, dashboard);
}
catch (RenderException e)
{
throw e;
}
catch (Throwable t)
{
@ -386,6 +277,52 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
}
}
/**
* 创建{@linkplain HtmlDashboard}
*
* @param renderContext
* @param dashboardWidget
* @return
*/
protected HtmlDashboard createHtmlDashboard(T renderContext, HtmlTplDashboardWidget<T> dashboardWidget)
{
HtmlDashboard dashboard = new HtmlDashboard();
dashboard.setId(IDUtil.uuid());
dashboard.setWidget(dashboardWidget);
dashboard.setRenderContext(renderContext);
dashboard.setCharts(new ArrayList<Chart>());
return dashboard;
}
/**
* 渲染{@linkplain Dashboard}
*
* @param renderContext
* @param dashboard
* @throws Exception
*/
protected abstract void renderHtmlDashboard(T renderContext, HtmlDashboard dashboard) throws Exception;
/**
* 获取{@linkplain HtmlTplDashboardWidget#getId()}的指定模板对象
*
* @param dashboardWidget
* @return
* @throws Exception
*/
protected Reader getTemplateReader(HtmlTplDashboardWidget<?> dashboardWidget) throws Exception
{
File templateFile = this.dashboardWidgetResManager.getFile(dashboardWidget.getId(),
dashboardWidget.getTemplate());
if (!templateFile.exists())
throw new RenderException("Dashboard template file not found");
return IOUtil.getReader(templateFile, getTemplateEncoding());
}
protected void inflateThemes(HtmlRenderContext renderContext)
{
RenderStyle renderStyle = HtmlRenderAttributes.getRenderStyle(renderContext);
@ -417,38 +354,6 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
}
}
/**
* 获取{@linkplain HtmlTplDashboardWidget#getId()}的指定模板对象
*
* @param dashboardWidget
* @return
* @throws RenderException
*/
protected Template getTemplate(HtmlTplDashboardWidget<T> dashboardWidget) throws RenderException
{
String path = this.dashboardWidgetResManager.getRelativePath(dashboardWidget.getId(),
dashboardWidget.getTemplate());
try
{
return getConfiguration().getTemplate(path);
}
catch (Throwable t)
{
throw new RenderException(t);
}
}
protected Configuration getConfiguration()
{
return _configuration;
}
protected void setConfiguration(Configuration _configuration)
{
this._configuration = _configuration;
}
/**
* 获取用于渲染指定ID图表的{@linkplain ChartWidget}
* <p>
@ -474,23 +379,47 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
return (HtmlChartWidget<HtmlRenderContext>) chartWidget;
}
protected Object buildHtmlDashboardRenderDataModel(HtmlDashboardRenderDataModel dataModel)
protected void writeHtmlDashboardScriptObject(Writer out, HtmlDashboard dashboard, boolean renderContextEmpty)
throws IOException
{
Map<String, Object> map = new HashMap<String, Object>();
map.put(KEY_HTML_DASHBOARD_RENDER_DATA_MODEL, dataModel);
return map;
getHtmlDashboardScriptObjectWriter().write(out, dashboard, renderContextEmpty);
}
protected HtmlDashboardRenderDataModel getHtmlDashboardRenderDataModel(Environment env)
throws TemplateModelException
protected void writeRenderContextScriptObject(Writer out, RenderContext renderContext) throws IOException
{
TemplateHashModel templateHashModel = env.getDataModel();
HtmlDashboardRenderDataModel dataModel = (HtmlDashboardRenderDataModel) templateHashModel
.get(KEY_HTML_DASHBOARD_RENDER_DATA_MODEL);
getHtmlDashboardScriptObjectWriter().writeRenderContext(out, renderContext, true);
}
return dataModel;
/**
* 写看板导入项
*
* @param renderContext
* @param dashboard
* @param importExclude
* @throws IOException
*/
protected void writeDashboardImport(HtmlRenderContext renderContext, HtmlDashboard dashboard, String importExclude)
throws IOException
{
if (this.htmlDashboardImports == null || this.htmlDashboardImports.isEmpty())
return;
Writer out = renderContext.getWriter();
List<String> excludes = StringUtil.splitWithTrim(importExclude, ",");
for (HtmlDashboardImport impt : this.htmlDashboardImports)
{
String name = impt.getName();
if (excludes.contains(name))
continue;
String content = replaceContextPathPlaceholder(impt.getContent(), renderContext.getContextPath());
writeNewLine(out);
out.write(content);
}
}
/**
@ -508,556 +437,39 @@ public class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext>
if (contextPath == null)
contextPath = "";
return str.replace(getImportContentContextPathPlaceholder(), contextPath);
return str.replace(getContextPathPlaceholder(), contextPath);
}
/**
* HTML看板渲染数据模型
* 写脚本开始标签
*
* @author datagear@163.com
*
* @param out
* @throws IOException
*/
protected static class HtmlDashboardRenderDataModel implements WrapperTemplateModel
protected void writeScriptStartTag(Writer out) throws IOException
{
private HtmlDashboard htmlDashboard;
private String contextPath = "";
public HtmlDashboardRenderDataModel()
{
super();
}
public HtmlDashboardRenderDataModel(HtmlDashboard htmlDashboard, String contextPath)
{
super();
this.htmlDashboard = htmlDashboard;
this.contextPath = contextPath;
}
public HtmlDashboard getHtmlDashboard()
{
return htmlDashboard;
}
public void setHtmlDashboard(HtmlDashboard htmlDashboard)
{
this.htmlDashboard = htmlDashboard;
}
public String getContextPath()
{
return contextPath;
}
public void setContextPath(String contextPath)
{
this.contextPath = contextPath;
}
@Override
public Object getWrappedObject()
{
return this.htmlDashboard;
}
}
protected abstract class AbstractTemplateDirectiveModel implements TemplateDirectiveModel
{
public AbstractTemplateDirectiveModel()
{
super();
}
/**
* 获取字符串参数值
*
* @param params
* @param key
* @return
* @throws TemplateModelException
*/
protected String getStringParamValue(Map<?, ?> params, String key) throws TemplateModelException
{
Object value = params.get(key);
if (value == null)
return null;
else if (value instanceof String)
return (String) value;
else if (value instanceof TemplateScalarModel)
return ((TemplateScalarModel) value).getAsString();
else
throw new TemplateModelException(
"Can not get string from [" + value.getClass().getName() + "] instance");
}
/**
* 写脚本开始标签
*
* @param out
* @throws IOException
*/
protected void writeScriptStartTag(Writer out) throws IOException
{
out.write("<script type=\"text/javascript\">");
}
/**
* 写脚本结束标签
*
* @param out
* @throws IOException
*/
protected void writeScriptEndTag(Writer out) throws IOException
{
out.write("</script>");
}
/**
* 写换行符
*
* @param out
* @throws IOException
*/
protected void writeNewLine(Writer out) throws IOException
{
out.write(getNewLine());
}
out.write("<script type=\"text/javascript\">");
}
/**
* @import指令
* 写脚本结束标签
*
* @author datagear@163.com
*
* @param out
* @throws IOException
*/
protected class ImportTemplateDirectiveModel extends AbstractTemplateDirectiveModel
protected void writeScriptEndTag(Writer out) throws IOException
{
public ImportTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
Writer out = env.getOut();
String importContent = getImportContent();
if (importContent == null)
importContent = "";
out.write("<meta charset=\"" + getWriterEncoding() + "\">");
if (!StringUtil.isEmpty(importContent))
{
importContent = replaceContextPathPlaceholder(importContent, dataModel.getContextPath());
writeNewLine(out);
out.write(importContent);
writeNewLine(out);
}
}
out.write("</script>");
}
/**
* @theme指令
* 写换行符
*
* @author datagear@163.com
*
* @param out
* @throws IOException
*/
protected class ThemeTemplateDirectiveModel extends AbstractTemplateDirectiveModel
protected void writeNewLine(Writer out) throws IOException
{
public ThemeTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlRenderContext renderContext = dataModel.getHtmlDashboard().getRenderContext();
Writer out = env.getOut();
DashboardTheme dashboardTheme = getDashboardTheme(renderContext);
writeDashboardTheme(out, dashboardTheme);
}
protected DashboardTheme getDashboardTheme(RenderContext renderContext)
{
DashboardTheme dashboardTheme = HtmlRenderAttributes.getDashboardTheme(renderContext);
return dashboardTheme;
}
protected void writeDashboardTheme(Writer out, DashboardTheme dashboardTheme) throws IOException
{
ChartTheme chartTheme = (dashboardTheme == null ? null : dashboardTheme.getChartTheme());
out.write("<style type=\"text/css\">");
writeNewLine(out);
out.write("body{");
writeNewLine(out);
out.write(" padding: 0px 0px;");
writeNewLine(out);
out.write(" margin: 0px 0px;");
writeNewLine(out);
if (dashboardTheme != null)
{
out.write(" background-color: " + dashboardTheme.getBackgroundColor() + ";");
writeNewLine(out);
out.write(" color: " + dashboardTheme.getForegroundColor() + ";");
writeNewLine(out);
}
out.write("}");
writeNewLine(out);
out.write("." + DASHBOARD_ELEMENT_STYLE_NAME + "{");
writeNewLine(out);
writeThemeCssAttrs(out, dashboardTheme);
writeBorderBoxCssAttrs(out);
if (isIgnoreDashboardStyleBorderWidth())
{
out.write(" border-width: 0px;");
writeNewLine(out);
}
out.write("}");
writeNewLine(out);
out.write("." + CHART_ELEMENT_WRAPPER_STYLE_NAME + "{");
writeNewLine(out);
out.write(" position: relative;");
writeNewLine(out);
writeThemeCssAttrs(out, chartTheme);
writeBorderBoxCssAttrs(out);
out.write("}");
writeNewLine(out);
out.write("." + HtmlChartPlugin.BUILTIN_CHART_ELEMENT_STYLE_NAME + "{");
writeNewLine(out);
writeFillParentCssAttrs(out);
writeBorderBoxCssAttrs(out);
out.write("}");
writeNewLine(out);
out.write("</style>");
writeNewLine(out);
}
protected void writeThemeCssAttrs(Writer out, Theme theme) throws IOException
{
if (theme != null)
{
String borderWidth = theme.getBorderWidth();
if (borderWidth == null)
borderWidth = "0";
out.write(" color: " + theme.getForegroundColor() + ";");
writeNewLine(out);
out.write(" background-color: " + theme.getBackgroundColor() + ";");
writeNewLine(out);
out.write(" border-color: " + theme.getBorderColor() + ";");
writeNewLine(out);
out.write(" border-width: " + theme.getBorderWidth() + ";");
writeNewLine(out);
out.write(" border-style: solid;");
writeNewLine(out);
}
}
protected void writeFillParentCssAttrs(Writer out) throws IOException
{
out.write(" position: absolute;");
writeNewLine(out);
out.write(" top: 0px;");
writeNewLine(out);
out.write(" bottom: 0px;");
writeNewLine(out);
out.write(" left: 0px;");
writeNewLine(out);
out.write(" right: 0px;");
writeNewLine(out);
}
protected void writeBorderBoxCssAttrs(Writer out) throws IOException
{
out.write(" box-sizing: border-box;");
writeNewLine(out);
out.write(" -moz-box-sizing: border-box;");
writeNewLine(out);
out.write(" -webkit-box-sizing: border-box;");
writeNewLine(out);
}
}
/**
* @dashboard指令
*
* @author datagear@163.com
*
*/
protected class DashboardTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public DashboardTemplateDirectiveModel()
{
super();
}
@SuppressWarnings("rawtypes")
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
String varName = getStringParamValue(params, "var");
String listener = getStringParamValue(params, "listener");
boolean hasListener = !StringUtil.isEmpty(listener);
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlDashboard dashboard = dataModel.getHtmlDashboard();
HtmlRenderContext renderContext = dashboard.getRenderContext();
int nextSequence = -1;
if (StringUtil.isEmpty(varName))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
varName = HtmlRenderAttributes.generateDashboardVarName(nextSequence);
}
dashboard.setVarName(varName);
Writer out = env.getOut();
writeScriptStartTag(out);
writeNewLine(out);
out.write("var ");
out.write(varName);
out.write("=");
writeNewLine(out);
writeHtmlDashboardScriptObject(out, dashboard, true);
out.write(";");
writeNewLine(out);
writeScriptEndTag(out);
writeNewLine(out);
HtmlRenderAttributes.setChartRenderContextVarName(renderContext, varName + ".renderContext");
if (body != null)
body.render(out);
writeScriptStartTag(out);
writeNewLine(out);
String tmpRenderContextVar = HtmlRenderAttributes.generateRenderContextVarName(nextSequence);
// 移除内部设置的属性
HtmlRenderAttributes.removeChartRenderContextVarName(renderContext);
HtmlRenderAttributes.removeChartNotRenderScriptTag(renderContext);
HtmlRenderAttributes.removeChartScriptNotInvokeRender(renderContext);
HtmlRenderAttributes.removeChartVarName(renderContext);
HtmlRenderAttributes.removeChartElementId(renderContext);
renderContext.removeAttribute(RENDER_ATTR_NAME_FOR_NOT_FOUND_SCRIPT);
out.write("var ");
out.write(tmpRenderContextVar);
out.write("=");
writeNewLine(out);
writeRenderContextScriptObject(out, renderContext);
out.write(";");
writeNewLine(out);
out.write(varName + ".renderContext.attributes = " + tmpRenderContextVar + ".attributes;");
writeNewLine(out);
List<? extends HtmlChart> charts = dashboard.getCharts();
if (charts != null)
{
for (HtmlChart chart : charts)
{
out.write(varName + ".charts.push(" + chart.getVarName() + ");");
writeNewLine(out);
}
}
out.write(varName + ".render = function(){");
writeNewLine(out);
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].render(); }");
writeNewLine(out);
out.write("};");
writeNewLine(out);
out.write(varName + ".update = function(){");
writeNewLine(out);
out.write(" for(var i=0; i<this.charts.length; i++){ this.charts[i].update(); }");
writeNewLine(out);
out.write("};");
writeNewLine(out);
if (hasListener)
{
out.write(varName + ".listener = window[\"" + listener + "\"];");
writeNewLine(out);
}
out.write("window.onload = function(){");
writeNewLine(out);
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.beforeRender)");
writeNewLine(out);
out.write(" " + varName + ".listener.beforeRender(" + varName + "); ");
writeNewLine(out);
}
out.write(varName + ".render();");
writeNewLine(out);
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.afterRender)");
writeNewLine(out);
out.write(" " + varName + ".listener.afterRender(" + varName + "); ");
writeNewLine(out);
}
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.beforeUpdate)");
writeNewLine(out);
out.write(" " + varName + ".listener.beforeUpdate(" + varName + "); ");
writeNewLine(out);
}
out.write(varName + ".update();");
writeNewLine(out);
if (hasListener)
{
out.write("if(" + varName + ".listener && " + varName + ".listener.afterUpdate)");
writeNewLine(out);
out.write(" " + varName + ".listener.afterUpdate(" + varName + "); ");
writeNewLine(out);
}
out.write("};");
writeNewLine(out);
writeScriptEndTag(out);
writeNewLine(out);
}
protected void writeHtmlDashboardScriptObject(Writer out, HtmlDashboard dashboard, boolean renderContextEmpty)
throws IOException
{
getHtmlDashboardScriptObjectWriter().write(out, dashboard, renderContextEmpty);
}
protected void writeRenderContextScriptObject(Writer out, RenderContext renderContext) throws IOException
{
getHtmlDashboardScriptObjectWriter().writeRenderContext(out, renderContext, true);
}
}
/**
* @chart指令
*
* @author datagear@163.com
*
*/
protected class ChartTemplateDirectiveModel extends AbstractTemplateDirectiveModel
{
public ChartTemplateDirectiveModel()
{
super();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws TemplateException, IOException
{
String widget = getStringParamValue(params, "widget");
String var = getStringParamValue(params, "var");
String elementId = getStringParamValue(params, "elementId");
HtmlDashboardRenderDataModel dataModel = getHtmlDashboardRenderDataModel(env);
HtmlDashboard htmlDashboard = dataModel.getHtmlDashboard();
HtmlRenderContext renderContext = htmlDashboard.getRenderContext();
int nextSequence = -1;
HtmlChartWidget<HtmlRenderContext> chartWidget = getHtmlChartWidgetForRender(renderContext, widget);
if (StringUtil.isEmpty(var))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
var = HtmlRenderAttributes.generateChartVarName(nextSequence);
}
if (StringUtil.isEmpty(elementId))
{
nextSequence = HtmlRenderAttributes.getNextSequenceIfNot(renderContext, nextSequence);
elementId = HtmlRenderAttributes.generateChartElementId(nextSequence);
}
HtmlRenderAttributes.setChartNotRenderScriptTag(renderContext, false);
HtmlRenderAttributes.setChartScriptNotInvokeRender(renderContext, true);
HtmlRenderAttributes.setChartVarName(renderContext, var);
HtmlRenderAttributes.setChartElementId(renderContext, elementId);
HtmlChart chart = chartWidget.render(renderContext);
List<HtmlChart> charts = (List<HtmlChart>) htmlDashboard.getCharts();
if (charts == null)
{
charts = new ArrayList<HtmlChart>();
htmlDashboard.setCharts(charts);
}
charts.add(chart);
}
/**
* 写脚本开始标签
*
* @param out
* @throws IOException
*/
@Override
protected void writeScriptStartTag(Writer out) throws IOException
{
out.write("<script type=\"text/javascript\">");
}
/**
* 写脚本结束标签
*
* @param out
* @throws IOException
*/
@Override
protected void writeScriptEndTag(Writer out) throws IOException
{
out.write("</script>");
}
/**
* 写换行符
*
* @param out
* @throws IOException
*/
@Override
protected void writeNewLine(Writer out) throws IOException
{
out.write(getNewLine());
}
out.write(getNewLine());
}
}

View File

@ -17,16 +17,16 @@ import org.junit.Assert;
import org.junit.Test;
/**
* {@linkplain HtmlTplDashboardWidget}单元测试类
* {@linkplain HtmlTplDashboardWidgetFmkRenderer}单元测试类
*
* @author datagear@163.com
*
*/
public class HtmlTplDashboardWidgetTest
public class HtmlTplDashboardWidgetFmkRendererTest
{
private HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget;
private HtmlTplDashboardWidgetFmkRenderer<HtmlRenderContext> renderer;
public HtmlTplDashboardWidgetTest() throws Exception
public HtmlTplDashboardWidgetFmkRendererTest() throws Exception
{
super();
@ -36,27 +36,24 @@ public class HtmlTplDashboardWidgetTest
chartPlugin, (DataSetFactory[]) null);
DashboardWidgetResManager resManager = new DashboardWidgetResManager(
"src/test/resources/org/datagear/analysis/support/html/htmlTplDashboardWidgets");
"src/test/resources/org/datagear/analysis/support/html/htmlTplDashboardWidgets/freemarker");
SimpleChartWidgetSource chartWidgetSource = new SimpleChartWidgetSource(htmlChartWidget);
HtmlTplDashboardWidgetRenderer<HtmlRenderContext> renderer = new HtmlTplDashboardWidgetRenderer<HtmlRenderContext>(
"<script type='text/javascript' src='static/js/jquery.js'></script>", resManager, chartWidgetSource);
renderer.init();
HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget = new HtmlTplDashboardWidget<HtmlRenderContext>(
"widget01", "index.html", renderer);
this.dashboardWidget = dashboardWidget;
this.renderer = new HtmlTplDashboardWidgetFmkRenderer<HtmlRenderContext>(resManager, chartWidgetSource);
this.renderer.init();
}
@Test
public void renderTest()
{
HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget = new HtmlTplDashboardWidget<HtmlRenderContext>(
"widget01", "index.html", this.renderer);
StringWriter stringWriter = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(stringWriter);
HtmlRenderAttributes.setRenderStyle(renderContext, RenderStyle.DARK);
HtmlDashboard dashboard = this.dashboardWidget.render(renderContext);
HtmlDashboard dashboard = dashboardWidget.render(renderContext);
String html = stringWriter.toString();

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.datagear.analysis.DataSetFactory;
import org.datagear.analysis.RenderStyle;
import org.datagear.analysis.support.DashboardWidgetResManager;
import org.datagear.analysis.support.SimpleChartWidgetSource;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetHtmlRenderer.ChartInfo;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetHtmlRenderer.DashboardInfo;
import org.datagear.util.IOUtil;
import org.junit.Assert;
import org.junit.Test;
/**
* {@linkplain HtmlTplDashboardWidgetHtmlRenderer}单元测试类
*
* @author datagear@163.com
*
*/
public class HtmlTplDashboardWidgetHtmlRendererTest
{
private HtmlTplDashboardWidgetHtmlRenderer<HtmlRenderContext> renderer;
protected static final String IMPORT_CONTENT_JQUERY = "<script type=\"text/javascript\" src=\"jquery.js\"></script>";
protected static final String IMPORT_CONTENT_UTIL = "<script type=\"text/javascript\" src=\"util.js\"></script>";
protected static final String IMPORT_CONTENT_THEME = "<link rel=\"stylesheet\" type=\"text/css\" href=\"theme.css\">";
protected static final String IMPORT_CONTENT_STYLE = "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">";
public HtmlTplDashboardWidgetHtmlRendererTest() throws Exception
{
super();
HtmlChartPlugin<HtmlRenderContext> chartPlugin = HtmlChartPluginTest.createHtmlChartPlugin();
HtmlChartWidget<HtmlRenderContext> htmlChartWidget = new HtmlChartWidget<HtmlRenderContext>("chart-widget-01",
chartPlugin, (DataSetFactory[]) null);
DashboardWidgetResManager resManager = new DashboardWidgetResManager(
"src/test/resources/org/datagear/analysis/support/html/htmlTplDashboardWidgets/html");
SimpleChartWidgetSource chartWidgetSource = new SimpleChartWidgetSource(htmlChartWidget);
List<HtmlDashboardImport> htmlDashboardImports = new ArrayList<HtmlDashboardImport>();
htmlDashboardImports.add(new HtmlDashboardImport("jquery", IMPORT_CONTENT_JQUERY));
htmlDashboardImports.add(new HtmlDashboardImport("util", IMPORT_CONTENT_UTIL));
htmlDashboardImports.add(new HtmlDashboardImport("theme", IMPORT_CONTENT_THEME));
htmlDashboardImports.add(new HtmlDashboardImport("style", IMPORT_CONTENT_STYLE));
this.renderer = new HtmlTplDashboardWidgetHtmlRenderer<HtmlRenderContext>(resManager, chartWidgetSource);
this.renderer.setHtmlDashboardImports(htmlDashboardImports);
}
@Test
public void renderHtmlDashboardTest() throws Exception
{
HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget = createHtmlTplDashboardWidget();
// 看板属性双引号
{
String template = "<html dg-dashboard-var=\"myDashboard\" dg-dashboard-listener=\"myListener\" "
+ " dg-dashboard-import-exclude=\"jquery\"><head></head><body></body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = out.toString();
Assert.assertEquals("myDashboard", dashboardInfo.getDashboardVar());
Assert.assertEquals("myListener", dashboardInfo.getListenerVar());
Assert.assertEquals("jquery", dashboardInfo.getImportExclude());
Assert.assertFalse(html.contains(IMPORT_CONTENT_JQUERY));
Assert.assertTrue(html.contains(IMPORT_CONTENT_UTIL));
Assert.assertTrue(html.contains(IMPORT_CONTENT_THEME));
Assert.assertTrue(html.contains(IMPORT_CONTENT_STYLE));
Assert.assertTrue(html.contains("var myDashboard"));
Assert.assertTrue(html.contains("myDashboard.listener = window[\"myListener\"];"));
}
// 看板属性无引号
{
String template = "<html dg-dashboard-var=myDashboard dg-dashboard-listener=myListener "
+ " dg-dashboard-import-exclude=jquery><head></head><body></body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = getHtmlWithPrint(out);
Assert.assertEquals("myDashboard", dashboardInfo.getDashboardVar());
Assert.assertEquals("myListener", dashboardInfo.getListenerVar());
Assert.assertEquals("jquery", dashboardInfo.getImportExclude());
Assert.assertFalse(html.contains(IMPORT_CONTENT_JQUERY));
Assert.assertTrue(html.contains(IMPORT_CONTENT_UTIL));
Assert.assertTrue(html.contains(IMPORT_CONTENT_THEME));
Assert.assertTrue(html.contains(IMPORT_CONTENT_STYLE));
Assert.assertTrue(html.contains("var myDashboard"));
Assert.assertTrue(html.contains("myDashboard.listener = window[\"myListener\"];"));
}
// 看板属性单引号
{
String template = "<html dg-dashboard-var='myDashboard' dg-dashboard-listener='myListener' "
+ " dg-dashboard-import-exclude='jquery'><head></head><body></body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = getHtmlWithPrint(out);
Assert.assertEquals("myDashboard", dashboardInfo.getDashboardVar());
Assert.assertEquals("myListener", dashboardInfo.getListenerVar());
Assert.assertEquals("jquery", dashboardInfo.getImportExclude());
Assert.assertFalse(html.contains(IMPORT_CONTENT_JQUERY));
Assert.assertTrue(html.contains(IMPORT_CONTENT_UTIL));
Assert.assertTrue(html.contains(IMPORT_CONTENT_THEME));
Assert.assertTrue(html.contains(IMPORT_CONTENT_STYLE));
Assert.assertTrue(html.contains("var myDashboard"));
Assert.assertTrue(html.contains("myDashboard.listener = window[\"myListener\"];"));
}
// 看板属性多个导入排除值
{
String template = "<html dg-dashboard-var='myDashboard' dg-dashboard-listener='myListener' "
+ " dg-dashboard-import-exclude='jquery,theme, style '><head></head><body></body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = getHtmlWithPrint(out);
Assert.assertEquals("myDashboard", dashboardInfo.getDashboardVar());
Assert.assertEquals("myListener", dashboardInfo.getListenerVar());
Assert.assertEquals("jquery,theme, style", dashboardInfo.getImportExclude());
Assert.assertFalse(html.contains(IMPORT_CONTENT_JQUERY));
Assert.assertTrue(html.contains(IMPORT_CONTENT_UTIL));
Assert.assertFalse(html.contains(IMPORT_CONTENT_THEME));
Assert.assertFalse(html.contains(IMPORT_CONTENT_STYLE));
Assert.assertTrue(html.contains("var myDashboard"));
Assert.assertTrue(html.contains("myDashboard.listener = window[\"myListener\"];"));
}
// 看板属性默认
{
String template = "<html><head></head><body></body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = getHtmlWithPrint(out);
Assert.assertNull(dashboardInfo.getDashboardVar());
Assert.assertNull(dashboardInfo.getListenerVar());
Assert.assertNull(dashboardInfo.getImportExclude());
Assert.assertTrue(html.contains(IMPORT_CONTENT_JQUERY));
Assert.assertTrue(html.contains(IMPORT_CONTENT_UTIL));
Assert.assertTrue(html.contains(IMPORT_CONTENT_THEME));
Assert.assertTrue(html.contains(IMPORT_CONTENT_STYLE));
Assert.assertTrue(html.contains("var dataGearDashboard1"));
Assert.assertFalse(html.contains("dataGearDashboard1.listener = window[\""));
}
// 图表属性
{
String template = "<html><head></head><body>" + "\r\n"
+ "<div id=\"element_1\" dg-chart-widget=\"chartwidget_1\" dg-chart-var=\"chartvar_1\"></div>"
+ "\r\n" + "<div id='element_2' dg-chart-widget='chartwidget_2' dg-chart-var='chartvar_2'></div>"
+ "\r\n" + "<div id=element_3 dg-chart-widget=chartwidget_3 dg-chart-var=chartvar_3></div>" + "\r\n"
+ "<div sdf abc def 12345677788 // >"
//
+ "\r\n"
+ "<div id=element_4 dg-chart-widget=chartwidget_4 dg-chart-var=chartvar_4 ></div>"
+ "\r\n"
+ "<div id = element_5 dg-chart-widget= chartwidget_5 dg-chart-var =chartvar_5/>"
+ "\r\n" + "<div id=element_6 dg-chart-widget=chartwidget_6 dg-chart-var=chartvar_6 />"
+ "\r\n" + "<div id=element_7 dg-chart-widget=chartwidget_7 dg-chart-var=chartvar_7 / >"
+ "\r\n" + "<div dg-chart-widget=chartwidget_8 / >"
//
+ "\r\n" + "<div dg-chart-widget=chartwidget_9/>"
//
+ "\r\n" + "<div dg-chart-widget=/>"
//
+ "\r\n" + "<div dg-chart-widget= />"
//
+ "\r\n" + "</body></html>";
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlDashboard dashboard = this.renderer.createHtmlDashboard(renderContext, dashboardWidget);
DashboardInfo dashboardInfo = this.renderer.renderHtmlDashboard(renderContext, dashboard,
IOUtil.getReader(template));
String html = getHtmlWithPrint(out);
List<ChartInfo> chartInfos = dashboardInfo.getChartInfos();
Assert.assertEquals(9, chartInfos.size());
for (int i = 0; i < 7; i++)
{
ChartInfo chartInfo = chartInfos.get(i);
Assert.assertEquals("element_" + (i + 1), chartInfo.getElementId());
Assert.assertEquals("chartwidget_" + (i + 1), chartInfo.getWidgetId());
Assert.assertEquals("chartvar_" + (i + 1), chartInfo.getChartVar());
}
Assert.assertTrue(html.contains("<html><head>"));
Assert.assertTrue(html.contains("</head><body>"));
Assert.assertTrue(html.contains(
"<div id=\"element_1\" dg-chart-widget=\"chartwidget_1\" dg-chart-var=\"chartvar_1\"></div>"));
Assert.assertTrue(html
.contains("<div id='element_2' dg-chart-widget='chartwidget_2' dg-chart-var='chartvar_2'></div>"));
Assert.assertTrue(
html.contains("<div id=element_3 dg-chart-widget=chartwidget_3 dg-chart-var=chartvar_3></div>"));
Assert.assertTrue(html.contains("<div sdf abc def 12345677788 // >"));
Assert.assertTrue(html.contains(
"<div id=element_4 dg-chart-widget=chartwidget_4 dg-chart-var=chartvar_4 ></div>"));
Assert.assertTrue(html.contains(
"<div id = element_5 dg-chart-widget= chartwidget_5 dg-chart-var =chartvar_5/>"));
Assert.assertTrue(html
.contains("<div id=element_6 dg-chart-widget=chartwidget_6 dg-chart-var=chartvar_6 />"));
Assert.assertTrue(html
.contains("<div id=element_7 dg-chart-widget=chartwidget_7 dg-chart-var=chartvar_7 / >"));
Assert.assertTrue(
html.contains("<div dg-chart-widget=chartwidget_8 id=\"dataGearChartElement1\" / >"));
Assert.assertTrue(html.contains("<div dg-chart-widget=chartwidget_9 id=\"dataGearChartElement2\" />"));
Assert.assertTrue(html.contains("<div dg-chart-widget=/>"));
Assert.assertTrue(html.contains("<div dg-chart-widget= />"));
Assert.assertTrue(html.contains("</body></html>"));
for (int i = 0; i < 7; i++)
Assert.assertTrue(html.contains("var chartvar_" + (i + 1)));
Assert.assertTrue(html.contains("var dataGearChart4"));
Assert.assertTrue(html.contains("var dataGearChart5"));
}
}
@Test
public void renderTest() throws Exception
{
HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget = createHtmlTplDashboardWidget();
StringWriter out = new StringWriter();
DefaultHtmlRenderContext renderContext = new DefaultHtmlRenderContext(out);
HtmlRenderAttributes.setRenderStyle(renderContext, RenderStyle.DARK);
HtmlDashboard dashboard = dashboardWidget.render(renderContext);
getHtmlWithPrint(out);
Assert.assertEquals(6, dashboard.getCharts().size());
}
protected HtmlTplDashboardWidget<HtmlRenderContext> createHtmlTplDashboardWidget()
{
HtmlTplDashboardWidget<HtmlRenderContext> dashboardWidget = new HtmlTplDashboardWidget<HtmlRenderContext>(
"widget01", "index.html", this.renderer);
return dashboardWidget;
}
protected String getHtmlWithPrint(StringWriter out)
{
String html = out.toString();
System.out.println(html);
System.out.println("");
System.out.println("-----------------------");
System.out.println("");
return html;
}
}

View File

@ -14,29 +14,16 @@
<script type="text/javascript">
var myListener =
{
beforeRender : function(dashboard)
onRender : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML = "<div>beforeRender</div>";
element.innerHTML += "<div>onRender</div>";
},
afterRender : function(dashboard)
onUpdate : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML += "<div>afterRender</div>";
},
beforeUpdate : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML += "<div>beforeUpdate</div>";
},
afterUpdate : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML += "<div>afterUpdate</div>";
element.innerHTML += "<div>onUpdate</div>";
}
};
</script>

View File

@ -0,0 +1,36 @@
<!doctype html>
<html dg-dashboard-var="myDashboard" dg-dashboard-listener="myListener" dg-dashboard-import-exclude="jquery,theme">
<head>
<script type="text/javascript">
var myListener =
{
onRender : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML += "<div>onRender</div>";
},
onUpdate : function(dashboard)
{
var element = document.getElementById("listener");
element.innerHTML += "<div>onUpdate</div>";
}
};
</script>
</head>
<body>
<div dg-chart-widget="chart-widget-01"></div>
<div id="element_1" dg-chart-widget="chart-widget-01" dg-chart-var="chartvar_01" ></div>
<div dg-chart-widget="chart-widget-03"></div>
<div id="element_2" dg-chart-widget="chart-widget-01" ></div>
<div dg-chart-widget="chart-widget-05"></div>
<div dg-chart-widget="chart-widget-01" dg-chart-var="chartvar_02"></div>
<div id="listener"></div>
</body>
</html>

View File

@ -11,7 +11,7 @@ import java.util.Date;
import org.datagear.analysis.support.html.HtmlRenderContext;
import org.datagear.analysis.support.html.HtmlTplDashboardWidget;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetRenderer;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetFmkRenderer;
/**
* {@linkplain HtmlTplDashboardWidget}实体
@ -48,7 +48,7 @@ public class HtmlTplDashboardWidgetEntity extends HtmlTplDashboardWidget<HtmlRen
}
public HtmlTplDashboardWidgetEntity(String id, String template,
HtmlTplDashboardWidgetRenderer<HtmlRenderContext> renderer, String name, User createUser)
HtmlTplDashboardWidgetFmkRenderer<HtmlRenderContext> renderer, String name, User createUser)
{
super(id, template, renderer);
this.name = name;

View File

@ -13,6 +13,7 @@ import java.util.Map;
import org.apache.ibatis.session.SqlSessionFactory;
import org.datagear.analysis.support.html.HtmlRenderContext;
import org.datagear.analysis.support.html.HtmlTplDashboardWidget;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetFmkRenderer;
import org.datagear.analysis.support.html.HtmlTplDashboardWidgetRenderer;
import org.datagear.management.domain.HtmlChartWidgetEntity;
import org.datagear.management.domain.HtmlTplDashboardWidgetEntity;
@ -49,7 +50,7 @@ public class HtmlTplDashboardWidgetEntityServiceImpl
AuthorizationService authorizationService)
{
super(sqlSessionFactory);
this.htmlTplDashboardWidgetRenderer = (HtmlTplDashboardWidgetRenderer<HtmlRenderContext>) htmlTplDashboardWidgetRenderer;
this.htmlTplDashboardWidgetRenderer = (HtmlTplDashboardWidgetFmkRenderer<HtmlRenderContext>) htmlTplDashboardWidgetRenderer;
this.authorizationService = authorizationService;
}
@ -59,7 +60,7 @@ public class HtmlTplDashboardWidgetEntityServiceImpl
AuthorizationService authorizationService)
{
super(sqlSessionTemplate);
this.htmlTplDashboardWidgetRenderer = (HtmlTplDashboardWidgetRenderer<HtmlRenderContext>) htmlTplDashboardWidgetRenderer;
this.htmlTplDashboardWidgetRenderer = (HtmlTplDashboardWidgetFmkRenderer<HtmlRenderContext>) htmlTplDashboardWidgetRenderer;
this.authorizationService = authorizationService;
}

View File

@ -20,6 +20,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
@ -335,6 +336,17 @@ public class IOUtil
return new BufferedReader(new InputStreamReader(in, encoding));
}
/**
* 获取输入流
*
* @param s
* @return
*/
public static StringReader getReader(String s)
{
return new StringReader(s);
}
/**
* 获取输出流
*

View File

@ -7,7 +7,10 @@
*/
package org.datagear.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
@ -187,4 +190,28 @@ public class StringUtil
return sb.toString();
}
/**
* 拆分字符串并删除元素两边的空格
* <p>
* 如果{@code s}{@code null}返回空列表
* </p>
*
* @param str
* @param splitter
* @return
*/
@SuppressWarnings("unchecked")
public static List<String> splitWithTrim(String str, String splitter)
{
if (str == null)
return Collections.EMPTY_LIST;
String[] strs = str.split(splitter);
for (int i = 0; i < strs.length; i++)
strs[i] = strs[i].trim();
return Arrays.asList(strs);
}
}

View File

@ -336,8 +336,15 @@
<property name="rootDirectory" ref="dashboardRootDirectory" />
</bean>
<bean id="htmlTplDashboardWidgetRenderer" class="org.datagear.analysis.support.html.HtmlTplDashboardWidgetRenderer" init-method="init">
<property name="importContent" value="&lt;script type='text/javascript' src='$CONTEXTPATH/static/script/jquery/jquery-1.12.4.js' &gt;&lt;/script&gt;" />
<bean id="htmlTplDashboardWidgetRenderer" class="org.datagear.analysis.support.html.HtmlTplDashboardWidgetHtmlRenderer">
<property name="htmlDashboardImports">
<list>
<bean class="org.datagear.analysis.support.html.HtmlDashboardImport">
<property name="name" value="jquery" />
<property name="content" value="&lt;script type='text/javascript' src='$CONTEXTPATH/static/script/jquery/jquery-1.12.4.js' &gt;&lt;/script&gt;" />
</bean>
</list>
</property>
<property name="dashboardWidgetResManager" ref="dashboardWidgetResManager" />
<property name="chartWidgetSource" ref="htmlChartWidgetEntityService" />
</bean>