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

FileUpload+WebUploader

WebUploader官网 跳转

FileUpload API 跳转

使用的框架Springboot+mybatis

在这里插入图片描述

POM文件
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>
前端代码 WebUpload

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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 = $(
                    '<div id="' + file.id + '" class="file-item thumbnail">' +
                    '<img>' +
                    '</div>'
                    ),
                    $img = $li.find('img');
                // $list为容器jQuery实例
                $list.append( $li );
                // 创建缩略图 如果为非图片文件,可以不用调用此方法。
                uploader.makeThumb( file, function( error, src ) {
                    if ( error ) {
                        $img.replaceWith('<span>不能预览</span>');
                        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 = $('<p class="progress"><span></span></p>')
                        .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>
<!--dom结构部分-->
<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的最大灵活性。工厂对每个项目的创建方式拥有最终控制权。

在这里插入图片描述

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);
    }
}

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

在这里插入图片描述

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

这里就是缺少了isFormField的判断

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

正确写法

在这里插入图片描述
在这里插入图片描述

本来到这里一个图片上传已经结束了,但是我发现虽然说已经成功上传但是这并不能满足我们实际开发中的需求,这只能说是一个小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);
    }

这时候我们有遇到了新的问题:发现我们访问不了图片了,我们来看一下啊
在这里插入图片描述

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

在这里插入图片描述

关于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加载静态资源.
其实我也不知道有没有这个必要

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
接下来我们进行源码追踪
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;

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

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值