小白也看得懂的图片上传【FileUpload+WebUploader】

FileUpload+WebUploader

WebUploader官网 跳转

FileUpload API 跳转

使用的框架Springboot+mybatis

小白也看得懂的图片上传【FileUpload+WebUploader】_第1张图片

POM文件

    commons-fileupload
    commons-fileupload
    1.3.1


    commons-io
    commons-io
    2.4

前端代码 WebUpload

这里我其实省略了很多 就是抄的官网上的例子 对于我来说已经够用了,大家有需求的话可以自己去官网查


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="stylesheet" href="../js/webuploader.css">
    <script src="../js/jquery.min.js">script>
    <script src="../js/webuploader.min.js">script>
    <script type="text/javascript">
        $(function () {
            var $list = $("#fileList");
            // 初始化Web Uploader
            var uploader = WebUploader.create({
                // 选完文件后,是否自动上传。
                auto: true,
                // 文件接收服务端。
                server: '/webUploaderController/upload',
                // 选择文件的按钮。可选。
                // 内部根据当前运行是创建,可能是input元素,也可能是flash.
                pick: '#filePicker',
                // 只允许选择图片文件。
                accept: {
                    title: 'Images',
                    extensions: 'gif,jpg,jpeg,bmp,png',
                    mimeTypes: 'image/*'
                },
                duplicate:true
            });
            // 当有文件添加进来的时候
            uploader.on( 'fileQueued', function( file ) {
                var $li = $(
                    '
+ file.id + '" class="file-item thumbnail">' + '' + '
'
), $img = $li.find('img'); // $list为容器jQuery实例 $list.append( $li ); // 创建缩略图 如果为非图片文件,可以不用调用此方法。 uploader.makeThumb( file, function( error, src ) { if ( error ) { $img.replaceWith('不能预览'); return; } $img.attr( 'src', src ); }, '100', '100' ); }); // 文件上传过程中创建进度条实时显示。 uploader.on( 'uploadProgress', function( file, percentage ) { var $li = $( '#'+file.id ), $percent = $li.find('.progress span'); // 避免重复创建 if ( !$percent.length ) { $percent = $('

'
) .appendTo( $li ) .find('span'); } $percent.css( 'width', percentage * 100 + '%' ); }); // 文件上传成功,给item添加成功class, 用样式标记上传成功。 uploader.on( 'uploadSuccess', function( file,obj ) { var data = obj._raw; alert(data); }); })
script> head> <body> <div id="uploader-demo"> <div id="fileList" class="uploader-list">div> div> <div id="filePicker">选择图片div> body> html>

注意这里默认为 multipart/form-data类型,不需要我们再去像jsp一样手动定义

后端代码 FileUpload

注意注意:在Springboot中有默认的文件上传组件,我们在使用Apache Commons FileUpload组件的时候需要关闭Springboot的默认配置 !!!

spring.servlet.multipart.enabled=false

否则我们使用FileUpload组件上传文件时总是返回null

FileUpload使用FileItemFactory创建新的文件项。这就是FileUpload的最大灵活性。工厂对每个项目的创建方式拥有最终控制权。

小白也看得懂的图片上传【FileUpload+WebUploader】_第2张图片

if (isMultipart){
    //创建工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    //创建文件上传处理程序
    ServletFileUpload upload = new ServletFileUpload(factory);
    //解析请求
    List<FileItem> items = upload.parseRequest(request);
    //处理文件项列表
    Iterator<FileItem> iter = items.iterator(); //次数的size为6
    while (iter.hasNext()){
        FileItem item = iter.next();
        String fieldName = item.getFieldName();
        String itemName = item.getName();
        filePath = filePath + itemName;
        File uploadFile = new File(filePath);
        item.write(uploadFile);
    }
}

文件已经成功写入到指定路径,让我们来看看效果

小白也看得懂的图片上传【FileUpload+WebUploader】_第3张图片

我们发现有很多异常数据 ,从这里我们可以看出遍历了六次只有最后一次才正真的获取到了文件对象。

这里就是缺少了isFormField的判断

只要当它是文件的时候我们才进行写入

正确写法

小白也看得懂的图片上传【FileUpload+WebUploader】_第4张图片
小白也看得懂的图片上传【FileUpload+WebUploader】_第5张图片

本来到这里一个图片上传已经结束了,但是我发现虽然说已经成功上传但是这并不能满足我们实际开发中的需求,这只能说是一个小demo罢了,那我们在实际开发中是怎么样的呢,在我们项目发布的时候我们需要将图片上传到你部署的tomcat(服务器)中,平时测试开发过程中也是上传到你本地部署的tomcat上。那这个时候我们就需要对路径进行配置了

好。上配置文件 毕竟都2020年了嘛 现在咱们做开发的要求什么 解耦解耦嘛,就不把路径写死了方便修改。

# 图片上传路径
imgUploadPath=D:\\Workspace\\IDEA_WORK\\IDEA2018\\myframe\\src\\main\\resources\\static\\img\\
# 图片访问路径
imgAccessPath=http://localhost:8089/img/
# 资源解析路径 虚拟路径
pathPatterns=/img/**

那这时候就需要一个获取properties的工具类了

PropertiesUtil
public class PropertiesUtil {
    public static String getPropInfo(String key){
        String propInfo = null;
        try {
            String propFile = "myframe.properties";
            InputStream stream = Thread.currentThread().
                getContextClassLoader().getResourceAsStream(propFile);
            Properties properties = new Properties();
            properties.load(stream);
            propInfo = properties.getProperty(key);
        }catch (Exception e){
            e.printStackTrace();
        }
        return propInfo;
    }
}

这时候我们再来改进下我们的图片上传Controller

@RequestMapping("/upload")
    public void upload(HttpServletRequest request, HttpServletResponse response) throws Exception{
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        String savePath = PropertiesUtil.getPropInfo("imgUploadPath");
        String accessPath = PropertiesUtil.getPropInfo("imgAccessPath");
        //检测是否有文件上传请求
        if (isMultipart){
           //创建工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //创建文件上传处理程序
            ServletFileUpload upload = new ServletFileUpload(factory);
            //解析请求
            List<FileItem> items = upload.
                (request);
            //处理文件项列表
            Iterator<FileItem> iter = items.iterator();
            while (iter.hasNext()){
                FileItem item = iter.next();
                if (!item.isFormField()){
                    String itemName = item.getName();
                    savePath = savePath + itemName;
                    accessPath = accessPath + itemName;
                    File uploadFile = new File(savePath);
                    item.write(uploadFile);
                }
            }
        }
        //返回给前端的和图片保存的路径不是同一个
        response.setCharacterEncoding("UTF-8");
        response.getWriter().print(accessPath);
    }

这时候我们有遇到了新的问题:发现我们访问不了图片了,我们来看一下啊
小白也看得懂的图片上传【FileUpload+WebUploader】_第6张图片

我们直接复制路径取查找 404 找不到,我可是好找啊,路径没问题啊,最后发现是少了配置

小白也看得懂的图片上传【FileUpload+WebUploader】_第7张图片

关于springboot的文件上传配置
//WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制
//WebMvcConfigurer类作用: 用于web的配置
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurer {
 	//此方法注册一个Handler 用来处理静态资源,配置静态资源的虚拟路径
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) { 
         //通过pathPatterns中的请求来访问 imgUploadPath 下的静态资源
        registry.addResourceHandler(PropertiesUtil.getPropInfo("pathPatterns")).
        addResourceLocations("file:"+ PropertiesUtil.getPropInfo("imgUploadPath"));
    }

好到这里大功告成啦,我这里说一下上面的html代码中我的图片回显,为了方便用的是 webuploader的缩略图预览,没有使用后台返回的值,大家有需求的话只要在 uploader.on( ‘uploadSuccess’, function( file,obj ) 中获取obj就是了 [你的图片路径]。

这里我还是要了spring-boot-starter-thymeleaf加载静态资源.
其实我也不知道有没有这个必要

 
     org.springframework.boot
     spring-boot-starter-thymeleaf
 
接下来我们进行源码追踪
FileItemFactory
FileItem createItem(
    String fieldName,
    String contentType,
    boolean isFormField,
    String fileName
);
createItem:
 	从提供的参数和本地配置来创建一个FileItem实例
DiskFileItemFactory
//用于创建FileItem的工厂
//这个实现用于创建org.apache.commons.fileupload.FileItem 实例,对与较小的项目将他们保存在内存中,较大的项目保存在磁盘上。
public class DiskFileItemFactory implements FileItemFactory {
    /**
     * 将文件保存在内存还是磁盘临时文件夹的默认临界值,值为10240,即10kb。
     */
    public static final int DEFAULT_SIZE_THRESHOLD = 10240;
    /**
     * 这里实际调用的就是
     * DiskFileItemFactory(int sizeThreshold, File repository)构造
     * 参数一:采用默认临界值和
     * 参数二:如果项目的大小超过默认连接之则会在repository中创建目录
     */
    public DiskFileItemFactory() {
        this(DEFAULT_SIZE_THRESHOLD, null);
    }
    
    public DiskFileItemFactory(int sizeThreshold, File repository) {
        this.sizeThreshold = sizeThreshold;
        this.repository = repository;
    }
}
ServletFileUpload
//这个类用来处理每个HTML的多个文件
//各个部件的数据存储方式由用于创建它们的工厂决定;可能在内存、磁盘或其他地方。
public class ServletFileUpload extends FileUpload {
	 /**
	  * 创建ServletFileUpload实例参数为 FiltItem工厂
      */
     public ServletFileUpload(FileItemFactory fileItemFactory) {
        super(fileItemFactory);
    }
    /**
     * 从请求中获取FileItem实例的列表
     */
    @Override
    public List<FileItem> parseRequest(HttpServletRequest request)
    throws FileUploadException {
        return parseRequest(new ServletRequestContext(request));
    }
}

我们来看一下最重要的FileItem

//头部注释一大推
//其实就是对接收到的文件或表单项的一些操作.
//我们来看一下我们经常会使用到的一些方法
public interface FileItem extends Serializable, FileItemHeadersSupport {
    InputStream getInputStream() throws IOException;
	//获得上传文件的类型
    String getContentType();
	//获得文件上传字段中的文件名。
    String getName();
	//判断FileItem存储在内存中,还是存储在临时文件中
    boolean isInMemory();
	//返回该上传文件的大小(以字节为单位)。
    long getSize();
	//将FileItem对象中保存的数据流内容以一个字符串返回 通常使用第一个可以指定字符集 不会出现乱码
    String getString(String encoding) throws UnsupportedEncodingException;
    String getString();
	//write方法用于将FileItem对象中的内容写入到指定的文件中。
    void write(File file) throws Exception;
	//清空fileItem中存放的内容
    void delete();
    //判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段
    boolean isFormField();
	//以流的形式返回上传文件的数据内容。
    OutputStream getOutputStream() throws IOException;

我这里花了张构造流程图大家可以看一下

小白也看得懂的图片上传【FileUpload+WebUploader】_第8张图片

你可能感兴趣的:(小白也看得懂的图片上传【FileUpload+WebUploader】)