重剑无锋,大巧不工 SpringBoot --- 使用 Ajax FromData 上传文件并传参
页面
1 | const formData = new FormData(); |
spring boot 处理
1 | @PostMapping("/file") |
注意
- antd 上传组件里,真正的文件是 file.originFileObj
- params 是复杂的对象的话, spring boot 接受的 Params 对象需要使用 String 字符串进行序列化成对象; 或者将 Params 对象的属性分开来写, 如果某个属性又是复杂对象的话通用需要序列化
Ubuntu 优雅的远程桌面服务端配置
背景
上一篇文章记录了因为远程桌面连接把 Ubuntu 的 /home
弄坏了
好一番折腾。。。。
其实这个远程桌面我早就想重新配置了,今天我终于受不了它了,于是我觉得仔细研究一番找到适合我自己的方式来操作
以前的方式
之前我的远程配置是 xrdp
+ tightvncserver
然后我每次都是使用 Windows 上的 mstsc
来连接的
连接上后会出现 xrpd
的登录选项
每次我都选第一个 sesman-Xvnc
然后输入用户名密码即可
可这样的连接方式有个很不好的方面,就是这种方式是多用户的,想回家继续没干完的事情
连接上发现是一个新的桌面
都不知道做到什么地方了
这也就算了
最大的问题远程操作操作这就没响应了,鼠标的指针变成了 × 号,所有的东西都不能点,而且第二天到公司桌面卡死不动,只能重启桌面或重启系统,很多打开软件和工具都会还原
这是我最不能忍的地方
决定改变
我决定不使用这种方式来进行远程,远程 teamviewer
是比较合适的选择,但是工作由于连接的终端太多,被检测商用,每次连接都是只有 1 min 的操作时间
很尴尬…
最后决定使用轻量级的 vnc
服务来解决这个问题,并且搭配 xrdp
的 any vnc
来使用 mstsc
远程连接
重新配置
x11vnc
- 卸载以前的 vnc 服务端
1 | sudo apt remove tigervncserver |
- 安装
x11vnc
,并进行配置
1 | sudo apt install x11vnc -y |
- 解决复制粘贴的问题
sudo apt install autocutsel
安装 autocutselautocutsel -f
后台运行
问题及解决
下载 vnc-view 新建一个连接发现连不上…
尴尬。。。
检查 5900
端口,是开放的
1 | joylau@joylau-work-192:~$ sudo netstat -tnlp | grep :5900 |
但是使用的进程是 vino-server
,这是 Ubuntu 自带程序开启的服务
原来端口被占用了
关闭服务 : 找到桌面共享,关闭 允许其他人查看您的桌面
重启 x11vnc
服务
连接成功
最后
现在有 4 中方式使用
- 使用
vnc-view
使用是单用户的,类似teamviewer
那样,2 边操作都能互相看见 - 使用
mstsc
, 连接到xrdp
后,再选中any vnc
使用vnc
协议连接,效果和第一种是一样的,只不过不需要客户端了 - 浏览器直接远程,这种最方便,下面有说明
- 以前的那种使用方式, 多用户的,估计我是不会再用了
补充
第三种多用户方式连接,没连接一次就生成一个新的桌面,这个很烦,想连接回上次的桌面,可修改配置 /etc/xrdp/xrdp.ini
1 | [globals] |
修改 port 为 固定端口号或者 ask-1
下次连接不修改即可
注:再记录下 sesman.ini
的配置
1 | [Globals] |
使用浏览器来远程桌面
像阿里云等云服务提供商一样直接在浏览器上进行远程操作
1 | docker run -e REMOTE_HOST=192.168.10.192 -e REMOTE_PORT=5900 -p 8081:8081 -d --restart always --name novnc dougw/novnc |
打开浏览器 http://host:8081/vnc.html
秀啊!!!
记录一次 Ubuntu 因磁盘问题导致开机进入紧急模式的情况
背景
在家里使用 vnc 协议远程连接公司的 Ubuntu 电脑
导致桌面卡死
期间还遇到了 搜狗输入法崩溃,提示我删除用户目录下的一个文件然后重启
鼠标可以动
界面上的任何东西都无法点击
没再操作
等第二天到公司解决
不重启解决 Ubuntu 桌面卡死
这样的情况遇到很多了
ctrl + alt + f1
1 | ps -t tty7 |
之后桌面上的应用都会被关闭,回到登录界面
重启进入紧急模式
之后我想着电脑很久没关机了,想重启一下,顺便去倒杯水
回来之后发现系统正在进行磁盘检测并且之后进入了紧急模式
journalctl -xb
查看启动日志
一直往下翻
发现 /dev/sdb6
分区出现问题导致系统无法启动
使用 lsblk
查看分区挂载情况
1 | joylau@joylau-work-192:~$ lsblk -f |
解决问题
上面看到 sdb6 没有挂载点,实际上是有的,只不过现在出问题了没有挂载上
可以找 UUID 76ad5dc1-37b7-4624-830b-d923dac8ac48
查看 /etc/fstab
1 | # /etc/fstab: static file system information. |
查看到 76ad5dc1-37b7-4624-830b-d923dac8ac48 对应挂载的 /home
目录
后面的 pass 写的是 2 ,就是说开机进行磁盘检查,并且数值越小,越先检查
这里有个临时的解决方式就是将 /home
的 pass 改为 0 ,也就是开机不进行检查,该分区有问题并不代表分区不可用
改完后依然可以访问 /home
目录
磁盘修复
强迫症让我不能就这么将就
我觉得修复这个磁盘错误
使用命令修复这个错误如下
1 | fsck -y /dev/sdb6 |
结果提示 分区已挂载,操作被终止
修改 fstab 将 sdb6 挂载的那行注释
重启
进入紧急模式
运行 fsck -y /dev/sdb6
这时会打印很多日志
重复执行,直到没有日志打印
这时在修改 fstab, 去掉注释,pass 改为 2
重启
解决
Docker 启动报错: Error starting daemon: Error initializing network controller: list bridge addresses failed: no available network
背景
Docker 启动报错: Error starting daemon: Error initializing network controller: list bridge addresses failed: no available network
错误详情
查看错误日志: journalctl -xe | grep docker
1 | [root@lenovo docker]# journalctl -xe | grep docker |
看到这样一句话: Error starting daemon: Error initializing network controller: list bridge addresses failed: no available network
查看本机网络: ip a
1 | [root@lenovo docker]# ip a |
没有 docker0 的桥接网络
手动添加一个即可
解决
1 | ip link add name docker0 type bridge |
再看一下,多了一个 docker0
1 | 5: docker0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 |
重启 docker 即可
OpenCV 读取数据流图片
背景
OpenCV 提供的 API 是直接根据路径读取图片的, 在实际生产环境中,可能大部分情况下都是直接读取网络图片
在内存就完成图片和 opencv 的 Mat 对象的转换
那么该如何读取 byte[] 的图片呢?
API
openCV 提供的 API
1 | Mat src = Imgcodecs.imread("/static/img/17.png"); |
很简单的就转化为 Mat 对象
而 该方法后面还有一个参数, flags, 该参数可选项有:
- IMREAD_UNCHANGED = -1,
- IMREAD_GRAYSCALE = 0,
- IMREAD_COLOR = 1,
- IMREAD_ANYDEPTH = 2,
- IMREAD_ANYCOLOR = 4,
- IMREAD_LOAD_GDAL = 8,
- IMREAD_REDUCED_GRAYSCALE_2 = 16,
- IMREAD_REDUCED_COLOR_2 = 17,
- IMREAD_REDUCED_GRAYSCALE_4 = 32,
- IMREAD_REDUCED_COLOR_4 = 33,
- IMREAD_REDUCED_GRAYSCALE_8 = 64,
- IMREAD_REDUCED_COLOR_8 = 65,
- IMREAD_IGNORE_ORIENTATION = 128;
IMREAD_UNCHANGED: 以图片原有的方式读入,不进行任何改变
IMREAD_GRAYSCALE: 以灰度图读取
IMREAD_COLOR: 以彩色图读取
过渡
为了支持 OpenCV 读取 byte[] 的图片,为此我查找了很多资料做了大量的实验,有很多失败报错了,也有读取成功的,下面我将一一列举出来….
读取失败
Converters 类
我留意到 opencv 提供的 api 里有一个 utils
包, 里面有个转换类 Converters
, 可以将 Mat 和 一些 java 的基本数据类型进行互相转换,其中有这样 2 个方法: vector_uchar_to_Mat
和 vector_char_to_Mat
参数是 List<Byte>
1 | private static Mat testConvertChar2Mat(byte[] bytes){ |
vector_uchar_to_Mat
指有符号
转换出来的图片是一个像素的竖直线,读取失败
new Mat
Mat 对象除了转化得到,还可以 new , 再利用 Mat 的 put 方法,来创建 Mat
1 | private static Mat testNewMat(int height, int width, byte[] bytes) throws IOException { |
转换出来的图片也不对,一些花花绿绿的像素点
new BufferByte
Mat 对象还有个构造方法,最后一个参数是传入 BufferByte,这时只需要在上述步骤中再将 byte[] 转化为 BufferByte
1 | private static Mat testNewBuffer(int height, int width, byte[] bytes){ |
抛出异常: CvException [org.opencv.core.CvException: cv::Exception: OpenCV(4.1.0-pre) /Users/joylau/opencv4/opencv/modules/core/include/opencv2/core/mat.inl.hpp:548: error: (-215:Assertion failed) total() == 0 || data != NULL in function ‘Mat’
读取成功
BufferedImage 转换
一次我在调试代码时 发现 HighGui.waitKey();
的实现是将 Mat 对象转化为 BufferedImage 的逻辑,于是我明白了,OpenCV 里操作的 Mat 在显示的时候也需要转化为 BufferedImage
源码里有这样一段代码
1 | public static Image toBufferedImage(Mat m) { |
此时,我逆向转化,将 byte[] 转 BufferedImage ,BufferedImage 再转 Mat 即可
1 | private static byte[] getBufferedImageByte(byte[] bytes) throws IOException{ |
该方法成功读取显示了图片
于是又引发了我的思考: 为什么直接从文件读取的 byte[] 无法被转化,而 BufferedImage 中得到的 byte[] 却可以被转化
于是我将 BufferedImage 中得到的 byte[] 在使用,调用 Converters.vector_char_to_Mat
方法
可惜却失败了…..
imdecode
Imgcodecs 类中有一个编码的方法 Imgcodecs.imdecode(Mat buf, int flags)
Mat 还有个子类 MatOfByte
1 | private static Mat testImdecode(byte[] bytes){ |
该方法可成功转化
而且比上一个方法的优势是:
- byte[] 不需要再通过 BufferedImage 转化
- 不需要初始化 Mat 的长和宽
为此还可以逆向得出 Mat 转换成 byte[] 的方法
1 | /** |
最后
以下是全部测试代码
1 | /** |
OpenCV 基础知识与概念
一些概念
数字图像
数字图像指的是现在的图像都是以二维数字表示,每个像素的灰度值均由一个数字表示,范围为0-255(2^8)
二值图像
图像中每个像素的灰度值仅可取0或1,即不是取黑,就是取白,二值图像可理解为黑白图像
灰度图像
图像中每个像素可以由0-255的灰度值表示,具体表现为从全黑到全白中间有255个介于中间的灰色值可以取
彩色图像
每幅图像是由三幅灰度图像组合而成,依次表示红绿蓝三通道的灰度值,即我们熟知的RGB,此时彩色图像要视为三维的 [height,width, 3]
CvType
通道
OpenCV 中,图像可以分别为1,2,3,4 通道
- 通道为灰度图;
- 通道的图像是RGB555和RGB565。2通道图在程序处理中会用到,如傅里叶变换,可能会用到,一个通道为实数,一个通道为虚数,主要是编程方便。RGB555是16位的,2个字节,5+6+5,第一字节的前5位是R,后三位+第二字节是G,第二字节后5位是B,可见对原图像进行压缩了
- 通道为彩色图(RGB);
- 通道为 RGBA ,是RGB加上一个A通道,也叫alpha通道,表示透明度,PNG图像是一种典型的4通道图像。alpha通道可以赋值0到1,或者0到255,表示透明到不透明
常使用的是1,3,4通道; 2通道不常见
组合规则
CV_[bite](U|S|F)C[channels]
bite : 比特数,位数。 有 8bite,16bite,32bite,64bite,对应在 Mat 中,每个像素的所占的空间大小,8位即 CV_8
U|S|F :
- U : unsigned int , 无符号整形
- S : signed int , 有符号整形
- F : float , 单精度浮点型,float类型本身即有符号
这里的有符号、无符号是针对图像二进制编码来讲的。我在写的过程中大多数情况下都是使用的无符号,即 CV_8U ,CV_16U,当有计算时可能会介入有符号(存在负数),没学过 C++,对底层也一知半解,望高手解答。
C (channels):图像的通道数
比如: CV_8UC3
即 8位无符号的3通道(RGB 彩色)图像
参数说明
8U
- 说明:无符号的8位图
- 值:CV_8UC1,CV_8UC2,CV_8UC3,CV_8UC4
- 通道取值范围:0~255
8S
- 说明:有符号的8位图
- 值:CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4
- 通道取值范围:-128~127
16U
- 说明:无符号的16位图
- 值:CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4
- 通道取值范围:0~65535
16S
- 说明:有符号的16位图
- 值:CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4
- 通道取值范围:-32768~32767
32S
- 说明:无符号的32位图
- 值:CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4
- 通道取值范围:2147483648~2147483647
32F
- 说明:浮点型32位图
- 值:CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4
- 通道取值范围:1.18*(10(-38次方))~3.40*(10(38次方))
64F
- 说明:浮点型64位图
-值:CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4
- 通道取值范围:2.23*(10(-308次方))~1.79*(10(308次方))
1U
- 说明:1位
- 值:IPL_DEPTH_1U
- 通道取值范围:0~1
色彩空间
常见的色彩空间
- RGB
- HSV
- HIS
- YCRCB
- YUV
HSV
HSV分别是色调(Hue),饱和度(Saturation)和亮度(Value)
H调整颜色;S越大,图像色彩越丰富,颜色越鲜艳;V越大,图像越亮
HSV颜色取值范围
H:0— 180 : 之所以不是 360,是因为 8 位图 最大是 255,360 已经超出范围,以 180 为限定
S: 0— 255
V: 0— 255
记住下面这张图, 可使用这张图中的范围来查找某种颜色
转换方法
Imgproc.cvtColor(src,det,Imgproc.COLOR_BGR2HSV);
Docker 容器挂载宿主机上的目录时出现 Permission denied
问题
启动 docker 容器时挂载容器以前存在的数据文件时出现了 Permission denied 的错误
解决
- 首先以为是挂载的文件夹有读写数据的权限问题
chmod -R 777 xxxx
, 没有解决,依然报错 - 再分析是文件目录的所属者的问题:
chown -R gname:uname xxxx
, 没有解决,依然报错 - 这时我们进入容器之后 使用 ll 查看挂载的目录的所属者,发现组名和户名跟宿主机的组名和用户名不一致
- 原因在于,操作系统判断用户组和用户其实并不是根据名称来的,而是根据名称对应的 id 来的
- 查看用户组和用户名对象的 id, 可查看
/etc/passwd
- 此时,我们需要将宿主机的用户组用户的 ID 和 容器内挂在目录所需的用户组和用户的 ID 对应起来,写一直即可
- 举个例子
- redis 镜像产生的数据文件在
/var/lib/redis
中,并且该目录的用户组和用户都为redis
, 此时我们查看容器的redis:redis
的 id , 假如是102:103
- 此时我们宿主机挂载目录是
/opt/docker/redis/data
,我们改变这个目录的所属者chown -R 102:103 /opt/docker/redis/data
- 不要管
102:103
在宿主机系统中有没有该用户组和用户 - 再次进入容器就可以看到
/var/lib/redis
目录的所属者是正确的了
mysql 和 mariaDB 的问题
这样的情况也发生在 mysql 和 mariaDB 上
按照上述的方法似乎没有奏效,确切的说奏效一半
因为 /var/lib/mysql
目录中文件夹可以看到,文件却没有权限看到
类似这样
1 | 190321 06:02:13 mysqld_safe Logging to '/var/lib/mysql/d240623581db.err'. |
原因分析是:
SELinux 造成的
有以下 4 中解决方法:
setenforce 0
: 临时关闭vi /etc/selinux/config
: 将SELINUX=enforcing
改为SELINUX=disabled
,重启- 在docker run 中加入
--privileged=true
给容器加上特定权限 - 修改 SELinux 规则
chcon -t mysqld_db_t -R /opt/docker/mysql/data