Spring boot使用logback实现多环境配置

目录

  1. 前言
  2. 引入依赖
  3. 配置项值方案
  4. 外部配置文件方案
  5. springProfile方案
  6. 总结

前言

上一篇文章中老顾介绍了logback基本配置,了解了日志配置的基本方式。我们平时在系统开发时,开发环境与生产环境的日志配置会不一样;那今天老顾就跟大家介绍一下如何实现多环境配置。

Logback是由log4j创始人设计的又一个开源日记组件,Logback 当前分成三个模块:logback-core,logback- classic和logback-accesslogback-core是其它两个模块的基础模块,logback-classic是log4j的一个改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日记的功能

引入依赖

引入logback所需要的依赖

  1. <dependency>
  2. <groupId>ch.qos.logback</groupId>
  3. <artifactId>logback-core</artifactId>
  4. <version>1.1.6</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>ch.qos.logback</groupId>
  8. <artifactId>logback-classic</artifactId>
  9. <version>1.1.6</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.slf4j</groupId>
  13. <artifactId>slf4j-api</artifactId>
  14. <version>1.7.18</version>
  15. </dependency>

如果使用spring-boot,兼容logback,默认已经集成了这些文件,所以就不需要自己依赖注入了,直接在项目中使用就行了。

配置项值方案

利用Spring boot中application.yml的spring.profiles.active

Spring boot使用logback实现多环境配置

 

环境配置,dev开发环境和部署环境连接的数据库地址、debug模式等等都是不同的,为了区分dev开发环境配置和生产环境配置,可以创建两个yml文件,什么环境使用相应的配置文件:

  • application.yml:公共配置文件,里面可以通过spring.profiles.active=dev来指定使用哪个配置文件
  • application-dev.yml:开发环境配置文件
  • application-prod.yml:生产环境配置文件

注意:

1、当公共配置文件application.yml和dev.yml(或prod.yml)同时存在同一个配置的时候,以dev.yml(prod.yml)配置文件为主

2、当配置项只在公共application.yml文件中有的时候,以公共配置为主

3、可以把公共配置项放到application.yml中

我们在看dev.xml和prod.xml配置文件

dev.xml配置

  1. #dev.xml中的配置,用户开发环境
  2. log:
  3. path: /Users/gujiachun/Downloads
  4. level: debug

prod.xml配置

  1. #prod.xml中的配置,用户生产环境
  2. log:
  3. path: /Users/gujiachun/Downloads
  4. level: info

此方案的设计原理就是,不同环境不同的配置值;然后在logback-spring.xml中使用此配置值。

Spring boot使用logback实现多环境配置

 

上图就是logback-spring.xml配置,里面有个重要的就是springProperty标签,可以利用这个标签引用到application.yml中的值(包含dev.xml、prod.xml);log.level和log.path的值就可以在logback-spring.xml中使用,使用方式${logPath}、${logLevel}

 

测试代码

Spring boot使用logback实现多环境配置

 

启动测试,指定spring.profiles.active=dev或prod;我们发现在logPath目录出现对应的日志文件

Spring boot使用logback实现多环境配置

 

因为不同的环境,我们配置成日志级别不一样,dev对应debug,prod对应info;日志文件内容不同环境对应不同内容

dev环境输出

  1. 20200104 10:01:50,298 — debug…
  2. 20200104 10:01:50,298 — info…
  3. 20200104 10:01:50,298 — error…

prod环境输出

  1. 20200104 10:03:55,198 — info…
  2. 20200104 10:03:55,198 — error…

外部配置文件方案

另一种更简单的方式,可以利用logging.config指定配置文件,而且有一个好处可以不一定要取名logback-spring.xml;我们来看一下

application-dev.xml环境

  1. #日志相关配置
  2. logging:
  3. config: classpath:conf/logback-dev.xml

application-prod环境

  1. #日志相关配置
  2. logging:
  3. config: classpath:conf/logback-prd.xml

logback-dev.xml配置

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

logback-prod.xml配置

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

Spring boot使用logback实现多环境配置

 

启动指定spring.profiles.active=dev

在控制台输出了

Spring boot使用logback实现多环境配置

 

而在日志文件

Spring boot使用logback实现多环境配置

 

日志内容

2020-01-04 11:56:10  [39mDEBUG[0;39m 7454  --- [main]  [36mc.r.g.t.LoggerTest[0;39m : debug:.... 

为什么只有debug日志,没有info、error;这个是因为日志文件中加了个过滤器

  1. <filter class=“ch.qos.logback.classic.filter.LevelFilter”>
  2. <level>${logLevel}</level>
  3. <onMatch>ACCEPT</onMatch>
  4. <onMismatch>DENY</onMismatch>
  5. </filter>

此过滤器中的属性onMatch和onMismatch,匹配日志级别就接受,不匹配就不接受。所以只接受debug级别。

启动指定spring.profiles.active=prod

控制台输出

Spring boot使用logback实现多环境配置

 

日志文件

Spring boot使用logback实现多环境配置

 

生成了4个文件,也是因为过滤器,生产环境的日志级别为info,所以debug日志文件里面为空。

springProfile方案

springProfile标签在logback.xml中可以起到区分不同环境分支;如果我们需要配置不同环境,不同的输出方式,如:dev环境输出到控制台以及文件,prod环境只要输出到文件。

logback-spring.xml配置

Spring boot使用logback实现多环境配置

 

这样就可以在同一个配置xml文件中,配置不同的环境值。

无法打开内核设备\\.\global\vmx86

使用vmware的过程中,可能出现很多报错的场景,今天在启动虚拟机的时候,虚拟机发现报错,原因是小编将win7中的虚拟机文件迁移到win10上之后,启动发生报错,此篇经验希望可以帮助到你们

Win 10 无法打开内核设备“\\.\Global\vmx86”

工具/原料

  • vmware
  • win10

方法/步骤

  1. 1

    步骤一:将win7中的vm迁移到win10的vmware中,启动时报错如图

    Win 10 无法打开内核设备“\\.\Global\vmx86”

  2. 2

    步骤二:找到c:\windows\system32\cmd.exe 文件,右击选择以管理员身份运行,进入cmd命令行模式

    Win 10 无法打开内核设备“\\.\Global\vmx86”

  3. 3

    步骤三:输入以下的命令并分别回车

    net start vmci

    net start vmx86

    net start VMnetuserif

    Win 10 无法打开内核设备“\\.\Global\vmx86”

  4. 4

    步骤四:再次启动虚拟机,问题解决

    Win 10 无法打开内核设备“\\.\Global\vmx86”

nginx的几个超时时间

nginx比较强大,可以针对单个域名请求做出单个连接超时的配置.

比如些动态解释和静态解释可以根据业务的需求配置

proxy_connect_timeout :后端服务器连接的超时时间_发起握手等候响应超时时间

proxy_read_timeout:连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)

proxy_send_timeout :后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据

nginx使用proxy模块时,默认的读取超时时间是60s。

 

 

1、请求超时

 

http {
    include       mime.types;
    server_names_hash_bucket_size  512;     
    default_type  application/octet-stream;
    sendfile        on;

    keepalive_timeout  65;  #保持
    tcp_nodelay on;
    client_header_timeout 15;
    client_body_timeout 15;
    send_timeout 25;
    include vhosts/*.conf;
}

复制代码

 

 

2、后端服务器处理请求的时间设置(页面等待服务器响应时间)

location / {
        ...
        proxy_read_timeout 150;  # 秒
        ...
    }

 

 

 

 

 

 

nginx常用的超时配置说明

client_header_timeout

语法 client_header_timeout time
默认值 60s
上下文 http server
说明 指定等待client发送一个请求头的超时时间(例如:GET / HTTP/1.1).仅当在一次read中,没有收到请求头,才会算成超时。如果在超时时间内,client没发送任何东西,nginx返回HTTP状态码408(“Request timed out”)

client_body_timeout 

语法 client_body_timeout time
默认值 60s
上下文 http server location
说明 该指令设置请求体(request body)的读超时时间。仅当在一次readstep中,没有得到请求体,就会设为超时。超时后,nginx返回HTTP状态码408(“Request timed out”)

keepalive_timeout 

语法 keepalive_timeout timeout [ header_timeout ]
默认值 75s
上下文 http server location
说明 *个参数指定了与client的keep-alive连接超时时间。服务器将会在这个时间后关闭连接。可选的第二个参数指定了在响应头Keep-Alive: timeout=time中的time值。这个头能够让一些浏览器主动关闭连接,这样服务器就不必要去关闭连接了。没有这个参数,nginx不会发送Keep-Alive响应头(尽管并不是由这个头来决定连接是否“keep-alive”)
两个参数的值可并不相同

  • 注意不同浏览器怎么处理“keep-alive”头
  • MSIE和Opera忽略掉”Keep-Alive: timeout=<N>” header.
  • MSIE保持连接大约60-65秒,然后发送TCP RST
  • Opera永久保持长连接
  • Mozilla keeps the connection alive for N plus about 1-10 seconds.
  • Konqueror保持长连接N秒

lingering_timeout

语法 lingering_timeout time
默认值 5s
上下文 http server location
说明 lingering_close生效后,在关闭连接前,会检测是否有用户发送的数据到达服务器,如果超过lingering_timeout时间后还没有数据可读,就直接关闭连接;否则,必须在读取完连接缓冲区上的数据并丢弃掉后才会关闭连接。

resolver_timeout

语法 resolver_timeout time
默认值 30s
上下文 http server location
说明 该指令设置DNS解析超时时间

proxy_connect_timeout

语法 proxy_connect_timeout time
默认值 60s
上下文 http server location
说明 该指令设置与upstream server的连接超时时间,有必要记住,这个超时不能超过75秒。
这个不是等待后端返回页面的时间,那是由proxy_read_timeout声明的。如果你的upstream服务器起来了,但是hanging住了(例如,没有足够的线程处理请求,所以把你的请求放到请求池里稍后处理),那么这个声明是没有用的,由于与upstream服务器的连接已经建立了。

proxy_read_timeout

语法 proxy_read_timeout time
默认值 60s
上下文 http server location
说明 该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来获得请求的响应。这个时间不是获得整个response的时间,而是两次reading操作的时间。

proxy_send_timeout

语法 proxy_send_timeout time
默认值 60s
上下文 http server location
说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。如果超时后,upstream没有收到新的数据,nginx会关闭连接

proxy_upstream_fail_timeout(fail_timeout)

语法 server address [fail_timeout=30s]
默认值 10s
上下文 upstream
说明 Upstream模块下 server指令的参数,设置了某一个upstream后端失败了指定次数(max_fails)后,该后端不可操作的时间,默认为10秒

解决IOS无法触发input:file的click事件

当你看到这篇文章的时候,你应该跟我一样也正在为这件事而头疼。

因为,用这种方法完全不能起作用:

html
<div class=”upload”> 上传照片 </div>

<input type=”file” class=”sr-only” id=”inputImage” name=”file” accept=”image/*”>

js:
$(‘.upload’).click(function(){
$(‘#inputImage’).click();

// return $(‘#inputImage’).click();

//以上2种都无效。

})

而写下这篇文章,是因为博主也体会过现在你的心情。

废话打止。下面看正文。

CSS
.upload {
cursor: pointer;

display: block;

width:100px;

height:100px;

line-height:100px;

position: relative;

text-align: center;

overflow: hidden;

}

.sr-only {
position: absolute;

width: 1px;

height: 1px;

padding: 0;

overflow: hidden;

clip: rect(0,0,0,0);

white-space: nowrap;

border: 0;

margin: -1px;

}

HTML
方法一:
<label class=”upload”>
上传照片
<input type=”file” class=”sr-only” id=”inputImage” name=”file” accept=”image/*”>
</label>
方法二:
<input type=”file” class=”sr-only” id=”inputImage” name=”file” accept=”image/*”>
<label class=”btn-image-all” οnclick=”document.querySelector(‘#inputImage’).click()”>替换</label>

没错,就只要这样就能实现了。利用了label标签的特性。

如果有解决你的问题,不妨点个赞个留言吧!!!O(∩_∩)O

初尝iOS开发之用代码添加按钮

今天学习了用代码创建按钮,具体如下

@implementation ViewController

//创建了一个监听事件btnClik:,事件名称是btnClik: 而不是btnClik

-(void)btnClik:(UIButton *)sender

{

NSLog(@”他摸了我”);

 

}

//方法-(void)viewDidLoad是在系统初始化完view后调用的

 

– (void)viewDidLoad

{

[superviewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

//快速创建自定义按钮,

UIButton *button1 = [UIButtonbuttonWithType:UIButtonTypeCustom];

//设置按钮的大小和位置

CGRect huge = CGRectMake(50, 50, 100, 50);

[button1 setFrame:huge ];

//设置按钮在普通状态下的文字

[button1 setTitle:@”别摸我”forState:UIControlStateNormal];

//设置文字在普通状态下的颜色

[button1 setTitleColor:[UIColorredColor] forState:UIControlStateNormal];

//给按钮设置在普通状态下的图片

UIImage *name1 = [UIImageimageNamed:@”sub_black_add.png”];

[button1 setImage:name1 forState:UIControlStateNormal];

//设置文字在高亮状态下的文字

[button1 setTitle:@”就摸你”forState:UIControlStateHighlighted];

//高亮状态下的文字颜色

[button1 setTitleColor:[UIColorgreenColor] forState:UIControlStateHighlighted];

//高亮状态下按钮的图片

UIImage *name2 = [UIImage imageNamed:@”sub_blue_add.png”];

[button1 setImage:name2 forState:UIControlStateHighlighted];

//把按钮添加到view中显示出来

[self.view addSubview:button1];

//给按钮添加一个点击事件

[button1 addTarget:selfaction:@selector(btnClik:) forControlEvents:UIControlEventTouchUpInside];

 

//第二种创建按钮的方法,通过alloc创建

UIButton *button2 =[[UIButton alloc]init];

button2.frame = CGRectMake(100, 100, 200, 50);

[button2 setTitle:@”你喜欢我吗” forState:UIControlStateNormal];

[button2 setTitleColor:[UIColorpurpleColor] forState:UIControlStateNormal];

UIImage *name3 = [UIImageimageNamed:@”sub_black_down.png”];

[button2 setImage:name3 forState:UIControlStateNormal];

[button2 setTitle:@”喜欢”forState:UIControlStateHighlighted];

[button2 setTitleColor:[UIColororangeColor] forState:UIControlStateHighlighted];

UIImage *name4 = [UIImageimageNamed:@”sub_blue_down.png”];

[button2 setImage:name4 forState:UIControlStateHighlighted];

[button2 addTarget:selfaction:@selector(btnClik:) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button2];

}

ios IPad全局禁止横屏设置

开发应用中,如果需要应用禁止横屏,除了在项目的target里设置【去除勾选支持的方向】,还需要勾选Full Screen选项【默认没有勾选,此时需要勾选】,然后在AppDelegate中加入代码:

– (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait;
}

这样才在IPad中真正做到禁止横屏。对于直接在info.plist文件中把Supported interface orientations (iPad)内的子项删除,达到控制应用禁止横屏的设置是不可取的。会导致无法提交应用进行审核。

iOS APP禁止横屏

1、在AppDelegate中增加,这个方法可以禁止横屏

– (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait;
}

2、在targets里边勾选如图三项

%title插图%num

iOS代码修改音量

*近在做一个项目,需要用户在打开APP后,自动将音量调节到某个值,于是研究了一下。
之前做过iOS上声音的研究,苹果对iPhone设备的输入/输出的控制很严格,因为苹果要控制用户体验的一致性。比如:用户将耳机拔下来的时候,苹果认为,用户这时候不希望其他人知道自己在听什么,于是这时候声音会被自动暂停。在音量调整上,苹果也采取了类似的策略。苹果认为,用户不需要APP来为他指定音量,因为这样有时候用户会感到不舒服。苹果的开发文档是这么说的:

You cannot change device volume programatically,however MPVolumeView (volume slider) is there to change device volume but only through user interaction.

苹果提供了一个让用户手动修改音量的方法:MPVolumeView。用户通过拖动slider bar修改音量,就是下面这玩意儿:

%title插图%num
虽然苹果将几乎所有的代码实现控制音量的方法都堵死了,但通过一些私有的方法还是可以修改的。比如,我们遍历一下MPVolumeView的subViews,从中得到UISlider,然后修改slider的value。这种方法虽然可以修改,但访问了私有的类,有被App Store拒*的风险。而且不知道什么时候苹果修改MPVolumeView的结构,这样的方法就不行了。

下面介绍一个可以修改音量的小trick,一个苹果想干掉而没法干掉的方法:

MPMusicPlayerController* musicController = [MPMusicPlayerController applicationMusicPlayer];
musicController.volume = 0.2;
使用之前需要添加MediaPlayer.framework。

为什么说苹果想干掉而没法干掉呢?这个方法是在iOS3.0里添加的,当时估计还没有”不允许使用代码修改音量“这样的规范;后来在7.0的时候,这个方法被depress掉了,说明苹果是想干掉的。但是对于一个持续改进的系统来说,一般都要做向前兼容,否则就会出现像WP6-WP7-WP8这样的悲剧。所以苹果对于去掉一个方法是非常谨慎的,终于还是把这个方法留着了,在它强大的围墙里给开发都留下了一扇窗户。