關於博客中使用的Guns版本問題請先閱讀 Guns二次開發目錄
因爲Guns v5.1-final 自帶的圖片上傳接口,是將上傳的圖片保存到一個指定的文件夾中,而我的項目架構中單獨搭建了FastDFS文件服務器來統一管理文件,所以就需要將Guns原來的圖片上傳接口的內部實現邏輯進行修改。又或者你僅僅只是想要修改圖片保存的位置,此時如何去找到修改點並改動別人的代碼,對於一些剛剛參加工作的開發者來說,也會很頭疼。畢竟,以我的經驗來說,即便是自己寫的代碼,時間久了也會忘記,更何況是去改動別人的代碼。鑑於此,下面我將以一個第一次接觸Guns的新手這個身份,來帶領大家,如何一步步找到修改點並修改Guns原生的代碼,進而實現本篇博客標題中的需求。閱讀這篇博客的時候,我希望大家將更多的關注點放在修改的過程和思路中,而不僅僅只是關注結果。這對你以後到了新公司,接手別人的代碼,並且因爲新的業務需求或者修改bug而不得不去改動前人的代碼時會有幫助。下面是具體的步驟:
第一步:找到Guns自帶的圖片上傳接口
第二步:Guns項目中引入FastDFS的Java客戶端實現代碼
FastDFS文件服務器的搭建過程此處我就不講解了,因爲並非本篇博客的主題,這篇博客的前提條件是我已經搭建好了FastDFS服務器和前臺的項目中已經實現了FastDFS的客戶端的,所以,在Guns二次開發的時候,我直接從其它項目將FastDFS的Java客戶端實現代碼扣到guns中來,以下是具體的代碼。
1、添加pom依賴
<!-- FastDfs 開始-->
<!-- https://mvnrepository.com/artifact/com.luhuiguo/fastdfs-spring-boot-starter -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.2</version>
<!-- 出現日誌相關異常時取消以下注釋 -->
<!-- <exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions> -->
</dependency>
<!-- FastDfs 結束-->
2、application.yml文件中添加配置
####### FastDFS相關配置開始 #######
fdfs:
## tracker地址,多個可fdfs.trackerList[0]、fdfs.trackerList[1]等方式配置
tracker-list: 192.168.0.115:22122
## 連接超時時間
connect-timeout: 5000
## 讀取inputsream阻塞時間
so-timeout: 3000
pool:
## 連接池最大數量
max-total: 200
## 每個tracker地址的最大連接數
max-total-per-key: 50
## 連接耗盡時等待獲取連接的最大毫秒數
max-wait-millis: 5000
## 縮略圖相關配置
thumbImage:
height: 150
width: 150
####### FastDFS相關配置結束 #######
注意這個配置信息,要儘量放在guns的application.yml文件的公共配置信息的位置,否則不會生效。
3、FastDFS的java客戶端代碼
FastDFSClientWrapper.java
package cn.stylefeng.guns.elephish.utils.fastdfs;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.domain.ThumbImageConfig;
import com.github.tobato.fastdfs.proto.storage.DownloadCallback;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
/**
* FastDFS文件上傳下載包裝類
*/
@Component
public class FastDFSClientWrapper {
@Autowired
private FastFileStorageClient storageClient;
@Autowired
private ThumbImageConfig thumbImageConfig;
/**
* @Description: 上傳文件
* @param file 文件對象
* @return 文件路徑
* @throws IOException String
*/
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(),
FilenameUtils.getExtension(file.getOriginalFilename()), null);
return storePath.getFullPath();
}
/**
* @Description: 上傳文件
* @param bytes 文件數據
* @param format 文件格式(後綴)
* @return String 文件路徑
*/
public String uploadFile(byte[] bytes, String format) {
StorePath storePath = storageClient.uploadFile(new ByteArrayInputStream(bytes), bytes.length, format, null);
return storePath.getFullPath();
}
/**
* @Description: 上傳文件
* @param file 文件對象
* @return
* @throws IOException String
*/
public String uploadFile(File file) throws IOException {
StorePath storePath = storageClient.uploadFile(FileUtils.openInputStream(file), file.length(),
FilenameUtils.getExtension(file.getName()), null);
return storePath.getFullPath();
}
/**
* @Description: 把字符串作爲指定格式的文件上傳
* @param content
* @param fileExtension
* @return String
*/
public String uploadFile(String content, String fileExtension) {
byte[] buff = content.getBytes(Charset.forName("UTF-8"));
ByteArrayInputStream stream = new ByteArrayInputStream(buff);
StorePath storePath = storageClient.uploadFile(stream, buff.length, fileExtension, null);
return storePath.getFullPath();
}
/**
* @Description: 上傳文件
* @param file 文件對象
* @return 文件路徑
* @throws IOException String
*/
public String uploadImageAndCrtThumbImage(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(),
FilenameUtils.getExtension(file.getOriginalFilename()), null);
return storePath.getFullPath();
}
/**
* @Description: 根據圖片路徑獲取縮略圖路徑(使用uploadImageAndCrtThumbImage方法上傳圖片)
* @param filePath 圖片路徑
* @return String 縮略圖路徑
*/
public String getThumbImagePath(String filePath) {
return thumbImageConfig.getThumbImagePath(filePath);
}
/**
* @Description: 根據文件路徑下載文件
* @param filePath 文件路徑
* @return 文件字節數據
* @throws IOException byte[]
*/
public byte[] downFile(String filePath) throws IOException {
StorePath storePath = StorePath.praseFromUrl(filePath);
return storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), new DownloadCallback<byte[]>() {
@Override
public byte[] recv(InputStream ins) throws IOException {
return org.apache.commons.io.IOUtils.toByteArray(ins);
}
});
}
/**
* @Description: 根據文件地址刪除文件
* @param filePath 文件訪問地址
*/
public void deleteFile(String filePath) {
StorePath storePath = StorePath.praseFromUrl(filePath);
storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
}
}
FastDFSConfiguration.java
package cn.stylefeng.guns.elephish.utils.fastdfs;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;
/**
* FastDFS的相關配置
*/
@Configuration
@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration= RegistrationPolicy.IGNORE_EXISTING)// 解決jmx重複註冊bean的問題
public class FastDFSConfiguration {
}
FileType.java
package cn.stylefeng.guns.elephish.utils.fastdfs;
import org.apache.commons.lang3.StringUtils;
/**
* 定義了用戶允許上傳的文件類型
* @ClassName: FileType
* @author hqq
* @date 2019年4月4日
*
*/
public enum FileType {
JPG("image/jpeg", "jpg")
,PNG("image/png","png")
// ,PDF("application/pdf","pdf")
// ,TXT("text/plain","txt")
// ,DOC("application/msword","doc")
// ,DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document","docx")
// ,XLS("application/vnd.ms-excel","xls")
// ,XLS2("application/octet-stream","xls")
// ,XLSM("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xlsm")
// ,XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xlsx")
;
//屬性
private String contentType;
private String suffix;
// 構造方法
private FileType(String contentType,String suffix ){
this.contentType=contentType;
this.suffix=suffix;
}
/**
* 傳入contentType,獲取後綴名
* @param contentType
* @return 返回對應的後綴名,沒有值就返回null
*/
public static String getSuffix(String contentType){
if(StringUtils.isBlank(contentType)){
return null;
}
for(FileType tf:FileType.values()){
if(StringUtils.endsWithIgnoreCase(contentType,tf.getContentType())){
return tf.getSuffix();
}
}
return null;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
4、修改Guns自帶的圖片上傳接口【/mgr/upload】的內部邏輯
@RequestMapping(method = RequestMethod.POST, path = "/upload")
@ResponseBody
public String upload(@RequestPart("file")MultipartFile file) {
try{
// 判斷文件類型
String suffix = FileType.getSuffix(file.getContentType());
// logger.info("文件類型:"+suffix);
if (suffix == null) {
// logger.info("暫不支持當前類型的文件上傳:"+suffix);
throw new ServiceException(BizExceptionEnum.UPLOAD_ERROR);
}
String fileUri = fastDFSClientWrapper.uploadFile(file.getBytes(),suffix);
//fastdfs服務器的域名
String prefix = "http://192.168.0.115/";
return prefix+fileUri;
}catch (Exception e){
throw new ServiceException(BizExceptionEnum.UPLOAD_ERROR);
}
}
5、重啓Guns項目測試
第三步:修改前端頁面的圖片顯示路徑
修改後的文件內容:
重啓服務器:
至此,功能實現!
該系列更多文章請前往 Guns二次開發目錄