1. 程式人生 > >spring實戰-Spring中Filter以及處理Exception方式

spring實戰-Spring中Filter以及處理Exception方式

第七篇:spring實戰-Spring中Filter以及處理Exception方式

Filter對於Web應用程式是至關重要的,如果web請求的字元轉換,XSS攻擊攔截等等

在SpringMVC中新增Filter也是非常方便的,可以通過重寫AbstractAnnotationConfigDispatcherServletInitializer的getServletFilters()來實現

如我們前幾節構架的應用程式,是無法將中文字元從前端傳到伺服器中去的,此時我們需要一個必要的字元轉換,可以通過Filter來實現

1,構建一個SetCharacterEncodingFilter

package com.halfworlders.idat.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class SetCharacterEncodingFilter implements Filter {  
    
	@Override  
    public void doFilter(ServletRequest request, ServletResponse response,  
            FilterChain filterChain) throws IOException, ServletException {  
        if (request.getCharacterEncoding() == null) {  
            request.setCharacterEncoding("UTF-8");  
        }  
        filterChain.doFilter(request, response);  
    }

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}

	@Override
	public void destroy() {
	}  
}  
2,在IdatWebAppInitializer中重寫getServletFilters()方法

/**
	 * 新增一個或多個Filter
	 * 返回的所有Filter都會對映到DispatcherServlet上,所以沒有為Filter設定對映路徑
	 */
	@Override
	protected Filter[] getServletFilters() {
		return new Filter[] {new SetCharacterEncodingFilter()};
	}
以上兩步就實現了一個Spring Filter並將其應用到SpringMVC應用程式中去了。



如果我們的程式一直在正在的程式碼路徑中執行就非常完美了,但是這是不可能的,程式中總是會出現各種異常的情況,如果不對程式異常的情況做處理,是非常糟糕的,簡單點可能是給使用者一個不友好的頁面,嚴重的可能會由於異常堆疊直接向客戶端暴露伺服器應用程式的私密資訊,甚至有些異常不加處理可能會導致應用程式奔潰。

所以一個健壯的應用程式應該包含完整的異常處理機制

Spring針對HTTP異常,實現了一個非常方便的處理方式,可以增加客戶頁面的友好提示,同時不洩露伺服器資訊,同時可以通過一個簡單的實現,處理所有控制器的異常資訊,但是也可以通過在單個控制器類實現@ExceptionHandler(AppException.class)來處理單個控制器HTTP異常,以下主要演示通過控制器通知的方式統一的為控制器提供異常處理。

控制器通知類定義

package com.halfworlders.idat.handler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import com.halfworlders.idat.exception.AppException;

/**
 * 定義控制器類
 * @author lllhappy
 *
 */
@ControllerAdvice
public class IdatExceptionHandler {

	/**
	 * 定義異常處理方法,可以為每個種類的異常定義一個處理方式
	 * @return
	 */
	@ExceptionHandler(AppException.class)
	public String appExceptionHandler(){
		return "error/appException";
	}
	
}

通過以上方式就可以將控制器中丟擲的AppException型別的異常捕獲到,並通過error/appException頁面給使用者友好提示,而不是簡單粗暴的給使用者一個異常堆疊的頁面



前面章節有演示通過post方式提交資料後,控制器中通過redirect:的方式返回重定向,這樣做時方式使用者提交後點擊重新整理按鈕,或者後退箭頭後,導致客戶端再次post提交

但是redirect:不同forward:,我們知道forward:是請求轉發,轉發的同時可以將request帶到下一次回話中,也同時可以將資料帶過去,但是redirect:不行,參考點選開啟連結

SpringMVC給了我們很好的處理方案,一種可以通過重定向URL進行資料傳遞,另外還可以通過RedirectAttributes使用flash屬性將物件屬性整體傳遞給下一次會話

@RequestMapping(value = "/create", method = RequestMethod.POST)
	public String create(@Valid Interface intf, Errors errors, RedirectAttributes model) {
		// 如果校驗不通過的話,返回建立表單頁面
		if (errors.hasErrors()) {
			return "createForm";
		}		
		Interface rintf = idatService.save(intf);
		// name屬性將填充到一下URL模板的name佔位符中
		model.addAttribute("name", rintf.getName());
		// 通過flash屬性,在重定向之前將整個模型物件全部打包複製到會話中,會存活到下一次請求才消失
		model.addFlashAttribute("intf", rintf);
		return "redirect:queryInterfacesByName/{name}/intf";
	}
重定向接受方控制器

@RequestMapping(value = "/queryInterfacesByName/{name}/intf", method = RequestMethod.GET)
	public String queryInterfacesByName(@PathVariable("name") String name, Model model) {
		// 先檢查是否已經存在對應的intf屬性,如果不包括,才會去資料庫中查詢
		if (!model.containsAttribute("intf")) {
			Interface interfaces = idatService.queryInterfacesByName(name);
			model.addAttribute("intf", interfaces);
		}
		return "interface";
	}