檔案下載

使用ResponseEntity實現下載檔案的功能

index.html

<!DOCTYPE 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>

控制器

@RequestMapping("/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>
  • 控制器
@RequestMapping("/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, @Nullable ModelAndView modelAndView) throws Exception {
} default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable 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設定需要排除的請求,即不需要攔截的請求

/**:攔截所有請求

/*:攔截一級目錄的請求

多個攔截器的執行順序

第一個攔截器

@Component
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");
}
}

第二個攔截器

@Component
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()會按照配置的反序執行

如果設定第一個攔截器對所有請求放行,第二個攔截器對所有請求攔截。

第一個攔截器

@Component
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");
}
}

第二個攔截器

@Component
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介面的實現類有:DefaultHandlerExceptionResolverSimpleMappingExceptionResolver

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將當前類標識為異常處理的元件
@ControllerAdvice
public class ExceptionController { //@ExceptionHandler用於設定所標識方法處理的異常
@ExceptionHandler(value = {ArithmeticException.class,NullPointerException.class})
//ex表示當前請求處理中出現的異常物件
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
} }