很多时候我们在前端页面需要展示一些图片,比如在创建菜品信息的时候,需要展示菜品的图片,有一个添加图片的功能,添加完之后,图片会立马回显到前端页面,那么这个功能如何实现呢?

首先前端代码当中有一个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返回前端,前端可以直接通过标签渲染获取文件;