i++

2017-08-14 15:37

@JFinal 今天看了3.2这部份源码。我并不认同这种把问题抛给使用者以自选的方式处理。原因
1.没有几个使用者会认真区分这两个方法的真正区别,大部份人只知道做下表面的试验,能用就好了。而这个问题在平时的开发使用过程中是很难发现问题的。而当应用服务出现问题时他们的第一反应是:jfinal这个框架不行。谨慎点的开发者看到了注释为了安全起见,他们往往会默认选择不缓存。不缓存性能相对就差点。
2.模板的主要特点就是可重用性,我是真想不到有什么业务场景要用到模板但只执行一次的。既然要使用多次,那么进行缓存肯定是比较好的。所以做为应用的底层默认是要缓存的。
3.这个问题的根源是在缓存方法中默认使用content的md5当key,做为一个开发框架的底层不应该使用这种有局限性的实现方法。所以要让方法通用,应该让使用者自己设置缓存的key。提供默认不缓存engine.getTemplateByString(content) 和默认缓存engine.getTemplateByString(key,content)两个方法。再提供engine.setTemplateCacheMaxSize()设置最大缓存条数,实现当缓存达到最大值时自动清除。或用设置有效期的方式,在jfinal框架本身把这个问题解决掉。而不是让使用者自己选择只能缓存某一类的数据,这样的约定在开发过程中的业务层是很常见,但在开发的框架底层使用这样的约定就会影响到使用业务的范围。

i++

2017-08-12 16:49

@JFinal 按你说的改了。但是我不是用value做判断,而是去判断有没有参传。所以参会值还是可以传null的,不会有你说的那两个问题。代码如下
if (index == -1) {
Expr[] exprArray = exprList.getExprArray();
Object ret = null;
for (Expr expr : exprArray) {
boolean hasPara = scope.getData().containsKey(expr.toString());
if (hasPara) {
ret = expr.eval(scope);
} else {//没有传参数抛异常
throw new TemplateException(
"The parameter '"+expr.toString()+"' must be assigned",
location);
}
}
sqlPara.addPara(ret);
// sqlPara.addPara(exprList.eval(scope));
}

有没有传参和传的是不是null值是两码事

i++

2017-08-12 11:36

我觉得jfinal在赋值sqlPara时,发现sql语句是的?没有对应的参数时,应该按正常的业务思维逻辑抛出参数缺失的异常,因为是通用接口,所以我不好在接口中对参数进行校验。也不能在sqltemplate中写#if()判断。@jfinal

i++

2017-07-06 19:56

@jfinal 不知道这么扩展行不行?帮我看下。因为templateCache 是私有的,在子类里也是无法用的。只能在子类里自己维护一个mainTemplateCache 。所以所有template有关的都要重写。

import java.util.HashMap;
import java.util.Map;

import com.jfinal.kit.HashKit;
import com.jfinal.log.Log;
import com.jfinal.template.Engine;
import com.jfinal.template.EngineConfig;
import com.jfinal.template.Env;
import com.jfinal.template.FileStringSource;
import com.jfinal.template.IStringSource;
import com.jfinal.template.MemoryStringSource;
import com.jfinal.template.Template;
import com.jfinal.template.stat.Parser;
import com.jfinal.template.stat.ast.Stat;


/**
* 描述:自定义Engine
* 优化mainTemplateCache,防止mainTemplateCache内存占用过大。
* @author Robin Zhang
* @created 2017年7月6日 下午5:18:50
*/
public class MainEngine extends Engine {

/**
* 描述:
*/
private static Log log = Log.getLog(MainEngine.class);

/**
* 描述:模板缓存
*/
private static Map mainTemplateCache = new HashMap();

static {
Runnable runnable = new Runnable() {
public void run() {
while (true) {
try {
int len = mainTemplateCache.size();
if(len>200){
mainTemplateCache.clear();
log.debug("MainEngine.mainTemplateCache的模板缓存大于200已被清理。");
} else {
try {
Thread.sleep(60000l);
} catch (InterruptedException e) {
log.error("MainEngine.mainTemplateCache.Thread.sleep()出错:",e);
}
}
} catch (Exception e) {
log.error("MainEngine.mainTemplateCache.保存访问记录缓存到数据库定时任务出错",e);
try {
Thread.sleep(60000l);
} catch (InterruptedException e1) {
log.error("MainEngine.mainTemplateCache.Thread.sleep()出错:",e);
}
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}

/**
* 描述:Get template with file name
* @author Robin Zhang
* @created 2017年7月6日 下午5:53:25
* @param fileName
* @return
* @see com.jfinal.template.Engine#getTemplate(java.lang.String)
*/
public Template getTemplate(String fileName) {
if (fileName.charAt(0) != '/') {
char[] arr = new char[fileName.length() + 1];
fileName.getChars(0, fileName.length(), arr, 1);
arr[0] = '/';
fileName = new String(arr);
}

Template template = mainTemplateCache.get(fileName);
if (template == null) {
template = buildTemplateByFileStringSource(fileName);
mainTemplateCache.put(fileName, template);
} else if (getDevMode()) {
if (template.isModified()) {
template = buildTemplateByFileStringSource(fileName);
mainTemplateCache.put(fileName, template);
}
}
return template;
}

/**
* 描述:
* @author Robin Zhang
* @created 2017年7月6日 下午5:54:23
* @param fileName
* @return
*/
private Template buildTemplateByFileStringSource(String fileName) {
EngineConfig config = getEngineConfig();
FileStringSource fileStringSource = new FileStringSource(config.getBaseTemplatePath(), fileName, config.getEncoding());
Env env = new Env(config);
Parser parser = new Parser(env, fileStringSource.getContent(), fileName);
if (getDevMode()) {
env.addStringSource(fileStringSource);
}
Stat stat = parser.parse();
Template template = new Template(env, stat);
return template;
}


/**
* 描述:Get template by string content
* @author Robin Zhang
* @created 2017年7月6日 下午5:54:34
* @param content
* @return
* @see com.jfinal.template.Engine#getTemplateByString(java.lang.String)
*/
public Template getTemplateByString(String content) {
String key = HashKit.md5(content);
Template template = mainTemplateCache.get(key);
if (template == null) {
template = buildTemplateByStringSource(new MemoryStringSource(content));
mainTemplateCache.put(key, template);
} else if (getDevMode()) {
if (template.isModified()) {
template = buildTemplateByStringSource(new MemoryStringSource(content));
mainTemplateCache.put(key, template);
}
}
return template;
}

/**
* 描述:Get template with implementation of IStringSource
* @author Robin Zhang
* @created 2017年7月6日 下午5:54:43
* @param stringSource
* @return
* @see com.jfinal.template.Engine#getTemplate(com.jfinal.template.IStringSource)
*/
public Template getTemplate(IStringSource stringSource) {
String key = stringSource.getKey();
Template template = mainTemplateCache.get(key);
if (template == null) {
template = buildTemplateByStringSource(stringSource);
mainTemplateCache.put(key, template);
} else if (getDevMode()) {
if (template.isModified()) {
template = buildTemplateByStringSource(stringSource);
mainTemplateCache.put(key, template);
}
}
return template;
}

/**
* 描述:
* @author Robin Zhang
* @created 2017年7月6日 下午5:54:53
* @param stringSource
* @return
*/
private Template buildTemplateByStringSource(IStringSource stringSource) {
EngineConfig config = getEngineConfig();
Env env = new Env(config);
Parser parser = new Parser(env, stringSource.getContent(), null);
if (getDevMode()) {
env.addStringSource(stringSource);
}
Stat stat = parser.parse();
Template template = new Template(env, stat);
return template;
}

/**
* 描述:
* @author Robin Zhang
* @created 2017年7月6日 下午5:06:26
* @param templateKey
* @see com.jfinal.template.Engine#removeTemplateCache(java.lang.String)
*/
@Override
public void removeTemplateCache(String templateKey) {
super.removeTemplateCache(templateKey);
mainTemplateCache.remove(templateKey);
}

/**
* 描述:
* @author Robin Zhang
* @created 2017年7月6日 下午5:06:26
* @see com.jfinal.template.Engine#removeAllTemplateCache()
*/
@Override
public void removeAllTemplateCache() {
super.removeAllTemplateCache();
mainTemplateCache.clear();
}

/**
* 描述:获取模板缓存大小
* @author Robin Zhang
* @created 2017年7月6日 下午5:18:03
* @return
*/
public int getTemplateCacheSize() {
return mainTemplateCache.size();
}
}





config.java中注册mainEngine
@Override
public void configEngine(Engine engine) {
Engine.setMainEngine(new MainEngine());
}

i++

2017-06-23 15:50

@JFinal String 型 Template 做缓存还是很有必要的。建议别去掉。即使String 型的不做templateCache。只有文件类型的做templateCache,templateCache也会一直增大的。因为文件(html)模板会重命名,会删除,而且文件模板不会太小。要是怕做先进先出的缓存影响性能,至少做个最大量的限制,超过了就全部删除,总比让他无限增长,内存用尽好。这个最大量让使用者可以自己根据服务器内存情况设置。

i++

2017-06-23 15:35

@JFinal 手动 remove cache时需要知道key。但我们并不知道无用的key是什么。请问有办法获取templateCache的大小吗。当templateCache等于一定量时,我们用removeAllTemplateCache()也行啊。

i++

2017-03-20 19:23

@jfinal
3.0版,这个问题还是没改。这个框架没有做单元测试吧。把DbPro.java中的两处:
int index = 0;
// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs
for (Entry e: attrs.entrySet())
attrNames[index++] = e.getKey();
String columns = StrKit.join(attrNames, ",");
代码改成:
StringBuffer columns = new StringBuffer();
for (Entry e : attrs.entrySet()){
String key = e.getKey();
if (attrs.get(key) instanceof String && config.dialect.isOracle() && ((String)attrs.get(key)).endsWith(".nextval")) {
} else {
columns.append(key+",");
}
}
if (columns.length()>1) {
columns = columns.deleteCharAt(columns.length()-1);
}

就可以了。

i++

2017-03-10 10:02

@JFinal 请问我想给Cache类加个扩展方法。要怎么做?是不是要自己仿RedisPlugin重新写个plugin。

i++

2017-03-10 09:19

@JFinal 要这么用:
byte[] s = jedis.hget(FstSerializer.me.keyToBytes(key),FstSerializer.me.fieldToBytes(field));
System.out.println(new String(s));

i++

2017-03-09 22:12

@JFinal 我用的是jfinal2.2的。 getCounter(key)方法只有一个参数,但我用的是hincrBy()方法,不是incr方法啊。郁闷 。难道3.0的getCounter有两个参数了?

i++

2017-03-09 20:52

@JFinal 用hincrBy方法放入的数据用hget时也出现这个错误了。要怎么办?急。。在线等。

i++

2016-07-19 11:23

条条大道通罗马,但我希望的是。有一个基础框架给出的有且只有一条相对好走能通的路。因为是基础框架,给那么多实现方式,不同的人用起来就会选择自己的方式,提供的方式多了,每个方式都要去改进,越改越多,多了再改,就会像spring一样,越来越大,到最后就背离了你的初忠了。多种传参方式,路由方式,要不要baseMode,其实只要提供一种就好了。要扩展的自己的扩,jfinal官方实在要做也弄个不同分支出来。有喜欢的人下有这些功能的。不喜欢的用原来的。