【Debug日志】1:初学S2SH的一些bug

当我通过反复翻看笔记,解决了下面第一个错误”域模型注入失败”时,我发觉要开始写Debug日志了,有些错误实在太容易忽略。

缺失public无参构造器使域模型注入失败

错误

当执行到:

Login usrLgn = ln_d.validate(ln.getXh(), ln.getPassword());

ln空引用异常,它是Action中的成员:

private Login ln;

本应通过域模型注入进来,反复检查找不到错。

解决

笔记11有总结过:

在域模型注入时就是要先用这个无参构造器建立出一个对象,再用setter方法往里面传值的

检查我的Login类(一个PO类),确实因为只写了有参构造器覆盖了原来的无参构造器,手动写一个即可。注意需要是public类型,才能控制反转给框架。

错把HQL当SQL尝试操作表和字段

错误

当执行到:

Query qry = sssn.createQuery("from LOGIN where XH=? and PASSWORD=?");

出现错误:

org.hibernate.hql.internal.ast.QuerySyntaxException: LOGIN is not mapped [from LOGIN where XH=? and PASSWORD=?]
解决

因为HQL逻辑上操作的是PO对象和对象的属性,而不是数据库表和表中字段。应当改为类名和属性名:

Query qry = sssn.createQuery("from Login where xh=? and password=?");

javassit的jar包冲突

错误

当执行到:

Login lgn = (Login) qry.uniqueResult();// 执行查询

报错:

java.lang.ClassCastException: myModel.Student_$$_javassist_1 cannot be cast to javassist.util.proxy.Proxy
解决

一个Hibernate的,一个Sturts2的:
这里写图片描述
删去一个低版本的,然后祈求高版本的能向下兼容即可。

文件上传缺少辅助对象 & 表单提交重复

错误

修改个人信息,表单中可以上传文件:
这里写图片描述
提交时总是返回INPUT视图。检查控制台发现警告:

严重: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'phoContentType' on 'class myAction.MyInfoAction: Error setting expression 'phoContentType' with value ['image/png', ]
五月 11, 2018 10:00:26 上午 com.opensymphony.xwork2.interceptor.ParametersInterceptor error
严重: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'phoFileName' on 'class myAction.MyInfoAction: Error setting expression 'phoFileName' with value ['照片_去文字.png', ]
五月 11, 2018 10:00:26 上午 com.opensymphony.xwork2.interceptor.ParametersInterceptor error
严重: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'stu.stuId' on 'class myAction.MyInfoAction: Error setting expression 'stu.stuId' with value ['1', '刘知昊', ]
五月 11, 2018 10:00:26 上午 com.opensymphony.xwork2.util.LocalizedTextUtil warn
警告: Missing key [invalid.fieldvalue.stuId] in bundles [[org/apache/struts2/struts-messages, com/opensymphony/xwork2/xwork-messages]]!
五月 11, 2018 10:00:26 上午 com.opensymphony.xwork2.util.LocalizedTextUtil warn
警告: Missing key [invalid.fieldvalue.stu.stuId] in bundles [[org/apache/struts2/struts-messages, com/opensymphony/xwork2/xwork-messages]]!

似乎和照片上传有关,在JSP中这一部分是:

<tr>
    <td>照片:</td>
    <!-- 上传照片 -->
    <td>
        <s:file name="pho"/>
    </td>
</tr>

在Action中关于它只组合了:

private File pho;// 照片文件

并提供了getter和setter。

解决

为文件上传的File对象提供两个辅助字段:

private String phoContentType;// 该文件对象(pho)的类型
private String phoFileName;// 该文件对象(pho)上传时的文件名

并提供getter和setter,消除了前两个警告。但依然返回INPUT视图,现在警告是:

严重: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'stu.stuId' on 'class myAction.MyInfoAction: Error setting expression 'stu.stuId' with value ['1', '刘知昊', ]
五月 11, 2018 10:05:03 上午 com.opensymphony.xwork2.util.LocalizedTextUtil warn
警告: Missing key [invalid.fieldvalue.stuId] in bundles [[org/apache/struts2/struts-messages, com/opensymphony/xwork2/xwork-messages]]!
五月 11, 2018 10:05:03 上午 com.opensymphony.xwork2.util.LocalizedTextUtil warn
警告: Missing key [invalid.fieldvalue.stu.stuId] in bundles [[org/apache/struts2/struts-messages, com/opensymphony/xwork2/xwork-messages]]!

错误信息中说stu.stuId被传入了一个值列表,里面有一个值1,还有一个值是名字。应该是页面提交问题,检查发现:

<tr>
    <td>学号:</td>
    <td>
        <!-- 学号是只读的,不能修改 -->
        <input type="text" name="stu.stuId" value="<s:property value="#request.stu.stuId"/>" readOnly/>
    </td>
</tr>
<tr>
    <td>姓名:</td>
    <td>
        <input type="text" name="stu.stuId" value="<s:property value="#request.stu.name"/>" />
    </td>
</tr>

在传姓名时的域模型注入目标使用了学号,所以出错,改正即可。

此外,学号既然是只读的,应当只显示不可提交,而不是仅在JSP上使其readOnly,学号可以在服务器端通过会话查出来。

懒加载导致没有获得成员对象

错误
Struts has detected an unhandled exception:

Messages:   
failed to lazily initialize a collection of role: myModel.Course.student, could not initialize proxy - no Session
File:   org/hibernate/collection/internal/AbstractPersistentCollection.java
Line number:    575

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: myModel.Course.student, could not initialize proxy - no Session

Course使用了student的集合作为成员,表示一个课有多个选课学生:

private Set<Student> student = new HashSet<Student>();

并且配置了映射文件:

<!-- N课程对应M个学生,加载课程时不必立即加载选课学生,控制反转-->
<set name="student" table="SC" lazy="true" inverse="true">
    <key column="COURSEID"/>
    <many-to-many class="Student" column="STUID"/>
</set>

意为在加载课程对象时不必立即加载选课学生,且inverse="true"控制反转将控制权交给学生对象,表示这个N-M映射关系由学生(的选课退课)来维护。

在学生提交个人信息时,为了不改变选课信息,将选课信息重新写到了域模型注入的对象中:

// 学生要提交自己的修改个人信息
public String updtCmmt() throws Exception {
    StudentDAO stu_d = new StudentDAOImp();
    ProfessDAO pf_d = new ProfessDAOImp();
    // 把提交的专业整合到提交的其它信息(Student对象)里
    stu.setZy(pf_d.getOneProfess(pf.getPfId()));
    // 处理传上来的照片文件
    if (this.pho != null) {
        // ...把照片存入数据库...
    } else {
        stu.setZp(stu_d.getOneStu(stu.getStuId()).getZp());
    }
    // 处理课程(也是直接重新设定一次)
    stu.setCourse(stu_d.getOneStu(stu.getStuId()).getCourse());
    System.out.println(stu);
    // 更新
    stu_d.update(stu);
    return SUCCESS;
}
解决

获取的课程中显然没有再去包含选课学生,这对单个学生来说也是不必要的。而PO持久化时这样的课程却是异常的,因为其中的学生没有了。

可以先去读出DB中的对象,在Session关闭后成为脱管对象,再在该对象上修改属性再重新变为PO存入DB。

// 学生要提交自己的修改个人信息
public String updtCmmt() throws Exception {
    StudentDAO stu_d = new StudentDAOImp();
    ProfessDAO pf_d = new ProfessDAOImp();
    // 获取PO的脱管对象
    Student stu_tmp = stu_d.getOneStu(stu.getStuId());
    // 处理专业
    stu_tmp.setZy(pf_d.getOneProfess(pf.getPfId()));
    // 处理传上来的照片文件
    if (this.pho != null) {
        // ...把照片存入数据库...
    } else {
        // 什么都不用做,脱管对象里自己有之前的
    }
    // 处理其它没有依赖其它对象的直接属性
    stu_tmp.setBz(stu.getBz());
    stu_tmp.setCssj(stu.getCssj());
    stu_tmp.setName(stu.getName());
    stu_tmp.setSex(stu.getSex());
    stu_tmp.setZp(stu.getZp());
    stu_tmp.setZxf(stu.getZxf());
    // 课程不需要动,在PO脱管里
    // 更新,让脱管对象变回PO,并持久化到数据库
    stu_d.update(stu_tmp);
    return SUCCESS;
}

照片没有成功存到blob字段中

错误

在Hibernate自顶向下将byte[]生成为tinyblob后,不能按课本上的方法上传照片。查了一下tinyblob只能支持最大255B的文件,改为blob(最大65KB)依然不行。

检查了表单,有配置enctype="multipart/form-data"无误;检查了映射文件中该字段的映射:

<property name="zp" type="binary" column="ZP"/>

Java的byte[]映射类型为binary,也没有错。

检查了文件对象本身传入Action的情况,编写(注意如果为该文件对象建立了输入流,要先将输入流关闭):

// 存到本地试试
String dataDir = "E:/home/";
File saveFile = new File(dataDir, phoFileName);
pho.renameTo(saveFile);

能够正确上传到本地,说明传入Action也是正常的:
这里写图片描述
在read之后尝试输出也没有问题:

for (byte b : buffer) {
    System.out.println(b + " ");
}

能够输出很多不同的数字。在数据库里改blob的长度也改不了,说明这种大型对象长度是自动的,不是手工设定的,它只有一个最大限制长度。

解决

直到我在后面看到了这句代码:

stu_tmp.setZp(stu.getZp());

被它覆盖了,删去就好。最终这部分的代码:

// 学生要提交自己的修改个人信息
public String updtCmmt() throws Exception {
    StudentDAO stu_d = new StudentDAOImp();
    ProfessDAO pf_d = new ProfessDAOImp();
    // 获取PO的脱管对象
    Student stu_tmp = stu_d.getOneStu(stu.getStuId());
    // 处理专业
    stu_tmp.setZy(pf_d.getOneProfess(pf.getPfId()));
    // 处理传上来的照片文件
    if (this.pho != null) {
        // 存到本地试试
        // String dataDir = "E:/home/";
        // File saveFile = new File(dataDir, phoFileName);
        // pho.renameTo(saveFile);
        // 读到byte数组里
        InputStream fis = new FileInputStream(pho);
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        // 尝试直接设定给stu_tmp这个脱管对象
        stu_tmp.setZp(buffer);
        fis.close();
        System.out.println("[scss]pho对象不为空");
    } else {
        // 什么都不用做,脱管对象里自己有之前的
        System.out.println("[debug]pho对象为空");
    }
    // 处理其它没有依赖其它对象的直接属性
    stu_tmp.setBz(stu.getBz());
    stu_tmp.setCssj(stu.getCssj());
    stu_tmp.setName(stu.getName());
    stu_tmp.setSex(stu.getSex());
    stu_tmp.setZxf(stu.getZxf());
    // 课程不需要动,在PO脱管里
    // 更新,让脱管对象变回PO,并持久化到数据库
    stu_d.update(stu_tmp);
    return SUCCESS;
}

上传效果:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值