SpringMVC
1.在SpringMVC中使用Session
當需要向Session中存入數據時,可以使用【ModelMap】
對象將數據進行封裝,操作方式與封裝轉發的數據完全相同,例如:
modelMap.addAttribute("username", username);
然後,需要在當前控制器類之前添加@SessionAttributes
註解,並且,在註解中顯式的指定ModelMap
中封裝的哪些數據是需要存儲在Session中的,例如:
@Controller
@RequestMapping(value="user")
@SessionAttributes("username")
public class UserController {
// ...
}
當添加了以上註解後,如果【ModelMap】
中被存入了名爲【username】
的數據,該數據就在Session中,而【ModelMap
】
中的其它數據依然只能用於轉發,也就是數據的作用域只在【Request】級別。
關於【@SessionAttributes】
註解,其屬性的配置可以參考該註解的源代碼:
@AliasFor("names")
String[] value() default {};
@AliasFor("value")
String[] names() default {};
Class<?>[] types() default {};
通過以上源代碼可以看到:【value】
和【names】
屬性的作用是完全相同,用於指定【ModelMap】
中的哪些名稱對應的數據需要存放到【Session】中,可以使用字符串數組表示多個屬性,另外,還可以配置【types】
屬性用於指定【Session】的數據的數據類型,也可以是數組類型,與配置的【names】
保持一致即可。
使用這種做法操作Session非常簡單,但是,也存在一系列的問題:
1.默認情況下,重定向時會把Session中的數據暴露在URL中;
2.通過ModelMap
存放的數據一定會在Request的作用域中,所以,通過這種方式存放到Session中的數據,其實在Request中也是存在的;
3.通過這種方式存放到Session中的數據,不可以通過Session對象的【invalidate()】
方法清除!只能通過SessionStatus
類的【setComplete()】
方法進行清除!
更加簡單的操作Session的方式就是直接在處理請求的方法中添加【HttpSession】
類型的參數,在方法體中直接操作即可。
@RequestMapping("handle_login.do")
public String handleLogin(String username, String password,
ModelMap modelMap, HttpSession session) {
// 日誌
System.out.println("UserController.handleLogin()");
System.out.println("\tusername=" + username);
System.out.println("\tpassword=" + password);
// 判斷用戶名是否正確
if ("root".equals(username)) {
// 是:判斷密碼是否正確
if ("1234".equals(password)) {
// 是:登錄成功,將用戶名存入到Session
// modelMap.addAttribute("username", username);
session.setAttribute("username", username);
// 重定向到主頁
return "redirect:../index.do";
} else {
// 否:密碼錯誤
modelMap.addAttribute("errorMessage", "ModelMap:密碼錯誤");
return "error";
}
} else {
// 否:用戶名錯誤
modelMap.addAttribute("errorMessage", "ModelMap:用戶名錯誤");
return "error";
}
}
使用這種做法並不存在以上使用@SessionAttributes
時的各種問題,操作也非常簡單,缺點就是不易於執行單元測試!
但有時可以忽略這個缺點,甚至“不使用@SessionAttributes
”,原因可能是:可以使用專門的測試工具去測試控制器,所以,在控制器中的方法本身是不需要執行單元測試的,甚至在大型項目中根本就不會使用Session,那各種使用方式都是不需要的!
2.在SpringMVC中統一處理異常
在Java中,異常的繼承體系是:
Throwable
Error
OutOfMemoryError
Exception
SQLException
IOEException
FileNotFoundException
RuntimeException
NullPointException
ClassNotFoundException
AirthmeticException
NumberFormatException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
常見異常處理的做法爲捕獲【try...catch】或者聲明拋出【throw/throws】,在實際處理時,如果當前類適合處理該異常,則捕獲,如果不適合,則聲明並向上層拋出,由上層調用者決定是否處理該異常,通常適合處理異常的都是【控制器】,但是異常可能在多個功能中都會出現,在處理不同的請求時,採用相同代碼處理,則會造成代碼冗餘,不便於統一管理,所以在SpringMVC框架中提供了統一處理異常的機制。
可以在控制器類中添加統一處理異常的方法,關於該方法:
1.使用【public】權限;
2.返回值的意義與處理請求的方法完全相同;
3.方法名稱可以自定義;
4.方法中必須包含異常類型的參數,且參數的類型能包括所有可能需要處理的異常;
5.與處理請求的方法不同,不可以使用【ModelMap】等對象,只能添加【HttpServletRequest】參數;
6.必須添加【@ExceptionHandler】註解,所以,處理i請求的方法可以是:
@ExceptionHandler
public String handleException(Throwable ex, HttpServletRequest request) {
if (ex instanceof NullPointerException) {
request.setAttribute("errorMessage", "空指針異常!");
} else if (ex instanceof ArrayIndexOutOfBoundsException) {
request.setAttribute("errorMessage", "數據下標越界異常異常!");
} else {
request.setAttribute("errorMessage", "未知異常:" + ex.getClass().getName());
}
return "error";
}
一旦添加了該方法,當前類中任何處理請求的方法都不需要處理相關異常,等同於這些方法把異常拋出了,所有拋出的異常將由該方法統一處理,需要注意的是,該方法只能處理該控制器出現的異常,其他控制器類拋出的異常不做處理。所以可以把該處理異常的方法放在所有控制器類公共的父類中,如【BaseController】!
關於@ExceptionHandler
的源代碼:
public @interface ExceptionHandler {
/**
* Exceptions handled by the annotated method. If empty, will default to any
* exceptions listed in the method argument list.
*/
Class<? extends Throwable>[] value() default {};
}
該註解可以指定需要被處理的異常的種類,允許定義多個異常處理方法,單獨處理同一類型異常,其參數可以是數組,即同時指定多種異常都將被該方法進行處理!
SpringMVC重點內容:
- 理解SpringMVC執行核心流程;
- 掌握獲取請求參數的方式;
- 理解轉發與重定向;
- 瞭解轉發時如何轉發數據;
- 掌握@RequestMapping、@RequestParam註解的使用;
- 掌握攔截器的使用;
- 掌握處理異常的使用。