很多时候我们在前端页面需要展示一些图片,比如在创建菜品信息的时候,需要展示菜品的图片,有一个添加图片的功能,添加完之后,图片会立马回显到前端页面,那么这个功能如何实现呢?
首先前端代码当中有一个file标签,可以打开我们系统的文件夹选择要保存的一张图片,之后发起请求到后端,由后端将这个二进制文件进行保存,而保存有两种方式。
一,本地存储
创建upload方法,将要保存的文件保存到我们本地磁盘上,然后通过download方法将文件重新响应到前端页面展示。
接收文件用到的是spring自带的MutipartFile类,获取到的文件是临时文件,一旦请求结束就会删除,因此需要将文件保存到本地,返回值是文件名,同时前端再次发起download请求下载刚刚保存的文件,通过IO流的形式读取和输出文件。
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
//file是一个临时文件,请求结束后自动删除
//获取原始文件名
String originalFilename = file.getOriginalFilename();
//取文件名的后缀
String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用uuid生成文件名,防止重复导致覆盖
String fileName = UUID.randomUUID().toString()+substring;
//创建一个目录对象
File dir=new File(basePath);
//判断目录是否存在
if(!dir.exists()){
//目录不存在,则先创建
dir.mkdirs();
}
try {
//将临时文件转存到指定位置
file.transferTo(new File(basePath+fileName));
} catch (IOException e) {
e.printStackTrace();
}
return R.success(fileName);
}
/**
* 文件下载
*/
@GetMapping("/download")
public void downLoad(String name, HttpServletResponse response){
try {
//输入流,通过输入流读取文件内容
FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));
//输出流,通过输出流将文件写回浏览器,在浏览器展示图片
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("image/jpeg");
int len=0;
byte[]bytes=new byte[1024];
while ((len=fileInputStream.read(bytes))!=-1){
outputStream.write(bytes,0,len);
outputStream.flush();
}
//关闭资源
outputStream.close();
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
二,云存储
这里以阿里云为例,前提是创建阿里云账号,申请oss存储,申请自己的ID、秘钥和存储空间。
步骤一
创建阿里云文件上传工具类
将自己的阿里云id,秘钥。存储空间地址信息等传入,就可以把文件保存到阿里云服务器上。
@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();
}
步骤二
调用工具类,实现upload方法的调用
@Autowired
private AliOssUtil aliOssUtil;
@PostMapping("/upload")
public Result<String> upload(MultipartFile file){
try {
//获取原始文件名
String originalFilename = file.getOriginalFilename();
//获取文件名后缀
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("上传文件失败");
}
return Result.error(MessageConstant.UPLOAD_FAILED);
}
二者的区别
本地存储需要前端发起两个请求,一个存,一个取因此需要upload和download两个方法;
云存储只需要一次请求,将文件保存到云服务器上,每一个文件都有一个唯一的url,upload方法中将url返回前端,前端可以直接通过标签渲染获取文件;