1. 程式人生 > >springboot 上傳檔案並回寫

springboot 上傳檔案並回寫

做的時候查看了很多部落格,也遇到了很多不經意的問題,如下

1,關於上傳路徑的問題,由於springboot內建tomcat,打包之後為jar包,無法上傳檔案至專案內部,查詢網上有很多解決方案,未見生效,下面為我的解決方案:上傳至伺服器預設資料夾:

程式碼如下:

首先是設定上傳檔案的檢視路徑,相當於配置路徑

${my.upload.base.dir}為在application.properties的配置,如下

#上傳路徑   windows端的配置,用於本地
my.upload.base.dir=D:/upload/

#linux伺服器端配置,選擇自己想上傳的資料夾

my.upload.base.dir=/root/upload/

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;


@Configuration
public class WebSecurityConfig extends WebMvcConfigurerAdapter {
    
    @Value("${my.upload.base.dir}") 
	private String uploadBaseDir;

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/ImgFile/**").addResourceLocations("file:"+uploadBaseDir+"ImgFile/");
		super.addResourceHandlers(registry);
	}
	
}

所有的配置都完成,後面為功能程式碼:

頁面程式碼:

<label><!-- 可以選取一張或者多種圖片上傳  multiple -->
	<input type="file" name="glycosylated_hemoglobin" multiple accept="image/jpg,image/jpeg,image/png,image/bmp">
	<span>上傳檢驗單</span>
</label>
$(function(){
	$("input[type='file']").change(function(){
		var files = $(this).prop('files');//獲取到檔案列表
		if (files.length == 0) {
            alert('請選擇檔案');
	    } else {
	    	//判斷選擇的檔案大小
	    	 var fileSize = 0;
	    	 for(var i = 0; i < files.length; i++) {
	    			fileSize += files[i].size;
	    	 }
	         var size = fileSize/1024/1024;//此處以兆為單位
	         if(size>50){
	            alert("附件不能大於50M");
	            target.value="";
	            return;   //阻止submit提交
	         }
        	 $(this).attr("disabled","disabled");
             saveAndUpdateFile($(this),files);
	    }
	})
	
})

var saveAndUpdateFile = function (that,files){
	var imgSrc = []; //圖片路徑
	var imgFile = []; //檔案流
	var imgName = []; //圖片名字
	
	 var formData = new FormData();
	 formData.append("name", that.attr("name"));  
	 for(var i = 0; i < files.length; i++) {
		formData.append("files", files[i]);   
	 }
	 var fileList = files;
		for(var i = 0; i < fileList.length; i++) {
			var imgSrcI = getObjectURL(fileList[i]);
			imgName.push(fileList[i].name);
			imgSrc.push(imgSrcI);
			imgFile.push(fileList[i]);
		}
	 
	 var url = "/record/uploadImg?version="+Math.random();
	$.ajax({
	    type:'post',
	    url:url,
	    data:formData,
	    async: false,
	    /**
         *必須false才會自動加上正確的Content-Type
         */
	    contentType: false,
	    /**
         * 必須false才會避開jQuery對 formdata 的預設處理
         * XMLHttpRequest會對 formdata 進行正確的處理
         */
	    processData: false,
		success: function (result) {
			that.removeAttr("disabled");
			if(result.statusCode==200){
           //這個頁面主要用於不重新整理頁面時回寫圖片的功能,拿到dom file回寫在頁面,不用可以不要,後面會有重新整理後臺回傳回寫操作
				addNewContent(that.parent().parent().find(".images-box"),imgSrc,imgName,imgFile,result.divid,that.attr("name"));
			}
	    },
	    error: function () {
	    }
	});
}
//主要用於未儲存不重新整理介面時回寫已經上傳過的圖片
function addNewContent(that,imgSrc,imgName,imgFile,ids,name){
	var id = ids.split(":");
	for(var a = 0; a < imgSrc.length; a++) {
		that.append('<div id='+id[a+1]+' class="img"><a href=' + imgSrc[a] + ' target="_blank"><img src=' + imgSrc[a] + ' class="" title=' + imgName[a] + ' alt=' + imgName[a] + ' ></a>'
				+'	<img src="/images/omit.png"  class="delete-img" onclick="deleteImage('+id[a+1]+','+name+')"></div>');
				
	}
}

//本地  不包含後臺圖片預覽路徑
function getObjectURL(file) {
	var url = null;
	if(window.createObjectURL != undefined) { // basic
		url = window.createObjectURL(file);
	} else if(window.URL != undefined) { // mozilla(firefox)
		url = window.URL.createObjectURL(file);
	} else if(window.webkitURL != undefined) { // webkit or chrome
		url = window.webkitURL.createObjectURL(file);
	}
	return url;
}

下面是controller程式碼:

使用ResourceLoader ,需要這行程式碼,img標籤圖片回寫時用

private final ResourceLoader resourceLoader;
    
	@Autowired
    public UploadFileUtil(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
@RequestMapping("/uploadImg")
	@ResponseBody
	 public BJUIResult uploadImg(
	    		@RequestParam("files") MultipartFile[] files,   //多檔案上傳
	    		@RequestParam("name") String name,
	            HttpServletRequest request) {
	    	
			List<Eye> imgs = new ArrayList<Eye>();
			Result ret = new Result();
			try {
				//判斷file陣列不能為空並且長度大於0
				if(files!=null&&files.length>0){
					//上傳files陣列
					
					//迴圈獲取file陣列中得檔案
					for(int i = 0;i<files.length;i++){
						MultipartFile file = files[i];
						String fileName = file.getOriginalFilename();
						
						String uploadPath = "imgFile";
						//realPath:獲取Web專案的全路徑 
						SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//設定日期格式
						
			            String directory = uploadBaseDir + uploadPath + File.separator + df.format(new Date()) + File.separator;
			            UploadFileUtil fileUtil = new UploadFileUtil();
		                String newPicName = fileUtil.saveFile(request, file, directory, fileName);
		                
		                logger.info("---------------------上傳的檢視圖片路徑----------------------"+ uploadPath+File.separator+df.format(new Date())+ File.separator +newPicName);
		                String viewPath = uploadPath+File.separator+df.format(new Date())+ File.separator +newPicName;
				        Eye img = new Eye();
						img.setName(name);
						img.setImgUrl(viewPath);//物件儲存一下圖片瀏覽地址
						img.setImgName(fileName);
						img.setUpdateTime(new Date());
						img.setCreateId(1);
						img.setCreateTime(new Date());
						img.setNowStatus(1);   //已上傳
						img.setType(0);
						imgs.add(img);
						//儲存檔案
					}
				}
				service.saveEyeImg(imgs);//儲存方法我就不提供了,自己去儲存
				String ids = "";
                //用於不重新整理頁面回寫,然後賦值,如果情況允許,應該上傳完成頁面是要重新整理的,所以不用考慮這個情況,後面講了回寫
				for(Eye img : imgs) {
					ids+=":"+img.getId();
				}
				ret.setDivid(ids);
				ret.setMessage("操作成功!");
				ret.setStatusCode(200);
			} catch (Exception e) {
				e.printStackTrace();
			}
	        return ret;
	    }

 public String saveFile(HttpServletRequest request, MultipartFile file, String realPath, String newPicName) throws Exception {
        // 判斷檔案是否為空
        if (!file.isEmpty()) {
            try {
            	
                if (file.getSize() != 0) {
                	String originalFileName = file.getOriginalFilename();
                    // 新的圖片名稱  需要就可以加,由於伺服器同文件夾對於傳同名的會被覆蓋,故需要uuid區分一下
                    newPicName =  originalFileName.substring(0,originalFileName.lastIndexOf("."))+UUID.randomUUID()+
                    		originalFileName.substring(originalFileName.lastIndexOf("."));
                    
                    // 新圖片,寫入磁碟
                    File f = new File(realPath, newPicName);
                    if (!f.exists()) {
                        // 先建立檔案所在的目錄
                        f.getParentFile().mkdirs();
                    }
                    file.transferTo(f);
               }
                return newPicName;
            } catch (Exception e) {
            	throw new Exception(e.getMessage());
            }
        }
        return "";
    }

這麼多程式碼就可以完成上傳操作了,然後是回寫上傳的圖片,一般是上傳結束會進行重新整理,然後回寫圖片,我上面的程式碼有一段js是可以直接回寫本地圖片,在不重新整理情況下,重新整理後顯示上傳的圖片,無縫銜接,大家看自己需求了;

後臺回寫程式碼如下:

<a href="/record/queryPic?id=${img.id}" target="_blank">
	<img src="/record/getFile?id=${img.id}" class="" title="${img.imgName}" alt="${img.imgName}">
</a>

由於我們有個需求是,點選圖片放大,到一個新的頁面,又不能直接給許可權讓使用者直接訪問地址,存在圖片洩露的風險,

如果你的圖片不保密,可以直接,下面的程式碼通過連結訪問,可以成功

<a href="${img.imgUrl}" target="_blank">
	<img src="${img.imgUrl}" class="" title="${img.imgName}" alt="${img.imgName}">
</a>

,controller去訪問,img標籤和a標籤點選的方法不同,程式碼如下:

//顯示圖片的方法   img標籤顯示圖片的方法
		//<img src="/record/getFile?id=${img.id}" class="" title="${img.imgName}" alt="${img.imgName}">
		@RequestMapping("/getFile")
		@ResponseBody
		public ResponseEntity<?> getFile(@RequestParam("id") Integer id) {
			Eye img = service.getEyeImgByImgId(id);
			try {
				return ResponseEntity.ok(resourceLoader.getResource(
	                    "file:" + Paths.get(uploadBaseDir + img.getImgUrl()).toString()));
			} catch (Exception e) {
				return ResponseEntity.notFound().build();
			}
		}
		
		/*
		* 獲取圖片並顯示在頁面  a標籤
		* @return
		* @throws SQLException
		* <a href="/record/queryPic?id=${img.id}" target="_blank">
		
		*/
		@RequestMapping(value = "queryPic")
		public void queryPic(@RequestParam("id") Integer id,HttpServletRequest request, HttpServletResponse response) throws IOException  {  
		
			Eye img = service.getEyeImgByImgId(id);
			if (img.getImgUrl().toString() != null){  
			   response.setContentType("image/jpeg");  
			   FileInputStream is = null;  
			   File filePic = new File(uploadBaseDir + img.getImgUrl().toString());
			   try {
				   	  is = new FileInputStream(filePic);
				   } catch (FileNotFoundException e) {
					   e.printStackTrace();
			   }
			   if (is != null){   
				   int i = is.available(); // 得到檔案大小  
				   byte data[] = new byte[i];  
				   is.read(data); // 讀資料  
				   is.close();  
				   response.setContentType("image/jpeg");  // 設定返回的檔案型別  
				   OutputStream toClient = response.getOutputStream(); // 得到向客戶端輸出二進位制資料的物件  
				   toClient.write(data); // 輸出資料  
				   toClient.close();  
			    }  
			}  
		} 

ok啦,就這麼多程式碼,沒啦,對了,我們前面用的freemaker框架,和jsp一樣的