JFinal

登录 注册
  • i++
    @JFinal 其实我自己不是用SqlKit.SQL_PARA_KEY 我自己用自己的常量了。只是发出来时改成这个了。没注意看这个不是public的。我改下
    08-26 16:31 回复
  • i++
    @JFinal 今天看了3.2这部份源码。我并不认同这种把问题抛给使用者以自选的方式处理。原因
    1.没有几个使用者会认真区分这两个方法的真正区别,大部份人只知道做下表面的试验,能用就好了。而这个问题在平时的开发使用过程中是很难发现问题的。而当应用服务出现问题时他们的第一反应是:jfinal这个框架不行。谨慎点的开发者看到了注释为了安全起见,他们往往会默认选择不缓存。不缓存性能相对就差点。
    2.模板的主要特点就是可重用性,我是真想不到有什么业务场景要用到模板但只执行一次的。既然要使用多次,那么进行缓存肯定是比较好的。所以做为应用的底层默认是要缓存的。
    3.这个问题的根源是在缓存方法中默认使用content的md5当key,做为一个开发框架的底层不应该使用这种有局限性的实现方法。所以要让方法通用,应该让使用者自己设置缓存的key。提供默认不缓存engine.getTemplateByString(content) 和默认缓存engine.getTemplateByString(key,content)两个方法。再提供engine.setTemplateCacheMaxSize()设置最大缓存条数,实现当缓存达到最大值时自动清除。或用设置有效期的方式,在jfinal框架本身把这个问题解决掉。而不是让使用者自己选择只能缓存某一类的数据,这样的约定在开发过程中的业务层是很常见,但在开发的框架底层使用这样的约定就会影响到使用业务的范围。
    08-14 15:37 回复
  • i++
    @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值是两码事
    08-12 16:49 回复
  • i++
    我觉得jfinal在赋值sqlPara时,发现sql语句是的?没有对应的参数时,应该按正常的业务思维逻辑抛出参数缺失的异常,因为是通用接口,所以我不好在接口中对参数进行校验。也不能在sqltemplate中写#if()判断。@jfinal
    08-12 11:36 回复
  • i++
    @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());
    }
    07-06 19:56 回复
  • i++
    @JFinal String 型 Template 做缓存还是很有必要的。建议别去掉。即使String 型的不做templateCache。只有文件类型的做templateCache,templateCache也会一直增大的。因为文件(html)模板会重命名,会删除,而且文件模板不会太小。要是怕做先进先出的缓存影响性能,至少做个最大量的限制,超过了就全部删除,总比让他无限增长,内存用尽好。这个最大量让使用者可以自己根据服务器内存情况设置。
    06-23 15:50 回复
  • i++
    @JFinal 手动 remove cache时需要知道key。但我们并不知道无用的key是什么。请问有办法获取templateCache的大小吗。当templateCache等于一定量时,我们用removeAllTemplateCache()也行啊。
    06-23 15:35 回复
  • i++
    @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);
    }

    就可以了。
    03-20 19:23 回复
  • i++
    @JFinal 请问我想给Cache类加个扩展方法。要怎么做?是不是要自己仿RedisPlugin重新写个plugin。
    03-10 10:02 回复
  • i++
    @JFinal 要这么用:
    byte[] s = jedis.hget(FstSerializer.me.keyToBytes(key),FstSerializer.me.fieldToBytes(field));
    System.out.println(new String(s));
    03-10 09:19 回复
  • i++
    @JFinal 我用的是jfinal2.2的。 getCounter(key)方法只有一个参数,但我用的是hincrBy()方法,不是incr方法啊。郁闷 。难道3.0的getCounter有两个参数了?
    03-09 22:12 回复