service-core
module
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
</dependency>
</dependencies>
<build>
<!-When the project is packaged, the*.xml file in the java directory will also be packed->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
Createdto
bag
ExcelDictDTO.java
package com.indi.srb.core.pojo.dto;
@Data
public class ExcelDictDTO {
// ExcelProperty Note
// When writing, you will write to Excel's head,
// When reading, it will automatically read the corresponding attribute according to the name of the header
@ExcelProperty("id")
private Long id;
@ExcelProperty("Upper Id")
private Long parentId;
@ExcelProperty("Name")
private String name;
@ExcelProperty("value")
private Integer value;
@ExcelProperty("Code")
private String dictCode;
}
DictMapper.java
void insertBatch(List<ExcelDictDTO> list);
DictMapper.xml
<insert id="insertBatch">
insert into dict(
id,
parent_id,
name,
value,
dict_code
) values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.id},
#{item.parentId},
#{item.name},
#{item.value},
#{item.dictCode}
)
</foreach>
</insert>
com.indi.srb.core
Package created belowlistener
bag
ExcelDictDTOListener.java
package com.indi.srb.core.listener;
@Slf4j
@NoArgsConstructor
public class ExcelDictDTOListener extends AnalysisEventListener<ExcelDictDTO> {
private DictMapper dictMapper;
List<ExcelDictDTO> list = new ArrayList<>(); // data list
// Storage data every 5 records
private static final int BATCH_COUNT = 5;
public ExcelDictDTOListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}
@Override
public void invoke(ExcelDictDTO excelDictDTO, AnalysisContext analysisContext) {
log.info("Analysis of a piece of data: {}", excelDictDTO);
// Stock the data into the data list
list.add(excelDictDTO);
if (list.size() >= BATCH_COUNT) {
saveData();
list.clear();
}
}
private void saveData() {
log.info("{} Data is stored to the database", list.size());
// Call the Save method of the mapper layer: Save list object
dictMapper.insertBatch(list);
log.info("{} Data Storage to Database success", list.size());
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// When the last remaining record is insufficient BATCH_COUNT, finally stored in one -time
saveData();
log.info("All data analysis is complete!");
}
}
DictService.java
void importData(InputStream inputStream);
DictServiceImpl.java
// Once the introduction fails halfway, roll back the data directly
@Transactional(rollbackFor = Exception.class)
@Override
public void importData(InputStream inputStream) {
EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOListener(baseMapper)).sheet().doRead();
log.info("Excel import success");
}
admin
Package created belowAdminDictController.java
@Api(tags = "Data Dictionary Management")
@RestController
@RequestMapping("/admin/core/dict")
@Slf4j
@CrossOrigin
public class AdminDictController {
@Resource
DictService dictService;
@ApiOperation("Batch import of data data")
@PostMapping("/import")
public R batchImport(
@ApiParam(value = "Excel Data Dictionary File", required = true)
@RequestParam("file") MultipartFile file){
try {
InputStream inputStream = file.getInputStream();
dictService.importData(inputStream);
return R.ok().setMessage("Data dictionary batch import success");
} catch (IOException e) {
throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e);
}
}
}
src/router/index.js
{
path: '/core',
component: Layout,
redirect: '/core/dict/list',
name: 'coreDict',
meta: {
title: 'System settings', icon: 'el-icon-setting' },
alwaysShow: true,
children: [
{
path: 'dict/list',
name: 'Data Dictionary',
component: () => import('@/views/core/dict/list'),
meta: {
title: 'Data Dictionary' }
}
]
},
src/views/core/dict/list.vue
<template>
<div class="app-container">
<div style="margin-bottom: 10px;">
<el-button
@click="dialogVisible = true"
type="primary"
size="mini"
icon="el-icon-download"
>Import Excel</el-button>
</div>
<el-dialog title="Data Dictionary Import" :visible.sync="dialogVisible" width="30%">
<el-form>
<el-form-item label="Please select Excel file">
<el-upload
:auto-upload="true"
:multiple="false"
:limit="1"
:on-exceed="fileUploadExceed"
:on-success="fileUploadSuccess"
:on-error="fileUploadError"
:action="BASE_API + '/admin/core/dict/import'"
name="file"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
>
<el-button size="small" type="primary">Click to upload</el-button>
</el-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">Cancel</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
// Define data
data() {
return {
dialogVisible: false, // Whether the file upload dialog box is displayed
BASE_API: process.env.VUE_APP_BASE_API // Get the rear end interface address
}
},
methods: {
// When uploading more files than one file
fileUploadExceed() {
this.$message.warning('Only one file' can be selected ')
},
// The successful recovery with the server communication with the server
fileUploadSuccess(response) {
if (response.code === 0) {
// business success
this.$message.success(data import successful ')
this.dialogVisible = false
} else {
// business failure
this.$message.error(response.message)
}
},
// Capsule of failed communication with the server
fileUploadError(error) {
this.$message.error('data import failed')
}
}
}
</script>
DictService.java
List<ExcelDictDTO> dictListData();
DictServiceImpl.java
@Override
public List<ExcelDictDTO> dictListData() {
List<Dict> dictList = baseMapper.selectList(null);
ArrayList<ExcelDictDTO> excelDictDTOList = new ArrayList<>(dictList.size());
dictList.forEach(dict -> {
ExcelDictDTO excelDictDTO = new ExcelDictDTO();
BeanUtils.copyProperties(dict,excelDictDTO);
excelDictDTOList.add((excelDictDTO));
});
return excelDictDTOList;
}
AdminDictController.java
@ApiOperation("Batch Export of Data")
@GetMapping("/export")
public void export(HttpServletResponse response) {
try {
// Pay attention to the use of Swagger to cause various problems here, please use the browser or postman directly
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// Here Urlencoder.encode can prevent Chinese garbled. Of course, it has nothing to do with EasyExcel
String fileName = URLEncoder.encode("mydict", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=mydict.xlsx");
// Mainly this place
EasyExcel.write(response.getOutputStream(), ExcelDictDTO.class).sheet().doWrite(dictService.dictListData());
} catch (IOException e) {
// export_data_error (104, "data export failure"),
throw new BusinessException(ResponseEnum.EXPORT_DATA_ERROR, e);
}
}
<el-button
@click="exportData"
type="primary"
size="mini"
icon="el-icon-download"
>Export Excel</el-button>
Add Excel data export method to Methods
// Excel data export
exportData() {
// Because the export interface of the back end is refreshing, we need to let the browser refresh,
// So you cannot use Axios to send ordinary requests. You need to use the following method to send a request
window.location.href = this.BASE_API + '/admin/core/dict/export'
}
Dict.java
Add attributes
@ApiModelProperty(value = "Whether it contains sub -nodes")
@TableField(exist = false) // ignore this column in the database table
private boolean hasChildren;
DictService.java
List<Dict> listByParentId(Long parentId);
DictServiceImpl.java
@Override
public List<Dict> listByParentId(Long parentId) {
QueryWrapper<Dict> queryWrapper = new QueryWrapper<Dict>().eq("parent_id",parentId);
List<Dict> dictList = baseMapper.selectList(queryWrapper);
// Fill the Haschildren field
dictList.forEach(dict -> {
boolean hasChildren = this.hasChildren(dict.getId());
dict.setHasChildren(hasChildren);
});
return dictList;
}
/**
* Determine whether the node where the current ID is located has a sub -node
*/
private boolean hasChildren(Long id) {
QueryWrapper<Dict> queryWrapper = new QueryWrapper<Dict>().eq("parent_id",id);
Integer count = baseMapper.selectCount(queryWrapper);
if(count.intValue() > 0) {
return true;
}
return false;
}
AdminDictController.java
/**
* Scheme 2: delay loading
* No need to return the data to the nested data in the back end, but it is necessary to define the Boolean attribute Haschildren, which means whether the current node contains sub -data
* If Haschildren is true, it means that the current node contains sub -data
* If Haschildren is false, it means that the current node does not contain sub -data
* If the current node contains sub -data, then when you click on the current node, you need to load the child data through the load method
*/
@ApiOperation("List of Data of Sub -Node for Surface ID")
@GetMapping("/listByParentId/{parentId}")
public R listByParentId(
@ApiParam(value = "superior node ID", required = true)
@PathVariable Long parentId) {
List<Dict> dictList = dictService.listByParentId(parentId);
return R.ok().data("list", dictList);
}
Createsrc/api/core/dict.js
import request from '@/utils/request'
export default {
listByParentId(parentId) {
return request({
url: `/admin/core/dict/listByParentId/${
parentId}`,
method: 'get'
})
}
}
src/views/core/dict/list.vue
Put it to the previously written</el-dialog>
closed tag below
<el-table :data="list" border row-key="id" lazy :load="load">
<el-table-column label="Name" align="left" prop="name" />
<el-table-column label="encoding" prop="dictCode" />
<el-table-column label="value" align="left" prop="value" />
</el-table>
First import Dictapi
import dictApi from '@/api/core/dict'
Data List of Data Dictionary
list: [] // Data dictionary list
METHODS adds a new method
// Call the API layer to get the 1 -level menu data
fetchData() {
dictApi.listByParentId(1).then(response => {
this.list = response.data.list
})
},
// The method of delaying the loading child node
load(tree, treeNode, resolve) {
dictApi.listByParentId(tree.id).then(response => {
// Responsible for putting the sub -node data in the expanded list
resolve(response.data.list)
})
}
initialization call
created() {
this.fetchData()
},
Data Refresh the data list of the page after importing