package com.xcong.farmer.cms.core.node;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.date.DatePattern;
|
import cn.hutool.core.date.DateTime;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.alibaba.fastjson.JSONObject;
|
import com.xcong.farmer.cms.core.handler.DataParserHandler;
|
import com.xcong.farmer.cms.core.tag.TagsEnum;
|
import com.xcong.farmer.cms.core.tag.model.TimeTag;
|
import com.xcong.farmer.cms.core.template.Configuration;
|
import com.xcong.farmer.cms.core.template.TemplateConfiguration;
|
import com.xcong.farmer.cms.utils.GroovySingleton;
|
import groovy.lang.Binding;
|
import groovy.lang.GroovyShell;
|
import groovy.lang.Script;
|
import org.apache.commons.text.StringSubstitutor;
|
import org.jsoup.nodes.Attribute;
|
import org.jsoup.nodes.Attributes;
|
import org.jsoup.nodes.Element;
|
import org.jsoup.select.Elements;
|
|
import java.time.format.DateTimeFormatter;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.Map;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
public class AttrNode extends Configuration {
|
private String tag;
|
|
public TagsEnum tagsEnum;
|
// tag标签中field字段的值 如 field=art 中的 art
|
private String field;
|
// 标签数据 如@artilces从数据库查询到的数据
|
private Object data;
|
// 用于给这个标签attr注入的数据
|
private Map<String, Object> parserData;
|
private Map<String, Object> systemData;
|
|
// Tag参数 {id=[1,2,3], page=1, limit=5, field=art}
|
private Object param;
|
|
private Element element;
|
private Element originalElement;
|
private boolean processContinue = true;
|
|
public AttrNode() {
|
}
|
|
public AttrNode(Element element) {
|
this.element = element.clone();
|
this.originalElement = element;
|
}
|
|
public AttrNode(Element element, Map<String, Object> parserData) {
|
this.element = element.clone();
|
this.originalElement = element;
|
this.parserData = parserData;
|
}
|
|
private boolean isNeedEmpty() {
|
Elements children = this.element.children();
|
if (CollUtil.isNotEmpty(children)) {
|
return true;
|
}
|
Attributes attributes = this.element.attributes();
|
if (CollUtil.isEmpty(attributes)) {
|
return false;
|
}
|
|
for (Attribute attribute : attributes) {
|
if (attribute.getKey().contains("@") || attribute.getKey().contains("$")) {
|
return true;
|
}
|
}
|
return false;
|
}
|
|
public void staticPath() {
|
// 设置img的链接访问
|
if ("img".equals(this.element.tagName())) {
|
String src = this.element.attr("src");
|
if (StrUtil.isNotBlank(STATIC_URL)) {
|
this.element.attr("src", STATIC_URL + src);
|
}
|
}
|
|
if ("link".equals(this.element.tagName())) {
|
String src = this.element.attr("href");
|
if (StrUtil.isNotBlank(STATIC_URL)) {
|
this.element.attr("href", STATIC_URL + src);
|
}
|
}
|
|
if ("script".equals(this.element.tagName())) {
|
String src = this.element.attr("src");
|
if (StrUtil.isNotBlank(STATIC_URL)) {
|
this.element.attr("src", STATIC_URL + src);
|
}
|
}
|
}
|
|
public void parser() {
|
staticPath();
|
// 判断是否为最小节点,如果是且没有特殊标签,则跳过清空
|
if (!isNeedEmpty()) {
|
return;
|
}
|
|
this.element.empty();
|
Attributes attributes = this.element.attributes();
|
if (attributes.isEmpty()) {
|
return;
|
}
|
|
// i = 1表示每个element上最多有一个tag
|
int i = 1;
|
|
// 判断element中是否包含tag,若有,则解析并查询对应数据
|
for (TagsEnum tagsEnum : TagsEnum.values()) {
|
if (!attributes.hasKey(tagsEnum.getName())) {
|
continue;
|
}
|
if (i > 1) {
|
throw new RuntimeException("element most one tag");
|
}
|
i++;
|
|
try {
|
Template.TAGS.add(tagsEnum.getName());
|
// {id=${col.id}, page=1, limit=5, field=art} ${col.id} 形式需先设置值
|
String tagValue = attributes.get(tagsEnum.getName());
|
tagValue = attrValueFormat(tagValue);
|
|
this.param = parserTag(tagValue, Class.forName(tagsEnum.getClassName()));
|
|
this.field = JSONObject.parseObject(JSONObject.toJSONString(param)).getString("field");
|
this.tagsEnum = tagsEnum;
|
|
DataParserHandler handler = (DataParserHandler) Class.forName(tagsEnum.getHandler()).newInstance();
|
handler.dataParser(this);
|
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
e.printStackTrace();
|
}
|
|
this.tag = tagsEnum.getName();
|
if (this.data == null) {
|
this.processContinue = false;
|
}
|
}
|
|
|
runDataInject();
|
}
|
|
public void runDataInject() {
|
Attributes attributes = this.element.attributes();
|
for (Attribute attribute : attributes) {
|
if (attribute.getKey().startsWith("\\$")) {
|
Template.TAGS.add(attribute.getKey());
|
}
|
|
String key = attribute.getKey().replaceAll("\\$", "");
|
String value = attribute.getValue();
|
|
String result = attrValueFormat(value);
|
// @{} 为java表达式; ${}为需要注入的数据项
|
if (value.startsWith("@{")) {
|
value = result.replaceAll("\\@\\{", "").replaceAll("}", "");
|
Binding binding = new Binding();
|
for (Map.Entry<String, Object> entry : this.parserData.entrySet()) {
|
String fieldKey = entry.getKey();
|
Map<String, Object> data = (Map<String, Object>) entry.getValue();
|
binding.setProperty(fieldKey, data.get("state"));
|
int index = (int) data.get("index");
|
binding.setVariable( "index", index);
|
}
|
GroovyShell shell = new GroovyShell(binding);
|
String evaluate = (String) shell.evaluate(value);
|
|
this.element.removeAttr("class");
|
this.element.attr("class", evaluate);
|
} else if (value.contains( "${")) {
|
if ("text".equals(key)) {
|
this.element.text(result);
|
} else if ("html".equals(key)) {
|
this.element.html(result);
|
} else if ("time".equals(key)) {
|
TimeTag time = parserTag(result, TimeTag.class);
|
String timeStr = DateUtil.format(DateUtil.parse(time.getDate(), DatePattern.NORM_DATETIME_PATTERN), time.getFormat());
|
this.element.text(timeStr);
|
} else {
|
this.element.attr(key, result);
|
}
|
}
|
}
|
}
|
|
public String attrValueFormat(String value) {
|
String pattern = "(?<=\\$\\{)[\\s\\S]*?(?=\\})";
|
Matcher matcher = Pattern.compile(pattern).matcher(value);
|
|
Map<String, String> targetData = new HashMap<>();
|
while (matcher.find()) {
|
String group = matcher.group();
|
|
GroovyShell groovyShell = GroovySingleton.getSingleton();
|
Binding binding = new Binding();
|
for (Map.Entry<String, Object> entry : this.parserData.entrySet()) {
|
String fieldKey = entry.getKey();
|
Map<String, Object> data = (Map<String, Object>) entry.getValue();
|
binding.setProperty(fieldKey, data.get("state"));
|
}
|
|
if (systemData != null) {
|
binding.setProperty("system", systemData);
|
}
|
|
synchronized (this) {
|
Script parse = groovyShell.parse(group);
|
parse.setBinding(binding);
|
Object evaluate = parse.run();
|
if (evaluate instanceof Date) {
|
evaluate = DateUtil.format((Date) evaluate, DatePattern.NORM_DATETIME_PATTERN);
|
}
|
|
if (evaluate == null) {
|
targetData.put(group, "");
|
} else {
|
targetData.put(group, evaluate.toString());
|
}
|
groovyShell.getClassLoader().clearCache();
|
}
|
}
|
|
StringSubstitutor str = new StringSubstitutor(targetData);
|
return str.replace(value);
|
}
|
|
public Object getData() {
|
return data;
|
}
|
|
public void setData(Object data) {
|
this.data = data;
|
}
|
|
public String getField() {
|
return field;
|
}
|
|
public void setField(String field) {
|
this.field = field;
|
}
|
|
public Element getElement() {
|
return element;
|
}
|
|
public Map<String, Object> getParserData() {
|
return parserData;
|
}
|
|
public Object getParam() {
|
return param;
|
}
|
|
public String getTag() {
|
return tag;
|
}
|
|
public boolean processContinue() {
|
return processContinue;
|
}
|
|
public void systemData(Map<String, Object> systemData) {
|
this.systemData = systemData;
|
}
|
|
public Object getSystemDataValue(String key) {
|
return this.systemData.get(key);
|
}
|
}
|