项目需求:SpringBoot读取excel并存入连接的数据库

路线:java-sql-jdbc-jpa-springboot

视频https://www.bilibili.com/video/BV12b411R7S2/?spm_id_from=333.788&vd_source=ad42090d7d6fcdfc144126ae0e2884ac

easycodehttps://blog.csdn.net/weixin_65644655/article/details/140277700

插件安装慢https://blog.csdn.net/m0_63622279/article/details/135415964

生成标准 代码https://blog.csdn.net/jokerdj233/article/details/105065973

https://www.cnblogs.com/fengzidexuanxue/p/17580858.html

https://blog.csdn.net/Loiterer_Y/article/details/136226332?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171474490616800185864592%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171474490616800185864592&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-1-136226332-null-null.nonecase&utm_term=%E4%B8%BA%E4%BB%80%E4%B9%88%E5%8F%AA%E8%83%BD%E9%80%89%E6%8B%A9java17%E3%80%8121%E3%80%8122&spm=1018.2226.3001.4450

读取excel

excel对应的实体类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.excel.Entity;

@Data
//指定excel单元格的列宽
@ColumnWidth(24)
//标题行的高度
@HeadRowHeight(15)
@ContentRowHeight(10)
public class DemoData {

    //ExcelProperty:绑定excel中的列
    @ExcelProperty("字符串标题")
    private String title;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Integer num;
    //这个注解的作用是:此属性不需要映射到Excel文件中
    @ExcelIgnore
    private String ignore;
}

测试读取过程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.excel;

@SpringBootTest
class ExcelApplicationTests {

	public static final String FILENAME = "demo.xlsx";

	//读取excel到实体列表中
	@Test
	void readExcelToEntity() {

		List<DemoData> list=EasyExcel.read(FILENAME).head(DemoData.class).sheet().doReadSync();
		//打印list
		list.forEach(System.out::println);
	}
	//读取excel到map列表中
	//列表中的每一行对应一个map
	@Test
	void readExcelToMap(){
		List<Map<String,Object>> list =EasyExcel.read(FILENAME).sheet().doReadSync();
		list.forEach(System.out::println);
	}

	//适应监听器读取excel文件,更灵活的处理数据方式

	@Test
	void readExcelWithListener(){
		EasyExcel.read(FILENAME,DemoData.class,new DemoReadListener()).sheet().doRead();
	}

}

1、Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class失败解决方案

排除自动配置:如果不需要Spring Boot的自动配置,可以在启动类上添加@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })注解来排除数据源的自动配置。

设置监听器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.excel.listener;

@Slf4j//日志
public class DemoReadListener extends AnalysisEventListener<DemoData> {


    private List<DemoData> datas = new ArrayList<>();

    //每读取到一行excel文件的数据就会执行一次
    @Override
    public void invoke(DemoData demoData, AnalysisContext analysisContext) {
        log.info("读取到的数据是{}",demoData);
        datas.add(demoData);

    }

    //全部数据读取完后执行,只会执行一次
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        datas.forEach(System.out::println);
    }
}

结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
DemoData(title=字符串0, date=Fri Jun 10 21:21:56 CST 2022, num=0, ignore=null)
DemoData(title=字符串1, date=Sat Jun 11 21:21:56 CST 2022, num=0, ignore=null)
DemoData(title=字符串2, date=Sun Jun 12 21:21:56 CST 2022, num=0, ignore=null)

---
    
{0=字符串0, 1=2022-6-10 21:21, 2=1}
{0=字符串1, 1=2022-6-11 21:21, 2=2}
{0=字符串2, 1=2022-6-12 21:21, 2=3}

---
2024-08-11T21:45:14.264+08:00  INFO 38408 --- [excel] [           main] c.e.excel.listener.DemoReadListener      : 读取到的数据是DemoData(title=字符串0, date=Fri Jun 10 21:21:56 CST 2022, num=1, ignore=null)
2024-08-11T21:45:14.269+08:00  INFO 38408 --- [excel] [           main] c.e.excel.listener.DemoReadListener      : 读取到的数据是DemoData(title=字符串1, date=Sat Jun 11 21:21:56 CST 2022, num=2, ignore=null)
2024-08-11T21:45:14.269+08:00  INFO 38408 --- [excel] [           main] c.e.excel.listener.DemoReadListener      : 读取到的数据是DemoData(title=字符串2, date=Sun Jun 12 21:21:56 CST 2022, num=3, ignore=null)
    
DemoData(title=字符串0, date=Fri Jun 10 21:21:56 CST 2022, num=1, ignore=null)
DemoData(title=字符串1, date=Sat Jun 11 21:21:56 CST 2022, num=2, ignore=null)
DemoData(title=字符串2, date=Sun Jun 12 21:21:56 CST 2022, num=3, ignore=null)

创建数据库

1
2
3
4
5
6
7
8
create table user(
id int AUTO_INCREMENT comment"自增主键" primary key,# 主键有问题
username char(10)null comment"用户名",
passuord varchar(18)null COMMENT "密码",
nickname varchar(50)null COMMENT "昵称",
phone varchar(11)null comment "电话",
email varchar(50)null comment"邮箱")
comment"用户表"

easycode生成代码:

https://blog.csdn.net/jokerdj233/article/details/105065973

数据库创建

1
2
3
4
5
6
7
8
create table user(
id int  comment"主键" primary key,
username char(10)null comment"用户名",
passuord varchar(18)null COMMENT "密码",
nickname varchar(50)null COMMENT "昵称",
phone varchar(11)null comment "电话",
email varchar(50)null comment"邮箱")
comment"用户表"

依赖pom.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>3.0.3</version>
		</dependency>

		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter-test</artifactId>
			<version>3.0.3</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>easyexcel</artifactId>
			<version>3.1.1</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.76</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
	</dependencies>
	<!--静态资源放行-->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>

		<!--导入mapper资源-->
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.xml</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*.xml</include>
				</includes>
			</resource>
		</resources>
	</build>

entity

实现了Serializable接口,使其对象可以被序列化。序列化是将对象的状态信息转换为可以存储或传输的形式的过程,通常是将对象状态保存为一系列字节,以便稍后可以重新构造对象。在Java中,如果一个对象需要被发送到远程对象、持久化到文件或数据库中,或者通过网络传输,那么该对象所属的类必须实现Serializable接口。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.example.excel_upload.entity;

import lombok.Data;
import java.io.Serializable;

/**
 * 用户表(User)实体类
 *
 * @author makejava
 * @since 2024-08-13 08:39:48
 */
@Data
public class User implements Serializable {
    private static final long serialVersionUID = -27082111527479054L;
    /**
     * 主键
     */
    private Integer id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 昵称
     */
    private String nickname;
    /**
     * 电话
     */
    private String phone;
    /**
     * 邮箱
     */
    private String email;
}

dao

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.example.excel_upload.dao;

import com.example.excel_upload.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.domain.PageRequest;


import java.util.List;

/**
 * 用户表(User)表数据库访问层
 *
 * @author makejava
 * @since 2024-08-13 08:39:48
 */
@Mapper
public interface UserDao {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    /**
     * 查询指定行数据
     *
     * @param user     查询条件
     * @param pageable 分页对象
     * @return 对象列表
     */
    List<User> queryAllByLimit(User user, @Param("pageable") PageRequest pageable);

    /**
     * 统计总行数
     *
     * @param user 查询条件
     * @return 总行数
     */
    long count(User user);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int insert(User user);

    /**
     * 批量新增数据(MyBatis原生foreach方法)
     *
     * @param entities List<User> 实例对象列表
     * @return 影响行数
     */
    int insertBatch(@Param("entities") List<User> entities);

    /**
     * 批量新增或按主键更新数据(MyBatis原生foreach方法)
     *
     * @param entities List<User> 实例对象列表
     * @return 影响行数
     * @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
     */
    int insertOrUpdateBatch(@Param("entities") List<User> entities);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 影响行数
     */
    int update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);

    /**
     * 查询所有数据
     * @return
     */
    List<User> queryAll();
}


mapper

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?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.excel_upload.dao.UserDao">

    <resultMap type="com.example.excel_upload.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="username" column="username" jdbcType="VARCHAR"/>
        <result property="password" column="password" jdbcType="VARCHAR"/>
        <result property="nickname" column="nickname" jdbcType="VARCHAR"/>
        <result property="phone" column="phone" jdbcType="VARCHAR"/>
        <result property="email" column="email" jdbcType="VARCHAR"/>
    </resultMap>



    <!--查询单个-->
    <select id="queryById" resultMap="UserMap">
        select id,
               username,
               password,
               nickname,
               phone,
               email
        from user
        where id = #{id}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
        id, username, password, nickname, phone, email
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="nickname != null and nickname != ''">
                and nickname = #{nickname}
            </if>
            <if test="phone != null and phone != ''">
                and phone = #{phone}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
        limit #{pageable.offset}, #{pageable.pageSize}
    </select>


    <!--查询所有数据-->
    <select id="queryAll" resultMap="UserMap">
        select
        id, username, password, nickname, phone, email
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="nickname != null and nickname != ''">
                and nickname = #{nickname}
            </if>
            <if test="phone != null and phone != ''">
                and phone = #{phone}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
    </select>


    <!--统计总行数-->
    <select id="count" resultType="java.lang.Long">
        select count(1)
        from user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null and username != ''">
                and username = #{username}
            </if>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="nickname != null and nickname != ''">
                and nickname = #{nickname}
            </if>
            <if test="phone != null and phone != ''">
                and phone = #{phone}
            </if>
            <if test="email != null and email != ''">
                and email = #{email}
            </if>
        </where>
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, nickname, phone, email)
        values (#{username}, #{password}, #{nickname}, #{phone}, #{email})
    </insert>

    <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, nickname, phone, email)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.phone}, #{entity.email})
        </foreach>
    </insert>

    <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
        insert into user(username, password, nickname, phone, email)
        values
        <foreach collection="entities" item="entity" separator=",">
            (#{entity.username}, #{entity.password}, #{entity.nickname}, #{entity.phone}, #{entity.email})
        </foreach>
        on duplicate key update
        username = values(username),
        password = values(password),
        nickname = values(nickname),
        phone = values(phone),
        email = values(email)
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update user
        <set>
            <if test="username != null and username != ''">
                username = #{username},
            </if>
            <if test="password != null and password != ''">
                password = #{password},
            </if>
            <if test="nickname != null and nickname != ''">
                nickname = #{nickname},
            </if>
            <if test="phone != null and phone != ''">
                phone = #{phone},
            </if>
            <if test="email != null and email != ''">
                email = #{email},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete
        from user
        where id = #{id}
    </delete>

</mapper>


service

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.example.excel_upload.service;

import com.example.excel_upload.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.util.List;

/**
 * 用户表(User)表服务接口
 *
 * @author makejava
 * @since 2024-08-13 08:39:48
 */
public interface UserService {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    User queryById(Integer id);

    /**
     * 分页查询
     *
     * @param user        筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    Page<User> queryByPage(User user, PageRequest pageRequest);

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User insert(User user);

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    User update(User user);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    boolean deleteById(Integer id);
    
      /**
     * @Description 查询全部数据
     * 
     * @return 对象列表
     */
    List<User> queryAll();


}

impl

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.example.excel_upload.service.impl;

import com.example.excel_upload.entity.User;
import com.example.excel_upload.dao.UserDao;
import com.example.excel_upload.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;


/**
 * 用户表(User)表服务实现类
 *
 * @author makejava
 * @since 2024-08-13 08:40:30
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }


    /**
     * 分页查询
     *
     * @param user        筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    @Override
    public Page<User> queryByPage(User user, PageRequest pageRequest) {
        long total = this.userDao.count(user);
        return new PageImpl<>(this.userDao.queryAllByLimit(user, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User insert(User user) {
        this.userDao.insert(user);
        return user;
    }

    /**
     * 修改数据
     *
     * @param user 实例对象
     * @return 实例对象
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }
    
       /**
     * 查询全部数据
     * @return
     */
    @Override
    public List<User> queryAll() {
        return this.userDao.queryAll();
    }
}

controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.example.excel_upload.controller;

import com.example.excel_upload.entity.User;
import com.example.excel_upload.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * 用户表(User)表控制层
 *
 * @author makejava
 * @since 2024-08-13 08:39:47
 */
@RestController
@RequestMapping("user")
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    /**
     * 分页查询
     *
     * @param user        筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    @GetMapping
    public ResponseEntity<Page<User>> queryByPage(User user, PageRequest pageRequest) {
        return ResponseEntity.ok(this.userService.queryByPage(user, pageRequest));
    }
    @RequestMapping("/showAll")
    public List<User> show(){
        List<User> users = this.userService.queryAll();
//        System.out.println(users);
        return users;
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("{id}")
    public ResponseEntity<User> queryById(@PathVariable("id") Integer id) {
        return ResponseEntity.ok(this.userService.queryById(id));
    }

    /**
     * 新增数据
     *
     * @param user 实体
     * @return 新增结果
     */
    @PostMapping
    public ResponseEntity<User> add(User user) {
        return ResponseEntity.ok(this.userService.insert(user));
    }

    /**
     * 编辑数据
     *
     * @param user 实体
     * @return 编辑结果
     */
    @PutMapping
    public ResponseEntity<User> edit(User user) {
        return ResponseEntity.ok(this.userService.update(user));
    }

    /**
     * 删除数据
     *
     * @param id 主键
     * @return 删除是否成功
     */
    @DeleteMapping
    public ResponseEntity<Boolean> deleteById(Integer id) {
        return ResponseEntity.ok(this.userService.deleteById(id));
    }

}


添加了 queryAll()方法

http://localhost:8080/user/showAll

easyexcel保存数据

listener:分批次存入数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.example.excel_upload.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.example.excel_upload.dao.UserDao;
import com.example.excel_upload.entity.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * ClassName: UserReadListener
 * Package: com.example.excel_upload.controller.listener
 * Description:
 *
 * @Author kong
 * @Create 2024/8/13 8:44
 * @Version 1.0
 */

@Slf4j
@Component
@RequiredArgsConstructor
public class UserReadListener extends AnalysisEventListener<User> {

    private final UserDao userDao;

    //批大小
    private static final Integer BATCH_COUNT =20;
    //list初始容量
    private List<User> datas = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    @Override
    public void invoke(User user, AnalysisContext context) {
        log.info("读取到了一行数据id={}",user.getId());

        datas.add(user);

        if (datas.size()>=BATCH_COUNT){
            //批量添加到数据库

            userDao.insertBatch(datas);
            datas=ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }



    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("数据读取完毕");
        datas.forEach(System.out::println);

        if (!datas.isEmpty()){
            userDao.insertBatch(datas);

        }
    }
}

修改了Userdao.xml中的insert方法(加入了id)

或者修改数据库id为自增主键

test

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.excel_upload;

import com.alibaba.excel.EasyExcel;
import com.example.excel_upload.dao.UserDao;
import com.example.excel_upload.listener.UserReadListener;
import com.example.excel_upload.entity.User;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ExcelUploadApplicationTests {

	@Resource
	UserDao userDao;
	@Test
	void contextLoads() {
	}

	//读取用户数据到数据库
	@Test
	void readUserToDB(){
		EasyExcel.read("user.xlsx", User.class,new UserReadListener(userDao)).sheet().doRead();
	}
}

清空数据库中表的数据

1
truncate table user;

写入excel

将数据库的数据保存到excel

test单元测试

1
2
3
4
5
6
7
8
9
	//将数据库数据写入到excel
	@Test
	void writeUserToExcel(){
		//从数据库中查找数据
		List<User> users=userDao.queryAll();
		EasyExcel.write("userData.xlsx",User.class)
				.sheet("用户")
				.doWrite(users);
	}

entity中添加user的注解,指定导出excel的属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Data
@HeadRowHeight(30)//导出表格的属性
@ContentRowHeight(20)
@ColumnWidth(20)
public class User implements Serializable {
    private static final long serialVersionUID = -27082111527479054L;
    /**
     * 主键
     */
    @ExcelProperty("序号")//指定列名
    @ColumnWidth(10)
    private Integer id;
}

web导出

http://localhost:8080/excel/download

controller层

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Controller
@RequestMapping("excel")
@RequiredArgsConstructor
public class ExcelController {

    @Resource
    private UserService userService;

    /**
     * 导出excel文件
     * 失败了会返回部分数据的excel
     * @param response
     * @throws IOException
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/vnd.ms-excel");
        //这里URLEncoder.encode可以防止中文乱码当然和easyexcel没有关系
        //+替换为空格
        String fileName= URLEncoder.encode("用户文件","UTF-8").replaceAll("\\+","%20");
        //文件写入响应流了,通过附件的形式进行了下载
        response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName +".xlsx");
        EasyExcel.write(response.getOutputStream(), User.class).sheet("测试").doWrite(userService.queryAll());

    }

    /**
     * 导出excel文件
     * 如果下载过程中存在异常会返回一个json错误提示
     * @param response
     * @throws IOException
     */
    @GetMapping("download2")
    public void download2(HttpServletResponse response) throws IOException {

        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/vnd.ms-excel");
            //这里URLEncoder.encode可以防止中文乱码当然和easyexcel没有关系
            //+替换为空格
            String fileName= URLEncoder.encode("用户文件","UTF-8").replaceAll("\\+","%20");
            //文件写入响应流了,通过附件的形式进行了下载
            response.setHeader("Content-disposition","attachment;filename*=utf-8''"+fileName +".xlsx");


            //如果出错就不要关闭输出流
            EasyExcel.write(response.getOutputStream(), User.class)
                    .autoCloseStream(Boolean.FALSE)
                    .sheet("测试").doWrite(userService.queryAll());
        }catch (Exception e){
            //下载出错,返回json串
            //重置响应流
            response.reset();
            //重新指定响应流的格式
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            Map<String,Object> map= new HashMap<>();
            map.put("code",-1);
            map.put("msg","Excel导出失败");
            response.getWriter().println(JSON.toJSONString(map));
        }

    }

}

web上传

数据库对于主键的设置说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# id为主键,重复会报错
# [2024-08-13 15:33:50] [23000][1062] Duplicate entry '1' for key 'PRIMARY'
insert into user(id,username, password, nickname, phone, email)
values ('1','11','11','111','111','111');

# Field 'id' doesn't have a default value
# 数据库没有设置id为自增,没有默认值
insert into user(username, password, nickname, phone, email)
values ('test','11','111','111','111');

# 如果主键冲突,仍想插入数据(更新原来的数据,需要指定更新列)
insert into user(id,username, password, nickname, phone, email)
values ('1','update','update','111','111','111')
ON DUPLICATE KEY UPDATE username=VALUES(username),password=VALUES(password);


# 批量上传数据
insert into user(username, password, nickname, phone, email)
values ('test','11','111','111','111'),('test','11','111','111','111');

controller

1
2
3
4
5
6
7
	@PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(),User.class,new UserReadListener(userDao)).sheet().doRead();
        return "上传成功";

    }

封装到excel工具类

alt+enter:快速如自动创建类、方法、变量等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.example.excel_upload.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;

/**
 * ClassName: ExcelUtils
 * Package: com.example.excel_upload.utils
 * Description: 上传excel文件并解析的工具类
 * 
 * 解析结果为Class类型的列表
 *
 * @Author kong
 * @Create 2024/8/13 16:53
 * @Version 1.0
 */
@Slf4j
public class ExcelUtils {

    public static <T> List<T> getExcelModelData(final InputStream inputstream, Class<T> clazz) {
        if (Objects.isNull(inputstream)) {
            throw new NullPointerException("输入流不能为空!");
        }
        ExcelReaderBuilder result = EasyExcel.read(inputstream, clazz, null);
        ExcelReaderSheetBuilder sheet1 = result.sheet();

        return sheet1.doReadSync();
    }
}


//解析结果为
// [User(id=1, username=update, password=update, nickname=张三, phone=111, email=111@111.com), User(id=2, username=112, password=12, nickname=李四, phone=222, email=222@222.com)]

controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
	@PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
//        EasyExcel.read(file.getInputStream(),User.class,new UserReadListener(userDao)).sheet().doRead();
        List<User> list = ExcelUtils.getExcelModelData(file.getInputStream(), User.class);
        System.out.println(list);
        if (userDao.insertBatch(list)>0) {
            return "上传成功";
        }

        return "上传失败";

    }

前端界面设计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 创建项目vue
vue create vue

> Manually select features
>(*) Babel
>(*) Router
> 2.x
y	
> In package.json
n

# 安装element-ui
npm i element-ui -S
# 安装axios
npm i axios -S
  • vue.config.js:工程的全局配置文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer:{
    port:8000
  },
  chainWebpack:config =>
      config.plugin('html').tap(args => {
        args[0].title = 'vue学习';
        return args;
      })
})
  • main.js:全局对象的挂载,#app-div的id,new一个实例挂载到div中,所有的对象都会在div中去渲染
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import Vue from 'vue'
import App from './App.vue'
import router from './router'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI,{size:'small'});

import '@/assets/css/global.css'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
  • route-index.js中配置路由-把路由和页面连接起来
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('../views/HomeView.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

homeview.vue

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<template>
  <div>
    <!--    外部盒子-->
    <el-container>
      <!--      侧边栏-->
      <el-aside>

      </el-aside>
      <el-container>
        <!--        头部区域-->
        <el-header>

        </el-header>
        <!--        主体区域-->
        <el-main>
          <div style="box-shadow:0 0 10px rgba(0,0,0,.1);padding:10px 20px;border-radius: inherit;">
            早安大胖狗开心快乐每一天
          </div>
          <!--          excel导入导出-->
          <div style="display: flex;margin-right: 10px">
            <el-card style="width:100%">
              <div slot="header" class="clearfix">
                <span><strong>Excel导入导出数据</strong></span>

                <div style="margin-top: 20px">
                  <el-upload
                      class="upload-demo"
                      action=""
                      :on-change="handleChange"
                      :on-success="handleSuccess"
                      :before-upload="beforeUpload"
                      :file-list="fileList"
                      :auto-upload="false">
                    <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
                    <el-button
                        style="margin-left: 10px;"
                        size="small"
                        type="success"
                        @click="submitUpload">上传到数据库
                    </el-button>


                    <el-button style="margin-left: 30px" type="warning" @click="downloadExcel">下载数据</el-button>

                  </el-upload>
                </div>


              </div>
              <div>
                <el-table :data="excel_users">
                  <el-table-column label="ID" prop="id"></el-table-column>
                  <el-table-column label="用户名" prop="username"></el-table-column>
                  <el-table-column label="昵称" prop="nickname"></el-table-column>
                  <el-table-column label="电话" prop="phone"></el-table-column>
                  <el-table-column label="邮箱" prop="email"></el-table-column>
                </el-table>
              </div>
            </el-card>

          </div>

        </el-main>
      </el-container>

    </el-container>
  </div>

</template>

<script>

import axios from "axios";

export default {
  name: 'HomeView',
  data(){
    return{
      excel_users: [],
      fileList: []
    }
  },
  //页面加载好再去请求数据,页面加载完后触发
  mounted() {

    axios.get('http://localhost:8080/user/showAll').then(res => {
      console.log(res.data)//后台返回的数据
      this.excel_users = res.data

    })
  },
  methods: {

    downloadExcel() {
      window.location.href = 'http://localhost:8080/excel/download';
    },

    handleChange(file, fileList) {
      this.fileList = fileList; // 更新文件列表
    },
    beforeUpload(file) {
      // 可以在这里做一些文件校验
      return false; // 不使用Element UI的自动上传功能
    },
    submitUpload() {
      if (this.fileList.length === 0) {
        this.$message.error('请选择文件!');
        return;
      }

      const formData = new FormData();
      formData.append('file', this.fileList[0].raw); // 假设我们只上传一个文件

      axios.post('http://localhost:8080/excel/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
          // 注意:这里通常不需要显式设置Content-Type,因为FormData的Content-Type会自动设置
          // 如果后端有问题,可能需要调整或去掉这个头部
        }
      }).then(response => {
        this.$message({
          message: response.data,
          type: 'success'
        });
        //刷新当前页面
        window.location.reload();
        // 清除文件列表(可选)
        this.fileList = [];
      })
          .catch(error => {
            console.error('上传失败:', error);
            this.$message.error('上传失败!');
          });
    },
    handleSuccess(response, file, fileList) {
      // Element UI的自动上传成功回调,但因为我们禁用了自动上传,所以这里不会用到
    }
  }
}
</script>