在Java中如何实现调用命令行

首先申明,不推荐使用此方式,我了解到的情况如下:执行过程是首先克隆一条和当前虚拟机拥有一样环境变量的进程,再用这个新的进程执行外部命令,最后退出这个进程。因此,频繁的创建对CPU和内存的消耗很大
基础代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* run command with one command
*
* @param command command
* @return command out
*/
public static String run(String command) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("bash", "-c", command);
String out = "";
try {
log.info(String.join(" ", processBuilder.command()));
Process process = processBuilder.start();
out = IOUtils.toString(process.getInputStream());
} catch (IOException e) {
log.error("run command error {}", e.getMessage());
e.printStackTrace();
}
return out;
}

需要考虑的问题

  1. 异常数据的输出,是否监控,以及如何监控,之前的做法是新启动一个线程去监听
  2. 使用此方法时,性能会有较大的损耗,如何改善,考虑去除所有监控进行性能对比
  3. 在执行命令出现异常时的异常处理如何。
    以上几点我会在后续的编码中考虑解决,可以关注我的github的demo项目 Git地址

注意事项

  1. 命令无权限
    考虑文件的可执行权限
  2. 等待shell返回
    在process.waitFor()前读取缓冲区
  3. 命令不存在
    需要将你的程序在bin下添加软链接
    以上参考了https://yq.aliyun.com/articles/2362 感谢

SpringCloud Zuul网关在Filter中添加或修改Request参数

使用目的

在网关中经常会处理一些Token或者鉴权信息,在处理完后,将Token处理后,把用户信息放到Request中,方便后续系统的时候。我这次使用的场景有些特别,由于项目需要兼容用户使用RequestBody 传递JSON参数,但是由于当前系统没有对RequestBody做兼容,导致数据获取不到,因此在Zuul中把参数处理完成后传递给后面的应用。

使用环境

1
2
3
4
5
6
7
8
   <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>

<spring-cloud.version>Dalston.SR2</spring-cloud.version>
阅读全文 »

SpringBoot项目中MultipartFile接受数据文件乱码原因

MultipartFile 在接收数据时会以系统默认的编码解码上传数据,如果系统默认的编码和页面编码不一致就会乱码。乱码其实就是当接收方和发送方的编码不一致就会出现。

单个SpringBoot项目解决方案

  1. 修改配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    spring:
    http:
    encoding:
    charset: UTF-8
    force: true
    enabled: true
    server:
    tomcat:
    uri-encoding: UTF-8
  1. 添加配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Configuration
    public class ConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Bean
    public HttpMessageConverter<String> responseBodyConverter() {
    StringHttpMessageConverter converter = new StringHttpMessageConverter(
    Charset.forName("UTF-8"));
    return converter;
    }

    @Override
    public void configureMessageConverters(
    List<HttpMessageConverter<?>> converters) {
    super.configureMessageConverters(converters);
    converters.add(responseBodyConverter());
    }

    @Override
    public void configureContentNegotiation(
    ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false);
    }
    }
  1. 获取文件名时添加编码转换

SpringCloud(使用Zuul做网关项目)解决方案

在使用上面几步都解决不了的情况下,你最需要考虑下你当前项目的请求流程,此处提供对zuul组件上传文件乱码的解决方案。
官网说明:

18.8 Uploading Files through Zuul
If you use @EnableZuulProxy, you can use the proxy paths to upload files and it should work, so long as the files are small. For large files there is an alternative path that bypasses the Spring DispatcherServlet (to avoid multipart processing) in “/zuul/*”. In other words, if you have zuul.routes.customers=/customers/*, then you can POST large files to /zuul/customers/. The servlet path is externalized via zuul.servletPath. If the proxy route takes you through a Ribbon load balancer, extremely large files also require elevated timeout settings, as shown in the following example:

1
2
3
4
5
6
application.yml

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 60000

Note that, for streaming to work with large files, you need to use chunked encoding in the request (which some browsers do not do by default), as shown in the following example:

1
2
$ curl -v -H "Transfer-Encoding: chunked" \
-F "[email protected]" localhost:9999/zuul/simple/file

zuul uploading files

1
2
3
4
5
/**
* Path to install Zuul as a servlet (not part of Spring MVC). The servlet is more
* memory efficient for requests with large bodies, e.g. file uploads.
*/
private String servletPath = "/zuul";

按照官网说明,可以将请求发送到/zuul/项目原转发路径/*,但是一般项目后期,如果要修改请求路径较为复杂。这里可以将所有请求都走此过滤。设置如下:

1
2
zuul:
servlet-path: /

A public key infrastructure (PKI) is a set of roles, policies, and procedures needed to create, manage, distribute, use, store & revoke digital certificates and manage public-key encryption. The purpose of a PKI is to facilitate the secure electronic transfer of information for a range of network activities such as e-commerce, internet banking and confidential email. It is required for activities where simple passwords are an inadequate authentication method and more rigorous proof is required to confirm the identity of the parties involved in the communication and to validate the information being transferred.
一个公共密钥基础设施PKI)是一组角色,策略,以及创建,管理,分发所需的程序,使用,储存和吊销的数字证书和管理公共密钥加密。PKI的目的是促进电子商务,网上银行和机密电子邮件等一系列网络活动的信息安全电子传输。对于简单密码认证方法不充分的活动,需要更严格的证据来确认通信中涉及的各方的身份并验证所传输的信息。

上文为WIKI对于PKI的解释,简单来说,PKI是一个基础设施,使用数字证书、密钥加密等措施来保障通信中的信息安全和身份安全。从我个人浅显的理解来说,PKI就是解决如何证明我是我、如何保证我传给A的东西其他人看不到只有A能看,而且A还能确信这是我发的。

PKI由什么组成

设备的派出所——CA

加密中证书颁发机构证书颁发机构CA)是颁发数字证书的实体。数字证书通过证书的指定主题来证明公钥的所有权。这允许其他人(依赖方)依赖签名或关于与经认证的公钥对应的私钥的断言。CA充当受信任的第三方 -由证书的主体(所有者)和依赖证书的一方进行信任。这些证书的格式由X.509标准指定。

和PKI的定义一样,它是一个基础设施,为了解决我是我的问题,引入了数字证书的概念,数字证书包括有关密钥的信息,有关其所有者身份的信息(称为主题),以及已验证证书内容的实体(称为发行者)的数字签名,在我看来这就相当于现实生活中的派出所,给你颁发了一个身份证,上面有你的个人信息(所有者身份的信息),也标上是哪个派出所发的,并且做了防伪(发行者的数字签名),这样在后续和其他设备交互的时候,你就可以使用数字证书去证明你是你了。

设备的户籍查询窗口——RA

确保有效和正确注册的PKI角色称为注册机构(RA)。RA负责接受对数字证书的请求并对发出请求的实体进行身份验证。

说是户籍查询窗口并不准确,在拥有RA的PKI系统中,RA作为一个和外界交互的主要通道,负责证书的申请、审批等。在PKI体系中也可以没有RA部分,直接使用SCEP进行申请服务(仅代表我所遇到的情况,如有补充欢迎评论)

记录着不可用证书的派出所——VA

公钥基础结构中验证机构VA)是一个实体,它根据X.509标准和RFC 5280(第69页)中描述的机制提供用于验证数字证书有效性的服务。[1]
用于此目的的主要方法是托管证书吊销列表,以便通过HTTPLDAP协议下载。为了减少证书验证所需的网络流量,可以使用OCSP协议。
虽然验证机构能够响应基于网络的CRL请求,但它缺乏颁发或吊销证书的能力。必须使用颁发CRL中包含的证书的证书颁发机构的当前CRL信息不断更新它。
虽然这是一个潜在的劳动密集型过程,但使用专用的验证机构可以动态验证脱机根证书颁发机构颁发的证书。虽然根CA本身对网络流量不可用,但始终可以通过验证机构和上述协议验证由其颁发的证书。
维护验证机构托管的CRL的持续管理开销通常很小,因为根CA颁发(或撤销)大量证书的情况并不常见。

这部分我了解不多,现阶段我所遇到的场景更多为内置脱机根证书并且使用OCSP方式查询,简单来说,VA就是为了避免出现:你的身份证被派出所取消了,我还傻傻的相信你这一情况。

本章主要是介绍PKI是什么,解决了什么问题,有哪些组成部分。后续会继续更新PKI相关的一些文章,比如SCEP是什么,OCSP,CRL又是什么,以及PKI相关技术在JAVA中的实现。

在Spring Boot2.0中集成Quartz

考虑到业务中需要对任务进行实时修改,因此本文的配置方式可能较为复杂
如果是想了解事务为何不生效的,先告诉结论:将Job中的RUN方法,提取成一个Class的方法,并在此方法上加@Transactional,在job.run中调用。具体原因请参考下文

以Spring Boot2.19版本为例,添加POM依赖:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

父项目为Spring Boot

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
阅读全文 »
0%