咸鱼

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

0%

1. 在应用商店安装Windows Terminal

安装完成之后,启动Windows Terminal,在Windows Terminal内完成一些软件安装。

2. 允许powershell执行脚本

1
$ Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

3. 安装posh-git和oh-my-posh

阅读全文 »

开发Android IOT平台应用要用到串口,但硬件往往慢一拍,我们为了快速调试,可以使用模拟串口来解决问题。

本文最终实现:PC端口串口和Genymotion模拟器串口进行通信。

安装模拟工具

在Windows平台下安装 串口模拟工具-VSP 新建一对串口模拟COM1和COM2。
创建
选择pair
命名串口
启动串口模拟

配置Genymotion模拟器

阅读全文 »

用Android Studio 3.5创建了JKS证书,提示以下警告:

1
JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore D:\demo\project\app\key.jks -destkeystore D:\demo\project\app\key.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。

按照上面的提示,执行命令:

1
2
3
4
5
6
7
8
$ keytool -importkeystore -srckeystore D:\\demo\\project\\app\\key.jks -destkeystore D:\\demo\\project\\app\\key.jks -deststoretype pkcs12

输入源密钥库口令:
已成功导入别名 myapp 的条目。
已完成导入命令: 1 个条目成功导入, 0 个条目失败或取消
Warning:
已将 "D:\demo\project\app\key.jks" 迁移到 Non JKS/JCEKS。将 JKS 密钥库作为 "D:\demo\project\app\key.j
ks.old" 进行了备份。

/drawable/start.xml

1
2
3
4
5
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/img1" android:duration="200" />
<item android:drawable="@drawable/img2" android:duration="100" />
</animation-list>

android:oneshot=”false” 表示一直播放(循环)

设置为background

1
2
3
4
5
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/start" />
阅读全文 »

startActivityForResult过期

一直都是这样启动一个带返回结果的Activity

1
2
3
4
5
6
7
8
val intent = Intent(this, VideoPlaybackListPPCSActivity::class.java).apply {
this.putExtra("data",111)
}

// 此方法已过期
// Deprecated
// use registerForActivityResult(ActivityResultContract, ActivityResultCallback) passing in a androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult object for the ActivityResultContract.
startActivityForResult(intent,10090)

使用registerForActivityResult跳转

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
//初始化不能在按键事件等地方执行,建议在onCreate执行
val launcher = registerForActivityResult(object: ActivityResultContract<String,String>(){
override fun createIntent(context: Context, input: String?): Intent {

return Intent(this@VideoPlayerPPCSActivity, VideoPlaybackListPPCSActivity::class.java).apply{
intent.extras?.let { ext ->
ext.putInt("session",remoteCamera.getSession())
this.putExtras(ext)
}
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String {

//解析Intent中的数据,返回给onActivityResult
//这里不需要数据
return "ok"
}
},object: ActivityResultCallback<String>{
override fun onActivityResult(result: String?) {

//拿到数据
}
})


// 需要跳转时,这样执行
val intent = Intent(this, VideoPlaybackListPPCSActivity::class.java).apply {
this.putExtra("data",111)
}
launcher.launch(intent)
阅读全文 »

请尽量使用:NotificationCompat 及其子类,以及 NotificationManagerCompat。
这样一来,您就无需编写条件代码来检查 API 级别,因为这些 API 会为您代劳。
但是要注意 NotificationManagerCompat 不能创建Android8.0以上所需要的Channel,创建Channel还是需要用NotificationManager。

简单的一个通知

1
2
3
4
5
6
7
8
9
10
11
String channelId = "news";
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(),
channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("测试Title")
.setContentText("一些简单的内容!!!");

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());

int notifyId = 123;
notificationManager.notify(notifyId, builder.build());

但这个通知在Android8.0不能发出去,因为8.0规定必须将单个通知放入特定Channel中。

阅读全文 »

2020年3月17日 JDK 14 发布,非 LTS 版本。

新特性: http://openjdk.java.net/projects/jdk/14/

  • 305: Pattern Matching for instanceof (Preview)
  • 343: Packaging Tool (Incubator)
  • 345: NUMA-Aware Memory Allocation for G1
  • 349: JFR Event Streaming
  • 352: Non-Volatile Mapped Byte Buffers
  • 358: Helpful NullPointerExceptions
  • 359: Records (Preview)
  • 361: Switch Expressions (Standard)
  • 362: Deprecate the Solaris and SPARC Ports
  • 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
  • 364: ZGC on macOS
  • 365: ZGC on Windows
  • 366: Deprecate the ParallelScavenge + SerialOld GC Combination
  • 367: Remove the Pack200 Tools and API
  • 368: Text Blocks (Second Preview)
  • 370: Foreign-Memory Access API (Incubator)

中文

  • 305: instanceof的模式匹配 (预览)
  • 343: 打包工具 (Incubator)
  • 345: G1的NUMA内存分配优化
  • 349: JFR事件流
  • 352: 非原子性的字节缓冲区映射
  • 358: 友好的空指针异常
  • 359: Records (预览)
  • 361: Switch表达式扩展 (标准)
  • 362: 弃用Solaris和SPARC端口
  • 363: 移除CMS(Concurrent Mark Sweep)垃圾收集器
  • 364: macOS系统上的ZGC
  • 365: Windows系统上的ZGC
  • 366: 弃用ParallelScavenge + SerialOld GC组合
  • 367: 移除Pack200 Tools和API
  • 368: 文本块 (第二个预览版)
  • 370: 外部存储器API (Incubator)
阅读全文 »

记录通过命令行备份和恢复的过程

本地备份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ mongo
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
> show dbs
admin 0.000GB
mshop 0.000GB
jeel 0.001GB
local 0.000GB
home 0.001GB
pymongo_test 0.000GB
> exit
bye
$ mongodump -h localhost -d mshop -o ./
$ mongodump -h localhost -d pymongo_test -o ./
$ ls
mshop pymongo_test

这里备份了两个数据库,分别在两个目录下。

这里是将两个目录迁移到另外一个服务器,执行以下操作:

阅读全文 »

忘记管理员密码对于创建数据库等操作会有影响,本文基于Mongo v3.4.10将做一次处理这个问题的示例,整体方向就是删除所有的管理员用户,重新创建。

  1. 关闭mongod的认证

    1
    2
    #security:
    # authorization: enabled
  2. 重启mongod

    1
    $ service mongod restart
  3. 登录mongo命令行,删除所有admim数据库中的账号

    1
    2
    3
    4
    $ mongo
    > use admin
    > db.system.users.find()
    > db.system.users.remove({})
  4. 创建超级管理员root

    1
    > db.createUser({user:'root',pwd:'123456',roles:[{"role":"root","db":"admin"}]})
  5. 验证root密码

    1
    > db.auth('root','123456')
  6. 创建一个示例数据库:testdb

    1
    > use testdb
  7. 为示例数据库:testdb 创建一个可读写的用户

    1
    > db.createUser({user:'testuser',pwd:'123456',roles:[{"role":"readWrite","db":"testdb"}]})
  8. 认证

    1
    > db.auth('testuser','123456')
  9. 在testdb的col(collection)插入一条数据(不然不会创建数据库)

    1
    > db.col.insert({'test':'123'})
  10. 开启认证
    去掉注释,重启mongod

    1
    security:authorization: enabled
  11. 与mongo同一台机器安装adminMongo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    $ git clone https://github.com/mrvautin/adminMongo.git
    $ cd adminMongo
    $ npm install
    $ vim /config/app.json
    {
    "app": {
    "host": "0.0.0.0",
    "port": 4321,
    "docs_per_page": 20,
    "password": "adm123",
    "locale": "en",
    "context": "dbApp",
    "monitoring": true
    }
    }
    $ npm start
  12. IP:port 访问adminMongo,密码是app.json中设置的密码

  13. adminMongo 用超级用户创建连接

    1
    mongodb://root:123456@127.0.0.1:27017
  14. 在adminMongo中试一下创建数据库,为数据库创建用户等操作,完成。

Android原版系统,连接的WiFi是正常的,但显示“不可访问互联网”,应该检查某个域名发现无法访问。
如果觉得看着别扭,可以通过以下命令修复,给它改一个域名来检查。

1
2
3
4
adb shell settings put global captive_portal_use_https 1
adb shell settings put global captive_portal_http_url http://204.ustclug.org
adb shell settings put global captive_portal_https_url https://204.ustclug.org
adb shell settings put global captive_portal_mode 0

最后重启手机就没有显示“不可访问互联网”啦!

fastboot常用命令

1
2
3
4
5
6
7
8
9
10
11
# 解锁
$ fastboot flashing unlock

# 重启
$ fastboot reboot

# 刷入recovery
$ fastboot flash recovery recovery.img

# 启动临时recovery
$ fastboot boot recovery.img

Pixel解Bootloader锁

想要刷ROM,解BL锁时第一步:

  1. 在Android系统设置选项的开发者中,打开调试模式,打开OEM解锁,连接数据线。
  2. 关机
  3. 长按 “音量-“ + “电源”按键,进入Bootloader
  4. fastboot flashing unlock命令解锁 (需要有platform-tools才能运行fastboot)
  5. 如果成功就重启 fastboot reboot
阅读全文 »

Genymotion模拟器下载的虚拟机默认是在C盘,如果要修改虚拟机的路径,在设置里修改即可,但是先存的虚拟机genymotion不会帮你移动。

我们手动移动虚拟机,比如移动到D盘,那这些的虚拟机都失效了,Genymotion并不支持导入。

修改 C:\Users\用户名.VirtualBox\VirtualBox.xml 文件 :

1
2
3
4
5
6
<MachineRegistry>
<MachineEntry uuid="{a9a20fe7-dc69-4869-8f8b-1feff2485745}" src="D:\GenymotionDevice\Google Pixel - 9.0\Google Pixel - 9.0.vbox"/>

<MachineEntry uuid="{a9a20fe7-dc69-4869-8f8b-1feff2485745}" src="D:\GenymotionDevice\Google Pixel - 8.0\Google Pixel - 8.0.vbox"/>

</MachineRegistry>

将路径改正确即可,如果不小心删掉了,也可以在xml里面增加一个item,按照他的格式来写,其中uuid在虚拟机的vbox文件里面可以找到。

阅读全文 »

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

public class UDPSearch{

private final String TAG = this.getClass().getSimpleName();
private final Object mLock;
private DatagramSocket socket = null;
private UDPCallback callback;
private Thread threadReceive,threadSend;

public UDPSearch(UDPCallback callback) {
this.callback = callback;
this.mLock = new Object();
}


public void start(){

threadReceive = new Thread(new UDPReceive());
threadSend = new Thread(new UDPSend());

threadReceive.start();
threadSend.start();
}
public void stop(){

if(threadSend != null){
threadSend.interrupt();
threadSend = null;
}
if(threadReceive != null){
threadReceive.interrupt();
threadReceive = null;
}
}


class UDPSend implements Runnable{

private final String TAG = this.getClass().getSimpleName();
private final int BROADCAST_PORT = 6666;
private final String BROADCAST_HOST = "255.255.255.255";
private final byte[] broadcastData = new byte[]{ 0x01 ,0x02, 0x03 ,0x04 };

@Override
public void run() {

Log.i(TAG,"run start");

try {

TimeUnit.SECONDS.sleep(2);
InetAddress inetAddress = InetAddress.getByName(BROADCAST_HOST);
socket = new DatagramSocket();
socket.setBroadcast(true);

Log.d(TAG, "create udp socket target port:" + socket.getPort() + " and local port : " + socket.getLocalPort());
//socket已创建,通知线程接收数据
synchronized (mLock){
mLock.notify();
Log.i(TAG, "notify create socket ok");
}
while (!Thread.currentThread().isInterrupted()) {
Log.d(TAG,"send udp broadcast target port: " + BROADCAST_PORT);
try{
socket.send(new DatagramPacket(broadcastData, broadcastData.length,
inetAddress, BROADCAST_PORT));
}catch (IOException io){
// 这种错误不应该结束发送广播,系统网络关闭可以复现。
// java.io.IOException: sendto failed: ENETUNREACH (Network is unreachable)
// Caused by: android.system.ErrnoException: sendto failed: ENETUNREACH (Network is unreachable)
io.printStackTrace();
}
TimeUnit.SECONDS.sleep(2);
}
} catch (InterruptedException | UnknownHostException | SocketException e) {
e.printStackTrace();
}finally {
Log.i(TAG,"socket close");
if(socket != null){
socket.close();
socket = null;
}
}
Log.i(TAG,"stop");
}
}


class UDPReceive implements Runnable{

private final String TAG = this.getClass().getSimpleName();

@Override
public void run() {

Log.i(TAG,"run start");
if(socket == null){
try {
Log.w(TAG,"socket not init, wait mLock.");
synchronized (mLock){
mLock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.i(TAG, "stop wait mLock");
while (socket != null && !Thread.currentThread().isInterrupted()) {
try {
final int len = 256;
DatagramPacket datagramPacket = new DatagramPacket(new byte[len], len);
Log.i(TAG, "receive data block");
socket.receive(datagramPacket);
Log.i(TAG, "receive data size = " + datagramPacket.getLength());
callback.onReceivePacket(datagramPacket.getData(), datagramPacket.getLength());
} catch (IOException e) {
e.printStackTrace();
}
}
Log.i(TAG,"stop");
}
}


}

1
2
3
public interface UDPCallback {
void onReceivePacket(byte[] data, int len);
}

签名的指纹在对接一些平台会用到,如微信,高德等。

很久没用,忘记了,这里记录一下,方便以后使用

命令

1
$ keytool -list -v -keystore 签名文件

Debug默认的签名

阅读全文 »

为了方便复习redis的数据类型,根据网络文章整理一份。

一、Redis 字符串(String)

字符串类型是最基础的类型,在redis里面字符串可以存储3中类型的值,字节串、整数、浮点数。
这里整数或者浮点数是可以执行自增或自减的。
使用场景:

  1. 计数
  2. 分布式锁
  3. 缓存数据

二、Redis 列表(List)

阅读全文 »

Spring3支持JSR-303验证框架,JSR-303 是Java EE 6 中的一项子规范,叫做BeanValidation,官方参考实现是hibernate Validator(与Hibernate ORM 没有关系),JSR 303 用于对Java Bean 中的字段的值进行验证。

1. 表单属性

1
2
3
4
5
6
@Data
public class User {

@NotBlank(message = "name不能为空")
private String name;
}

2. Controller中开启验证

1
2
3
4
5
6
7
import org.springframework.validation.annotation.Validated;

@PostMapping("/register")
public ResponseEntity<Void> register(@Validated User user) {

return ResponseEntity.noContent().build();
}
阅读全文 »

在VM虚拟机中NAT网络转为桥接,客户机CentOS则要改为静态IP,下面是操作日志。

ens33是默认的网卡,我们就修改这个网卡。
修改内容

  1. 设置一个静态IP、网关
  2. 启动IPV4,关闭IPV6
1
2
3
4
5
6
7
# 图形编辑
$ nmtui edit ens33

# 等同于编辑文件
$ vi /etc/sysconfig/network-scripts/ifcfg-ens33

$ service network restart

nmtui edit ens33

阅读全文 »

卸载

CentOS会自带OpenJDK,卸载自带的OpenJDK,再安装我们需要的版本

1
2
3
4
5
6
7
8
9
$ rpm -qa | grep jdk

java-11-openjdk-headless-11.0.4.11-1.el7_7.x86_64
java-1.8.0-openjdk-headless-1.8.0.222.b10-0.el7_6.x86_64
copy-jdk-configs-3.3-10.el7_5.noarch

$ rpm -e --nodeps java-1.8.0-openjdk-headless-1.8.0.222.b10-0.el7_6.x86_64
$ rpm -e --nodeps java-11-openjdk-headless-11.0.4.11-1.el7_7.x86_64
$ rpm -e --nodeps copy-jdk-configs-3.3-10.el7_5.noarch

搜索

1
$ yum search openjdk | grep -i --color openjdk
阅读全文 »

Ubuntu 默认的Gnome桌面有很酷炫的动画,在GUI没有找到关闭动画的设置。

为了省资源,可以通过以下指令控制桌面动画的开关。

1
$ gsettings set org.gnome.desktop.interface enable-animations false