二 基于Spring的异常体系处理
1.Spring的DAO异常体系
Spring在DAO层建立了一套面向DAO层统一的异常体系,同时将各种访问数据的检查型异常转换为非检查型异常,为整合各种持久层框架(spring JDBC,Hibernate,ibatis)提供基础。
Spring将DAO层进行了封装,形成统一的异常体系架构,其基类为DataAccessException。
2、基于spring的JEE体系架构异常处理方案
程序中对于异常的处理,应遵循一个原则,那就是能处理的异常要处理,不能处理的异常要抛出去,二不能隐藏或遗漏异常的处理。同时,针对抛出的异常,我们应根据类型分为应用异常和系统异常。
应用异常是由于违反相关的业务逻辑而导致的错误。该错误不是致命的错误,可把错误信息报告给用户,来提醒用户,用户可通过重新操作来完成预期的业务。针对应用系统异常,应划分更详细的子异常,以满足业务的需要才是有意义的。
系统异常是程序系统发生的bug错误或出现的致命错误,此时必须终止服务,抛出错误。即使用户再重复操作,也不能完成业务将受限,是后台管理员关注的。
针对这种情况,我们可以定义如下的异常:
(1)数据层异常
spring框架提供了统一的DAO异常处理架构,其基类为DataAccessException。分析下数据库的操作和抛出的DataAccessException子类,以区分哪些是应用异常,哪些是系统异常。
插入操作:应抛出DuplicateKeyException(应用异常)和DataAccessException(系统异常)。
查询操作:findbyPrimarykey 应抛出ObjectNotFoundException(应用异常)和DataAccessException(系统异常)。count应抛出DataAccessException(系统异常)。
更新操作:应抛出ObjectNotFoundException(应用异常)DuplicateKeyException(应用异常)和DataAccessException(系统异常)。
删除操作:应抛出ObjectNotFoundException(应用异常)和DataAccessException(系统异常)。
spring的DAO层异常架构将异常统一为非检查异常。我们在DAO层的代码中可以将上述的异常抛出,也可以不做异常处理,但在业务层的处理中必须将这些异常捕获出来转换为我们定义的应用异常和系统异常。
下面的代码都可以接受:
public addUser(User){ 框架集成接口 }
public addUser(user)throws DuplicateKeyException,DataAccessExceptiom{ //orm框架接口操作 }
(2)业务层异常处理
业务层中,通过异常链保存原始异常信息。程序员必须自己编码来保存原始异常的信息。在业务逻辑中,捕获DataAccessException异常,处理包装成SystemException异常抛出。捕获ObjectNotFoundException,DuplicateKeyException异常,处理包装成BusinessException异常抛出。业务层中应根据业务的不同,将异常尽量分得细一点,否则,自定义的异常没有太多的意义。
业务层异常处理代码如下:
public addUser(User user) throws BusinessException,SystemException{ try{ userDao.addUser(user); }catch(DuplicatekeyException ex){ log.infor("......................"); throw new BusinessException(ex.getCause(),"国际化信息"); }catch(DataAccessException ex){ log.error("......................"); throw new SystemException(ex.getCause(),"国际化信息"); } }
(3) 表现层异常处理
在控制层,我们需要将通过try..catch方法进行捕获异常,经行包装处理,保存异常信息,将错误信息同时转到error页面。下面以spring MVC方式举例说明异常页面的处理。
I. 公共页面403,404. 405,500错误需要配置在web.xml中
web.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SpringExceptionResearch</display-name> <!--******************************** --> <!--*******log4j日志信息的配置,设置在classpath根目录下 ,spring中很多代码使用了不同的日志接口, 既有log4j也有commons-logging,这里只是强制转换为log4j!并且,log4j的配置文件只能放在classpath根路径。 同时,需要通过commons-logging配置将日志控制权转交给log4j。同时commons-logging.properties必须放置 在classpath根路径****** --> <!--******************************* --> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j.xml</param-value> </context-param> <!--Spring默认刷新Log4j配置文件的间隔,单位为millisecond,可以不设置 --> <context-param> <param-name>log4jRefreshInterval</param-name> <param-value>60000</param-value> </context-param> <!--******************************** --> <!--*******spring bean的配置******** --> <!--applicationContext.xml用于对应用层面做整体控制。按照分层思想, 统领service层,dao层,datasource层,及国际化层--> <!--******************************* --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <!--******************************** --> <!--*******字符集 过滤器************ --> <!--******************************* --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Spring 分发器,设置MVC配置信息 --> <servlet> <servlet-name>SpringExceptionResearch</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!--******************************** --> <!--***使用.html后缀,一方面用户不能通过URL知道我们采用何种服务端技术, 同时,可骗过搜索引擎,增加被收录的概率 。真正的静态网页可以用.htm,以避免被框架拦截--> <!--******************************* --> <servlet-mapping> <servlet-name>SpringExceptionResearch</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <error-page> <error-code>403</error-code> <location>/WEB-INF/pages/error/403.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/WEB-INF/pages/error/404.jsp</location> </error-page> <error-page> <error-code>405</error-code> <location>/WEB-INF/pages/error/405.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/WEB-INF/pages/error/500.jsp</location> </error-page> </web-app>
2、在dispatch对应的MVC xml配置如下
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置静态资源,直接映射到对应的文件夹,不被DispatcherServlet处理 --> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/html/**" location="/html/"/> <mvc:resources mapping="/common/**" location="/common/"/> <!-- Configures the @Controller programming model --> <mvc:annotation-driven /> <!--扫描web包,应用Spring的注解--> <context:component-scan base-package="com.jason.web"/> <bean id="captchaProducer" name= "captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"> <property name="config"> <bean class="com.google.code.kaptcha.util.Config"> <constructor-arg> <props> <prop key="kaptcha.image.width">300</prop> <prop key="kaptcha.image.height">60</prop> <prop key="kaptcha.textproducer.char.string">0123456789</prop> <prop key="kaptcha.textproducer.char.length">4</prop> </props> </constructor-arg> </bean> </property> </bean> <!-- 全局异常配置 start --> <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 系统常见设置statusCodes --> <property name="exceptionMappings"> <props> <prop key="com.jason.exception.SystemException">error/500</prop> <prop key="com.jason.exception.BusinessException">error/errorpage</prop> </props> </property> <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 --> <property name="warnLogCategory" value="WARN"></property> <!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 --> <property name="defaultErrorView" value="error/500"></property> <!-- 默认HTTP状态码 --> <property name="defaultStatusCode" value="500"></property> </bean> <!-- 全局异常配置 end --> <!--启动Spring MVC的注解功能,设置编码方式,防止乱码--> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <bean class = "org.springframework.http.converter.StringHttpMessageConverter"> <property name = "supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> </list> </property> </bean> </list> </property> </bean> <!--对模型视图名称的解析,即在模型视图名称添加前后缀InternalResourceViewResolver--> <!--默认的就是JstlView所以这里就不用配置viewClass --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/pages/" p:suffix=".jsp" /> </beans>