放弃幻想,认清现实,准备斗争

何为数据字典?数据字典负责管理系统常用的分类数据或者一些固定数据,例如:省市区三级联动数据、民族数据、行业数据、学历数据等,数据字典帮助我们方便的获取和适用这些通用数据。

这样子的设置避免了多表的雍余
core中添加如下依赖
- <dependency>
- <groupId>com.alibabagroupId>
- <artifactId>easyexcelartifactId>
- dependency>
-
- <dependency>
- <groupId>org.apache.xmlbeansgroupId>
- <artifactId>xmlbeansartifactId>
- dependency>
- @Data
- public class ExcelDictDTO {
-
- @ExcelProperty("id")
- private Long id;
-
- @ExcelProperty("上级id")
- private Long parentId;
-
- @ExcelProperty("名称")
- private String name;
-
- @ExcelProperty("值")
- private Integer value;
-
- @ExcelProperty("编码")
- private String dictCode;
- }
- @Slf4j
- //@AllArgsConstructor //全参
- @NoArgsConstructor //无参
- public class ExcelDictDTOListener extends AnalysisEventListener
{ -
- /**
- * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
- */
- private static final int BATCH_COUNT = 5;
- List
list = new ArrayList(); -
- private DictMapper dictMapper;
-
- //传入mapper对象
- public ExcelDictDTOListener(DictMapper dictMapper) {
- this.dictMapper = dictMapper;
- }
-
- /**
- *遍历每一行的记录
- * @param data
- * @param context
- */
- @Override
- public void invoke(ExcelDictDTO data, AnalysisContext context) {
- log.info("解析到一条记录: {}", data);
- list.add(data);
- // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
- if (list.size() >= BATCH_COUNT) {
- saveData();
- // 存储完成清理 list
- list.clear();
- }
- }
-
- /**
- * 所有数据解析完成了 都会来调用
- */
- @Override
- public void doAfterAllAnalysed(AnalysisContext context) {
- // 这里也要保存数据,确保最后遗留的数据也存储到数据库
- saveData();
- log.info("所有数据解析完成!");
- }
-
- /**
- * 加上存储数据库
- */
- private void saveData() {
- log.info("{}条数据,开始存储数据库!", list.size());
- dictMapper.insertBatch(list); //批量插入
- log.info("存储数据库成功!");
- }
- }
接口:DictMapper
void importData(InputStream inputStream);
实现:DictServiceImpl
- @Transactional(rollbackFor = {Exception.class})
- @Override
- public void importData(InputStream inputStream) {
- // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
- EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOListener(baseMapper)).sheet().doRead();
- log.info("importData finished");
- }
注意:此处添加了事务处理,默认情况下rollbackFor = RuntimeException.class 。能保证发现错误或者异常情况出现以后,能及时的回滚。避免数据的不正确
AdminDictController
- @Api(tags = "数据字典管理")
- @RestController
- @RequestMapping("/admin/core/dict")
- @Slf4j
- @CrossOrigin
- public class AdminDictController {
-
- @Resource
- private DictService dictService;
-
- @ApiOperation("Excel批量导入数据字典")
- @PostMapping("/import")
- public R batchImport(
- @ApiParam(value = "Excel文件", required = true)
- @RequestParam("file") MultipartFile file) {
-
- try {
- InputStream inputStream = file.getInputStream();
- dictService.importData(inputStream);
- return R.ok().message("批量导入成功");
- } catch (Exception e) {
- //UPLOAD_ERROR(-103, "文件上传错误"),
- throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e);
- }
- }
- }
注意:因为maven工程在默认情况下src/main/java目录下的所有资源文件是不发布到target目录下的,因此我们需要在pom.xml中添加xml配置文件发布配置
- <build>
-
- <resources>
- <resource>
- <directory>src/main/javadirectory>
- <includes>
- <include>**/*.xmlinclude>
- includes>
- <filtering>falsefiltering>
- resource>
- resources>
- build>
创建 src/views/core/dict/list.vue
- class="app-container">
-
-
-
- export default {
-
- }
- {
- path: '/core',
- component: Layout,
- redirect: '/core/dict/list',
- name: 'coreDict',
- meta: { title: '系统设置', icon: 'el-icon-setting' },
- alwaysShow: true,
- children: [
- {
- path: 'dict/list',
- name: '数据字典',
- component: () => import('@/views/core/dict/list'),
- meta: { title: '数据字典' }
- }
- ]
- },
- <div class="app-container">
- <div style="margin-bottom: 10px;">
- <el-button
- @click="dialogVisible = true"
- type="primary"
- size="mini"
- icon="el-icon-download"
- >
- 导入Excel
- el-button>
-
- <el-button
- @click="exportData"
- type="primary"
- size="mini"
- icon="el-icon-upload2" >导出Excelel-button>
- div>
-
- <el-dialog title="数据字典导入" :visible.sync="dialogVisible" width="30%">
- <el-form>
- <el-form-item label="请选择Excel文件">
- <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">点击上传el-button>
- el-upload>
- el-form-item>
- el-form>
- <div slot="footer" class="dialog-footer">
- <el-button @click="dialogVisible = false">
- 取消
- el-button>
- div>
- el-dialog>
- <el-table :data="list" border row-key="id" lazy :load="load">
- <el-table-column label="名称" align="left" prop="name" />
- <el-table-column label="编码" prop="dictCode" />
- <el-table-column label="值" align="left" prop="value" />
- el-table>
- div>
-
-
- <script>
- import dictApi from '@/api/core/dict'
- export default {
-
-
-
- created() {
- console.log("123231231")
- this.fetchData()
- },
-
-
- // 定义数据
- data() {
-
- return {
-
- dialogVisible: false, //文件上传对话框是否显示
- BASE_API: process.env.VUE_APP_BASE_API ,//获取后端接口地址
- list: [],//数据字典列表
- }
- },
-
-
- methods: {
- // 调用api层获取数据库中的数据
- fetchData() {
- dictApi.listByParentId(1).then(response => {
- console.log("8888888888")
- this.list = response.data.list
- })
- },
- //延迟加载子节点
- getChildren(row, treeNode, resolve) {
- dictApi.listByParentId(row.id).then(response => {
- //负责将子节点数据展示在展开的列表中
- resolve(response.data.list)
- })
- },
- // 上传多于一个文件时
- fileUploadExceed() {
- this.$message.warning('只能选取一个文件')
- },
-
- //上传成功回调
- fileUploadSuccess(response) {
- if (response.code === 0) {
- this.$message.success('数据导入成功')
- this.dialogVisible = false
- this.fetchData()
- } else {
- this.$message.error(response.message)
- }
- },
-
- //上传失败回调
- fileUploadError(error) {
- this.$message.error('数据导入失败')
- },
- //Excel数据导出
- exportData() {
- window.location.href = this.BASE_API + '/admin/core/dict/export'
- },
- //加载节点
- load(tree,treeNode,resolve){
- //获取数据
- dictApi.listByParentId(tree.id).then(response => {
- resolve(response.data.list)
- })
- }
- }
-
- }
-
- script>
接口:DictService
List listDictData();
实现:DictServiceImpl
- @Override
- public List
listDictData() { -
- List
dictList = baseMapper.selectList(null); - //创建ExcelDictDTO列表,将Dict列表转换成ExcelDictDTO列表
- ArrayList
excelDictDTOList = new ArrayList<>(dictList.size()); - dictList.forEach(dict -> {
-
- ExcelDictDTO excelDictDTO = new ExcelDictDTO();
- BeanUtils.copyProperties(dict, excelDictDTO);
- excelDictDTOList.add(excelDictDTO);
- });
- return excelDictDTOList;
- }
- @ApiOperation("Excel数据的导出")
- @GetMapping("/export")
- public void export(HttpServletResponse response){
-
- try {
- // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
- response.setContentType("application/vnd.ms-excel");
- response.setCharacterEncoding("utf-8");
- // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
- String fileName = URLEncoder.encode("mydict", "UTF-8").replaceAll("\\+", "%20");
- response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
- EasyExcel.write(response.getOutputStream(), ExcelDictDTO.class).sheet("数据字典").doWrite(dictService.listDictData());
-
- } catch (IOException e) {
- //EXPORT_DATA_ERROR(104, "数据导出失败"),
- throw new BusinessException(ResponseEnum.EXPORT_DATA_ERROR, e);
- }
- }
- <el-button
- @click="exportData"
- type="primary"
- size="mini"
- icon="el-icon-upload2" >导出Excelel-button>
- //Excel数据导出
- exportData() {
- window.location.href = this.BASE_API + '/admin/core/dict/export'
- }
Dict中添加属性
- @ApiModelProperty(value = "是否包含子节点")
- @TableField(exist = false)//在数据库表中忽略此列
- private boolean hasChildren;
接口:DictService
List listByParentId(Long parentId);
实现:DictServiceImpl
- @Override
- public List
listByParentId(Long parentId) { - List
dictList = baseMapper.selectList(new QueryWrapper().eq("parent_id", parentId)); - dictList.forEach(dict -> {
- //如果有子节点,则是非叶子节点
- boolean hasChildren = this.hasChildren(dict.getId());
- dict.setHasChildren(hasChildren);
- });
- return dictList;
- }
-
- /**
- * 判断该节点是否有子节点
- */
- private boolean hasChildren(Long id) {
- QueryWrapper
queryWrapper = new QueryWrapper().eq("parent_id", id); - Integer count = baseMapper.selectCount(queryWrapper);
- if(count.intValue() > 0) {
- return true;
- }
- return false;
- }
- @ApiOperation("根据上级id获取子节点数据列表")
- @GetMapping("/listByParentId/{parentId}")
- public R listByParentId(
- @ApiParam(value = "上级节点id", required = true)
- @PathVariable Long parentId) {
- List
dictList = dictService.listByParentId(parentId); - return R.ok().data("list", dictList);
- }
创建 src/api/core/dict.js
- import request from '@/utils/request'
- export default {
- listByParentId(parentId) {
- return request({
- url: `/admin/core/dict/listByParentId/${parentId}`,
- method: 'get'
- })
- }
- }
定义data
list: [], //数据字典列表
生命周期函数
- created() {
- this.fetchData()
- },
获取数据的方法
import dictApi from '@/api/core/dict'
- // 调用api层获取数据库中的数据
- fetchData() {
- dictApi.listByParentId(1).then(response => {
- this.list = response.data.list
- })
- },
-
- //延迟加载子节点
- getChildren(row, treeNode, resolve) {
- dictApi.listByParentId(row.id).then(response => {
- //负责将子节点数据展示在展开的列表中
- resolve(response.data.list)
- })
- },
"list" border row-key="id" lazy :load="load"> - <el-table-column label="名称" align="left" prop="name" />
- <el-table-column label="编码" prop="dictCode" />
- <el-table-column label="值" align="left" prop="value" />
数据导入后刷新页面的数据列表
- //上传成功回调
- fileUploadSuccess(response) {
- if (response.code === 0) {
- this.$message.success('数据导入成功')
- this.dialogVisible = false
- this.fetchData()
- } else {
- this.$message.error(response.message)
- }
- },
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use
问题有可能是有两个:
1.没有写启动类:
2.虽然写了启动类但是启动类所在的包和单元测试的包不在同一级根目录下。
如:一个是在cn.xxxx.cmcc,另一个是在cn.xxxxx,他们不在同一个目录下所以报 找不到启动类:
放在同一个包目录下就解决这个问题了。
总结:单元测试的测试类一定要和启动类在同一个根目录下。