2.html通过ajax上传base64的图片,服务端通过Servlet接收数据并在本地创建文件
一、应用场景
本地上传一张图片,回显在img中
然后点击按钮通过ajax上传到服务器,服务器拿到图片在本地保存
二、前端
1.点击按钮本地上传图片,回显在img
首先打开本地文件的需求需要file类型的input,这个input一般不显示出来,用来读取本地文件。那就把这个input设置成隐藏,另外设置一个按钮,点击这个按钮触发上面这个input的onclick()事件。选择好文件之后,input中就有file文件了,这时候通过这是input的onchange()函数(状态改变),进行图片回显。
2.file类型的input,设置成隐藏,状态改变,触发showImg()函数,传入自身
<input type="file" id="btn_file" style="display:none" onchange="showImg(this)">
3.点击按钮,触发F_Open_dialog()函数
<button type="button" class="btn btn-primary" style="font-size:20px" onclick="F_Open_dialog()">点击本地上传</button>
4.F_Open_dialog()函数触发上方input的点击事件,进行本地文件上传操作
<script type="text/javascript">
function F_Open_dialog(){
document.getElementById("btn_file").click();
}
</script>
5.数据上传完成保存在input中,这时候input状态改变,触发showImg()函数
function showImg(input){
var file=input.files[0];
var url=window.URL.createObjectURL(file);
console.log(url)
document.getElementById('myimage').src=url;
}
这里这个files[0]注意是复数,如果input属性multiple="multiple",那么可以同时选中多个文件上传到input中,如果只是一个文件,就是第一个文件,下标是0。
通过URL,创造一个临时的blob资源地址,把这个地址赋给image标签做到照片的回显
blob(Binary Large Object)二进制大对象,file类型的文件是blob的子类。
算是临时给一个文件一个url,这个url只用来回显,传送这个blob地址到后端没用。
6.点击图片上传按钮,触发F_Submit()函数
<button type="button" class="btn btn-primary" style="font-size:20px" onclick="F_Submit()">点击开始识别</button>
7.F_Submit()函数
function F_Submit(){
var file=$("#gou").find("input")[0].files[0];
var reader=new FileReader();
reader.readAsDataURL(file);
var data_64;
reader.onloadend=function(e){
data_64=e.target.result;
console.log(data_64)
var url="myservlet?method=processPicture";
console.log(url)
$.ajax({
url:url,
type:'POST',
data:data_64,
// data:formData
contentType:false,
processData:false,//这个很有必要,不然不行
//dataType:"json",
success:function(data){ document.getElementById('result').innerText = data;
}
});
};
}
找到file类型的图片,通过FileReader的readAsDataURL方法,把file转换成base64类型的数据。这个FileReader读取有一段时间,如果ajax写在外面,这个数据可能还没读完,所以我把ajax写在了FileReader读完的函数内,读完把这个数据塞在data中,url写上你请求的内容。这个data中的数据会放入http报文的body部分。之前想过把base64字符串放在url中,结果报错,显示报文头太长。
还有,传图片一般用post,不限制大小,get方式会限制大小
下面有个success方法,如果ajax请求成功,则执行方法中的内容。
三、服务端(servlet)
1.服务端通过request的getReader()方法得到前端传来的httpbody部分,即ajax的data属性值
BufferedReader reader = req.getReader();
String msg=null;
String line;
while((line=reader.readLine())!=null)
msg+=line;
2.把获取到的base64字符串进行切割操作
String myString=msg.substring(msg.lastIndexOf(',')+1);
本身base64格式如下,从逗号开始切就行,拿后面的主体部分
3.base64字符串转file
public File base64ToFile(String base64str){
System.out.println("base64 to file ....");
if(base64str==null||"".equals(base64str)){
return null;
}
byte[] buff=Base64.decode(base64str);
File file=null;
FileOutputStream fout=null;
try {
file=File.createTempFile("tmp", ".jpg");
fout=new FileOutputStream(file);
fout.write(buff);
} catch (Exception e) {
}
if(fout!=null){
try {
fout.close();
} catch (Exception e) {
}
}
return file;
}
4.本地保存文件(脚本)
public void saveImage(File file){
System.out.println("saveImage..");
String strPath="D:/myImg/1.jpg";
File myfile=new File(strPath);
try {
if(myfile.exists()) //目录下有文件就删除
myfile.delete();
if(!myfile.getParentFile().exists()) //文件夹不存在创建文件夹
myfile.getParentFile().mkdirs();
FileInputStream fin=new FileInputStream(file);
FileOutputStream fout=new FileOutputStream(myfile);
byte[] myByteArray=new byte[(int) file.length()];
int n=0;
while((n=fin.read(myByteArray))!=-1)
fout.write(myByteArray, 0, n);
fout.close();
fin.close();
}
catch (Exception e) {
// TODO: handle exception
}
}
5.最后就是通过上面两个封装好的脚本,把base64数据转换成,file,再保存在本地
6.如果需要给html返回数据,找response对象,找到它的写入器,把内容写入就行,ajax的success函数能收到这个数据
PrintWriter writer=resp.getWriter();
writer.write(myString);
四.小结
1.客户端给服务端传送图片,还能通过formdata的形式,在formdata中直接塞入file类型的数据,通过ajax传送
2.http报文如下
方U协 行头体
这个url在请求行中,不能过长,所以不能放base64的图片
通过ajax传送的data中的数据会放在报头体内
报文头中是一些属性和属性值(键值对)
3.url
URI(Uniform Resourse Identifier)统一资源标识符
URL(Uniform Resourse Locator)统一资源定位符
一个统一资源定位器(URL) 用于定位万维网上的文档
URN(Uniform Resourse Name)统一资源名称
后续可以再研究研究这个url,有点神奇