临汾山东漯河饰品美体美文
投稿投诉
美文创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品
漯河衢州
兴义眉山
桂林阳泉
玉溪简阳
山东遂宁
永城新余
梧州洛阳
泸州温州
临汾清远
营口常熟
浙江大连
桐乡宜昌

十二条后端开发经验分享,纯干货

11月19日 皇极城投稿
  一。优雅的进行线程池异常处理
  在Java开发中,线程池的使用必不可少,使用无返回值execute()方法时,线程执行发生异常的话,需要记录日志,方便回溯,一般做法是在线程执行方法内trycatch处理,如下:Testpublicvoidtest()throwsException{ThreadPoolExecutorthreadPoolExecutornewThreadPoolExecutor(5,10,60,TimeUnit。SECONDS,newArrayBlockingQueue(100000));FutureIntegersubmitthreadPoolExecutor。execute((){try{inti10;}catch(Exceptione){log。error(e。getMessage(),e);}});}复制代码
  但是当线程池调用方法很多时,那么每个线程执行方法内都要trycatch处理,这就不优雅了,其实ThreadPoolExecutor类还支持传入ThreadFactory参数,自定义线程工厂,在创建thread时,指定setUncaughtExceptionHandler异常处理方法,这样就可以做到全局处理异常了,代码如下:ThreadFactorythreadFactoryr{ThreadthreadnewThread(r);thread。setUncaughtExceptionHandler((t,e){记录线程异常log。error(e。getMessage(),e);});};ThreadPoolExecutorthreadPoolExecutornewThreadPoolExecutor(5,10,60,TimeUnit。SECONDS,newArrayBlockingQueue(100000),threadFactory);threadPoolExecutor。execute((){log。info();inti10;});复制代码二。线程池决绝策略设置错误导致业务接口执行超时
  先介绍下线程池得四种决绝策略AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,这是线程池默认的拒绝策略DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。CallerRunsPolicy:由调用线程处理该任务
  如下是一个线上业务接口使用得线程池配置,决绝策略采用CallerRunsPolicy某个线上线程池配置如下ThreadPoolExecutorthreadPoolExecutornewThreadPoolExecutor(50,最小核心线程数50,最大线程数,当队列满时,能创建的最大线程数60L,TimeUnit。SECONDS,空闲线程超过核心线程时,回收该线程的最大等待时间newLinkedBlockingQueue(5000),阻塞队列大小,当核心线程使用满时,新的线程会放进队列newCustomizableThreadFactory(task),自定义线程名newThreadPoolExecutor。CallerRunsPolicy()线程执行的拒绝策略);复制代码
  在某些情况下,子线程任务调用第三方接口超时,导致核心线程数、最大线程数占满、阻塞队列占满的情况下执行拒绝策略时,由于使用CallerRunsPolicy策略,导致业务线程执行子任务时继续超时,进而导致接口执行异常,这种情况下,考虑到子线程任务得重要性,不是很重要得话,可以使用DiscardPolicy策略,要是很重要,可以发送到消息队列中持久化子线程任务数据待后续处理三。优雅的单例模式懒加载帮助类代码实现
  博主推荐通过静态内部类实现单例模式,并实现懒加载效果,代码如下使用静态内部类完成单例模式封装,避免线程安全问题,避免重复初始化成员属性Slf4jpublicclassFilterIpUtil{privateFilterIpUtil(){}privateListStringstringsnewArrayList();代码块在FilterIpUtil实例初始化时才会执行{在代码块中完成文件的第一次读写操作,后续不再读这个文件System。out。println(FilterIpUtilinit);try(InputStreamresourceAsStreamFilterIpUtil。class。getClassLoader()。getResourceAsStream(filterIp。txt)){将文件内容放到string集合中IoUtil。readUtf8Lines(resourceAsStream,strings);}catch(IOExceptione){log。error(e。getMessage(),e);}}publicstaticFilterIpUtilgetInstance(){returnInnerClassInstance。}使用内部类完成单例模式,由jvm保证线程安全privatestaticclassInnerClassInstance{privatestaticfinalFilterIpUtilinstancenewFilterIpUtil();}判断集合中是否包含目标参数publicbooleanisFilter(Stringarg){returnstrings。contains(arg);}}复制代码四。使用ip2region实现请求地址解析
  在博主之前公司得项目中,ip解析是调用淘宝IP还有聚合IP接口获取结果,通常耗时200毫秒左右,并且接口不稳定时而会挂。都会影响业务接口耗时,后来在github上了解到ip2region这个项目,使用本地ip库查询,查询速度微秒级别,精准度能达到90,但是ip库还是有少部分ip信息不准,建议数据库中把请求ip地址保存下来。简介如下:
  ip2regionv2。0是一个离线IP地址定位库和IP定位数据管理框架,10微秒级别的查询效率,提供了众多主流编程语言的xdb数据生成和查询客户端实现基于xdb文件的查询,下面是一个Spring项目中ip2region帮助类来实现ip地址解析ip2region工具类Slf4jComponentpublicclassIp2region{privateSValue({ip2region。path:})privateStringip2regionPPostConstructprivatevoidinit(){1、从dbPath加载整个xdb到内存。StringdbPathip2regionP1、从dbPath加载整个xdb到内存。byte〔〕cBtry{cBuffSearcher。loadContentFromFile(dbPath);searcherSearcher。newWithBuffer(cBuff);}catch(Exceptione){log。error(failedtocreatecontentcachedsearcher:{},e。getMessage(),e);}}publicIpInfoBeangetIpInfo(Stringip){if(StringUtils。isBlank(ip)){}3、查询try{longsTimeSystem。nanoTime();国家区域省份城市ISPStringregionsearcher。search(ip);longcostTimeUnit。NANOSECONDS。toMicros((long)(System。nanoTime()sTime));log。info({region:{},ioCount:{},took:{}s},region,searcher。getIOCount(),cost);if(StringUtils。isNotBlank(region)){String〔〕splitregion。split();IpInfoBeanipInfonewIpInfoBean();ipInfo。setIp(ip);if(!。equals(split〔0〕)){ipInfo。setCountry(split〔0〕);}if(!。equals(split〔2〕)){ipInfo。setProvince(split〔2〕);}if(!。equals(split〔3〕)){ipInfo。setCity(split〔3〕);}if(!。equals(split〔4〕)){ipInfo。setIsp(split〔4〕);}returnipI}}catch(Exceptione){log。error(failedtosearch({}):{},ip,e);}4、关闭资源该searcher对象可以安全用于并发,等整个服务关闭的时候再关闭searchersearcher。close();备注:并发使用,用整个xdb数据缓存创建的查询对象可以安全的用于并发,也就是你可以把这个searcher对象做成全局对象去跨线程访问。}}复制代码
  要注意得就是ip2regionv2。0版本使用的xdb文件不建议放在项目resources下一起打包,存在编码格式问题,建议通过指定路径加载得方式单独放在服务器目录下五。优雅得Springbootmybatis配置多数据源方式
  Springbootmybatis得项目中一般通过MapperScan注解配置dao层包目录,来实现dao层增强,其实项目中配置一个MapperScan是指定一个数据源,配置两个MapperScan就可以指定两个数据源,通过不同得dao层包目录区分,来实现不同数据源得访问隔离。
  比如下面代码中,com。xxx。dao。master目录下为主数据源dao文件,com。xxx。dao。slave为从数据源dao文件,这个方式比网上得基于aop加注解得方式更加简洁好用,也没有单个方法中使用不同数据源切换得问题,因此推荐这种写法主数据源Slf4jConfigurationMapperScan(basePackages{com。xxx。dao。master},sqlSessionFactoryRefMasterSqlSessionFactory)publicclassMasterDataSourceConfig{Bean(nameMasterDataSource)Qualifier(MasterDataSource)ConfigurationProperties(prefixspring。datasource。master)publicDataSourceclickHouseDataSource(){returnDruidDataSourceBuilder。create()。build();}Bean(nameMasterSqlSessionFactory)publicSqlSessionFactorygetSqlSessionFactory(Qualifier(MasterDataSource)DataSourcedataSource)throwsException{MybatisSqlSessionFactoryBeansessionFactoryBeannewMybatisSqlSessionFactoryBean();sessionFactoryBean。setDataSource(dataSource);sessionFactoryBean。setMapperLocations(newPathMatchingResourcePatternResolver()。getResources(classpath:mappermaster。xml));log。info(MasterDataSource配置成功);returnsessionFactoryBean。getObject();}}从数据源Slf4jConfigurationMapperScan(basePackages{com。xxx。dao。slave},sqlSessionFactoryRefSlaveSqlSessionFactory)publicclassMasterDataSourceConfig{Bean(nameSlaveDataSource)Qualifier(SlaveDataSource)ConfigurationProperties(prefixspring。datasource。slave)publicDataSourceclickHouseDataSource(){returnDruidDataSourceBuilder。create()。build();}Bean(nameSlaveSqlSessionFactory)publicSqlSessionFactorygetSqlSessionFactory(Qualifier(SlaveDataSource)DataSourcedataSource)throwsException{MybatisSqlSessionFactoryBeansessionFactoryBeannewMybatisSqlSessionFactoryBean();sessionFactoryBean。setDataSource(dataSource);sessionFactoryBean。setMapperLocations(newPathMatchingResourcePatternResolver()。getResources(classpath:mapperslave。xml));log。info(SlaveDataSource配置成功);returnsessionFactoryBean。getObject();}}复制代码
  数据源yml配置spring:datasource:type:com。alibaba。druid。pool。DruidDataSourcedriverClassName:com。mysql。cj。jdbc。Driver主库数据源master:url:jdbc:mysql:localhost:3306db1?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT2B8username:rootpassword:slave:url:jdbc:mysql:localhost:3306db2?useUnicodetruecharacterEncodingutf8zeroDateTimeBehaviorconvertToNulluseSSLtrueserverTimezoneGMT2B8username:rootpassword:复制代码
  博主刚开始编码一、两年得时候一个项目中遇到了多数据源使用得问题,那时候题主便在网上搜索Spring多数据源得帖子,大多数都是基于Spring提供得AbstractRoutingDataSourceAOP注解来做动态切换,包括现在流行得Mybatisplus官方得多数据源解决方案也是这种做法,这种做法解决了博主当时得多数据源使用问题,后来加了一个需求,在一个定时任务中,查询两个数据源得数据,才发现动态切换在单个方法中不好用了,最后使用得原生jdbc数据源解决。多年后,博主在另一家公司得项目中又遇到了多数据源问题,但是这次博主在网上搜索得是Mybatis多数据源,才发现了这个优雅得解决方案,进而推荐给大家六。SpringSecurity项目中,使用MDC实现接口请求调用追踪,以及用户ID记录MDC介绍
  MDC(MappedDiagnosticContext,映射调试上下文)是log4j、logback及log4j2提供的一种方便在多线程条件下记录日志的功能。MDC可以看成是一个与当前线程绑定的哈希表,可以往其中添加键值对。MDC中包含的内容可以被同一线程中执行的代码所访问。当前线程的子线程会继承其父线程中的MDC的内容。当需要记录日志时,只需要从MDC中获取所需的信息即可。
  虽然MDC能够方便得实现接口请求调用追踪功能,但是它在子线程中会丢失父线程中添加得键值对信息,解决方法是通过父线程中调用线程池前调用MDC。getCopyOfContextMap(),然后在子线程中第一个调用MDC。setConextMap()获取键值对信息,完整实现代码如下:自定义Spring线程池,解决子线程丢失reqestid问题publicclassThreadPoolExecutorMdcWrapperextendsThreadPoolTaskExecutor{Overridepublicvoidexecute(Runnabletask){super。execute(ThreadMdcUtil。wrap(task,MDC。getCopyOfContextMap()));}OverridepublicTFutureTsubmit(CallableTtask){returnsuper。submit(ThreadMdcUtil。wrap(task,MDC。getCopyOfContextMap()));}OverridepublicF?submit(Runnabletask){returnsuper。submit(ThreadMdcUtil。wrap(task,MDC。getCopyOfContextMap()));}}MDC帮助类,添加reqestidpublicclassThreadMdcUtil{publicstaticfinalStringREQUESTID设置请求唯一IDpublicstaticvoidsetTraceIdIfAbsent(){if(MDC。get(REQUESTID)null){MDC。put(REQUESTID,IdUtil。getUid());}}存在userId则添加到REQUESTID中paramuserIdpublicstaticvoidsetUserId(StringuserId){StringsMDC。get(REQUESTID);if(s!null){MDC。put(REQUESTID,suserId);}}publicstaticvoidremoveTraceId(){MDC。remove(REQUESTID);}publicstaticTCallableTwrap(finalCallableTcallable,finalMapString,Stringcontext){return(){if(contextnull){MDC。clear();}else{MDC。setContextMap(context);}setTraceIdIfAbsent();try{returncallable。call();}finally{MDC。clear();}};}publicstaticRunnablewrap(finalRunnablerunnable,finalMapString,Stringcontext){return(){if(contextnull){MDC。clear();}else{MDC。setContextMap(context);}设置traceIdsetTraceIdIfAbsent();try{runnable。run();}finally{MDC。clear();}};}}复制代码
  在SpringSecurity中添加token过滤器token过滤器验证token有效性authorruoyiSlf4jComponentpublicclassJwtAuthenticationTokenFilterextendsOncePerRequestFilter{AutowiredprivateTokenServicetokenSOverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainchain)throwsServletException,IOException{try{入口传入请求IDThreadMdcUtil。setTraceIdIfAbsent();LoginUserDetailloginUsertokenService。getLoginUser(request);if(Objects。nonNull(loginUser)Objects。isNull(SecurityContextHolder。getContext()。getAuthentication())){记录userIdThreadMdcUtil。setUserId(String。valueOf(loginUser。getMember()。getId()));tokenService。verifyToken(loginUser);UsernamePasswordAuthenticationTokenauthenticationTokennewUsernamePasswordAuthenticationToken(loginUser,null,loginUser。getAuthorities());authenticationToken。setDetails(newWebAuthenticationDetailsSource()。buildDetails(request));SecurityContextHolder。getContext()。setAuthentication(authenticationToken);}chain。doFilter(request,response);}finally{出口移除请求IDThreadMdcUtil。removeTraceId();}}}复制代码
  最后在logback。xml中添加X{requestid}propertynamepatternvalued{yyyyMMddHH:mm:ss。SSS}〔X{requestid}〕〔thread〕〔5level〕logger{36}:LMmsgn复制代码
  日志打印效果如下:2022112721:29:48。008〔86c76336100c414dbe9217aeb099ccd512〕〔httpnio82exec2〕〔INFO〕c。w。m。a。s。impl。IHomeServiceImpl:56getHomeIndexDataCompletableFuturegetHomeIndexDataCompletableFuture:com。wayn。common。util。R701f7b8e〔code200,msg操作成功,map{bannerList〔{createTime:2020062619:56:03,delFlag:false,id:14,imgUrl:https:m。360buyimg。commobilecmss700x280jfst111733539138372630995f291a83E8ba761d05c0460445cb28248。jpg!cr1125x4490166!q70。jpg。dpg,jumpUrl:http:82。157。141。70malldetail1155015,sort:0,status:0,title:hh2,updateTime:2022061909:16:46},{createTime:2020062619:56:03,delFlag:false,id:15,imgUrl:https:m。360buyimg。commobilecmss700x280jfst12020962611652265782616acb67E4fcdc9ac8d7cdfbb6c934e67。jpg!cr1125x4490166!q70。jpg。dpg,jumpUrl:detail1155015,sort:0,status:0,title:hh,updateTime:2022061909:04:58}〕,newGoodsList〔{actualSales:0,brandId:0,brief:酥脆奶香,甜酸回味,categoryId:1008015,counterPrice:56。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1116011,id:1116011,isHot:true,isNew:true,isOnSale:true,keywords:,name:蔓越莓曲奇200克,picUrl:http:yanxuan。nosdn。127。net767b370d07f3973500db54900bcbd2a7。png,retailPrice:36。00,shareUrl:,sort:5,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:粉彩色泽,记录生活,categoryId:1012003,counterPrice:49。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1127047,id:1127047,isHot:false,isNew:true,isOnSale:true,keywords:,name:趣味粉彩系列笔记本,picUrl:http:yanxuan。nosdn。127。net6c03ca93d8fe404faa266ea86f3f1e43。png,retailPrice:29。00,shareUrl:,sort:2,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:慢回弹海绵,时尚设计。,categoryId:1008002,counterPrice:66。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1134030,id:1134030,isHot:false,isNew:true,isOnSale:true,keywords:,name:简约知性记忆棉坐垫,picUrl:http:yanxuan。nosdn。127。netaa49dfe878becf768eddc4c1636643a6。png,retailPrice:46。00,shareUrl:,sort:12,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:慢回弹海绵的呵护,萌趣添彩。,categoryId:1008002,counterPrice:69。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1134032,id:1134032,isHot:false,isNew:true,isOnSale:true,keywords:,name:趣味粉彩系列记忆棉坐垫,picUrl:http:yanxuan。nosdn。127。net8b30eeb17c831eba08b97bdcb4c46a8e。png,retailPrice:49。00,shareUrl:,sort:13,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:100桑蚕丝,丝滑润肤,categoryId:1008009,counterPrice:2619。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1135002,id:1135002,isHot:false,isNew:true,isOnSale:true,keywords:,name:宫廷奢华真丝四件套,picUrl:http:yanxuan。nosdn。127。net45548f26cfd0c7c41e0afc3709d48286。png,retailPrice:2599。00,shareUrl:,sort:1,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:自由海军领探索未来梦,categoryId:1020003,counterPrice:89。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1135072,id:1135072,isHot:false,isNew:true,isOnSale:true,keywords:,name:经典海魂纹水手裙(婴童),picUrl:http:yanxuan。nosdn。127。net43e57d4208cdc78ac9c088f9b3e798f5。png,retailPrice:69。00,shareUrl:,sort:3,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:经典海魂纹自由海军领,categoryId:1020003,counterPrice:89。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1135073,id:1135073,isHot:false,isNew:true,isOnSale:true,keywords:,name:海魂纹哈衣水手服(婴童),picUrl:http:yanxuan。nosdn。127。net53052b04ae001d289c040e09ea92231c。png,retailPrice:69。00,shareUrl:,sort:4,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:5,brandId:0,brief:差旅好伴侣,categoryId:1032000,counterPrice:119。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1152031,id:1152031,isHot:true,isNew:true,isOnSale:true,keywords:,name:魔兽世界伊利丹颈枕眼罩套装,picUrl:http:yanxuan。nosdn。127。netfd6e78a397bd9e9804116a36f0270b0a。png,retailPrice:99。00,shareUrl:,sort:4,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:5,brandId:0,brief:桌面整理神器,categoryId:1032000,counterPrice:519。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1152095,id:1152095,isHot:false,isNew:true,isOnSale:true,keywords:,name:魔兽世界联盟暴风城堡垒收纳盒,picUrl:http:yanxuan。nosdn。127。netc86b49f635fa141decebabbd0966a6ef。png,retailPrice:499。00,shareUrl:,sort:6,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:0,brandId:0,brief:3重透气,清爽柔滑,categoryId:1008009,counterPrice:479。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1152161,id:1152161,isHot:false,isNew:true,isOnSale:true,keywords:,name:竹语丝麻印花四件套,picUrl:http:yanxuan。nosdn。127。net977401e75113f7c8334c4fb5b4bf6215。png,retailPrice:459。00,shareUrl:,sort:6,unit:件,updateTime:2018020100:00:00,virtualSales:10}〕,categoryList〔{createTime:2020120823:09:12,delFlag:false,iconUrl:http:cdn。wayn。xin9fc3c52571aa38a1466f114c2dc892fc。png,id:2,jumpType:0,name:大牌手机,picUrl:http:cdn。wayn。xin2545dd00ca4575759024af2811949a9d。jpg,sort:1,status:0,updateTime:2020121219:26:48,valueId:5,valueUrl:http:baidu。com},{createTime:2020120613:27:54,delFlag:false,iconUrl:http:82。157。141。70upload20220221a23fa32c8f4004a8c9fbbb1784462163。jpg,id:1,jumpType:0,name:滋补保健2,picUrl:http:cdn。wayn。xind4de7172eb7ae4178ae4dafd6a973d8f。jpg,sort:2,status:0,updateTime:2022061909:17:20,valueId:2},{createTime:2020120823:26:15,delFlag:false,iconUrl:http:cdn。wayn。xin6bc0f8a131d2d16b8fc2004d4aa4860c。png,id:3,jumpType:1,name:不锈钢锅,picUrl:http:cdn。wayn。xin314d87257f7a2ff03d5f4c5183797912。jpg,sort:2,status:0,updateTime:2020121219:27:24,valueId:1036000},{createTime:2020121219:28:08,delFlag:false,iconUrl:http:cdn。wayn。xin5a90531d901529967885279d7dc826e1。png,id:14,jumpType:0,name:进口牛奶,picUrl:http:cdn。wayn。xin0b1f6ab63d5e222c52c83a2d0581e44c。jpg,sort:3,status:0,valueId:5},{createTime:2020121219:28:33,delFlag:false,iconUrl:http:cdn。wayn。xin33530951827ca7e59940d51cda537d84。png,id:15,jumpType:0,name:量贩囤货,picUrl:http:cdn。wayn。xinbb6daee3b3e51c3008db97585249f513。jpg,sort:4,status:0,valueId:2},{createTime:2020121219:28:50,delFlag:false,iconUrl:http:cdn。wayn。xin7d337f25111b263b29d5d12589015c46。png,id:16,jumpType:0,name:清洁用品,picUrl:http:cdn。wayn。xinbe8995bda39d03b17349b8ec0dcab3d5。jpg,sort:5,status:0,valueId:2},{createTime:2020121219:29:10,delFlag:false,iconUrl:http:cdn。wayn。xin2e632ec0173bb477dcdb601495e0412a。png,id:17,jumpType:0,name:洗护用品,picUrl:http:cdn。wayn。xin53fb88c9d1245caa882aa3fc29187d0b。jpg,sort:6,status:0,valueId:4},{createTime:2020121219:29:28,delFlag:false,iconUrl:http:cdn。wayn。xin942323c0e74677cf2aa15f09a1e63bca。png,id:18,jumpType:0,name:日用百货,picUrl:http:cdn。wayn。xin8587f91db2edcb43e57da9835cc7ec76。jpg,sort:7,status:0,valueId:2},{createTime:2020121219:29:46,delFlag:false,iconUrl:http:cdn。wayn。xin18d9d860ba9b8b28522e050f11a8a8e0。png,id:19,jumpType:0,name:明星乳胶,picUrl:http:cdn。wayn。xin65273c7fb2273e90958e92626248a90a。jpg,sort:8,status:0,valueId:6},{createTime:2020121219:30:15,delFlag:false,iconUrl:http:cdn。wayn。xin7c790577afda91eebc3c95586e190957。png,id:20,jumpType:0,name:口碑好物,picUrl:http:cdn。wayn。xin210011b35be4ceee39e6a466b40b8e22。jpg,sort:9,status:0,updateTime:2021040120:13:08,valueId:5}〕,expiretime1669549170235,hotGoodsList〔{actualSales:1,brandId:1001045,brief:一级桑蚕丝,吸湿透气柔软,categoryId:1036000,counterPrice:719。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1006013,id:1006013,isHot:true,isNew:false,isOnSale:true,keywords:,name:双宫茧桑蚕丝被空调被,picUrl:http:yanxuan。nosdn。127。net583812520c68ca7995b6fac4c67ae2c7。png,retailPrice:699。00,shareUrl:,sort:7,unit:件,updateTime:2021080811:19:36,virtualSales:10},{actualSales:1,brandId:1001045,brief:双层子母被,四季皆可使用,categoryId:1008008,counterPrice:14199。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1006014,id:1006014,isHot:true,isNew:false,isOnSale:true,keywords:,name:双宫茧桑蚕丝被子母被,picUrl:http:yanxuan。nosdn。127。net2b537159f0f789034bf8c4b339c43750。png,retailPrice:1399。00,shareUrl:,sort:15,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:6,brandId:1001000,brief:加大加厚,双色精彩,categoryId:1036000,counterPrice:219。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1011004,id:1011004,isHot:true,isNew:false,isOnSale:true,keywords:,name:色织精梳AB纱格纹空调被,picUrl:http:yanxuan。nosdn。127。net0984c9388a2c3fd2335779da904be393。png,retailPrice:199。00,shareUrl:,sort:2,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:6,brandId:0,brief:共享亲密2人时光,categoryId:1008008,counterPrice:219。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1019002,id:1019002,isHot:true,isNew:false,isOnSale:true,keywords:,name:升级款护颈双人记忆枕,picUrl:http:yanxuan。nosdn。127。net0118039f7cda342651595d994ed09567。png,retailPrice:199。00,shareUrl:,sort:10,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:6,brandId:0,brief:健康保护枕,categoryId:1008008,counterPrice:119。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1019006,id:1019006,isHot:true,isNew:false,isOnSale:true,keywords:,name:植物填充护颈夜交藤枕,picUrl:http:yanxuan。nosdn。127。net60c3707837c97a21715ecc3986a744ce。png,retailPrice:99。00,shareUrl:,sort:7,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:6,brandId:0,brief:厚实舒适,categoryId:1008001,counterPrice:59。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1021000,id:1021000,isHot:true,isNew:false,isOnSale:true,keywords:被,name:埃及进口长绒棉毛巾,picUrl:http:yanxuan。nosdn。127。net7191f2599c7fe44ed4cff7a76e853154。png,retailPrice:39。00,shareUrl:,sort:7,unit:条,updateTime:2018020100:00:00,virtualSales:10},{actualSales:6,brandId:1001020,brief:浪漫毛线绣球,简约而不简单,categoryId:1008009,counterPrice:319。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1022000,id:1022000,isHot:true,isNew:false,isOnSale:true,keywords:,name:意式毛线绣球四件套,picUrl:http:yanxuan。nosdn。127。net5350e35e6f22165f38928f3c2c52ac57。png,retailPrice:299。00,shareUrl:,sort:18,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:32,brandId:1001000,brief:柔软纱布,婴童可用,categoryId:1036000,counterPrice:269。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1027004,id:1027004,isHot:true,isNew:false,isOnSale:true,keywords:,name:色织六层纱布夏凉被,picUrl:http:yanxuan。nosdn。127。net6252f53aaf36c072b6678f3d8c635132。png,retailPrice:249。00,shareUrl:,sort:3,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:32,brandId:0,brief:原生苦荞,健康护颈,categoryId:1008008,counterPrice:119。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1036002,id:1036002,isHot:true,isNew:false,isOnSale:true,keywords:,name:高山苦荞麦枕,picUrl:http:yanxuan。nosdn。127。netffd7efe9d5225dff9f36d5110b027caa。png,retailPrice:99。00,shareUrl:,sort:5,unit:件,updateTime:2018020100:00:00,virtualSales:10},{actualSales:32,brandId:0,brief:5cm记忆绵的亲密包裹,categoryId:1008008,counterPrice:619。00,createTime:2018020100:00:00,delFlag:false,goodsSn:1037011,id:1037011,isHot:true,isNew:false,isOnSale:true,keywords:,name:安睡慢回弹记忆绵床垫,picUrl:http:yanxuan。nosdn。127。neta03ea6f4509439acdafcb7ceba1debe0。png,retailPrice:599。00,shareUrl:,sort:22,unit:件,updateTime:2018020100:00:00,virtualSales:10}〕}〕2022112721:29:48。336〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPagempCount:137debugPreparing:SELECTCOUNT()AStotalFROMshopgoodsWHEREdelflag0ANDisonsale12022112721:29:48。387〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPagempCount:137debugParameters:2022112721:29:48。426〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPagempCount:137debugTotal:12022112721:29:48。430〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPage:137debugPreparing:selectid,goodssn,name,picurl,counterprice,retailprice,actualsales,virtualsalesfromshopgoodsWHEREdelflag0andisonsale1orderbycreatetimedescLIMIT?2022112721:29:48。452〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPage:137debugParameters:6(Long)2022112721:29:48。476〔9d919fb6d33c4652ba28ff87ae21080912〕〔httpnio82exec3〕〔DEBUG〕c。w。c。c。m。s。G。selectGoodsListPage:137debugTotal:6复制代码
  最后分析上诉日志:通过86c76336100c414dbe9217aeb099ccd5实现接口调用追踪,通过12用户ID,实现用户调用追踪七。alibabaexcel导出时自定义格式转换优雅实现
  官网介绍:EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
  EasyExcel是alibaba出的一个基于javapoi得excel通用处理类库,他的优势在于内存消耗。对比easypoi方案,EasyExcel在内存消耗、知名度(大厂光环)上更出众些。
  博主在使用过程中发现导出excel,官网对自定义格式字段提供了converter接口,但只简单提供了CustomStringStringConverter类代码,达不到博主想要得优雅要求,如下:publicclassCustomStringStringConverterimplementsConverterString{OverridepublicC?supportJavaTypeKey(){returnString。}OverridepublicCellDataTypeEnumsupportExcelTypeKey(){returnCellDataTypeEnum。STRING;}这里读的时候会调用paramcontextreturnOverridepublicStringconvertToJavaData(ReadConverterC?context){return自定义:context。getReadCellData()。getStringValue();}这里是写的时候会调用不用管returnOverridepublicWriteCellD?convertToExcelData(WriteConverterContextStringcontext){returnnewWriteCellData(context。getValue());}}复制代码
  在以上代码中,打个比方想要实现性别字段得自定义格式转换,就需要在convertToExcelData方法中,添加如下代码OverridepublicWriteCellD?convertToExcelData(WriteConverterContextStringcontext){Stringvaluecontext。getValue();if(man。equals(value)){returnnewWriteCellData(男);}else{returnnewWriteCellData(女);}}复制代码
  可以看到,非常得不优雅,对于这种类型字段,博主习惯使用枚举类来定义字段所有类型,然后将枚举类转换为map(value,desc)结构,就可以优雅得实现这个自定义格式得需求一、先定义int字段抽象转换类,实现通用转换逻辑publicabstractclassAbstractIntConverterimplementsConverterInteger{abstractListConverterDTOgetArr();publicWriteCellD?convertToExcelData(Integervalue,ExcelContentPropertycontentProperty,GlobalConfigurationglobalConfiguration){ListConverterDTOvaluesgetArr();MapInteger,Stringmapvalues。stream()。collect(toMap(ConverterDTO::getType,ConverterDTO::getDesc));Stringresultmap。getOrDefault(value,);returnnewWriteCellData(result);}staticclassConverterDTO{privateIprivateSpublicIntegergetType(){}publicvoidsetType(Integertype){this。}publicStringgetDesc(){}publicvoidsetDesc(Stringdesc){this。}publicConverterDTO(Integertype,Stringdesc){this。this。}}}二、定义通用状态字段转换类publicclassStatusConverterextendsAbstractIntConverter{OverrideListConverterDTOgetArr(){StatusEnum〔〕valuesStatusEnum。values();returnArrays。stream(values)。map(sexEnumnewConverterDTO(sexEnum。getType(),sexEnum。getDesc()))。toList();}状态枚举enumStatusEnum{MAN(0,启用),WOMAN(1,禁用);privateIprivateSStatusEnum(Integertype,Stringdesc){this。this。}publicIntegergetType(){}publicStringgetDesc(){}}}复制代码
  最后再导出ExcelProperty中甜腻加StatusConverter,就优雅得实现了自定义格式得需求publicclassUserextendsBaseEntity{。。。用户状态0启用1禁用ExcelProperty(value用户状态,converterStatusConverter。class)privateIntegeruserS。。。}复制代码八。Springboot默认redis客户端lettuce经常连接超时解决方案
  不知道大家有没有遇到这种情况,线上项目使用lettuce客户端,当操作redis得接口一段时间没有调用后(比如30分钟),再次调用redis操作后,就会遇到连接超时得问题,导致接口异常。博主直接给出分析过程:通过wireshark抓包工具,发现项目中redis连接创建后,一段时间未传输数据后,客户端发送psh包,未收到服务端ack包,触发tcp得超时重传机制,在重传次数重试完后,最终客户端主动关闭了连接。
  到这里我们就知道这个问题,主要原因在于服务端没有回复客户端(比如tcp参数设置、防火墙主动关闭等,都是针对一段时间内没有数据传输得tcp连接会做关闭处理),造成了客户端得连接超时
  面对这个问题有三种解决方案:redis操作异常后进行重试,这篇文章有介绍生产环境Redis连接,长时间无响应被服务器断开问题启用一个心跳定时任务,定时访问redis,保持redis连接不被关闭,简而言之,就是写一个定时任务,定时调用redis得get命令,进而保活redis连接基于Springboot提供得LettuceClientConfigurationBuilderCustomizer自定义客户端配置,博主这里主要针对第三种自定义客户端配置来讲解一种优雅得方式
  Springboot项目中关于lettuce客户端得自动配置是没有启用保活配置得,要启用得话代码如下:自定义lettuce客户端配置returnLettuceClientConfigurationBuilderCustomizerBeanpublicLettuceClientConfigurationBuilderCustomizerlettuceClientConfigurationBuilderCustomizer(){returnclientConfigurationBuilder{LettuceClientConfigurationclientConfigurationclientConfigurationBuilder。build();ClientOptionsclientOptionsclientConfiguration。getClientOptions()。orElseGet(ClientOptions::create);ClientOptionsbuildclientOptions。mutate()。build();SocketOptions。KeepAliveOptions。Builderbuilderbuild。getSocketOptions()。getKeepAlive()。mutate();保活配置builder。enable(true);builder。idle(Duration。ofSeconds(30));SocketOptions。BuildersocketOptionsBuilderclientOptions。getSocketOptions()。mutate();SocketOptions。KeepAliveOptionskeepAliveOptionsbuilder。build();socketOptionsBuilder。keepAlive(keepAliveOptions);SocketOptionssocketOptionssocketOptionsBuilder。build();ClientOptionsclientOptions1ClientOptions。builder()。socketOptions(socketOptions)。build();clientConfigurationBuilder。clientOptions(clientOptions1);};}复制代码
  添加lettuce客户端的自定义配置,在KeepAliveOptions中启用enable,这样lettuce客户端就会在tcp协议规范上启用keepalive机制自动发送心跳包九。redis客户端lettuce启用epoll
  直接给官网连接,配置很简单,添加一个nettyall得依赖,lettuce会自动检测项目系统是否支持epoll(linux系统支持),并且是否有nettytransportnativeepoll依赖(nettyall包含nettytransportnativeepoll),都满足得话就会自动启用epoll事件循环,进一步提升系统性能dependencygroupIdio。nettygroupIdnettyallartifactIddependency复制代码十。Springbootweb项目优雅停机
  web项目配置了优雅停机后,在重启jar包,或者容器时可以防止正在活动得线程被突然停止(kill9无解,请不要使用这个参数杀线上进程,dockercompose项目尽量不要用dockercomposedown命令关闭项目,使用dockercomposermsvf可以触发优雅停机),造成用户请求失败,在此期间允许完成现有请求但不允许新请求,配置如下:server:shutdown:graceful复制代码十一。nginx配置通用请求后缀
  先说下这个配置产生得前提,博主公司pc客户项目是基于electron打包得网页项目,每次项目大版本更新时,为了做好兼容性,防止客户端网页缓存等,会使用一个新网页地址,打个比方:
  老网页地址,v1。1。0版本网页访问地址:api。dev。compageV110
  新网页地址,v1。2。0版本网页访问地址:api。dev。compageV120
  那么项目得nginx配置则则需要新加一个v1。2。0得配置如下:server{listen80;servernameapi。dev。clientmaxbodysize10m;老网页v1。1。0配置locationpageV110{aliashomewwwrootapi。dev。compageV110;indexindex。htmlindex。}新网页v1。2。0配置locationpageV120{aliashomewwwrootapi。dev。compageV120;indexindex。htmlindex。}}复制代码
  那么博主在每次项目发布得时候就需要配合前端发版,配置一个新网页,故产生了这个通用配置得需求,如下:server{listen80;servernameapi。dev。clientmaxbodysize10m;配置正则localtionlocationpageV(。){sets1;定义后缀变量aliashomewwwrootapi。dev。compageVs;indexindex。htmlindex。}}复制代码
  在nginx配置文件语法中,location语句可以使用正则表达式,定义sets1变量,实现了通用配置十二。关于开发人员的自我提升和突破
  博主这里主要总结了四点:多和他人沟通,沟通能把复杂问题简单化,有时候开发阶段一个需求多问几句,可以减少因为个人理解差异导致的需求不一致问题,进而减少开发时间建立长短期目标,观看技术视频、书籍给自己充电,比如7天利用业余时间看完一本电子书,三十天从零开始一个新项目等善于总结,对于项目中的疑难bug,踩坑点要有记录,防止下次遇到再掉坑里敢于尝试、担责,对项目、代码里明确不合理的地方要敢于跟他人沟通,修改问题代码,达到优化目的。对于自己造成的问题要承担,不要推卸责任。对于线上问题要重视,优先解决线上问题。
  作者:wayn
  链接:https:juejin。cnpost7171770606940061727
投诉 评论

沉稳应对低谷期方能破局而出当下正值隆冬,虽然万物皆枯,但天地正在蕴藏着无限生机。现在听到最多的词儿就是难,其实岁月静好是片刻,一地鸡毛是日常。人生不如意,十之八九,在大家都面对同样难的情况下,如何……清荷札记与爱相携,心安当下作者:清荷札记时光,匆匆的脚步,更迭着四季的风景。昨日的缱绻成了时光里一阕染了沧桑,却依旧透着温柔的词章。人生的诸多烦恼,因为我们想得太多。当时光如水流逝,所有的日子,都……绿地今年无地很多人知道绿地是因为绿地的房子。很多人知道绿地是因为绿地的高楼。也许用这样一句话来形容绿地比较贴切:高楼,绿地造!根据绿地集团的官网介绍:成立30……健康养生三个细节,教你冬季养生进入冬季,随着气温下降,不少人会在秋冬之交生病。做好以下三个日常起居习惯,会减少疾病发生的概率,提升身体水平。日常注重三小步,健康文明一大步。愿健康伴随您走过一整个……贾乃亮7万片酬,带黄圣依逛街被嫌弃,女友一爆红就将其抛弃当年,贾乃亮拿着到手的七万片酬,向女友黄圣依报喜:这是我第一次拿这么高的片酬,我带你去逛街购物庆祝一下。黄圣依冷漠地说:就这么一点钱,有必要这么高兴吗?你也太没追求了。过后,黄……有科学的角度证明阎王爷住在哪里?首先我们了解一下地球的结构。它包含外层的地壳平均厚度是:17千米,中层的地幔:2865千米,内层的地核:3473千米。其中外层的地壳和内层的地核均为硬质结构。而中间的地幔……十二条后端开发经验分享,纯干货一。优雅的进行线程池异常处理在Java开发中,线程池的使用必不可少,使用无返回值execute()方法时,线程执行发生异常的话,需要记录日志,方便回溯,一般做法是在线程执……别帮女儿带娃,一位姥姥给出的忠告很现实,跟重男轻女无关邻居阿姨过来串门,一进门就拉着我妈诉苦,说再也不帮女儿带娃了,这一天天吃力不讨好,每天费心费力,担心来担心去,闺女不但不领情,反而还要跟她吵架。我很疑惑,阿姨带外孙也有四……旅游精品线路石家庄发布10条精品旅游线路石家庄市文广旅局特推出石家庄冬季旅游10条精品线路。一、红色传承革命圣地之旅具体线路:西柏坡纪念馆西柏坡中共中央旧址北庄村(歌曲《团结就是力量》诞生……冬季养肾就是养命?10种食材经常换着吃,养肾健脾,冬天少生病冬季养肾就是养命?10种食材经常换着吃,养肾健脾,冬天不生病。俗语说:秋养肺,冬养肾。冬天是养肾的好时机。冬天气温低,寒冷,人体需要较多的热量来抵御寒冷,所以饮食需要以温补为主……金融支持房地产市场平稳健康发展举措出台央视网消息:中国人民银行、银保监会日前发布做好当前金融支持房地产市场平稳健康发展工作的通知,多条具体举措出台,因城施策,支持刚性和改善性住房需求,保持房地产融资合理适度,促进房……寻觅古格王朝的今生前世现存古格王朝遗址照片拍摄于2022年6月21日扎达县古格王朝遗址照片拍摄于2022年6月21日扎达县古格王朝遗址照片拍摄于2022年6月21日扎达县古格王朝遗……
房子被天灾冲垮,没还完的房贷还算数吗?银行已给出答案倪鹏飞应实施大城市青新市民安居工程2021年中国19大城市群,看看你在哪个城市群山东省各地市2021年3月房价出炉9座城市下跌了各地严查经营贷,楼市何时能停歇提前还房贷注意事项不破不立,大盘底部为期不远,3大投资策略,赢取2022投资之希腊码头经理爱上中国智慧河北混采由40降至3。6元说明了什么?4月汽车销量排名最全版共497款车型,看看你的爱车排第几?3月1日起!个人收款码这样调整金价大涨行情需要以下要素小龙虾肉质松散会不会是品种问题和品种没多大关系丰碑评课稿医院业务工作总结趣说城市毛泽东诗词《七律和周世钊同志》原文、注释及赏析失眠相济汤治疗失眠多梦易醒判断女生喜不喜欢你就看这点夏季养心正当时,打通心包经的阻滞点从裸体艺术看汉代两性关系的开放窗口单位改进作风专项行动工作情况的汇报初中的时候对男生有好感是这样做的东风解冻省试

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找