中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

利用h5做網(wǎng)站的心得公司網(wǎng)頁設(shè)計模板

利用h5做網(wǎng)站的心得,公司網(wǎng)頁設(shè)計模板,南寧網(wǎng)站設(shè)計圖,網(wǎng)站上傳照片的功能怎么用JSP做在絕大多數(shù)的項目中都會涉及到文件上傳等,下面我們來說一下技術(shù)派中是如何實現(xiàn)原生圖片上傳的,這個功能說起來簡單,但其實對于技術(shù)還是有考驗的。圖片的上傳涉及到IO讀寫,一個文件上傳的功能,就可以把IO流涉及到的知識…

在絕大多數(shù)的項目中都會涉及到文件上傳等,下面我們來說一下技術(shù)派中是如何實現(xiàn)原生圖片上傳的,這個功能說起來簡單,但其實對于技術(shù)還是有考驗的。圖片的上傳涉及到IO讀寫,一個文件上傳的功能,就可以把IO流涉及到的知識點全覆蓋,比如字節(jié)流ByteArrayInputStream、緩存流BufferedOutputStream、文件File的讀寫權(quán)限、文件魔數(shù)等等。

如果你想實現(xiàn)一個自己的文件讀寫Util類,需要考慮的細(xì)節(jié)還是很多的,比如靜態(tài)資源的配置、圖片大小限制、前端圖片上傳組件,后端圖片接收參數(shù)MutiparHttpServletRequest等等。

業(yè)務(wù)介紹

技術(shù)派中關(guān)于圖片上傳的入口有三處:

  • ? ? ? ? 發(fā)表文章時
  • ? ? ? ? 上傳文章封面時
  • ? ? ? ? 上傳用戶頭像時

看發(fā)表文章時,涉及到四種方式:

  • ? ? ? ? 通過編輯器的菜單添加圖片。
  • ? ? ? ? 直接復(fù)制一張圖片粘貼到編輯器中
  • ? ? ? ? 復(fù)制外部的圖片鏈接(markdown格式),到編輯器中。
  • ? ? ? ? 導(dǎo)入MD文件到編輯器中(如果圖片有連接時)。

這四種方式都會出發(fā)圖片上傳功能(嚴(yán)格一點,后面兩個還涉及到圖片轉(zhuǎn)鏈)后臺的接口都是一樣的,都調(diào)用的是ImageRestController,上傳圖片調(diào)用的是upload方法,請求參數(shù)為HttpServletRequest;轉(zhuǎn)存圖片鏈接調(diào)用的是save方法,參數(shù)為圖片的外部鏈接。響應(yīng)的結(jié)果為ResVo<ImageVo> ,其中包含最關(guān)鍵的信息------圖片路徑。

代碼實現(xiàn)

第一步,在dev/application-image.yml文件中添加圖片的配置

image:abs-tmp-path: /tmp/storage/web-img-path: /forum/image/tmp-upload-path: /tmp/forum/cdn-host:oss:type: localprefix: paicoding/endpoint:ak:sk:bucket:host: https://cdn.tobebetterjavaer.comspring:web:resources:# 支持本地圖片上傳之后的鏈接,其中 file:///d的用于win系統(tǒng),后面的file: 適用于mac/linux系統(tǒng)static-locations:- classpath:/static/- file:///d:${image.abs-tmp-path}- file:${image.abs-tmp-path}

來解釋一下參數(shù)的含義:

  • ? ? ? ? abs-tmp-path: 存儲的絕對路徑
  • ? ? ? ? web-image-path: 圖片在Web應(yīng)用中的相對路徑
  • ? ? ? ? tmp-upload-path: 上傳文件的臨時存儲目錄
  • ? ? ? ? cdn-host: 圖片的CDN訪問域名(本地不需要)
  • ? ? ? ? oss: 圖片上傳到阿里云OSS時的配置
  • ????????spring: web: resources: static-locations 是Spring Boot提供的一種加載靜態(tài)資源的機(jī)制。

靜態(tài)資源通常包括CSS、JavaScript、圖片等文件,通過設(shè)置????spring: web: resources: static-locations,我們可以告訴 Spring Boot 在哪些位置查找靜態(tài)資源。 Spring Boot 的默認(rèn)靜態(tài)資源位置包括;

當(dāng)我們?yōu)閟pring.web.?resources.?static-locations 提供自定義的值時,Spring Boot會覆蓋這些默認(rèn)值。在技術(shù)派的項目結(jié)構(gòu)中,我們將CSS和javaScript,以及一些圖片資源放在了,paicoding-ui模塊static目錄下。

也就意味著,在我們的前端頁面中,如果遇到類似這樣的<link href="/css/views/home.css" rel="stylesheet" />請求時,Spring Boot將會從 classpath:/static/目錄下去找。

注意,我們還指定了另外兩個靜態(tài)資源位置:?file:///d:${image.abs-tmp-path} 和?file:${image.abs-tmp-path} ,前者用于Windows系統(tǒng) ,后者用于macOS和Linux系統(tǒng)。用macOs舉例,我們會把圖片保存在 /tmp/storage/forum/image目錄下。

也就是說,我們可以通過 http://127.0.0.1:8080/forum/image/20230423060009676_69.jpg這種形式訪問圖片。

file:/是一個URI(統(tǒng)一資源標(biāo)識符)的方案,表示在本地文件上的系統(tǒng)資源。例如,如果你想要引用本地文件系統(tǒng)上的一個文件,可以使用file:/。以下是一些實例:

  • file:/c:/path/to/your/file.txt : 表示在Windows系統(tǒng)上的??c:/path/to/your/file.txt文件。
  • file:/Users/username/path/to/your/file.txt : 表示在macOS或Linux系統(tǒng)上的/Users/username/path/to/your/file.txt文件。

第二步,新建ImageProperties.java類

使用?@ConfigurationProperties 注解使其和配置文件中的圖片配置關(guān)聯(lián)起來。

@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "image")
public class ImageProperties {/*** 存儲絕對路徑*/private String absTmpPath;/*** 存儲相對路徑*/private String webImgPath;/*** 上傳文件的臨時存儲目錄*/private String tmpUploadPath;/*** 訪問圖片的host*/private String cdnHost;private OssProperties oss;public String buildImgUrl(String url) {if (!url.startsWith(cdnHost)) {return cdnHost + url;}return url;}
}
  • @Setter 和 @Getter 是lombok提供的注解,這樣我們就不用寫冗長的getter 和setter。
  • @Component 表示這個類是一個 Spring管理的Bean。
  • @ConfigurationProperties是Spring Boot中用于將外部配置文件(如application.properties
  • 或者application.yml)中的屬性綁定到Java類的一個注解。通過使用這個注解,我們可以將配置文件中的值自動映射到有相應(yīng)字段的Java類中。參數(shù)prefix = "image" 表示將配置文件image作為前綴的屬性綁定到該類中。

第三步,構(gòu)建前端上傳組件和發(fā)起上傳請求。

我們先來看比較簡單的一種,上傳文章封面,在發(fā)表文章的頁面,點擊保存按鈕,會彈出文章封面的上傳模態(tài)框。

代碼非常簡單,用了一個input組件,type為file,接受的文件類型為image。

<input type = "file"accept = "image/*"id = "upload"class = "click-input"
/>

當(dāng)選擇圖片后,會觸發(fā)change事件。

      upload.on("change", function (e) {let objUrl = getObjectURL(this.files[0]) //獲取圖片的路徑,該路徑不是圖片在本地的路徑if (objUrl) {console.log("uploadImg", this.value)uploadImg(() => (this.value = null), objUrl)}})

在事件回調(diào)函數(shù)中,代碼會執(zhí)行以下操作。

  • ? ? 使用 getObjectURL函數(shù)獲取選中文件(this.files[0])的臨時URL。
  • ? ? ? ? 注意,這里的this指向觸發(fā)事件的文件輸入元素。
  • 檢查objUrl是否存在。如果存在,繼續(xù)。
  • 輸出this.value到控制臺,這里的this.value是選中文件的本地路徑(例如:Windows下是: C:\fakepath\file.jpg)
  • 調(diào)用uploadImg函數(shù),并將一個回調(diào)函數(shù)和objUrl作為參數(shù)傳遞。這個回調(diào)函數(shù)將在uploadImage函數(shù)內(nèi)部執(zhí)行(圖片上傳完成后)?;卣{(diào)函數(shù)中,將文件輸入元素的value屬性設(shè)置為null,以清除選中文件。

來看一下getObjectURL函數(shù)(創(chuàng)建一個臨時URL,用于訪問本地文件):

//建立一?可存取到?file的url
const getObjectURL = function (file) {let url = nullif (window.createObjectURL != undefined) {// basicurl = window.createObjectURL(file)} else if (window.URL != undefined) {// mozilla(firefox)url = window.URL.createObjectURL(file)} else if (window.webkitURL != undefined) {// webkit or chromeurl = window.webkitURL.createObjectURL(file)}return url
}

? 這段代碼使用三種不同的方式來創(chuàng)建臨時URL,以確保兼容性:

 window.createObjectURL(file): 這是一個比較舊的方法,用于創(chuàng)建臨時URL。在現(xiàn)代的瀏覽器中,這個方法可能被廢棄。
window.URL.createObjectURL(file): 這是一個比較新的方法,用于創(chuàng)建按臨時URL。在許多現(xiàn)代瀏覽器中(如FIrefox、Chrome、Edge等),這個方法已經(jīng)取代了window.createObjectURL。
 window.webkitURL.createObjectURL(file): 這是一個WenKit特定的方法,用于創(chuàng)建臨時的URL。在基于WebKit的瀏覽器中(如舊版本的Chrome和Safari)這個方法可能是唯一可用的方法。

再來看uploadImge方法(實用jQuery的Ajax實現(xiàn)圖片上傳):

 // 上傳頭圖到服務(wù)器function uploadImg(callback, objUrl) {let uploadPic = upload[0].files[0]console.log("準(zhǔn)備上傳", uploadPic)if (!checkFileSize(uploadPic)) {return;}let file = new FormData()file.append("image", uploadPic)$.ajax({url: "/image/upload",type: "post",data: file,cache: false,contentType: false,processData: false,success: function (data) {console.log("response data", data);if (data.status.code > 0) {// 圖片上傳失敗toastr.error(data.status.msg, "圖片上傳失敗!");return;}const {result: { imagePath },} = data || {}defaults['cover'] = imagePath;//將圖片路徑存入src中,顯示出圖片pic.attr("src", objUrl).css('visibility', 'visible') // 展示圖片$('.upload-icon-up').css('visibility', 'hidden') // 隱藏上傳callback();toastr.info("圖片上傳成功!");},error : function(jqXHR, textStatus, errorThrown) {toastr.error(jqXHR.responseText, "圖片上傳失敗!");},})}

解釋一下代碼:

這段代碼是一個用于上傳圖片到服務(wù)器的函數(shù)。下面是對代碼的解釋:

```javascript
// 上傳頭圖到服務(wù)器
function uploadImg(callback, objUrl) {
? let uploadPic = upload[0].files[0] // 獲取上傳的圖片文件
? console.log("準(zhǔn)備上傳", uploadPic) // 打印準(zhǔn)備上傳的圖片信息

? if (!checkFileSize(uploadPic)) { // 檢查文件大小是否符合要求
? ? return; // 如果不符合要求,直接返回
? }

? let file = new FormData() // 創(chuàng)建一個新的FormData對象
? file.append("image", uploadPic) // 將上傳的圖片文件添加到FormData對象中
? $.ajax({ // 使用jQuery的ajax方法發(fā)送POST請求
? ? url: "/image/upload", // 請求的URL地址
? ? type: "post", // 請求類型為POST
? ? data: file, // 請求的數(shù)據(jù)為FormData對象
? ? cache: false, // 禁用緩存
? ? contentType: false, // 不設(shè)置Content-Type請求頭
? ? processData: false, // 不處理數(shù)據(jù)
? ? success: function (data) { // 請求成功時的回調(diào)函數(shù)
? ? ? console.log("response data", data); // 打印響應(yīng)數(shù)據(jù)
? ? ? if (data.status.code > 0) { // 判斷圖片上傳是否失敗
? ? ? ? // 圖片上傳失敗
? ? ? ? toastr.error(data.status.msg, "圖片上傳失敗!"); // 顯示錯誤提示信息
? ? ? ? return; // 結(jié)束函數(shù)執(zhí)行
? ? ? }

? ? ? const {result: { imagePath },} = data || {} // 從響應(yīng)數(shù)據(jù)中提取圖片路徑
? ? ? defaults['cover'] = imagePath; // 將圖片路徑存入defaults對象中的cover屬性

? ? ? // 將圖片路徑存入src中,顯示出圖片
? ? ? pic.attr("src", objUrl).css('visibility', 'visible') // 展示圖片
? ? ? $('.upload-icon-up').css('visibility', 'hidden') // 隱藏上傳按鈕

? ? ? callback(); // 調(diào)用回調(diào)函數(shù)
? ? ? toastr.info("圖片上傳成功!"); // 顯示成功提示信息
? ? },
? ? error : function(jqXHR, textStatus, errorThrown) { // 請求失敗時的回調(diào)函數(shù)
? ? ? toastr.error(jqXHR.responseText, "圖片上傳失敗!"); // 顯示錯誤提示信息
? ? },
? })
}
```

這段代碼定義了一個名為`uploadImg`的函數(shù),該函數(shù)接受兩個參數(shù):`callback`和`objUrl`。`callback`是一個回調(diào)函數(shù),在圖片上傳成功后會被調(diào)用;`objUrl`是圖片的URL地址。

函數(shù)內(nèi)部首先獲取上傳的圖片文件,并打印出準(zhǔn)備上傳的圖片信息。然后通過調(diào)用`checkFileSize`函數(shù)來檢查文件大小是否符合要求,如果不符合要求則直接返回。

接下來,創(chuàng)建一個新的`FormData`對象,并將上傳的圖片文件添加到其中。然后使用jQuery的`ajax`方法發(fā)送POST請求,將`FormData`對象作為請求的數(shù)據(jù)發(fā)送給服務(wù)器的`/image/upload`接口。

在請求成功時,會打印響應(yīng)數(shù)據(jù),并根據(jù)響應(yīng)結(jié)果判斷圖片上傳是否失敗。如果上傳失敗,會顯示錯誤提示信息并結(jié)束函數(shù)執(zhí)行。如果上傳成功,會從響應(yīng)數(shù)據(jù)中提取圖片路徑,并將其存入`defaults`對象的`cover`屬性中。然后通過修改DOM元素的樣式,將圖片路徑存入`src`屬性中,并顯示圖片。同時,隱藏上傳按鈕,并調(diào)用傳入的回調(diào)函數(shù)。最后,顯示成功提示信息。

在請求失敗時,會顯示錯誤提示信息。

解釋:

  • 函數(shù) uploadlmg 接受兩個參數(shù):-個回調(diào)函數(shù)callback和一個對象URL? objUrl。
  • 從文件輸入框 upload 中獲取要上傳的圖片文件(uploadPic)
  • 使用checkFilesize函數(shù)檢査文件大小,如果文件大小不符合要求,則終止執(zhí)行。
  • 創(chuàng)建一個新的FormData對象,并將圖片添加到其中。FormData是一個Web API,它提供了一種在瀏覽器中方便地構(gòu)造、發(fā)送表單數(shù)據(jù)的方法。它主要用于發(fā)送包含二進(jìn)制文件和鍵值對的數(shù)據(jù),如圖片、視頻、文檔等。FormData對象可以與Aiax一起使用,以便在不刷新頁面的情況下將表單數(shù)據(jù)發(fā)送到服務(wù)器。當(dāng)使用FormData時,瀏覽器會自動將數(shù)據(jù)編碼為 multipart/form-data 格式,這是一種特殊的格式,允許在表單中包含二進(jìn)制文件數(shù)據(jù),如圖片或視頻。
  • 使用jQuery的 $.ajax 方法發(fā)起一個異步的POST請求,將圖片文件發(fā)送到服務(wù)器的 /image/upload 接口。
  • 在ajax方法中,設(shè)置一些關(guān)鍵的參數(shù),如:cache:false表示禁用瀏覽器緩存;contentType: false表示不設(shè)置內(nèi)容類型(讓瀏覽器自動設(shè)置);processData:false表示不對數(shù)據(jù)進(jìn)行預(yù)處理。
  • 定義一個success回調(diào)函數(shù),當(dāng)服務(wù)器成功響應(yīng)時觸發(fā)。檢査響應(yīng)數(shù)據(jù)中的狀態(tài)(data.status.code)。如果大于0,表示圖片上傳失敗,顯示錯誤消息。否則,從響應(yīng)數(shù)據(jù)中獲取圖片路徑(imagePath),將圖片路徑設(shè)置為pic元素的src屬性,使圖片可見。調(diào)用回調(diào)函數(shù)callback。顯示圖片上傳成功的提示信息
  • 定義一個error回調(diào)函數(shù),當(dāng)請求發(fā)生錯誤時觸發(fā)。在這個回調(diào)函數(shù)中,顯示錯誤消息。

第四步,在ImageRestController接受圖片并處理

@Permission(role = UserRole.LOGIN)
@RequestMapping(path = {"image/", "admin/image/", "api/admin/image/",})
@RestController
@Slf4j
public class ImageRestController {@Autowiredprivate ImageService imageService;/*** 圖片上傳** @return*/@RequestMapping(path = "upload")public ResVo<ImageVo> upload(HttpServletRequest request) {ImageVo imageVo = new ImageVo();try {String imagePath = imageService.saveImg(request);imageVo.setImagePath(imagePath);} catch (Exception e) {log.error("save upload file error!", e);return ResVo.fail(StatusEnum.UPLOAD_PIC_FAILED);}return ResVo.ok(imageVo);}

來詳細(xì)解釋一下。

  • @RequestMapping(path = "image/")注解用于指定控制器處理的請求路徑為"image"。
    
  • @RestController 注解表示這是一個用于處理RESTful風(fēng)格請求的控制器。
  • @Slf4j 注解用于自動注入一個SLF4J日志對象
    
  • 使用 @Autowired 注解將一個?ImageService(用于處理圖片保存和轉(zhuǎn)鏈的關(guān)鍵類)自動注入到控制器中。
  • 接下來,讓我們看看這個控制器中的upload方法,這個方法用于處理圖片上傳請求。
  • 使用 @RequestMapping(path = "upload") 注解將此方法映射到”image/upload“路徑。
  • 該方法接受一個HttpServletRequest參數(shù),該參數(shù)代表客戶端發(fā)送的Http請求。
  • 在該方法的內(nèi)部,調(diào)用imageService.saveImg(request)方法將圖片保存到服務(wù)器,并獲取圖片路徑。
  • 將圖片路徑設(shè)置到ImageVo對象中,然后將ImageVo對象作為數(shù)據(jù)返回給客戶端。

第五步·定義ImageService接口

很簡單,不在解釋。

    /*** 保存圖片** @param request* @return*/String saveImg(HttpServletRequest request);
}

第六步,實現(xiàn)ImageService接口。

 @Overridepublic String saveImg(HttpServletRequest request) {MultipartFile file = null;if (request instanceof MultipartHttpServletRequest) {file = ((MultipartHttpServletRequest) request).getFile("image");}if (file == null) {throw ExceptionUtil.of(StatusEnum.ILLEGAL_ARGUMENTS_MIXED, "缺少需要上傳的圖片");}// 目前只支持 jpg, png, webp 等靜態(tài)圖片格式String fileType = validateStaticImg(file.getContentType());if (fileType == null) {throw ExceptionUtil.of(StatusEnum.ILLEGAL_ARGUMENTS_MIXED, "圖片只支持png,jpg,gif");}try {return imageUploader.upload(file.getInputStream(), fileType);} catch (IOException e) {log.error("Parse img from httpRequest to BufferedImage error! e:", e);throw ExceptionUtil.of(StatusEnum.UPLOAD_PIC_FAILED);}}

這個方法的主要功能是從HTTP請求中提取圖片并保存,描述一下該方法的邏輯:

  • ? ? ? ? 首先,檢查HttpServletRequest 是否是 MultipartHttpServletRequest ,如果是,則從請求中獲取名為 “image” 的文件并將其保存到MultipartFile對象中。
  • MultipartHttpServletRequest是一個Java接口,他繼承自HttpServletRequest 接口。在Spring框架中,這個接口用于處理包含文件上傳的HTTP請求,即請求內(nèi)容類型為 multipart/form-data。 在這種請求類型中,表單數(shù)據(jù)可以包含文本字段和二進(jìn)制文件,如圖片、視頻、或者文檔。
  • 如果file為空(即未上傳任何文件),則拋出一個異常,表示請求中缺少需要上傳的圖片。
  • 接下來,驗證圖片文件類型。當(dāng)前方法只支持jpg、png和webp等靜態(tài)圖片格式。
  • validateStaticImg方法檢查傳入的內(nèi)容類型是否屬于這些支持的類型,并返回相應(yīng)的文件類型,如果文件不支持,則拋出一個異常。
    
  • 從MultipartFile對象中獲取輸入流,然后傳遞給upload方法,如果在上傳的過程中發(fā)生任何錯誤,例如將圖片轉(zhuǎn)換為BufferedImage時出現(xiàn)問題,將拋出一個異常。

第七步,定義ImageUploader接口。

public interface ImageUploader {String DEFAULT_FILE_TYPE = "txt";Set<MediaType> STATIC_IMG_TYPE = new HashSet<>(Arrays.asList(MediaType.ImagePng, MediaType.ImageJpg, MediaType.ImageWebp, MediaType.ImageGif));/*** 文件上傳** @param input* @param fileType* @return*/String upload(InputStream input, String fileType);/*** 獲取文件類型** @param input* @param fileType* @return*/default String getFileType(ByteArrayInputStream input, String fileType) {if (StringUtils.isNotBlank(fileType)) {return fileType;}MediaType type = MediaType.typeOfMagicNum(FileReadUtil.getMagicNum(input));if (STATIC_IMG_TYPE.contains(type)) {return type.getExt();}return DEFAULT_FILE_TYPE;}
}

來解釋一下這段代碼。

  • ????????DEFAULT_FILE_TYPE: 一個默認(rèn)的文件類型,用于表示當(dāng)前文件類型無法識別時的默認(rèn)值。在這個接口中,他被設(shè)置為“txt”。
  • ????????STATIC_IMG_TYPE: 一個包含支持的靜態(tài)圖片類型的集合。包括PNG、JPG、WebP和GIF等類型。
  • ????????String upload(InputStream input, String fileType);這是一個需要實現(xiàn)的抽象方法,用于將輸入流中的文件保存。
  • ????????default String getFileType(ByteArrayInputStream input, String fileType) {: 這是一個默認(rèn)實現(xiàn)的方法,用于根據(jù)輸入流中的文件內(nèi)容和給定的文件類型獲取最終的文件類型。首先檢查fileType是否為空,如果為空直接返回,然后使用MediaType.typeOfMagicNum()方法通過文件的魔數(shù)來判斷文件類型。如果文件類型屬于支持的靜態(tài)圖片類型集合,則返回對應(yīng)的擴(kuò)展名。否則,返回默認(rèn)的文件類型。

來看一下獲取文件魔數(shù)的靜態(tài)方法 getMagicNum:

    public static String getMagicNum(ByteArrayInputStream inputStream) {byte[] bytes = new byte[28];inputStream.read(bytes, 0, 28);inputStream.reset();return bytesToHex(bytes);}

假如是一張jpg的文件,我們來看一下魔術(shù)是多少?

    @Testpublic  void testMagic() throws FileNotFoundException {FileInputStream fileInputStream = new FileInputStream("docs/imgs/init_00.jpg");ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();byte[] buffer = new byte[4039];int bytesRead;try {while ((bytesRead = fileInputStream.read(buffer)) != -1) {byteArrayOutputStream.write(buffer, 0, bytesRead);}} catch (IOException e) {e.printStackTrace();}ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());//算魔數(shù)String magicNum = FileReadUtil.getMagicNum(byteArrayInputStream);System.out.println(magicNum);//根據(jù)魔數(shù)判斷文件類型MediaType mediaType = MediaType.typeOfMagicNum(magicNum);System.out.println("文件類型" + mediaType);}

解釋:

這段代碼是一個Java方法,名為`testMagic`,它沒有返回值(void)并且聲明了可能拋出`FileNotFoundException`異常。下面是對代碼的詳細(xì)解釋:

1. 首先,創(chuàng)建一個`FileInputStream`對象`fileInputStream`,用于讀取指定路徑下的文件"docs/imgs/init_00.jpg"。
2. 創(chuàng)建一個`ByteArrayOutputStream`對象`byteArrayOutputStream`,用于存儲從文件中讀取的數(shù)據(jù)。
3. 定義一個長度為4039的字節(jié)數(shù)組`buffer`,用于臨時存儲每次從文件中讀取的數(shù)據(jù)。
4. 使用循環(huán)結(jié)構(gòu),通過調(diào)用`fileInputStream.read(buffer)`方法從文件中讀取數(shù)據(jù),并將讀取到的字節(jié)數(shù)賦值給變量`bytesRead`。
5. 如果`bytesRead`不等于-1,表示還有數(shù)據(jù)可以讀取,將`buffer`中的數(shù)據(jù)寫入`byteArrayOutputStream`中,從索引0開始,寫入`bytesRead`個字節(jié)。
6. 如果在讀取文件過程中發(fā)生`IOException`異常,捕獲該異常并打印堆棧跟蹤信息。
7. 創(chuàng)建一個`ByteArrayInputStream`對象`byteArrayInputStream`,使用`byteArrayOutputStream.toByteArray()`方法將`byteArrayOutputStream`中的數(shù)據(jù)轉(zhuǎn)換為字節(jié)數(shù)組作為參數(shù)傳入。
8. 調(diào)用`FileReadUtil.getMagicNum(byteArrayInputStream)`方法獲取魔數(shù)(magic number),并將結(jié)果賦值給字符串變量`magicNum`。
9. 輸出魔數(shù)`magicNum`。
10. 調(diào)用`MediaType.typeOfMagicNum(magicNum)`方法根據(jù)魔數(shù)判斷文件類型,并將結(jié)果賦值給`MediaType`類型的變量`mediaType`。
11. 輸出文件類型`mediaType`。

總結(jié):這段代碼主要用于讀取指定路徑下的文件,并將其內(nèi)容轉(zhuǎn)換為字節(jié)數(shù)組,然后根據(jù)魔數(shù)判斷文件類型,并輸出魔數(shù)和文件類型。

來看輸出結(jié)果:

Java字節(jié)碼文件(.class)的魔數(shù)是一個4字節(jié)的十六進(jìn)制: 0xCAFEBABE。魔數(shù)是文件格式的標(biāo)識符,用于表示文件類型。

第八步,新建LocalStorageWrapper類實現(xiàn)ImageUploader接口。

@Slf4j
@ConditionalOnExpression(value = "#{'local'.equals(environment.getProperty('image.oss.type'))}")
@Component
public class LocalStorageWrapper implements ImageUploader {@Autowiredprivate ImageProperties imageProperties;private Random random;public LocalStorageWrapper() {random = new Random();}@Overridepublic String upload(InputStream input, String fileType) {// 記錄耗時分布StopWatchUtil stopWatchUtil = StopWatchUtil.init("圖片上傳");try {if (fileType == null) {// 根據(jù)魔數(shù)判斷文件類型InputStream finalInput = input;byte[] bytes = stopWatchUtil.record("流轉(zhuǎn)字節(jié)", () -> StreamUtils.copyToByteArray(finalInput));input = new ByteArrayInputStream(bytes);fileType = getFileType((ByteArrayInputStream) input, fileType);}String path = imageProperties.getAbsTmpPath() + imageProperties.getWebImgPath();String fileName = genTmpFileName();InputStream finalInput = input;String finalFileType = fileType;FileWriteUtil.FileInfo file = stopWatchUtil.record("存儲", () -> FileWriteUtil.saveFileByStream(finalInput, path, fileName, finalFileType));return imageProperties.buildImgUrl(imageProperties.getWebImgPath() + file.getFilename() + "." + file.getFileType());} catch (Exception e) {log.error("Parse img from httpRequest to BufferedImage error! e:", e);throw ExceptionUtil.of(StatusEnum.UPLOAD_PIC_FAILED);} finally {log.info("圖片上傳耗時: {}", stopWatchUtil.prettyPrint());}}/*** 獲取文件臨時名稱** @return*/private String genTmpFileName() {return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmssSSS")) + "_" + random.nextInt(100);}
  • 該類使用了@ConditionalOnExpression 注解,表示只有在配置文件中的?image.oss.type屬性為“l(fā)ocal”時才會實例化該類。
  • imageProperties: 一個ImageProperties 類型的對象,用于獲取圖片相關(guān)的配置信息。
  • random: 一個 Random類型的對象,用于生成隨機(jī)數(shù)。
  • upload(InputStream input, String fileType): 實現(xiàn) ImageUploader接口中的upload方法,用于將給定的輸入流保存到本地的文件系統(tǒng)。首先檢查fileType是否為null,如果是,則根據(jù)輸入流中的字節(jié)數(shù)據(jù)的魔術(shù)確定文件的類型,然后,根據(jù)配置文件中的路徑設(shè)置和文件類型,將文件保存到本地文件,并返回文件的URL。
  •  genTmpFileName(): 一個輔助方法,用于生成臨時文件名,他使用當(dāng)前日期和一個隨機(jī)數(shù)生成文件名。
  • 其中調(diào)用了 FileWriteUtil.saveFileByStream(finalInput, path, fileName, finalFileType) 方法來對圖片進(jìn)行保存。
    public static FileInfo saveFileByStream(InputStream stream, FileInfo fileInfo) throws FileNotFoundException {if (!StringUtils.isBlank(fileInfo.getPath())) {mkDir(new File(fileInfo.getPath()));}String tempAbsFile = fileInfo.getPath() + "/" + fileInfo.getFilename() + "." + fileInfo.getFileType();BufferedOutputStream outputStream = null;InputStream inputStream = null;FileInfo var6;try {inputStream = new BufferedInputStream(stream);outputStream = new BufferedOutputStream(new FileOutputStream(tempAbsFile));int len = inputStream.available();//判斷長度是否大于4Kif (len <= 4096) {byte[] bytes = new byte[len];inputStream.read(bytes);outputStream.write(bytes);} else {int byteCount = false;byte[] bytes = new byte[4096];//1M逐個讀取int byteCount;while((byteCount = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, byteCount);}}var6 = fileInfo;return var6;} catch (Exception var16) {log.error("save stream into file error! filename: {} e: {}", tempAbsFile, var16);var6 = null;} finally {try {if (outputStream != null) {outputStream.flush();outputStream.close();}if (inputStream != null) {inputStream.close();}} catch (IOException var15) {log.error("close stream error!", var15);}}return var6;}

該方法的參數(shù)包括輸入流和一個FileInfo對象,其中FileInfo對象包含了文件路徑、文件名和文件類型。

代碼實現(xiàn)了一下功能:

  • 檢查文件路徑是否存在,如果不存在則創(chuàng)建文件夾。
  • 根據(jù)文件路徑、文件名和文件類型創(chuàng)建一個臨時的絕對路徑。
  • 使用BufferedInputStream和BufferedOUtputStream對輸出流和輸入流進(jìn)行緩沖處理,以提高文件的讀寫性能。
  • 判斷輸入流的長度是否大于4KB。如果小于等于4KB,就一次性讀取所有字節(jié)并寫入輸出流,否則,以4KB的塊逐步讀取輸入流并寫入輸出流,直到內(nèi)容都被處理。
  • 在操作完成后,返回FileInfo對象。

小結(jié):

簡單總結(jié)一下,本地圖片上傳和保存的邏輯可以分為前端和后端兩個部分:

前端(使用Ajax上傳):

? ? ? ? a.用戶選擇一張土圖片并上傳。

? ? ? ? b.使用FormData對象封裝圖片數(shù)據(jù)。FormData對象能夠讓你通過XMLHttpRequest發(fā)送表單數(shù)據(jù)。

? ? ? ? c. 利用jQuery的$.ajax方法發(fā)送一個POST請求,將FormData 對象傳遞給后端的服務(wù)器。

后端(Java代碼處理上傳和保存):

  • ????????? ? ?從HttpServletRequest對象中提取MultipartFile對象,該對象包含了上傳的圖片數(shù)據(jù)。
  • ? ? ? ? ? ? ? 驗證圖片類型,確保上傳的文件是支持的圖片格式。
  • ? ? ? ? ? ? ? ? 將MultipartFile對象轉(zhuǎn)換為InputStream,以便后續(xù)處理。
  • ? ? ? ? ? ? ? ? 調(diào)用一個專門負(fù)責(zé)處理圖片上傳的方法(如:upload(),該方法可能需要處理文件類型和文件名等邏輯。)
  • ? ? ? ? 保存圖片到本地的文件系統(tǒng)。這里可以使用一個方法(如: savaFileByStream()),將InputStream保存為文件。保存過程中,可以使用BufferedInputStream和BufferedOutputStream來提高文件讀寫性能。
  • ? ? ? ? 將圖片的存儲路徑返回給前端,前端可以使用這個路徑來顯示上傳成功的圖片。
  • 這樣一來,前端通過Ajax發(fā)送的圖片數(shù)據(jù)到后端,后端處理上傳請求并將圖片保存到本地文件系統(tǒng),最后將圖片路徑返回給前端進(jìn)行展示。??
http://m.risenshineclean.com/news/62251.html

相關(guān)文章:

  • 汽車網(wǎng)站建設(shè)多少錢百度一下手機(jī)版網(wǎng)頁
  • php心水主論壇網(wǎng)站制作網(wǎng)頁設(shè)計上海市人大常委會
  • 企業(yè)網(wǎng)站建設(shè)和維護(hù)游戲推廣公司靠譜嗎
  • 大連網(wǎng)站建設(shè)詳細(xì)流程網(wǎng)站seo診斷報告
  • 中國icp備案的有多少企業(yè)網(wǎng)站正版搜索引擎優(yōu)化
  • 手機(jī)網(wǎng)站建設(shè)公司熱線電話seo網(wǎng)絡(luò)優(yōu)化日常工作內(nèi)容
  • 多就能自己做網(wǎng)站seo網(wǎng)址超級外鏈工具
  • html5 網(wǎng)站建設(shè)貴州seo和網(wǎng)絡(luò)推廣
  • 北京skp個人網(wǎng)站seo
  • 網(wǎng)站做360推廣需要什么條件廊坊關(guān)鍵詞排名優(yōu)化
  • 網(wǎng)站上的個人詞條怎么做的百度高級搜索首頁
  • 網(wǎng)站建設(shè)排行公司seo網(wǎng)頁優(yōu)化平臺
  • 鄭州 網(wǎng)站建設(shè)的公司搜索優(yōu)化
  • 青海網(wǎng)站維護(hù)網(wǎng)紅推廣
  • 做一個平臺網(wǎng)站大概多少錢關(guān)鍵詞優(yōu)化公司推薦
  • wordpress靜態(tài)頁面css引用上海seo公司哪家好
  • wordpress粉絲搜索引擎優(yōu)化是指
  • 社交類網(wǎng)站開發(fā)國內(nèi)免費(fèi)推廣產(chǎn)品的網(wǎng)站
  • 游戲釣魚網(wǎng)站怎么做網(wǎng)絡(luò)營銷講師
  • 學(xué)做網(wǎng)站有沒有前途鏈接提交
  • 網(wǎng)站建設(shè)分為哪幾種18款禁用看奶app入口
  • 國內(nèi)網(wǎng)站建設(shè)公司排名外貿(mào)seo公司
  • 怎么免費(fèi)建立自己網(wǎng)站淘寶優(yōu)化
  • 做印章網(wǎng)站網(wǎng)站注冊地址查詢
  • 服裝企業(yè)的網(wǎng)站建設(shè)現(xiàn)在廣告行業(yè)好做嗎
  • WordPress顯示插件網(wǎng)站排名優(yōu)化制作
  • 哈爾濱做網(wǎng)站公司哪家好網(wǎng)站制作報價
  • 政府網(wǎng)站建設(shè)淺析手機(jī)百度網(wǎng)盤登錄入口
  • 做微信公眾號的網(wǎng)站有哪些內(nèi)容推廣標(biāo)題怎么寫
  • wordpress主題漢化是什么意思福建seo顧問