Day106.尚医通:数据字典列表、EasyExcel、数据字典导入导出、集成Redis缓存

本文主要是介绍Day106.尚医通:数据字典列表、EasyExcel、数据字典导入导出、集成Redis缓存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、数据字典列表

1、后端接口

2、前端搭建

Nginx 反向代理

二、EasyExcel

1. 实现写操作测试实例

2. 实现读操作测试实例

三、数据字典导出

1、数据字典导出接口实现

2、前端页面

四、数据字典导入

1、数据字典导入接口实现

2、前端页面

五、数据字典添加Redis缓存

1、Redis 回顾,启动Redis

2、整合Redis


1、是什么

数据字典就是管理系统常用的分类数据或者一些固定数据,例如:省市区三级联动数据、民族数据、行业数据、学历数据等,由于该系统大量使用这种数据,所以我们要做一个数据管理方便管理系统数据,一般系统基本都会做数据管理。

数据字典就是系统中数据展示文字和编码的映射关系

2、需求分析

数据展示-树形表展示

表结构 

 

数据分析

*国标数据查询

*自定义数据查询

 搭建项目模块 -- 8002 service_cmn (省略)

一、数据字典列表

1、后端接口

根据element组件要求,返回列表数据必须包含hasChildren字典,如图:

https://element.eleme.cn/#/zh-CN/component/table

 在model模块查看实体:com.atguigu.yygh.model.cmn.Dict,包含自定义字段 hasChildren

@Data
@ApiModel(description = "数据字典")
@TableName("dict")
public class Dict {private static final long serialVersionUID = 1L;@ApiModelProperty(value = "id")private Long id;@ApiModelProperty(value = "创建时间")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@TableField("create_time")private Date createTime;@ApiModelProperty(value = "更新时间")@TableField("update_time")private Date updateTime;@ApiModelProperty(value = "逻辑删除(1:已删除,0:未删除)")@TableLogic@TableField("is_deleted")private Integer isDeleted;@ApiModelProperty(value = "其他参数")@TableField(exist = false)private Map<String,Object> param = new HashMap<>();@ApiModelProperty(value = "上级id")@TableField("parent_id")private Long parentId;@ApiModelProperty(value = "名称")@TableField("name")private String name;@ApiModelProperty(value = "值")@TableField("value")private String value;@ApiModelProperty(value = "编码")@TableField("dict_code")private String dictCode;@ApiModelProperty(value = "是否包含子节点")@TableField(exist = false)private boolean hasChildren;}

1. 添加Config 配置类,mapper扫描

@Configuration
@EnableTransactionManagement
@MapperScan("com.atguigu.yygh.cmn.mapper")
public class CmnConfig {
}

2. controller

@Api(description = "数据字典接口")
@RestController
@RequestMapping("/admin/cmn/dict")
@CrossOrigin
public class DictController {@Autowiredprivate DictService dictService;//根据数据id查询子数据列表@ApiOperation(value = "根据数据id查询子数据列表")@GetMapping("findChildData/{id}")public R findChildData(@PathVariable Long id){List<Dict> list = dictService.findChildData(id);return R.ok().data("list",list);}}

3. service

public interface DictService extends IService<Dict> {//根据数据id查询子数据列表List<Dict> findChildData(Long id);
}@Service
public class DictServiceImplextends ServiceImpl<DictMapper, Dict>implements DictService {//根据数据id查询子数据列表@Overridepublic List<Dict> findChildData(Long id) {//1.根据父id查询子级别数据集合QueryWrapper<Dict> wrapper = new QueryWrapper<>();wrapper.eq("parent_id",id);List<Dict> dictList = baseMapper.selectList(wrapper);//2.遍历查询是否有子数据for (Dict dict : dictList) {boolean hasChildren = this.isChildren(dict.getId());dict.setHasChildren(hasChildren);}return dictList;}//查询是否有子数据,方法提取private boolean isChildren(Long id) {QueryWrapper<Dict> wrapper = new QueryWrapper<>();wrapper.eq("parent_id",id);Integer count = baseMapper.selectCount(wrapper);return count > 0;}
}

4. mapper

public interface DictMapper extends BaseMapper<Dict> {
}

2、前端搭建

1、路由、创建对应页面

  {path: '/cmn',component: Layout,redirect: '/cmn/list',name: '数据管理',alwaysShow: true, //总是展示一级菜单meta: { title: '数据管理', icon: 'example' },children: [{path: 'list',name: '数据字典',component: () => import('@/views/yygh/dict/list'),meta: { title: '数据字典', icon: 'table' }}]},

2、api接口

import request from '@/utils/request'
//提取请求路径
const api_name = '/admin/cmn/dict'export default{//根据数据id查询子数据列表findChildData(id){return request({url: `${api_name}/findChildData/${id}`,//插值表达式method: 'get'})},}

3、添加页面元素

lazy 只加载一级节点 ,通过 :load="load" 方法加载子节点数据

<template><div class="app-container"> <!-- lazy 只加载一级节点 :load="load"  --><el-table :data="list" style="width: 100%" row-key="id" border lazy :load="load":tree-props="{children: 'children', hasChildren: 'hasChildren'}"><el-table-column prop="name" label="名称" width="150"></el-table-column><el-table-column prop="dictCode" label="编码" width="150"></el-table-column><el-table-column prop="value" label="值" width="150"></el-table-column><el-table-column prop="createTime" label="创建时间"></el-table-column></el-table></div>
</template>

4、实现js

<script>
import dictApi from "@/api/yygh/dict"
export default{data() {return {list: []  //字典数据集合   }},created() {this.getDate(1)},methods: {//初始化查询方法getDate(id){dictApi.findChildData(id).then(response=>{this.list = response.data.list})},//树形节点加载方法,tree为节点对象,通过resolve()加载数据load(tree, treeNode, resolve){dictApi.findChildData(tree.id).then(response=>{//参考官方文档resolve(response.data.list)})}}
}</script>

5、测试、报错

分析1、跨域问题,不排除

 

分析2、请求地址错误,需要Nginx反向代理

 

Nginx 反向代理

反向代理、负载均衡、动静分离

1、安装Windows版,解压即可启动

2、修改配置文件

	server {listen       9001;server_name  localhost;location ~ /hosp/ {           proxy_pass http://localhost:8201;}location ~ /cmn/ {           proxy_pass http://localhost:8202;}
}

3、重启nginx,访问测试

nginx目录下cmd 热加载,nginx.exe -s reload

http://localhost:9001/admin/cmn/dict/findChildData/1

4、前端修改dev配置文件,重新测试 

二、EasyExcel

Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。面对高访问高并发,一定会OOM或者JVM频繁的full gc (重jc)。

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

文档地址:https://alibaba-easyexcel.github.io/index.html

github地址:https://github.com/alibaba/easyexcel

1. 实现写操作测试实例

1. cmd项目,导入依赖

    <!--EasyExcel--><dependencies><!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version></dependency></dependencies>

2. 实体对象

@Data
public class Stu {//设置表头名称@ExcelProperty("学生编号")private int sno;//设置表头名称@ExcelProperty("学生姓名")private String sname;}

3. 测试类

public class WriteTest {public static void main(String[] args) {String fileName = "E:\\test.xlsx";EasyExcel.write(fileName,Stu.class).sheet("学生信息").doWrite(data());}//循环设置要添加的数据,最终封装到list集合中private static List<Stu> data() {List<Stu> list = new ArrayList<Stu>();for (int i = 0; i < 10; i++) {Stu data = new Stu();data.setSno(i);data.setSname("张三"+i);list.add(data);}return list;}
}

   

2. 实现读操作测试实例

1. 改造实体类,指定对应关系

@Data
public class Stu {//设置表头名称,指定映射关系(第0行)@ExcelProperty(value = "学生编号",index = 0)private int sno;//设置表头名称,指定映射关系(第1行)@ExcelProperty(value = "学生姓名",index = 1)private String sname;}

2. 创建监听器

public class ExcelListener extends AnalysisEventListener<Stu> {//一行一行去读取excle内容@Overridepublic void invoke(Stu stu, AnalysisContext analysisContext) {System.out.println("stu = " + stu);}//读取excel表头信息@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {System.out.println("表头信息:"+headMap);}//读取完成后执行@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}
}

3. 测试

public class ReadTest {public static void main(String[] args) {String fileName = "E:\\test.xlsx";EasyExcel.read(fileName,Stu.class,new ExcelListener()).sheet().doRead();}}

三、数据字典导出

1、数据字典导出接口实现

1. 添加依赖

    <!--EasyExcel--><dependencies><!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.1</version></dependency></dependencies>

2. 确认vo

@Data
public class DictEeVo {@ExcelProperty(value = "id" ,index = 0)private Long id;@ExcelProperty(value = "上级id" ,index = 1)private Long parentId;@ExcelProperty(value = "名称" ,index = 2)private String name;@ExcelProperty(value = "值" ,index = 3)private String value;@ExcelProperty(value = "编码" ,index = 4)private String dictCode;}

3. 分析接口

参数:response  (可以获取输出流)

返回值:无

4. 实现controller

    //导出字典数据@Overridepublic void exportData(HttpServletResponse response) {try {//1.设置response的基本数据response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("数据字典", "UTF-8");response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");//2.查询所有字典数据List<Dict> dictList = baseMapper.selectList(null);//3.转换字典数据类型List<DictEeVo> dictEeVoList = new ArrayList<>();for (Dict dict : dictList) {DictEeVo dictEeVo = new DictEeVo();//spring提供的工具类,对象拷贝BeanUtils.copyProperties(dict,dictEeVo);dictEeVoList.add(dictEeVo);}//4,使用工具导出EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("数据字典").doWrite(dictEeVoList);} catch (IOException e) {e.printStackTrace();}}

2、前端页面

1. 确认入口

2. 添加页面元素

<div class="el-toolbar"><div class="el-toolbar-body" style="justify-content: flex-start;"><el-button type="text" @click="exportData"><i class="fa fa-plus"/> 导出</el-button></div>
</div>

3. js实现

            //导出数据exportData(){//window.open("http://localhost:8202/admin/cmn/dict/exportData")//照葫芦画瓢。从配置文件读取window.open(`${process.env.VUE_APP_BASE_API}admin/cmn/dict/exportData`)}

4. 测试
 

四、数据字典导入

1、数据字典导入接口实现

1. 分析接口

参数:file (文件)

返回值:R.ok()

2. controller 实现

    @ApiOperation(value = "导入字典数据")@PostMapping("importData")public R importData(MultipartFile file){dictService.importData(file);return R.ok();}

3. 实现监听器 DictListener

@Component //
public class DictListener extends AnalysisEventListener<DictEeVo> {@Autowiredprivate DictMapper dictMapper;@Overridepublic void invoke(DictEeVo dictEeVo, AnalysisContext analysisContext) {//转换类型Dict dict = new Dict();BeanUtils.copyProperties(dictEeVo,dict);//设置默认值dict.setIsDeleted(0);dictMapper.insert(dict);}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}
}

4. 实现service

    @AutowiredDictListener dictListener;//导入字典数据@Overridepublic void importData(MultipartFile file) {try {InputStream inputStream = file.getInputStream();EasyExcel.read(inputStream,DictEeVo.class,dictListener).sheet().doRead();} catch (IOException e) {e.printStackTrace();throw new YyghException(20001,"导入数据失败");}}

5. 测试

2、前端页面

1. 确认入口

2. 添加页面元素

        <div class="el-toolbar"><div class="el-toolbar-body" style="justify-content: flex-start;"><el-button type="text" @click="exportData"><i class="fa fa-plus" />导出</el-button><el-button type="text" @click="importData"><i class="fa fa-plus" />导入</el-button></div></div>

2. 添加对话框、文件上传组件

ajax无法传递文件,只能通过上传组件,直接提交请求,:action 传入请求地址

        <el-dialog title="导入" :visible.sync="dialogImportVisible" width="480px"><el-form label-position="right" label-width="170px"><el-form-item label="文件"><el-upload :multiple="false" :on-success="onUploadSuccess":action="BASE_API" class="upload-demo"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传xls文件,且不超过500kb</div></el-upload></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogImportVisible = false">取消</el-button></div></el-dialog>

3. js实现

        data() {return {list: [],  //字典数据集合 dialogImportVisible: false,  //对话框,默认不显示BASE_API: `${process.env.VUE_APP_BASE_API}admin/cmn/dict/importData` //请求地址}},created() {this.getDate(1)},methods: {....//打开导入对话框importData(){this.dialogImportVisible = true},//上传成功后的操作onUploadSuccess(){//1.关闭对话框this.dialogImportVisible = false//2.上传成功提示this.$message({type: "success",message: "上传成功!"})//3.刷新表格this.getDate(1)}}

4. 测试

 

五、数据字典添加Redis缓存

1、Redis 回顾,启动Redis

Redis 与 Memcache区别:

1、Memcache 数据只在缓存中,Redis 可以进行持久化操作 (RDB、AOF)

2、Memcache 只支持字符串类型,Redis多数据类型(string、list、set、hash、zset...)

3、命令机制:多线程加锁。Redis 单线程 + 多路io复用

Redis的特点: 

原子性、单线程+多路io复用

启动

(1)虚拟机

(2)安装redis

(3)确认redis配置

 

(4)关闭虚拟机防火墙服务

(5)启动redis

2、整合Redis

1. common_uilts模块添加依赖

    <dependencies><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.0</version></dependency></dependencies>

2. 添加配置类

(建议关闭自动导包?)

@Configuration
@EnableCaching  //开启缓存
public class RedisConfig {/*** 设置RedisTemplate规则* @param redisConnectionFactory* @return*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);//序列号key valueredisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}/*** 设置CacheManager缓存规则* @param factory* @return*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//解决查询缓存转换异常的问题ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// 配置序列化(解决乱码的问题),过期时间600秒RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).disableCachingNullValues();RedisCacheManager cacheManager = RedisCacheManager.builder(factory).cacheDefaults(config).build();return cacheManager;}}

3. service_cmn 配置文件 添加redis配置

#redis
spring.redis.host=192.168.86.86
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

4. redis 缓存原理

5. 添加缓存,service方法 添加@Cacheable 注解即可 

注意:redis字符串key 为 value+key

    //根据数据id查询子数据列表//redis k:v  k=dict::selectIndexList  v=List<Dict>@Cacheable(value = "dict", key = "'selectIndexList'")@Overridepublic List<Dict> findChildData(Long id) {

属性/方法名

解释

value

缓存名,必填,它指定了你的缓存存放在哪块命名空间

cacheNames

与 value 差不多,二选一即可

key

可选属性,可以使用 SpEL 标签自定义缓存的key

第一次:查询数据库,添加缓存

出现问题:一级数据可以展现,二级数据没有展现

原因:查询一级、二级时,查询的是同一个方法,redis key是相同的,但缓存中没有二级数据

解决:key值加入参数 id

 

同步缓存:

方案1. 加锁、效率低

方案2. 写操作时,清空相关缓存。再次查询时同步

这篇关于Day106.尚医通:数据字典列表、EasyExcel、数据字典导入导出、集成Redis缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/411383

相关文章

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf