真正在Jfinal的学习上进了一步。不过理解还不够透彻,对render的理解还需再深入研究。
最初并没有考虑通过render来实现,但在controller中实现这个功能时,图片也能显示,但就是在后台总有错误,具体为:java.lang.IllegalStateException: ......
在网上找了很多资料,说是与jsp页面显示时自动执行的out.getWriter()重复调用导致。但实际我是用的beetl模板,这样看来beetl模板执行了类似前面说的out.getWriter(),从而造成冲突。
后来想到在jfinal的验证码和二维码中实现了类似的功能,于是参考实现了以下图片显示类。
--------
应波总鼓励,代码贴出来,请波总和大家指导一下:(ImageRender类的实现主要参考了JFinal验证码和二维码的实现)
页面的代码:
<img src="/pijianattach/showAttImage/${imgId}">
Cotroller中的方法:
/** * 从数据库中读取二进制内容 */ public void showAttImage() { int id=getParaToInt(0); PijianAttachModel att = PijianAttachModel.dao.findById(id); String sExt=att.getStr("附件扩展名"); render(new ImageRender(att.getBytes("附件内容"),sExt.replaceAll("\\.", ""))); }
ImageRender类:
package com.base.controller; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletOutputStream; import com.jfinal.kit.LogKit; import com.jfinal.render.Render; import com.jfinal.render.RenderException; /** * 图片的输出类 * @author Administrator * */ public class ImageRender extends Render { protected InputStream inputStream; protected String sFileExt; @Override public void render() { //response.setHeader("Pragma","no-cache"); //response.setHeader("Cache-Control","no-cache"); //response.setDateHeader("Expires", 0); response.setContentType("image/"+this.sFileExt); byte buf[] = new byte[1024]; //定义缓存大小 ServletOutputStream sos = null; try { sos = response.getOutputStream(); while (inputStream.read(buf) != -1) { sos.write(buf); } } catch (IOException e) { if (getDevMode()) { throw new RenderException(e); } } catch (Exception e) { throw new RenderException(e); } finally { if (sos != null) { try {sos.close();} catch (IOException e) {LogKit.logNothing(e);} } } } /** * 构造函数。 * @param is 输出流 * @param sExt 文件扩展名,或者叫文件类型。此处不带“.”。如jpg */ public ImageRender(byte[] bytes,String sExt){ this.inputStream=new ByteArrayInputStream(bytes); this.sFileExt=sExt; } }
为方便大家参考,下面是附件的入库操作:
附件上传对应的Controller中的方法:
//文件上传 public void uploadPijianAtt(){ // TODO Auto-generated method stub try { // 获取上传的文件 UploadFile uf=getFile(); //验证扩展名 String enableExt=".doc,.docx,.jpg,.jpeg,.png,.zip,.rar,"; String fileExt=FileUtils.getFileType(uf.getFileName()).toLowerCase(); // if(enableExt.contains(fileExt+",")) { //另存为 //String saveAsName=""; //saveAsName=FileUtils.uploadfile(uf, "upload/tempfiles"); //读取文件,写入数据库 FileInputStream fis = new FileInputStream(uf.getFile()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); //附件表的模型 PijianAttachModel pjatt=new PijianAttachModel(); //获取文件内容 byte[] read = new byte[1024]; int len = 0; while((len = fis.read(read))!= -1){ bos.write(read,0,len); } // pjatt.set("附件内容", bos.toByteArray()); pjatt.set("附件大小", bos.toByteArray().length);//此处是否有更好的方法? pjatt.set("附件名称", uf.getFileName()); pjatt.set("附件扩展名", fileExt); fis.close(); bos.close(); // pjatt.save(); //删除上传的临时文件 FileUtils.delDirOrFile(uf.getUploadPath()+"/"+uf.getFileName()); // renderJson(0,pjatt.get("编号")); }else { renderJson(1,"文件格式不正确,请上传"+enableExt+"格式的文件。"); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); renderJson(1,"上传出错。"); } }
文件操作工具类中的相关处理方法:
/** * 获取文件的类型 * @param fileName * @return 文件类型扩展名,如:.jpg */ public static String getFileType(String fileName){ String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());// 后缀 return suffix; } /** * 删除文件夹或文件 * * @param path 要删除的路径或文件,文件应带路径 * @return */ public static void delDirOrFile(String path) { File f = new File(path);// 定义文件路径 //判断路径是否存在 if(f.exists()){ //判断是文件还是文件夹 if(f.isDirectory()){ //目录 // 若有则把文件放进数组,并判断是否有下级目录 File delFile[] = f.listFiles(); int i = f.listFiles().length; for (int j = 0; j < i; j++) { if (delFile[j].isDirectory()) { delDirOrFile(delFile[j].getAbsolutePath());// 递归调用del方法并取得子目录路径 } delFile[j].delete();// 删除文件 } }else{ //文件 f.delete(); } } }
在界面上,使用了ajaxfileupload的js组件,上传后,将附件id返回界面,用于主记录保存。
扩展:
一般用户上传的附件可能会很大,尤其在现在手机像素越来越高的情况下,拍照的图片文件会达到10M以上,而对于库中保存不需要这么大的文件,清晰度够用就行。因此,可以考虑将图片进行压缩处理,如像素降低后再入库,这样更省空间。