介绍
文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。
文件上传时,对页面的form表单有如下要求:
-
method="post" 采用post方式提交数据
-
enctype="multipart/form-data!采用multipart格式上传文件type="file"
-
使用input的file控件上传
举例:
ini
<form method="post" action="/common/upload" enctype="multipart/form-data">
<input name="myFile" type="file"/>
<input type="submit"value="提交"/>
</form>
核心代码
java
package com.example.demo.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.example.demo.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
@Value("${takeOutFile.fileLocaltion}")
private String basePath ;
@PostMapping("/upload")
public Result<String> upload(MultipartFile file){
//这里的file只是一个临时的文件存储,临时存储到某一个位置,然后待接收完毕后再转存到目标位置上,然后再把这个临时文件删除
//截取文件后缀
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
//生成UUID
String randomUUID = UUID.randomUUID().toString();
//拼接文件最后名称,结果为文件本体名字+UUID+后缀
String fileName = file.getOriginalFilename() + randomUUID + suffix;
//保证存储的位置有这个文件夹
File dir = new File(basePath);
if (!dir.exists()) {
//目标存储位置不存在,就创建一个文件夹
dir.mkdirs();
}
try {
//转存文件到指定位置+文件的名称全拼
file.transferTo(new File(basePath+fileName));
} catch (IOException e) {
e.printStackTrace();
}
//把文件的名字上传回去,方便后续回显读取路径
return Result.success(fileName);
}
/**
* 文件回显接口
* @param httpServletResponse 响应对象
* @param name 上传的文件名称
* @throws IOException IO异常
*/
@GetMapping("/download")
public void fileDownload(HttpServletResponse httpServletResponse, String name) throws IOException {
//把刚刚存的文件读取到内存中,准备回显
FileInputStream fileInputStream = new FileInputStream(new File(basePath+name));
log.info("文件存储的位置为:"+basePath+name);
//把读取到内存中的图片用输出流写入Servlet响应对象里
ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream();
//可选项,选择响应类型
httpServletResponse.setContentType("image/jpeg");
//用byte数组写入,注意是小写b,不是大写,大写就是包装类了
byte[] fileArray = new byte[1024];
int length=0;
try {
//只要没读到数组的尾部就一直读下去,这部分是IO的内容
while ((length=fileInputStream.read(fileArray))!=-1) {
//写入响应流,从0开始,写入到数组末尾长度
servletOutputStream.write(fileArray, 0, length);
//把流里的东西挤出来
servletOutputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭流
fileInputStream.close();
servletOutputStream.close();
}
return;
}
}
使用阿里云上传文件
添加application.yml配置
yaml
sky:
alioss:
endpoint: ${sky.alioss.endpoint}
access-key-id: ${sky.alioss.access-key-id}
access-key-secret: ${sky.alioss.access-key-secret}
bucket-name: ${sky.alioss.bucket-name}
创建工具类
typescript
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
/**
* 文件上传
*
* @param bytes
* @param objectName
* @return
*/
public String upload(byte[] bytes, String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
//文件访问路径规则 https://BucketName.Endpoint/ObjectName
StringBuilder stringBuilder = new StringBuilder("https://");
stringBuilder
.append(bucketName)
.append(".")
.append(endpoint)
.append("/")
.append(objectName);
log.info("文件上传到:{}", stringBuilder.toString());
return stringBuilder.toString();
}
}
注入实体类
less
@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
注入工具类
less
/**
* 配置类,用于创建AliOssUtil对象
*/
@Configuration
@Slf4j
public class OssConfiguration {
@Bean
@ConditionalOnMissingBean
public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
log.info("开始创建阿里云文件上传工具类对象:{}",aliOssProperties);
return new AliOssUtil(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}
使用工具类
less
/**
* 通用接口
*/
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {
@Autowired
private AliOssUtil aliOssUtil;
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
@ApiOperation("文件上传")
public Result<String> upload(MultipartFile file){
log.info("文件上传:{}",file);
try {
//原始文件名
String originalFilename = file.getOriginalFilename();
//截取原始文件名的后缀 dfdfdf.png
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
//构造新文件名称
String objectName = UUID.randomUUID().toString() + extension;
//文件的请求路径
String filePath = aliOssUtil.upload(file.getBytes(), objectName);
return Result.success(filePath);
} catch (IOException e) {
log.error("文件上传失败:{}", e);
}
return Result.error(MessageConstant.UPLOAD_FAILED);
}
}