Helius
2022-07-02 27b61ffe97c575cdc6c2e8b9f010ab1021e7160e
添加模板解析逻辑
21 files added
1 files modified
1119 ■■■■■ changed files
pom.xml 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/ArticleDataParserHandler.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/ArticlesDataParserHandler.java 33 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/ChildDataParserHandler.java 30 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/DataParserHandler.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/NavDataParserHandler.java 43 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/handler/TemplateCodeDataParserHandler.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/node/AttrNode.java 203 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/node/PartNode.java 102 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/TagsEnum.java 60 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Ad.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Article.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Articles.java 48 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Child.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Column.java 48 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Columns.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Include.java 27 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/tag/model/Nav.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/template/Configuration.java 111 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/template/Template.java 71 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/template/TemplateConfiguration.java 105 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/farmer/cms/cms/template/TemplateLoader.java 66 ●●●●● patch | view | raw | blame | history
pom.xml
@@ -265,6 +265,20 @@
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy</artifactId>
            <version>2.5.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.9</version>
        </dependency>
    </dependencies>
    <build>
src/main/java/com/xcong/farmer/cms/cms/handler/ArticleDataParserHandler.java
New file
@@ -0,0 +1,22 @@
package com.xcong.farmer.cms.cms.handler;
import com.xcong.farmer.cms.cms.node.AttrNode;
import java.util.HashMap;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-06-24
 **/
public class ArticleDataParserHandler implements DataParserHandler {
    @Override
    public void dataParser(AttrNode node) {
        System.out.println("ArticleDataParserHandler");
        Map<String, Object> map = new HashMap<>();
        map.put("title", "这是单个文章标题");
        node.setData(map);
    }
}
src/main/java/com/xcong/farmer/cms/cms/handler/ArticlesDataParserHandler.java
New file
@@ -0,0 +1,33 @@
package com.xcong.farmer.cms.cms.handler;
import com.xcong.farmer.cms.cms.node.AttrNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-06-24
 **/
public class ArticlesDataParserHandler implements DataParserHandler  {
    @Override
    public void dataParser(AttrNode node) {
        System.out.println("ArticlesDataParserHandler");
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("path", "这是链接1");
        map.put("title", "这是标题1");
        list.add(map);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("path", "这是链接2");
        map2.put("title", "这是标题2");
        list.add(map2);
        node.setData(list);
    }
}
src/main/java/com/xcong/farmer/cms/cms/handler/ChildDataParserHandler.java
New file
@@ -0,0 +1,30 @@
package com.xcong.farmer.cms.cms.handler;
import com.alibaba.fastjson.JSONObject;
import com.xcong.farmer.cms.cms.node.AttrNode;
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-06-29
 **/
public class ChildDataParserHandler implements DataParserHandler {
    @Override
    public void dataParser(AttrNode attrNode) {
        System.out.println("ChildDataParserHandler");
        Map<String, Object> parserData = attrNode.getParserData();
        Object param = attrNode.getParam();
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(param));
        String obj = jsonObject.getString("obj");
        Object o = parserData.get(obj);
        Object state = JSONObject.parseObject(JSONObject.toJSONString(o)).get("state");
        List children = JSONObject.parseObject(JSONObject.toJSONString(state)).getObject("children", List.class);
        attrNode.setData(children);
    }
}
src/main/java/com/xcong/farmer/cms/cms/handler/DataParserHandler.java
New file
@@ -0,0 +1,10 @@
package com.xcong.farmer.cms.cms.handler;
import com.xcong.farmer.cms.cms.node.AttrNode;
public interface DataParserHandler {
    void dataParser(AttrNode attrNode);
}
src/main/java/com/xcong/farmer/cms/cms/handler/NavDataParserHandler.java
New file
@@ -0,0 +1,43 @@
package com.xcong.farmer.cms.cms.handler;
import com.xcong.farmer.cms.cms.node.AttrNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-06-28
 **/
public class NavDataParserHandler implements DataParserHandler {
    @Override
    public void dataParser(AttrNode node) {
        System.out.println("NavDataParserHandler");
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> aa = new HashMap<>();
        aa.put("title", "导航1");
        list.add(aa);
        Map<String, Object> bb = new HashMap<>();
        bb.put("title", "导航2");
        List<Map<String, Object>> sub = new ArrayList<>();
        Map<String, Object> subBB = new HashMap<>();
        subBB.put("title", "子导航1");
        subBB.put("src", "http://1234");
        sub.add(subBB);
        Map<String, Object> subAA = new HashMap<>();
        subAA.put("title", "子导航2");
        subAA.put("src", "http://123455555");
        sub.add(subAA);
        bb.put("children", sub);
        list.add(bb);
        node.setData(list);
    }
}
src/main/java/com/xcong/farmer/cms/cms/handler/TemplateCodeDataParserHandler.java
New file
@@ -0,0 +1,15 @@
package com.xcong.farmer.cms.cms.handler;
import com.xcong.farmer.cms.cms.node.AttrNode;
/**
 * @author wzy
 * @date 2022-06-29
 **/
public class TemplateCodeDataParserHandler implements DataParserHandler {
    @Override
    public void dataParser(AttrNode tagNode) {
        System.out.println("TemplateCodeDataParserHandler");
    }
}
src/main/java/com/xcong/farmer/cms/cms/node/AttrNode.java
New file
@@ -0,0 +1,203 @@
package com.xcong.farmer.cms.cms.node;
import com.alibaba.fastjson.JSONObject;
import com.xcong.farmer.cms.cms.handler.DataParserHandler;
import com.xcong.farmer.cms.cms.tag.TagsEnum;
import com.xcong.farmer.cms.cms.tag.model.Articles;
import com.xcong.farmer.cms.cms.template.Configuration;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import org.apache.commons.text.StringSubstitutor;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
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;
    // Tag参数 {id=[1,2,3], page=1, limit=5, field=art}
    private Object param;
    private Element element;
    private Element originalElement;
    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;
    }
    public static void main(String[] args) {
//        String data = "{id=[1,2,3], page=1, limit=5, field=art}";
//        Articles articles = new AttrNode().parserTag(data, Articles.class);
//        String value = "{id=${col.id}, page=1, limit=5, field=art}";
//        String pattern = "(?<=\\$\\{)[\\s\\S]*?(?=\\})";
//        Matcher matcher = Pattern.compile(pattern).matcher(value);
//        while (matcher.find()) {
//            String group = matcher.group();
//            System.out.println(1);
//        }
        System.out.println(1);
    }
    public void parser() {
        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 {
                // {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();
        }
        runDataInject();
    }
    public void runDataInject() {
        Attributes attributes = this.element.attributes();
        for (Attribute attribute : attributes) {
            String key = attribute.getKey().replaceAll("\\$", "");
            String value = attribute.getValue();
            // @{} 为java表达式; ${}为需要注入的数据项
            if (value.startsWith("@{")) {
                value = value.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);
                    binding.setVariable(fieldKey + ".index", 1);
                }
                GroovyShell shell = new GroovyShell(binding);
                String evaluate = (String) shell.evaluate(value);
                this.element.removeAttr("class");
                this.element.attr("class", evaluate);
            } else if (value.startsWith("${")) {
                String result = attrValueFormat(value);
                if ("text".equals(key)) {
                    this.element.text(result);
                } 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();
            String splitValue = group.replaceAll("\\$\\{", "").replaceAll("}", "");
            String[] split = splitValue.split("\\.");
            if (split.length == 0) {
                continue;
            }
            for (Map.Entry<String, Object> entry : this.parserData.entrySet()) {
                String fieldKey = entry.getKey();
                Map<String, Object> data = (Map<String, Object>) entry.getValue();
                JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(data.get("state")));
                for (Map.Entry<String, Object> map : jsonObject.entrySet()) {
                    if (map.getValue() instanceof String) {
                        targetData.put(fieldKey + "." + map.getKey(), (String) map.getValue());
                    }
                }
            }
        }
        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;
    }
}
src/main/java/com/xcong/farmer/cms/cms/node/PartNode.java
New file
@@ -0,0 +1,102 @@
package com.xcong.farmer.cms.cms.node;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.xcong.farmer.cms.cms.template.Configuration;
import org.jsoup.nodes.Element;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PartNode extends Configuration {
    private Element element;
    private Element originalElement;
    private String html;
    public PartNode(Element element) {
        this.element = element.clone();
        this.originalElement = element;
    }
    public void parser() {
        this.html = parser(this.element, null);
    }
    public String parser(Element element, Map<String, Object> tagDataMap) {
        AttrNode attrNode = new AttrNode(element, tagDataMap);
        attrNode.parser();
//        attrNode.runDataInject();
        StringBuilder result = new StringBuilder();
        if (CollUtil.isNotEmpty(element.children())) {
            Object parseData = attrNode.getData();
            if (tagDataMap == null) {
                tagDataMap = new HashMap<>();
            }
            if (parseData == null) {
                // 特殊处理。 如果有子节点标签@child,但数据中没有子节点数据,则将该子节点直接删除即直接返回空字符串
                if (!"@child".equals(attrNode.getTag())) {
                    for (Element children : element.children()) {
                        String html = parser(children, tagDataMap);
                        result.append(html);
                    }
                } else {
                    return "";
                }
            } else {
                if (parseData instanceof List) {
                    List list = (List) parseData;
                    int i = 1;
                    for (Object o : list) {
                        if (StrUtil.isNotBlank(attrNode.getField())) {
                            Map<String, Object> data = new HashMap<>();
                            data.put("index", i);
                            data.put("state", o);
                            tagDataMap.put(attrNode.getField(), data);
                        }
                        StringBuilder listHtml = new StringBuilder();
                        for (Element children : element.children()) {
                            String html = parser(children, tagDataMap);
                            listHtml.append(html);
                        }
                        result.append(listHtml);
                        i++;
                    }
                } else if (parseData instanceof Map) {
                    if (StrUtil.isNotBlank(attrNode.getField())) {
                        Map<String, Object> data = new HashMap<>();
                        data.put("index", 1);
                        data.put("state", parseData);
                        tagDataMap.put(attrNode.getField(), data);
                    }
                    for (Element children : element.children()) {
                        String html = parser(children, tagDataMap);
                        result.append(html);
                    }
                }
            }
        }
        if (attrNode.tagsEnum != null && attrNode.tagsEnum.getType() == 1) {
            this.put(attrNode.getField(), result.toString());
        }
        attrNode.getElement().append(result.toString());
        return attrNode.getElement().toString();
    }
    public Element getElement() {
        return element;
    }
    public String getHtml() {
        return html;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/TagsEnum.java
New file
@@ -0,0 +1,60 @@
package com.xcong.farmer.cms.cms.tag;
/**
 * @author wzy
 * @date 2022-06-20
 **/
public enum TagsEnum {
    INCLUDE("@include", "com.xcong.farmer.cms.cms.tag.model.Include", "com.xcong.farmer.cms.cms.handler.TemplateCodeDataParserHandler",  1),
    NAV("@nav", "com.xcong.farmer.cms.cms.tag.model.Nav", "com.xcong.farmer.cms.cms.handler.NavDataParserHandler", 2),
    ARTICLES("@articles", "com.xcong.farmer.cms.cms.tag.model.Articles", "com.xcong.farmer.cms.cms.handler.ArticlesDataParserHandler",2),
    ARTICLE("@article", "com.xcong.farmer.cms.cms.tag.model.Article", "com.xcong.farmer.cms.cms.handler.ArticleDataParserHandler",2),
    CHILD("@child", "com.xcong.farmer.cms.cms.tag.model.Child", "com.xcong.farmer.cms.cms.handler.ChildDataParserHandler",2);
//    AD("@ad", "com.xcong.farmer.cms.cms.tag.model.Ad", "",2),
//    COLUMNS("@columns", "com.xcong.farmer.cms.cms.tag.model.Columns", "",2),
//    COLUMN("@column", "com.xcong.farmer.cms.cms.tag.model.Column", "",2);
    private String name;
    private String className;
    private String handler;
    // 标签类型 1-模板标签  2-数据标签
    // 模板标签 : 该标签可以变为通用模板,在各个页面引入
    // 数据模板 : 该标签需要注入数据
    private int type;
    TagsEnum(String name, String className, String handler, int type) {
        this.name = name;
        this.className = className;
        this.type = type;
        this.handler = handler;
    }
    public String getName() {
        return name;
    }
    public String getClassName() {
        return className;
    }
    public int getType() {
        return type;
    }
    public String getHandler() {
        return handler;
    }
    public static TagsEnum getEnumByName(String name) {
        for (TagsEnum value : values()) {
            if (name.equals(value.getName())) {
                return value;
            }
        }
        return null;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Ad.java
New file
@@ -0,0 +1,28 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-22
 **/
public class Ad {
    private String id;
    private String field;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Article.java
New file
@@ -0,0 +1,28 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-22
 **/
public class Article {
    private String id;
    private String field;
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Articles.java
New file
@@ -0,0 +1,48 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-20
 **/
public class Articles {
    private String colId;
    private String page;
    private String limit;
    private String field;
    public String getColId() {
        return colId;
    }
    public void setColId(String colId) {
        this.colId = colId;
    }
    public String getPage() {
        return page;
    }
    public void setPage(String page) {
        this.page = page;
    }
    public String getLimit() {
        return limit;
    }
    public void setLimit(String limit) {
        this.limit = limit;
    }
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Child.java
New file
@@ -0,0 +1,28 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-07-01
 **/
public class Child {
    private String obj;
    private String field;
    public String getObj() {
        return obj;
    }
    public void setObj(String obj) {
        this.obj = obj;
    }
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Column.java
New file
@@ -0,0 +1,48 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-22
 **/
public class Column {
    private String id;
    private String field;
    private String code;
    private String hasChild;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getHasChild() {
        return hasChild;
    }
    public void setHasChild(String hasChild) {
        this.hasChild = hasChild;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Columns.java
New file
@@ -0,0 +1,9 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-22
 **/
public class Columns {
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Include.java
New file
@@ -0,0 +1,27 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-23
 **/
public class Include {
    private String field;
    private String repeat = "1";
    public String getRepeat() {
        return repeat;
    }
    public void setRepeat(String repeat) {
        this.repeat = repeat;
    }
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}
src/main/java/com/xcong/farmer/cms/cms/tag/model/Nav.java
New file
@@ -0,0 +1,18 @@
package com.xcong.farmer.cms.cms.tag.model;
/**
 * @author wzy
 * @date 2022-06-28
 **/
public class Nav {
    String field;
    public String getField() {
        return field;
    }
    public void setField(String field) {
        this.field = field;
    }
}
src/main/java/com/xcong/farmer/cms/cms/template/Configuration.java
New file
@@ -0,0 +1,111 @@
package com.xcong.farmer.cms.cms.template;
import com.xcong.farmer.cms.cms.node.AttrNode;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public abstract class Configuration {
    public String staticPath;
    public String templatePath;
    public String outputPath;
    public Configuration() {
    }
    public Configuration(String templatePath, String staticPath, String outputPath) {
        this.staticPath = staticPath;
        this.templatePath = templatePath;
        this.outputPath = outputPath;
    }
    public static Map<String, String> templateCode = new HashMap<>();
    private final String PREFIX_DEFAULT = "{";
    private final String SUFFIX_DEFAULT = "}";
    public <T> T parserTag(String attr, Class<T> clazz) {
        if (!attr.startsWith(PREFIX_DEFAULT) || !attr.endsWith(SUFFIX_DEFAULT)) {
            return null;
        }
        int i = 1;
        int length = attr.length();
        int startIndex = 1;
        int endIndex = 1;
        T object = null;
        try {
            object = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        boolean hasMulti = false;
        for (; i <= length - 1; i++) {
            if (attr.charAt(i) =='[') {
                hasMulti = true;
            } else if (attr.charAt(i) == ']') {
                hasMulti = false;
            }
            if (!hasMulti) {
                if (attr.charAt(i) == ',' || i == length - 1) {
                    String columnStr = attr.substring(startIndex, endIndex);
                    String[] columns = columnStr.split("=");
                    if (columns.length != 2) {
                        return null;
                    }
                    try {
                        Field field = clazz.getDeclaredField(columns[0].trim());
                        field.setAccessible(true);
                        field.set(object, columns[1].replace("[", "").replace("]", "").trim());
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        e.printStackTrace();
                        return null;
                    }
                    startIndex = i + 1;
                }
            }
            endIndex++;
        }
        return object;
    }
    public void put(String key, String templateCode) {
        Configuration.templateCode.put(key, templateCode);
    }
    public String get(String key) {
        return Configuration.templateCode.get(key);
    }
    public String getStaticPath() {
        return staticPath;
    }
    public void setStaticPath(String staticPath) {
        this.staticPath = staticPath;
    }
    public String getTemplatePath() {
        return templatePath;
    }
    public void setTemplatePath(String templatePath) {
        this.templatePath = templatePath;
    }
    public String getOutputPath() {
        return outputPath;
    }
    public void setOutputPath(String outputPath) {
        this.outputPath = outputPath;
    }
}
src/main/java/com/xcong/farmer/cms/cms/template/Template.java
New file
@@ -0,0 +1,71 @@
package com.xcong.farmer.cms.cms.template;
import cn.hutool.core.collection.CollUtil;
import com.xcong.farmer.cms.cms.node.PartNode;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-06-22
 **/
public class Template {
    private String name;
    private Document document;
    private Map<String, Map<String, Object>> params = new HashMap<>();
    private List<PartNode> partNodes = new ArrayList<>();
    public void parser() {
        Elements children = document.body().children();
        if (CollUtil.isNotEmpty(children)) {
            for (Element child : children) {
                PartNode partNode = new PartNode(child);
                partNode.parser();
                this.add(partNode);
            }
        }
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Document getDocument() {
        return document;
    }
    public void setDocument(Document document) {
        this.document = document;
    }
    public void add(PartNode partNode) {
        this.partNodes.add(partNode);
    }
    public List<PartNode> getPartNodes() {
        return partNodes;
    }
    public Map<String, Map<String, Object>> getParams() {
        return params;
    }
    public void putParams(String key, Map<String, Object> value) {
        this.params.put(key, value);
    }
}
src/main/java/com/xcong/farmer/cms/cms/template/TemplateConfiguration.java
New file
@@ -0,0 +1,105 @@
package com.xcong.farmer.cms.cms.template;
import cn.hutool.core.collection.CollUtil;
import com.xcong.farmer.cms.cms.node.PartNode;
import com.xcong.farmer.cms.cms.tag.TagsEnum;
import org.jsoup.nodes.Document;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2022-07-01
 **/
public class TemplateConfiguration extends Configuration{
    private TemplateLoader templateLoader;
    public TemplateConfiguration(String templatePath, String staticPath, String outputPath) {
        super(templatePath, staticPath, outputPath);
    }
    public void templateLoader(TemplateLoader templateLoader) {
        this.templateLoader = templateLoader;
    }
    public void process() {
        if (this.templateLoader == null) {
            throw new RuntimeException("TemplateLoader do not able to be null");
        }
        List<Template> templates = templateLoader.templates();
        if (CollUtil.isEmpty(templates)) {
            return;
        }
        for (Template template : templates) {
            output(template);
        }
    }
    public List<Template> templates() {
        return this.templateLoader.templates();
    }
    public Template template(String templateName) {
        return template(new File(path(this.templatePath) + templateName));
    }
    public Template template(File file) {
        if (file == null) {
            throw new RuntimeException("template not exist");
        }
        return this.templateLoader.template(file);
    }
    public void columnProcess(Long id, String templateName) {
        Template template = template(templateName);
    }
    public void columnProcess(String code, String templateName) {
    }
    public void articleProcess(Long id, String templateName) {
        Map<String, Map<String, Object>> map = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("id", id);
        map.put(TagsEnum.ARTICLE.getName(), data);
    }
    public void output(Template template) {
        Document document = template.getDocument();
        List<PartNode> partNodes = template.getPartNodes();
        StringBuilder sb = new StringBuilder();
        for (PartNode partNode : partNodes) {
            sb.append(partNode.getHtml());
        }
        document.body().empty().html(sb.toString());
        String outPath = path(this.outputPath);
        String html = document.html();
        try {
            FileOutputStream outputStream = new FileOutputStream(outPath + template.getName());
            outputStream.write(html.getBytes());
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private String path(String path) {
        if (!path.endsWith("/")) {
            path = path + "/";
        }
        return path;
    }
}
src/main/java/com/xcong/farmer/cms/cms/template/TemplateLoader.java
New file
@@ -0,0 +1,66 @@
package com.xcong.farmer.cms.cms.template;
import cn.hutool.core.collection.CollUtil;
import com.xcong.farmer.cms.cms.node.AttrNode;
import com.xcong.farmer.cms.cms.node.PartNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TemplateLoader {
    private Configuration cfg;
    private List<Template> templates = new ArrayList<>();
    public TemplateLoader() {}
    public TemplateLoader(Configuration cfg) {
        this.cfg = cfg;
    }
    public Template template(File file) {
        Document document = null;
        try {
            document = Jsoup.parse(file, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (document == null) {
            throw new NullPointerException();
        }
        Template template = new Template();
        template.setDocument(document);
        template.setName(file.getName());
        template.parser();
        return template;
    }
    public List<Template> templates(String templatePath) {
        File files = new File(templatePath);
        if (files.listFiles() == null) {
            return null;
        }
        for (File file : files.listFiles()) {
            if (file.isDirectory()) {
                continue;
            }
            templates.add(template(file));
        }
        return templates;
    }
    public List<Template> templates() {
        return templates(cfg.getTemplatePath());
    }
}