在一个应用系统里,会有上传本地文件到系统服务器里或从系统服务器查看、下载有关文件到本地的需要。这里只对自己了解到的做一个总结

文件上传

这里是把本地文件上传到服务器文件目录,而不是放到项目目录里。

前端用的bootstrap和Jquery,上传文件界面显示在是模态框里

//文件上传
<input id="uploadFile" type="file" name="file" style="margin-left: 90px; margin-top: 10px">
<!-- 模态框 -->
	<div class="modal fade" id="newImg">
		<div class="modal-dialog">
			<div class="modal-content">
				<div class="modal-header">上传新的流程图</div>
				<!-- <form class="form-horizontal"> -->
					<div class="modal-body">
						<div class="form-group">
							<label for="inputEmail" class="col-sm-2 control-label">添加描述</label>
							<div class="col-sm-10">
								<input id="describle" type="text"
									class="form-control list-inline" />
							</div>
						</div>
						<div class="form-group">
							<label class="control-label" style="margin-left: 30px">待上传的文件</label>
							<div style="margin-left: 20px">
								<label class="control-label">输入记录id</label> 
								<input type="text" id="relId_ajax" name="relId_ajax">
								<input id="uploadFile" type="file" name="file" style="margin-left: 90px; margin-top: 10px">
							</div>
						</div>
						<div class="modal-footer">
							<button id="back_btn" class="btn btn-danger" data-dismiss="modal">取消</button>
							<button class="btn btn-success" onclick="submit_btn()" data-dismiss="modal">上传</button>
						</div>
					</div>
				<!-- </form> -->
			</div>
		</div>
	</div>

点击上传之后。调用JS方法使用ajax方法进行上传。上传成功之后,接收到后端返回的信息,并再次调用ajax请求对这些信息进行处理。这些信息后面会提到

//上传新的流程图(单文件上传,ajax方式)
		function submit_btn(){
			var relId = $("#relId_ajax").val();
			var fileDescribe = $("#describle").val();
			var file = $("#uploadFile")[0].files[0];

			var formData = new FormData();

			formData.append("file", file);
			formData.append("relId", relId);
			formData.append("fileDescribe", fileDescribe);
			
			$.ajax({
				dataType : "JSON",
				contentType : "application/json;charset=UTF-8",
				type : "POST",
				data : formData,
				url : "/hzsh/eomc-front/file/multiUpload",
				processData : false, // 使数据不做处理
				contentType : false, // 不要设置Content-Type请求头
				success : function(result) {
					console.log(result)
					console.log(result.msg)
					var JsonData = JSON.parse(result.data) //将后端传回的json数组字符串转换为json对象 
                                                     //[{"fileName":"compareWithAll.PNG","id":"4b267540-1d97-4703-85b8-6522ee26843f"}]
					var imgId = JsonData[0].id;
					console.log(imgId);   
						$.ajax({
							type:"post",
							url:"/hzsh/eomc-zzhj/nyglms/updateImg",
							data:{"imgId":imgId},
							success:function(result){
								console.log("进行流程图更新")
								if(result.code){
									alert("上传成功")
								}else{
									alert("上传失败")
								}
							}
						})
				},
				error : function() {
					console.log("上传出错");
				}
			})
		}

效果如图:(这里我上传的是图片)

java文件上传的原理 java文件上传功能_文件上传


点击上传之后,会先将文件保存到数据库的附件表里,这张表就是对上传的文件元数据做统一的管理,包括文件类型、文件原名、文件大小、上传时间、上传用户等等。因为考虑到文件安全问题,上传的文件经过后端处理,存到服务器端文件目录里的文件名是一串随机字符串序列。

@RequestMapping("/file/multiUpload")
    public String multiUpload(HttpServletRequest request, HttpServletResponse response,HttpSession session) {
    
    	try {
    		
        	String userName = (String) session.getAttribute("userName");
        	
        	String fileDescribe = request.getParameter("fileDescribe");
        	String relId = request.getParameter("relId");
        	String sort = request.getParameter("sort");
        	
        	log.info("文件描述" + fileDescribe);
        	List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        	boolean result = true;
        	String retMsg = "";
        	JSONArray retDataArray = new JSONArray();
            for (int i = 0; i < files.size(); i++) {
                MultipartFile file = files.get(i);
                if (file.isEmpty()) {
                	
                	retMsg += "第" + (i + 1) + "个文件为空";
                	continue;
                }
                String fileName = file.getOriginalFilename();

                //定义附件表对象,用于将上传的文件元数据写入附件表
                CommAttachEntity commAttachEntity = new CommAttachEntity();
                commAttachEntity.setId(UUID.randomUUID().toString());
                commAttachEntity.setRealName(fileName);
                commAttachEntity.setEncName(commAttachEntity.getId());
                int extendIndex = fileName.indexOf(".");
                if(extendIndex < 0) {
                	
                	extendIndex = 0;
                }
                commAttachEntity.setExtendName(fileName.substring(extendIndex));
                if(CDataUtil.isPicture(fileName)) {
                	
                	commAttachEntity.setFileType("图片");
                }else if(CDataUtil.isDocument(fileName)) {
                	
                	commAttachEntity.setFileType("文档");
                }else {
                	
                	commAttachEntity.setFileType("未知");
                }
                
                commAttachEntity.setFlgDel("0");
                commAttachEntity.setFileSize(file.getSize() + "");
                commAttachEntity.setCreateUser(userName);
                commAttachEntity.setCreateDate(CDateTimeUtil.sysDateTime("yyyy-MM-dd HH:mm:ss"));
                commAttachEntity.setRemark(fileDescribe);
                commAttachEntity.setRelId(relId);
                if(sort == null || sort.trim().equals("")) {
                	
                	 commAttachEntity.setSort(i + "");
                }else {
                	
                	 commAttachEntity.setSort(sort);
                }

                //文件输出到本地
                File dest = new File(EnvConstant.attachPath + commAttachEntity.getEncName());
                try {
                    file.transferTo(dest);
                    log.info("第" + (i + 1) + "个文件上传成功(" + fileName + ")");
                } catch (Exception e) {
                	log.error("第" + (i + 1) + "个文件上传失败(" + fileName + ")" + e.toString(), e);
                	result = false;
                	retMsg += fileName + ";";
                }
                
                //写入附件表
                commAttachMapper.insert(commAttachEntity);
                JSONObject retDataJson = new JSONObject();
                
                retDataJson.put("id", commAttachEntity.getId());
                retDataJson.put("fileName", fileName);
                retDataArray.add(retDataJson);
            }
          System.out.println(retDataArray+"KKKKKKKKKKKKKKKKKKK");
            if(result) {
            	System.out.println("上传成功");
            	return CIOUtil.buildRetMsg(true, "上传成功", retDataArray);
            }else {
            	return CIOUtil.buildRetMsg(false, retMsg + " 文件上传失败", retDataArray);
            }
           
    	}catch(Exception e) {
    		return CIOUtil.buildRetMsg(false, "文件上传出错", e.getMessage());
    	}
    }

上面这段代码就是对前端发送来的文件进行处理,生成一些文件元数据保存到数据库对应的附件表里。附件表主键就是在这里生成的随机序列:UUID.randomUUID()

该接口代码处理完文件信息后一方面将文件元数据传到数据库,

//写入附件表
             commAttachMapper.insert(commAttachEntity);

一方面将文件保存到对应的文件目录里,其中 EnvConstant.attachPath 是之前在类中定义好的
文件保存路径

//文件输出到本地
                File dest = new File(EnvConstant.attachPath + commAttachEntity.getEncName());
                file.transferTo(dest);

另一方面向前端返回一些信息

if(result) {
            	System.out.println("上传成功");
            	return CIOUtil.buildRetMsg(true, "上传成功", retDataArray);
            }else {
            	return CIOUtil.buildRetMsg(false, retMsg + " 文件上传失败", retDataArray);
            }

像前端返回的信息里包含了很重要的一项,就是随机生成的文件序列,也是文件上传后保存到服务器端目录里的文件加密名,这里的ajax请求是在点击“上传”后的JS方法里,是一个回调请求。

success : function(result) {
					console.log(result)
					console.log(result.msg)
					var JsonData = JSON.parse(result.data) //将后端传回的json数组字符串转换为json对象 
                                                     //[{"fileName":"compareWithAll.PNG","id":"4b267540-1d97-4703-85b8-6522ee26843f"}]
					var imgId = JsonData[0].id;
					console.log(imgId);   
						$.ajax({
							type:"post",
							url:"/hzsh/eomc-zzhj/nyglms/updateImg",
							data:{"imgId":imgId},
							success:function(result){
								console.log("进行流程图更新")
								if(result.code){
									alert("上传成功")
								}else{
									alert("上传失败")
								}
							}
						})
				},

将随机生成的文件字符串序列保存到业务表里,作为外键和附件表进行关联。因为这里模拟的是特定业务的文件上传,业务里文件只有一个,所以上传文件属于更新操作。文件信息保存到业务表里始终只有一条记录。

@ResponseBody
	@RequestMapping("/nyglms/updateImg")
	public String updateNyglmsImg(HttpServletRequest request, HttpServletResponse response, HttpSession session) {

		// 获取CommAttachEntity对象流程图的Id信息
		String imgId = request.getParameter("imgId");
		// 将CommAttachEntity的流程图id信息写到nyglms表中
		String userName = (String) session.getAttribute("userName");

		DateFormat df = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
		Calendar calendar = Calendar.getInstance();
		String create_img_time = df.format(calendar.getTime());

		EomcZzhjNyglmsEntity eomcZzhjNyglmsEntity = new EomcZzhjNyglmsEntity();
		eomcZzhjNyglmsEntity.setId(1);
		eomcZzhjNyglmsEntity.setCreateImgUser(userName);
		eomcZzhjNyglmsEntity.setCreateImgTime(create_img_time);
		eomcZzhjNyglmsEntity.setImgId(imgId);

		int result = eomcZzhjNyglmsService.updateNyglmsImg(eomcZzhjNyglmsEntity);

		if (result == 1) {
		  return CIOUtil.buildRetMsg(true, "上传成功", null);
		} else {
		   return CIOUtil.buildRetMsg(false,  "上传失败,请重新上传", null);
		}

	}

文件查看

此时,文件上传操作已经完成。当我们想在功能模块里查看已上传的文件时,只需发送请求到后端的业务表里获取唯一的文件随机字符串序列,并将字符串序列和文件保存路径进行拼接。这里使用IO流的方式将特定文件写出到前端页面。

@ResponseBody
	@RequestMapping("/nyglms/queryImg")
	public String queryNyglmsImage(HttpServletRequest request, HttpServletResponse response) {
		// 获取最新上传的流程图片信息(从业务表中)
	   EomcZzhjNyglmsEntity eomcZzhjNyglmsEntity =	eomcZzhjNyglmsService.queryNyglmsImg();
	   String imgId = eomcZzhjNyglmsEntity.getImgId();
	   System.out.println("查询流程图************************:"+imgId);
		try {
			File file = new File(EnvConstant.attachPath +imgId);
			FileInputStream fis = new FileInputStream(file);
			OutputStream out = response.getOutputStream();
			long size = file.length();
			byte[] temp = new byte[(int) size];
			fis.read(temp, 0, (int) size);
			fis.close();
			byte[] data = temp;
			response.setContentType("image/PNG");
			// data = Base64.encodeBase64(data);
			out.write(data);
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return CIOUtil.buildRetMsg(true, "显示流程图成功", null);
	}

前端代码:

<div>
			<img id="Img" alt="" src="/nyglms/queryImg" style="height: 400px; width: 600px;" />
	 </div>

文件下载

可以从附件表获取文件随机字符串序列,也可以从业务表中获取。
这里从业务表中获取更容易一些(点击前端下载按钮,调用该后端接口)

/**
	 * a根据附件名称,下载附件
	 * @param fileName
	 * @param request
	 * @param response
	 * @param model
	 * @return
	 */
	@RequestMapping("/file/download")
	public String download( HttpServletRequest request, HttpServletResponse response ,Model model) {
			// 获取最新上传的流程图片信息(从业务表中)
	   EomcZzhjNyglmsEntity eomcZzhjNyglmsEntity =	eomcZzhjNyglmsService.queryNyglmsImg();
	   String imgId = eomcZzhjNyglmsEntity.getImgId();
		if(getImgId== null || getImgId.trim().equals("")) {
			
			log.info("imgId为空,无法下载附件");
			return CIOUtil.buildRetMsg(false, "imgId不能为空", null);
		}
        //设置为png格式的文件
		setHeader(request, response, imgId);
        byte[] buff = new byte[1024];
        //创建缓冲输入流
        BufferedInputStream bis = null;
        OutputStream outputStream = null;

        try {
            outputStream = response.getOutputStream();

            //这个路径为待下载文件的路径
            bis = new BufferedInputStream(new FileInputStream(new File(EnvConstant.attachPath + imgId)));
            int read = bis.read(buff);

            //通过while循环写入到指定了的文件夹中(这里指浏览器设置的目录文件夹)
            while (read != -1) {
                outputStream.write(buff, 0, buff.length);
                outputStream.flush();
                read = bis.read(buff);
            }
        } catch ( IOException e ) {
            e.printStackTrace();
            //出现异常返回给页面失败的信息
            model.addAttribute("result","下载失败");
            return "下载失败";
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //成功后返回成功信息
        model.addAttribute("result","下载成功");
        return CIOUtil.buildRetMsg(true, "下载成功", null);
	}
	

private boolean setHeader(HttpServletRequest request, HttpServletResponse response, String fileName) {
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("content-type", "application/octet-stream");
            String browser = request.getHeader("User-Agent");
            if (-1 < browser.indexOf("MSIE 6.0") || -1 < browser.indexOf("MSIE 7.0")) {
                // IE6, IE7 浏览器
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else if (-1 < browser.indexOf("MSIE 8.0")) {
                // IE8
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("MSIE 9.0")) {
                // IE9
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Chrome")) {
                // 谷歌
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Safari")) {
                // 苹果
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else {
                // 火狐或者其他的浏览器
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            }
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }