七、Spring MVC高階技術

魚換水發表於2020-05-31

知識點

  • 處理檔案上傳
  • 使用flash屬性
  • 在控制器中處理異常

關鍵詞

  • 控制器通知 (Controller Advice)

7.1 處理異常

Spring提供了多種方式將異常轉換為響應:

  • 特定的Spring異常將會自動對映為指定的HTTP狀態碼
  • 異常上可以新增@RequestStatus註解,從而將其對映為某一個HTTP狀態碼
  • 在方法上可以新增@ExceptionHandler註解,使其用來處理異常

最簡單的方式就是第二種,對映。

7.1.1 將異常對映為HTTP狀態碼

在預設情況下,Spring會將自身的一些異常自動轉化為合適的狀態碼。

Spring異常 HTTP狀態碼
BindException 400-Bad Request
ConversionNotSupportedException 500-Internal Server Error
HttpMessageNotReadableException 400-Bad Request
HttpMessageNotWriteableException 500-Internal Server Error
HttpRequestMethodNotSupportedException 405-Method Not Allowed
MethodArgumentNotValidException 400-Bad Request
MissingServletRequestParameterException 400-Bad Request
MissingServletRequestPartException 400-Bad Request
NoSuchRequestHandlingMethodException 404-Not Found
TypeMismatchException 400-Bad Request
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
public class .....

7.2 為控制器新增通知

控制器通知是任意帶有@ControllerAdvice註解的類,這個類包含以下的方法:

  • @ExceptionHandler 註解標註的fangfa
  • @InitBinder註解標註的方法
  • @ModelAttribute註解標註的方法
    以上這些方法會自動運用到整個應用程式所有控制器中帶有@RequestMapping註解的方法上。
// 寫一個控制器異常處理類
package test
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
// 定義控制器類
@ControllerAdvice
public class AppWideExceptionHandler {
	// 定義處理異常的方法
	@ExceptionHandler(DuplicateSpittleException.class)
	public String duplicateSpittleHandler() {
		return "error/duplicate";
	}
}

如果任何地方丟擲DuplicateSpittleException,則會呼叫duplicateSpittleHandler方法來處理異常。

7.5 跨重定向請求傳遞資料

在5.4說了重定向的基礎功能,Spring還為其提供了其他的輔助功能。

Q:正在發起重定向功能的方法該如何傳送資料給重定向的目標方法呢?

當一個處理器方法完成之後,該方法所指定的模型資料將會複製到請求中,並作為請求中的屬性,請求會轉發到檢視上進行渲染。因為控制器方法和檢視所處理的是同一個請求,所以在轉發中請求屬效能夠得以儲存。

以上是請求的處理內容,但是重定向不同。
當控制器返回的結果是重定向的話,原始的請求就結束了,並且會發起新的一個GET請求。原始請求中帶有的引數也會一起消失,在新請求屬性中,沒有任何來自模型的資料,必須通過方法內獲取後,賦值到重定向的結果中,作為新請求的資料。

重定向傳遞資料的兩種方法:

  • 使用URL模板以路徑變數和/或查詢引數的形式傳遞資料。
  • 通過flash屬性傳送資料。

第一種方法

	@RequestMapping(value="/register",method=POST)
	public String executeRegister(Spittr spittr,Model model) {\
		spitterRepository.save(spittr);
		model.addAttribute("username",spitter.getUsername());
		// 假設有一個POJO類為spittr,且有一個變數為Username,並生成一個getUsername()的方法
		// 5.4中的寫法
		// return "redirect:/home/" + spittr.getUsername()
		return "redirect:/home/{username}";

	}

將username作為佔位符填充到URL模板中,而不是直接連線字串,在佔位符中重新轉義編碼,提升了一定的安全性。

例2:

	@RequestMapping(value="/register",method=POST)
	public String executeRegister(Spittr spittr,Model model) {\
		spitterRepository.save(spittr);
		model.addAttribute("username",spitter.getUsername());
		model.addAttribute("userId",spitter.getId());
		// 假設有一個POJO類為spittr,且有一個變數為Username,並生成一個getUsername()的方法
		// 5.4中的寫法
		// return "redirect:/home/" + spittr.getUsername()
		return "redirect:/home/{username}";
	}

新增userId,但是在重定向路徑中並沒有userId的佔位符,重定向後它會被載入到尾部,假設ID=47,生成
/home/lihua?userId=47。有沒有對這個url比較熟悉,?後面的內容就是這樣子加上去的。

該方法的侷限性:在於它只可以傳送簡單的值,比如字串或者數字等,沒辦法處理更為複雜的值。處理複雜的值就是flash方法存在的意義。

第二章方法--flash

如果要傳送實際的物件等,Spring會將胯重定向存活的資料放到會話中,提供將資料傳送為flash屬性的功能,按照定義,flash屬性會一直攜帶這些資料直到下一次請求。提供RedirectAttributes設定flash屬性的方法。該模組不僅包含了Model的所有功能,還提供幾個方法設定flash屬性。

	@RequestMapping(value="/register",method=POST)
	public String executeRegister(Spittr spittr,RedirectAttributes model) {\
		spitterRepository.save(spittr);
		model.addAttribute("username",spitter.getUsername());
		// 假設有一個POJO類為spittr,且有一個變數為Username,並生成一個getUsername()的方法
		// 5.4中的寫法
		// return "redirect:/home/" + spittr.getUsername();
		model.addFlashAttribute("spitter",spitter);
		return "redirect:/home/{username}";

	}

"spitter"為key,後面spitter為值,而flash會自動進行推斷而不需要設定。

相關文章