人工智能:助手还是替代者?

摘要

本文探讨了人工智能(AI)的概念、应用范围以及它对人类工作和社会关系的潜在影响。通过分析AI的当前能力与局限,本文旨在提供一个全面的视角,以理解AI如何与人类协作,而非简单地替代我们。

什么是AI?

人工智能(Artificial Intelligence,简称AI)是指由人造系统所表现出来的智能行为。它是计算机科学的一个分支,旨在创建能够执行通常需要人类智能的任务的机器和软件。
人工智能的核心目标是模拟、延伸和扩展人类智能。它通过研究、开发用于模拟人类认知任务的理论、方法、技术及应用系统来实现这一目标。这些任务包括感知、理解、学习、推理和行动等。

能干什么?

AI使用范围很广,工作、生活、娱乐方方面面都可以用到,下面以一个简单的生活场景举例:

没有AI前

以前面对不懂或者不会的东西可能需要网上搜索或者问他人,但是这些都有弊端。网上的信息太庞杂,很多时候搜索出来的信息筛选也需要很大的功夫,如果没有好的搜索技巧和判断能力费力不讨好;而问其他人,一次两次还好,如果次数太多可能别人也会烦,自己也会觉得不好意思,不会的还是不会。

有了AI后

使用AI可以让上述事情变得很简单,如果有不懂的问题我们可以直接去问AI,如果没看明白我们可以让它给出详细的解释,如此反复直到你弄明白。是不是感觉很棒。

如何使用?

截至目前AI工具已经很多,无法一一列举,按照目前我经常使用的主要是ChatGPT,KimiAI,秘塔搜索等,这些网站都做的很直观点进去就会用,主要是要动起来。可以用来帮忙整理excel表格,做文本转换,做翻译,生成一份报告,只要你有想法都可以让他试着实现。

能否替代人类?

用多了以后你就会发现AI真的很强,作为一个开发人员,有时候我就会想AI是否会让我停止思考,进而替代我的工作。

个人觉得人类有很多方面是目前AI无法理解的,比如情感,社会关系等。很多工作生活其实是情感、社会关系、独立思考等各种能力参与才能实现,这些场景目前的AI无法替代。但是有些简单的工作比如上述说的做一些文本转换,生成一些简单的文章,做一些excel表格等,AI完全可以胜任。如果是日复一日只从事上述工作的人员,很容易被AI替代。

开发人员是否会被AI替代? 现在有很多AI编程工具,只要你能把场景描述清楚,它就可以迅速实现代码,这时候不免担心这么下去是否会被淘汰。其实仔细想想目前是不可能的,开发工作本身涉及面也很广,不是简单的CRUD,需要对业务的了解,跟其他人员的沟通交流,系统架构的设计,所以纯粹AI目前是无法完全替代开发人员的。但是我们可以充分利用AI,他就像一个刚入行的新人,需要你把业务给他说明白,只要他来完成一些简单的代码模块(业务简单,算法相关),这样可以极大的增加我们的工作效率。代码写完以后我们又可以把AI作为一个仔细的老师,帮我们检查下代码漏洞,留出时间摸鱼很香。

如果太依赖AI会不会让自己的能力降低? 这个担心一点不多余,可能很多时候老师都告诉我们要自己先思考,不明白了再去问人,这就是要锻炼我们独立思考能力。但是有了AI肯能会让我们养成惰性,直接上来就问,这个习惯可不好,会让我们变成一个缺乏独立思考的zz。所以个人觉得对于自己成长(money)有帮助的事情,首先还是要自己先去思考去实现,简单的、重复很多次的事情可以偶尔交给AI去完成,保持我们的敏感度。对于开发人员来说,技术就是根本,这个如果只想着靠AI去喂,趁早转行吧,但是写ppt了啥的很讨厌,让AI这个”新人”去搞很合理。

结论

AI是一个强大的工具,可以作为我们的助手,提高工作效率。然而,它不应该成为我们思考和创造的替代品。真正的专业人士会利用AI来扩展自己的能力,而不是被其替代。

互动环节

所以,您觉得我们最终是否会被AI替代? 欢迎在评论区分享您的看法。

在日常工作和生活中使用Linux-开篇

前言

欢迎来到《在日常工作和生活中使用Linux》的系列分享。在这个系列中,我们将探讨为什么选择Linux,以及如何在日常工作和生活中高效地使用它。无论你是刚刚接触Linux的新手,还是希望深入了解高级应用的老手,我们都希望这个系列能为你提供有用的指导和灵感。

为什么选择Linux?

  • 开放源代码:Linux是开源的,这意味着你可以自由地查看、修改和分发它的源代码(科普用,使用来说爱咋咋)。
  • 灵活性:你可以根据自己的需求定制Linux,从桌面环境到系统工具,应有尽有(这个我最喜欢)。
  • 系统占用: 对于老旧的pc系统占用很重要,相比win开机至少4g来说,linux选择太多了,linux又快又猛。

适用场景

  • 开发和编程:Linux支持多种编程语言和开发工具,是开发人员的理想选择。
  • 日常办公:办公软件、邮件客户端、浏览器等应有尽有,完全可以满足日常办公需求。
  • 多媒体娱乐:还是用win吧,这方面linux差得原。

预期读者群体

  • Linux新手:刚开始接触Linux,希望学习基本操作和配置。
  • 开发人员:希望搭建和优化开发环境,提高开发效率。
  • 系统管理员:关注系统安全、网络管理和自动化运维。
  • 普通用户:希望在日常生活中使用Linux,提升工作和娱乐体验。

系列文章结构

1. Linux入门

  • 什么是Linux:简要历史和不同发行版
  • 如何选择适合自己的发行版(如Ubuntu、Fedora、Arch Linux等)
  • 安装Linux:从下载ISO文件到安装系统的详细步骤
  • 安装后的基本配置

2. 基础命令和工具

  • 常用命令介绍(如ls、cd、cp、mv、rm、cat、grep等)
  • 文件系统和权限管理
  • 使用终端和Shell脚本入门
  • 编辑器推荐及使用(如Vim、Emacs)

3. 日常工作中的Linux

  • 办公套件:Wps,LibreOffice
  • 浏览器推荐及配置(如Firefox、Chrome)
  • 文件管理器(PCManFM)

4. 开发环境搭建

  • 编程语言环境配置(如Python、Java、C++等)
  • 集成开发环境(IDE)推荐及配置(如VSCode、IntelliJ IDEA、Eclipse等)
  • 版本控制系统(如Git)的使用
  • Docker和虚拟机管理(如VirtualBox)

5. 系统维护与优化

  • 软件包管理(如apt、yum、pacman)
  • 系统更新与备份策略
  • 性能监控和优化(如htop、iotop)
  • 日志管理和故障排除

6. 多媒体与娱乐

  • 音乐和视频播放软件推荐(如VLC)
  • 图像编辑工具(如GIMP)
  • 游戏(如Steam)

8. 高级话题

  • 自定义Shell和脚本编写
  • 参与开源社区和项目

交流

欢迎关注公众号, 更方便查看文章

公众号: 陌上花kai

环境工具

系统archlinux

手柄 北通360, usb

安卓手机 小米11

游戏 流行群侠传

步骤

手机要打开开发者调试, 并通过usb连接测试

不属于此次重点, 可自行搜索, 通过命令行adb
devices测试输出,说明连接成功

安装scrcpy

此工具用来在电脑端远程操作手机, 并且该软件开源, 而且使用还算流畅

1
sudo pacman -S scrcpy

在手机电脑正常连接的情况下, 直接启动改程序即可

测试键盘控制

通过键盘测试游戏中一些主要操作的对应按键, 后续跟手柄进行绑定

键盘

  1. 前后左右(wsad)

  2. 轻击(h)

  3. 重击(j)

  4. 技能1(u)

  5. 技能2/3(i)

    随从技能也会一起被放出去,真刺激

  6. 闪避(k)

  7. 怒气(p)

  8. 换武器(l)

编写手柄键盘按键映射程序

这里要注意, 按键使用的是keyboard组件, 测试使用pyautogui会出现连点的情况

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
"""
通过python + adb + scrcpy的方式,实现手柄玩安卓手机游戏

# Released by rdb under the Unlicense (unlicense.org)
# Based on information from:
# https://www.kernel.org/doc/Documentation/input/joystick-api.txt

# 参考
https://blog.csdn.net/Enderman_xiaohei/article/details/88050036?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-9-88050036-blog-109139735.pc_relevant_3mothn_strategy_recovery&spm=1001.2101.3001.4242.6&utm_relevant_index=12

https://blog.csdn.net/dhjabc_1/article/details/117444998

使用:
linux下需要使用管理员身份运行(触发按键需要), 否则运行报错

sudo python xx.py

"""
import pygame
# 键盘
import keyboard
import pyautogui
import time

# 鼠标, 没啥用了
# from pymouse import PyMouseMeta
# m = PyMouseMeta()


class JoyToKey:
"""
将手柄映射到键盘输入上
"""

def exec(self, joystick, event):
# 可能的joystick行为: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
# if event.type == pygame.JOYBUTTONUP:
# print("Joystick button released.")
# ********************键盘按键********************
if event.type == pygame.KEYDOWN:
# print(pygame.key.get_pressed())
pass
# event.key 表示键盘按键的值,比如k 的值是107, 回车键的值是13,等
# self.toggle_show_fps(event.key)
elif event.type == pygame.KEYUP:
# print(pygame.key.get_pressed())
pass

# ********************手柄操作********************
elif event.type == pygame.JOYBUTTONDOWN:
# 检测到手柄上的键按下
# print("Joystick button pressed.")
if joystick.get_button(7) == 1:
# 手柄start键 --> 键盘中的回车键。
keyboard.press('enter')
if joystick.get_button(0) == 1:
# 手柄A键 --> 键盘的k键,也就是对应跳(闪)的功能。
keyboard.press('k')
if joystick.get_button(2) == 1:
# 手柄X键 --> 键盘u
keyboard.press('u')
if joystick.get_button(1) == 1:
# 手柄B键 --> 键盘i
keyboard.press('i')
if joystick.get_button(3) == 1:
# 手柄Y键 --> 键盘p
keyboard.press('p')
if joystick.get_button(4) == 1:
keyboard.press('h')
if joystick.get_button(5) == 1:
# 手柄又键 --> 键盘l(换武器)
# keyboard.press('l')
keyboard.press('j')
elif event.type == pygame.JOYBUTTONUP:
# print("Joystick button release.")
if joystick.get_button(7) == 0:
# 手柄start键 --> 键盘中的回车键。
keyboard.release('enter')
if joystick.get_button(0) == 0:
# 手柄A键 --> 键盘的k键,也就是对应跳(闪)的功能。
keyboard.release('k')
if joystick.get_button(2) == 0:
# 手柄X键 --> 键盘u
keyboard.release('u')
if joystick.get_button(1) == 0:
# 手柄B键 --> 键盘i
keyboard.release('i')
if joystick.get_button(3) == 0:
# 手柄Y键 --> 键盘p
keyboard.release('p')
if joystick.get_button(4) == 0:
keyboard.release('h')
if joystick.get_button(5) == 0:
# 手柄又键 --> 键盘l(换武器)
# keyboard.release('l')
# 攻击键容易连点
keyboard.release('j')

# 攻击键
elif event.type == pygame.JOYAXISMOTION:
# print("Joystick axis pressed.")
if joystick.get_axis(2) > 0:
# 手柄左x --> 键盘h
# 注意: 这里需要让手柄, pygame来控制按压和释放, 如果用pyautogui, keydown每次会触发很多按压,(连点)
# 还是用这个保险
keyboard.press('h')
if joystick.get_axis(5) > 0:
# 手柄右x --> 键盘j
keyboard.press('j')
if round(joystick.get_axis(1)) < 0:
# 前
keyboard.press('w')
if round(joystick.get_axis(1)) > 0:
# 后
keyboard.press('s')
if round(joystick.get_axis(0)) < 0:
# 左
keyboard.press('a')
if round(joystick.get_axis(0)) > 0:
# 右
keyboard.press('d')

# 释放
# print("Joystick axis released.")
# print("s", joystick.get_axis(1))
if joystick.get_axis(2) < 0:
# 手柄左x --> 键盘h
keyboard.release('h')
if joystick.get_axis(5) < 0:
# 手柄右x --> 键盘j
keyboard.release('j')
if round(joystick.get_axis(0)) == 0:
# 释放左右
keyboard.release('a')
keyboard.release('d')
if round(joystick.get_axis(1)) == 0:
# 释放前后
keyboard.release('w')
keyboard.release('s')

# 摇杆转向
# 当前鼠标光标位置, 固定位置, 不单独获取了
# x, y = pygame.mouse.get_pos()
x, y = 482, 305
pyautogui.moveTo(x, y)
# 1. 设置当前鼠标光标位置, 放中间或偏右
# 2. 根据摇杆变化, 利用pyautogui进行拖拽
# 3, 4为遥感的横/纵向变化
if joystick.get_axis(3) != 0 or joystick.get_axis(4) != 0:
# 将当前光标位置的东西向下移动100个像素点,在拖动的过程中按住鼠标左键。
# >> > pyautogui.drag(100, 0, button='left')
# 一样的问题, 连点
# pyautogui.drag(int(round(joystick.get_axis(4))), int(round(joystick.get_axis(3))), button='left')
print(y+int(round(joystick.get_axis(4))), x+int(round(joystick.get_axis(3))))

# 使用pymouse实现上述payautogui的拖拽
# x, y = pygame.mouse.get_pos()
# m.press(x, y)
# x1 = x + joystick.get_axis(3)
# y1 = y + joystick.get_axis(4)
# m.move(x1, y1)
# m.release(x1, y1)


if __name__ == '__main__':
pygame.init()

# 初始化joystick
pygame.joystick.init()

# 得到joystick的数量
joystick_count = pygame.joystick.get_count()
print("Number of joysticks: {}".format(joystick_count))

# 之考虑一个手柄
joystick = pygame.joystick.Joystick(0)
# 按键映射对象
joyToKey = JoyToKey()

# -------- 程序主循环 -----------
# 保持循环直到用户点击关闭按钮
done = False
while not done:
# 事件处理的步骤
# 手柄事件触发
for event in pygame.event.get():
# 如果用户触发了关闭事件
if event.type == pygame.QUIT:
# 设置我们做了这件事的标志,所以我们就可以退出循环了
done = True
else:
joyToKey.exec(joystick, event)

# 关闭窗口并退出.
pygame.quit()

程序运行

程序使用的是keyboard组件, 在linux下运行时需要sudo

1
sudo python 北通360-流行群侠传手游.py

此时在scrcpy界面, 通过手柄即可控制手机进行游戏操作, 并且流畅性也还可以

说明

只是为了提高下游戏的趣味性, 其它操作可自行发掘

摇杆目前无法适应

摇杆转向跟鼠标适配未实现, 事件刷新太快, 暂时未想到好方法进行转换

需求规定

为了减少注释和swagger注解的重复定义, 通过规范注释,
让swagger可以通过javadoc来产生

替换@Api、@ApiOperation、@ApiModel、@ApiModelProperties等注解

只是对swagger的扩展,如果有swagger注解,以注解为准

运行环境

springboot2.1.7

jdk1.8

设计思想

系统构思

  1. 编译完成的class里没有注释的,所以注释信息只有在编译代码时存储起来
  2. swagger本身是通过注解实现接口定义描述等加载的,现将代码注释生成json格式,
    利用swagger扩展在启动项目时通过json进行加载到swagger中
  3. 需要配合自定义的javadoc-json-maven-plugin先将注释生成json文件

关键技术与算法

生成javadoc.json文件

com.example.CommentToJsonMain(已做成maven插件, 这里原始文件可做测试)

插件: https://github.com/zhaozhiwei1992/javadoc-json-maven-plugin

swagger扩展代码

com.example.SpringbootSwaggerJavadocApplication启动即可生效

类定义: com.example.plugin.CommentApiBuilder

方法定义: com.example.plugin.CommentOperationBuilder

类代码注释规范

1
2
3
4
5
6
7
8
9
/**
* @Title: PersonController
* @Package: com/example/springbootcache/controller/PersonController.java
* @Description: 用户信息接口
* @author: zhaozhiwei
* @date: 2022/10/25 下午8:23
* @version: V1.0
*/

方法代码注释规范

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @date: 2022/10/25-上午10:19
* @author: zhaozhiwei
* @method: findByID
* @param id : 唯一id
* @return: com.lx.demo.springbootcache.domain.Person
* @Description: 根据id获取用户信息
* 获取十次, 只有第一次是读库,后续都是取缓存
* 直接删掉redis缓存里的内容,仍然可以获取数据,并且走缓存,此时获取的是服务缓存ehcache中的信息
* seq 10 |xargs -i curl -XGET 'http://localhost:8080/persons/2'
*/

基本处理流程

系统流程图

file
1
2
3
4
5
6
7
8
9
start
:引入javadoc-json插件;
:使用插件:generate goals生成json版注释;
:正常启动web服务;
:访问swagger-ui.html;
note right
此时即可看到没有注解的方法也可以显示方法描述信息
end note
end

代码

https://github.com/zhaozhiwei1992/demo/tree/master/springboot/springboot-swagger-javadoc

参考

swagger扩展

https://github.com/hadix-lin/springfox-plus

https://blog.csdn.net/ydonghao2/article/details/109593416

https://blog.csdn.net/baiihcy/article/details/53861267

https://blog.csdn.net/qq_17623363/article/details/109259315

目的

将java的代码注释转换为json格式,并写入文件

本文介绍了完整的开发流程及如何使用

运行环境

jdk1.8

maven3.x

设计思想

系统构思

  1. 编译完成的class里没有注释的,所以注释信息只有在编译代码时存储起来
  2. 将能够生成javadoc.json的代码做成maven插件

关键技术与算法

需要实现Doclet

必须引入下述jar包, 来导入com.sun.javadoc.Doclet

1
2
3
4
5
6
7
8
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>/home/zhaozhiwei/applications/jdk1.8.0_181/lib/tools.jar</systemPath>
</dependency>

代码路径

https:github.com:zhaozhiwei1992/javadoc-json-maven-plugin

入口: com.example.Javadoc2JsonMojo#execute

生成javadoc.json文件

com.example.CommentToJson(做成maven插件使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"com.example.web.rest.PersonResource.findByID(java.lang.Long)#date": "2022/10/25-上午10:19",
"com.example.web.rest.PersonResource#Package": "com/example/springbootcache/controller/PersonController.java",
"com.example.web.rest.PersonResource.findByID(java.lang.Long)#Description": "根据id获取用户信息",
"com.example.web.rest.PersonResource.save(Person)#method": "save",
"com.example.web.rest.PersonResource#author": "zhaozhiwei",
"com.example.web.rest.PersonResource.deleteByID(java.lang.Long)#Description": "根据id删除person信息",
"com.example.web.rest.PersonResource#Title": "PersonController",
"com.example.web.rest.PersonResource.update(Person)#date": "2022/10/25-上午10:21",
"com.example.web.rest.PersonResource.save(Person)#Description": "保存方法",
"com.example.web.rest.PersonResource#Description": "用户信息接口",
"com.example.web.rest.PersonResource#date": "2022/10/25 下午8:23",
"com.example.web.rest.PersonResource.update(Person)#Description": "修改内容看是否会调整缓存",
... 省略了一大堆
}

类代码注释规范

1
2
3
4
5
6
7
8
9
/**
* @Title: PersonController
* @Package: com/example/springbootcache/controller/PersonController.java
* @Description: 用户信息接口
* @author: zhaozhiwei
* @date: 2022/10/25 下午8:23
* @version: V1.0
*/

方法代码注释规范

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @date: 2022/10/25-上午10:19
* @author: zhaozhiwei
* @method: findByID
* @param id : 唯一id
* @return: com.lx.demo.springbootcache.domain.Person
* @Description: 根据id获取用户信息
* 获取十次, 只有第一次是读库,后续都是取缓存
* 直接删掉redis缓存里的内容,仍然可以获取数据,并且走缓存,此时获取的是服务缓存ehcache中的信息
* seq 10 |xargs -i curl -XGET 'http://localhost:8080/persons/2'
*/

参数定义

1
2
3
4
5
6
7
@parameter额外属性:

@parameter alias="<aliasName>":为mojo参数使用别名

@parameter expression="${aSystemProperty}":使用系统属性表达式对mojo参数进行赋值

@parameter defaultValue="aValue/${anExpression}":提供一个默认值

开发流程

项目构建

1
mvn archetype:generate -DgroupId=com.example -DartifactId=javadoc-json-maven-plugin -DarchetypeArtifactId=maven-archetype-mojo -DinteractiveMode=false

使用插件

Install

在javadoc-json-maven-plugin项目中执行maven的install命令,
将插件安装到本地仓库

引入自定义插件

在其它项目引入插件测试

展开插件可以看到Mojo列表,由于项目里只有一个Mojo,且Mojo上用注释@goal指定了名称为generate,所以这里只能看到一个javadoc-json:generate

1
2
3
4
5
6
7
8
9
10
            <plugin>
<groupId>com.example</groupId>
<artifactId>javadoc-json-maven-plugin</artifactId>
<version>2.0-SNAPSHOT</version>
<configuration>
<!-- 指定java注释扫描目录-->
<basePackage>com/example/web/rest</basePackage>
</configuration>
</plugin>

执行插件

双击javadoc-json:generate就会执行这个插件。

执行完毕后,可以看到项目根目录的target文件下多了个javadoc.json文件。

命令行执行插件(可选)

命令格式为mvn groupId:artifactId:version:goal,执行如下命令:

mvn com.example:javadoc-json-maven-plugin:1.0.0-SNAPSHOT:generate

由于我们的插件命名符合规范,所以上面的命令可以简写为:

mvn javadoc-json:generate

尚未解决的问题

javadoc插件去掉异常提示

参考

maven插件开发

https://www.jianshu.com/p/9cfe599b3c5e

参数定义

https://blog.csdn.net/z69183787/article/details/52984622

目的

通过一台linux机器操作android手机做一些常用的操作

复杂的操作都是由简单操作开始的, 可以自行发掘

环境

1
2
3
4
5
6
7
笔记本: thinkpad t480

操作系统: archlinux

adb版本: 31.0.3p2-android-tools

手机: 小米手机 muui13.09

操作步骤

笔记本安装adb环境

1
sudo pacman -S android-tools

测试

1
2
3
4
5
adb --version

Android Debug Bridge version 1.0.41
Version 31.0.3p2-android-tools
Installed as /usr/bin/adb

手机打开usb调试开关

设置—-全部参数—–狂戳miui版本,这样就打开开发者模式了。

设置—–更多设置——开发者选项—开启开发者选项。

需要开启的按钮有:USB调试、USB安装、USB调试(安全设置)、关闭启动MIUI优化。

连接手机

通过usb连接手机后,
需要在小米手机上面的USB的用途上面选择传输文件或者传输照片(除了仅充电就行~)

测试连接: 查看连接设备 adb devices, 正常输出说明连接成功,
usb连通后也可以用wifi连接 :D

使用命令操作手机拍照

启动相机

1
adb shell am start -a android.media.action.STILL_IMAGE_CAMERA

camera键 拍照

1
adb shell input keyevent 27 

back键 暂退相机

1
adb shell input keyevent 4

这里只是个简单操作, 并且相机的启动入口基本是固定的,
如果是其它的app需要先获取到应用的入口, 可以自行搜索或联系我

对于按键操作, 最好是网上搜索一份按键编码对应表

概述

多数据源单服务写入, 分布式事务实现

使用随机数控制产生异常

注: 网上很多都是只有多数据源配置,实际不能控制事务统一回滚,
单服务场景下如果多个数据源只有一个写,剩下都是读, 则不需要分布式事务

为减少篇幅,详细代码在代码仓库,可自行参考

版本

springboot 2.1.7.RELEASE

配置引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

增加配置类

AtomikosJtaPlatform

JPAAtomikosTransactionConfig Atomikos事务配置类

PrimaryConfig 主数据源配置

SecondaryConfig 其它数据源配置

数据对象实现

User

增加仓储实现

需要分别实现primary和secondary, 从而支持多个数据源访问

PrimaryUserRepository

SecondaryUserRepository

实现服务类

PrimaryUserService

SecondaryUserService

ExampleService

负责统一调用 PrimaryUserService 和 SecondaryUserService,
模拟一个服务同时访问多个服务类(每个服务类引用了不同数据源)

如果其中某个服务抛出异常,则整个事务回滚, @Transactional(rollbackOn =
Exception.class) 是必须的

测试

com.example.springbootatomikos.services.UserServiceTest#testSave

代码

github地址

gitee地址

目标

通过指纹识别解锁slim-lock

环境

操作系统archlinux

桌面管理器slim

锁屏slimlock

硬件 Thinkpad T480

注: 指纹设备id, 06cb:009a

安装

测试设备 lsusb

1
2
3
4
5
6
7
8
9
10
11
12
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 002: ID 0bda:0316 Realtek Semiconductor Corp. Card Reader
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

# 这玩意儿应该就是指纹设备了
Bus 001 Device 005: ID 06cb:009a Synaptics, Inc. Metallica MIS Touch Fingerprint Reader

Bus 001 Device 004: ID 04f2:b604 Chicony Electronics Co., Ltd Integrated Camera (1280x720@30)
Bus 001 Device 003: ID 8087:0a2b Intel Corp. Bluetooth wireless interface
Bus 001 Device 002: ID 3044:50e0 MIIIW MW Keyboard Air Mini
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

安装libfprint-vfs009x-git (测试不通过)

yaourt -S libfprint-vfs009x-git

python-vlidity(推荐)

https://github.com/uunicorn/python-validity

安装: yaourt -S python-validity

录入指纹及解锁

fprintd-enroll

按照下述同时,录入指纹,直到completed

1
2
3
4
5
6
7
8
9
10
11
Using device /net/reactivated/Fprint/Device/1
Enrolling right-index-finger finger.
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-stage-passed
Enroll result: enroll-completed

校验指纹是否正常fprintd-verify

1
2
3
4
Using device /net/reactivated/Fprint/Device/1
Listing enrolled fingers:
- #0: WINBIO_ANSI_381_POS_RH_INDEX_FINGER
Verify result: verify-match (done)

查看当前用户指纹 fprintd-list 用户名

1
2
3
4
5
found 1 devices
Device at /net/reactivated/Fprint/Device/1
Using device /net/reactivated/Fprint/Device/1
Fingerprints for user zhaozhiwei on DBus driver (press):
- #0: WINBIO_ANSI_381_POS_RH_INDEX_FINGER

ThinkPadT480 slimlock指纹解锁

vim /etc/pam.d/system-local-login

将pam_fprintd.so添加到auth部分的顶部

auth sufficient pam_fprintd.so

重新启动计算机,会提示扫描手指以解锁登录(指纹灯亮)

slimlock认证后直接回车,不需要输入密码

问题列表

Impossible to enroll: GDBus.Error:net.reactivated.Fprint.Error.NoSuchDevice: No devices available

运行fprintd-enroll报错

https://wiki.archlinux.org/title/Lenovo_ThinkPad_T470#Fingerprint_reader

Install fprintd and libfprint-vfs009x-git AUR, then reboot. You can now
enroll your fingers with fprintd-enroll.

github下载很慢

将repository导入到gitee中,并且注意该项目有子模块,
所有需要手动增加.gitmodules

https://gitee.com/zhaozhiwei_1992/libfprint.git

https://gitee.com/zhaozhiwei_1992/libfprint-tod-vfs0090.git

libfprint/meson.build:1:0: ERROR: Unknown options: "x11-examples"

The x11-examples option seems to have been removed. It looks like it's
been replaced by "gtk-examples". I edited that in PKGBUILD and it
built successfully.

https://aur.archlinux.org/packages/libfprint-vfs009x-git

修改build文件, x11-example改成gtk-example

libfprint-vfs009x-git和fprintd >=1.92+版本冲突

安装低版本 sudo pacman -U
https://archive.archlinux.org/packages/f/fprintd/fprintd-1.90.1-1-x86_64.pkg.tar.zst

list_devices failed: No devices available

thinkpad t480 指纹id为 06cb:009a, 上述一些工具不支持,
直接使用python-validity即可

环境

archlinux

桌面管理器i3wm

登录管理器 slim

python 3.10.4

dlib

1
pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple dlib

face_recognition 依赖dlib

1
pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple face_recognition

opency 读取摄像头

1
pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python

笔记本内置摄像头

流程图

代码

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
"""
人脸识别认证

使用摄像头检验当前用户是否匹配
"""
# -*- coding: utf-8 -*-
import cv2
import os
import face_recognition
import pyautogui
import time


class AuthByFace:

def __init__(self, clicked, clocked):
self.clicked = clicked
self.clocked = clocked
# 设置图像保存目录
self.SUCCESS_DIR = os.environ['HOME'] + "/Pictures/authFaces/success/"

# 认证通过返回true
def isAuthSuccess(self):

# 获取摄像头中人脸
cameraCapture = cv2.VideoCapture(0)
result, image = cameraCapture.read()
if result:
# cameraImageRgb = image[:, :, ::-1]
# 摄像头中的人脸位置, 可能出现多张脸
cameraImageFaceLocations = face_recognition.face_locations(image)
# 摄像头中人脸进行编码
cameraImageEncodings = face_recognition.face_encodings(image, cameraImageFaceLocations)[0]

# 使用仓库中文件 测试匹配
# unknownImage = face_recognition.load_image_file(self.SUCCESS_DIR + "image_1.jpg")
# cameraImageEncodings = face_recognition.face_encodings(unknownImage)[0]

personNames = []
knownImageEncodings = []
# 跟所有保存的人脸比对
files = os.listdir(self.SUCCESS_DIR)
for file in files:
if file.endswith("jpg") or file.endswith("png"):
name, _ = os.path.split(file)
personNames.append(name)
knowImagePath = self.SUCCESS_DIR + file
knownImage = face_recognition.load_image_file(knowImagePath)
# 将仓库中照片全部编码, 后续比对需要
knownImageEncodings.append(face_recognition.face_encodings(knownImage)[0])

# 遍历locations,face_encodings,识别图片中的人脸
matchs = face_recognition.compare_faces(knownImageEncodings, cameraImageEncodings)
print("hhaha", matchs)
for index, match in enumerate(matchs):
if match:
# 有一个匹配就返回
print("图像: ", personNames[index], "匹配成功")
return True

# 打开摄像头, 监听鼠标事件
def onMouse(self, event, x, y, flags, param):
# 点击左键, 重置click状态
if event == cv2.EVENT_LBUTTONUP:
self.clicked = True

def savePicture(self):
# 打开摄像头
# VideoCapture()中参数是0,表示打开笔记本的内置摄像头,
# 参数是视频文件路径则打开视频
cameraCapture = cv2.VideoCapture(0)
if not cameraCapture.isOpened():
print("摄像头未打开~~")
exit()
cameraCapture.set(3, 100)
# 帧宽度和帧高度都设置为100像素
cameraCapture.set(4, 100)
cv2.namedWindow('MyWindow')
cv2.setMouseCallback('MyWindow', self.onMouse)
# 点击左键保存
print('showing camera feed. Click window or press and key to stop.')
result, image = cameraCapture.read()
# True/False 是否读取到照片
print(result)

# 点击鼠标左键后, 保存图片, 关闭窗口
while result and cv2.waitKey(1) == -1 and not self.clicked:
cv2.imshow('MyWindow', cv2.flip(image, 0))
result, image = cameraCapture.read()
name = self.SUCCESS_DIR + 'image_0.jpg'
cv2.imwrite(name, image)
cv2.destroyWindow('MyWindow')
cameraCapture.release()


if __name__ == '__main__':
authByFace = AuthByFace(False, False)

# 仓库没有照片则先录入照片
files = os.listdir(authByFace.SUCCESS_DIR)
if len(files) < 1:
authByFace.savePicture()
else:
# 锁定状态才会走这个认证逻辑
# 每1分钟运行一次认证
while True:
time.sleep(10)
try:
isSuccess = authByFace.isAuthSuccess()
if authByFace.clocked and isSuccess:
# 认证通过则解开锁屏
print("认证通过")
# 输入锁屏密码
pyautogui.typewrite("1")
pyautogui.press("enter")
pyautogui.press("Esc")
authByFace.clocked = False
elif not isSuccess:
# 如果认证不通过, 调用系统快捷键, 锁定屏幕
pyautogui.hotkey('win', 'c')
pyautogui.press(['l'], interval=0.1)
# 对象设置为锁定状态
authByFace.clocked = True
except Exception as exc:
print(type(exc))
if not authByFace.clocked:
pyautogui.hotkey('win', 'c')
pyautogui.press(['l'], interval=0.1)
# 对象设置为锁定状态
authByFace.clocked = True

开启启动

方式1 systemd (未通过)

经过测试,
无法将该程序放入到systemd单元,跟cv2等包有关系,引入就启动失败

方式2

直接加入到i3wm的开机启动即可,加载该文件时图形界面已经加载,正合适

1
exec --no-startup-id /usr/bin/python ~/workspace/python/demo/AuthByFace.py > /tmp/authByFace.log 2>&1

参考

https://www.cnblogs.com/sclu/p/12626553.html

问题列表

解决python安装opencv速度慢

使用清华镜像(速度快)

pip install –user -i https://pypi.tuna.tsinghua.edu.cn/simple
opencv-python

0%