余近日开发spring boot +vue的后台管理项目,涉及到文件上传功能,使用之前项目的文件上传模块,一直有问题。遂经过两天的百度,加个人理解,最终解决了基本的文件上传功能。
首先,html页面:
<!--form中是要加这个enctype的--><form class="form-horizontal" enctype="multipart/form-data"><div v-if="menu.type == 1" class="form-group"><div class="col-sm-2 control-label">图片</div><div class="col-sm-10"><div class="ui-upfile"><div style="width: 150px;height: 140px;display:none;" class="file-area" /></div><input type="hidden" name="menuImgUrl" class="menu-image-url" v-model="menu.menuImgUrl"><input type='button' class='btn' value='上传图片'onclick="document.getElementById('file').click()" style="background-color: #48aae3c7;"/><input type="file" class="menu-image-url" value="" id="file" @change="onUpload" style="filter:alpha(opacity:0);opacity:0;width:0px"> </div></div></div>
这里要说明一下,由于使用的是vue,所有这里赋值取值都是使用v-model,然后这里为什么会有这么多input框,
第一个是返回我对象的属性值的;
第二个是手写的一个按钮,因为如果直接使用input type=file的话,样式比较丑,还会有未选择文件那个字样 ,可以那个type=file的input又是必须的。
所以这里我们使用一个button去覆盖type=file的功能,并且把type=file的input隐藏起来,这里的核心代码是:opacity:0;
接下来,js代码:
onUpload(e){var files = e.target.files[0];var formFile = new FormData();formFile.append("file", files);$.ajax({url: baseURL + 'sys/upload/uploadPic',//这里是请求后台的上传文件接口type: 'POST',dataType: 'json',cache: false,data: formFile,processData: false,contentType: false,success: function(r){ if (r.code === 0) {vm.menu.menuImgUrl = r.fileUrl;$(".file-area").css("display","block");$(".file-area").html("<img src= '"+ r.fileUrl +"'>");}else{alert("文件上传失败:" + r.msg);}}});}
由于使用的是vue,所以这里是写在methods下面的。
这里主要是请求后台,把文件传过去,然后返回一个url,通过这个url我们可以直接访问到图片。
后台 UploadController类
@RestController@RequestMapping("/sys/upload")public class UploadController extends BaseController {/*** 上传图片* @param file* @param request* @throws IOException*/@RequestMapping( value = "/uploadPic")@ResponseBodypublic R uploadPic(@RequestParam(value = "file", required = false) MultipartFile file, HttpServletRequest request) throws IOException {//目前这里是写死的本地硬盘路径String path = "D:/img";logger.info("path:" + path);//获取文件名称String fileName = file.getOriginalFilename();//获取文件名后缀Calendar currTime = Calendar.getInstance();String time = String.valueOf(currTime.get(Calendar.YEAR))+String.valueOf((currTime.get(Calendar.MONTH)+1));//获取文件名后缀String suffix = fileName.substring(file.getOriginalFilename().lastIndexOf("."));suffix = suffix.toLowerCase();if(suffix.equals(".jpg") || suffix.equals(".jpeg") || suffix.equals(".png")/* || suffix.equals(".gif")*/){fileName = UUID.randomUUID().toString()+suffix;File targetFile = new File(path, fileName);if(!targetFile.getParentFile().exists()){ //注意,判断父级路径是否存在targetFile.getParentFile().mkdirs();}long size = 0;//保存try {file.transferTo(targetFile);size = file.getSize();} catch (Exception e) {e.printStackTrace();return R.error("上传失败!");}//项目url,这里可以使用常量或者去数据字典获取相应的url前缀;String fileUrl="http://localhost:8080";//文件获取路径fileUrl = fileUrl + request.getContextPath() + "/img/" + fileName;logger.info("fileUrl:" + fileUrl);return R.ok().put("fileUrl", fileUrl);}else{return R.error("图片格式有误,请上传.jpg、.png、.jpeg格式的文件");}}}
这里有个坑,就是由于spring boot使用的内置tomcat,所以会自动在系统盘下生成一个编译路径,大概是这样的:
C:\Users\69223\AppData\Local\Temp\tomcat-docbase.6718506550492189172.8080
可是把文件放到这个下面,我们无法去正确获取,而且这里的tomcat生成的文件夹中间那一段数字,还都是在变化的。具体原因没有细究。
经过一天的百度及个人理解,最终决定使用映射;
在application.yml文件中添加要映射的绝对路径,即图片要保存的位置:
#文件上传cbs:imagesPath:file:/D:/img/
yml文件中格式要求极为严格 ,必须是4个空格,tab键不起作用,直接使用cbs.imagesPath.file也报错。
这里的文件绝对路径就是我们上传文件时写的上传路径;
之后编写WebMvcConfig配置文件;
@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter{@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("forward:/login.html");registry.setOrder(Ordered.HIGHEST_PRECEDENCE);super.addViewControllers( registry );} /*** 在配置文件中配置的文件保存路径*/@Value("${cbs.imagesPath}")private String mImagesPath;@Beanpublic MultipartConfigElement multipartConfigElement(){MultipartConfigFactory factory = new MultipartConfigFactory();//文件最大KB,MBfactory.setMaxFileSize("1024MB");//设置总上传数据总大小factory.setMaxRequestSize("1024MB");return factory.createMultipartConfig();}/*** 这里是映射文件路径的方法*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {if(mImagesPath.equals("") || mImagesPath.equals("${cbs.imagesPath}")){String imagesPath = WebMvcConfig.class.getClassLoader().getResource("").getPath();if(imagesPath.indexOf(".jar")>0){imagesPath = imagesPath.substring(0, imagesPath.indexOf(".jar"));}else if(imagesPath.indexOf("classes")>0){imagesPath = "file:"+imagesPath.substring(0, imagesPath.indexOf("classes"));}imagesPath = imagesPath.substring(0, imagesPath.lastIndexOf("/"))+"/img/";mImagesPath = imagesPath;}registry.addResourceHandler("/img/**").addResourceLocations(mImagesPath);super.addResourceHandlers(registry);}}
addResourceHandlers()方法是映射文件路径的方法;
这里我们还需要在权限配置类中添加如下,即放开img下的权限控制,否则会涉及到权限,被拦截;
filterMap.put("/img/**", "anon");
截止到这里,我们的上传图片基本已经完成了,接下来就可以进入测试阶段。
我们把文件上传到D盘下面的img文件夹,上传成功之后,我们使用:
http://localhost:8080/项目名/img/3b13ad02-3812-4c39-880d-799172801284.png
就可以直接访问到我们的图片了。
项目得启动起来。
只是基本的使用,具体的底层原理,并未深究。
点个赞吧!^_^ !