解决产品添加页面中有提交文件的解决思路
设计原则
在jsp页面的表单里面
<form action="ArticleServlet" enctype="multipart/form-data" method="post">
<input type="hidden" name="method" value="add"><div>
<input type="text" name="title" id="title" value="" size="60" maxlength="200" /> </div>后台xxxServlet中
无法通过这种方式进行后台表单数据的接收
String name = request.getparameter(title);
为什么呢?
因为在xxxServlet中 doPost() doGet()方法中没法接收到method方法!!
解决思路见图
使用装饰流设计模式包装httpServletRequest
定义这样一个类
class MultipartrequestWrapper extends HttpRequestWrapper {
public MultipartRequestWrapper(HttpServletRequest request) {
super(request);
//首先判断是否multipart编码类型
//如果是multipart编码类型,就逐个从request中取出各个表单域//contentType:multipart/form-data; boundary=---------------------------317894718690 //如果表单域是普通的表单域,则将它的值取出,放到allParams中(通过表单上传到服务器是通过requestUtil.copyParam()) //如果表单域是文件,则 //1、把文件先存储到磁盘的某个目录中! //2、把文件的有关信息(名称,类型,上传时间)包装成Attachment[]类型 //3、把包装好的Attachment[]类型,放到allParams中 //拿到迭代器
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request); if(!isMultipart){ allParams = request.getParameterMap(); }else{ // Create a new file upload handler allParams = new HashMap(); ServletFileUpload upload = new ServletFileUpload(); FileItemIterator iter = upload.getItemIterator(request); while(iter.hasNext()){ FileItemStream item = iter.next();//拿到表单域对象 String name = item.getFieldName();//拿到表单域的名称 //得到表单域得值(这是一个输入流) InputStream stream = item.openStream(); //如果是普通表单域 if(item.isFormField()){ String value = Streams.asString(stream,request.getCharacterEncoding()); //此处不能直接allParams.put(name,value);如果在表单处有两个相同字段都需要保存下来,如若不保存后面会覆盖前面的 addFieldsAndValuesToMap(name, value); }else{ //文件附件类型 if(stream.available()!=0){ //如果是ie浏览器上传就会把路径也提交上来 //而我们只需要文件名 String filename = item.getName(); if(filename!=null){ //为了解决IE上传本地文件路径问题 filename = FilenameUtils.getName(filename);//只需要文件名不需要路径 } //3是否自动关闭 Streams.copy(stream,new FileOutputStream("D:/temp/update/"+filename), true); Attachment attachment = new Attachment(); attachment.setContentType(item.getContentType()); attachment.setName(filename); attachment.setUploadTime(new Date()); //如果是多个文件 addFieldsAndValuesToMap(name, attachment); } } } } }catch (Exception e) { e.printStackTrace(); }}
//为了处理多个上传文件
private void addFieldsAndValuesToMap(String name, Attachment value) { Attachment[] fieldValues = (Attachment[]) allParams.get(name); if(fieldValues==null){ allParams.put(name, new Attachment[]{value}); }else{ //如果不为空说明map集合里面已经有一份了 //'sex','male'界面又传来一个表单仍然需要保存 //'sex','male',null fieldValues = Arrays.copyOf(fieldValues, fieldValues.length+1); //再给新数组赋值 fieldValues[fieldValues.length-1]=value;//给最后一个赋值最新的value allParams.put(name, fieldValues);// } }/**
* 目标实现数组的拷贝 * @param name * @param value * map的键是唯一的 */ private void addFieldsAndValuesToMap(String name, String value) { String[] fieldValues = (String[]) allParams.get(name); if(fieldValues==null){ allParams.put(name, new String[]{value}); }else{ //如果不为空说明map集合里面已经有一份了 //'sex','male'界面又传来一个表单仍然需要保存 //'sex','male',null fieldValues = Arrays.copyOf(fieldValues, fieldValues.length+1); //再给新数组赋值 fieldValues[fieldValues.length-1]=value;//给最后一个赋值最新的value allParams.put(name, fieldValues);//{'sex','male','male'} } }@Override
public String getParameter(String name) { String[] values = (String[]) allParams.get(name); if(values != null){ return values[0]; } return null; }@Override
public Map getParameterMap() { return allParams; }public Map getAllParams() { return allParams; }
public void setAllParams(Map allParams) {
this.allParams = allParams; }}}
如此在xxxServlet中
Attachment[] attachments = (Attachment[])request.getParameterMap().get("attachs");
if(attachments != null){ for(Attachment atta : attachments){ System.out.println(atta.getName()+",已经被上传,文件类型是:"+atta.getContentType()); a.addAttachments(atta);// GRASP模式中专家模式的运用 } }在baseServlet中悄悄得把httpServletRequest替换成MultipartServletRequest
这样在客户端的servlet就依赖于MultipartServletRequest request
@Override
public String getParameter(String name) { String[] values = (String[]) allParams.get(name); if(values != null){ return values[0];} return null;}
@Override
public Map getParameterMap() { return allParams;}