起因:webApp中需要一个拍摄照片并上传服务器的功能
由于我正好使用Hbuilder在做webApp,所以自然想到了使用h5+中的调用摄像头功能
从此开始了踩坑之旅。。。
1.手机连接电脑问题
如果你没有连接问题请跳过。
手机通过数据线本来连接电脑好好的,突然就中断了,然后再咋也连不上电脑了,使用360手机助手连接也没用,而且我的手机设置和数据线及接口肯定没毛病,电脑重启一下就可以重连了,但总重启不是个事。
然后我就想到通过数据线真机调试有问题,我试试用无线wifi真机调试看看行不行,借鉴了这篇文章:
https://www.cnblogs.com/weibanggang/p/9961742.html
下载了WiFi ADB工具,还真给无线连上了,然后再赶紧真机调试,发现可以连接了。结果运行app时才发现有大坑,我html引入的jq,bootstrap,图片啥的资源都找不到,没办法,还是想办法用usb连接电脑吧。
查了半天,觉得唯一的可能就是我的usb驱动有问题,360手机助手提供的驱动可能兼容性不行,于是我下载了符合自己手机型号的usb驱动。因为我的是华为手机,只需要下载一个华为手机助手就可以了,下载地址:https://consumer.huawei.com/cn/support/hisuite/ 下载安装后连接手机就没问题了。(其他型号手机下载对应的驱动即可)
2.接口问题
由于官方文档写的不太清楚,理解有点费劲
5+调用相册接口官方文档:http://www.hcoder.net/tutorials/info_107.html
可知回调有三个参数:选择成功回调,选择失败回调,option配置参数。如果option配置了muitiple属性,则paths不再是一个路径,而是路径数组。
plus.gallery.pick(function(path){
console.log(path);
$("#albumCoverImg").attr("src",path);//给我的img元素添加src,可以直接显示出图片
});
返回的结果就是图片的物理路径
或者这么写:
plus.gallery.pick(
function(paths){
console.log(paths)
plus.nativeUI.showWaiting();
},
function(e){mui.toast('取消了选择');},
{multiple:true,maximum:5}
);
这样paths为一个数组,但貌似也只能选择一张图片,无法多选
调用摄像头接口:
plus.camera.getCamera().captureImage(function(e){
console.log("e is" + e);
plus.io.resolveLocalFileSystemURL(e, function(entry) {
var path = entry.toLocalURL();
console.log(path);
$("#albumCoverImg").attr("src",path) ;
//upload(path);
}, function(e) {
mui.toast("读取拍照文件错误:" + e.message);
});
});
3.上传问题
可以选择图片并返回图片的路径以后,上传图片又成了一个问题。
由于只能获取到图片的物理路径,js是无法只通过一个物理路径就上传这个文件的。因为浏览器的安全机制,所以得操作必须由用户点击来获取,只能使用h5中的input file才能获取到文件并保存到fileList中,且此数组为只读,外界获取不到,关于file可以看看这个https://blog.csdn.net/lianzhang861/article/details/80283120
所以这就不能直接将图片放在form中上传了,只能通过5+的上传模块上传
5+ uploader模块官方文档:http://www.hcoder.net/tutorials/info_108.html
原理应该就是通过http 的post请求上传文件
//服务端接口路径
var server = ip+"package/uploadImg";
// 上传文件
function upload(path){
console.log(server)
var wt=plus.nativeUI.showWaiting();
var task=plus.uploader.createUpload(server,
{method:"POST"},
function(t,status){ //上传完成
if(status==200){
var data=JSON.parse(t.responseText);
alert("上传成功:"+t.responseText);
wt.close(); //关闭等待提示按钮
}else{
alert("上传失败:"+status);
wt.close();//关闭等待提示按钮
}
}
);
//添加其他参数
task.addData("name","test");
task.addFile(path,{key:"file"});
task.start();
}
代码就是上述所写,server为上传的服务端接口,如果上传成功,则回调的status会返回200,不成功或者接口参数有问题会返回400或者500。t.responseText返回服务端返回的结果,一般服务端会返回json,解析一下json就可以使用了。
传输其他文件时如果还想添加其他参数,用.addData(key,value),添加图片用.addFile(图片路径,{key:后端接收文件的名字}),
配合后端代码看会好理解,后端我用java接收的:
后端代码
@RequestMapping(value = "/uploadImg", produces = "text/html;charset=utf-8")
@ResponseBody
public String uploadImg(@RequestParam Map<String, Object> paramMap,
@RequestParam(value = "file") MultipartFile file,HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
String path=request.getSession().getServletContext().getRealPath("/")+"images\\";
try {
Map<String,String> name=uploadFile(path,file, request);
map.put("success", true);
map.put("code", "0");
map.put("msg", "图片上传成功!");
map.put("data","images/"+name.get("saveName"));
} catch (Exception e) {
e.printStackTrace();
map.put("success", false);
map.put("code", "-10");
map.put("msg", "图片上传失败!");
}
return JSON.toJSONString(map);
}
public Map<String,String> uploadFile(String path,MultipartFile file, HttpServletRequest request) throws IOException {
Map<String,String> result=new HashMap<String,String>();
String fileName = file.getOriginalFilename();
// String basePath=request.getSession().getServletContext().getRealPath("/");
// path=basePath+path; //设置文件保存路径
// File tempFile = new File(path, new Date().getTime() + String.valueOf(fileName));
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
String saveName=String.valueOf((new Date()).getTime()).substring(8)+(int)((Math.random()*999+1))+'.'+fileType;
//File tempFile = new File(basePath+path, String.valueOf(saveName));
File tempFile = new File(path, String.valueOf(saveName));
if (!tempFile.getParentFile().exists()) { //创建文件夹
tempFile.getParentFile().mkdir();
}
if (!tempFile.exists()) {
tempFile.createNewFile();
}
file.transferTo(tempFile);
result.put("fileName",fileName);
result.put("saveName",saveName);
return result;
}
用标准的MultipartFile接收即可。
返回图片的保存路径,用来配合其他表单一起提交。
前端完整代码示例:
<!DOCTYPE HTML>
<html>
<head>
<title>情报制作</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="../css/mui.min.css">
<link rel="stylesheet" href="../css/font-awesome-4.7.0/css/font-awesome.css" />
<script src="../js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body style="background-color: #f3f6f9;">
<div style="height:500px;width:500px;overflow: hidden;">
<img src="" alt="" id="albumCoverImg" style="width:100%;"/>
</div>
<button type="button" onclick="appendByGallery()">相册</button>
<button type="button" onclick="appendByCamera()">拍摄</button>
<script src="../js/mui.js"></script>
<script type="text/javascript">
//扩展API完成后执行的操作
function plusReady(){
//page.imgUp();
}
//弹出系统按钮选择框
/*var page=null;
page={
imgUp:function(){
var m=this;
plus.nativeUI.actionSheet({cancel:"取消",buttons:[
{title:"拍照"},
{title:"从相册中选择"}
]}, function(e){//1 是拍照 2 从相册中选择
switch(e.index){
case 1:appendByCamera();break;
case 2:appendByGallery();break;
}
});
}
} */
// 拍照添加文件
function appendByCamera(){
plus.camera.getCamera().captureImage(function(e){
console.log("e is" + e);
plus.io.resolveLocalFileSystemURL(e, function(entry) {
var path = entry.toLocalURL();
$("#albumCoverImg").src = path;
$("#albumCoverImg").attr("src",path) ;
upload(path);
}, function(e) {
mui.toast("读取拍照文件错误:" + e.message);
});
});
}
// 从相册添加文件
function appendByGallery(){
plus.gallery.pick(function(path){
console.log(path);
$("#albumCoverImg").attr("src",path) ;
upload(path);
});
}
//服务端接口路径
var server ='http://192.168.100.149:8085/packagePK/package/uploadImg';
// 上传文件
function upload(path){
console.log(server)
var wt=plus.nativeUI.showWaiting();
var task=plus.uploader.createUpload(server,
{method:"POST"},
function(t,status){ //上传完成
if(status==200){
var data=JSON.parse(t.responseText);
console.log(data.data);
alert("上传成功:"+t.responseText);
wt.close(); //关闭等待提示按钮
}else{
alert("上传失败:"+status);
wt.close();//关闭等待提示按钮
}
}
);
//添加其他参数
task.addData("name","test");
task.addFile(path,{key:"file"});
task.start();
}
//扩展API是否准备好,如果没有准备好则监听plusReady
if(window.plus){
plusReady();
}else{
document.addEventListener("plusready",plusReady,false);
}
</script>
</body>
</html>