2020-03-25 10:52

me.setToClassPathSourceFactory() 是去jar 包和 Class Path 下读文件,而你的 html 仍然放在了 webwebapp 下

2020-03-24 21:22

@小风yy 抛异常的原因是:
1:Db.find(Db.getSql("demo.customer")); 查出来的字段是实时的,也就是说你添加了字段 remark1 以后,上面的代码再执行时,会获取到 remark1 这个字段的值

2:ActiveRecordPlugin 在启动时,会对所有映射的 Model 进行初始化,这个过程会从数据库获取字段名

3:出于安全性考虑,Model._setAttrs(...) 这个方法会检测放入的字段是否存在,而这时使用的字段是前面第二步在启动时初始化决定的

4:由于添加了 remark1 这个字段, Model._setAttrs 检测时发现这个字段在内存中不存在,抛出异常

知道了原理,根据情况解决一下。

其实我在前面的回复中已经给出了几种解决办法,就看你用不用

2020-03-24 20:30

@小风yy 添加字段就是动态改变数据表结构

你的项目正在运行中,但你为表添加了字段,不抛异常才是错的

2020-03-24 20:19

为什么要查询出来用 Record, 然后 update 的时候再用回 Model ?

这种用法太奇怪了

要么全用 Record , 要么全用 Model

Record 也可以保存:
Db.save("customer", records.get(0));


当前你这种用法之下,如果仅仅是希望不出现异常的话,将
new Customer()._setAttrs(...)
改成
new Customer().put(...) 即可

put 方法不检查你的字段是否存在,就不会报异常。但这种用法你自己要注意是否有安全隐患,为什么要动态动改数据表的结构?

2020-03-24 19:01

这里有几点说明:
1:#(sum.expense / sum.budget) 这种用法,sum.expense 与 sum.budget 变量的值取决于其本身的类型,这个一定要通过调试搞清楚,到底是 float 还是 double 类型

2:#(10396.08 / 954095.26) 这种用法,其中的 10396.08 与 954095.26 常量会被 enjoy 转换成 Double 类型

所以,确定 sum.expense 与 sum.budget 变量的类型是关键,如果这两个变量的类型都是 Double 的话,那输出结果应该是完全一样的

通过上面的推断, sum.expense 与 sum.budget 变量的类型应该不是 Double

2020-03-24 18:45

@himans 我发现你的 #number 指令传递的 format 表达式不对,改成下面用法试一下:
#number(sum.expense / sum.budget, "#.##%")

不是 "0.00%", 而是 "#.##%"

注意要用 #number 指令来测试

2020-03-24 18:40

具体的类在 com.jfinal.template.expr.ast.Arith.java

2020-03-24 18:39

@himans
需要调试 enjoy Arith.java 的计算细节,你那正好有这个测试用例

希望你能就你当前碰到的这些数值在 Arith.java 内调试,看每一步计算的结果,到底哪一步与预期不符

希望你继续反馈这个问题

2020-03-24 15:04

@liugz 使用新版本的脚本,下载首页的 jfinal_demo_for_maven.zip ,从里面拿到最新版本

2020-03-24 15:03

请求 /evox/about 这类 url 不存在,仅此而已

2020-03-24 15:02

文档中有很明确的说明,参考一下:
https://jfinal.com/doc/1-11

2020-03-24 11:53

@himans 用 #number 指令,不要用输出指令

2020-03-23 21:34

@杜福忠 connection 资源耗尽后的 getConnection() 会等待,达到最长等待时间会抛异常,最长等待时间之内获取到 connection 后流程继续

不同的连接池实现可能有所不同,druid 中有一个 maxWait 配置最长等待时间,其它连接池不一定有这个

2020-03-23 18:22

@goodJfinal 区分数据源建议在更高层去区分,而不要在 sql 层面,更不要在 sql 模板层面,太不优雅

用拦截器就是一个很好的切换数据源的办法,在拦截器中只需要根据当前请求账号来切换就可以了,切换的具体代码大至如下:
Account account = getLoginAccount();

String ds = account.getDataSourceName();
Config config = DbKit.getConfig(ds);

// 将 Connection 对象绑定到 ThreadLocal,也就是绑定到当前线程
Connection conn = config.getDataSource().getConnection();
config.setThreadLocalConnection( conn );

try {
inv.invoke();
}
finally {
conn.close();
}


核心在于对当前线程绑定 connection 对象,绑定后,后续的数据库操作都会依赖于这个 connection,而这个 connection 的 DataSource 对象又是与当前登录账号相关联的