在spring MVC的配置文件中:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- 總錯誤處理--> < bean id = "exceptionResolver" class = "org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" > < property name = "defaultErrorView" > < value >/error/error</ value > </ property > < property name = "defaultStatusCode" > < value >500</ value > </ property > < property name = "warnLogCategory" > < value >org.springframework.web.servlet.handler.SimpleMappingExceptionResolver</ value > </ property > </ bean > |
這里主要的類是SimpleMappingExceptionResolver類,和他的父類AbstractHandlerExceptionResolver類。
具體可以配置哪些屬性,我是通過查看源碼知道的。
你也可以實現HandlerExceptionResolver接口,寫一個自己的異常處理程序。spring的擴展性是很好的。
通過SimpleMappingExceptionResolver我們可以將不同的異常映射到不同的jsp頁面(通過exceptionMappings屬性的配置)。
同時我們也可以為所有的異常指定一個默認的異常提示頁面(通過defaultErrorView屬性的配置),如果所拋出的異常在exceptionMappings中沒有對應的映射,則Spring將用此默認配置顯示異常信息。
注意這里配置的異常顯示界面均僅包括主文件名,至于文件路徑和后綴已經在viewResolver中指定。如/error/error表示/error/error.jsp
顯示錯誤的jsp頁面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<%@ page language= "java" contentType= "text/html; charset=GBK" pageEncoding= "GBK" %> <%@ page import = "java.lang.Exception" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <meta http-equiv= "Content-Type" content= "text/html; charset=GBK" > <title>錯誤頁面</title> </head> <body> <h1>出錯了</h1> <% Exception e = (Exception)request.getAttribute( "exception" ); out.print(e.getMessage()); %> </body> </html> |
其中一句:request.getAttribute("exception"),key是exception,也是在SimpleMappingExceptionResolver類默認指定的,是可能通過配置文件修改這個值的,大家可以去看源碼。
如何把全局異常記錄到日志中?
在前的配置中,其中有一個屬性warnLogCategory,值是“SimpleMappingExceptionResolver類的全限定名”。我是在SimpleMappingExceptionResolver類父類AbstractHandlerExceptionResolver類中找到這個屬性的。查看源碼后得知:如果warnLogCategory不為空,spring就會使用apache的org.apache.commons.logging.Log日志工具,記錄這個異常,級別是warn。值:“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”,是“SimpleMappingExceptionResolver類的全限定名”。這個值不是隨便寫的。 因為我在log4j的配置文件中還要加入log4j.logger.org.springframework.web.servlet.handler.SimpleMappingExceptionResolver=WARN,保證這個級別是warn的日志一定會被記錄,即使log4j的根日志級別是ERROR。
如何給spring3 MVC中的Action做JUnit單元測試?
使用了spring3 MVC后,給action做單元測試變得很方便,我以前從來不給action寫單元測試的,現在可以根據情況寫一些了。 不用給每個Action都寫單元測試吧,自己把握。
JUnitActionBase類是所有JUnit的測試類的父類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
package test; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.BeforeClass; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.XmlWebApplicationContext; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping; /** * 說明: JUnit測試action時使用的基類 * * * */ public class JUnitActionBase { private static HandlerMapping handlerMapping; private static HandlerAdapter handlerAdapter; /** * 讀取spring3 MVC配置文件 */ @BeforeClass public static void setUp() { if (handlerMapping == null ) { String[] configs = { "file:src/springConfig/springMVCxml" }; XmlWebApplicationContext context = new XmlWebApplicationContext(); context.setConfigLocations(configs); MockServletContext msc = new MockServletContext(); context.setServletContext(msc); context.refresh(); msc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); handlerMapping = (HandlerMapping) context .getBean(DefaultAnnotationHandlerMapping. class ); handlerAdapter = (HandlerAdapter) context.getBean(context.getBeanNamesForType(AnnotationMethodHandlerAdapter. class )[ 0 ]); } } /** * 執行request對象請求的action * * @param request * @param response * @return * @throws Exception */ public ModelAndView excuteAction(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain chain = handlerMapping.getHandler(request); final ModelAndView model = handlerAdapter.handle(request, response, chain.getHandler()); return model; } } |
這是個JUnit測試類,我們可以new Request對象,來參與測試,太方便了。給request指定訪問的URL,就可以請求目標Action了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package test.com.app.user; import org.junit.Assert; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.servlet.ModelAndView; import testJUnitActionBase; /** * 說明: 測試OrderAction的例子 * * * */ public class TestOrderAction extends JUnitActionBase { @Test public void testAdd() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletResponse response = new MockHttpServletResponse(); request.setServletPath( "/order/add" ); request.addParameter( "id" , "1002" ); request.addParameter( "date" , "2010-12-30" ); request.setMethod( "POST" ); // 執行URI對應的action final ModelAndView mav = this .excuteAction(request, response); // Assert logic Assert.assertEquals( "order/add" , mav.getViewName()); String msg=(String)request.getAttribute( "msg" ); System.out.println(msg); } } |
需要說明一下 :由于當前最想版本的Spring(Test) 3.0.5還不支持@ContextConfiguration的注解式context file注入,所以還需要寫個setUp處理下,否則類似于Tiles的加載過程會有錯誤,因為沒有ServletContext。3.1的版本應該有更好的解決方案。