SpringMVC實現文件上傳與下載、攔截器、異常處理器等功能

文件下載

使用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}" rel="external nofollow" >點擊下載</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()
  • afterCompletion:處理完視圖和模型數據,渲染視圖完畢之後執行afterCompletion()

控制器

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

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

第一個攔截器

@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的攔截器之前的攔截器的afterCompletion()會執行

異常處理器

基於配置的異常處理

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將當前類標識為異常處理的組件
@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";
    }

}

總結

到此這篇關於SpringMVC實現文件上傳與下載、攔截器、異常處理器等功能的文章就介紹到這瞭,更多相關SpringMVC文件上傳與下載、攔截器、異常處理器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: