Unit06: Spring对JDBC的 整合支持 、 Spring+JDBC Template 、Spring异常处理
1. springmvc提供的异常处理机制
我们可以将异常抛给spring框架,让spring来帮我们处理异常。
(1)使用简单异常处理器
step1. 配置简单异常处理器。
step2. 添加对应的异常处理页面。
注:该方式只适合处理简单异常的处理,如果要对异常做复杂处理,比如
记录日志等,则不合适了。
(2)使用@ExceptionHandler注解
step1. 在处理器类当中,添加一个异常处理方法, 该方法要使用@ExceptionHandler注解来标注。
step2.添加对应的异常处理页面。
2. SpringJdbc
(1)SpringJdbc是什么?
是spring框架中的一个模块,对jdbc api做了封装,简化了 jdbc的代码(比如,不用考虑获取连接与关闭连接了)
(2)编程步骤
step1. 导包。
step2. 添加spring配置文件。
step3. 添加JdbcTemplate配置。
注:JdbcTemplate对jdbc的api做了封装。
step4. 调用JdbcTemplate提供的方法。
注:通常将JdbcTemplate注入到DAO。
-
springmvc提供的异常处理机制代码
src/main/java
controller
package controller; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @ExceptionHandler public String handler(Exception ex, HttpServletRequest request){ System.out.println("handler()"); /* * 依据异常类型,分别进行相应的处理。 * ex:就是方法所抛出的异常。 */ if(ex instanceof NumberFormatException){ request.setAttribute("msg", "亲,请输入正确的数字"); return "error"; }else if(ex instanceof StringIndexOutOfBoundsException){ request.setAttribute("msg", "下标越界了"); return "error"; }else{ //其它异常 return "sys_error"; } } @RequestMapping("/toHello.do") public String toHello(){ System.out.println("toHello()"); String str = "123a"; Integer.parseInt(str); return "hello"; } @RequestMapping("/toHello2.do") public String toHello2(){ System.out.println("toHello2()"); String str = "abcd"; str.charAt(10); return "hello"; } }
interceptors
package interceptors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class SomeInterceptor implements HandlerInterceptor{ /** * 最后执行的方法。 * ex:处理器所抛出的异常。 */ public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object arg2, Exception ex) throws Exception { System.out.println("afterCompletion()"); } /** * 在处理器已经执行完毕,正准备将处理结果 * (ModelAndView)返回给前端控制器之前,执行 * postHandle方法。 * 注:可以在该方法里面,修改处理结果。 */ public void postHandle( HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView mav) throws Exception { System.out.println("postHandle()"); } /** * 如果该方法返回值为true,表示继续向后 * 调用(即调用后面的拦截器和处理器); * 如果该方法的返回值为false,则不再向后 * 调用,返回处理结果。 * arg2: 处理器方法对象。 */ public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception { System.out.println("preHandle()"); return true; } }
src/main/resources
<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"> <!-- 配置组件扫描 --> <context:component-scan base-package="controller"/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 配置拦截器 --> <!-- <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="interceptors.SomeInterceptor"/> </mvc:interceptor> </mvc:interceptors> --> <!-- 配置简单异常处理器 --> <!-- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="java.lang.NumberFormatException">ex1</prop> <prop key="java.lang.StringIndexOutOfBoundsException">ex2</prop> </props> </property> </bean> --> </beans>
WEB-INF
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <html> <head></head> <body style="font-size:30px;"> ${msg} </body> </html>
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <html> <head></head> <body style="font-size:30px;"> 请输入正确的数字 </body> </html>
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <html> <head></head> <body style="font-size:30px;"> 下标越界 </body> </html>
<h1>Hello,SpringMVC</h1>
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <html> <head></head> <body style="font-size:30px;"> 系统繁忙,稍后重试 </body> </html>
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet的初始化方法在执行时, 会启动spring容器。 contextConfigLocation负责指定spring 配置文件的位置。 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.2.8.RELEASE</version> </dependency> </dependencies>
SQL语句:
CREATE table emp_fre( id number(8) primary key, name varchar2(50), age number(3) ); CREATE sequence emp_seq_fre;
src/main/java
com.tarena.netctoss.controller
package com.tarena.netctoss.controller; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.tarena.netctoss.dao.AdminDAO; import com.tarena.netctoss.entity.Admin; @Controller public class LoginController { @Resource(name="adminDAO") private AdminDAO dao; @RequestMapping("/toLogin.do") public String toLogin(){ System.out.println("toLogin()"); return "login"; } @RequestMapping("/login.do") public String login( HttpServletRequest request){ System.out.println("login()"); String adminCode = request.getParameter("adminCode"); String pwd = request.getParameter("pwd"); System.out.println("adminCode:" + adminCode + " pwd:" + pwd); //使用DAO来访问数据库 Admin admin = null; try{ admin = dao.findByAdminCode(adminCode); }catch(Exception e){ e.printStackTrace(); //系统异常,需要提示用户稍后重试 return "error"; } if(admin == null){ //帐号错误 request.setAttribute( "login_failed", "帐号错误"); return "login"; }else{ if(admin.getPassword().equals(pwd)){ //登录成功 return "redirect:toIndex.do"; }else{ //密码错误 request.setAttribute( "login_failed", "密码错误"); return "login"; } } } @RequestMapping("/toIndex.do") public String toIndex(){ return "index"; } }
com.tarena.netctoss.dao
package com.tarena.netctoss.dao; import com.tarena.netctoss.entity.Admin; public interface AdminDAO { public Admin findByAdminCode(String adminCode); }
package com.tarena.netctoss.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.annotation.Resource; import javax.sql.DataSource; import org.springframework.stereotype.Repository; import com.tarena.netctoss.entity.Admin; @Repository("adminDAO") public class AdminDAOJdbcImpl implements AdminDAO{ @Resource(name="ds") private DataSource ds; public Admin findByAdminCode( String adminCode) { Admin admin = null; Connection conn = null; try { conn = ds.getConnection(); String sql = "select * from admin_info_lhh " + "where admin_code=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, adminCode); ResultSet rs = ps.executeQuery(); if(rs.next()){ admin = new Admin(); admin.setAdminId(rs.getInt("admin_id")); admin.setAdminCode(rs.getString("admin_code")); admin.setPassword(rs.getString("password")); admin.setName(rs.getString("name")); admin.setTelephone(rs.getString("telephone")); admin.setEmail(rs.getString("email")); admin.setEnrolldate(rs.getTimestamp("enrolldate")); } } catch (SQLException e) { //记日志 e.printStackTrace(); /* * 要看异常能否恢复,如果能够恢复, * 则立即恢复,如果不能够恢复( * 比如,数据库服务停止,一般称这样 * 的异常为系统异常),则提示用户稍后 * 重试。 */ throw new RuntimeException(e); }finally{ if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } return admin; } }
com.tarena.netctoss.entity
package com.tarena.netctoss.entity; import java.io.Serializable; import java.sql.Timestamp; public class Admin implements Serializable { private Integer adminId; private String adminCode; private String password; private String name; private String telephone; private String email; private Timestamp enrolldate; @Override public String toString() { return "Admin [adminId=" + adminId + ", adminCode=" + adminCode + ", password=" + password + ", name=" + name + ", telephone=" + telephone + ", email=" + email + ", enrolldate=" + enrolldate + "]"; } public Integer getAdminId() { return adminId; } public void setAdminId(Integer adminId) { this.adminId = adminId; } public String getAdminCode() { return adminCode; } public void setAdminCode(String adminCode) { this.adminCode = adminCode; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Timestamp getEnrolldate() { return enrolldate; } public void setEnrolldate(Timestamp enrolldate) { this.enrolldate = enrolldate; } }
src/main/resources
# db connection parameters # key=value driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@192.168.201.227:1521:orcl user=openlab pwd=open123 # datasource parameters initSize=1 maxSize=1
<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd"> <!-- 配置组件扫描 --> <context:component-scan base-package="com.tarena.netctoss"/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 读取properties文件的内容 --> <util:properties id="db" location="classpath:db.properties"/> <!-- 配置连接池 --> <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="#{db.driver}" /> <property name="url" value="#{db.url}" /> <property name="username" value="#{db.user}" /> <property name="password" value="#{db.pwd}" /> </bean> </beans>
src/test/java
test
package test; import java.sql.SQLException; import javax.sql.DataSource; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.tarena.netctoss.dao.AdminDAO; import com.tarena.netctoss.entity.Admin; public class TestCase { @Test public void test1() throws SQLException{ ApplicationContext ac = new ClassPathXmlApplicationContext( "spring-mvc.xml"); DataSource ds = ac.getBean("ds", DataSource.class); System.out.println( ds.getConnection()); } @Test //测试 DAO public void test2(){ ApplicationContext ac = new ClassPathXmlApplicationContext( "spring-mvc.xml"); AdminDAO dao = ac.getBean("adminDAO", AdminDAO.class); Admin admin = dao.findByAdminCode("caocao"); System.out.println("admin:" + admin); } }
WEB-INF
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>达内-NetCTOSS</title> <link type="text/css" rel="stylesheet" media="all" href="styles/global.css" /> <link type="text/css" rel="stylesheet" media="all" href="styles/global_color.css" /> <script language="javascript" type="text/javascript"> var timer; //启动跳转的定时器 function startTimes() { timer = window.setInterval(showSecondes,1000); } var i = 5; function showSecondes() { if (i > 0) { i--; document.getElementById("secondes").innerHTML = i; } else { window.clearInterval(timer); location.href = "toLogin.do"; } } //取消跳转 function resetTimer() { if (timer != null && timer != undefined) { window.clearInterval(timer); location.href = "toLogin.do"; } } </script> </head> <body class="error_page" onload="startTimes();"> <h1 id="error"> 遇到错误, <span id="secondes">5</span> 秒后将自动跳转,立即跳转请点击 <a href="javascript:resetTimer();">返回</a> </h1> </body> </html>
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>达内-NetCTOSS</title> <link type="text/css" rel="stylesheet" media="all" href="styles/global.css" /> <link type="text/css" rel="stylesheet" media="all" href="styles/global_color.css" /> </head> <body class="index"> <!--导航区域开始--> <div id="index_navi"> <ul id="menu"> <li><a href="index.html" class="index_on"></a></li> <li><a href="role/role_list.html" class="role_off"></a></li> <li><a href="admin/admin_list.html" class="admin_off"></a></li> <li><a href="fee/fee_list.html" class="fee_off"></a></li> <li><a href="account/account_list.html" class="account_off"></a></li> <li><a href="service/service_list.html" class="service_off"></a></li> <li><a href="bill/bill_list.html" class="bill_off"></a></li> <li><a href="report/report_list.html" class="report_off"></a></li> <li><a href="user/user_info.html" class="information_off"></a></li> <li><a href="user/user_modi_pwd.html" class="password_off"></a></li> </ul> </div> </body> </html>
<%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>达内-NetCTOSS</title> <link type="text/css" rel="stylesheet" media="all" href="styles/global.css" /> <link type="text/css" rel="stylesheet" media="all" href="styles/global_color.css" /> </head> <body class="index"> <div class="login_box"> <form action="login.do" method="post"> <table> <tr> <td class="login_info">账号:</td> <td colspan="2"><input name="adminCode" type="text" class="width150" /></td> <td class="login_error_info"><span class="required">30长度的字母、数字和下划线</span></td> </tr> <tr> <td class="login_info">密码:</td> <td colspan="2"><input name="pwd" type="password" class="width150" /></td> <td><span class="required">30长度的字母、数字和下划线</span></td> </tr> <tr> <td class="login_info">验证码:</td> <td class="width70"><input name="" type="text" class="width70" /></td> <td><img src="images/valicode.jpg" alt="验证码" title="点击更换" /></td> <td><span class="required">验证码错误</span></td> </tr> <tr> <td></td> <td class="login_button" colspan="2"> <a href="javascript:document.forms[0].submit();"><img src="images/login_btn.png" /></a> </td> <td><span class="required"> ${login_failed}</span></td> </tr> </table> </form> </div> </body> </html>
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet的初始化方法在执行时, 会启动spring容器。 contextConfigLocation负责指定spring 配置文件的位置。 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <filter> <filter-name>encodingFilter</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> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc14</artifactId> <version>10.2.0.4.0</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>