struts2图片文件上传经验总结

  说到文件上传,最开始想到的用JSPSmartUpload完成图片上传。后来放弃,因为它适用于普通动态网页,而我的网站是s2sh的。查到用struts2的文件上传最适合,以下就是开发经验。

  首先,导入相应的包,我用的是struts2的标签<s:form>,其中特别重要的两个属性method="post" enctype="multipart/form-data"。里面是<s:file name="pic">,再加一个<s:submit value="上传"/>,文件上传输入页面完成。

  该页面通过struts.xml文件的设置,对应到相应的Action类,类里面有 

  private File pic;
  private String picFileName;

  和其get和set方法。File pic对应<s:file name="pic">,而String picFileName并没有在输入页面设置,它从何而来呢?

  原来它是系统默认并自动传递的参数,只需把File的name加上“FileName”,String picFileName里就会有值,在Action类就可以使用。好神奇啊。

  接收上传文件数据的代码,可以在Action类中定义,以下是代码:

  public String add() throws Exception{
  DateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");
  String formatdate=format.format(new Date());
  int random=new Random().nextInt(10000);
  int position=picFileName.lastIndexOf(".");
  String extension=picFileName.substring(position);
  String newfilename=formatdate+random+extension;
  
  String realPath=ServletActionContext.getServletContext().getRealPath("images/product");
  File saveFile=new File(realPath,newfilename);
  FileUtils.copyFile(pic, saveFile);
  product.setPic("images/product/"+newfilename);
  productServiceImpl.add(product);

  return SUCCESS;}

通过System.out.print(picFileName);显示了当前上传的文件名,可是马上又提示错误,说File pic的值为null。嗯?这是怎么回事?文件名都可以传递,文件本身却为空。

难到要在struts.xml里设置Fileupload的interceptor拦截器,研究下来,不需要。

在success.jsp里写${pic},显示有上传文件tmp存在。而这个tmp文件在Action里却“收不到”。说明这个传递被“某些东西”阻挡了。

经过不停的调试,发现问题竟然是Action类的接口:ModelDriven。去除此接口以及它的getModel()方法,File pic里就有值了,大功告成。

上传的文件大小要在2M以内,类型可以是图片,MP3,txt等。

把这些写下来,勉励自己,提示他人。

 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我说过,文件上传功能与struts2的ModelDriven是冲突的。

有ModelDriven接口的action会拦截File pic对象,导致上传出错。
我现在要做一个product_updateInput.jsp顾名思义,这是产品更新的导入页。
要把action类中的product对象传到product_updateInput.jsp的文件中,再把product的字段导入文本域。
我之前做过把product_addInput.jsp新建产品输入页中的数据传到product_add.action中,并数据库保存成功。
即jsp传递数据到action成功,但action传递数据到jsp,尚在研究中。
我的代码是:
 public String updateInput() throws Exception{
  ActionContext.getContext().put("cs", categoryServiceImpl.listAllCategory());
  Product tp=productServiceImpl.load(id);
  product.setName(tp.getName());//*
  return SUCCESS;
 }
运行后,*号行报错,报空指针异常。action无法传递数据到jsp。


 public String add() throws Exception{

  DateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");
  String formatdate=format.format(new Date());
  int random=new Random().nextInt(10000);
  int position=picFileName.lastIndexOf(".");
  String extension=picFileName.substring(position);
  String newfilename=formatdate+random+extension;
  
  String realPath=ServletActionContext.getServletContext().getRealPath("images/product");
  File saveFile=new File(realPath,newfilename);
  FileUtils.copyFile(pic, saveFile);//*
  

  product.setPic("images/product/"+newfilename);
  productServiceImpl.add(product,cid);
  //System.out.print(product);
  return SUCCESS;
 }
无奈,只好加了ModelDriven接口和getModel()方法,传输数据成功。但同时,文件上传功能*号行开始报错。
另说一句,只有加了ModelDriven接口,product对象才会出现在值栈的顶端(值栈的底端是ProductAction)。
于是我又在“ModelDriven接口”和“文件上传功能”上纠结,出现了鱼和熊掌不能兼得的情况。
我开始想解决办法。
即然是FileUtils.copyFile(pic, saveFile);出问题,我就改另一种上传方法。

 public String add() throws Exception{

  DateFormat format=new SimpleDateFormat("yyyyMMddHHmmss");
  String formatdate=format.format(new Date());
  int random=new Random().nextInt(10000);
  int position=picFileName.lastIndexOf(".");
  String extension=picFileName.substring(position);
  String newfilename=formatdate+random+extension;
  
  String realPath=ServletActionContext.getServletContext().getRealPath("images/product");


  
  BufferedOutputStream bos=null;
  BufferedInputStream bis=null;
  try{
   FileInputStream fis=new FileInputStream(pic);
   bis=new BufferedInputStream(fis);
   FileOutputStream fos=new FileOutputStream(new File(realPath,newfilename));//*
   bos=new BufferedOutputStream(fos);
   byte[] buf=new byte[1024];
   int len=-1;
   while((len=bis.read(buf))!=-1){
    bos.write(buf,0,len);
   }
  }finally{
   try{
    if(bis!=null){
     bis.close();
    }
   }catch(IOException e){
    e.printStackTrace();
   }
   
   try{
    if(bos!=null){
     bos.close();
    }
   }catch(IOException e){
    e.printStackTrace();
   }
  }
  
  
  product.setPic("images/product/"+newfilename);
  productServiceImpl.add(product,cid);
  //System.out.print(product);
  return SUCCESS;
 }

可是,*号行报错,这个方法也不行。
我想让文件上传功能,避开ModelDriven接口,于是我把文件上传代码写到Service类的方法中,再由继承ModelDriven接口的Action类“调用”。
但是没用,因为Action类接收不到File pic,调用失败。
我想自己写个拦截器,拦截Action类使其通过文件上传,避开ModelDriven,仔细想想,这不可能,于是也放弃了。

我想研究避开ModelDriven接口,实现action传递数据到jsp,才是可行的。
action里传参数,只有实行<result type="redirectAction">才能使用<parem>参数,但还要指定一个"actionName",这是不符合我的项目设定,所以不可用。

我在struts.xml加了
  <action name="product_updateInput" class="productAction" method="updateInput">
   <result>/admin/product_updateInput.jsp?product=${product}</result>
  </action>
即在文件名?后“传递”参数,结果么,果然是失败的。
最后,我在updateInput()方法里,写了System.out.println(product);得到的是null,我很吃惊。
我一直以为,Action 类中已经有了从jsp文件传来的product类,product类是包含数据的,有“内容”的类。
如果product类是null的话。我单单写product.setName(tp.getName());这句代码,是会出“问题”的。于是我加了一句……
product=new Product();
完整代码为

 public String updateInput() throws Exception{
  ActionContext.getContext().put("cs", categoryServiceImpl.listAllCategory());//使商品类型下拉框显示数据库里的值<s:select list="#cs" listKey="id" listValue="name" name="cid" />
  Product tp=productServiceImpl.load(id);//从数据库中导入数据
  product=new Product();
  product.setName(tp.getName());//使jsp的文本域显示数据库中的数据
  return SUCCESS;
 }
我的天,Action传递数据到jsp成功!<input type="text" name="product.name" value="${product.name}"/>

 

  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 使用java.util.Map接口实现文件组的上传 */ private void muchUploadFile(IndexActionForm objForm) { Map<String, FormFile> fileList = objForm.getFileList(); for(String str : fileList.keySet()) if((fileList.get(str)).getFileSize() > 0 && (fileList.get(str)).getFileSize() < BUFFER_SIZE) { String fileName = DIRECTORY +"/"+ fileList.get(str).getFileName(); try { this.fileStream( fileList.get(str).getInputStream(), fileName, fileList.get(str).getFileSize()); } catch (IOException ex) { System.out.println(ex.getMessage()); } } } /* * 使用org.apache.strtus.upload.FormFile实现文件的单一上传 */ private void singleUploadFile(IndexActionForm objForm) { if(objForm.getFile().getFileSize() == 0|| BUFFER_SIZE < objForm.getFile().getFileSize()) throw new RuntimeException("文件过大或不存在!!!"); String fileName = DIRECTORY +"/"+ objForm.getFile().getFileName(); try { this.fileStream( objForm.getFile().getInputStream(), fileName, objForm.getFile().getFileSize()); } catch (IOException ex) { System.out.println(ex.getMessage()); } } /* * copy 到本地目录 */ private void fileStream(InputStream strem, String fileName, int size) { byte[] buffer = new byte[size]; try { InputStream in = null; OutputStream out = null; try{ in = new BufferedInputStream(strem, size); out = new BufferedOutputStream(new FileOutputStream(fileName), size); while(in.read(buffer) > 0) out.write(buffer); }finally { if(null != in) in.close(); if(null != out){ out.flush(); out.close(); } } System.out.println("Uploading Success!!!"); } catch (IOException ex) { System.out.println(ex.getMessage()); } }
struts2是一种基于Java的开源框架,用于开发Web应用程序。在早期版本的struts2中存在一个安全漏洞,即struts2 020任意文件下载。这个漏洞允许攻击者下载服务器上的任意文件,可能是敏感信息或者可执行文件。 当一个struts2应用程序被配置为使用动态方法调用(DMI)时,攻击者可以构造一个恶意的URL请求,通过漏洞获取和下载任意文件。攻击者可以通过URL中的特殊字符和参数来伪造请求,并使用已知文件路径的结尾来读取文件内容或执行文件。 为了解决这个漏洞,struts2社区发布了相应的安全补丁。开发者应该及时升级他们的struts2版本,并遵循最佳实践来防止任意文件下载漏洞。 以下是一些防止struts2 020任意文件下载漏洞的措施: 1. 及时更新struts2版本:确保使用的是最新的稳定版本,这样可以最大程度地减少已知漏洞带来的风险。 2. 输入验证和过滤:对用户输入进行验证和过滤,尤其是文件的路径或文件名参数。可以使用安全的文件路径自检函数,如struts2提供的FileUploadInterceptor。 3. 安全配置:在struts.xml配置文件中,禁用动态方法调用(DMI),并限制只允许访问必要的Action方法。 4. 强化访问控制:确保只有授权用户能够访问敏感文件,并在服务器上采取必要的安全措施来限制对文件的访问。 5. 安全审计:定期进行安全审计,查找潜在的漏洞和弱点,并修复它们。 总的来说,struts2 020任意文件下载漏洞是一个严重的安全威胁。为了保护应用程序和服务器的安全,开发者应该及时升级版本,并采取适当的安全措施来防止攻击者利用这个漏洞获取敏感信息或执行恶意文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值