前言

终于开始学习做项目了,本篇文章是学习B站黑马程序员苍穹外卖的学习笔记📑。我的学习路线是Java基础语法-JavaWeb-做项目,登录功能结束后,就进入复杂功能的开发,✌️✌️✌️在新增菜品的功能中我们需要通过文件上传的功能来实现添加菜品的头像。

因为是上传,首先还是先看一下JavaIO基础😎:

📚IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。

流的分类(IO 流有40 多个类,但都是从这几个基类中派生出来的):

类型 常见类
输入流(所有输入流基类) InputStream(字节输入流), Reader(字符输入流)
输出流(所有输出流基类) OutputStream(字节输出流), Writer(字符输出流)

🧐下面来看看几个简单的代码:

  1. InputStream(字节输入流):
//读取文件
FileInputStream fis = new FileInputStream("input.txt");
int data;
while ((data = fis.read()) != -1) {  // 每次读一个字节
    System.out.print((char) data);   // 转成字符输出
}
fis.close();
  1. OutputStream(字节输出流)
//写入文件
FileOutputStream fos = new FileOutputStream("output.txt");
String text = "Hello Java IO!";
fos.write(text.getBytes());  // 把字符串转成字节写入文件
fos.close();
  1. Reader(字符输入流)
//读取文本
FileReader fr = new FileReader("input.txt");
int ch;
while ((ch = fr.read()) != -1) {
    System.out.print((char) ch);
}
fr.close();
  1. Writer(字符输出流)
//写入文本
FileWriter fw = new FileWriter("output.txt");
fw.write("你好,Java IO!");
fw.close();

✨这里举个例子,主要是来看看JavaIO在具体项目中怎么用:

用它来实现文件上传最基本的功能,将接收到的文件保存在本地服务器的磁盘目录中了,客户端访问时可以显示出来
结合前端看看具体功能(提交姓名性别头像):
在这里插入图片描述

来看后端代码:

...
@Slf4j
@RestController
public class UploadController {

    private static final String UPLOAD_DIR = "D:/images/";
    /**
     * 上传文件 - 参数名file
     */
    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws Exception {
        log.info("上传文件:{}, {}, {}", username, age, file);
        if (!file.isEmpty()) {
            // 生成唯一文件名(防止上传的文件名相同,后面上传的会覆盖前面文件)
            String originalFilename = file.getOriginalFilename();
            String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
            String uniqueFileName = UUID.randomUUID().toString().replace("-", "") + extName;
            // 拼接完整的文件路径
            File targetFile = new File(UPLOAD_DIR + uniqueFileName);

            // 如果目标目录不存在,则创建它
            if (!targetFile.getParentFile().exists()) {
                targetFile.getParentFile().mkdirs();
            }
            // 保存文件
            file.transferTo(targetFile);
        }
        return Result.success();
    }
}

🙌其中有几个点不好理解(我让ai解释了一下):
1.MultipartFile:Spring中提供了一个API,使用这个API就可以来接收到上传的文件
String getOriginalFilename(); MultipartFile 常见方法,获取原始文件名

2.file.transferTo(…) InputStream 常用方法:作用是将上传的临时文件写入目标位置。

调用 transferTo() 方法后,Spring 会使用 Java I/O 流的方式将这个临时文件复制到指定的目标路径。
其本质是调用了类似下面的逻辑:


InputStream inputStream = file.getInputStream();
OutputStream outputStream = new FileOutputStream(targetFile);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
    outputStream.write(buffer, 0, bytesRead);
}

上面说的是把文件存储在服务器短的C盘里,但在实际开发中,这样做是很不安全,容易丢失的,一般使用云服务阿里云OSS来存储。

🔍阿里云OSS

账号注册和开通阿里云账号就不说了可以看链接:黑马程序员的JavaWeb 这里只说说🙌苍穹外卖的后端文件上传代码实现:

主要是分为三步(视频里讲的不是很详细,但是之前学JavaWeb有讲过)我根据自己😎的理解分为三步来说:

1. 首先就是根据阿里云OSS官方所提供的sdk示例,改造引入阿里云OSS上传文件工具类以及引入依赖(这个视频配套资料都存在的)
可以查看一下自己idea上的package com.sky.utils和pom.xml文件:

package com.sky.utils;
...
@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();
    }
}

<!--阿里云OSS依赖-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.17.4</version>
</dependency>

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

2. 配置参数,阿里云OSS上传文件工具类中生成的文件路径中的配置项中是需要我们改成自己的

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

✅这几个值在你的阿里云上都可以找到:

endpoint:阿里云OSS中的bucket对应的域名
bucketName:Bucket名称
objectName:对象名称,在Bucket中存储的对象的名称
region:bucket所属区域

application.yml

  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}

application-dev.yml 这个要自己填一下:

  alioss:
    bucket-name: 
    access-key-secret: 
    access-key-id:
    endpoint: 
package com.sky.config;

import com.sky.properties.AliOssProperties;
import com.sky.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置类用于创建阿里云OSSUtill对象
 */
@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());
    }
}

注:
因为这个苍穹外卖项目课程是前几年的,所以代码不是很先进,想我学JavaWeb是的项目就不是这么配置的(实现功能都一样)。
本来还想解释一下每行代码的功能,有感觉没必要只要会用就行,知道干啥的就行(不过其中涉及到SpringBoot的原理配置感觉面试的时候会问,我以后再写🤪)

3. 最后修改一下Controller层:让这一层调用阿里云OSS上传文件工具类上传文件到阿里云,并返回可以查看图片的阿里云URL:

package com.sky.controller.admin;
...
/**
 * 通用接口
 */
@Slf4j
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
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();
            //获取文件名后缀
            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);
    }
}

小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)

…。。。。。。。。。。。…请添加图片描述…。。。。。。。。。。。…

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐