0


SpringBoot简单优雅实现图片上传功能(超详细)

文章目录


前言

最近有一个需求需要实现图片上传,因此,本人找到了一个可以快速实现该功能的插件mini-upload-form。在此记录分享一下使用过程。

mini-upload-form的Github跳转
在这里插入图片描述
将程序从github拉下后,前端页面index.html可简单修改后直接使用,我们的精力主要放在后端实现。

技术栈

  • jdk1.8.0_162
  • maven-3.3.9
  • mybatis-plus

项目目录

在这里插入图片描述

需将mini-upload-from中assets文件下的资源引入自己项目中。除外还需引入bootstrap和jquery。

前端实现

index.html

<!DOCTYPEhtml><html><head><metacharset="utf-8"/><title>Mini Ajax File Upload Form</title><!-- The main CSS file --><linkhref="mini-upload-form/css/style.css"rel="stylesheet"/><linkhref="bootstrap/css/bootstrap.css"rel="stylesheet"/></head><body><divclass="row"><divclass="col align-self-start"><div><h4>上传照片:</h4></div><divclass="d-flex flex-row flex-wrap mb-5"id="upload-img-container"><p>暂无</p></div></div></div><divclass="row"><divclass="col align-self-start"><formid="upload"method="post"action="/file/upload"enctype="multipart/form-data"><divid="note"class="text-white"></div><divid="drop">
                拖到此区域
                <a>浏览本地</a><inputid="uploadFile"type="file"name="file"multiple/></div><ul><!-- The file uploads will be shown here --></ul></form><divclass="col align-self-start"></div><divclass="row"><divclass="col align-self-start"><divclass="text-center"><atype="button"id="submit-file-btn"class="text-center btn btn-info text-white">提交</a></div></div></div></div></div><scriptsrc="js/jquery-1.11.3.js"></script><scriptsrc="bootstrap/js/bootstrap.js"></script><scriptsrc="mini-upload-form/js/jquery.knob.js"></script><!-- jQuery File Upload Dependencies --><scriptsrc="mini-upload-form/js/jquery.ui.widget.js"></script><scriptsrc="mini-upload-form/js/jquery.iframe-transport.js"></script><scriptsrc="mini-upload-form/js/jquery.fileupload.js"></script><!-- Our main JS file --><scriptsrc="mini-upload-form/js/script.js"></script></body></html>

script.js

本文还实现了上传成功后回写到前端页面,所以需修改script.js添加提交成功后回调函数。

// Automatically upload the file once it is added to the queuevar jqXHR = data.submit().success(function(result){var status = result['code'];var fileUri = result['fileUri'];var fileId = result['fileId'];var originFileName = result['originFileName'];if(status!='200'){
                    data.context.addClass('error');
                    numError++;}else{
                    images.push(fileId)
                    localStorage.setItem('cd_files',JSON.stringify(images))
                    numSuccess++;$("#upload-img-container>p:nth-child(1)").remove()const imageHTML ="<div style='width:100px;height:100px;margin:.5rem;text-align:center'>"+"<image class='rounded' style='width:100%;height:100%' src="+staticServer + fileUri +" alt=>"+"<p class='text-center text-muted ' style='word-wrap: break-word;'>"+originFileName+"</p></div>";$("#upload-img-container").append(imageHTML)}updateNote();});
// Update the notefunctionupdateNote(){if($('#note').length)$('#note').html('<span>'+ numSuccess +'</span> 个成功上传.<br /><span id="note-error">'+ numError +'</span> 个上传失败.'+(numError >0?' <a href="#" id="btn-retry"> (Retry all)</a>':''));}

后端实现

MultipartFile 介绍

MultipartFile是SpringMVC提供简化上传操作的工具类。

在不使用框架之前,都是使用原生的HttpServletRequest来接收上传的数据,文件是以二进制流传递到后端的,然后需要我们自己转换为File类。使用了MultipartFile工具类之后,我们对文件上传的操作就简便许多了。
MultipartFile接口方法

packageorg.springframework.web.multipart;importjava.io.File;importjava.io.IOException;importjava.io.InputStream;importjava.nio.file.Files;importjava.nio.file.Path;importorg.springframework.core.io.InputStreamSource;importorg.springframework.core.io.Resource;importorg.springframework.lang.Nullable;importorg.springframework.util.FileCopyUtils;publicinterfaceMultipartFileextendsInputStreamSource{//getName() 返回参数的名称StringgetName();//获取源文件的昵称@NullableStringgetOriginalFilename();//getContentType() 返回文件的内容类型@NullableStringgetContentType();//isEmpty() 判断是否为空,或者上传的文件是否有内容booleanisEmpty();//getSize() 返回文件大小 以字节为单位longgetSize();//getBytes() 将文件内容转化成一个byte[] 返回byte[]getBytes()throwsIOException;//getInputStream() 返回InputStream读取文件的内容InputStreamgetInputStream()throwsIOException;defaultResourcegetResource(){returnnewMultipartFileResource(this);}//transferTo(File dest) 用来把 MultipartFile 转换换成 FilevoidtransferTo(File var1)throwsIOException,IllegalStateException;defaultvoidtransferTo(Path dest)throwsIOException,IllegalStateException{FileCopyUtils.copy(this.getInputStream(),Files.newOutputStream(dest));}}

配置文件

# server
server.port=8010

# datasource
spring.datasource.url=jdbc:mysql://xxxx:3306/upload?characterEncoding=utf-8&useSSL=false
spring.datasource.username=***
spring.datasource.password=****
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 
# upload size setting
spring.servlet.multipart.max-file-size=30MB
spring.servlet.multipart.max-request-size=30MB       

file.upload.dir=D://upload
file.visit.path=upload

实体类

图片存储实体类SysFile

@Data@Builder@TableName("sys_file")publicclassSysFile{privateString fileId;privateString mediaType;privateString fileFormat;privateString filePath;privateString originalName;privateLong fileSize;privateInteger imageWidth;privateInteger imageHeight;privateString createUserId;privateDate createDate;privateString updateUserId;privateDate updateDate;}

Controller

@RestController@RequestMapping("/file")publicclassFileUploadController{@AutowiredprivateLocalStorageService localStorageService;@RequestMapping("/upload")publicAjaxResultupload(@RequestParam("file")MultipartFile file)throwsException{try{if(file.isEmpty()){thrownewRuntimeException("上传文件不能为空");}return localStorageService.upload(file);}catch(Exception e){
            e.printStackTrace();returnAjaxResult.error("文件上传失败");}}}

AjaxResult

publicclassAjaxResultextendsHashMap<String,Object>{privatestaticfinallong serialVersionUID =1L;/**
     * 状态码
     */publicstaticfinalStringCODE_TAG="code";/**
     * 返回内容
     */publicstaticfinalStringMSG_TAG="msg";/**
     * 数据对象
     */publicstaticfinalStringDATA_TAG="data";/**
     * 状态类型
     */publicenumType{/**
         * 成功
         */SUCCESS(200),/**
         * 警告
         */WARN(301),/**
         * 错误
         */ERROR(500);privatefinalint value;Type(int value){this.value = value;}publicintvalue(){returnthis.value;}}/**
     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
     */publicAjaxResult(){}/**
     * 初始化一个新创建的AjaxResult对象
     *
     * @param type 状态类型
     * @param msg  返回内容
     */publicAjaxResult(Type type,String msg){super.put(CODE_TAG, type.value);super.put(MSG_TAG, msg);}/**
     * 初始化一个新创建的 AjaxResult 对象
     *
     * @param type 状态类型
     * @param msg  返回内容
     * @param data 数据对象
     */publicAjaxResult(Type type,String msg,Object data){super.put(CODE_TAG, type.value);super.put(MSG_TAG, msg);if(!ObjectUtils.isEmpty(data)){super.put(DATA_TAG, data);}}/**
     * 返回成功消息
     *
     * @return 成功消息
     */publicstaticAjaxResultsuccess(){returnAjaxResult.success("操作成功");}/**
     * 返回成功数据
     *
     * @return 成功消息
     */publicstaticAjaxResultsuccess(Object data){returnAjaxResult.success("操作成功", data);}/**
     * 返回成功消息
     *
     * @param msg 返回内容
     * @return 成功消息
     */publicstaticAjaxResultsuccess(String msg){returnAjaxResult.success(msg,null);}/**
     * 返回成功消息
     *
     * @param msg  返回内容
     * @param data 数据对象
     * @return 成功消息
     */publicstaticAjaxResultsuccess(String msg,Object data){returnnewAjaxResult(Type.SUCCESS, msg, data);}/**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */publicstaticAjaxResultwarn(String msg){returnAjaxResult.warn(msg,null);}/**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */publicstaticAjaxResultwarn(String msg,Object data){returnnewAjaxResult(Type.WARN, msg, data);}/**
     * 返回错误消息
     *
     * @return
     */publicstaticAjaxResulterror(){returnAjaxResult.error("操作失败");}/**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */publicstaticAjaxResulterror(String msg){returnAjaxResult.error(msg,null);}/**
     * 返回错误消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */publicstaticAjaxResulterror(String msg,Object data){returnnewAjaxResult(Type.ERROR, msg, data);}/**
     * 方便链式调用
     *
     * @param key   键
     * @param value 值
     * @return 数据对象
     */@OverridepublicAjaxResultput(String key,Object value){super.put(key, value);returnthis;}}

Mapper

SysFileMapper

@MapperpublicinterfaceSysFileMapperextendsBaseMapper<SysFile>{}

Service

SysFileService

publicinterfaceSysFileServiceextendsIService<SysFile>{}
@Servicepublicclass sysFileServiceImpl extendsServiceImpl<SysFileMapper,SysFile>implementsSysFileService{}

LocalStorageService

@Slf4j@Service("localStorageService")publicclassLocalStorageService{@AutowiredprivateSysFileService sysFileService;@Value("${file.upload.dir}")privateString uploadDir;@Value("${file.visit.path:upload}")privateString visitPath;privatestaticfinalString[]ALLOW_FILE_TYPES={"jpg","jpeg","png"};publicAjaxResultupload(MultipartFile file)throwsException{String contentType =  file.getContentType().toLowerCase();boolean allowType =false;for(String allowFileType :ALLOW_FILE_TYPES){if(contentType.contains(allowFileType)){
                allowType =true;break;}}if(!allowType){returnAjaxResult.error("请上传正确的文件格式");}String fileId =UUID.randomUUID().toString();String subFolder =hashBy256(fileId);File destFolder =newFile(uploadDir +File.separator + subFolder);if(!destFolder.exists()){
            destFolder.mkdirs();}String originalFilename = file.getOriginalFilename();String fileExt =getFileType(originalFilename);String destFileName = fileId +"."+ fileExt;File destFile =newFile(uploadDir +File.separator + subFolder +File.separator + destFileName);
        log.info("file saved in: {}", destFile.getAbsoluteFile());
        file.transferTo(destFile);String filePath = visitPath +File.separator + subFolder +File.separator + destFileName;String fileUri =transferPathAsImageUri(filePath);Long fileSize = file.getSize();SysFile sysFile =SysFile.builder().fileId(fileId).filePath(filePath).fileFormat(fileExt).fileSize(fileSize).mediaType(contentType).originalName(originalFilename).build();
        sysFileService.save(sysFile);returnAjaxResult.success().put("fileId", fileId).put("filePath", filePath).put("originFileName", originalFilename).put("fileName", destFileName).put("fileUri", fileUri);}privateStringgetFileType(String originalFilename){int extPos = originalFilename.lastIndexOf(".");if(extPos !=-1){return originalFilename.substring(extPos +1);}thrownewRuntimeException("未知类型");}publicstaticStringhashBy256(String str){String s =Integer.toHexString(Math.abs(str.hashCode())%256).toUpperCase();if(s.length()==1){
            s ="0"+ s;}return s;}publicstaticStringtransferPathAsImageUri(String fileServerPath){if(!StringUtils.hasLength(fileServerPath)){returnnull;}return"/"+ fileServerPath.replaceAll("\\\\","/");}}

拦截器

ResourceConfig,该拦截器用于上传后回写到界面

@ConfigurationpublicclassResourceConfigimplementsWebMvcConfigurer{@Value("${file.visit.path:upload}")privateString visitPath;@Value("${file.upload.dir}")privateString resourceDir;@OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/"+ visitPath +"/**").addResourceLocations("file:"+ resourceDir +"/");}}

测试结果展示

前端界面
在这里插入图片描述


标签: java html spring boot

本文转载自: https://blog.csdn.net/BBQ__ZXB/article/details/128277206
版权归原作者 一只努力的笨笨熊 所有, 如有侵权,请联系我们删除。

“SpringBoot简单优雅实现图片上传功能(超详细)”的评论:

还没有评论