JavaScript

SpringBoot与H5实现文件上传和下载

2023-07-21  本文已影响0人  h2coder

环境说明

后端

依赖(pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zh</groupId>
    <artifactId>spring-boot-file-upload</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--使用上springboot都必须要继承父模块-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!--spring-boot启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!--junit启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--springmvc的启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

        <!--字符串工具类-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

    <build>
        <!-- 设置打包的jar包名称,如果不设置,默认模块名为打包名称 -->
        <!-- <finalName>spring-boot-file-upload</finalName> -->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

配置

# 服务端口
server:
  port: 8080

# 文件上传配置
spring:
  application:
    name: spring-boot-file-upload
  # SpringMVC,设置上传文件大小
  servlet:
    multipart:
      max-file-size: 500MB

# 上传目录配置
upload:
  # Windows文件上传到的目录地址
  path: c:\Project\upload\file\
  # Linux 文件上传目录
  # path: /img/

启动类

@SpringBootApplication
//打印日志注解,是lombok提供的,打印日志时,会带有类全名、方法名、标识哪里输出的日志
@Slf4j
public class AppApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
        log.info("项目启动成功");
    }
}

跨域配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 是否发送Cookie
                .allowCredentials(true)
                // 放行哪些原始域
                .allowedOriginPatterns("*")
                // 放行哪些请求方式
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                // 放行哪些原始请求头部信息
                .allowedHeaders("*")
                // 暴露哪些头部信息
                .exposedHeaders("*");
    }
}

服务配置

服务配置,用于获取服务器的IP和端口

@Component
public class ServerConfig implements ApplicationListener<WebServerInitializedEvent> {
    /**
     * 端口
     */
    private int serverPort;

    /**
     * 获取服务器的访问Url
     */
    public String getUrl() {
        InetAddress address = null;
        try {
            address = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return "http://" + address.getHostAddress() + ":" + this.serverPort;
    }

    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.serverPort = event.getWebServer().getPort();
    }
}

Controller控制器

/**
 * 文件上传与下载接口
 */
@RestController
@RequestMapping("/common")
public class CommonController {
    /**
     * 存储上传文件的目录路径
     */
    @Value("${upload.path}")
    private String baseDir;

    /**
     * 服务端配置
     */
    @Autowired
    private ServerConfig serverConfig;

    /**
     * 上传文件
     * MultipartFile:SpringMVC获取前端的输入文件流,封装的文件解析对象
     * file:是 MultipartFile 对象参数的变量名(参数名),这个名字必须与前端传递的文件参数一致!,这里就是file
     */
    @PostMapping("/upload")
    public R<Map<String, String>> upload(MultipartFile file) throws IOException {
        //判断上传目录是否存在,不存在则创建
        File fileDir = new File(baseDir);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }
        //获取上传的原始文件名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            originalFilename = "";
        }
        //获取拓展名,截取最后一个.后面的字符串,就是拓展名
        String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
        //直接使用原始文件名,会导致相同文件名的图片会覆盖,所以添加UUID作为文件夹
        String fileName = UUIDUtils.getUUID() + extName;
        //存储到服务器上
        file.transferTo(new File(fileDir, fileName));

        //构造访问文件Url,并返回
        String fileUrl = serverConfig.getUrl() + "/common/download?name=" + fileName;
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("url", fileUrl);
        return R.success(resultMap);
    }

    /**
     * 文件下载
     * 注意:方法返回值为void,而不是R,因为响应的是一个图片文件流,而不是json
     *
     * @param name     需要下载的文件名
     * @param response 响应对象,用于输出文件流给客户端
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) throws IOException {
        //文件
        File file = new File(baseDir + name);
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
        ServletOutputStream out = response.getOutputStream();

        //原生IO流实现
        //输出文件到响应中
        byte[] buf = new byte[1024];
        int length;
        while ((length = bis.read(buf)) != -1) {
            out.write(buf, 0, length);
        }
        out.flush();
        //关闭资源,ServletOutputStream out 响应输出流不需要关闭,Tomcat会帮我们关闭
        bis.close();

        //使用工具类实现
        //IOUtils.copy(fis, out);
    }
}

统一返回结果实体类

/**
 * 统一返回结果实体
 */
@Data
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 编码:1成功,0和其它数字为失败
     */
    private Integer code;

    /**
     * 错误信息
     */
    private String msg;

    /**
     * 数据对象
     */
    private T data;

    /**
     * 动态数据对象
     */
    private Map map = new HashMap();

    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }

    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }

    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }
}

UUID工具类

public class UUIDUtils {
    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    public static Integer getUUIDInOrderId() {
        int orderId = UUID.randomUUID().toString().hashCode();
        orderId = orderId < 0 ? -orderId : orderId; //String.hashCode() 值会为空
        return orderId;
    }
}

前端

前端页面

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图片上传</title>
</head>

<body>
  <!-- 文件选择元素 -->
  <input type="file" class="upload">
  <img src="" alt="" class="my-img">

  <script src="../lib/axios.js"></script>
  <script>
    // 文件选择
    const uploadInput = document.querySelector('.upload');
    // 图片
    const myImg = document.querySelector('.my-img');

    /* 
      绑定值改变事件
      通过文件input框的files属性,获取到文件列表
    */
    uploadInput.addEventListener('change', function (e) {
      // 获取上传的文件
      const file = uploadInput.files[0];
      // 创建FormData实例
      const formData = new FormData();
      // key是参数名,value是文件
      formData.append('file', file);

      const url = 'http://localhost:8080/common/upload';

      // 发送请求,上传文件
      axios({
        url: url,
        method: 'POST',
        data: formData
      }).then(result => {
        console.log(result);
        // 获取图片Url,并设置到图片
        const imgUrl = result.data.data.url;
        myImg.src = imgUrl;
      });
    });
  </script>
</body>

</html>
上一篇下一篇

猜你喜欢

热点阅读