基于springmvc的文件上传及其讲解

来源:互联网 发布:php oa系统流程 编辑:程序博客网 时间:2021/05/15 18:45

支持和原理解析

Springmvc对文件上传的支持,springmvc内部已经实现了客户端上传文件到服务端我们只需要按照自己的需求去配置即可,

通过在springmvc的核心配置文件中配置支持文件上传的实体类即可


跟源码可以发现commonsMulitpartResolver 类继承了 CommonsFileUploadSupport 实现了 MultipartReolverServletContextAware等接口


在上传文件的时候需要配置两个属性,一个是默认的编码格式,defaultEncoding 一个是允许上传的文件的最大大小maxUpLoadSize,

defaultEncoding 在commonsMulitpartResolver  类中

maxUpLoadSize CommonsFileUploadSupport 类中


正如我想象的一样,CommonsFileUploadSupport 是一个抽象类,commonsMulitpartResolver继承了这个抽象类就拥有了CommonsFileUploadSupport 的所有方法,然后在根据自己的需求去扩展,这样用法的java编程种堪称为经典,屡试不爽,这是一种吧oop运用到了极致的做法,可以体现springmvc的思想之与java的高度一致。

众所周知,客户端不可能上传无限大的文件到服务端的(其实不仅仅只是文件),这就是为什么CommonsFileUploadSupport是抽象类的原因,但是不管是是上传文件还是上传别的东西,文件的大小是上传文件的必须要做一个限制的,所有该属性在抽象类中,二编码风格则不同,更具具体的需求可以设置不同的编码,如果在抽象类中定义死了不便于扩展,所有这个属性是可以让子类去重写的。

关于实现MultipartReolverServletContextAware接口,这才是能做到文件上传的关键回归最原始的上传文件,servlet上传文件,因为springmvc无论是入口还是对web的操作的原理都是基于servlet的,并在此基础上做扩展,所有文件上传也是如此,servlet上传文件要求表单的enctype的属性必须是 multipart/form-data,,所有实现MultipartReolver表示该请求支持表单的MIME编码,

至于ServletContextAware,那肯定就是是通过该容器去获取其他的8个对象,jsp中的9大对象中只需要获取它就能通过它去获取其他的8个对象了,再次回到servlet上传文件,要求对request对象进行加强和重写,而不能直接在request对象中获取文件,struts2中的某一个拦截器拦截器就对requers进行了加强和重写,这就是为什么struts2中上传文件只需限制文件大小(其实也有默认)而不用做过多的配置的原因,springmvc也是通过ServletContext容器去获取request对象然后进行重写和加强,以致于在控制器中直接通过request获取文件相关属性和把表单元素对象直接转化为文件对象。这也是springmvc的可扩展性的体现,不需要上传文件的时候不配置,而struts2即使不做文件上传struts框架仍然会对requers进行拦截和加强。

实现上传

所需环境和所选框架

本案例选重在讲解文件上传,所有没有持久化框架的参与,所以总体架构是springmvc+spring

因为是客户端上传到服务端,而我们的前端矿建又是用的springmvcspringmvc又是基于servle的,所有一些web相关的jar包和环境肯定是要的



Springmvc也是基于spring的,所有spring的框架相关的也是必不可少的



因为是文件上传,所有与文件和io相关的jar也是需要的



因为是客户端上传到服务端,jsp页面的一些标签和上传成功以后通过el表达是获取服务端的值,所以jstl标签库也是要的



环境配置

为了吧服务器的效率最大化,这里采用的而是nginx+tomcat+SwitchHosts,,通过反向代理的方式吧一些静态资源显示到客户端

通过SwitchHosts配置本地localhost,配置


一个像图片访问路径,一个是项目访问路径

 

通过nginx配置请求代理

项目请求代理


图片请求代理



Tomcat插件配置




端口是8081,反问路径是 /

 

框架配置文件

springmvc配置文件<!-- 注解驱动 --><mvc:annotation-driven/><!-- 扫描指定包 --><context:component-scan base-package="cn.liu.controller"/><!-- 配置视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/" /><property name="suffix" value=".jsp" /></bean><!-- 静态资源不拦截 --><mvc:default-servlet-handler /><!-- 支持上传文件 -->      <bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 设定默认编码 --><property name="defaultEncoding" value="UTF-8"></property><!-- 设定文件上传的最大值50MB,50*1024*1024 --><property name="maxUploadSize" value="52428800"></property></bean>    

spring配置<beanclass="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><!-- 配置资源文件 --><property name="locations"><list><value>classpath:env.properties</value></list></property></bean><!-- 使用组件的自动扫描扫描 --><context:component-scan base-package="cn.liu" />
为了便于项目的迁移和图片上传位置的随时改动这里配置了2个环境变量<IMAGE_BASE_URL=http://image.dome.comREPOSITORY_PATH=D:\\file-upload

一个是用来改变图片服务器的访问更连接

一个是用俩控制图片上传到本地服务器的磁盘中的绝对位置


实现效果:上传文件以后做一个页面跳转,因为没有存入数据库,所以跳转以后吧当前文件已图片的形式展现出来,如果不是图片,则不能正常显示,但上传是没问题的,
如果<span style="font-family: Arial, Helvetica, sans-serif;">是图片则显示图片,然后可以删除该图片(但是只能删除当前上传的一个文件,原因是没有存入数据库Jsp页面代码</span>
<body><form action="file/upload" method="post" enctype="multipart/form-data">  <input type="file" name="uploadFile" />    <input type="submit" value="Submit"/></form></body>
一个表单,以post方式提交 ,提交到对呀的控制器java后台代码:
   @RequestMapping("upload")    public ModelAndView upload(@RequestParam("uploadFile") MultipartFile uploadFile ,            HttpServletResponse response) throws Exception{        //文件原始名称(上传前的名称,存入数据库)        String fileName=uploadFile.getOriginalFilename();        //文件类型(后缀)        String fileType=fileName.substring(fileName.indexOf("."), fileName.length());        //文件路径(相对路径,建议存入数据库)        String newFileName=System.currentTimeMillis()+fileType;        String filePath=new SimpleDateFormat("yy/MM/dd").format(new Date()).toString();        // 文件磁盘路径        String path=pathService.REPOSITORY_PATH+"\\"+filePath;        //创建目录        File newFile = new File(path);        // 如果目录不存在,则创建目录        if (!newFile.isDirectory())              newFile.mkdirs();        //创建目标文件        File resultFile = new File(path+"\\"+newFileName);        //写入磁盘        uploadFile.transferTo(resultFile);        //返回服务器显示路径        String servicePath=pathService.IMAGE_BASE_URL+"/"+filePath+"/"+newFileName;        ModelAndView mv=new ModelAndView("file-show");        mv.addObject("servicePath", servicePath);        mv.addObject("filePath", filePath+"/"+newFileName);        return mv;    }

创建一个普通的类,通过注解吧该类变为一个控制器

@Autowiredprivate PathService pathService;

注入PathService ,通过PathService  可以获取一些文件上传和显示的环境变量

首先通过参数获取页面表单元素,因为该请求是上传图片的请求,所有该请求是经过加强和重写的请求,所有参数 uploadFile 本身就是一个实现了MultipartFile接口的MultipartFile类型

通过该对象可以获取该文件的名称,类型(后缀), 大小

具体实现,首先获取文件的类型(后缀),然后通过获取一个时间戳,最后给文件创建衣蛾新的文件名称(带后缀),然后通过对当前时间年月日的切割,通过pathService获取本地磁盘的绝对路径一起构造成一个完整的文件目录和文件,然后把当前文件写入本地磁盘。上传成功以后再次通过pathService获取获取文件服务器路径,和文件新名称和类型构造一个完整的文件路径返回给客户,供客户端操作和下载







0 0