spring mvc怎么获取上传文件的原路径
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring mvc怎么获取上传文件的原路径相关的知识,希望对你有一定的参考价值。
@RequestMapping(value = "/upload", method = RequestMethod.POST)public ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response) throws Exception
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy/MM/dd/HH");
/** 构建文件保存的目录* */
String logoPathDir = "/business/shops/upload/"
+ dateformat.format(new Date());
/** 得到文件保存目录的真实路径* */
String logoRealPathDir = request.getSession().getServletContext()
.getRealPath(logoPathDir);
/** 根据真实路径创建目录* */
File logoSaveFile = new File(logoRealPathDir);
if (!logoSaveFile.exists())
logoSaveFile.mkdirs();
/** 页面控件的文件流* */
MultipartFile multipartFile = multipartRequest.getFile("file");
/** 获取文件的后缀* */
String suffix = multipartFile.getOriginalFilename().substring(
multipartFile.getOriginalFilename().lastIndexOf("."));
/** 使用UUID生成文件名称* */
String logImageName = UUID.randomUUID().toString() + suffix;// 构建文件名称
/** 拼成完整的文件保存路径加文件* */
String fileName = logoRealPathDir + File.separator + logImageName;
File file = new File(fileName);
try
multipartFile.transferTo(file);
catch (IllegalStateException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
/** 打印出上传到服务器的文件的绝对路径* */
System.out.println("****************"+fileName+"**************");
insertDate(fileName);
return new ModelAndView("redirect:/business/shops/my.jsp");
参考技术A 将文件转换为CommonsMultipartFile类型然后file.getFileItem().getName();即可
Spring MVC学习(10)—文件上传配置DispatcherServlet的路径配置请求和响应内容编码
基于最新Spring 5.x,详细介绍了Spring MVC项目的一些特殊配置,包含文件上传的配置,DispatcherServlet的路径配置,请求体和响应体的编码配置。
本次我们来学习Spring MVC项目的一些特殊配置,包含文件上传的配置,DispatcherServlet的路径配置,请求体和响应体的编码配置。
Spring MVC学习 系列文章
Spring MVC学习(1)—MVC的介绍以及Spring MVC的入门案例
Spring MVC学习(2)—Spring MVC中容器的层次结构以及父子容器的概念
Spring MVC学习(3)—Spring MVC中的核心组件以及请求的执行流程
Spring MVC学习(4)—ViewSolvsolver视图解析器的详细介绍与使用案例
Spring MVC学习(5)—基于注解的Controller控制器的配置全解【一万字】
Spring MVC学习(6)—Spring数据类型转换机制全解【一万字】
Spring MVC学习(7)—Validation基于注解的声明式数据校验机制全解【一万字】
Spring MVC学习(8)—HandlerInterceptor处理器拦截器机制全解
Spring MVC学习(9)—项目统一异常处理机制详解与使用案例
Spring MVC学习(10)—文件上传配置、DispatcherServlet的路径配置、请求和响应内容编码
Spring MVC学习(11)—跨域的介绍以及使用CORS解决跨域问题
文章目录
1 Spring MVC文件上传
org.springframework.web.multipart
包提供了一个用于处理文件上传的Multipart
多部分解析框架,使用该框架可以非常方便的实现文件上传,避免了编写繁琐的底层API。该框架的核心类是一个解析包括文件上传在内的多部分请求的MultipartResolver
策略接口,以及用于在web应用中访问Multipart多部分内容的HttpServletRequest
的扩展接口MultipartHttpServletRequest
。
要启用多部分处理,我们需要在DispatcherServlet
关联的Spring 配置文件中声明一个MultipartResolver 的bean
,并命名为“multipartResolver
”。DispatcherServlet会检测到该bean,并将其应用到传入的请求分析过程中。
当收到一个content-type为multipart/form-data的POST请求
时,多部分解析器将分析请求内容并包装当前 HttpServletRequest为一个MultipartHttpServletRequest
,通过MultipartHttpServletRequest
可以对已解析部分的访问,以及可以将已解析部分直接作为请求处理器方法的参数。
从Spring 3.1
开始,Spring MVC为我们提供了MultipartResolver
的两种实现,一种是基于ApacheCommons FileUpload
的实现——CommonsMultipartResolver
,另一种是基于基于Servlet 3.0
多部分请求解析的实现StandardServletMultipartResolver
。
1.1 Apache Commons FileUpload
想要使用Apache Commons FileUpload,我们必须引入commons-fileupload
的依赖。
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-
fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
在Spring MVC配置文件中配置名为multipartResolver
的CommonsMultipartResolver
实现,并且可以配置其中的属性:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置允许上传的最大大小(以byte字节为单位)。-1 表示没有限制(默认值)。-->
<property name="maxUploadSize" value="#{10*1024*1024}"/>
<!--设置为用于分析请求、应用于单个部件的标头和窗体字段的将默认字符编码。根据 Servlet 规范,默认值为 ISO-8859-1-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
1.2 Servlet 3.0
Servlet 3.0
开始默认支持multipart解析,因此我们不需要再引入外部依赖
,但是需要支持Servlet3.0的容器,tomcat服务器自7.0.x
版本开始就支持Servlet3.0了,详细支持信息:http://tomcat.apache.org/whichversion.html
。
在确定服务器支持Servlet3.0之后,在Spring MVC配置文件中配置名为multipartResolver
的CommonsMultipartResolver
实现:
<bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
如果想要自定义上传配置,那么需要在DispatcherServlet
的声明中配置<multipart-config>
:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!--Servlet WebApplicationContext子容器的配置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc-config.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
<!--文件上传配置-->
<multipart-config>
<!--上传的文件的最大限制,单位byte-->
<max-file-size>4194304</max-file-size>
<!--multipart/form-data请求的最大限制,单位byte-->
<max-request-size>10485760</max-request-size>
<!--将存储上载文件的目录位置-->
<!--<location></location>-->
</multipart-config>
</servlet>
1.3 上传文件
无论是基于Apache Commons FileUpload还是Servlet3.0,上传文件的代码都差不多!前端应该发送multipart/form-data的POST请求,并且请求的内容可以作为常规请求参数进行解析和访问!
一个简单的前端页面如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<h3>Springmvc文件上传</h3>
<form action="/mvc/upload" method="post" enctype="multipart/form-data">
name: <label><input type="text" name="name"/></label>
file:<label><input type="file" name="file"/></label><br>
<input type="submit" value="上传"/>
</form>
</body>
</html>
后端Controller如下,其中MultipartFile用于接收上传的文件:
@RestController
public class MultipartController {
@PostMapping("/upload")
public void upload(String name, MultipartFile file) {
System.out.println(name);
System.out.println(file.getName());
System.out.println(file.getOriginalFilename());
}
}
将参数类型声明为List<MultipartFile>
表示允许为同一参数名称解析多个文件。
将参数类型声明为Map<String, MultipartFile>
或者MultiValueMap<String, MultipartFile>
时,并且在@RequestParam
注解中未指定参数名称的情况下,参数Map将填充映射每个给定参数名称以及对应的multipart文件。
如果使用 Servlet 3.0
多部分解析,那么还可以声明 javax.servlet.http.part
而不是 Spring 的MultipartFile
来接收上传的文件。
当然multipart内容可以和命令对象(command object
)绑定在一起,例如,下面示例中的表单字段和文件可以是一个对象中的字段,如下所示:
public class MultipartModel {
private String name;
private MultipartFile file;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
}
Controller如下:
@RestController
public class MultipartController {
@PostMapping("/upload")
public void upload(MultipartModel multipartModel) {
System.out.println(multipartModel.getName());
System.out.println(multipartModel.getFile().getName());
System.out.println(multipartModel.getFile().getSize());
}
}
2 DispatcherServlet路径
想要明白DispatcherServlet的路径配置,我们应该明白原始Servlet的路径规则并且对Spring MVC的组件有所了解,这些我们在此前就在文章《Java Web(4)—Servlet的概念以及Servlet开发案例》的Servlet的细节部分学习过了,这里不再赘述!
- DispatcherServlet的映射路径
url-pattern
如果设置为“/”
,此时普通请求
都会进入该Servlet,但是对于访问静态资源
的请求同样会被转发到该Servlet中,并且请求的路径被默认认定为Handler映射路径,即普通请求,这将导致由于静态资源请求因找不到Handler而抛出404
异常。但是对于以“.jsp”
结尾的动态资源访问,不会进入DispatcherServlet,因为它被tomcat容器为我们配置的路径为“*.jsp”
的JspServlet
处理了。 - DispatcherServlet的映射路径
url-pattern
如果设置为“/*”
,那么所有访问
都会进入DispatcherServlet,包括以“.jsp”
结尾的动态资源访问,并且请求的路径被默认认定为Handler映射路径,即普通请求,这将导致由于jsp请求和静态资源请求因找不到Handler而抛出404
异常。
通常我们配置DispatcherServlet的url-pattern
为“/”
,此时想要让DispatcherServlet处理静态资源的请求,那么有下面两个方法!
2.1 配置静态资源
通过<mvc:resources/>
标签配置静态资源的位置和请求映射
,该标签有如下几个属性:
location
表示静态资源的位置,可以指定多个不同的位置,使用“,”
分隔。默认定位到webapp
目录下,即应用根目录,可以使用classpath:
指定本地类路径和jar包路径。、mapping
表示资源请求的路径,可以使用**表示匹配任何路径。这些相对路径用于查找基于location
路径的资源。cache-period
表示静态资源的缓存时间,以确保记尽量减少浏览器发出的HTTP请求。
使用该配置后,静态资源的访问仍然会首先被DispatcherServlet拦截。
每一个<mvc:resources/>
标签都将配置一个SimpleUrlHandlerMapping
,并且它们的Order为Integer. MAX_VALUE
,也就是排在handlerMapping链
的末尾,在其内部的urlmap
集合中,key为mapping的值
,value为ResourceHttpRequestHandler
。对于静态资源的访问,对应的handler就是ResourceHttpRequestHandler
,而在后续获取的HandlerAdpater也是HttpRequestHandlerAdapter
,我们在此前MVC组件就介绍过了,该处理器适配器转换用于处理通过Spring MVC来访问的静态资源的请求
。
和其他HandlerAdapter一样,HttpRequestHandlerAdapter
的handle方法内部仅仅是对ResourceHttpRequestHandler的handleRequest方法进行调用
,因此静态资源的访问,实际上是通过ResourceHttpRequestHandler
处理器来进行处理的,并且支持通过classpath
引入本地类路径和jar包路径下的静态资源。最后返回的ModelAndView为null
,也就是不再需要进行后续的视图处理了,还是很简单的!
ResourceHttpRequestHandler的handleRequest方法
中:
- 会根据路径找到真实的静态资源并加载为Resource,找不到就返回
404
; - 找到之后,会判断请求是否使用了
If-Modified-Since
头,如果使用了,那么该头部值会跟Resource资源的last-modified作比较,如果相等或者Resource的lastModified更小,则返回304
状态代码,表示资源未被修改,浏览器可以使用已缓存的静态资源! - 如果 Resource的
lastModified
更大或者没有使用If-Modified-Since
头,那么从目标资源Resource获取InputStream,其中的数据会被读取为byte[]数组并写入response的OutputStream(通过流的形式返回响应),也就是响应体,最终在浏览器被渲染。
一种常见的XML配置如下:
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
对应的JavaConfig配置如下:
/**
* @author lx
*/
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
/*也可以如下样式,但是它们有些许区别*/
//registry.addResourceHandler("/css/**", "/images/**", "/js/**")
// .addResourceLocations("/css/", "/images/", "/js/");
}
}
如果某个<mvc:resources/>
标签的location为“/A/B/”
,mapping为“/C/D/**”
,如果某个请求路径为“/C/D/E/index.html”
,那么在后台查找的对应的资源真实位置为webapp
下的“/A/B/E/index.html”
。
2.2 配置默认Servlet
此前在Java EE部分的《Java Web(4)—Servlet的概念以及Servlet开发案例》的Servlet的细节部分我们就讲过了,tomcat容器会为web项目配置一个默认Servlet,专门用于处理静态资源的请求
,并且url-pattern为“/”
。也就是说,如果DispatcherServlet
的url-pattern为“/”
,那么表示我们是将DispatcherServlet作为默认Servlet
,这将覆盖容器为我们配置的默认Servlet,因此静态资源也会由DispatcherServlet来处理,而如果我们没有特殊处理的话,静态资源的请求会因为被作为普通请求而找不到handler而返回404
,除非向上面那样配置静态资源处理器!
实际上,上面所说的“覆盖”并不是直接将容器为我们创建的DefaultServlet
抹除了,而是默认只使用我们自己配置的默认Servlet,但是容器为我们配置的DefaultServlet
仍然还是存在的!也就是说,如果我们能够获取容器配置的默认Servlet,那么我们或许就有另一种方式来处理静态资源了!
在Spring MVC中,允许将DispatcherServlet映射到“/”从而覆盖了容器默认Servlet的映射,但同时仍允许并且有办法获取容器创建的默认Servlet来处理静态资源请求!**
如果是JavaConfig方式,那么可以如下配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
如果是XML方式,那么可以加入如下配置(如果使用<mvc:default-servlet-handler/>
标签,那么还需要添加<mvc:annotation-driven/>
标签。):
<mvc:default-servlet-handler/>
开启这个功能之后,静态资源的访问仍然会首先被DispatcherServlet拦截。
实际上,同样是配置一个SimpleUrlHandlerMapping
的处理器映射器,只不过它的order值为Integer.MAX_VALUE
,也就是说,在HandlerMapping链中它排在最末尾,在其内部的urlmap
集合中,key默认为“/**”
,value为DefaultServletHttpRequestHandler
。也就是说,如果在这个HandlerMapping之前所有的HandlerMapping都无法解析给定的请求路径为handler时,这些请求都会被最后一个SimpleUrlHandlerMapping
所处理!在后续获取的HandlerAdpater也是HttpRequestHandlerAdapter
。
为什么这个SimpleUrlHandlerMapping要放在HandlerMapping链的末尾呢?因为其对应的DefaultServletHttpRequestHandler
在执行时会将所有到达此HandlerMapping的请求都转发到web应用真正的默认Servlet中,这个Servlet把请求URL专门用来查找静态资源!因此如果排在最前面,那么动态资源请求仍然会被转发到这个容器默认Servlet而导致异常,而排在最后面,则表示此前的所有的HandlerMapping都无法处理这个请求,那么这个请求可能就是静态资源的请求!
DefaultServletHttpRequestHandler的处理请求的方法:
tomcat
配置的默认的Servlet名为“default”
。在DefaultServletHttpRequestHandler
中,会尝试将请求直接forward转发
给默认的Servlet去处理,是不是很简单?
3 内容编码
对于请求体和响应体
的编码,Spring MVC已经为我们提供了一个现成的Filter
——CharacterEncodingFilter
,使用时我们只需要配置到web.xml
文件中即可!
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置编码-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--对于request和response是否强制使用指定的编码-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--<!–对于request是否强制使用指定的编码–>-->
<!--<init-param>-->
<!-- <param-name>forceRequestEncoding</param-name>-->
<!-- <param-value>true</param-value>-->
<!--</init-param>-->
<!--<!–对于response是否强制使用指定的编码–>-->
<!--<init-param>-->
<!-- <param-name>forceResponseEncoding</param-name>-->
<!-- <param-value>true</param-value>-->
<!--</init-param>-->
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
其中encoding
,表示要使用的编码格式,forceEncoding
表示是否对请求和响应强制使用指定的编码(同时设置forceRequestEncoding和forceResponseEncoding),默认false。forceRequestEncoding
表示是否对请求强制使用指定的编码,默认false,forceResponseEncoding
表示是否对响应强制使用指定的编码,默认false。
CharacterEncodingFilter的处理过程如下:
源码还是很简单的:
- 如果指定了encoding,那么可能会应用指定编码:
- 如果forceRequestEncoding为true或者此前没有默认的请求编码,那么设置请求编码为的encoding;
- 如果forceResponseEncoding为true,那么设置响应编码为encoding;
- 如果未指定encoding,此CharacterEncodingFilter什么也不做,即不会设置任何编码,进入下一个Filter!
相关文章:
https://spring.io/
Spring Framework 5.x 学习
Spring Framework 5.x 源码
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!
以上是关于spring mvc怎么获取上传文件的原路径的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 上传文件 获取项目根路径 物理地址 resttemplate上传文件