时隔上次写博客有个把月了,主要最近一段时间上班很忙,加上带娃,各种杂碎的事情繁多,一下子一天一下子一周一下子一个月就过去了,心中也有愧疚,所以为什么说奋斗要在30岁前,因为那时候你最年轻,有活力,有时间,有精力,没房贷,没车贷,没孩子,没老婆,父母年轻,一天到晚出了上班没点P事,如果能回到五年前,说实话,我也想改变点生活状态,比如去健身,去旅行,还有大把的时间学习新知识,否则,就只能像我一样,现在有了斗志的心,却每天被柴米油盐的琐事困扰着,有些朋友会说,都是你自己给自己找借口,责任这种东西怎么说,你去付了,就是有责任感,你去负了,就是没责任感,看个人吧,至少,我喜欢我的小家庭,疼爱我的老婆,小女儿,我希望能陪她们,等到女儿睡了,基本时间就不多了,你说可以熬夜,也是个人问题吧,我有乙肝大三阳,病毒指数也是8次方级别的,医生也建议不要熬夜,我也希望健康第一位,所以,所以,哈哈哈,家家有本难念的经,好了,闲扯几句,反正都不认识,反正只是瞎bb,说正事。
除去前面一些个人原因,这次这么久更新,主要是因为这次的功能是上传头像,其实就是上传图片,这个功能在任何web开发或者是app开发都是至关重要的,导致,这里面有许多坑,我也是花了好久,查了好多资料,才顺利解决,而且你的技术选型不一样,导致很多代码不一样,网上资料也非常少,走了不少弯路,开心的是,还是解决了,还是那句老话,之所以贴代码,只是为了帮助那些需要的人,我相信在这个地球的某处还是有人被一样的问题困扰,或者说没有我那么幸运找到最终解决方案,所以自己记录,顺便做做善事。
先说逻辑吧,上传图片(或者上传文件,逻辑类似),既然我们使用的是MUI+SPRING MVC,首先我们要考虑的是,前台如何上传,我考虑过两种方式,第一种就是前台将图片转换成BASE64编码,然后mui.post直接传送到后台,后台解析BASE64编码的图片,保存,这种方法理论是可行的,缺点很明显,你上传的图片要足够小,不然那个BASE64的编码能恶心死你,所以我直接说第二种方法,就是使用H5的upload方法,字节流的方式上传图片,后台按字节流接收图片。当然为了考虑图片上传效率,和使用性价比,我们在上传前,进行压缩。代码如下:
//点击头像,弹出【拍照,从相册选择】,因为用到很多H5的函数,则在plusReady里执行
mui.plusReady(function(){
// 上传文件
var filepath;
var newUrlAfterCompress;
imgdiv.addEventListener('tap',function(){
if(mui.os.plus){
var a=[{
title:'拍照'
},{
title:'从手机相册选择'
}];
plus.nativeUI.actionSheet({
title:'修改头像',
cancel:'取消',
buttons:a
},function(b){
switch(b.index){
case 0:
break;
case 1:
//拍照
getImages();
break;
case 2:
//打开相册
galleryImages();
break;
default:
break;
}
},false);
}
});
//拍照
function getImages(){
var mobileCamera=plus.camera.getCamera();
mobileCamera.captureImage(function(e){
plus.io.resolveLocalFileSystemURL(e,function(entry){
var path=entry.toLocalURL()+'?version='+new Date().getTime();
// console.log("camera:"+path);
var dstname="_downloads/"+getUid()+".jpg";//设置压缩后图片的路径
compressImage(path,dstname,0);
// filepath = newUrlAfterCompress;
},function(err){
console.log("读取拍照文件错误");
});
},function(e){
console.log("er",err);
},function(){
filename:'_doc/head.png';
});
}
//从本地相册选择
function galleryImages(){
console.log("你选择了从相册选择");
plus.gallery.pick(function(a){
plus.io.resolveLocalFileSystemURL(a,function(entry){
plus.io.resolveLocalFileSystemURL('_doc/',function(root){
root.getFile('head.png',{},function(file){
//文件已经存在
file.remove(function(){
console.log("文件移除成功");
entry.copyTo(root,'head.png',function(e){
var path=e.fullPath+'?version='+new Date().getTime();
var dstname="_downloads/"+getUid()+".jpg";//设置压缩后图片的路径
compressImage(path,dstname,270);
// filepath = dstname;
//upload();
},function(err){
console.log("copy image fail: ",err);
});
},function(err){
console.log("删除图片失败:("+JSON.stringify(err)+")");
});
},function(err){
//打开文件失败
entry.copyTo(root,'head.png',function(e){
var path=e.fullPath+'?version='+new Date().getTime();
uploadHeadImg(path);
},function(err){
console.log("上传图片失败:("+JSON.stringify(err)+")");
});
});
},function(e){
console.log("读取文件夹失败:("+JSON.stringify(err)+")");
});
});
},function(err){
console.log("读取拍照文件失败: ",err);
},{
filter:'image'
});
};
// 产生一个随机数
function getUid() {
return Math.floor(Math.random() * 100000000 + 10000000).toString();
}
function upload() {
var task = plus.uploader.createUpload('http://47.96.239.47:8080/yqrcbapp/userInfo/uploadImage', {
method: "POST"
},
function(t, status) { //上传完成
if (status == 200) {
console.log(t.responseText);
imgdiv.innerHTML = '<img id="userImg" src="'+t.responseText+'"/>';
} else {
console.log("上传失败:" + status);
}
}
);
task.addData('username',username);
task.addFile(filepath, {
key:filepath
});
task.start();
}
//压缩图片,这个比较变态的方法,无法return
function compressImage(src,dstname,rotate) {
//var dstname="_downloads/"+getUid()+".jpg";
plus.zip.compressImage({
src: src,
dst: dstname,
overwrite:true,
quality: 20 ,
rotate: rotate
},
function(event) {
console.log("Compress success:"+event.target);
filepath = event.target;
upload();
},
function(error) {
console.log(error);
// filepath = src;
//alert("Compress error!");
});
}
});
前台上传了图片,后台如何接收呢?每种框架接收方式不一样,我选择的是JAVA的MVC框架,所以后台代码如下
@RequestMapping(value="/uploadImage", method=RequestMethod.POST)
@ResponseBody
private String uploadImage(HttpServletRequest request){
String username = (String)request.getParameter("username");
// 复杂类型的request对象
MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
// 获取文件名集合放入迭代器
Iterator<String> files = mRequest.getFileNames();
while (files.hasNext()) {
//获取上传文件的对象
MultipartFile mFile = mRequest.getFile(files.next());
if (mFile != null) {
//
// String path= "";
try {
byte[] bytes = mFile.getBytes();
// // 当前app根目录
// String rootPath = request.getServletContext().getRealPath("/");
//
// // 需要上传的相对地址(application.properties中获取)
// String relativePath = "img";
//
// // 文件夹是否存在,不存在就创建
// File dir = new File(rootPath + File.separator + relativePath);
// if (!dir.exists())
// dir.mkdirs();
// // String fileExtension = getFileExtension(file);
String filename1 = mFile.getOriginalFilename();
String fileExtension = filename1.substring(filename1.lastIndexOf(".")+1);
//
// 生成UUID样式的文件名
String filename = java.util.UUID.randomUUID().toString() + "." + fileExtension;
//
// // 文件全名
// String fullFilename = dir.getAbsolutePath() + File.separator + filename;
//
//
//
// // 保存图片
// File serverFile = new File(fullFilename);
// BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
// stream.write(bytes);
// stream.close();
//保存图片到图片OSS服务器,然后返回访问地址
String endpoint = "http://oss-cn-beijing.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "***";
String accessKeySecret = "***";
String bucketName = "dreamxieimg";
String objectName = filename;
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 上传文件。<yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
Date expiration = new Date(new Date().getTime() + 3600 * 1000*24);
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
URL url = ossClient.generatePresignedUrl(bucketName,objectName , expiration);
// 关闭OSSClient。
ossClient.shutdown();
Map<String,Object> params = new HashMap<String, Object>();
params.put("img", url.toString());
params.put("username", username);
userInfoService.changeimg(params);
// //将图片访问路径保存在数据库中
// String serverPath = new URL(request.getScheme(), request.getServerName(), request.getServerPort(),
// request.getContextPath()).toString();
return url.toString();
} catch (Exception e) {
e.printStackTrace();
// LOGGER.info("error: {}", e);
}
}
}
return null;
}
注意几点,
1.阿里的OSS服务器提供的jar包可能会与项目jar包冲突,需要自己删除老版本jar包
2.controller只能用request接收,不能用mutiFile接收
具体的都自己看代码吧