day06項(xiàng)目【整合阿里云OSS和Excel導(dǎo)入分類】

1 整合阿里云OSS

01-阿里云存儲(chǔ)OSS

一、對(duì)象存儲(chǔ)OSS

為了解決海量數(shù)據(jù)存儲(chǔ)與彈性擴(kuò)容,項(xiàng)目中我們采用云存儲(chǔ)的解決方案- 阿里云OSS。?

1、開(kāi)通“對(duì)象存儲(chǔ)OSS”服務(wù)

(1)申請(qǐng)阿里云賬號(hào)

(2)實(shí)名認(rèn)證

(3)開(kāi)通“對(duì)象存儲(chǔ)OSS”服務(wù)

(4)進(jìn)入管理控制臺(tái)

2、創(chuàng)建Bucket

選擇:標(biāo)準(zhǔn)存儲(chǔ)、公共讀、不開(kāi)通

3、上傳默認(rèn)頭像

創(chuàng)建文件夾avatar,上傳默認(rèn)的用戶頭像






02-后端集成OSS

一、新建云存儲(chǔ)微服務(wù)

1、在service模塊下創(chuàng)建子模塊service-oss

2、配置pom.xml

service-oss上級(jí)模塊service已經(jīng)引入service的公共依賴,所以service-oss模塊只需引入阿里云oss相關(guān)依賴即可,

service父模塊已經(jīng)引入了service-base模塊,所以Swagger相關(guān)默認(rèn)已經(jīng)引入

<dependencies>

? ? ? ? <!-- 阿里云oss依賴 -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.aliyun.oss</groupId>

? ? ? ? ? ? <artifactId>aliyun-sdk-oss</artifactId>

? ? ? ? </dependency>

? ? ? ? <!-- 日期工具欄依賴 -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>joda-time</groupId>

? ? ? ? ? ? <artifactId>joda-time</artifactId>

? ? ? ? </dependency>

? ? </dependencies>

3、配置application.properties

#服務(wù)端口

server.port=8002

#服務(wù)名

spring.application.name=service-oss

#環(huán)境設(shè)置:dev、test、prod

spring.profiles.active=dev

#阿里云OSS

#不同的服務(wù)器,地址不同

aliyun.oss.file.endpoint=your endpoint

aliyun.oss.file.keyid=your accessKeyId

aliyun.oss.file.keysecret=your accessKeySecret

#bucket可以在控制臺(tái)創(chuàng)建,也可以使用java代碼創(chuàng)建

aliyun.oss.file.bucketname=guli-file

4、logback-spring.xml


5、創(chuàng)建啟動(dòng)類

創(chuàng)建OssApplication.java

package com.atguigu.oss;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication

@ComponentScan(basePackages = {"com.atguigu"})

public class OssApplication {

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(OssApplication.class,args);

? ? }

}

6、啟動(dòng)項(xiàng)目

報(bào)錯(cuò)

spring boot 會(huì)默認(rèn)加載org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration這個(gè)類,

而DataSourceAutoConfiguration類使用了@Configuration注解向spring注入了dataSource bean,又因?yàn)轫?xiàng)目(oss模塊)中并沒(méi)有關(guān)于dataSource相關(guān)的配置信息,所以當(dāng)spring創(chuàng)建dataSource bean時(shí)因缺少相關(guān)的信息就會(huì)報(bào)錯(cuò)。

@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)

即可成功:

二、實(shí)現(xiàn)文件上傳

1、從配置文件讀取常量

創(chuàng)建常量讀取工具類:ConstantPropertiesUtil.java

使用@Value讀取application.properties里的配置內(nèi)容

用spring的 InitializingBean 的 afterPropertiesSet 來(lái)初始化配置信息,這個(gè)方法將在所有的屬性被初始化后調(diào)用。

//當(dāng)項(xiàng)目已啟動(dòng),spring接口,spring加載之后,執(zhí)行接口一個(gè)方法

@Component

public class ConstantPropertiesUtil implements InitializingBean {

????//讀取配置文件內(nèi)容

? ? @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;


????//定義公開(kāi)靜態(tài)常量

? ? public static String END_POINT;

????public static String ACCESS_KEY_ID;

????public static String ACCESS_KEY_SECRET;

????public static String BUCKET_NAME;


????@Override

? ? public void afterPropertiesSet()throws Exception {

????????END_POINT =endpoint;

????????ACCESS_KEY_ID =keyId;

????????ACCESS_KEY_SECRET =keySecret;

????????BUCKET_NAME =bucketName;

????}

}

2、文件上傳

創(chuàng)建Service接口:uploadFileAvatar.java

public interface OssService {

????String uploadFileAvatar(MultipartFile file);

}

實(shí)現(xiàn):OssServiceImpl.java

參考SDK中的:Java->上傳文件->簡(jiǎn)單上傳->流式上傳->上傳文件流

@Service

public class OssServiceImpl implements OssService {

????//上傳頭像到oss

? ? @Override

? ? public String uploadFileAvatar(MultipartFile file) {

????????// Endpoint以杭州為例,其它Region請(qǐng)按實(shí)際情況填寫。

? ? ? ? String endpoint =ConstantPropertiesUtil.END_POINT;

????????String accessKeyId =ConstantPropertiesUtil.ACCESS_KEY_ID;

????????String accessKeySecret =ConstantPropertiesUtil.ACCESS_KEY_SECRET;

????????String bucketName =ConstantPropertiesUtil.BUCKET_NAME;


????????try {

????????????// 創(chuàng)建OSSClient實(shí)例。

? ? ? ? ? ? OSS ossClient =new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);

????????????// 上傳文件流。

? ? ? ? ? ? InputStream inputStream = file.getInputStream();

????????????//獲取文件名稱

? ? ? ? ? ? String fileName = file.getOriginalFilename();

????????????//調(diào)用oss方法實(shí)現(xiàn)上傳

? ? ? ? ? ? //第一個(gè)參數(shù) Bucket名稱

? ? ? ? ? ? //第二個(gè)參數(shù) 上傳到oss文件路徑和文件名稱 如/aa/bb/1.jpg

? ? ? ? ? ? //第三個(gè)參數(shù) 上傳文件輸入流

? ? ? ? ? ? ossClient.putObject(bucketName,fileName,inputStream);

????????????// 關(guān)閉OSSClient。

? ? ? ? ? ? ossClient.shutdown();


?????????? //把上傳之后文件的路徑返回

? ? ? ? ? ? //需要把上傳到阿里云oss路徑手動(dòng)拼接出來(lái)

? ? ? ? ? ? //https://guli-file-1010.oss-cn-beijing.aliyuncs.com/11.jpg

? ? ? ? ? ? String url ="https://"+bucketName+"."+endpoint+"/"+fileName;

????????????return url;

????????}catch (IOException e) {

????????????e.printStackTrace();

????????????return null;

????????}

????}

}

3、控制層

創(chuàng)建controller:FileUploadController.java

@Api(description="阿里云文件管理")

@RestController

@RequestMapping("/eduoss/fileoss")

@CrossOrigin

public class OssController {

????@Autowired

? ? private OssService ossService;


????//上傳頭像的方法

? ? @ApiOperation(value ="文件上傳")

????@PostMapping

? ? public R uploadOssFile(@ApiParam(name ="file", value ="文件", required =true)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? @RequestParam("file")MultipartFile file){

????????//獲取上傳文件

? ? ? ? //返回上傳到oss的路徑

? ? ? ? String url =ossService.uploadFileAvatar(file);

????????return R.ok().data("url",url);

????}

}

4、重啟oss服務(wù)

5、Swagger中測(cè)試文件上傳

解決上傳文件覆蓋問(wèn)題:

//1 在文件名稱里面添加隨機(jī)唯一的值

String uuid =UUID.randomUUID().toString().replaceAll("-","");

//如qwadsfadeasd01.jpg

fileName =uuid+fileName;


//2 把文件按照日期進(jìn)行分類

//2020/11/12/01.jpg

//獲取當(dāng)前日期

String datePath =new DateTime().toString("yyyy/MM/dd");

//拼接

//如2020/11/12/qwadsfadeasd01.jpg

fileName =datePath +"/" + fileName;

測(cè)試:

6、配置nginx反向代理

配置nginx實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)的功能:

驗(yàn)證:



03-前端整合上傳組件

一、前端整合圖片上傳組件

1、復(fù)制頭像上傳組件

從vue-element-admin復(fù)制組件:

vue-element-admin/src/components/ImageCropper

vue-element-admin/src/components/PanThumb

2、前端參考實(shí)現(xiàn)

src/views/components-demo/avatarUpload.vue

3、前端添加文件上傳組件

src/views/edu/teacher/save.vue

template:


引入組件模塊:

import?ImageCropper?from?'@/components/ImageCropper'

import?PanThumb?from?'@/components/PanThumb'

4、設(shè)置默認(rèn)頭像(也可不設(shè)置)

onfig/dev.env.js中添加阿里云oss bucket地址

OSS_PATH:'"https://guli-file.oss-cn-beijing.aliyuncs.com"'

組件中初始化頭像默認(rèn)地址

const defaultForm = {

? ......,

? avatar: process.env.OSS_PATH + '/avatar/default.jpg'

}

5、js腳本實(shí)現(xiàn)上傳和圖片回顯

export?default?{

????components:?{?ImageCropper,?PanThumb?},

????data(){

????????return?{

????????????teacher:{

.........

????????????},

????????????//上傳彈框組件是否顯示

????????????imagecropperShow:false,

????????????imagecropperKey:0,//上傳組件key值

????????????BASE_API:?process.env.BASE_API,?//?接口API地址

????????????saveBtnDisabled:?false?//?保存按鈕是否禁用,

????????}

????},

?? ......,

????methods: {

????????//其他函數(shù)

????????......,

??????? close(){//關(guān)閉上傳彈框方法

????????????this.imagecropperShow?=?false;

????????????//?上傳失敗后,重新打開(kāi)上傳組件時(shí)初始化組件,否則顯示上一次的上傳結(jié)果

????????????this.imagecropperKey?=?this.imagecropperKey?+?1

????????},

????????cropSuccess(data){//上傳成功方法

????????????this.imagecropperShow?=?false;

????????????//上傳之后接口返回圖片地址

????????????this.teacher.avatar?=?data.url

????????????//?上傳成功后,重新打開(kāi)上傳組件時(shí)初始化組件,否則顯示上一次的上傳結(jié)果

????????????this.imagecropperKey?=?this.imagecropperKey?+?1

????????},

二、測(cè)試文件上傳

前后端聯(lián)調(diào)



2 EasyExcel導(dǎo)入課程分類

01-EasyExcel讀寫Excel的基本使用

一、Excel導(dǎo)入導(dǎo)出的應(yīng)用場(chǎng)景

1、數(shù)據(jù)導(dǎo)入:減輕錄入工作量

2、數(shù)據(jù)導(dǎo)出:統(tǒng)計(jì)信息歸檔

3、數(shù)據(jù)傳輸:異構(gòu)系統(tǒng)之間數(shù)據(jù)傳輸

二、EasyExcel簡(jiǎn)介

1、EasyExcel特點(diǎn)

????Java領(lǐng)域解析、生成Excel比較有名的框架有Apache poi、jxl等。但他們都存在一個(gè)嚴(yán)重的問(wèn)題就是非常的耗內(nèi)存。如果你的系統(tǒng)并發(fā)量不大的話可能還行,但是一旦并發(fā)上來(lái)后一定會(huì)OOM或者JVM頻繁的full gc。

????EasyExcel是阿里巴巴開(kāi)源的一個(gè)excel處理框架,以使用簡(jiǎn)單、節(jié)省內(nèi)存著稱。EasyExcel能大大減少占用內(nèi)存的主要原因是在解析Excel時(shí)沒(méi)有將文件數(shù)據(jù)一次性全部加載到內(nèi)存中,而是從磁盤上一行行讀取數(shù)據(jù),逐個(gè)解析。

????EasyExcel采用一行一行的解析模式,并將一行的解析結(jié)果以觀察者的模式通知處理(AnalysisEventListener)。



02-Excel寫

一、創(chuàng)建項(xiàng)目,實(shí)現(xiàn)EasyExcel對(duì)Excel寫操作

1、創(chuàng)建一個(gè)普通的maven項(xiàng)目

項(xiàng)目名:excel-easydemo

2、pom中引入xml相關(guān)依賴

<dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.alibaba</groupId>

? ? ? ? ? ? <artifactId>easyexcel</artifactId>

? ? ? ? ? ? <version>2.1.1</version>

? ? ? ? </dependency>

? ? </dependencies>

3、創(chuàng)建實(shí)體類

設(shè)置表頭和添加的數(shù)據(jù)字段

@Data

public class DemoData {

????//設(shè)置excel表頭名稱

? ? @ExcelProperty("學(xué)生編號(hào)")

????private Integer sno;

????@ExcelProperty("學(xué)生姓名")

????private String sname;

}

4 、實(shí)現(xiàn)寫操作

TestEasyExcel.java

(1)創(chuàng)建方法循環(huán)設(shè)置要添加到Excel的數(shù)據(jù)

//循環(huán)設(shè)置要添加的數(shù)據(jù),最終封裝到list集合中

private static List<DemoData> getData(){

? ? ? ? List<DemoData> list = new ArrayList<>();

? ? ? ? for (int i=0;i<10;i++){

? ? ? ? ? ? DemoData data = new DemoData();

? ? ? ? ? ? data.setSno(i);

? ? ? ? ? ? data.setSname("lucy"+i);

? ? ? ? ? ? list.add(data);

? ? ? ? }

? ? ? ? return list;

? ? }

(2)實(shí)現(xiàn)最終的添加操作(寫法一)

public static void main(String[] args) {

? ? ? ? //實(shí)現(xiàn)excel寫的操作

? ? ? ? //1 設(shè)置寫入文件夾地址和excel文件名稱

? ? ? ? String filename = "F:\\write.xlsx";

? ? ? ? //2 調(diào)用easyexcel里面的方法實(shí)現(xiàn)寫操作

? ? ? ? //write方法兩個(gè)參數(shù):第一個(gè)參數(shù)文件路徑名稱,第二個(gè)參數(shù)實(shí)體類class

? ? ? ? EasyExcel.write(filename,DemoData.class).sheet("學(xué)生列表").doWrite(getData());

? ? }

(3)實(shí)現(xiàn)最終的添加操作(寫法二)

public static void main(String[] args) throws Exception {

????????// 寫法2,方法二需要手動(dòng)關(guān)閉流

????????//實(shí)現(xiàn)excel寫的操作

? ? ? ? //1 設(shè)置寫入文件夾地址和excel文件名稱

? ? ? ? String filename = "F:\\write.xlsx";

? ? ? ??ExcelWriter excelWriter=EasyExcel.write(fileName,DemoData.class).build();

????????WriteSheet writeSheet=EasyExcel.writerSheet("寫入方法二").build();

????????excelWriter.write(data(),writeSheet);

????????/// 千萬(wàn)別忘記finish 會(huì)幫忙關(guān)閉流

????????excelWriter.finish();

? ? }


03-Excel讀

一、實(shí)現(xiàn)EasyExcel對(duì)Excel讀操作

1、創(chuàng)建實(shí)體類

@Data

public class DemoData {

? ? //設(shè)置excel表頭名稱

? ? @ExcelProperty(value = "學(xué)生編號(hào)",index = 0)

? ? private Integer sno;

? ? @ExcelProperty(value = "學(xué)生姓名",index = 1)

? ? private String sname;

}

2、創(chuàng)建讀取操作的監(jiān)聽(tīng)器

public class ExcelListener extends AnalysisEventListener<DemoData> {

? ? //一行一行讀取excel內(nèi)容

? ? @Override

? ? public void invoke(DemoData demoData, AnalysisContext analysisContext) {

? ? ? ? System.out.println("******"+demoData);

? ? }

? ? //讀取表頭內(nèi)容

? ? @Override

? ? public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {

? ? ? ? System.out.println("表頭:"+headMap);

? ? }

? ? //讀取完成之后

? ? @Override

? ? public void doAfterAllAnalysed(AnalysisContext analysisContext) {

? ? }

}

3、調(diào)用實(shí)現(xiàn)最終的讀取

public class TestEasyExcel {

? ? public static void main(String[] args) {

? ? ? ? //實(shí)現(xiàn)excel讀操作

????????// 寫法1:

? ? ? ? String filename = "F:\\write.xlsx";

????????// 這里 需要指定讀用哪個(gè)class去讀,然后讀取第一個(gè)sheet 文件流會(huì)自動(dòng)關(guān)閉

? ? ? ? EasyExcel.read(filename,DemoData.class,new ExcelListener()).sheet().doRead();

????????// 寫法2:

????????InputStream in = new BufferedInputStream(new FileInputStream("F:\\01.xlsx"));

? ? ? ? ExcelReader excelReader = EasyExcel.read(in, DemoData.class, new ExcelListener()).build();

? ? ? ? ReadSheet readSheet = EasyExcel.readSheet(0).build();

? ? ? ? excelReader.read(readSheet);

? ? ? ? // 這里千萬(wàn)別忘記關(guān)閉,讀的時(shí)候會(huì)創(chuàng)建臨時(shí)文件,到時(shí)磁盤會(huì)崩的

? ? ? ? excelReader.finish();

? ? }


04-前端頁(yè)面的實(shí)現(xiàn)

一、Excel模板(本案例中使用靜態(tài)模板)

1、編輯Excel模板

2、將文件上傳至阿里云OSS

二、配置路由

1、添加路由

{

????path:?'/subject',

????component:?Layout,

????redirect:?'/subject/table',

????name:?'課程分類管理',

????meta:?{?title:?'課程分類管理',?icon:?'example'?},

????children:?[

??????{

????????path:?'table',

????????name:?'課程分類列表',

????????component:?()?=>?import('@/views/edu/subject/list'),

????????meta:?{?title:?'課程分類列表',?icon:?'table'?}

??????},

??????{

????????path:?'tree',

????????name:?'添加課程分類',

????????component:?()?=>?import('@/views/edu/subject/save'),

????????meta:?{?title:?'添加課程分類',?icon:?'tree'?}

??????}

????]

??},

2、添加vue組件

三、表單組件save.vue

1、js定義數(shù)據(jù)

<script>

export?default?{

????data(){

????????return?{

????????????BASE_API:?process.env.BASE_API,?//?接口API地址

????????????importBtnDisabled:?false,?//?按鈕是否禁用,

????????????loading:?false

????????}

????},

2、template

<template>

??<div?class="app-container">

????<el-form?label-width="120px">

??????<el-form-item?label="信息描述">

????????<el-tag?type="info">excel模版說(shuō)明</el-tag>

????????<el-tag>

??????????<i?class="el-icon-download"/>

??????????<a?:href="'/static/01.xlsx'">點(diǎn)擊下載模版</a>

????????</el-tag>

??????</el-form-item>


??????<el-form-item?label="選擇Excel">

????????<el-upload

??????????ref="upload" ?? //相當(dāng)于id='upload'

??????????:auto-upload="false"

??????????:on-success="fileUploadSuccess"

??????????:on-error="fileUploadError"

??????????:disabled="importBtnDisabled"

??????????:limit="1"? //限制每次只能上傳一個(gè)文件

??????????:action="BASE_API+'/eduservice/edu-subject/addSubject'"

??????????name="file"

??????????accept="application/vnd.ms-excel">

??????????<el-button?slot="trigger"?size="small"?type="primary">選取文件</el-button>

??????????<el-button

????????????:loading="loading"

????????????style="margin-left:?10px;"

????????????size="small"

????????????type="success"

????????????@click="submitUpload">上傳到服務(wù)器</el-button>

????????</el-upload>

??????</el-form-item>

????</el-form>

??</div>

</template>

3、js上傳方法

methods:{

????????//點(diǎn)擊按鈕上傳文件到接口里面

????????submitUpload(){

????????????this.importBtnDisabled?=?true

????????????this.loading?=?true

????????????//js:document.getElementById("upload").submit()

????????????this.$refs.upload.submit()

????????},

????????........

????}

4、回調(diào)函數(shù)

????????//上傳成功

????????fileUploadSuccess(){

????????????//提示信息

????????????this.loading?=?false

????????????this.$message({

????????????????type:?'success',

????????????????message:'添加課程分類成功'

????????????})

????????????//跳轉(zhuǎn)課程分類列表

????????},

????????//上傳失敗

????????fileUploadError(){

????????????this.loading?=?false

????????????this.$message({

????????????????type:'error',

????????????????message:'添加課程失敗'

????????????})

????????}



05-課程分類管理接口

一、添加依賴

1、service-edu模塊配置依賴

<dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.alibaba</groupId>

? ? ? ? ? ? <artifactId>easyexcel</artifactId>

? ? ? ? ? ? <version>2.1.1</version>

? ? ? ? </dependency>

? ? </dependencies>

二、業(yè)務(wù)處理

1、EduSubjectController

@Api(description="課程分類管理")

@RestController

@RequestMapping("/eduservice/edu-subject")

@CrossOrigin //跨域

public class EduSubjectController {

? ? @Autowired

? ? private EduSubjectService subjectService;

? ? //添加課程分類

? ? //獲取上傳過(guò)來(lái)的文件把文件內(nèi)容讀取出來(lái)

? ? @PostMapping("addSubject")

? ? public R addSubject(MultipartFile file){

? ? ? ? //上傳過(guò)來(lái)的excel文件

? ? ? ? subjectService.saveSubject(file,subjectService);

? ? ? ? return R.ok();

? ? }

}

2、創(chuàng)建和Excel對(duì)應(yīng)的實(shí)體類

@Data

public class SubjectData {

? ? @ExcelProperty(index = 0)

? ? private String oneSubjectName;

? ? @ExcelProperty(index = 1)

? ? private String twoSubjectName;

}

3、EduSubjectService

(1)接口

public interface EduSubjectService extends IService<EduSubject> {

? ? //添加課程分類

? ? void saveSubject(MultipartFile file,EduSubjectService subjectService);

}

(2)實(shí)現(xiàn)類

@Service

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

? ? //添加課程分類

? ? @Override

? ? public void saveSubject(MultipartFile file,EduSubjectService subjectService) {

? ? ? ? try {

? ? ? ? ? ? //文件輸入流

? ? ? ? ? ? InputStream in = file.getInputStream();

? ? ? ? ? ? //調(diào)用方法進(jìn)行讀取

? ? ? ? ? ? EasyExcel.read(in, SubjectData.class,new SubjectExcelListener(subjectService)).sheet().doRead();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

}

4、創(chuàng)建讀取Excel監(jiān)聽(tīng)器

public class SubjectExcelListener extends AnalysisEventListener<SubjectData> {

? ? //因?yàn)镾ubjectExcelListener不能交給spring進(jìn)行管理,需要自己new,不能注入其他對(duì)象

? ? //不能實(shí)現(xiàn)數(shù)據(jù)庫(kù)操作

? ? public EduSubjectService subjectService;

? ? public SubjectExcelListener() {}

? ? public SubjectExcelListener(EduSubjectService subjectService) {

? ? ? ? this.subjectService = subjectService;

? ? }


? ? //讀取excel內(nèi)容,一行一行進(jìn)行讀取

? ? @Override

? ? public void invoke(SubjectData subjectData, AnalysisContext analysisContext) {

? ? ? ? if (subjectData == null){

? ? ? ? ? ? throw new GuliException(20001,"文件數(shù)據(jù)為空");

? ? ? ? }

? ? ? ? //一行一行讀取,每次讀取有兩個(gè)值,第一個(gè)值一級(jí)分類,第二個(gè)值二級(jí)分類

? ? ? ? //判斷一級(jí)分類是否重復(fù)

? ? ? ? EduSubject exitOneSubject = this.exitOneSubject(subjectService, subjectData.getOneSubjectName());

? ? ? ? if (exitOneSubject == null){//沒(méi)有相同一級(jí)分類,進(jìn)行添加

? ? ? ? ? ? exitOneSubject = new EduSubject();

? ? ? ? ? ? exitOneSubject.setParentId("0");

? ? ? ? ? ? exitOneSubject.setTitle(subjectData.getOneSubjectName()); //一級(jí)分類名稱

? ? ? ? ? ? subjectService.save(exitOneSubject);

? ? ? ? }


? ? ? ? String pid = exitOneSubject.getId();

? ? ? ? //添加二級(jí)分類

? ? ? ? //判斷二級(jí)分類是否重復(fù)

? ? ? ? EduSubject exitTwoSubject = this.exitTwoSubject(subjectService, subjectData.getTwoSubjectName(), pid);

? ? ? ? if (exitTwoSubject == null){

? ? ? ? ? ? exitTwoSubject = new EduSubject();

? ? ? ? ? ? exitTwoSubject.setParentId(pid);

? ? ? ? ? ? exitTwoSubject.setTitle(subjectData.getTwoSubjectName()); //一級(jí)分類名稱

? ? ? ? ? ? subjectService.save(exitTwoSubject);

? ? ? ? }

? ? }


? ? //判斷一級(jí)分類不能重復(fù)添加

? ? private EduSubject exitOneSubject(EduSubjectService subjectService, String name){

? ? ? ? QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();

? ? ? ? wrapper.eq("title",name);

? ? ? ? wrapper.eq("parent_id","0");

? ? ? ? EduSubject oneSubject = subjectService.getOne(wrapper);

? ? ? ? return oneSubject;

? ? }

? ? //判斷二級(jí)分類不能重復(fù)添加

? ? private EduSubject exitTwoSubject(EduSubjectService subjectService, String name,String pid){

? ? ? ? QueryWrapper<EduSubject> wrapper = new QueryWrapper<>();

? ? ? ? wrapper.eq("title",name);

? ? ? ? wrapper.eq("parent_id",pid);

? ? ? ? EduSubject twoSubject = subjectService.getOne(wrapper);

? ? ? ? return twoSubject;

? ? }


? ? @Override

? ? public void doAfterAllAnalysed(AnalysisContext analysisContext) {

? ? }

}




06-分類列表展示

一、前端實(shí)現(xiàn)

1、參考 views/tree/index.vue

2、創(chuàng)建api

api/edu/subject.js

import?request?from?'@/utils/request'

export?default{

????//1?課程分類

????getSubjectList(){

????????return?request({

????????????url:`/eduservice/edu-subject/getAllSubject`,

????????????method:'get'

????????})

????}

}

3、list.vue

<template>

??<div?class="app-container">

????<el-input?v-model="filterText"?placeholder="Filter?keyword"?style="margin-bottom:30px;"?/>

????<el-tree

??????ref="tree2"

??????:data="data2"

??????:props="defaultProps"

??????:filter-node-method="filterNode"

??????class="filter-tree"

??????default-expand-all

????/>

??</div>

</template>

<script>

import?subject?from?'@/api/edu/subject'

export?default?{

??data()?{

????return?{

??????filterText:?'',

??????data2:?[],?//返回所有分類數(shù)據(jù)

??????defaultProps:?{

????????children:?'children',

????????label:?'title'

??????}

????}

??},

??created(){

????this.getAllSubjectList()

??},

??watch:?{

????filterText(val)?{

??????this.$refs.tree2.filter(val)

????}

??},

??methods:?{

????getAllSubjectList(){

??????subject.getSubjectList()

????????.then(response=>{

????????????this.data2?=?response.data.list

????????})

????},

????filterNode(value,?data)?{

??????if?(!value)?return?true

??????return?data.title.toLowerCase().indexOf(value.toLowerCase())?!==?-1? //優(yōu)化前端過(guò)濾功能

????}

??}

}

</script>

二、后端實(shí)現(xiàn)

1、創(chuàng)建vo

//一級(jí)分類

@Data

public class OneSubject {

????private String id;

????private String title;

????//一個(gè)一級(jí)分類含有多個(gè)二級(jí)分類

? ? private Listchildren =new ArrayList<>();

}

//二級(jí)分類

@Data

public class TwoSubject {

????private String id;

????private String title;

}

2、創(chuàng)建controller

????//課程分類列表(樹形)
????@ApiOperation(value = "嵌套數(shù)據(jù)列表")

? ? @GetMapping("getAllSubject")

? ? public R getAllSubject(){

? ? ? ? //list集合泛型是一級(jí)分類

? ? ? ? List<OneSubject> list = subjectService.getAllOneTwoSubject();

? ? ? ? return R.ok().data("list",list);

? ? }

3、創(chuàng)建service

接口

????//課程分類列表(樹形)

? ? List<OneSubject> getAllOneTwoSubject();

實(shí)現(xiàn)Final

????@Override

? ? public List<OneSubject> getAllOneTwoSubject() {

? ? ? ? //1 獲取一級(jí)分類 parent_id=0

? ? ? ? QueryWrapper<EduSubject> wrapperOne = new QueryWrapper<>();

? ? ? ? wrapperOne.eq("parent_id","0");

? ? ? ? List<EduSubject> oneSubjectList = baseMapper.selectList(wrapperOne);

? ? ? ? //2 獲取二級(jí)分類

? ? ? ? QueryWrapper<EduSubject> wrapperTwo = new QueryWrapper<>();

? ? ? ? wrapperTwo.ne("parent_id","0");

? ? ? ? List<EduSubject> twoSubjectList = baseMapper.selectList(wrapperTwo);


? ? ? ? //創(chuàng)建list集合用于存儲(chǔ)最終封裝數(shù)據(jù)

? ? ? ? List<OneSubject> finalSubjectList = new ArrayList<>();


? ? ? ? //3 封裝一級(jí)分類

? ? ? ? //查詢出來(lái)的所有一級(jí)分類list集合遍歷,得到每一個(gè)分類對(duì)象,獲取每一個(gè)一級(jí)分類對(duì)象值

? ? ? ? //封裝到要求的list集合里面 List<OneSubject> finalSubjectList

? ? ? ? for (int i = 0; i < oneSubjectList.size(); i++) {

? ? ? ? ? ? //得到oneSubjectList每個(gè)eduSubject對(duì)象

? ? ? ? ? ? EduSubject eduSubject = oneSubjectList.get(i);


? ? ? ? ? ? //把eduSubject里面獲取出來(lái)的值,放到oneSubject對(duì)象里面

? ? ? ? ? ? OneSubject oneSubject = new OneSubject();

//? ? ? ? ? ? oneSubject.setId(eduSubject.getId());

//? ? ? ? ? ? oneSubject.setTitle(eduSubject.getTitle());

? ? ? ? ? ? BeanUtils.copyProperties(eduSubject,oneSubject);

? ? ? ? ? ? //多個(gè)oneSubject放到finalSubjectList里面

? ? ? ? ? ? finalSubjectList.add(oneSubject);


? ? ? ? ? ? //4 封裝二級(jí)分類

? ? ? ? ? ? //在一級(jí)分類循環(huán)遍歷查詢所有二級(jí)分類

? ? ? ? ? ? //創(chuàng)建list集合封裝每一個(gè)一級(jí)分類的二級(jí)分類

? ? ? ? ? ? List<TwoSubject> twoFinalSubjectList = new ArrayList<>();


? ? ? ? ? ? for (int m = 0; m < twoSubjectList.size(); m++) {

? ? ? ? ? ? ? ? //獲取每個(gè)二級(jí)分類

? ? ? ? ? ? ? ? EduSubject tSubject = twoSubjectList.get(m);


? ? ? ? ? ? ? ? //判斷二級(jí)分類parentid和一級(jí)分類id是否一樣

? ? ? ? ? ? ? ? if (tSubject.getParentId().equals(eduSubject.getId())){

? ? ? ? ? ? ? ? ? ? //把tSubject值復(fù)制到twoSubject里面,放到twoFinalSubjectList里面

? ? ? ? ? ? ? ? ? ? TwoSubject twoSubject = new TwoSubject();

? ? ? ? ? ? ? ? ? ? BeanUtils.copyProperties(tSubject,twoSubject);

? ? ? ? ? ? ? ? ? ? twoFinalSubjectList.add(twoSubject);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? //把一級(jí)下面所有的二級(jí)分類放到一級(jí)分類里面

? ? ? ? ? ? oneSubject.setChildren(twoFinalSubjectList);

? ? ? ? }

? ? ? ? return finalSubjectList;

? ? }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容