前端Ajax/JS/HTML+後端SpringMVC(二)
1. jQuery AJAX
1.1. jQuery框架中的ajax()函數
在應用了jQuery框架後,調用ajax()
函數即可發出AJAX請求,並獲取響應結果,該函數的參數必須是JSON對象,通常,在JSON對象中封裝的屬性有:
url:處理請求的URL,也可以理解為將請求發送到哪個URL,取值可以是絕對路徑,或相對路徑,但是,不可以跨域
data:請求的數據,通常是
username=xx&password=xx&phone=xx
類似的格式,可以通過字符串拼接得到該值,也可以通過jQuery中的$("#form-id").serialize()
函數將整個表單中所有控件的值都封裝起來,使用這個函數時,是以控件的名稱與控件中的值進行封裝的,所以,需要註意各控件的名稱type:請求的類型,可以是
get
或post
dataType:響應的數據的類型,可以是
text
、xml
、json
,主流做法多使用json
,但是,具體使用哪一種,取決於服務器響應時給出的Response Headers中的Content-TypebeforeSend:發出請求之前如何處理,取值是函數,用於決於具體執行的代碼,多用於例如:將發出請求的按鈕禁用,以避免在沒有響應之前卻反復提交請求
success:成功響應後如何處理,取值是函數,success對應的函數只在正確的響應情況下被執行,如果服務端的響應碼是302、4xx、5xx,並不會導致success對應的函數被執行!該處理函數可以添加參數,參數即是服務端響應的數據,如果
dataType
json
,則此處的函數參數類型就是JSON對象error:響應出錯如何處理,取值是函數,只要響應碼是3xx、4xx、5xx,都會導致error對應的函數被執行!
2. 異常的處理
2.1. 設計案例
創建簡單的案例,發出/test/null.do
請求,服務端將產生NullPointerException
,發出/test/array.do
請求,服務端將產生ArrayIndexOutOfBoundsException
。
2.2. 創建並完成案例
創建Maven Project,Group Id使用com.company.spring
,Artifact Id使用SPRINGMVC-04-EXCEPTION
檢查spring-mvc.xml
的配置,在組件掃描的包下創建TestController
,使用@Controller
和@RequestMapping("/test")
註解:
@Controller
@RequestMapping("/test")
public class TestController {
}
然後添加2個方法處理2個請求,並在處理過程中,使得程序出現對應的異常:
@RequestMapping("/null.do")
public String handleNull() {
String str = null;
str.length();
return null;
}
@RequestMapping("/array.do")
public String handleArray() {
int[] arr = { 0 };
System.out.println(arr[10]);
return null;
}
2.3. 【不推薦】使用SimpleMappingExceptionResolver
如果沒有對異常進行處理,默認的處理方式下,會把異常的跟蹤信息顯示在頁面中,這種做法會導致較差的用戶體驗,並且可能對外泄露了當前的業務邏輯甚至是項目機密。但是,頻繁的使用try...catch
語法來處理異常,則很大程度上增加了編碼的難度,也不易於統一規劃和處理!
SpringMVC中提供了SimpleMappingExceptionResolver
,可以配置異常與轉發到的視圖的對應關系,也就是說:只要出現了某種異常,就直接轉發到某個視圖,而不需要編寫try...catch
相關代碼:
<!-- 處理異常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 異常與轉發到的視圖的映射 -->
<property name="exceptionMappings">
<props>
<prop key="java.lang.NullPointerException">error_null</prop>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error_array</prop>
</props>
</property>
</bean>
使用這種做法最大的問題:無法針對某個問題進行詳細的處理!也無法將具體的錯誤信息顯示在頁面中!
2.4. 【推薦】使用@ExceptionHandler
在控制器類中自定義某個方法,用於統一處理異常,這個方法需要使用@ExceptionHandler
註解,並且,可以使用Exception
作為方法的參數:
@ExceptionHandler
public String handleException(Exception e) {
return null;
}
每當出現異常時,SpringMVC就會自動調用以上方法,並且將捕獲的異常對象作為調用該方法的參數,則處理時:
@ExceptionHandler
public String handleException(Exception e, HttpServletRequest request) {
String message = e.getMessage();
if (e instanceof ArrayIndexOutOfBoundsException) {
request.setAttribute("msg", message);
return "err_array";
}
return null;
}
註意:嘗試轉發數據時,可以使用HttpServletRequest參數,也可以使用ModelAndView返回值,卻不可以使用ModelMap參數。
2.5. Q&A
Q:使用@ExceptionHandler和配置SimpleMappingExceptionResolver這2個做法來處理異常會沖突嗎?
A:兩者同時使用,代碼並不會出現錯誤,但是,對於同一個異常,註解方式優先。
Q:使用@ExceptionHandler這種方式處理異常時,可以不使用轉發作為處理方式,而是直接響應JSON數據嗎?
A:可以!在處理異常的方法之前添加@ResponseBody
註解,並且將方法的返回值調整為ResponseResult
即可(需要事先添加Jackson依賴,配置註解驅動)
Q:使用@ExceptionHandler這種方式處理異常時,處理異常的方法可以作用於其它控制器類中處理請求方法嗎?
A:不可以!常規做法是定義BaseController
類,在這個類中添加處理異常的方法,然後,項目中所有其它的控制器類都繼承自這個類!例如:
public abstract class BaseController {
@ExceptionHandler(ServiceException.class)
@ResponseBody
public ResponseResult handleException(ServiceException e) {
// 準備返回值
ResponseResult rr = new ResponseResult();
// 向返回結果中封裝錯誤信息
rr.setMessage(e.getMessage());
// 判斷異常
if (e instanceof UserNotFoundException) {
rr.setState(401);
} else if (e instanceof PasswordNotMatchException) {
rr.setState(402);
} else if (e instanceof UpdateException) {
rr.setState(500);
} else {
rr.setState(600);
}
// 返回
return rr;
}
}
2.6. 小結
在開發項目時,業務層會在出現各種業務錯誤的情況下拋出不同的業務異常,例如此前項目中的UserNotFoundException
、PasswordNotMatchException
……而控制器層調用業務層的方法時,就需要處理這些異常,而某些異常出現的次數可能較多,反復的使用try...catch
不便於統一處理,代碼也顯得非常復雜!
SpringMVC提供的統一處理異常的方式有2種,分別是使用SimpleMappingExceptionResolver
和使用@ExceptionHandler
註解,前者在處理方面非常有局限性!一般對於業務異常的處理,推薦使用後者!
關於業務異常的處理,通常會在項目中創建BaseController
,然後在這個類中編寫處理異常的方法,項目中實際使用的其它控制器類都應該繼承自BaseController
。
前端Ajax/JS/HTML+後端SpringMVC(二)