咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

如果header有下划线,是不转发的,如果一定要下划线,要在配置 http{} 加入 underscores_in_headers on;

参考

如果使用Nginx做反向代理到本地的SpringBoot服务,那么SpringBoot服务获取的远程 地址IP是nginx的,如何获取客户端的IP呢?

有一简单的方法是通过设置一个自定义Header来实现。

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name 127.0.0.1:80;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_pass http://127.0.0.1:8282/api/;
}
}

SpringBoot内获取客户端的真实IP

1
2
3
4
5
6
7
// HttpServletRequest

//这里其实是nginx的IP,则本地。
String nginxIP = request.getRemoteAddr();

//自己设置的自定义Header,为请求clicent端的IP。
String clientIP = request.getHeader("X-Real-IP");

1. 最简单的全局日志

全部server的日志都记录再统计一个log文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
http {

...

##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;


server{
***
}

server{
***
}

...
}

2. server局部日志

每个server单独分配一个log文件,可以避免不同server之间的日志混淆,可以更加清晰的分析日志。

阅读全文 »

本文是对知乎的问答进行感兴趣知识提取,内容太多,以下是不完全提取,阅读原文 传送门

直播Android主播端解决方案

github

他推流用的是 JavaCV 库 ,JavaCV 是一款开源的视觉处理库,基于GPLv2协议,对各种常用计算机视觉库封装后的一组jar包,其中就有ffmpeg,可以直接拿来作为推流用。

视频直播解决方案
Android使用FFMpeg实现推送视频直播流到服务器
如何在网页端和移动端播放Rtmp和hls视频流

阅读全文 »

压缩打包

tar

1
2
3
4
5
6
# 仅打包(不压缩)
$ tar -cvf /tmp/etc.tar /etc
# gzip格式压缩( z参数 .tar.gz 或 .tgz)
$ tar -czvf /tmp/etc.tar.gz /etc
# bzip2格式压缩(j 参数 .tar.bz2)
$ tar -cjvf /tmp/etc.tar.bz2 /etc

zip 打包目录

1
$ zip -r -o -9  test.zip test/
阅读全文 »

https://github.com/judasn/Linux-Tutorial

目录(Contents)

情景

很多文章,很多用户,用户把喜欢的文章添加在账户下,方便查看自己的收藏记录,但是文章不在本地数据库。

一对多

三张表(用户表,收藏文章表,用户-收藏文章的中间表),一个用户对应多个收藏记录,用户实体类维护关系。
一个收藏记录只能被一个用户所添加,所有每次收藏,都要生成新的收藏记录。

缺点:

阅读全文 »

server.xml的Host节点

1
2
<Context path="/demo" docBase="D:\SourceCode\MyEclipse\KevinServlet\WebRoot" reloadable="true" />
<Context path="/example" docBase="D:\SourceCode\MyEclipse\examples" reloadable="true" />

项目地址

文档传送门 ,根据网站底部的说明:
此文档由 docsify 生成
docsify 是一个动态生成文档网站的工具。不同于 GitBook、Hexo 的地方是它不会生成将 .md 转成 .html 文件,所有转换工作都是在运行时进行。

使用教程

其实原理就是将 https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/docs
目录的md文件生成github page ,在index.html引入docsify.js

阅读全文 »

1、首页全局安装gulp

npm install --global gulp

2、其次局部安装gulp

npm install gulp --save-dev

3、安装依赖

阅读全文 »

【Lottie】 是Airbnb开源的一个面向 iOS、Android、React Native 的动画库,能分析 Adobe After Effects 导出的动画,并且能让原生 App 像使用静态素材一样使用这些动画,完美实现动画效果。

android 项目地址:https://github.com/airbnb/lottie-android

1
2
3
dependencies {
implementation 'com.airbnb.android:lottie:4.2.0'
}

本翻译文章原文链接
这篇文章最新的内容在 《向您的项目添加 C 和 C++ 代码》

注:官网上面的技术文章也在不断地汉化中,只是进度有点慢。在我翻译本篇文章的时候,官网没有对应的中文教程。经人提醒,该文章现在在官网已经有对应的中文版教程了,链接地址:向您的项目添加 C 和 C++代码。有需要的朋友可以直接阅读官方中文解说。

———–分割线————-

Android Studio 2.2 正式版发布后,看到更新内容中有提到对 C/C++ 支持的完善,表示非常高兴。然后将官网上这一部分内容翻译出来,如有错误,欢迎指正。
原文链接:Add C and C++ Code to Your Project

使用 Android studio,你可以将 C 和 C++ 代码编译成 native library(即 .so 文件),然后打包到你的 APK 中。你的 Java 代码可以通过 Java Native Interface(JNI)调用 native library 中的方法。

阅读全文 »

Android 上有很多优秀的第三方下载库,功能很强大,如断点续传,异步等。

为了快速下载一个小文件,有时候并不需要牛刀,利用Android自带的 java.net.HttpURLConnection 即可以完成下载,应用场景,比如小的缓存文件,用子线程同步下载即可。

步骤(经典的阻塞输入/输出流读写):

  1. 连接
  2. 获取输入流
  3. 读取buffer写入到本地文件输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MiniFileDownload {

private static final String TAG = "MiniFileDownload";
interface DownloadCallBack{
void onError(Exception e);
void onOK(File file);
void onProgress(float progress);
}
public static void start(String url, File saveFile, DownloadCallBack callBack) {

if(saveFile.exists()){
saveFile.delete();
}
if(callBack == null){
return;
}
HttpURLConnection conn;
try {

//连接URL服务器
conn = (HttpURLConnection)new URL(url).openConnection();
conn.setConnectTimeout(3 * 1000);
conn.setUseCaches(false);
} catch (IOException e) {
e.printStackTrace();
callBack.onError(e);
return;
}

InputStream is = null;
BufferedOutputStream bos = null;
try {

//判断响应码,如果服务器不响应错误,开始下载。
if (conn.getResponseCode() != 200){
Log.e(TAG,"ResponseCode = " + conn.getResponseCode());
return;
}
//获取文件总大小
int contentLength = conn.getContentLength();
Log.d(TAG,"content Length = " + contentLength);
byte[] buffer = new byte[1024];
int offset = 0 ;
int len;

//本地文件输出流
bos = new BufferedOutputStream( new FileOutputStream(saveFile) );

//获取输入流
is = conn.getInputStream();
//循环读(下载)
while ((len = is.read(buffer)) != -1) {

Log.d(TAG,"read buffer len = " + len);
bos.write(buffer, 0, len);
offset += len;
Log.d(TAG,"offset = " + offset + " ;total=" + contentLength);
//计算进度
float progress = (float)offset / (float)contentLength;
Log.d(TAG,"progress = " + progress);
//更新进度到回调,UI层可以显示下载进度
callBack.onProgress(progress);
}
Log.d(TAG,"ok");
callBack.onOK(saveFile);
} catch (IOException e) {
e.printStackTrace();
callBack.onError(e);
}finally {

//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if(bos != null){
try {
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
conn.disconnect();
}
}

}

GridLayoutManager 很少用,所以它的Decoration用法这里做一下备忘。

  • 主要记住行、列的计算,第一行、最后一行、第一列、最后一列的计算。
  • Item的布局要用 match_parent 采用自动适应的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class TestGridDecoration extends RecyclerView.ItemDecoration{

private int offset;

public TestGridDecoration(int offset) {
this.offset = offset;
}

@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);

int childLayoutPosition = parent.getChildLayoutPosition(view);

//每行的元素数量
int spanCount = ((GridLayoutManager)parent.getLayoutManager()).getSpanCount();

//总行数
int maxRow = state.getItemCount() / spanCount;
//所处的行号
int row = childLayoutPosition / spanCount;
//所处的列号
int column = childLayoutPosition % spanCount;


if(row == 0){
//第一行
outRect.top = 0;
outRect.bottom = 0;
}else if(row == maxRow){
//最后一行
outRect.top = offset;
outRect.bottom = offset;
}else{
//中间行
outRect.top = offset;
outRect.bottom = 0;
}


if(column == 0){
//第一列
outRect.left = offset;
outRect.right = offset / 2;
}else if(column == spanCount - 1){
//最后一列
outRect.left = offset / 2;
outRect.right = offset;
}else{
//中间列
outRect.left = offset / 2;
outRect.right = offset / 2;
}

}
}