关于博客中使用的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二次开发目录