Day205.阿里云OSS、讲师管理前后端【上传头像功能】、课程分类管理【环境搭建、Excel文件读取添加数据库】 -谷粒学院

谷粒学院

阿里云存储OSS

一、对象存储OSS

为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案 - 阿里云 OSS 。

1、开通“对象存储OSS”服务

( 0 )www.aliyun.com

( 1 )申请阿里云账号

( 2 )实名认证

( 3 )开通 “ 对象存储 OSS” 服务

( 4 )进入管理控制台

2、创建Bucket

选择:标准存储、公共读、不开通

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFX57Xvq-1614433115438)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227111640686.png)]

3、上传默认头像

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SVM0jE9I-1614433115440)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227112407033.png)]

4、创建RAM子用户

一般在公司中,我们没有权限可以直接操作公司的阿里云账户,

所以我们需要获取创建阿里云OSS许可证(阿里云颁布id和秘钥)

通过java代码上传

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5erGm7PQ-1614433115442)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227112908227.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9btAUdvc-1614433115447)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227113032001.png)]


二、使用SDK

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Zq3qfGP-1614433115451)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227113317085.png)]


1、创建Maven项目

com.achang
aliyun-oss

2、pom

<!--aliyunOSS-->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.1.0</version>
</dependency>

3、找到编码时需要用到的常量值

( 1 ) endpoint

( 2 ) bucketName

(3)accessKeyId

(4)accessKeySecret

4、测试创建Bucket的连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-76RyoVU7-1614433115453)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227113924731.png)]

创建存储空间

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

// 创建存储空间。
ossClient.createBucket(bucketName);

// 关闭OSSClient。

5、判断存储空间是否存在

@Test
public void testExist() {
    
    
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
boolean exists = ossClient.doesBucketExist(bucketName);
System.out.println(exists);
// 关闭OSSClient。
ossClient.shutdown();
}

6、设置存储空间的访问权限

@Test
public void testAccessControl() {
    
    
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 设置存储空间的访问权限为:公共读。
ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
// 关闭OSSClient。
ossClient.shutdown();
}

讲师管理后端【上传讲师头像功能】

一、新建云存储微服务

1、在service模块下创建子模块service_oss

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XSLz1G7O-1614433115454)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227114654383.png)]

2、配置pom.xml

service_oss上级模块service已经引入service的公共依赖,所以service-oss模块只需引入阿里云oss相关依赖即,service父模块已经引入了service_base模块,所以Swagger相关默认已经引入

<!-- 阿里云oss依赖 -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!--日期工具栏依赖-->
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
</dependency>

3、配置application.properties

#服务端口
server.port=8002
#服务名
spring.application.name=service-oss
#环境设置:dev、test、prod
spring.profiles.active=dev
#阿里云 OSS
#不同的服务器,地址不同
aliyun.oss.file.endpoint=oss-cn-hangzho3u.aliyuncs.com
aliyun.oss.file.keyid=LTAI4GBABS7Sq8M21Lf2RNwLuu
aliyun.oss.file.keysecret=ynfsD31FLdcRoQVFSI2dHP7AeoKaf4o
#bucket可以在控制台创建,也可以使用java代码创建
aliyun.oss.file.bucketname=achang-edu

4、logback-spring.xml

5、创建启动类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfaSyQTG-1614433115456)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227120846687.png)]

6、启动项目

报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcBJlWmT-1614433115457)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227121105257.png)]

spring boot 会默认加载 org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration 这个类,而 DataSourceAutoConfiguration 类使用了 @Configuration 注解向 spring 注入了 dataSource bean ,又因为项目( oss 模块)中并没有关于 dataSource 相关的配置信息,所以当 spring 创建 dataSource bean 时因缺少相关的信息就会报错。

解决办法

@SpringBootApplication 注解上加上 exclude ,解除自动加载 DataSourceAutoConfiguration

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

二、实现文件上传

1、从配置文件读取常量

创建常量读取工具类:ConstantPropertiesUtil.java

使用@Value读取application.properties里的配置内容

用spring的 InitializingBean 的 afterPropertiesSet 来初始化配置信息,这个方法将在所有的属性被初始化后调用。

//常量类,读取配置文件application.properties中的配置
@Component
public class ConstantPropertiesUtil implements InitializingBean {
    
    

    @Value("${aliyun.oss.file.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.file.keyid}")
    private String keyid;

    @Value("${aliyun.oss.file.keysecret}")
    private String keysecret;

    @Value("${aliyun.oss.file.bucketname}")
    private String bucketname;

    public static String END_POINT;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String BUCKET_NAME;


    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        KEY_ID=this.keyid;
        KEY_SECRET=this.keysecret;
        END_POINT=this.endpoint;
        BUCKET_NAME=this.bucketname;
    }

}

2、文件上传

创建Service接口:OssService.java

public interface OssService {
    
    
    //上传头像到OSS
    String uploadFileAvatar(MultipartFile file);

}

实现:OssServiceImpl.java

参考SDK中的:Java->上传文件->简单上传->流式上传->上传文件流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5UM3NyS-1614433115460)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227130619095.png)]

@Service
public class OssServiceImpl implements OssService {
    
    

    //上传头像到OSS
    @Override
    public String uploadFileAvatar(MultipartFile file) {
    
    

        //工具类获取值
        String endpoint = ConstantPropertiesUtil.END_POINT;
        String accessKeyId = ConstantPropertiesUtil.KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;


        InputStream inputStream = null;


        try {
    
    
            // 创建OSS实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 获取上传文件的输入流
            inputStream = file.getInputStream();

            //获取文件名称
            String fileName = file.getOriginalFilename();

            //调用oss实例中的方法实现上传
            //参数1: Bucket名称
            //参数2: 上传到oss文件路径和文件名称 /aa/bb/1.jpg
            //参数3: 上传文件的输入流
            ossClient.putObject(bucketName, fileName, inputStream);
            // 关闭OSSClient。
            ossClient.shutdown();

            //把上传后文件路径返回
            //需要把上传到阿里云oss路径手动拼接出来
            //https://achang-edu.oss-cn-hangzhou.aliyuncs.com/default.gif
            String url = "http://"+bucketName+"."+endpoint+"/"+fileName ;

            return url;
        } catch (IOException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

}

3、控制层

创建controller:OssController.java

@Api(description="阿里云文件管理")
@CrossOrigin //跨域
@RestController
@RequestMapping("/edu_oss/fileoss")
public class OssController {
    
    

    @Autowired
    private OssService ossService;

    //上传头像
    @ApiOperation(value = "文件上传")
    @PostMapping("/upload")
    public R uploadOssFile(@RequestParam("file") MultipartFile file){
    
    
        //获取上传的文件

        //返回上传到oss的路径
        String url = ossService.uploadFileAvatar(file);

        //返回r对象
        return R.ok().data("url",url).message("文件上传成功");
    }

}

4、重启oss服务

5、Swagger中测试文件上传

访问:http://localhost:8002/swagger-ui.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rqhs57Vb-1614433115461)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227132837713.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KleoZyIq-1614433115463)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227132842455.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T2vw0NOB-1614433115466)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227132849172.png)]

测试通过


6、后端代码完善

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BR97O4nv-1614433115468)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227133822157.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v6hXgU7E-1614433115471)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227134950419.png)]

  • 测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vrwaac94-1614433115473)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227135054656.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AbdwrveY-1614433115475)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227135013038.png)]

7、nginx回顾

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ls6KniS9-1614433115476)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227135823133.png)]

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OSlZRllj-1614433115481)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227141248529.png)]


8、配置nginx反向代理

nginx根目录/conf/nginx.conf配置,配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBRZPrEl-1614433115488)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227141935096.png)]


修改nginx默认端口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-npogaTbS-1614433115490)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227141708658.png)]


配置nginx转发规则

下面的~表示正则匹配,不加要求完全匹配

说明:当地址中包含eduservice转发到8001端口,其他类似

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMr4d7BQ-1614433115492)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227144336118.png)]

	server {
    
    
        listen       9001;
        server_name  localhost;
		
		location ~ /eduservice/ {
    
    
				proxy_pass http://localhost:8001;
        }
        location ~ /edu_oss/ {
    
    
				proxy_pass http://localhost:8002;
        }

    }

修改前端 端口号为9001

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smXA2tbp-1614433115493)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227144534653.png)]

  • 测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQQxF0ph-1614433115495)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227152757492.png)]

启动前端9528

启动nginx81,监听9001

9001会监听请求转发

启动后端8001、8002


讲师管理前端【上传头像功能】

一、创建上传组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vxg9D1xY-1614433115496)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227153628008.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZvw7wQ2-1614433115506)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227153927067.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5y7r6E3-1614433115508)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227153639885.png)]

二、使用组件

guli-admin\src\views\edu\teacher\save.vue

<!-- 讲师头像:TODO -->
<!-- 讲师头像 -->
<el-form-item label="讲师头像">
    <!-- 头衔缩略图 -->
    <pan-thumb :image="teacher.avatar" />
    <!-- 文件上传按钮 -->
    <el-button
               type="primary"
               icon="el-icon-upload"
               @click="imagecropperShow = true"
               >更换头像
    </el-button>
    <!--
v-show:是否显示上传组件
:key:类似于id,如果一个页面多个图片上传控件,可以做区分
:url:后台上传的url地址
@close:关闭上传组件
@crop-upload-success:上传成功后的回调 -->
    <image-cropper
                   v-show="imagecropperShow"
                   :width="300"
                   :height="300"
                   :key="imagecropperKey"
                   :url="BASE_API + '/admin/oss/file/upload'"
                   field="file"
                   @close="close"
                   @crop-upload-success="cropSuccess"
                   />
</el-form-item>

引入组件模块

//引入头像组件
import ImageCropper from '@/components/ImageCropper'
import PanThumb from '@/components/PanThumb'

声明组件

export default {
    
    
  //声明引入的组件
  components:{
    
    ImageCropper,PanThumb},
    ...
    
}

给组件中用到的变量定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrVGHrJa-1614433115510)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227172014251.png)]

    close(){
    
     //关闭上传弹框的方法
      this.imagecropperShow=false;
      //上传组件初始化
      this.imagecropperKey = this.imagecropperKey+1
    },
    cropSuccess(data){
    
     //上传成功的方法
      this.imagecropperShow=false;
      //参数resp.data被封装到了方法参数data中了
      this.teacher.avatar = data.url
      this.imagecropperKey = this.imagecropperKey+1
    }

三、js脚本上传和图片回显

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvoBvcfO-1614433115511)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227171040950.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYtvU4UR-1614433115515)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227162413794.png)]


四、测试文件上传

前后端联调

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AnWO4siy-1614433115517)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227171354112.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UNjgaBeI-1614433115522)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227171442278.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V1Jitwey-1614433115524)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227171455251.png)]


课程分类管理【环境搭建、Excel文件读取添加数据库】

0.课程分类存储结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FG1ojRmW-1614433115527)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227173425271.png)]

读写Excel表格导入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rXbNeXlU-1614433115529)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227173632515.png)]

一、数据库语句

CREATE TABLE `edu_subject` (
  `id` char(19) NOT NULL COMMENT '课程类别ID',
  `title` varchar(10) NOT NULL COMMENT '类别名称',
  `parent_id` char(19) NOT NULL DEFAULT '0' COMMENT '父ID',
  `sort` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序字段',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='课程科目';

#
# Data for table "edu_subject"
#

INSERT INTO `edu_subject` VALUES ('1178214681118568449','后端开发','0',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681139539969','Java','1178214681118568449',1,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681181483010','前端开发','0',3,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681210843137','JavaScript','1178214681181483010',4,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681231814658','云计算','0',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681252786178','Docker','1178214681231814658',5,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681294729217','Linux','1178214681231814658',6,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681324089345','系统/运维','0',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681353449473','Linux','1178214681324089345',7,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681382809602','Windows','1178214681324089345',8,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681399586817','数据库','0',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681428946945','MySQL','1178214681399586817',9,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681454112770','MongoDB','1178214681399586817',10,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681483472898','大数据','0',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681504444418','Hadoop','1178214681483472898',11,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681529610242','Spark','1178214681483472898',12,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681554776066','人工智能','0',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681584136193','Python','1178214681554776066',13,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681613496321','编程语言','0',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178214681626079234','Java','1178214681613496321',14,'2019-09-29 15:47:25','2019-09-29 15:47:25'),('1178585108407984130','Python','1178214681118568449',2,'2019-09-30 16:19:22','2019-09-30 16:19:22'),('1178585108454121473','HTML/CSS','1178214681181483010',3,'2019-09-30 16:19:22','2019-09-30 16:19:22');

二、EasyExcel读写Excel的基本使用

1、Excel导入导出的应用场景

  • 数据导入:减轻录入工作量

  • 数据导出:统计信息归档

  • 数据传输:异构系统之间数据传输


2、EasyExcel简介

EasyExcel特点

  • Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。

  • EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

  • EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。


三、EasyExcel写

1、创建项目,实现EasyExcel对Excel写操作

1)、引入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.1</version>
</dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zcwt2t6Y-1614433115530)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227184400805.png)]

因为service已经引入,所以不用引入了,easyexcel:2.1.1poi:3.17对应


2)、 创建实体类

要求实体类属性和excel行列

设置表头和添加的数据字段

//设置表头和添加的数据字段
@Data
@ToString
public class DemoData {
    
    

    //学生序号
    //设置excel表头名称
    @ExcelProperty("学生序号")
    private Integer sno;

    //学生名称
    //设置excel表头名称
    @ExcelProperty("学生姓名")
    private String sname;

}

3)、实现写操作

创建方法循环设置要添加到Excel的数据(写法一)推荐

public class TestEasyExcel {
    
    
    public static void main(String[] args) {
    
    
        //实现excel写操作
        //1、设置写入文件夹地址和excel文件名称
        String filename="C:\\Users\\PePe\\Desktop\\DemoData.xlsx";

        //调用easyExcel里面的方法实现写操作
        //参数1:文件名称
        //参数2:对应实体类
        EasyExcel
                .write(filename,DemoData.class)
                .sheet("学生列表")
                .doWrite(getLists());
    }

    //创建方法返回List集合
    private static List<DemoData> getLists(){
    
    
        ArrayList<DemoData> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
    
    
            DemoData demoData = new DemoData();
            demoData.setSno(i);
            demoData.setSname("achang :"+ i);
            list.add(demoData);
        }
        return list;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlO3FraG-1614433115532)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227191353676.png)]

实现最终的添加操作(写法二)

    public static void main(String[] args) {
    
    
        //实现excel写操作
        //1、设置写入文件夹地址和excel文件名称
        String filename="C:\\Users\\PePe\\Desktop\\DemoData2.xlsx";

        ExcelWriter excelWriter = EasyExcel.write(filename, DemoData.class)
                .build();
        WriteSheet build = EasyExcel.writerSheet("写入方法2").build();
        // 这里 需要指定写用哪个class去写
        excelWriter.write(getLists(),build);
        // 千万别忘记finish 会帮忙关闭流
        excelWriter.finish();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V1I6hz9a-1614433115533)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227192031497.png)]


四、EasyExcel读

1、创建实体类

需要用index指定excel表格字段索引

//设置表头和添加的数据字段
@Data
@ToString
public class DemoData {
    
    

    //学生序号
    //设置excel表头名称
    //index代表excel表格字段索引
    @ExcelProperty(value = "学生序号",index = 0)
    private Integer sno;

    //学生名称
    //设置excel表头名称
    //index代表excel表格字段索引
    @ExcelProperty(value = "学生姓名",index = 1)
    private String sname;

}

2、创建读取操作的监听器

//创建读取excel监听器
public class ExcelListener extends AnalysisEventListener<DemoData> {
    
    
    //创建list集合封装最终的数据
    List<DemoData> list = new ArrayList<>();

    //一行一行去读取excle内容
    @Override
    public void invoke(DemoData demoData, AnalysisContext analysisContext) {
    
    
        System.out.println("***************"+demoData);
        list.add(demoData);
    }

    //读取excel表头信息
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
    
    
        System.out.println("表头信息========="+headMap);
    }

    //读取完成后执行
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    
    
    }
}

3、调用实现最终的读取

@Test
public void testReadExcel(){
    
    
    String filename="C:\\Users\\PePe\\Desktop\\DemoData2.xlsx";

    // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
    EasyExcel.read(filename,DemoData.class,new ExcelListener())
        .sheet().doRead();
}
  • 结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eiOLOstZ-1614433115536)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227194936541.png)]


五、课程分类添加功能_环境搭建

1、引入EasyExcel依赖

上面的service和service_edu已经引入了

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.1.1</version>
</dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gMKwAhcm-1614433115540)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227184400805.png)]

2、使用代码生成器生成课程分类代码

因为还是在service_edu里面,所以其他都不用改变,只用在下面的5、中修改为edu_subject数据库表即可生成

public class CodeGenerator {
    
    

//    @Test
    public void run() {
    
    

        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir("D:\\JavaStudy\\gulixueyuan\\guli_parent\\service\\service_edu" + "/src/main/java"); //输出目录

        gc.setAuthor("achang"); //作者名
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖

        gc.setServiceName("%sService");	//去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("00000");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();

        //生成包:com.achang.eduservice
        pc.setModuleName("eduservice"); //模块名
        pc.setParent("com.achang");

        //生成包:com.achang.oss.controller
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("edu_subject");//根据数据库哪张表生成,有多张表就加逗号继续填写

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀

        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作

        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);


        // 6、执行
        mpg.execute();
    }
}

六、课程分类读取Excel文件方法

1、EduSubjectController

com.achang.eduservice.controller.EduSubjectController

@RestController
@RequestMapping("/eduservice/edu-subject")
@CrossOrigin //解决跨域问题
@Api(description="课程分类管理")
public class EduSubjectController {
    
    

    @Autowired
    private EduSubjectService eduSubjectService;

    //添加课程分类
    //获取上传过来的文件,把文件内容读取出来
    @PostMapping("/addSubject")
    public R addSubject(MultipartFile file){
    
    
        //获取上传的excel文件 MultipartFile

        eduSubjectService.saveSubject(file,eduSubjectService);
        //判断返回集合是否为空

        return R.ok();
    }

}

2、创建和Excel对应的实体类

@Data
@ToString
public class SubjectData {
    
    

    //一级分类
    @ExcelProperty(index = 0)
    private String oneSubjectName;

    //二级分类
    @ExcelProperty(index = 1)
    private String twoSubjectName;
}

3、SubjectExcelListener监听器

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {
    
    

    //因为SubjectExcelListener態交给spring进行ioc管理,需要自己手动new,不能注入其他对象
    //不能实现数据库操作

    public EduSubjectService eduSubjectService;

    //有参,传递subjectService用于操作数据库
    public SubjectExcelListener(EduSubjectService eduSubjectService) {
    
    
        this.eduSubjectService = eduSubjectService;
    }

    //无参
    public SubjectExcelListener() {
    
    
    }

    //读取excel内容,一行一行读取
    @Override
    public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {
    
    
        //表示excel中没有数据,就不需要读取了
        if (subjectData==null){
    
    
            throw new AchangException(20001,"添加失败");
        }

        //一行一行读取,每次读取有两个值,第一个值一级分类,第二个值二级分类
        //判断是否有一级分类是否重复
        EduSubject existOneSubject = this.existOneSubject(eduSubjectService, subjectData.getOneSubjectName());
        if (existOneSubject == null){
    
     //没有相同的一级分类,进行添加
            existOneSubject = new EduSubject();
            existOneSubject.setParentId("0"); //设置一级分类id值,0代表为一级分类
            existOneSubject.setTitle(subjectData.getOneSubjectName());//设置一级分类名
            eduSubjectService.save(existOneSubject);//给数据库添加一级分类
        }

        //获取一级分类的id值
        String parent_id = existOneSubject.getId();
        //判断是否有耳机分类是否重复
        EduSubject existTwoSubject = this.existTwoSubject(eduSubjectService, subjectData.getTwoSubjectName(), parent_id);
        if (existTwoSubject==null){
    
    //没有相同的二级分类,进行添加
            existTwoSubject = new EduSubject();
            existTwoSubject.setParentId(parent_id); //设置二级分类id值
            existTwoSubject.setTitle(subjectData.getTwoSubjectName());//设置二级分类名
            eduSubjectService.save(existTwoSubject);//给数据库添加二级分类
        }

    }


    //判断一级分类不能重复添加
    private EduSubject existOneSubject(EduSubjectService eduSubjectService,String name){
    
    
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title",name)
                .eq("parent_id","0");
        EduSubject oneSubject = eduSubjectService.getOne(wrapper);
        return oneSubject;
    }

    //判断二级分类不能重复添加
    private EduSubject existTwoSubject(EduSubjectService eduSubjectService,String name,String parentId){
    
    
        QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();
        wrapper.eq("title",name)
                .eq("parent_id",parentId);
        EduSubject twoSubject = eduSubjectService.getOne(wrapper);
        return twoSubject;
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    
    

    }
}

4、SubjctService

1)接口

public interface EduSubjectService extends IService<EduSubject> {
    
    
    //添加课程分类
    void saveSubject(MultipartFile file,EduSubjectService eduSubjectService);
}

2)impl

@Service
public class EduSubjectServiceImpl extends ServiceImpl<EduSubjectMapper, EduSubject> implements EduSubjectService {
    
    

    //添加课程分类
    @Override
    public void saveSubject(MultipartFile file,EduSubjectService eduSubjectService) {
    
    
        try {
    
    
            //文件输入流
            InputStream is = file.getInputStream();

            //调用方法进行读取
            EasyExcel.read(is, SubjectData.class,new SubjectExcelListener(eduSubjectService))
                    .sheet().doRead();

        }catch (Exception e){
    
    
            e.printStackTrace();
            throw new AchangException(20002,"添加课程分类失败");
        }
    }
}

5、测试

先将数据库edu_subject表中的数据清空测试

DELETE FROM edu_subject

启动8001端口

访问:localhost:8001/swagger-ui.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PJFAnzLd-1614433115542)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227212343277.png)]

传入01.xlsx,Excel文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oVHpKjby-1614433115543)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227212414706.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LK3JFDkC-1614433115544)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227213402487.png)]

  • 查看数据库是否有数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PlNr6ZxX-1614433115545)(../../../../../AppData/Roaming/Typora/typora-user-images/image-20210227213434426.png)]

成功添加

猜你喜欢

转载自blog.csdn.net/qq_43284469/article/details/114193909