概述
- 本文只是回顾这样一次经历,所以不会贴大段大段代码
- 当时拿到的需求是,先在手机上写好签名,然后上传到服务器持久化到数据库,最后供web和移动端以图片的形式展示出来。
过程
第一反应是这功能有啥用,默默地吐槽完领导后开始考虑怎么去实现。
需求的理解
- 最先想到的是手机输入法的手写功能,去讯飞看了一下,基本上都是说的语音识别(因为最近人工智能很火),没找到手写相关的API。正苦恼的时候发现自己思路跑偏了,既然是要签名,手写的给识别出来了就没意义了(签名就是要认不出来)。”写啥样就要存啥样”,这不就是画画嘛。
- 于是转向了canvas。其实对canvas我的了解仅仅局限于这是能在页面上画画的。接下来就是去找ionic有没有相关的插件,结果找到了
signature_pad.js
,更幸福的是,已经有人在ionic上用过。
如何实现
- 在github上作者也详细介绍了怎么使用,如何导出成图片。实践的过程中发现可以导出为
.jpg
,.png
,.svg
三种格式。但是导出的内容是”dataurl”,对于在此之前仅仅知道图片本质也是二进制的我而言,新的问题出现了。怎么把dataurl转换成真正的图片呢? - 这时候需求增加了。需要在手机端本地存储这张图片,以便以后直接调用,减少一次请求。
- 这实际上还是之前的问题,dataurl→图片。”内事不决问百度”。经过一番搜索后,发现dataurl可以转为Blob对象,通过Blob对象能够生成一个文件。
ionic本地文件系统
-
在ionic中获取设备文件系统,进而取得文件路径,最后写入文件内容,这个问题已经解决了。通过
cordova-plugin-file
这个插件就能解决该问题。 - 到这个时候,我认为问题已经完全解决了,既然dataurl在手机本地能够直接转为图片,那么在服务器上自然也能转为图片,最后再把图片路径持久化到数据库就万事大吉了。中间需要解决就是把dataurl发送到服务器。
图片上传到后台
- 最开始我觉得这都不是问题,发数据到服务器,post请求不就完事了。接下来,通过Angular的http模块,设置header为
applicant/x-www-form-urlencoded
,再服务端通过文件上传API生成了图片。问题又来了。 - dataurl在本地与在服务器生成的图片竟然不一样。于是在chrome控制台看请求响应信息。把请求中的dataurl拿出来在服务器直接本地测试,生成的图片又是正确的。最后在服务器打断点debug,发现服务器接受到的dataurl是客户端发送的dataurl截取后的值。
- dataurl一般会很长,可能会达到10000个字符。经过百度后发现,post请求本身对长度是没有限制的,但是服务器会有,tomcat就有这方面的参数可以设置。但是服务器一般配置好了不会轻易更改,因此还是只能从自身来找解决方案。
form表单的提交方式
- 在MDN上查看Using_XMLHttpRequest相关的页面上了解到,form表单有四种提交方式
-
method=post, enctype=applicant/x-www-form-urlencoded
这是表单提交的默认方式 -
method=post, enctype=multipart/form-data
文件上传时表单的提交方式 method=post, enctype=text/plain
-
method=get
这种情况下enctype
会被忽略
-
- 这时候我突然想到,图片上传到服务器的过程中,图片数据是以什么形式存在的呢?我尝试直接把dataurl放到
img
标签的src
属性中,果然,直接把图片显示出来了。那么文件上传时,图片数据可能就是把dataurl直接发送到后台,而且因为是文件上传,那么服务器对于请求数据的大小应该是没有限制或者说限制的字节数会大得多
在没有form表单的情况下构造文件上传
-
因为没有form标签,没有办法直接通过表单提交的方式上传图片。有两个备选方案:
- 通过js生成一个form表单
- 直接手动构造一个文件上传请求
-
方案一太麻烦,不够直接。所以直接就采用了方案二。通过FormData的API可以直接构造表单项。
let fd = new FormData(); fd.append("Filename", "signature.png"); fd.append("Filedata", params, "signature.png");
-
然后在后台方法中,直接将该dataurl写到文件里面,就能够生成一张
.png
图片了
感想
-
对需求的理解很重要。最开始拿到需求时,我的脑海里关键词就是手写。甚至都想这不是需要人工智能识别的嘛。很显然这个思路就偏了。当对需求的理解有偏差的时候,后面的实现必然会遇到各种问题。
-
对技术原理、实质的认识是实现的关键。在这个过程中,
- 对图片压根不了解
- 对java上传文件不熟悉
- 对表单相关API掌握的不够深入
最后完成这个功能,我发现自己都完整写了一遍最原始的java文件上传代码,文件流相关的代码等等...
-
发散思维,自己不会就得找资料,现在开始学习,一切都来得及。Never Too Old To Learn
网友评论