使用ResponseEntity
实现下载文件的功能
index.html
<html lang="en" xmlns:th="http:www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a th:href="@{/testDown}">点击下载</a>
</body>
</html>
控制器
"/testDown")(
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
注意:如果报500
错误,可能是项目中无法找到静态资源文件,需要对项目重新打包。
文件上传要求form
表单的请求方式必须为post
,并且添加属性enctype="multipart/form-data"
以二进制方式上传
SpringMVC中将上传的文件封装到MultipartFile
对象中,通过此对象可以获取文件相关信息
上传步骤:
- 添加依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
- 在SpringMVC的配置文件
springMVC.xml
中添加配置
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<!--必须设置id属性,springMVC是根据id获取,且id必须设置为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
index.html
<form method="post" th:action="@{/testUp}" enctype="multipart/form-data">
<input type="file" name="photo">
<input type="submit" value="上传">
</form>
- 控制器
"/testUp")(
//MultipartFile的形参名必须与index.html中的file标签的name一致
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//处理文件重名问题
String hzName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString() + hzName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
if(!file.exists()){
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//实现上传功能
photo.transferTo(new File(finalPath));
return "success";
}
拦截器的配置
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
接口
HandlerInterceptor
源码
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
HandlerInterceptor
接口有三个默认方法
preHandle
:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法postHandle
:控制器方法执行之后执行postHandle()afterComplation
:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
控制器
FirstInterceptor.java
public class FirstInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
- 方式一
<mvc:interceptors>
<bean class="com.gonghr.springmvc.interceptors.FirstInterceptor"></bean>
</mvc:interceptors>
输出:
FirstInterceptor-->preHandle
- 方式二
<mvc:interceptors>
<ref bean="firstInterceptor"></ref>
</mvc:interceptors>
注意提前开启注解扫描,并把拦截器放入Ioc容器
输出:
FirstInterceptor-->preHandle
注意:以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截。
- 方式三
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/> <!--拦截所有请求-->
<mvc:exclude-mapping path="/"/> <!--不拦截主页-->
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
可以进入首页
发送任意请求都会被拦截
输出:
FirstInterceptor-->preHandle
以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping
设置需要拦截的请求,通过mvc:exclude-mapping
设置需要排除的请求,即不需要拦截的请求
/**
:拦截所有请求
/*
:拦截一级目录的请求
多个拦截器的执行顺序
第一个拦截器
public class FirstInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
第二个拦截器
public class SecondInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor-->preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor-->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor-->afterCompletion");
}
}
两个拦截器都设置为对任意请求放行。
输出:
FirstInterceptor-->preHandle
SecondInterceptor-->preHandle
SecondInterceptor-->postHandle
FirstInterceptor-->postHandle
SecondInterceptor-->afterCompletion
FirstInterceptor-->afterCompletion
- 若每个拦截器的preHandle()都返回
true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()
会按照配置的顺序执行,而postHandle()
和afterComplation()
会按照配置的反序执行
如果设置第一个拦截器对所有请求放行,第二个拦截器对所有请求拦截。
第一个拦截器
public class FirstInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
第二个拦截器
public class SecondInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor-->preHandle");
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor-->postHandle");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor-->afterCompletion");
}
}
输出:
FirstInterceptor-->preHandle
SecondInterceptor-->preHandle
FirstInterceptor-->afterCompletion
- 若某个拦截器的
preHandle()
返回了false
preHandle()
返回false
和它之前的拦截器的preHandle()
都会执行,postHandle()
都不执行,返回false
的拦截器之前的拦截器的afterComplation()
会执行
基于配置的异常处理
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver
接口的实现类有:DefaultHandlerExceptionResolver
和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver
,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--
properties的键表示处理器方法执行过程中出现的异常
properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
-->
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
<!--
exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
error.html
出现错误
<p th:text="${ex}"></p>
index.html
<a th:href="@{/testException}">测试异常处理</a>
基于注解的异常处理
//@ControllerAdvice将当前类标识为异常处理的组件
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
(value = {ArithmeticException.class,NullPointerException.class})
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}