日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

22-08-06 西安 尚医通(03)EasyExcel; Spring Cache 、Redis做缓存

發布時間:2023/12/20 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 22-08-06 西安 尚医通(03)EasyExcel; Spring Cache 、Redis做缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

EasyExcel

EasyExcel:一行一行讀取到內存
EasyExcel是阿里巴巴開源的一個excel處理框架,以使用簡單、節省內存著稱

POI:java里操作excel,讀取、創建excel

POI的缺點:耗內存。因為會把所有數據一起加載到內存中


EasyExcl讀寫演示

1.加依賴

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

2.@ExcelProperty,創建實體類Anchor用來和表格做映射
index第幾列,value列名

@Data @AllArgsConstructor @NoArgsConstructor public class Anchor {@ExcelProperty(index = 0,value = "主播姓名")private String name;@ExcelProperty(index = 1,value = "直播平臺")private String platform;@ExcelProperty(index=2,value = "成名英雄")private String hero; }

演示創建excel表格

一行代碼,調用3個方法 EasyExcel.write().sheet().doWrite();

public static void main(String[] args) {Anchor anchor1 = new Anchor("北慕", "虎牙", "露娜");Anchor anchor2 = new Anchor("騷白", "斗魚", "花木蘭");Anchor anchor3 = new Anchor("賴神", "虎牙", "老夫子");List<Anchor> anchorList = Arrays.asList(anchor1, anchor2, anchor3);EasyExcel.write("C:\\Users\\lenovo\\Desktop\\主播列表.xlsx",Anchor.class).sheet("主播列表").doWrite(anchorList);}

效果如下:

—————————————————————————————————————————

演示讀取excel表格

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

invoke方法用于處理每條數據,讀者可以在這邊進行業務邏輯處理
doAfterAllAnalysed方法是只處理完所有數據后進行的動作;

public class ExcelListener extends AnalysisEventListener<Anchor> {//一行一行去讀取excle內容@Overridepublic void invoke(Anchor anchor, AnalysisContext analysisContext) {System.out.println("***"+anchor);}//所有行讀取完成后執行@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {System.out.println("讀取完成后");} }

主函數:正真讀取是按照第二行開始的

public static void main(String[] args) {String fileName = "C:\\Users\\lenovo\\Desktop\\主播列表.xlsx";// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關閉EasyExcel.read(fileName, Anchor.class, new ExcelListener()).sheet("主播列表").doRead();}

控制臺打印如下:


數據字典導出

后端代碼

可以理解為文件下載功能

DictEeVo,導出的數據字典格式

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

字典文件下載controller層,返回值為void就行,必須用response對象

@ApiOperation(value="導出") @GetMapping(value = "/exportData") public void exportData(HttpServletResponse response) {dictService.exportData(response); }

正真的實現是在service層。如下

public void exportData(HttpServletResponse response) {try {//設置響應頭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");//封裝數據集合List<Dict> dictList = baseMapper.selectList(null);ArrayList<DictEeVo> dictEeVos = new ArrayList<>();dictList.forEach(dict -> {DictEeVo dictEeVo = new DictEeVo();BeanUtils.copyProperties(dict, dictEeVo);dictEeVos.add(dictEeVo);});//用流的方式,瀏覽器文件下載EasyExcel.write(response.getOutputStream(), DictEeVo.class).sheet("數據字典").doWrite(dictEeVos);} catch (IOException e) {e.printStackTrace();}}

前端代碼

在前臺頁面點擊導出,


相關前端代碼大致如下:

<div class="el-toolbar-body" style="justify-content: flex-start"><el-button type="primary" @click="exportData"><i class="el-icon-download el-icon--right" /> 導出</el-button> ```

不需要寫api部分,直接訪問。也可以訪問9001

exportData() {window.open("http://localhost:8202/admin/cmn/dict/exportData");},

導出效果:


數據字典導入

后端接口

導入的excel文件格式,要滿足格式DictEeVo

Controller方法想接收一個文件,這里文件名稱必須是file,可以使用@RequestParam(“file”)

@ApiOperation(value = "導入")@PostMapping("importData")public R importData(MultipartFile file) {dictService.importDictData(file);return R.ok();}
1、創建監聽器讀取

invoke,每讀一行,這個方法就調用一次

@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);dictMapper.insert(dict);}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {} }
2.service層實現業務邏輯
@Overridepublic void importDictData(MultipartFile file) {try {EasyExcel.read(file.getInputStream(), DictEeVo.class, dictListener).sheet().doRead();} catch (IOException e) {e.printStackTrace();}}
3.使用postman測試文件上傳接口

查看數據庫的字典表,導入成功


前端部分


點擊彈窗框上選擇導入的文件,visible.sync控制顯示隱藏彈出框

<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="'http://localhost:8202/admin/cmn/dict/importData'"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>

效果如下:

導入成功回調方法

importData() {this.dialogImportVisible = true;},onUploadSuccess(response, file) {this.$message.info("導入成功");//關閉彈出框this.dialogImportVisible = false;//重新查詢一級數據this.getDictList(1);},

Spring Cache

Spring Cache 是一個非常優秀的緩存組件;是Spring基于aop提供的自動緩存管理

只需要通過注解標注到查詢的業務方法上 可以將查詢方法返回的結果緩存起來,以后查詢時有緩存不在執行業務代碼

Spring Cache步驟:
1、為springcache提供一個緩存管理接口的實現
2、啟動類/配置類 添加**@EnableCaching注解
3、在需要緩存管理的業務方法(查詢)上使用
@Cachable(…key )** 標注

spring會自動管理業務方法的數據緩存 調用第一步實現的緩存管理對象的生命周期方法管理緩存


1、緩存管理接口的實現

redis緩存:緩存的目的避免(減少)客戶端從mysql中讀取數據

1.添加依賴

<!-- 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>

2.創建配置類(拷貝)


@EnableCaching 必須要加,否則spring-data-cache相關注解不會生效…

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

當然還有第二版,這一版是之后加的(這版是老師講過的,還算是能看懂。。。)

@Configuration public class RedisCacheConfig {//1、RedisTemplate配置鍵和值的序列化器@AutowiredRedisTemplate redisTemplate;@PostConstructpublic void init(){redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());}//2、緩存管理CacheManager接口的實現//LettuceConnectionFactory commons-pool2包中提供的Redis連接池工廠類@Beanpublic CacheManager cacheManager(LettuceConnectionFactory connectionFactory){RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30)) //緩存過期時間.disableCachingNullValues() //不緩存空值.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) //鍵序列化器.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));//值序列化器RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(cacheConfig).build();return cacheManager;} }

3.配置文件

spring.redis.host=192.168.2.108 spring.redis.port=6379 spring.redis.database= 0 spring.redis.timeout=1800000#連接池最大連接數 spring.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

2、使用@Cachable緩存管理

@Cacheable添加緩存

1、查詢數據字典+@Cacheable

  • 如果緩存存在,則直接讀取緩存數據返回;
  • 如果緩存不存在,則執行方法,并把返回的結果存入緩存中。

1.key 可選屬性,可以使用 SpEL 標簽自定義緩存的key, key中可以獲取業務方法的形參值
2.#號代表這是一個 SpEL 表達式,此表達式可以遍歷方法的參數對象
@Cacheable(value = "dictCache", key = "'dict_'+#id")
3. 緩存的key: 使用value和key的值拼接,如: dictCache::dict_id的值

如果參數是對象Dict dict,可以這么獲取
> key="'dict_'+#dict.value"

//value:命名空間@Cacheable(value = "dictCache", key = "'dict_'+#id")@Overridepublic List<Dict> findChildData(Long id) {QueryWrapper<Dict> queryWrapper = new QueryWrapper<>();queryWrapper.eq("parent_id", id);//向list集合每個dict對象中設置hasChildrenList<Dict> dicts = baseMapper.selectList(queryWrapper);System.out.println("從mysql中查詢id=" + id + "的數據");dicts.forEach(dict -> {dict.setHasChildren(this.isChildren(dict.getId()));});return dicts;}

redis中效果:


@CacheEvict緩存驅逐

放在刪除、更新方法上

使用該注解**@CacheEvict**標志的方法,會清空指定的緩存。一般用在更新或者刪除方法上
allEntries 是否清除當前 value值空間下的所有緩存數據。默認false

導入數據的時候,把redis中數據都清除

@CacheEvict(value = "dictCache", allEntries = true)@Overridepublic void importDictData(MultipartFile file) {try {EasyExcel.read(file.getInputStream(), DictEeVo.class, dictListener).sheet().doRead();} catch (IOException e) {e.printStackTrace();}}

@CachePut更新緩存

用在修改方法或添加方法上

同步緩存的做法
當mysql中的數據發生改變,就會清空redis中對應命名空間下的緩存數據


3、手動緩存管理

由于緩存雪崩的問題,我們需要手動管理緩存。。使TTL設置的時間不那么集中。雖然這是另外一個方法,不要在意這些細節。。。

@Autowired PmsClient pmsClient;//遠程服務調用的feign接口@Autowired RedisTemplate redisTemplate; //刪除上面的Cacheable注解 @Override public List<CategoryEntity> levelTwoAndSubsCates(String cid) {//使用緩存管理//1、從緩存中查詢cid的二級三級分類集合 如果有直接返回String key = "idx:cache:cates:"+cid;Object obj = redisTemplate.opsForValue().get(key);if(obj!=null){return (List<CategoryEntity>) obj;}//2、如果緩存沒有 再遠程查詢二三級分類集合ResponseVo<List<CategoryEntity>> responseVo = pmsClient.lv2AndSubsCates(cid);//將查詢結果存到緩存中redisTemplate.opsForValue().set(key,responseVo.getData() ,1800+new Random().nextInt(200), TimeUnit.SECONDS);return responseVo.getData(); }

4、緩存一致性

數據庫數據更新后如何保證緩存的數據和數據庫數據一致:

  • 雙寫模式:數據庫更新同時更新redis緩存數據

    ? 先寫哪一個存在問題:redis和數據庫之間的事務不容易保證

  • 失效模式: 更新數據庫時 讓緩存失效

    ? 更新數據庫業務執行時 緩存會失效,此時如果數據還未寫成功 有請求查詢數據查到了數據庫中還未更新的數據到緩存中,此時才寫成功 緩存的數據和數據庫仍然不一致

  • 雙刪模式:更新數據庫前刪除一次緩存 更新成功后再刪除一次緩存

  • 數據庫同步中間件:基于mysql的binlog日志將數據庫更新的數據同步到第三方的中間件(redis mq es)

    • canal:阿里開源的一個框架

5、緩存并發問題

1.緩存雪崩

緩存雪崩:首頁數據訪問量大,數據緩存過期時間接近 會導致多個緩存同時失效,大量的請求可能直接查詢數據庫

解決:隨機因子 讓多個熱門key失效的時間分散


2.緩存擊穿

緩存擊穿:單個熱點key突然失效,導致大量的請求同時訪問數據庫查詢數據

?解決:控制只讓一個線程查數據 其他的等待使用緩存 分布式鎖


3.緩存穿透

緩存穿透 : 訪問數據庫一定不存在的數據時,請求每次都會先查詢緩存,然后再查數據庫

解決:

  • 空數據也短暫的緩存:為了避免惡意攻擊
  • 布隆過濾器
  • 總結

    以上是生活随笔為你收集整理的22-08-06 西安 尚医通(03)EasyExcel; Spring Cache 、Redis做缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。