- 博客(83)
- 资源 (5)
- 收藏
- 关注
原创 经典游戏,用java实现的坦克大战小游戏
今天给大家分享一个使用java编写的坦克大战小游戏,整体还是挺好玩的,通过对这款游戏的简单实现,加深对java基础的深刻理解。1.坦克大战小游戏通过java实现,其第一步需要先绘制每一关对应的地图,地图包括河流、草地、砖块、铁块等。2.需要绘制玩家坦克、敌方坦克、以及坦克移动过程中使用到的碰撞算法,子弹与坦克之间的碰撞,包括击中敌方坦克后的爆炸效果,通过重绘实现坦克的移动,以及各种道具的随机生成算法。其中,切换到下一关,按键盘N,上一个按P,空格键射击。有兴趣的可以试一试。
2024-08-19 22:31:25
350
原创 Java实现mysql的分页及流式查询导出
在实际应用中,当我们需要导出大数据量数据时,可能会存在一些问题,因为当我们一下子将数据全部加载出来到内存中,很可能会发生OOM(内存溢出),而且查询会很慢,因为框架耗费大量的时间和内存去把数据库查询的结果封装成我们想要的对象(实体类)。但是需要注意的是:在使用分页查询需要注意深分页问题,否则会导致导出效率非常低。而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此,使用流式查询导出可以有效避免大数据量导出时的OOM问题,但是流式查询需要注意长时间占用数据库连接的问题。
2024-05-06 17:00:28
706
原创 ElasticSearch深度分页原理及解决方案
简单来说,就是搜索的特别深,比如总共有100000条数据,四个primary shard,每个shard上分了25000条数据,每页是10条数据,这个时候,你要搜索到第1000页,实际上要拿到的是10001~10010,为了获取这些深层次页面的数据,系统通常需要先查询并处理前面所有页面的数据,以确保能够正确地显示用户所请求的页面,这个过程可能导致查询范围非常广泛,从而显著降低查询效率,增加服务器负担。3.数据不稳定性:在深度分页过程中,如果有新的文档被索引或删除,可能会导致结果的不稳定性。
2024-04-27 14:45:58
1459
原创 Redis缓存淘汰策略分析
把其中最小的淘汰出去。而且,当有数据被访问时,需要在链表上把数据移动到 MRU 端,如果有大量的数据被访问,就会带来很多链表移动操作,会耗时,进而降低 Redis 缓存性能。redis缓存是在内存中保存数据,避免业务从数据库中读取数据,从而提升系统的响应速度,而redis缓存淘汰是指当缓存数据达到一定容量时,为了给新的数据腾出空间,需要按照一定的策略从缓存中移除旧的数据。LRU算法其实可以这样理解,就是认为刚刚访问的数据可能还会被访问到,就会放在MRU端,长时间不访问的数据放在LRU端,缓存满了就删除它。
2024-04-26 09:38:15
648
原创 Alibaba 的fastjson源码详解
一、概述Fastjson 是阿里巴巴开源的一个 Java 工具库,它常常被用来完成 Java 的对象与 JSON 格式的字符串的相互转化。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。二、源码分析1.首先以fastjson-1.2.70为例,用IDEA打开看下项目结构,如下:2.涉及Java 的对象与 JSON 格式的字符串的相互转化,首先的分析JSON这个抽象类。(1)这个类有很多的方法,如下图:上述只是部分方法。JSON类实现了2个接口,JSON
2024-04-25 09:07:29
1136
原创 Java 后台实现通过阿里云短信api发送短信验证码
在实际项目中, 涉及用户登录或者注册时,可能需要有多种登录方式,通过用户密码登录或者手机号验证码登录,那么当使用验证码登录时,就需要发送手机验证码,下面就具体说明如何通过aliyun 短信Api实现发送验证码的功能。main方法执行后,如果发送成功,则会打印发送的验证码,否则打印 errror。2.编写发送短信验证码的工具类AliyunSmsUtils。1.引入阿里云短信相关的Maven依赖。3.接着我们通过main方法调用。二、如何实现发送验证码?
2024-04-24 09:25:33
477
原创 java实现解析html获取图片或视频url
有时在实际项目中,比如发布某篇文章,需要取文章中的某张图片作为封面,那么此时需要文章内容,获取html内容中的图片地址作为封面,下面讲下如何获取html中的图片或视频地址。1.先定义一个工具类,解析html获取图片地址。2.通过main方法调用看是否可获取。结果是正常获取到了图片或视频的url。上面通过正则匹配获取src中的地址。
2024-04-23 09:22:15
576
2
原创 Springboot如何实现接口重试
在实际项目中,往往在某些特定的场景下,我们需要实现接口调用异常的重试机制,比如在跨平台的业务中,需要调用第三方接口实现某些功能,难免会遇到一些网络问题,这时候需要加入重试机制了。在重试过程中,需要考虑接口并发的问题,如果多个线程同时进行重试,可能会导致请求重复发送或请求顺序混乱等问题。1.合理设置重试次数和重试间隔时间,避免频繁地发送请求,同时也不要设置过大的重试次数,以免影响系统的性能和响应时间。这时候调用失败时会重试,并且在重试发生出发监听,打印相应的异常日志。3.定义一个服务类,编写需要重试的方法。
2024-04-22 09:26:32
511
原创 Java中的ConcurrentHashMap原理详解
ConcurrentHashMap是(java.util.concurrent包)的重要成员,它是HashMap的一个线程安全的、支持高效并发的版本,ConcurrentHashMap和HashMap一样,是一个存放键值对的容器。1.高并发性能:ConcurrentHashMap JDK1.8 在 1.7 的数据结构上做了大的改动,采用了CAS+synchronized+Node+红黑树实现,结合了原子操作的优势,同时也保持了锁的简洁性。(1)取消了Segment类,直接用table数组存储键值对。
2024-04-21 10:53:04
1184
原创 Springcloud中的@RefreshScope详解
3.当应用首次请求一个被@RefreshScope标记的Bean时,Spring容器会调用RefreshScope的get方法来创建Bean的实例,创建完成后,这个Bean实例会被缓存在RefreshScope中,以便后续快速获取。@RefreshScope注解是Spring Cloud中的一个注解,它用来实现Bean中属性的动态刷新,这意味着您可以在不停止和重新启动应用程序的情况下更改配置,它在微服务配置中心的场景下经常出现。8.经过刷新操作后,应用中的Bean将使用新的配置。
2024-04-20 12:15:08
2402
1
原创 SpringCloud中的nacos注册中心分析
(1)服务注册:服务提供者在启动时,将自己的服务信息注册到nacos 注册中心,nacos 客户端会通过发送REST请求的方式向nacos server注册自己的服务,提供自身的元数据,比如ip地址、端口等信息。(2)分组(Group):nacos数据模型中次于命名空间的一种隔离概念,区别于命名空间的强制隔离属性,分组属于一个弱隔离概念,主要用于逻辑区分一些服务使用场景或不同应用的同名服务,最常用的情况主要是同一个服务的测试分组和生产分组、或者将应用名作为分组以防不同应用提供的服务重名。
2024-04-19 21:38:21
1227
原创 springboot实现文件上传到Sftp
注:host,username,passwd是sftp连接相关信息,填写你自己的sftp地址等信息就行。最近项目有需求需要将本地文件上传到sftp上,那么如何实现呢?这里就讲下具体实现。3.接下来通过main方法测试上传图片到sftp。2.编写上传到sftp工具类SftpUtil。这样就可以连接到sftp上传文件了。1.添加sftp maven依赖。二、实现文件上传到sftp。大家可以自己尝试下。
2024-04-18 22:01:01
410
原创 SpringCloud中的nacos配置中心分析
就是这个客户端进行启动的时候,就会优先拉取本地的配置,如果本地配置不存在,那么就会和这个服务端建立这个http请求,然后去拉取这个服务端的全部配置,就是配置中心的全部配置。在拉取到全部配置之后,会去获取每一个配置文件的dataId,然后通过这个id对服务端的每一个配置文件进行一个监听的操作。当服务端这边的配置文件出现修改的时候,就可以通过这个监听器进行感知,然后这个客户端也会对对应的配置文件进行修改,每一份修改的配置都会存储在这个nacos配置文件里面,会作为一个历史文件保留。以下是读取本地配置具体实现。
2024-04-17 11:26:21
349
原创 Springboot中@FeignClient详解
FeignClient 注解是 Spring Cloud 中的一个组件,基于 Netflix Feign 实现的,@FeignClient 注解可以帮助我们定义和实现服务之间的 RESTful 接口,使得服务之间的调用更加方便和可靠。Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,返回给调用者。在微服务架构中,服务之间的调用是非常频繁的。
2024-04-16 07:54:14
3177
原创 Springboot整合nacos实现配置中心及服务发现
首先,nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。而springboot能够创建一个独立运行spring应用框架,因此,springboot整合nacos,可以更方便实现服务的发现、配置管理等相关功能。}来引用nacos中的配置。在bootstrap.properties或bootstrap.yml文件中配置nacos的相关信息。接着启动应用后,就可以在nacos的服务列表中看到我们已经注册到nacos的服务。1.在pom文件中添加nacos依赖。2.配置nacos。
2024-04-15 14:53:53
722
原创 java通过Feign调用上传接口报错问题分析
在feign接口的地方加上 consumes = MediaType.MULTIPART_FORM_DATA_VALUE。最近项目中需要上传jar文件需求,需要调用远程服务实现,但是在这个过程中出现调用报错的问题,这里做下相关分析。feign接口文件参数使用@RequestPart注解,该注解对于文件参数,声明这是multipart类型。这是因为Feign客户端在发送请求时没有将请求标记为multipart类型。这样就可以正常上传了。
2024-04-07 10:57:13
521
原创 java Lock锁详解
1.公平锁:就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己。await(long time, TimeUnit unit):使当前线程等待一段时间,在指定的时间内没有被其他线程调用signal()或signalAll()方法唤醒,将自动唤醒。await():使当前线程等待,直到被其他线程调用signal()或signalAll()方法唤醒。
2024-03-11 16:53:19
1913
原创 Mysql索引失效分析
分析:因为索引保存的是索引字段的原始值,不是 id + 1 表达式计算后的值,所以无法走索引,只能通过把索引字段的值取出来,然后进行表达式的计算来进行条件判断,因此就是采用全表扫描的方式。在实际项目中,我们会遇到在使用Mysql数据库时,使用了索引,但是查询依旧很慢,发现是索引失效了,从而导致查询效率下降,甚至全表扫描,影响数据库性能。索引是提高MySQL查询性能的重要工具,但在某些情况下,索引也会失效,所以我们在使用索引前需要先了解索引失效的原因以及优化策略,这样便于更好的使用索引。5.使用了不等于(!
2024-03-11 10:59:30
421
原创 Java实现从本地读取CSV文件数据
最近项目中需要实现这样一个功能,就是从本地读取CSV文件,并以指定行作为标题行,指定行开始作为数据读取行,读取数据并返回给前端,下面具体说下是如何通过java实现。其中readCount表示返回的数据数量。2.定义一个工具类CsvUtils。接着通过main方法调用下。1.引入相关maven依赖。
2024-03-08 16:18:07
622
原创 java实现文件的压缩及解压
最近在项目开发中需要实现文件的压缩及解压功能,以满足某些特定场景的下的需要,因此在这里说下具体实现。接口main方法调用下方法就可以了。
2024-03-07 10:01:22
542
2
原创 Springboot整合Redis实现消息发布订阅
有时候在实际项目中,某些业务场景下我们需要使用消息的发布订阅功能,以实现某些特殊的需求,那么我们实际上可以有多种选择,比如使用常见的消息中间件Rabbitmq,Kafka,Activemq等,但这几个都算是重量级的消息队列,使用成本相比较于Redis要高,而在有些业务中,我们可能只是想实现消息的发布订阅,并不是需要保证消息的完全的可靠性没有很高的要求,那么使用Redis无疑是最好的选择。3.实现自定义的Redis 消息订阅-消息监听器,处理收到的订阅消息。6.我们也可以在Controller测试下。
2023-12-13 18:11:13
940
1
原创 Redis数据类型String详解
(1)获取长度的时间复杂度为 O(1):SDS 内部维护了一个 len 属性,这个属性记录了字符串的长度,因此获取字符串长度的时间复杂度为 O(1),而 C 字符串需要遍历整个字符串才能获取到长度,时间复杂度为 O(n);(2)内存效率:SDS 通过维护一个 free 属性,记录了 buf 数组中未使用的字节数量,这样可以在需要扩展字符串时,直接使用这些未使用的空间,而不需要重新分配内存,提高了内存的使用效率;这个数组的末尾总是包含一个空字符(‘\0’),这样 SDS 就可以兼容 C 语言的字符串函数。
2023-12-11 11:15:35
946
原创 Java实现布隆过滤器
当我们需要判断一个元素是否存时,首先对给定元素再次执行哈希计算,得到与添加元素时相同的位数组位置,判断所得位置是否都为 1,如果其中有一个为 0,那么说明元素不存在,若都为 1,则说明元素有可能存在。布隆过滤器本质上是一个很长的二进制数组,主要用来判断一个数据存不存在数组里,如果存在就用1表示,不存在用0表示,它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。因此,布隆过滤器容错还是非常可以的,当然也可以通过redis实现布隆过滤器,这里就不说明了。
2023-12-08 11:49:33
459
原创 Springboot实现配置多数据源
在实际开发应用中,我们可能需要在一个项目中连接多个数据源,已满足实际的开发业务需求,那么就需要实现连接多数据源的功能,而一些框架和工具,如Spring Boot和MyBatis等,提供了对多数据源的支持,简化了多数据源的配置和管理过程。1.在pom.xml中添加相应的数据库驱动和Spring Boot的数据库依赖,比如Postgresql、Mysql等。在Spring Boot的配置类中创建多个数据源的DataSource Bean,并注入对应的配置信息。二、Spring Boot 如何配置多数据源?
2023-12-07 16:11:11
937
原创 Java8新特性CompletableFuture详解
thenCombine()被用来当两个独立的Future都完成的时候,用来做一些事情。CompletableFuture 是Java 8 中引入的 Java Future API的扩展,用于 Java 中的异步编程,它可以使我们的任务运行在与主线程分离的其他线程中,并通过回调在主线程中得到异步任务执行状态,包括是否完成,是否异常等信息。我们 使用 thenCompose()组合两个独立的future,假设我们想从一个远程API中获取一个用户的信息,当用户信息可用时,我们想从另外一个服务中获取另外的信息。
2023-12-06 17:08:06
1404
原创 Java自定义mybatis拦截器实现创建人等相关信息自动填充
创建时间,更新时间,创建人,更新人这些,但是又不想在每个业务中都去设置这些值,那么我们就可以使用mybatis拦截器实现数据自动填充。在实际项目开发中,我们可能需要在mapper层插入相应的数据,而这些数据在各个表基本都有,比如。下面是TokenUtil类,用于获取当前登录用户id。这样就实现了在DAO层 创建人等相关信息自动填充。1.首先添加mybatis相关依赖。2.自定义mybatis拦截器。
2023-12-05 15:33:52
663
原创 Java中CAS底层原理
解释:当某一个线程如果对一个值更新,可以看对这个值进行分段更新,每一段叫做一个Cell,在更新每一个Cell的时候,如果很难更新它的值,出现了多次 CAS失败了,无限循环自旋的时候,进行自动迁移段,它会去尝试更新别的分段Cell的值,这样的话就可以让一个线程不会盲目的CAS自旋等待一个更新分段cell的值。当有多个线程对一个原子类进行操作的时候,某个线程在短时间内将原子类的值 A 修改为 B,又马 上将其修改为 A,此时其他线程无感知,还是会修改成功。操作时,先从内存位置读取到值,然后和预期值A比较。
2023-12-04 18:15:26
911
原创 Java新特性Stream流详解
Stream是Java 8中非常重要的一个API,本文详细介绍了Java Stream流的概念、使用方法。通过Stream流,开发人员可以以声明式的方式对数据进行操作,使代码更加简洁、易读。iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成3个偶数。API添加的一个新的抽象,以一种声明性方式处理数据集合(侧重对于源数据计算能力的封装,并且支持序列与并行两种操作方式)。1.创建Stream流。
2023-10-13 18:00:06
870
1
原创 Java8新特性Optional 详解
7.flatMap: map 方法参数中的函数 mapper 输出的是值,然后 map 方法会使用 Optional.ofNullable 将其包装为 Optional;8.filter: 接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;可以多次使用map操作。3.orElse: 参数是一个值,如果 Optional 中有值则将其返回,否则返回 orElse 方法传入的参数。方法返回true,调用get()方法可以获取值。
2023-10-12 11:23:53
364
1
原创 Springboot引入jasypt实现加解密
有时在实际应用中,我们可能需要使用到一些秘钥,针对某些资源文件中的内容通常情况下是明文显示,安全性就比较低一些,比如redis登陆密码以及第三方的密钥等等一览无余,这时就可以使用jasypt来实现加解密。jasypt由于其使用的是PBEWithMD5AndDES加密方式,所以每次加密出来的结果都不一样,但是解密都是一样的,所以很适合对数据进行加密。1.引入Maven jar包。3.接着写个测试类。
2023-10-11 17:58:02
348
原创 idea 启动项目报错 Command line is too long
1.idea 启动报错 Command line is too long,启动报错信息:Error running ‘Application‘: Command line is too long.2.打开项目下的*.idea* 文件夹下的 workspace.xml 文件。1)idea打开一个项目。这样就可以正常启动了。
2023-10-11 16:11:43
1129
原创 git clone项目报错文件名过长
Windows支持最长260字符的文件名(包括其路径在内),相对的,Git 可以创建 4096 长度的文件名,而在Windows下使用长文件名的前提时要先打开Windows的长路径支持。1.最近从git上clone项目时,有时会遇到报错,报出Filename too long错误。在执行克隆命令前,先执行如下命令,目的是打开Windows长路径支持。
2023-10-11 15:32:14
1063
原创 SpringBoot读取Resource下文件
ResourceLoader接口是Spring框架提供的用于加载各种资源的接口,包括classpath下的资源。有时在项目中,涉及一些导入的功能,那么需要提供一些模板下载,那么就需要读取模板,而模板放在resource下,那么可以通过多种方式读取文件。此方法默认是从 classpath 路径(即:src 或 resources 路径下)下查找文件的,但它的路径前需要加 “/”。相对于项目名(即:编译后的 classes 文件夹),路径前是需要加 “/”。以上是常见的读取方式。
2023-10-11 11:03:08
1647
原创 Springboot实现Web组件注册
在实际开发中,有时候我们可能使用springboot注册web组件,实现某些功能,比如我们需要生成一些api来提供对外的服务,而对应的路径其实是不固定的,那么这种情况下,其实是可以通过这种方式来注册web组件的。1.使用SpringBoot注解加继承HttpServet类实现注册Servlet组件。最后启动类中的@ServletComponentScan注解扫描web组件。2.通过继承HttpServet类加配置类来进行注册。3.注册Filter组件实现过滤。两种注册方式都是可用的。
2023-10-10 18:00:40
171
原创 详解Volatile关键字
synchronized的原子性是指,只要声明为synchronized的方法或代码块,在执行上就是原子操作的,而volatile是不修饰方法或代码块的,它只用来修饰变量,对于单个volatile变量的读和写操作都具有原子性,但类似于volatile++这种复合操作不具有原子性。volatile可见性的实现是借助了CPU的lock指令,lock指令在多核处理器下,可以将当前处理器的缓存行的数据写回到系统内存,同时使其他CPU里缓存了该内存地址的数据置为无效。
2023-10-09 17:00:21
65
原创 论Spring事务失效的多种场景
从前面的内容可以知道,updateData方法拥有事务的能力是因为spring aop生成代理了对象,但是这种方法直接调用了this对象的方法,所以updateData方法不会生成事务。看过spring事务的源码,就会知道spring事务底层使用了aop,也就是通过jdk动态代理或者cglib,帮我们生成了代理类,在代理类中实现的事务功能。在实际开发当中,如果使用事务不当,会造成Spring事务的失效,那么可能就会引发一些问题,如何解决呢,首先需要了解导致Spring事务失效的场景。
2023-09-22 17:48:09
181
原创 Mybatis工作流程及原理详解
5.Executor:Executor(执行器)接口有两个实现类,其中BaseExecutor有三个继承类分别是BatchExecutor(重用语句并执行批量更新),ReuseExecutor(重用预处理语句prepared statement,跟Simple的唯一区别就是内部缓存statement),SimpleExecutor(默认,每次都会创建新的statement)。本文结合Mybatis源码,详细的阐述了业务编码中通过Mapper接口方式来操作数据库的底层实现原理。二、MyBatis的重要组件。
2023-09-19 16:30:23
1506
1
原创 谈谈线程及线程池的生命周期
shutdownNow()是一个立即关闭过程,线程池停止接受新的任务,同时线程池取消所有执行的任务和已经进入队列但是还没有执行的任务,这时候线程池处于STOP状态。虽然创建销毁线程比创建销毁进程更轻量, 但是在频繁创建销毁线程的时候还是会比较低效,线程池就是为了解决这个问题,如果某个线程不再使用了,并不是真正把线程释放,而是放到一个“池子”中,下次如果需要用到线程就直接从池子中取,不用再次创建。(3)STOP:停止状态,不再接受新的任务,也不处理阻塞队列中的任务,中断正在处理的任务线程。
2023-09-19 11:52:52
186
原创 Java实现敏感日志脱敏
在实际项目中,可能需要对日志中的一些敏感数据脱敏,比如使用遮掩算法,只显示部分数据。1.首先定义一个工具类,对常见的一些敏感数据脱敏。2.使用反射实现脱敏。
2023-09-16 18:01:36
721
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人