springboot 上傳檔案並回寫
阿新 • • 發佈:2019-02-20
做的時候查看了很多部落格,也遇到了很多不經意的問題,如下
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一樣的