通过easyexcel实现数据导入功能

上一篇文章通过easyexcel导出数据到excel表格已经实现了简单的数据导出功能,这篇文章也介绍一下怎么通过easyexcel从excel表格中导入数据。

目录

一、前端代码

index.html

index.js

二、后端代码

controller

service

SongServiceImpl

三、功能预览

四、后端代码改进

频繁访问数据库问题


首先,需要在实体类中添加需要导出的字段,@ExcelIgnore注解表示该字段不会被导出到excel,当然,导入的时候也不会读这个字段。

package com.example.springboot.entity;

import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 歌曲
 * @author heyunlin
 * @version 1.0
 */
@Data
@TableName("song")
public class Song implements Serializable {
    private static final long serialVersionUID = 18L;

    @ExcelProperty("歌曲编号")
    @TableId(type = IdType.INPUT)
    private String id;

    /**
     * 歌曲名
     */
    @ExcelProperty("歌曲名")
    private String name;

    /**
     * 歌手
     */
    @ExcelProperty("歌手")
    private String singer;

    /**
     * 描述信息
     */
    @ExcelProperty("描述信息")
    private String note;

    /**
     * 最后一次修改时间
     */
    @ExcelIgnore
    @TableField("last_update_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime lastUpdateTime;
}

一、前端代码

在之前的easyui-crud项目的基础上修改,切换到最新代码分支springboot-crud2.0

springboot+mybatis实现增删查改的入门项目。icon-default.png?t=N7T8https://gitee.com/he-yunlin/springboot-crud.git在原来的页面上添加一个对话框,对话框内放一个easyui的filebox,同时,让filebox镶嵌在一个form表单内,因为要对该表单进行必填验证,只有选择了文件才能点击上传按钮。

index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>easyui crud应用</title>
		<link rel="stylesheet" href="/css/themes/icon.css" />
		<link rel="stylesheet" href="/css/themes/default/easyui.css" />
		<script src="/js/jquery.min.js"></script>
		<script src="/js/jquery.easyui.min.js"></script>
		<script src="/js/easyui-lang-zh_CN.js"></script>
		<script src="/js/datagrid-filter.js"></script>
		<script src="/js/index.js"></script>
	</head>
	
	<body>
		<div id="import_dialog" style="display:none;">
			<form id="import_form">
				<table style="border-spacing:5px;">
					<tr>
						<td>上传文件:</td>
						<td><input id="select_file" /></td>
					</tr>

					<tr>
						<td>文件名称:</td>
						<td><div id="file-name"></div></td>
					</tr>

					<tr>
						<td>文件大小:</td>
						<td><div id="file-size"></div></td>
					</tr>
				</table>
			</form>
		</div>

		<table id="song_list"></table>
	</body>
</html>

index.js

在原来的js代码中添加以下代码,这里渲染了刚刚在页面中添加的对话框和输入框,然后在表格的头部工具栏中添加了一个导入按钮。

let form = new FormData();

function importHandler() {
	requestUrl = "/song/import";

	$("#file-name").empty();
	$("#file-size").empty();

	$("#import_dialog").dialog("open");
}

$(document).ready(function() { 
    $("#select_file").filebox({
		buttonText: "选择文件",
		width: 200,
		required: true,
		onChange: function() {
			let file = $(this).context.ownerDocument.activeElement.files[0];

			form.append("file", file);

			$("#file-name").html(file.name);
			$("#file-size").html((file.size / 1024).toFixed(1) + "KB");
		}
	})

	$("#import_dialog").dialog({
		title: "数据导入",
		modal: true,
		closed: true,
		closable: true,
		draggable: false,
		buttons: [{
			iconCls: "icon-ok",
			text: "导入",
			handler: function() {
				let bool = $("#import_form").form("validate");

				if (bool) {
					$.ajax({
						url: requestUrl,
						data: form,
						cache: false,
						async: true,
						type: "POST",
						dataType: "json",
						processData: false,
						contentType: false,
						success: function (response) {
							$.messager.show({
								title: "系统消息",
								timeout: 5000,
								showType: "slide",
								msg: response.message,
							});

							$("#import_dialog").dialog("close");
							$("#member_list").datagrid("reload");
						},
						error: function (resp) {
							// 请求有响应
							if (resp && resp.responseJSON) {
								let response = resp.responseJSON;
								let status = resp.status;

								if (status) {
									let message;

									if (status === 404) { // 404 not found
										if (response.path) {
											message = "路径" + response.path + "不存在。";
										} else {
											message = response.message;
										}
									} else {
										message = response.message;
									}

									$.messager.alert("系统提示", message, "error");
									console.log("响应状态码:" + status + ", 响应消息:" + message);
								} else {
									console.log("请求没有响应状态码~");
								}
							} else {
								console.log("请求无响应~");
							}
						}
					});
				} else {
					$.messager.alert("系统提示", "请选择文件", "warning");
				}
			}
		}, {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				$("#select_file").filebox("initValue", null);
				$("#import_dialog").dialog("close");
				form.delete("file");
			}
		}]
	});

    let datagrid = $("#song_list").datagrid({
		url: "/song/selectByPage",
		title: "歌曲列表",
		toolbar: [{
			iconCls: "icon-upload",
			text: "导入",
			handler: function() {
				importHandler();
			}
		}],
		columns: [[
			{field: "id", title: "id", width: 200},
			{field: "name", title: "name", width: 200, editor: "textbox"},
			{field: "singer", title: "singer", width: 200, editor: "textbox"},
			{field: "note", title: "note", width: 200, editor: "textbox"},
			{field: "lastUpdateTime", title: "lastUpdateTime", width: 200, sortable: true}
		]]
	});

});

二、后端代码

controller

在controller中添加一个接口,请求类型为post,路径为/import,因为import是java关键字,所以方法名不能使用import,改成importData。

/**
 * @author heyunlin
 * @version 1.0
 */
@RestController
@RequestMapping(path = "/song", produces="application/json;charset=utf-8")
public class SongController {

    private final SongService songService;

    @Autowired
    public SongController(SongService songService) {
        this.songService = songService;
    }

    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public void importData(MultipartFile file) throws IOException {
        songService.importData(file);
    }

}

service

SongService接口添加importData()方法

/**
 * @author heyunlin
 * @version 1.0
 */
public interface SongService {

    void importData(MultipartFile file) throws IOException;
}

SongServiceImpl

通过easyexcel的API读取上传的文件,然后根据读取的结果,判断插入或修改现有数据。

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class SongServiceImpl implements SongService {

    private final SongMapper songMapper;

    @Autowired
    public SongServiceImpl(SongMapper songMapper) {
        this.songMapper = songMapper;
    }

    @Override
    public void importData(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), Song.class, new ReadListener<Song>() {
            @Override
            public void invoke(Song data, AnalysisContext context) {
                Song song = songMapper.selectById(data.getId());

                if (song == null) {
                    songMapper.insert(data);
                } else {
                    songMapper.updateById(data);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {

            }
        }).sheet().doRead();
    }

}

三、功能预览

如图,选择文件之后会显示文件的预览信息,点击导入,就会通过ajax上传文件到后台controller接口。

点击导入按钮,后端读取到了表格数据,并在控制台打印。

四、后端代码改进

上面的代码有一个很明显的问题

// 频繁查询数据库,excel表有多少行就查询多少次
Song song = songMapper.selectById(data.getId());

频繁访问数据库问题

对此,需要进行相应的改进,减少查询次数。

最有效的方法是一次性查询所有歌曲,然后以ID为key保存到一个map里,当然,这只适合数据量不是特别大的情况。

优化后的代码如下:

@Override
public void importData(MultipartFile file) throws IOException {
    // 查询全部歌曲信息
    List<Song> list = songMapper.selectList(null);
    
    // 把歌曲信息以ID为key保存到map中
    Map<String, Song> map = new HashMap<>(list.size());

    for (Song song : list) {
        map.put(song.getId(), song);
    }
    
    // 读excel表
    EasyExcel.read(file.getInputStream(), Song.class, new ReadListener<Song>() {
        @Override
        public void invoke(Song data, AnalysisContext context) {
            if (map.containsKey(data.getId())) {
                songMapper.updateById(data);
            } else {
                songMapper.insert(data);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {

        }
    }).sheet().doRead();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/168837.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电机应用开发-PID控制器参数整定

PID控制器参数整定 比例调节&#xff1a;调节作用快&#xff0c;系统一出现偏差&#xff0c;调节器立即将偏差放大输出。 积分调节&#xff1a;输出变化和输入偏差的积分成正比。输出不仅取决于偏差大小&#xff0c;还取决于偏差存在的时间。只要有偏差存在&#xff0c;尽管偏差…

7年经验之谈 —— 如何高效的开展app的性能测试?

APP性能测试是什么 从网上查了一下&#xff0c;貌似也没什么特别的定义&#xff0c;我这边根据自己的经验给出一个自己的定义&#xff0c;如有巧合纯属雷同。 客户端性能测试就是&#xff0c;从业务和用户的角度出发&#xff0c;设计合理且有效的性能测试场景&#xff0c;制定…

Androidstudio中build.gradle classpath如何添加

Androidstudio中build.gradle classpath如何添加 build.gradle classpath如何添加 build.gradle classpath如何添加 升级as之后&#xff0c;gradle版本也升级了&#xff0c;导致project的build.gradle中的写法也不一样了。 buildscript {repositories {google()mavenCentral(…

机器学习算法项目开发流程

机器学习算法是当今人工智能领域最重要的技术之一&#xff0c;它可以让计算机通过学习数据中的模式和规律来实现预测和决策。在实际应用中&#xff0c;开发一个成功的机器学习算法项目需要遵循一定的开发流程。本文将介绍一个常见的机器学习算法项目开发流程&#xff0c;帮助读…

Linux mmap 的作用是什么?

文章目录 1.简介2.相关函数3.mmap和常规文件操作的区别4.作用参考文献 1.简介 mmap&#xff08;memory map&#xff09;即内存映射&#xff0c;用于将一个文件或设备映射到进程的地址空间。 2.相关函数 创建映射函数&#xff1a; #include <sys/mman.h>void *mmap(v…

【Android】画面卡顿优化列表流畅度六(终篇)

上一篇&#xff1a; 【Android】画面卡顿优化列表流畅度五之下拉刷新上拉加载更多组件RefreshLayout修改 场景回顾&#xff1a; 业务经过一年半左右的运行后&#xff0c;出现了明显的列表卡顿情况&#xff1b;于是开始着手进行列表卡顿优化。目前的情况是&#xff1a; 网络图…

【18年扬大真题】给定有m个整数的递增有序数组a和有n个整数的递减有序数组b,将a数组和b数组归并为递增有序的数组c

【18年扬大真题】 给定有m个整数的递增有序数组a和有n个整数的递减有序数组b&#xff0c; 将a数组和b数组归并为递增有序的数组c。 void Merge(int arr[],int m ,int brr[],int n,int crr[]) {int i 0;int j n-1;int k 0;while(i < m&&j > 0) {if (arr[i] &l…

STM32 SPI

SPI介绍 SPI是Serial Pepheral interface缩写&#xff0c;串行外围设备接口。 SPI接口是一种高速的全双工同步通信总线&#xff0c;已经广泛应用在众多MCU、存储芯片、AD转换器和LCD之间。大部分STM32有3个SPI接口&#xff0c;本实验使用的是SPI1。 SPI同一时刻既能发送数据&…

简单模拟 Spring 创建的动态代理类(解释一种@Transactional事务失效的场景)

模拟 Spring 创建的动态代理类 本文主要目的是从父类和子类继承的角度去分析为什么在 Service 标注的业务类中使用 this 调用方法会造成事务失效。解释在这种情况下 this 为什么是原始类对象而不是代理类对象。 问题描述 在 Service 标注的业务类中&#xff0c;如果调用本类…

22年+21年 计算机能力挑战赛初赛C语言程序题 题解

22年 第14题&#xff1a;答案&#xff1a;33 #include<stdio.h> int x1; int f(int a) { static int x2;int n0;if(a%2){ static int x3;nx; }else { static int x5;nx; }return nx;} void main() { int sumx,i;for(i0;i<4;i) sumf(i); printf(&qu…

B站短视频如何去水印?一键解析下载B站视频!

在浏览B站视频时&#xff0c;我们有时会遇到带有水印的场景。这些水印可能会干扰我们对视频内容的观看体验&#xff0c;特别是在全屏观看时。此外&#xff0c;当我们想要保存或分享这些视频时&#xff0c;水印也会成为一种障碍。因此&#xff0c;去除水印的需求就变得非常迫切。…

JAXB:根据Java文件生成XML schema文件

说明 JAXB有个schemagen脚本&#xff0c;可以根据Java文件生成XML schema。这个工具在JAXB独立发布包中有&#xff0c;可以从官网下载JAXB的独立发布包&#xff1a; https://eclipse-ee4j.github.io/jaxb-ri/ 示例 使用schemagen -d <path> <java files>格式 …

4-5学生分数对应的成绩

![#include<stdio.h> int main(){float score;char grade;for(int i0;i<7;i){printf("请输入成绩&#xff1a;");scanf("%f",&score);while(score>100||score<0){printf("\n输入的成绩有误&#xff0c;请重新输入&#xff1a;&quo…

「实体京东」:汽车行业里的一盘棋

在消费升级&#xff0c;产业愈发蓬勃发展的未来&#xff0c;不仅是汽车行业&#xff0c;在接下来的一众工业细分方向&#xff0c;供应链的重构和进化都将成为新的主旋律&#xff0c;串点成链&#xff0c;串链成网&#xff0c;通过对成本、效率、体验的重构&#xff0c;进而真正…

5年经验之谈 —— 如何编写有效的接口测试?

简介&#xff1a; 在所有的开发测试中&#xff0c;接口测试是必不可少的一项。有效且覆盖完整的接口测试&#xff0c;不仅能保障新功能的开发质量&#xff0c;还能让开发在修改功能逻辑的时候有回归的能力&#xff0c;同时也是能优雅地进行重构的前提。编写接口测试要遵守哪些原…

css animation 动画如何保留动画结束后的状态 animation-fill-mode: forwards

css animation 动画如何保留动画结束后的状态 animation-fill-mode: forwards 一、问题描述 在做一个弹窗动画提示的时候遇到了一个问题&#xff1a; 在动画结束的时候&#xff0c;移除元素时会有闪一下的问题&#xff0c;像这样&#xff0c;有残留的痕迹。 我的动画结尾是这…

WebLOAD: 一站式性能测试工具

WebLOAD 是一款一站式前端性能测试工具&#xff0c;对测试人员来说使用非常方便。 它可以帮助前端工程师和测试快速对网页进行性能测试和优化&#xff0c;提高网页加载速度&#xff0c;减少页面卡顿和闪烁。 WebLOAD的特点、使用指南以及企业实际使用中的案列。 WebLOAD的特…

Nessus扫描结果出现在TE.IO或者ES容器结果查看问题解决方案

Nessus扫描结果出现在TE.IO或者ES容器结果查看问题解决方案 也是昨天晚上折腾了一个晚上到凌晨四点多,实在没有头绪,在论坛,贴吧,各种求助查贴,没有什么人解决.后面请教了一个安全圈的大佬朋友给解决了. 我的问题是在kali上的,所以只写了kali 的解决方案: 修改插件: vim /opt/…

零代码编程:用ChatGPT将SRT字幕文件批量转为Word文本文档

一个文件夹中有多个srt视频字幕文件&#xff0c;srt文件里面有很多时间轴&#xff1a; 现在想将其批量转为word文档&#xff0c;去掉里面与字符无关的时间轴&#xff0c;在ChatGPT中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个批量将SRT字幕文件转为…

R语言:利用biomod2进行生态位建模

在这里主要是分享一个不错的代码&#xff0c;喜欢的可以慢慢研究。我看了一遍&#xff0c;觉得里面有很多有意思的东西&#xff0c;供大家学习和参考。 利用PCA轴总结的70个环境变量&#xff0c;利用biomod2进行生态位建模&#xff1a; #------------------------------------…