领导:谁再用定时任务实现关闭订单,立马滚蛋!

在电商、支付等领域,往往会有这样的场景,用户下单后放弃支付了,那这笔订单会在指定的时间段后进行关闭操作,细心的你一定发现了像某宝、某东都有这样的逻辑,而且时间很准确,误差在1s内;那他们是怎么实现的呢? 一般的做法有如下几种 定时任务关闭订单 rocketmq延迟队列 rabbitmq死信队列 时间轮算法 redis过期监听 一、定时任务关闭订单(最low) 一般情况下,最不推荐的方式就是关单方式就是定时任务方式,原因我们可以看下面的图来说明 我们假设,关单时间为下单后10分钟,定时任务间隔也是10分钟;通过上图我们看出,如果在第1分钟下单,在第20分钟的时候才能被扫描到执行关单操作,这样误差达到10分钟,这在很多场景下是不可接受的,另外需要频繁扫描主订单号造成网络IO和磁盘IO的消耗,对实时交易造成一定的冲击,所以PASS 二、rocketmq延迟队列方式 延迟消息 生产者把消息发送到消息服务器后,并不希望被立即消费,而是等待指定时间后才可以被消费者消费,这类消息通常被称为延迟消息。 在RocketMQ开源版本中,支持延迟消息,但是不支持任意时间精度的延迟消息,只支持特定级别的延迟消息。 消息延迟级别分别为1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h,共18个级别。 发送延迟消息(生产者)

  消费延迟消息(消费者)

  实现监听类,处理具体逻辑

 

  这种方式相比定时任务好了很多,但是有一个致命的缺点,就是延迟等级只有18种(商业版本支持自定义时间),如果我们想把关闭订单时间设置在15分钟该如何处理呢?显然不够灵活。 三、rabbitmq死信队列的方式 Rabbitmq本身是没有延迟队列的,只能通过Rabbitmq本身队列的特性来实现,想要Rabbitmq实现延迟队列,需要使用Rabbitmq的死信交换机(Exchange)和消息的存活时间TTL(Time To Live) 死信交换机 一个消息在满足如下条件下,会进死信交换机,记住这里是交换机而不是队列,一个交换机可以对应很多队列。 一个消息被Consumer拒收了,并且reject方法的参数里requeue是false。也就是说不会被再次放在队列里,被其他消费者使用。 上面的消息的TTL到了,消息过期了。 队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上。 死信交换机就是普通的交换机,只是因为我们把过期的消息扔进去,所以叫死信交换机,并不是说死信交换机是某种特定的交换机 消息TTL(消息存活时间) 消息的TTL就是消息的存活时间。RabbitMQ可以对队列和消息分别设置TTL。对队列设置就是队列没有消费者连着的保留时间,也可以对每一个单独的消息做单独的设置。超过了这个时间,我们认为这个消息就死了,称之为死信。如果队列设置了,消息也设置了,那么会取值较小的。所以一个消息如果被路由到不同的队列中,这个消息死亡的时间有可能不一样(不同的队列设置)。这里单讲单个消息的TTL,因为它才是实现延迟任务的关键。

  可以通过设置消息的expiration字段或者x-message-ttl属性来设置时间,两者是一样的效果。只是expiration字段是字符串参数,所以要写个int类型的字符串:当上面的消息扔到队列中后,过了60秒,如果没有被消费,它就死了。不会被消费者消费到。这个消息后面的,没有“死掉”的消息对顶上来,被消费者消费。死信在队列中并不会被删除和释放,它会被统计到队列的消息数中去 处理流程图 创建交换机(Exchanges)和队列(Queues) 创建死信交换机 如图所示,就是创建一个普通的交换机,这里为了方便区分,把交换机的名字取为:delay 创建自动过期消息队列 这个队列的主要作用是让消息定时过期的,比如我们需要2小时候关闭订单,我们就需要把消息放进这个队列里面,把消息过期时间设置为2小时 创建一个一个名为delay_queue1的自动过期的队列,当然图片上面的参数并不会让消息自动过期,因为我们并没有设置x-message-ttl参数,如果整个队列的消息有消息都是相同的,可以设置,这里为了灵活,所以并没有设置,另外两个参数x-dead-letter-exchange代表消息过期后,消息要进入的交换机,这里配置的是delay,也就是死信交换机,x-dead-letter-routing-key是配置消息过期后,进入死信交换机的routing-key,跟发送消息的routing-key一个道理,根据这个key将消息放入不同的队列 创建消息处理队列 这个队列才是真正处理消息的队列,所有进入这个队列的消息都会被处理 消息队列的名字为delay_queue2 消息队列绑定到交换机 进入交换机详情页面,将创建的2个队列(delayqueue1和delayqueue2)绑定到交换机上面 自动过期消息队列的routing key 设置为delay 绑定delayqueue2 delayqueue2 的key要设置为创建自动过期的队列的x-dead-letter-routing-key参数,这样当消息过期的时候就可以自动把消息放入delay_queue2这个队列中了 绑定后的管理页面如下图: 当然这个绑定也可以使用代码来实现,只是为了直观表现,所以本文使用的管理平台来操作 发送消息

  设置了让消息6秒后过期 注意:因为要让消息自动过期,所以一定不能设置delay_queue1的监听,不能让这个队列里面的消息被接受到,否则消息一旦被消费,就不存在过期了 接收消息 接收消息配置好delay_queue2的监听就好了

  […]

@RequestMapping 使用详解

这一节虽然简单,但是很繁琐,可以先了解 @RequestMapping 的使用,不是很明白也没有关系,先继续往下学习,等你回头再看一遍的时候,你会发现 @RequestMapping 竟然是如此的简单! @RequestMapping可以在控制器类上或者控制器方法上使用。 在类的级别上的注解会将一个特定请求或者请求模式映射到一个控制器之上。之后你还可以另外添加方法级别的注解来进一步指定到处理方法的映射关系。 基础用法: 下面的 @RequestMapping("/index") 等同于 @RequestMapping(value = "/index")

  method 参数支持:GET, PUT, POST, DELETE 以及 PATCH。使用 method 可以限制接受的请求类型。 hello() 方法将只接受请求方式为 GET 方式,请求地址为:/index/hello 的请求。 world() 方法将只接受请求方式为 POST 方式,请求地址为:/index/world 的请求。 @GetMapping("/hello") 等同于 @RequestMapping(value="/hello", method=RequestMethod.GET) @PostMapping("/world") 等同于 @RequestMapping(value="/world", method=RequestMethod.POST) 映射多个地址: @RequestMapping 还可以将多个请求映射到一个方法上,只需要给 value 来指定一个包含多个路径的列表。

  URI模板: URI模板可以为快速访问 @RequestMapping 中指定的URL的一个特定的部分提供很大的便利。 使用 @PathVariable 可以获取到 {name} 的值,并在控制台进行输出。比如请求地址为:http://localhost:8080/SpringMVC/hello/jack 那么控制台上将会把 jack 进行输出。

  如果路径中的URI变量和方法中的参数名不一样的话,那么需要在 @PathVariable 中显示的绑定参数。

  一个方法可以拥有任意数量的 @PathVariable 注解:

  @PathVariable 可以被应用于所有 简单类型 的参数上,比如 int、long、Date 等类型。Spring会自动地帮你把参数转化成合适的类型,如果转换失败,就抛出一个 TypeMismatchException。如果你需要处理其他数据类型的转换,也可以注册自己的类。 带正则表达式的URI模板: 你可以使用正则表达式来准确的描述可以接受的请求路径:

  Ant风格的路径模式: 除了URI模板外,@RequestMapping注解还支持Ant风格的路径模式(如/hello/*.do等)。不仅如此,还可以把URI模板变量和Ant风格的glob组合起来使用(比如/hello/*/user/{userId}这样的用法等)。其中*则表示任意字符串。但是遇到 / 那么就会认为是下一部分的URI,所以 * 中不能有 / 。

  那么想要匹配带 / 的路径那该怎么办?可以使用 ** 来进行匹配。例如 /hello/**/user/{userId} 则会匹配 /hello/ 和 /user/{userId} 之间的部分。

  路径样式的匹配(Path Pattern Comparison): 当一个URL同时匹配多个模板(pattern)时,我们将需要一个算法来决定其中最匹配的一个。 URI模板变量的数目和通配符数量的总和最少的那个路径模板更准确。举个例子,/hotels/{hotel}/*这个路径拥有一个URI变量和一个通配符,而/hotels/{hotel}/**这个路径则拥有一个URI变量和两个通配符,因此,我们认为前者是更准确的路径模板。 如果两个模板的URI模板数量和通配符数量总和一致,则路径更长的那个模板更准确。举个例子,/foo/bar*就被认为比/foo/*更准确,因为前者的路径更长。 如果两个模板的数量和长度均一致,则那个具有更少通配符的模板是更加准确的。比如,/hotels/{hotel}就比/hotels/*更精确。 […]

解决IDEA2021版compiler.automake.allow.when.app.running不存在的问题

IntelliJ IDEA 简称 IDEA,被业界公认为最好的 Java 集成开发工具,尤其在智能代码助手、代码自动提示、代码重构、代码版本管理(Git、SVN、Maven)、单元测试、代码分析等方面有着亮眼的发挥。IDEA 产于捷克,开发人员以严谨著称的东欧程序员为主。IDEA 分为社区版和付费版两个版本。 idea2021免费激活教程: https://www.jb51.net/article/195962.htm https://www.jb51.net/article/196349.htm 下面开始今天的正文介绍: 很多文章介绍IntelliJ IDEA开启热部署功能都会写到在IntelliJ IDEA中的注册表中开启compiler.automake.allow.when.app.running选项,此选项在IntelliJ IDEA 2021.2之后的版本迁移到高级设置中。如下图所示:   如果你安装了中文语言包,那么它在这里 到此这篇关于解决IDEA2021版compiler.automake.allow.when.app.running不存在的问题的文章就介绍到这了,更多相关idea2021compiler.automake.allow.when.app.running不存在内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!   from:https://www.jb51.net/article/223927.htm

Java日志框架SLF4J和log4j以及logback的联系和区别

1.SLF4J(Simple logging Facade for Java) 意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接口方法进行调用即可,由于它只是一个接口,并不是一个具体的可以直接单独使用的日志框架,所以最终日志的格式、记录级别、输出方式等都要通过接口绑定的具体的日志系统来实现,这些具体的日志系统就有log4j,logback,java.util.logging等,它们才实现了具体的日志系统的功能。 如何使用SLF4J? 既然SLF4J只是一个接口,那么实际使用时必须要结合具体的日志系统来使用,我们首先来看SLF4J和各个具体的日志系统进行绑定时的框架原理图: 其实slf4j原理很简单,他只提供一个核心slf4j api(就是slf4j-api.jar包),这个包只有日志的接口,并没有实现,所以如果要使用就得再给它提供一个实现了些接口的日志包,比 如:log4j,common logging,jdk log日志实现包等,但是这些日志实现又不能通过接口直接调用,实现上他们根本就和slf4j-api不一致,因此slf4j又增加了一层来转换各日志实现包的使 用,当然slf4j-simple除外。其结构如下: slf4j-api(接口层)    | 各日志实现包的连接层( slf4j-jdk14, slf4j-log4j)    | 各日志实现包 所以,结合各日志实现包使用时提供的jar包情况为: SLF4J和logback结合使用时需要提供的jar:slf4j-api.jar,logback-classic.jar,logback-core.jar SLF4J和log4j结合使用时需要提供的jar:slf4j-api.jar,slf4j-log412.jar,log4j.jar SLF4J和JDK中java.util.logging结合使用时需要提供的jar:slf4j-api.jar,slf4j-jdk14.jar SLF4J和simple(SLF4J本身提供的一个接口的简单实现)结合使用时需要提供的jar:slf4j-api.jar,slf4j-simple.jar 当然还有其他的日志实现包,以上是经常会使用到的一些。 注意,以上slf4j和各日志实现包结合使用时最好只使用一种结合,不然的话会提示重复绑定日志,并且会导致日志无法输出。 slf4j-api.jar:对外提供统一的日志调用接口,该接口具体提供的调用方式和方法举例说明: public class Test { private static final Logger logger = LoggerFactory.getLogger(Tester.class);  //通过LoggerFactory获取Logger实例 public static void main(String[] args) { //接口里的统一的调用方法,各具体的日志系统都有实现这些方法 logger.info("testlog: {}", "test"); logger.debug("testlog: {}", "test"); logger.error("testlog: {}", "test"); logger.trace("testlog: {}", "test"); logger.warn("testlog: {}", "test"); } } 如果系统中之前已经使用了log4j做日志输出,想使用slf4j作为统一的日志输出,该怎么办呢? 如果之前系统中是单独使用log4j做为日志输出的,这时再想使用slf4j做为日志输出时,如果系统中日志比较多,此时更改日志输出方法肯定是不太现实的,这个时候就可以使用log4j-over-slf4j.jar将使用log4j日志框架输出的日志路由到slf4j上来统一采用slf4j来输出日志。 为什么要使用SLF4J?  slf4j是一个日志接口,自己没有具体实现日志系统,只提供了一组标准的调用api,这样将调用和具体的日志实现分离,使用slf4j后有利于根据自己实际的需求更换具体的日志系统,比如,之前使用的具体的日志系统为log4j,想更换为logback时,只需要删除log4j相关的jar,然后加入logback相关的jar和日志配置文件即可,而不需要改动具体的日志输出方法,试想如果没有采用这种方式,当你的系统中日志输出有成千上万条时,你要更换日志系统将是多么庞大的一项工程。如果你开发的是一个面向公众使用的组件或公共服务模块,那么一定要使用slf4的这种形式,这有利于别人在调用你的模块时保持和他系统中使用统一的日志输出。 slf4j日志输出时可以使用{}占位符,如,logger.info("testlog: {}", "test"),而如果只使用log4j做日志输出时,只能以logger.info("testlog:"+"test")这种形式,前者要比后者在性能上更好,后者采用+连接字符串时就是new 一个String 字符串,在性能上就不如前者。 2.log4j(log for java) Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。 如何使用? 引入jar,使用log4j时需要的jar为:log4j.jar。 定义配置文件log4j.properties或log4j.xml 在具体的类中进行使用: 在需要日志输出的类中加入:private static final Logger logger = Logger.getLogger(Tester.class);  //通过Logger获取Logger实例 在需要输出日志的地方调用相应方法即可:logger.debug(“System […]

我把SpringBoot应用部署到了K8S上,怎么感觉用起来像Docker!

SpringBoot实战电商项目mall(40k+star)地址:github.com/macrozheng/… 摘要 想要把一个复杂的微服务项目部署到K8S上去,首先我们得学会把单个SpringBoot应用部署上去。今天我们来讲下如何把SpringBoot应用部署到K8S上去,和使用Docker Compose部署非常类似,希望对大家有所帮助! 学前准备 学习本文需要有一些K8S基础,对K8S还不了解的朋友可以参考如下的文章。 《K8S太火了!花10分钟玩转它不香么?》 《自从上了K8S,项目更新都不带停机的!》 推送镜像到Docker Hub 之前我们都是自建的镜像仓库,这次我们换种方式,把镜像上传到Docker Hub中去。 首先我们得注册个Docker Hub的账号,Docker Hub地址:hub.docker.com/ 部署应用使用之前的mall-tiny-fabric项目,先修改pom.xml文件,主要是添加Docker Hub的认证信息和修改下镜像前缀,具体内容如下;

  修改完成后使用package命令先把镜像打包到Linux服务器,再使用docker:push命令把镜像推送到Docker Hub中去: 推送成功以后就可以在Docker Hub中看到镜像了。 应用部署 接下来我们将把应用部署到K8S上去,包含SpringBoot应用的部署和MySQL的部署。 部署MySQL 首先添加配置文件mysql-deployment.yaml用于创建Deployment,具体说明参考注释即可;

  通过应用配置文件来创建Deployment;

  运行成功后查询Deployment,发现mysql-deployment已经就绪;

  想要其他Pod可以通过服务名称访问MySQL,需要创建Service,添加配置文件mysql-service.yaml用于创建Service;

  通过应用配置文件来创建Service;

  运行成功后查询Service,发现mysql-service已经暴露在Node的30306端口上了;

  部署完成后需要新建mall数据库,并导入相关表,表地址:github.com/macrozheng/… 这里有个比较简单的方法来导入数据库,通过Navicat创建连接,先配置一个SSH通道; 之后我们就可以像在Linux服务器上访问数据库一样访问Minikube中的数据库了,直接添加Minikube中数据库IP和端口即可。 部署SpringBoot应用 首先添加配置文件mall-tiny-fabric-deployment.yaml用于创建Deployment,这里我们可以通过环境变量来覆盖SpringBoot中的默认配置;

  通过应用配置文件来创建Deployment;

  我们可以通过kubectl logs命令来查看应用的启动日志;

  如果想要从外部访问SpringBoot应用,需要创建Service,添加配置文件mall-tiny-fabric-service.yaml用于创建Service;

  通过应用配置文件来创建Service;

  此时服务已经暴露到了Node的30180端口上了;

  在Linux服务器上,我们可以通过curl命令来访问下项目的Swagger页面,不过只能查看到返回的一串HTML代码。

  外部访问应用 由于使用Minikube安装的K8S Node处于Linux服务器的内网环境,无法直接从外部访问,所以我们需要安装一个Nginx反向代理下才能访问。 首先我们需要安装Nginx,对Nginx不熟悉的朋友直接参考该文章即可:《Nginx的这些妙用,你肯定有不知道的!》 安装完成后添加一个Nginx的配置文件,这里我的配置路径为/mydata/nginx/conf/conf.d/,用于将mall-tiny.macrozheng.com域名的访问代理到K8S中的SpringBoot应用中去,proxy_pass为上面curl使用的路径;

  重启Nginx服务,再修改访问Linux服务器的本机host文件,添加如下记录;

  之后即可直接在本机上访问K8S上的SpringBoot应用了,访问地址:mall-tiny.macrozheng.com/swagger-ui.… 总结 通过把SpringBoot应用部署到K8S上的一顿操作,我们可以发现在K8S上部署和在Docker上部署有很多相似之处。K8S上很多部署用的脚本,直接翻译之前使用Docker Compose的脚本即可,非常类似。如果你之前用过Docker,那么你就可以轻松上手K8S! 项目源码地址 github.com/macrozheng/… 作者:MacroZheng 链接:https://juejin.cn/post/6924462821774196750 […]

java -jar 中文乱码

java -Dfile.encoding=utf-8 -jar demo.jar 添加编码即可   from:https://www.cnblogs.com/provence666/p/10743551.html

kaptcha谷歌验证码工具

Kaptcha 简介 Kaptcha 是一个可高度配置的实用验证码生成工具,可自由配置的选项如: 验证码的字体 验证码字体的大小 验证码字体的字体颜色 验证码内容的范围(数字,字母,中文汉字!) 验证码图片的大小,边框,边框粗细,边框颜色 验证码的干扰线 验证码的样式(鱼眼样式、3D、普通模糊、…) Kaptcha 详细配置表 kaptcha.border 图片边框,合法值:yes , no yes kaptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black kaptcha.image.width 图片宽 200 kaptcha.image.height 图片高 50 kaptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha kaptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator kaptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx kaptcha.textproducer.char.length 验证码长度 5 kaptcha.textproducer.font.names 字体 Arial, Courier kaptcha.textproducer.font.size 字体大小 40px. kaptcha.textproducer.font.color 字体颜色,合法值: r,g,b 或者 white,black,blue. black kaptcha.textproducer.char.space 文字间隔 2 kaptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise kaptcha.noise.color 干扰 颜色,合法值: r,g,b 或者 white,black,blue. black kaptcha.obscurificator.impl 图片样式:<br />水纹 com.google.code.kaptcha.impl.WaterRipple <br /> 鱼眼 com.google.code.kaptcha.impl.FishEyeGimpy <br /> 阴影 com.google.code.kaptcha.impl.ShadowGimpy com.google.code.kaptcha.impl.WaterRipple kaptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground kaptcha.background.clear.from […]

SPRING BOOT——[UNABLE TO START LIVERELOAD SERVER]解决方案

问题描述 在使用SpringBoot 热部署插件 devtools ,同时启动多个Application时,控制台会报这个警告:   问题分析 经查询,发现DevToolsProperties中配置了一个端口,默认是35729。

原因:多个端口冲突了,导致热部署插件不生效。   解决方案 在application.properties文件中加上以下配置

  参考文章 https://blog.csdn.net/xudc0521/article/details/85560221 https://blog.csdn.net/weixin_43852529/article/details/90369869   from:https://www.freesion.com/article/3170268716/

docker部署springboot,并且查看运行日志

docker部署springboot(默认已经安装好docker) 第一步:构建镜像 创建Dockerfile文件,文件内容如下:

  其中 index-1.5.10.RELEASE.jar是你要发布的jar包。 然后把Dockerfile和index-1.5.10.RELEASE.jar建个文件夹,放到服务器上面。 cd进入你的文件夹,运行以下命令向docker中添加镜像:

  执行命令后,你的docker中就添加了名为jingxiangming的镜像。 查看镜像命令:

  第二步:启动容器

  关于上面的命令,我认为有必要具体讲解一下: -d: 后台运行容器,并返回容器ID; -p: 端口映射,格式为:主机(宿主)端口:容器端口;//意思是第一个访问服务器的端口,第二个8080是服务器本地占用访问的端口 jingxiangming:docker里面的镜像名称 当然除了上面基本的参数外,还有额外的参数,这个就需要大家自己去查阅资料了,我这里只列举比较重要的。   启动成功后,会返回一个容器id,然后就可以测试访问了!   日志查看 查看运行的容器日志:

 

  from:https://blog.csdn.net/qq_29611427/article/details/81534037

Linux部署SpringBoot项目jar包,输出日志到文件并追踪

本文小秋熊介绍在Linux中使用命令启动SpringBoot生成的jar包,并且查看日志的方法。 1.首先将SpringBoot项目打包成JAR包,通过xFTP或者其他工具将JAR包上传到Linux上,然后执行如下命令启动项目: java -jar xxx.jar 该命令启动jar,一旦Xshell窗口关闭,JAR就停止运行了. 如果想让项目在后台一直运行,通过如下命令启动JAR: nohup java -jar xxx.jar > consoleMsg.log 2>&1 & 上面的2 和 1 的意思如下: 0 标准输入(一般是键盘) 1 标准输出(一般是显示屏,是用户终端控制台) 2 标准错误(错误信息输出) 注意:consoleMsg.log文件要先创建,执行命令: touch consoleMsg.log 查看项目运行日志: 1、tailf consoleMsg.log | grep --line-buffered findUserList 实时跟踪日志,这里是只要findUserList 这个方法被运行,就会将它的日志打印出来,用于跟踪特定的日志运行。 --line-buffered 是一行的缓冲区,只要这一行的缓冲区满了就会打印出来,所以可以用于实时监控日志。 2、 tailf -n 500 consoleMsg.log 打印最后500行日志,并且持续跟踪日志。 tail -n 2000 consoleMsg.log | less   分页查看最后2000行日志,并可以使用pageUp,pageDn滚动 3、tail -f consoleMsg.log (常用)直接查看日志末尾,有新日志会实时滚动更新。ctrl + c 退出 其它举例: (1)nohup java -jar xxx.jar >/data/log.log 2>/data/err.log & 解释:标准日志输出到/data/log.log文件,错误日志输出到/data/err.log文件。 (2)nohup java -jar xxx.jar >/data/log.log 2>&1 & 解释:标准日志输出到/data/log.log文件,错误日志重定向也输出到/data/log.log文件。 (3)nohup java -jar xxx.jar >/dev/null 2>/data/err.log & 解释:标准日志输出到/dev/null,也就是不输出标准日志,错误日志输出到/data/err.log文件。 一般采用上面(3)只输出错误日志就可以了,有需要的按照(1)、(2)进行输出。 命令后面加的 & ,可让命令在后台执行,否则关闭会话会停止程序。 […]

转载Java NIO中的Files类的使用

Java NIO中的Files类(java.nio.file.Files)提供了多种操作文件系统中文件的方法。 Files.exists() Files.exits()方法用来检查给定的Path在文件系统中是否存在。 在文件系统中创建一个原本不存在的Payh是可行的。例如,你想新建一个目录,那么闲创建对应的Path实例,然后创建目录。 由于Path实例可能指向文件系统中的不存在的路径,所以需要用Files.exists()来确认。 下面是一个使用Files.exists()的示例:

  这个示例中,我们首先创建了一个Path对象,然后利用Files.exists()来检查这个路径是否真实存在。 注意Files.exists()的的第二个参数。他是一个数组,这个参数直接影响到Files.exists()如何确定一个路径是否存在。在本例中,这个数组内包含了LinkOptions.NOFOLLOW_LINKS,表示检测时不包含符号链接文件。 Files.createDirectory() Files.createDirectory()会创建Path表示的路径,下面是一个示例:

  第一行创建了一个Path实例,表示需要创建的目录。接着用try-catch把Files.createDirectory()的调用捕获住。如果创建成功,那么返回值就是新创建的路径。 如果目录已经存在了,那么会抛出java.nio.file.FileAlreadyExistException异常。如果出现其他问题,会抛出一个IOException。比如说,要创建的目录的父目录不存在,那么就会抛出IOException。父目录指的是你要创建的目录所在的位置。也就是新创建的目录的上一级父目录。 Files.copy() Files.copy()方法可以吧一个文件从一个地址复制到另一个位置。例如:

  这个例子当中,首先创建了原文件和目标文件的Path实例。然后把它们作为参数,传递给Files.copy(),接着就会进行文件拷贝。 如果目标文件已经存在,就会抛出java.nio.file.FileAlreadyExistsException异常。类似的吐过中间出错了,也会抛出IOException。 覆盖已经存在的文件(Overwriting Existing Files) copy操作可以强制覆盖已经存在的目标文件。下面是具体的示例:

  注意copy方法的第三个参数,这个参数决定了是否可以覆盖文件。 Files.move() Java NIO的Files类也包含了移动的文件的接口。移动文件和重命名是一样的,但是还会改变文件的目录位置。java.io.File类中的renameTo()方法与之功能是一样的。

  首先创建源路径和目标路径的,原路径指的是需要移动的文件的初始路径,目标路径是指需要移动到的位置。 这里move的第三个参数也允许我们覆盖已有的文件。 Files.delete() Files.delete()方法可以删除一个文件或目录:

  首先创建需要删除的文件的path对象。接着就可以调用delete了。 Files.walkFileTree() Files.walkFileTree()方法具有递归遍历目录的功能。walkFileTree接受一个Path和FileVisitor作为参数。Path对象是需要遍历的目录,FileVistor则会在每次遍历中被调用。 下面先来看一下FileVisitor这个接口的定义:

  FileVisitor需要调用方自行实现,然后作为参数传入walkFileTree().FileVisitor的每个方法会在遍历过程中被调用多次。如果不需要处理每个方法,那么可以继承他的默认实现类SimpleFileVisitor,它将所有的接口做了空实现。 下面看一个walkFileTree()的示例:

  FileVisitor的方法会在不同时机被调用: preVisitDirectory()在访问目录前被调用。postVisitDirectory()在访问后调用。 visitFile()会在整个遍历过程中的每次访问文件都被调用。他不是针对目录的,而是针对文件的。visitFileFailed()调用则是在文件访问失败的时候。例如,当缺少合适的权限或者其他错误。 上述四个方法都返回一个FileVisitResult枚举对象。具体的可选枚举项包括: CONTINUE TERMINATE SKIP_SIBLINGS SKIP_SUBTREE 返回这个枚举值可以让调用方决定文件遍历是否需要继续。 CONTINE表示文件遍历和正常情况下一样继续。 TERMINATE表示文件访问需要终止。 SKIP_SIBLINGS表示文件访问继续,但是不需要访问其他同级文件或目录。 SKIP_SUBTREE表示继续访问,但是不需要访问该目录下的子目录。这个枚举值仅在preVisitDirectory()中返回才有效。如果在另外几个方法中返回,那么会被理解为CONTINE。 Searching For Files 下面看一个例子,我们通过walkFileTree()来寻找一个README.txt文件:

  Deleting Directies Recursively Files.walkFileTree()也可以用来删除一个目录以及内部的所有文件和子目。Files.delete()只用用于删除一个空目录。我们通过遍历目录,然后在visitFile()接口中三次所有文件,最后在postVisitDirectory()内删除目录本身。

    from:https://www.cnblogs.com/liangblog/p/8920579.html

Java NIO系列教程(十 五)Java NIO Path

原文链接  译者:章筱虎 Path接口是java NIO2的一部分。首次在java 7中引入。Path接口在java.nio.file包下,所以全称是java.nio.file.Path。 java中的Path表示文件系统的路径。可以指向文件或文件夹。也有相对路径和绝对路径之分。绝对路径表示从文件系统的根路径到文件或是文件夹的路径。相对路径表示从特定路径下访问指定文件或文件夹的路径。相对路径的概念可能有点迷糊。不用担心,我将在本文的后面详细介绍相关细节。 不要将文件系统的path和操作系统的环境变量path搞混淆。java.nio.file.Path接口和操作系统的path环境变量没有任何关系。 在很多方面,java.nio.file.Path接口和java.io.File有相似性,但也有一些细微的差别。在很多情况下,可以用Path来代替File类。 创建Path实例 为了使用java.nio.file.Path实例,必须首先创建它。可以使用Paths 类的静态方法Paths.get()来产生一个实例。以下是示例:

请注意例子开头的两个import语句。想要使用Paths类和Path接口,必须首先引入相应包。其次,注意Paths.get(“c:\\data\\myfile.txt”)的用法。其使用了Paths.get方法创建了Path的实例。它是一个工厂方法。 创建绝对路径Path 调用传入绝对路径当做参数的Paths.get()工厂方法,就可以生成绝对路径Path。示例如下:

示例中的绝对路径是c:\data\myfile.txt。有两个\字符的原因是第一个\是转义字符,表示紧跟着它的字符需要被转义。\\表示需要向字符串中写入一个\字符。 上文示例的path是windows下的路径。在Unix系统(Linux,MacOS,FreeBSD等)中,上文中的path是这样的:

/home/jakobjenkov/myfile.txt就称作绝对路径。 如果把以/开头path的格式运行在windows系统中,系统会将其解析为相对路径。例如:

将会被解析为路径是在C盘。对应的绝对路径是: C:/home/jakobjenkov/myfile.txt 创建相对路径Path 相对路径指从一个已确定的路径开始到某一文件或文件夹的路径。将确定路径和相对路径拼接起来就是相对路径对应的绝对路径地址。 java NIO Path类也能使用相对路径。可以通过Paths.get(basePath, relativePath)创建一个相对路径Path。示例如下:

第一个例子创建了一个指向d:\data\projects文件夹的实例。第二个例子创建了一个指向 d:\data\projects\a-project\myfile.txt 文件的实例。 当使用相对路径的时候,可以使用如下两种特别的符号。它们是: . .. .表示当前路径。例如,如果以如下方式创建一个相对路径:

创建的Path实例对应的路径就是运行这段代码的项目工程目录。 如果.用在路径中,则其表示的就是当前路径下。示例: Path currentDir = Paths.get(“d:\\data\\projects\.\a-project”); 对应的就是如下路径 d:\data\projects\a-project ..表示父类目录。示例: Path parentDir = Paths.get(“..”); Path对应的路径是当前运行程序目录的上级目录。 如果在path中使用..,表示上级目录的含义。例如:

对应的绝对路径地址为: d:\data\projects\another-project 在a-project目录后面的..符号,将指向的目录修改为projects目录,因此,最终path指向another-project目录。 .和..都可以在Paths.get()的双形参方法中使用。示例:

下面介绍NIO 的Path类有关相对路径的其他使用方法。 Path.normalize() Path 的normalize()方法可以标准化路径。标准化的含义是路径中的.和..都被去掉,指向真正的路径目录地址。下面是Path.normalize()示例:

上文示例,首先创建了一个包含..字符的路径地址。之后输出此路径。 之后,调用normalize方法,返回一个新的path对象。输出新对象的路径。 输出结果如下:

如你所见,标准化后的路径不再包含 a-project\..部分,因为它是多余的。   from:https://ifeve.com/java-nio-path-2/