上传文件,本质上都是包含以几个步骤:
1.客户端向服务器发送http请求
2.客户端向请求路径写二进制数据
3.服务器读二进制数据
写数据到磁盘(即保存文件到服务器)
保存文件路径到数据库表的路径字段html
下面介绍几个实际应用场景。java
1.基于开源file-upload实现
封装了读二进制流的处理
最后,获得文件项集合List<FileItem>android
2.基于struts2实现
也是基于开源file-upload
只不过结合struts2,封装得更加好用
最后,获得文件数组File[] web
File[]是Action类的数据 算法
3.基于springMVC实现
同struts2spring
生成二维码图片数据库
1.第一次访问
1)生成二维码
保存二维码到服务器
2)保存二维码路径到数据库apache
2.第二次访问
根据数据库的路径字段,访问服务器二维码存放路径数组
控制器浏览器
/** * * <pre> * 生成合伙人二维码 * </pre> * @author gzh * @date 2017年3月30日下午8:33:29 */ public String doGenerateHeHuoRenQRcode() throws IOException { try { ProxyUser proxyUser = (ProxyUser) getSessionAttribute("proxyUser"); //判断是否已经生成二维码 Proxy proxy2 = proxyService.getProxyById(proxyUser.getProxyId()); if (proxy2.getQrCode() != null) { //已生成 //输出数据 String imgUrl = ConfigUtil.PROXY_LOOKPATH_QRCODE + File.separator + proxy2.getQrCode(); // imgUrl = imgUrl.replaceAll("\\\\", "/"); setRequestAttribute("imgUrl", imgUrl); }else { //未生成 if(!isNotNullOrEmpty(proxyUser.getInviteCode())){ proxyUserService.updateProxyUserInviteCode(proxyUser); } ProxyUser pu = proxyUserService.getProxyUser(proxyUser); // 生成二维码 StringBuffer toHeHuoRenUrl = new StringBuffer(ConfigUtil.TO_HEHUOREN_URL_QRCODE); //代理商-生成二维码图片的路径 //toHeHuoRenUrl.append(proxyUser.getId()); toHeHuoRenUrl.append(pu.getInviteCode()); String logoPath = "";// 二维码Logo StringBuffer imgPath = new StringBuffer(ConfigUtil.PROXY_UPLOADPATH_QRCODE);// 代理商-二维码图片的上传路径 String date = DateUtils.getInstance().today1(); //判断日期目录是否存在 File dateDir = new File(imgPath + File.separator + date); if (!dateDir.exists()) { //不存在 dateDir.mkdirs(); } String imgName = date + File.separator + UuidGenerator.getUuidGenerator() + "." + IMAGE_TYPE; // 图片名称 imgPath.append(File.separator).append(imgName); try { QRCodeComm.encoderQRCode(toHeHuoRenUrl.toString(), imgPath.toString(), IMAGE_TYPE, logoPath); } catch (Exception e) { log.error("HeHuoRen.doGenerateHeHuoRenQRcode() error " + e); return ""; } //保存二维码路径 Proxy proxy = new Proxy(); proxy.setId(proxyUser.getProxyId()); proxy.setQrCode(imgName.toString()); int result = proxyService.updateProxy(proxy); if (result == 0) { log.error("HeHuoRen.doGenerateHeHuoRenQRcode() error: update t_proxy failed!"); } //输出数据 String imgUrl = ConfigUtil.PROXY_LOOKPATH_QRCODE + File.separator + imgName; setRequestAttribute("imgUrl", imgUrl); } } catch (Exception e) { log.error("doGenerateHeHuoRenQRcode() error", e); return ""; } return "success"; }
向第三方支付通道进件
第三方支付向银行通道或其余第三方支付通道(例如,支付宝和微信)进件
1.app发送请求
1)http请求路径
2)往请求路径写二进制流
3)http请求对象的内容类型content-type字段,须要设置为多媒体类型
2.后台接收请求
1)基于上传文件开源框架-apache fileupload读二进制流
上传文件框架会把二进制流转换为文件对象(框架里的文件对象,与jdk的File不是一个东西)
2)从文件对象取文件流
3)读文件流
4)写数据到服务器磁盘
后台控制器代码
注:app发送http请求时,确保2点,1.往请求路径写二进制流数据 2.请求类型字段content-type的值,设置为多媒体类型
package com.dinpay.dpp.cpmobile.action.cpinfo; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.dinpay.dpp.pmsmobile.comm.PmsBaseAction; /** * * <pre> * 类的名称: * 类的做用:进件 * 1.商家进件到第三方支付公司通道 * 2.第三方支付公司通道再把数据进件到支付宝和微信 * </pre> * * @author gzh * @date 2017年12月21日下午12:00:47 */ public class IntoPieceAction extends PmsBaseAction { /** * */ private static final long serialVersionUID = 5706369770419859939L; private static Log log = LogFactory.getLog(PayInAction.class); /** * * <pre> * 进件 * 1、上传图片 * 1.读文件流数据 * 2.写数据到本地磁盘(即保存文件到本地服务器) * 3.文件存放路径 * * 2、进件 * </pre> * @author gzh * @date 2017年12月21日下午12:03:43 */ public void doIntoPiece() { String savePath = getServletContext().getRealPath("/photo/intoPiece"); // 获得上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不容许外界直接访问,保证上传文件的安全 String tempPath = getServletContext().getRealPath("/photo/intoPieceTemp"); // 上传时生成的临时文件保存目录 File tmpFile = new File(tempPath); if (!tmpFile.exists()) { tmpFile.mkdir(); } try { DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(1024 * 100); factory.setRepository(tmpFile); ServletFileUpload upload = new ServletFileUpload(factory); // upload.setProgressListener(new ProgressListener() { // public void update(long pBytesRead, long pContentLength, // int arg2) { // System.out.println("文件大小为:" + pContentLength + ",当前已处理:" // + pBytesRead); // /** // * 文件大小为:14608,当前已处理:4096 文件大小为:14608,当前已处理:7367 // * 文件大小为:14608,当前已处理:11419 文件大小为:14608,当前已处理:14608 // */ // float f = pBytesRead / pContentLength; // try { // getHttpResponse().getWriter().write(f + ""); // } catch (IOException e) { // // Auto-generated catch block // e.printStackTrace(); // } // // } // }); upload.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(getHttpRequest())) { // 判断提交上来的数据是不是上传表单的数据 return; } upload.setFileSizeMax(1024 * 1024 * 5); upload.setSizeMax(1024 * 1024 * 5 * 5); List<FileItem> list = upload.parseRequest(getHttpRequest()); for (FileItem item : list) { if (item.isFormField()) { // 若是fileitem中封装的是普通输入项的数据 String name = item.getFieldName(); String value = item.getString("UTF-8"); log.info(name + "=" + value); } else { // 若是fileitem中封装的是上传文件 String filename = item.getName(); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不一样的浏览器提交的文件名是不同的,有些浏览器提交上来的文件名是带有路径的,如: // c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename .substring(filename.lastIndexOf("\\") + 1); String fileExtName = filename.substring(filename .lastIndexOf(".") + 1); // 获得上传文件的扩展名 log.info("上传的文件的扩展名是:" + fileExtName); // 若是须要限制上传的文件类型,那么能够经过文件的扩展名来判断上传的文件类型是否合法 //读文件流数据 InputStream in = item.getInputStream(); // 获取item中的上传文件的输入流 String saveFilename = makeFileName(filename); // 获得文件保存的名称 String realSavePath = makePath(saveFilename, savePath); // 获得文件的保存目录 log.info(realSavePath); FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename); // 建立一个文件输出流 byte buffer[] = new byte[1024]; int len = 0; // 判断输入流中的数据是否已经读完的标识 while ((len = in.read(buffer)) > 0) { // 循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 //写数据到本地磁盘 out.write(buffer, 0, len); // 使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\"+ filename)当中 } in.close(); out.close(); item.delete(); } } // TODO 进件 } catch (FileUploadBase.FileSizeLimitExceededException e) { e.printStackTrace(); return; } catch (FileUploadBase.SizeLimitExceededException e) { e.printStackTrace(); return; } catch (Exception e) { e.printStackTrace(); } } /** * @Method: makeFileName * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称 * @Anthor:孤傲苍狼 * @param filename * 文件的原始名称 * @return uuid+"_"+文件的原始名称 */ private String makeFileName(String filename) { // 2.jpg // 为防止文件覆盖的现象发生,要为上传文件产生一个惟一的文件名 return UUID.randomUUID().toString() + "_" + filename; } /** * 为防止一个目录下面出现太多文件,要使用hash算法打散存储 * * @Method: makePath * @Description: * @Anthor:孤傲苍狼 * * @param filename * 文件名,要根据文件名生成存储目录 * @param savePath * 文件存储路径 * @return 新的存储目录 */ private String makePath(String filename, String savePath) { // 获得文件名的hashCode的值,获得的就是filename这个字符串对象在内存中的地址 int hashcode = filename.hashCode(); int dir1 = hashcode & 0xf; // 0--15 int dir2 = (hashcode & 0xf0) >> 4; // 0-15 // 构造新的保存目录 String dir = savePath + "\\" + dir1 + "\\" + dir2; // upload\2\3 // upload\3\5 // File既能够表明文件也能够表明目录 File file = new File(dir); // 若是目录不存在 if (!file.exists()) { // 建立目录 file.mkdirs(); } return dir; } }