目录

前端

1、编写模板

2、发请求

后端 

相关依赖

1、创建实体类

2、编写控制类

3、service层 

4、Mapper层

5、工具类

6、sql脚本


前端

1、编写模板
<template>
    <div>
        <el-upload ref="upload" class="upload-demo" action="http://localhost:8080/api/book/uploadExcel" :limit="1"
            :before-upload="beforeUpload" :on-success="handleSuccess" :on-error="uploadError" :file-list="fileList">
            <el-button type="primary">导入</el-button>
        </el-upload>
        <el-button type="success" @click="downloadExcel">导出</el-button>
    </div>
</template>

上述代码是一个 Vue 组件的模板部分。这个组件包含了两个按钮:一个用于文件上传,另一个用于文件导出。

  • <el-upload> 是 Element UI 提供的上传组件,通过设置 action 属性指定了文件上传的目标地址。:limit="1" 表示限制只能上传一个文件。:before-upload:on-success 和 :on-error 是组件提供的事件回调函数,用于处理上传前的验证、上传成功和上传失败的情况。:file-list="fileList" 则是绑定了一个文件列表,用于展示已上传的文件。
  • <el-button> 是 Element UI 提供的按钮组件,通过设置 type 属性指定按钮的样式类型。@click 是按钮点击事件的监听器,绑定了名为 downloadExcel 的方法。
2、发请求

<script>
export default {
    name: 'book',
    data() {
        return {
            fileList: []
        }
    },
    methods: {
        //导出
        downloadExcel() {
            this.$axios({
                method: 'get',
                url: ' http://localhost:8080/api/book/downloadExcel',
                responseType: 'blob'
            }).then((res) => {
                let filename = decodeURIComponent(res.headers.get('X-Filename'));
                const url = window.URL.createObjectURL(new Blob([res.data]))
                const link = document.createElement('a')
                link.href = url
                link.setAttribute('download', filename)
                document.body.appendChild(link)
                link.click()
            })

        },
        //上传之前调用:校验类型、大小
        beforeUpload(file) {
            console.log("file.type:" + file.type);

            const fileSize = file.size / Math.pow(2, 20);
            if (file.type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
                this.$message.error('只能上传excel文件')
                return false;
            }

            if (fileSize > 10) {
                this.$message.error("图片不能超过10MB")
                return false;
            }

            return true;
        },
        //图片上传成功之后:将上传图片的数据添加到fileList
        handleSuccess(response, file, fileList) {
            // 根据后端返回的数据修改fileList集合
            console.log("图片上传成功之后response:" + JSON.stringify(response));

        },

        //上传失败的逻辑
        uploadError(err, file, fileList) {
            this.$message({
                message: err.message,
                type: "error",
            });
        },

    }
}
</script>
  • this.$axios 是 Vue 实例中的 $axios 对象,用于发送 HTTP 请求。
  • method: 'get' 表示发送 GET 请求。
  • url: 'http://localhost:8080/api/book/downloadExcel' 指定了要下载的 Excel 文件的地址。
  • responseType: 'blob' 表示期望响应的数据类型为 Blob 类型,即二进制数据。

在请求成功后,使用 then 方法处理返回的响应。res 是响应对象,包含了服务器返回的数据和响应头等信息。

  • let filename = decodeURIComponent(res.headers.get('X-Filename')) 从响应头中获取文件名,并进行 URL 解码。
  • const url = window.URL.createObjectURL(new Blob([res.data])) 创建一个临时的 URL,用于将二进制数据转换为可下载的文件。
  • const link = document.createElement('a') 创建一个 <a> 元素,用于触发文件下载。
  • link.href = url 设置 <a> 元素的链接地址为临时 URL。
  • link.setAttribute('download', filename) 设置下载属性,其中 filename 是文件名。
  • document.body.appendChild(link) 将 <a> 元素添加到文档中。
  • link.click() 触发点击事件,实现文件下载。

后端 

相关依赖
 <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.0.1-jre</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.2</version>
 </dependency>
1、创建实体类

import java.util.Date;

public class Book {


    @ExcelIgnore //设置导出时不导出这个字段
    private String bookId;
    
    @ExcelProperty(value="书名",index = 0)//value 属性指定了 Excel 列的标题或名称,index 属性指定了 Excel 列的索引位置
    @ColumnWidth(15) // 设置宽度为16个字符
    private String bookName;
    @ExcelProperty(value="作者",index = 1)
    @ColumnWidth(15) // 设置宽度为16个字符
    private String author;
    @ExcelProperty(value="价格",index = 2)
    private double price;
    @ExcelProperty(value="图书编号",index = 3)
    @ColumnWidth(25) // 设置宽度为16个字符
    private String isbn;
    @ExcelProperty(value="出版社",index = 4)
    @ColumnWidth(15) // 设置宽度为16个字符
    private String publisher;
    @ExcelProperty(value="发行日期",index = 5)
    @ColumnWidth(20) // 设置宽度为16个字符
//    @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    private Date releaseTime;

    @ExcelIgnore
    private String status;

    public Book() {
    }


    public static void main(String[] args) {
        Book book = new Book();

        //book 反射
        Class<? extends Book> aClass = book.getClass();
        System.out.println(aClass.getName());
    }

    public Book(String bookId, String bookName, String author, double price, String isbn, String publisher, Date releaseTime, String status) {
        this.bookId = bookId;
        this.bookName = bookName;
        this.author = author;
        this.price = price;
        this.isbn = isbn;
        this.publisher = publisher;
        this.releaseTime = releaseTime;
        this.status = status;
    }

    public String getBookId() {
        return bookId;
    }

    public void setBookId(String bookId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public Date getReleaseTime() {
        return releaseTime;
    }

    public void setReleaseTime(Date releaseTime) {
        this.releaseTime = releaseTime;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}
2、编写控制类
@RestController
@RequestMapping("/book")
public class BookController {
    @Autowired
    BookService bookService;
    
    @PostMapping("/uploadExcel")
    public Result uploadExcel(@RequestPart MultipartFile file) {
        return bookService.uploadExcel(file);
    }

    @GetMapping("/downloadExcel")
    public void downloadExcel(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        bookService.downloadExcel(httpServletResponse);
    }
}
  • @RestController 注解表示这是一个 RESTful 服务的控制器类,用于处理 HTTP 请求并返回 JSON 或 XML 等数据。
  • @RequestMapping("/book") 注解表示该控制器中所有处理 "/book" 路径下的请求。

控制器中包含两个方法:

  1. uploadExcel 方法处理 POST 请求,用于接收上传的 Excel 文件,并调用 BookServiceuploadExcel 方法进行处理。@RequestPart MultipartFile file 表示从请求中接收名为 "file" 的文件部分,并将其作为 MultipartFile 对象注入到方法参数中。上传成功后,返回处理结果(Result 对象)。

  2. downloadExcel 方法处理 GET 请求,用于下载 Excel 文件,并调用 BookServicedownloadExcel 方法。通过传入 HttpServletResponse 对象来设置响应,实现文件下载功能。

  3. HttpServletRequestHttpServletResponse。这两个参数分别表示 HTTP 请求和响应。

    在方法内部,调用了 bookServicedownloadExcel 方法,并传入 httpServletResponse。这意味着在 bookServicedownloadExcel 方法中会对 HttpServletResponse 进行操作,以便向客户端发送 Excel 文件。

    bookServicedownloadExcel 方法中,通常会进行以下操作:

  • 设置响应的内容类型,告诉客户端响应的数据类型是 Excel 文件。
  • 设置响应的头部信息,包括文件名、内容长度等。
  • 将 Excel 文件的内容写入到响应的输出流中,使客户端可以下载该文件。
3、service层 

接口

public interface BookService {
    Result uploadExcel(MultipartFile file);

    void downloadExcel(HttpServletResponse httpServletResponse) throws IOException;
}

接口实现


import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Service
public class BookServiceImpl implements BookService {

    /**
     * 每隔1000条存储数据库,然后清理list ,方便内存回收
     */
    //TODO 定义变量
    private static final int BATCH_COUNT = 1000;
    @Autowired
    BookMapper bookMapper;

    @Override
    public Result uploadExcel(MultipartFile file) {
        try {
            // 1、获取输入流,这里需要自行实现获取输入流的逻辑
            InputStream inputStream = file.getInputStream();

            //2、解析输入流数据,并添加到集合
            List<Book> list = EasyExcelUtil.read(inputStream, Book.class);

            //3、对集合进行分批次
            List<List<Book>> partition = Lists.partition(list, BATCH_COUNT);

            //4、保存到数据库
            for (List<Book> bookList : partition) {
                bookMapper.batchInsertBook(bookList);
            }
        } catch (Exception e) {
            // 处理异常
            e.printStackTrace();
            return Result.failed("导入失败");
        }
        return Result.succeed("导入成功");
    }

    @Override
    public void downloadExcel(HttpServletResponse httpServletResponse) throws IOException {
        //1、查询数据库数据
        List<Book> list =bookMapper.selectAllBook();
        
        //导出
        EasyExcelUtil.download(httpServletResponse,list,Book.class, "喜欢看得书籍","书籍");
    }
}
  • uploadExcel 方法中,首先通过 file.getInputStream() 获取上传文件的输入流。然后使用 EasyExcelUtil.read 方法将输入流中的数据解析成 Book 对象的列表。接着,使用 Lists.partition 方法将列表分割成小的批量列表,每个批量包含多个 Book 对象。最后,遍历分割后的批量列表,调用 bookMapper.batchInsertBook 方法将批量数据插入到数据库中。
  • downloadExcel 方法中,首先通过 bookMapper.selectAllBook() 从数据库中获取所有的书籍数据。然后使用 EasyExcelUtil.download 方法将获取到的书籍列表以 Excel 文件的形式下载到客户端。其中,Book.class 是指定数据对象的类,"喜欢看得书籍" 是指定生成的 Excel 文件名称,"书籍" 是指定 Excel 文件的 sheet 名称。

这样,通过调用 BookServiceImpl 类中的方法,可以实现上传和下载 Excel 文件的功能。

4、Mapper层

接口mapper

public interface BookMapper {
    void batchInsertBook(List<Book> list);

    List<Book> selectAllBook();
}

mapper对应的xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.goods_admin.mapper.BookMapper">

    <!--    结果映射:数据库字段与实体类字段的映射关系-->
    <resultMap id="BaseResultMap" type="com.example.goods_admin.entity.Book">
        <id column="bookId" jdbcType="INTEGER" property="bookId" />
        <result column="bookName" jdbcType="VARCHAR" property="bookName" />
        <result column="author" jdbcType="VARCHAR" property="author" />
        <result column="price" jdbcType="DOUBLE" property="price" />
        <result column="isbn" jdbcType="VARCHAR" property="isbn" />
        <result column="publisher" jdbcType="INTEGER" property="publisher" />
        <result column="releaseTime" jdbcType="VARCHAR" property="releaseTime" />
        <result column="status" jdbcType="VARCHAR" property="status" />
    </resultMap>

    <insert id="batchInsertBook">
    insert into book(bookName,author,price,isbn,publisher,releaseTime) values
        <foreach collection="list" item="item" separator=",">
            (#{item.bookName},#{item.author},#{item.price},#{item.isbn},#{item.publisher},#{item.releaseTime})
        </foreach>
    </insert>
    <select id="selectAllBook" resultType="com.example.goods_admin.entity.Book">
        select * from book where status='1'
    </select>
</mapper>
5、工具类
package com.example.goods_admin.utils;

import com.alibaba.excel.EasyExcel;
import com.example.goods_admin.listener.DataListener;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

public class EasyExcelUtil {


    public static <T> List<T> read(String filePath) {
        File f = new File(filePath);
        try (FileInputStream fis = new FileInputStream(f)) {
            return read(String.valueOf(fis));
        } catch (FileNotFoundException e) {

        } catch (IOException e) {

        }

        return null;
    }

    public static <T> List<T> read(InputStream inputStream, final Class<T> clazz) {
        if (inputStream == null) {

        }

        // 有个很重要的点 DataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        DataListener<T> listener = new DataListener<>();

        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, clazz, listener).sheet().doRead();
        return listener.getRows();
    }

    public static void write(String outFile, List<?> list) {
        Class<?> clazz = list.get(0).getClass();
        // 新版本会自动关闭流,不需要自己操作
        EasyExcel.write(outFile, clazz).sheet().doWrite(list);
    }

    public static void write(String outFile, List<?> list, String sheetName) {
        Class<?> clazz = list.get(0).getClass();
        // 新版本会自动关闭流,不需要自己操作
        EasyExcel.write(outFile, clazz).sheet(sheetName).doWrite(list);
    }

    public static void write(OutputStream outputStream, List<?> list, String sheetName) {
        Class<?> clazz = list.get(0).getClass();
        // 新版本会自动关闭流,不需要自己操作
        // sheetName为sheet的名字,默认写第一个sheet
        EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(list);
    }

    /**
     * 文件下载(失败了会返回一个有部分数据的Excel),用于直接把excel返回到浏览器下载
     */
    public static <T> void download(HttpServletResponse response, List<?> list, Class<T> tClass, String fileName, String sheetName) throws IOException {

        //如果 fileName 中包含空格字符,那么这些字符会被编码成 %20,因为在 URL 中空格字符必须被转义成 %20 才能正确传输
        fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        //必须:设置文件响应格式为二进制二进制流数据类型
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        //必须:设置 HTTP 响应的字符编码,以便客户端能够正确地解码和显示接收到的文本数据
        response.setCharacterEncoding("utf-8");
        //必须:通过设置 Content-Disposition 头部,告诉客户端如何处理接收到的响应内容,以及指定附件的文件名
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

        EasyExcel.write(response.getOutputStream(), tClass).sheet(sheetName).doWrite(list);
    }
}
6、sql脚本
/*
 Navicat Premium Data Transfer

 Source Server         : database
 Source Server Type    : MySQL
 Source Server Version : 80029
 Source Host           : localhost:3306
 Source Schema         : goods_admin

 Target Server Type    : MySQL
 Target Server Version : 80029
 File Encoding         : 65001

 Date: 28/01/2024 22:25:45
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book`  (
  `bookId` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `bookName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '书名',
  `author` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '作者',
  `price` double(10, 2) NULL DEFAULT NULL COMMENT '价格',
  `isbn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图书编号',
  `publisher` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '出版社',
  `releaseTime` datetime(0) NULL DEFAULT NULL COMMENT '发行日期',
  `status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '1' COMMENT '状态',
  PRIMARY KEY (`bookId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:2 个月前 )
c345bb45 6 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐