3.2K Star 8.8K Fork 3.6K

GVPJFinal / JFinal

 / 详情

关于controller层getModel后数据处理时,为啥一定要求前后数据类型一定一致呢?

已完成
创建于  
2015-06-13 15:22

前几天遇到这样的一种情况:

表单提交了一个日期,格式是 yyyy-mm-dd (前端插件输出的)。

我打算在后端做一个转换,将字符串时间转换成时间戳然后存入数据库:

Activity m = getModel(Activity.class);
m.set("start_time", Tools.datetimeToTimestamp(getPara("activity.start_time")));
m.save();

然后紧接着就遇到一个500,错误信息大概如下:

[ERROR]-[Thread: qtp16393153-18]-[com.jfinal.core.ActionHandler.handle()]: /act/new/save
java.lang.RuntimeException: Can not convert parameter: activity.start_time

Caused by: java.lang.NumberFormatException: For input string: "2015-06-01"

我以为弄错了,怀疑set并未起效然后翻到一篇文章:
http://www.oschina.net/question/245971_124636

发现方法完全一样。

最终才注意到,他的参数前后类型是相同的(str->str),而我的前后类型是不同的(str->long)。

我觉得完全没有必要这样啊,为什么数据都改变了,还要对旧数据进行类型转换呢?很不理解。

评论 (11)

异常信息没贴完全,据推测 jdbc 在保存数据时,发现原本要求 starg_time 为datetime类型 却被传入的是 timestamp,从而造成的数据类型转换错误,这个转换 jfinal 并未干预,jfinal 只是直接把将参数和 sql 直接扔给了 jdbc,贴出更详细的异常,以及数据表结构才能弄清楚最终原因: desc tableName

数据表是这样的

mysql> desc activity;
+------------+------------+------+-----+---------+----------------+
| Field      | Type       | Null | Key | Default | Extra          |
+------------+------------+------+-----+---------+----------------+
| id         | bigint(20) | NO   | PRI | NULL    | auto_increment |
| uid        | bigint(20) | NO   |     | NULL    |                |
| title      | text       | YES  |     | NULL    |                |
| brief      | text       | YES  |     | NULL    |                |
| content    | text       | YES  |     | NULL    |                |
| price      | double     | YES  |     | NULL    |                |
| post_time  | bigint(20) | YES  |     | NULL    |                |
| start_time | bigint(20) | YES  |     | NULL    |                |
| over_time  | bigint(20) | YES  |     | NULL    |                |
| state      | int(11)    | YES  |     | NULL    |                |
+------------+------------+------+-----+---------+----------------+
10 rows in set

因为是原型项目做的比较对付。

整篇的错误比较长 当时就没贴。如果你需要的话,我一会开起来项目弄一个完整版。

上面代码中的 Tools.datetimeToTimestamp(...) 返回值让它是 long 即可打完收工

@JFinal

Tools.datetimeToTimestamp 这个返回值本来就是Long

public static Long datetimeToTimestamp(String datetime);

其实看LOG就知道并不是这个错误,如果返回的值仍是string,那么至少转换为时间戳的数据应该不再是 "2015-06-01"

start_time 是 bigint(20) 类型,那么jdbc 映射为的 java 类型是 Long型,所以出现这个问题非常诡异,按理说是正确的。我在 jfinal.com 中的 expireAt 字段就是这样用的,完全没事:

mysql> desc session;
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id        | varchar(33) | NO   | PRI | NULL    |       |
| accountId | int(11)     | NO   |     | NULL    |       |
| expireAt  | bigint(20)  | NO   |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
3 rows in set (0.14 sec)
调试一下 com.jfinal.plugin.activerecord.TableBuilder 看一下 start_time 是否被映射成了 Long 类型,你用的是哪个版本的 jfinal ?

我明天试一下。

当时提问题的时候,还是上一个版本,我换成2.0看看。

问题依旧存在,完整LOG如下:

2015-06-24 16:14:58
[ERROR]-[Thread: qtp16393153-22]-[com.jfinal.core.ActionHandler.handle()]: /act/new/save
java.lang.RuntimeException: Can not convert parameter: activity.start_time
	at com.jfinal.core.ModelInjector.injectActiveRecordModel(ModelInjector.java:102)
	at com.jfinal.core.ModelInjector.inject(ModelInjector.java:50)
	at com.jfinal.core.ModelInjector.inject(ModelInjector.java:37)
	at com.jfinal.core.Controller.getModel(Controller.java:647)
	at tuan.action.activity.ActivityController.publishAdd(ActivityController.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:71)
	at com.jfinal.validate.Validator.intercept(Validator.java:72)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:65)
	at tuan.Interceptor.LoginInterceptor.intercept(LoginInterceptor.java:20)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:65)
	at com.jfinal.ext.interceptor.POST.intercept(POST.java:30)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:65)
	at tuan.Interceptor.JspInterceptor.intercept(JspInterceptor.java:26)
	at com.jfinal.aop.Invocation.invoke(Invocation.java:65)
	at com.jfinal.core.ActionHandler.handle(ActionHandler.java:74)
	at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:72)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1307)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:453)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:560)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1072)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:382)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1006)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
	at org.eclipse.jetty.server.Server.handle(Server.java:365)
	at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:485)
	at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:937)
	at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:998)
	at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:856)
	at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
	at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628)
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NumberFormatException: For input string: "2015-06-05"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:589)
	at java.lang.Long.parseLong(Long.java:631)
	at com.jfinal.core.TypeConverter.convert(TypeConverter.java:62)
	at com.jfinal.core.ModelInjector.injectActiveRecordModel(ModelInjector.java:98)
	... 42 more

代码如下:


    @ActionKey("/act/new/save")
    @Before({POST.class, LoginInterceptor.class, ActEditValidator.class})
    public void publishAdd()
    {
       Activity m = getModel(Activity.class);
        m.set("uid", getSessionAttr("user_id"));
        m.set("start_time", Tools.datetimeToTimestamp(getPara("activity.start_time")));
        m.set("over_time", Tools.datetimeToTimestamp(getPara("over_time")));
        m.set("now_time", Tools.getNowTime());
        m.set("state", ActivityState.SELLING.ordinal());
        m.save(); // BUG: 这里居然无法修改数据

        ...
    }

通过异常看到,你从前端页面传进去的参数是"2015-06-05",而 jfinal 在系统启动的时候通过反射 "activity.start_time"字段,断定该字断为 Long型,所以在 getModel 的时候会试图将 "2015-06-05" 转换成 Long 型数据,必须会抛出这个异常,简单解决办法是为个这段在前端取名为 "start_time" 而非 "activity.start_time",这样的话 getModel 就不会处理这个字段,然后再这样:m.set("start_time", Tools.datetimeToTimestamp(getPara("start_time")))

原来 getModel() 的时候就已经出错了吗?

这下我明白了来龙去脉,之前还以为是save的时候报错来着,怪不得会如此!

@傻大影子 写程序时没调试? 错误要精准定位,才知道如何解决

状态更改为 已关闭

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(2)
840 jfinal 1580661334 77892 fy0 1578916546
Java
1
https://gitee.com/jfinal/jfinal.git
git@gitee.com:jfinal/jfinal.git
jfinal
jfinal
JFinal

搜索帮助