提交 5cc2c44b 编写于 作者: 智布道's avatar 智布道 👁

优化freemarker自定义标签的实现代码,便于扩展

上级 0275ca01
......@@ -13,7 +13,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 提到core模块中,方便控制前后台
* 用于监控freemarker自定义标签中共享变量是否发生变化,发生变化时实时更新到内存中
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 2.0
......@@ -23,7 +23,7 @@ import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)
public class RenderAspects {
public class FreemarkerSharedVariableMonitorAspects {
private static volatile long configLastUpdateTime = 0L;
@Autowired
......@@ -46,10 +46,10 @@ public class RenderAspects {
}
Long updateTime = config.getUpdateTime().getTime();
if (updateTime == configLastUpdateTime) {
log.info("config表未更新");
log.debug("config表未更新");
return;
}
log.info("config表已更新,重新加载config到freemarker tag");
log.debug("config表已更新,重新加载config到shared variable");
configLastUpdateTime = updateTime;
try {
configuration.setSharedVariable("config", config);
......
......@@ -21,8 +21,8 @@ package com.zyd.blog.framework.config;
import com.jagregory.shiro.freemarker.ShiroTags;
import com.zyd.blog.business.service.SysConfigService;
import com.zyd.blog.framework.tag.ArticleTagDirective;
import com.zyd.blog.framework.tag.CustomTagDirective;
import com.zyd.blog.framework.tag.ArticleTags;
import com.zyd.blog.framework.tag.CustomTags;
import freemarker.template.TemplateModelException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
......@@ -43,9 +43,9 @@ public class FreeMarkerConfig {
@Autowired
protected freemarker.template.Configuration configuration;
@Autowired
protected CustomTagDirective customTagDirective;
protected CustomTags customTags;
@Autowired
protected ArticleTagDirective articleTagDirective;
protected ArticleTags articleTags;
@Autowired
private SysConfigService configService;
......@@ -54,8 +54,8 @@ public class FreeMarkerConfig {
*/
@PostConstruct
public void setSharedVariable() {
configuration.setSharedVariable("zhydTag", customTagDirective);
configuration.setSharedVariable("articleTag", articleTagDirective);
configuration.setSharedVariable("zhydTag", customTags);
configuration.setSharedVariable("articleTag", articleTags);
try {
configuration.setSharedVariable("config", configService.get());
//shiro标签
......
/**
* MIT License
*
* <p>
* Copyright (c) 2018 yadong.zhang
*
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* <p>
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
......@@ -28,12 +28,10 @@ import com.zyd.blog.business.entity.Article;
import com.zyd.blog.business.enums.ArticleStatusEnum;
import com.zyd.blog.business.service.BizArticleService;
import com.zyd.blog.business.vo.ArticleConditionVO;
import freemarker.core.Environment;
import freemarker.template.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.Map;
/**
......@@ -44,61 +42,55 @@ import java.util.Map;
* @website https://www.zhyd.me
* @date 2018/4/16 16:26
* @since 1.0
* @modify by zhyd 2018-09-20
* 调整实现,所有自定义标签只需继承BaseTag后通过构造函数将自定义标签类的className传递给父类即可。
* 增加标签时,只需要添加相关的方法即可,默认自定义标签的method就是自定义方法的函数名。
* 例如:<@articleTag method="recentArticles" ...></@articleTag>就对应 {{@link #recentArticles(Map)}}方法
*/
@Component
public class ArticleTagDirective implements TemplateDirectiveModel {
private static final String METHOD_KEY = "method";
public class ArticleTags extends BaseTag {
@Autowired
private BizArticleService articleService;
@Override
public void execute(Environment environment, Map map, TemplateModel[] templateModels, TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25);
if (map.containsKey(METHOD_KEY)) {
String method = map.get(METHOD_KEY).toString();
int pageSize = 10;
if (map.containsKey("pageSize")) {
String pageSizeStr = map.get("pageSize").toString();
pageSize = Integer.parseInt(pageSizeStr);
}
long typeId = -1;
if (map.containsKey("typeId")) {
String typeStr = map.get("typeId").toString();
typeId = Long.parseLong(typeStr);
}
public ArticleTags() {
super(ArticleTags.class.getName());
}
public Object recentArticles(Map params) {
int pageSize = this.getPageSize(params);
return articleService.listRecent(pageSize);
}
public Object recommendedList(Map params) {
int pageSize = this.getPageSize(params);
return articleService.listRecommended(pageSize);
}
public Object randomList(Map params) {
int pageSize = this.getPageSize(params);
return articleService.listRandom(pageSize);
}
public Object hotList(Map params) {
int pageSize = this.getPageSize(params);
return articleService.listHotArticle(pageSize);
}
switch (method) {
case "recentArticles":
// 近期文章
environment.setVariable("recentArticles", builder.build().wrap(articleService.listRecent(pageSize)));
break;
case "recommendedList":
// 站长推荐
environment.setVariable("recommendedList", builder.build().wrap(articleService.listRecommended(pageSize)));
break;
case "randomList":
// 随机文章
environment.setVariable("randomList", builder.build().wrap(articleService.listRandom(pageSize)));
break;
case "hotList":
// 热门文章
environment.setVariable("hotList", builder.build().wrap(articleService.listHotArticle(pageSize)));
break;
case "typeList":
// 按文章分类查询
ArticleConditionVO vo = new ArticleConditionVO();
vo.setTypeId(typeId);
// 已发布状态
vo.setStatus(ArticleStatusEnum.PUBLISHED.getCode());
vo.setPageSize(pageSize);
PageInfo<Article> pageInfo = articleService.findPageBreakByCondition(vo);
environment.setVariable("typeList", builder.build().wrap(null == pageInfo ? null : pageInfo.getList()));
break;
default:
break;
}
public Object typeList(Map params) {
int pageSize = this.getPageSize(params);
long typeId = -1;
String typeStr = getParam(params, "typeId");
if (!StringUtils.isEmpty(typeStr)) {
typeId = Long.parseLong(typeStr);
}
templateDirectiveBody.render(environment.getOut());
// 按文章分类查询
ArticleConditionVO vo = new ArticleConditionVO();
vo.setTypeId(typeId);
// 已发布状态
vo.setStatus(ArticleStatusEnum.PUBLISHED.getCode());
vo.setPageSize(pageSize);
PageInfo<Article> pageInfo = articleService.findPageBreakByCondition(vo);
return null == pageInfo ? null : pageInfo.getList();
}
}
package com.zyd.blog.framework.tag;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.DefaultObjectWrapperBuilder;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 所有自定义标签的父类,负责调用具体的子类方法
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0
* @website https://www.zhyd.me
* @date 2018/9/18 16:19
* @since 1.8
*/
public abstract class BaseTag implements TemplateDirectiveModel {
private String clazzPath = null;
public BaseTag(String targetClassPath) {
clazzPath = targetClassPath;
}
private String getMethod(Map params) {
return this.getParam(params, "method");
}
protected int getPageSize(Map params) {
int pageSize = 10;
String pageSizeStr = this.getParam(params, "pageSize");
if (!StringUtils.isEmpty(pageSizeStr)) {
pageSize = Integer.parseInt(pageSizeStr);
}
return pageSize;
}
private void verifyParameters(Map params) throws TemplateModelException {
String permission = this.getMethod(params);
if (permission == null || permission.length() == 0) {
throw new TemplateModelException("The 'name' tag attribute must be set.");
}
}
String getParam(Map params, String paramName) {
Object value = params.get(paramName);
return value instanceof SimpleScalar ? ((SimpleScalar) value).getAsString() : null;
}
private DefaultObjectWrapper getBuilder() {
return new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25).build();
}
private TemplateModel getModel(Object o) throws TemplateModelException {
return this.getBuilder().wrap(o);
}
@Override
public void execute(Environment environment, Map map, TemplateModel[] templateModels, TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
this.verifyParameters(map);
String funName = getMethod(map);
Method method = null;
try {
Class clazz = Class.forName(clazzPath);
method = clazz.getDeclaredMethod(funName, Map.class);
if (method != null) {
// 核心处理,调用子类的具体方法,获取返回值
Object res = method.invoke(this, map);
environment.setVariable(funName, getModel(res));
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
e.printStackTrace();
}
templateDirectiveBody.render(environment.getOut());
}
}
......@@ -25,17 +25,21 @@ package com.zyd.blog.framework.tag;
import com.zyd.blog.business.entity.User;
import com.zyd.blog.business.enums.UserTypeEnum;
import com.zyd.blog.business.service.*;
import com.zyd.blog.business.service.BizCommentService;
import com.zyd.blog.business.service.BizTagsService;
import com.zyd.blog.business.service.BizTypeService;
import com.zyd.blog.business.service.SysConfigService;
import com.zyd.blog.business.service.SysResourcesService;
import com.zyd.blog.util.SessionUtil;
import freemarker.core.Environment;
import freemarker.template.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.NumberUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 自定义的freemarker标签
......@@ -45,10 +49,17 @@ import java.util.Map;
* @website https://www.zhyd.me
* @date 2018/4/16 16:26
* @since 1.0
* @modify by zhyd 2018-09-20
* 调整实现,所有自定义标签只需继承BaseTag后通过构造函数将自定义标签类的className传递给父类即可。
* 增加标签时,只需要添加相关的方法即可,默认自定义标签的method就是自定义方法的函数名。
* 例如:<@zhydTag method="types" ...></@zhydTag>就对应 {{@link #types(Map)}}方法
*/
@Component
public class CustomTagDirective implements TemplateDirectiveModel {
private static final String METHOD_KEY = "method";
public class CustomTags extends BaseTag {
private final Random randoms = new Random();
private final DecimalFormat df = new DecimalFormat("#.##");
@Autowired
private BizTypeService bizTypeService;
@Autowired
......@@ -60,55 +71,48 @@ public class CustomTagDirective implements TemplateDirectiveModel {
@Autowired
private SysConfigService configService;
@Override
public void execute(Environment environment, Map map, TemplateModel[] templateModels, TemplateDirectiveBody templateDirectiveBody) throws TemplateException, IOException {
DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25);
if (map.containsKey(METHOD_KEY)) {
String method = map.get(METHOD_KEY).toString();
int pageSize = 10;
if (map.containsKey("pageSize")) {
String pageSizeStr = map.get("pageSize").toString();
pageSize = Integer.parseInt(pageSizeStr);
}
switch (method) {
case "types":
environment.setVariable("types", builder.build().wrap(bizTypeService.listTypeForMenu()));
break;
case "tagsList":
// 所有标签
environment.setVariable("tagsList", builder.build().wrap(bizTagsService.listAll()));
break;
case "availableMenus":
// 所有可用的菜单资源
environment.setVariable("availableMenus", builder.build().wrap(resourcesService.listAllAvailableMenu()));
break;
case "recentComments":
// 近期评论
environment.setVariable("recentComments", builder.build().wrap(commentService.listRecentComment(pageSize)));
break;
case "siteInfo":
// 站点属性
environment.setVariable("siteInfo", builder.build().wrap(configService.getSiteInfo()));
break;
case "menus":
Integer userId = null;
User user = SessionUtil.getUser();
if (map.containsKey("userId") && user != null && !user.getUserTypeEnum().equals(UserTypeEnum.ROOT)) {
String userIdStr = map.get("userId").toString();
if (StringUtils.isEmpty(userIdStr)) {
return;
}
userId = Integer.parseInt(userIdStr);
}
Map<String, Object> params = new HashMap<>(2);
params.put("type", "menu");
params.put("userId", userId);
environment.setVariable("menus", builder.build().wrap(resourcesService.listUserResources(params)));
break;
default:
break;
}
public CustomTags() {
super(CustomTags.class.getName());
}
public Object types(Map params) {
return bizTypeService.listTypeForMenu();
}
public Object tagsList(Map params) {
return bizTagsService.listAll();
}
public Object availableMenus(Map params) {
return resourcesService.listAllAvailableMenu();
}
public Object recentComments(Map params) {
int pageSize = this.getPageSize(params);
return commentService.listRecentComment(pageSize);
}
public Object siteInfo(Map params) {
return configService.getSiteInfo();
}
public Object menus(Map params) {
User user = SessionUtil.getUser();
String userIdStr = getParam(params, "userId");
Integer userId = null;
if (!StringUtils.isEmpty(userIdStr) && user != null && !user.getUserTypeEnum().equals(UserTypeEnum.ROOT)) {
userId = Integer.parseInt(userIdStr);
return null;
}
templateDirectiveBody.render(environment.getOut());
Map<String, Object> p = new HashMap<>(2);
p.put("type", "menu");
p.put("userId", userId);
return resourcesService.listUserResources(p);
}
public Object random(Map params) {
int max = NumberUtils.parseNumber(getParam(params, "max"), Integer.class);
int min = NumberUtils.parseNumber(getParam(params, "min"), Integer.class);
return df.format(randoms.nextInt(max) % (max - min + 1) + min + Math.random());
}
}
......@@ -55,20 +55,16 @@
</div>
</div>
<div class="sidebar-module">
<h5 class="sidebar-title"><i class="fa fa-tags icon"></i><strong>文章标签</strong></h5>
<ul class="list-unstyled list-inline">
<@zhydTag method="tagsList" pageSize="10">
<#if tagsList?exists && (tagsList?size > 0)>
<#list tagsList as item>
<li class="tag-li">
<a class="btn btn-default btn-xs" href="${config.siteUrl}/tag/${item.id?c}" title="${item.name?if_exists}" data-toggle="tooltip" data-placement="bottom">
${item.name?if_exists}
</a>
</li>
</#list>
</#if>
</@zhydTag>
</ul>
<h5 class="sidebar-title"><i class="fa fa-tags icon"></i><strong>标签云</strong></h5>
<@zhydTag method="tagsList" pageSize="10">
<#if tagsList?exists && (tagsList?size > 0)>
<#list tagsList as item>
<a style="font-size: <@zhydTag method="random" max="15" min="10">${random}</@zhydTag>px;margin: 5px;" href="${config.siteUrl}/tag/${item.id?c}" title="${item.name?if_exists}" data-toggle="tooltip" data-placement="bottom">
${item.name?if_exists}
</a>
</#list>
</#if>
</@zhydTag>
</div>
<@zhydTag method="recentComments" pageSize="10">
<#if recentComments?? && recentComments?size gt 0>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册