咱们先看一下效果
html
继上一篇的图片上传和回显,咱们来实战一下图片上传的整个过程,今天咱们将打通先后端,咱们来真实的了解一下,咱们上传的文件,是以什么样的形式上传到服务器,难道也是一张图片?等下咱们来揭晓前端
咱们在实战开始前呢,咱们先作一下准备工做,好比新建一个java web工程,若是你不懂这个的话,那我建议你先学一下Javaweb,能够去个人公众号找一下这方面的教程。咱们就给咱们的工程起名为UpImg,咱们再给他建一个web包和util包,再把咱们之前前端作的图片回显的代码拷到工程里,咱们来看一下项目java
咱们发布一下项目来看一下
web
这样的话,咱们基本的框架就作好了,咱们今天就先用form表单来实战一下图片的上传,下一期咱们就经过ajax来实现异步图片上传,咱们先给咱们的前端代码加点料ajax
<form action="upload" method="post" enctype="multipart/form-data"> <div class="uploadImgBtn" id="uploadImgBtn"> <input class="uploadImg" type="file" name="file" multiple id="file"> </div> <input type="submit" value="上传"> </form>
这个样式我就再也不美化了,咱们来看一下效果
这样的话,咱们前端基本就完成了,我来说解一下部分代码吧;表单的enctype属性:后端
一、默认属性:application/x-www-form-urlencoded,只处理表单域中的value属性值,采用这种编码的方式的表单会将表单域的值处理成url编码方式tomcat
二、multipart/form-data,这种编码方式的表单会以二进制流的方法来处理表单数据。这种编码方式会将文件域指定文件的内容也封装到请求参数里服务器
三、text/plain,这种方式主要适用于直接经过表单发送邮件的方式app
接下来咱们讲解一下文件上传的思路,
一、先是表单提交
二、对数据和附件进行二进制编码
三、servlet中使用二进制流获取内容框架
思路咱们已经知道了,那咱们就开始编码吧
咱们先在util包下新建一个类,我就起名为UpImgUtils,接下来咱们就编码吧
package util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import javax.servlet.http.HttpServletRequest; /** * upload Img Utils * * @author admin * */ public class UpImgUtils { /* * 思路 一、从request当中获取流信息 * 二、新建一个临时文件,用输出流指向这个文件 * 三、关闭流 */ public static void keepFile(HttpServletRequest request) throws IOException { // 一、从request当中获取流信息 InputStream fileSource = request.getInputStream(); /* * 临时文件的存储路径(咱们在webContent下新建一个temp文件夹,发布项目的时候极可能由于temp为空, * 没在tomcat中创建一个文件夹,到时候本身在发布的项目中添加一个便可) */ String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt"; // 二、新建一个临时文件,用输出流指向这个文件 // 建一个文件 File tempFile = new File( tempFileName ); // 用输出流指向这个文件 FileOutputStream outputStream = new FileOutputStream( tempFile ); //咱们就每次读写10K,咱们的文件小,这个就已经够用了 byte[] b = new byte[1024*10]; int n = 0 ; //读写文件,-1标识为空 while( (n = fileSource.read(b) ) != -1 ) { outputStream.write(b, 0, n); } // 三、关闭流 fileSource.close(); outputStream.close(); } }
这个类就是用来读取form表单传来的字节流,写到一个临时文件中,咱们就一个servlet来调用一下咱们的工具来看看效果。
package web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import util.UpImgUtils; public class upload extends HttpServlet { private static final long serialVersionUID = 1L; public upload() { super(); // TODO Auto-generated constructor stub } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub UpImgUtils.keepFile(request); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } }
代码已经写好,个人项目是java web项目2.5的版本,会自动配置servlet,配置的话,就再也不讲解。咱们来运行看一下效果
咱们已经看到了,实际上文件上传就是把文件的二进制流上传到服务端,这难道就结束了吗?
那确定不可能啊,咱们上传的是个图片,那咱们确定但愿仍是图片啊,咱们就来从新封装一个工具类,在封装以前,咱们先看一下临时文件的格式
这是我随便找的两个文件,上传后生成的临时文件,咱们就不实战封装两个文件了,咱们就实战一下封装一个临时文件,所以呢咱们先把input标签中的multiple属性去掉,把咱们的前端自动生成input标签的代码也先注释掉,咱们先看一下改动的代码
<script> $(document).ready(function(){ //为外面的盒子绑定一个点击事件 $("#uploadImgBtn").click(function(){ /* 一、先获取input标签 二、给input标签绑定change事件 三、把图片回显 */ // 一、先回去input标签 var $input = $("#file"); console.log($input) // 二、给input标签绑定change事件 $input.on("change" , function(){ console.log(this) //补充说明:由于咱们给input标签设置multiple属性,所以一次能够上传多个文件 //获取选择图片的个数 var files = this.files; var length = files.length; console.log("选择了"+length+"张图片"); //三、回显 $.each(files,function(key,value){ //每次都只会遍历一个图片数据 var div = document.createElement("div"), img = document.createElement("img"); div.className = "pic"; var fr = new FileReader(); fr.onload = function(){ img.src=this.result; div.appendChild(img); document.body.appendChild(div); } fr.readAsDataURL(value); }) }) //把这下面的注释掉便可 // //四、咱们把当前input标签的id属性remove // $input.removeAttr("id"); // //咱们作个标记,再class中再添加一个类名就叫test // var newInput = '<input class="uploadImg test" type="file" name="file" multiple id="file">'; // $(this).append($(newInput)); }) }) </script>
咱们来看一下一个文件的时候,临时文件的格式
咱们来分析一下,第二行的filename是咱们须要的,这是文件的名称,咱们已经看到中文名称乱码,一会编码的时候,咱们须要解决一下;第4行有一个空行,到第5行的时候才到咱们的正文部分;咱们的正文结束的时候会有一个空格;既然知道了这些,咱们就去完善一下咱们的工具类吧
package util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import javax.servlet.http.HttpServletRequest; /** * upload Img Utils * * @author admin * */ public class UpImgUtils { /* * 思路 一、从request当中获取流信息 * 二、新建一个临时文件,用输出流指向这个文件 * 三、关闭流 */ public static void keepFile(HttpServletRequest request) throws IOException { // 一、从request当中获取流信息 InputStream fileSource = request.getInputStream(); /* * 临时文件的存储路径(咱们在webContent下新建一个temp文件夹,发布项目的时候极可能由于temp为空, * 没在tomcat中创建一个文件夹,到时候本身在发布的项目中添加一个便可) */ String tempFileName = request.getServletContext().getRealPath("/") + "temp/tempfile.txt"; //二、新建一个临时文件,用输出流指向这个文件 //建一个文件 File tempFile = new File( tempFileName ); //用输出流指向这个文件 FileOutputStream outputStream = new FileOutputStream( tempFile ); //咱们就每次读写10K,咱们的文件小,这个就已经够用了 byte[] b = new byte[1024*10]; int n = 0 ; //读写文件,-1标识为空 while( (n = fileSource.read(b) ) != -1 ) { outputStream.write(b, 0, n); } //三、关闭流 fileSource.close(); outputStream.close(); //第二部分...................................................... /** * 思路 * 一、获取文件的名称,并解决中文乱码 * 二、获取文件的内容 * 三、保存文件 */ //第二部分 一、获取文件的名称,并解决中文乱码 RandomAccessFile randomFile = new RandomAccessFile(tempFile,"r"); randomFile.readLine();//先读取一行 String str = randomFile.readLine();//读取第二行 int beginIndex = str.lastIndexOf("filename=\"") + 10;//定位到文件名开始的地方 int endIndex = str.lastIndexOf("\"");//定位到文件名结尾的地方 String filename = str.substring(beginIndex, endIndex); //判断文件名是全路径名仍是只是文件名(google和火狐是只是文件名,微软系列是全路径名) endIndex = filename.lastIndexOf("\\") + 1; if( endIndex > -1 ) { filename = filename.substring(endIndex); } //通过上面的这几步,咱们就已经获取到了文件名,咱们还须要解决一下中文名乱码的问题 //解决上传文件中文名字乱码 filename = new String(filename.getBytes("ISO-8859-1"), "UTF-8"); System.out.println("filename: " + filename ); //第二部分 二、获取文件的内容 //从新定位文件指针到文件头 randomFile.seek(0); long startPosition = 0L;//正文开始的位置 int i = 1; while( ( n = randomFile.readByte() ) != -1 && i <=4 ) { if( n == '\n') { startPosition = randomFile.getFilePointer(); i++; } } // startPosition = randomFile.getFilePointer() - 1 ; //获取文件内容,结束位置 randomFile.seek(randomFile.length() );//指针定位到尾部 long endPosition = randomFile.getFilePointer(); int j = 1; while( endPosition >= 0 && j <=2 ) { endPosition--; randomFile.seek(endPosition); if(randomFile.readByte() == '\n' ) { j++; } } endPosition = endPosition - 1; //第二部分 三、保存文件 //设置保存上传文件的路径,咱们好保存到temp中 String realPath = request.getServletContext().getRealPath("/") + "temp"; File fileupload = new File( realPath ); File saveFile = new File(realPath,filename); RandomAccessFile randomAccessFile = new RandomAccessFile(saveFile,"rw"); // //从临时文件当中读取文件内容(根据起止位置获取) randomFile.seek(startPosition); while(startPosition < endPosition ) { randomAccessFile.write(randomFile.readByte()); startPosition = randomFile.getFilePointer(); } // //关闭输入输出流、删除临时文件 randomAccessFile.close(); randomFile.close(); //tempFile.delete(); } }
咱们来看一下效果
这样的话,咱们的上传图片也已经上传成功了,咱们来把上传图片的url反回给前端吧,这些代码就再也不展现,本身实现一下吧。