拦截器和springmvc异常处理、springjdbc
什么是拦截器
DispatcherServlet收到请求之后,如果有拦截器,则先执行拦截器的方法,再执行处理器(Controller)的方法
过滤器属于Servlet规范,拦截的是Servlet容器调用过程
而拦截器属于Spring框架,拦截的是DispatcherServlet的调用过程
如何写拦截器
- 写一个java类,实现HandlerInterceptor接口
- 在接口方法当中,实现拦截处理逻辑
- 配置拦截器
添加jar包依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.company</groupId>
<artifactId>TestDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- servlet的jar包依赖, <scope>provided</scope> 表示编译时有效,不会打包发布到Tomcat中 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- jsp的jar包依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- jstl表达式 -->
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<!-- 添加tomcat插件 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<hostName>localhost</hostName>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置前端控制器
<?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">
<display-name>TestDemo</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Controller的编写
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello() {
System.out.println("hello()");
return "hello";
}
@RequestMapping("/demo/hello2")
public String hello2() {
System.out.println("hello2()");
return "hello";
}
}
hello.jsp
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body style="font-size:30px;">
Hello Kitty
</body>
</html>
编写拦截器
- 1、先调用preHandle,返回true继续向后执行,返回false中断请求
- 2、调用Controller(处理器)返回ModelAndView给前端控制器之前调用postHandle
- 3、请求处理完毕,最后调用afterCompletion
package inceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class SomeInceptor implements HandlerInterceptor {
/*
* DispatcherServlet在收到请求之后,
* 会先调用 拦截器的preHandle方法。
* 如果该方法的返回值是true,是继续向后执行;
* 如果该方法的返回值是false,
* 则中断请求,返回结果。
* handler:处理器方法对象
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle()");
return true;
}
/*
* 处理器(Controller)的方法执行完毕,正准备将
* 处理结果(ModelAndView)返回给DispatcherServlet
* 之前,执行postHandle方法。
* 注:
* 可以在该方法里面,修改处理结果(ModelAndView)。
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle()");
}
/*
*整个请求处理完毕,最后执行的方法。
*ex:处理器方法所抛出的异常
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion()");
}
}
配置拦截器
在springmvc的配置文件中配置拦截器
<?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" />
<!-- 配置MVC注解扫描 -->
<mvc:annotation-driven />
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
<!--静态资源的加载 -->
<mvc:resources location="/" mapping="/**" />
<!-- 配置springmvc的拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="inceptor.SomeInceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
页面访问
控制台输出
拦截器的优先级
依据配置的先后顺序执行。
SpringMVC中的异常处理
可以将异常抛给Spring框架,由Spring框架来处理异常
配置简单异常处理器
在springmvc的配置文件中添加配置如下
<!-- 配置简单异常处理器 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--java.lang.NumberFormatException:异常类型, erro1:视图页面 -->
<prop key="java.lang.NumberFormatException">erro1</prop>
</props>
</property>
</bean>
添加异常处理页面:jsp页面
<%@ page contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body style="font-size:30px;">
请输入正确的数字
</body>
</html>
3、控制器的编写
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello() {
System.out.println("hello()");
Integer.parseInt("123a");
return "hello";
}
}
4、页面访问
http://localhost:8080/TestDemo/hello
@ExceptionHandler注解
- 在处理器类里面增加一个异常处理方法,该方法前面需要添加@ExceptionHandler
- Spring框架捕获到异常之后,会调用异常处理方法
- 在异常处理方法里面,编写异常处理逻辑
- 添加异常处理页面
增加一个异常处理方法
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 {
@RequestMapping("/hello")
public String hello() {
System.out.println("hello()");
Integer.parseInt("123a");
return "hello";
}
@RequestMapping("/hello2")
public String hello2() {
System.out.println("hello2()");
"1234".charAt(8);
return "hello";
}
/*
* e:处理器方法所抛出的异常
*/
@ExceptionHandler
public String handleEx(Exception e,HttpServletRequest request) {
System.out.println("handleEx()");
if(e instanceof NumberFormatException) {
request.setAttribute("msg","请输入合法的数字");
return "error3";
}
if(e instanceof StringIndexOutOfBoundsException) {
request.setAttribute("msg","下标越界啦");
return "error3";
}
//其他异常
return "error";
}
}
添加异常处理页面
error.jsp
<%@page pageEncoding="utf-8"
contentType="text/html; charset=utf-8" %>
<html>
<head></head>
<body style="font-size:30px;">
系统繁忙,稍后重试
</body>
</html>
error3.jsp
<%@page pageEncoding="utf-8"
contentType="text/html; charset=utf-8" %>
<html>
<head></head>
<body style="font-size:30px;">
${msg}
</body>
</html>
页面访问
配有拦截器的调用过程
SpringJdbc
什么是SpringJdbc
Spring框架对jdbc的封装。
注:比起直接使用jdbc,使用SpringJdbc代码更简洁,质量更高。
比如,不用考虑获取连接与关闭连接等操作。
如何使用
1、导包
spring-webmvc,spring-jdbc,mysql,dbcp,junit
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--springjdbc的jar包依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--mysql -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!--数据库连接池,dbcp -->
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!--junit:单元测试 -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2、添加Spring配置文件
配置JdbcTemplate
<?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">
<!-- 配置数据库连接池 -->
<util:properties location="classpath:db.properties" id="db"/>
<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="#{db['jdbc.driver']}"/>
<property name="url" value="#{db['jdbc.url']}"/>
<property name="username" value="#{db['jdbc.username']}"/>
<property name="password" value="#{db['jdbc.password']}"/>
</bean>
<!-- 配置组件扫描 -->
<context:component-scan base-package="dao"/>
<!-- 配置JdbcTemplate -->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jt">
<property name="dataSource" ref="ds"/>
</bean>
</beans>
3、添加entity和dao(持久层)
package entity;
public class Employee {
private int id;
private String ename;
private double salary;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Employee [id=" + id + ", ename=" + ename + ", salary=" + salary + ", age=" + age + "]";
}
}
调用JdbcTemplate提供的方法来访问数据库,通常将JdbcTemplate注入到DAO
package dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import entity.Employee;
@Repository("employeeDAO")
public class EmployeeDAO {
@Autowired
@Qualifier("jt")
JdbcTemplate jt;
/*
*新增数据
*/
public void save(Employee e){
String sql="insert into t_emp values(null,?,?,?)";
//数组元素应该与?一一对应
Object[]args= {
e.getEname(),e.getSalary(),e.getAge()
};
jt.update(sql,args);
}
/*
*查询所有数据
*/
public List<Employee>findAll(){
String sql="select * from t_emp";
List<Employee>employees=jt.query(sql, new EmpRowMapper());
return employees;
}
/*
*根据id查询
*/
public Employee findById(int id) {
String sql="select * from t_emp where id=?";
Object[]args= {id};
Employee e=null;
try {
e=jt.queryForObject(sql, args, new EmpRowMapper());
}catch(EmptyResultDataAccessException e1) {
/*
* 找不到对应的记录,queryForObject方法。
* 会抛出EmptyResultDataAccessException
*/
return null;
}
return e;
}
/*
*更新数据
*/
public void update(Employee e) {
String sql="update t_emp set ename=?,salary=?,age=? where id=?";
Object[]args= {
e.getEname(),e.getSalary(),e.getAge(),e.getId()
};
jt.update(sql, args);
}
/*
*根据id删除数据
*/
public void delete(int id) {
String sql="delete from t_emp where id=?";
Object[]args= {id};
jt.update(sql, args);
}
/**
* 负责高速JdbcTemplate如何将记录转换成一个对象,
* rowNum:正在被处理的记录的下标
*/
class EmpRowMapper implements RowMapper<Employee>{
public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
Employee e=new Employee();
e.setId(rs.getInt("id"));
e.setEname(rs.getString("ename"));
e.setSalary(rs.getDouble("salary"));
e.setAge(rs.getInt("age"));
return e;
}
}
}
测试程序
package test;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import dao.EmployeeDAO;
import entity.Employee;
public class TestCase {
EmployeeDAO dao;
//junit在执行测试方法前,会先执行@Before修饰的方法
@Before
public void before() {
String config = "spring-jdbc.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
dao = ac.getBean("employeeDAO", EmployeeDAO.class);
}
@Test
public void save() {
Employee e = new Employee();
e.setEname("小月");
e.setSalary(20000);
e.setAge(22);
dao.save(e);
}
@Test
public void findAll() {
List<Employee> employees = dao.findAll();
for (Employee employee : employees) {
System.out.println(employee);
}
}
@Test
public void findById() {
Employee e=dao.findById(3);
System.out.println(e);
}
@Test
public void update() {
Employee e=dao.findById(3);
e.setAge(e.getAge()+10);
e.setSalary(e.getSalary()*2);
dao.update(e);
}
@Test
public void delete() {
dao.delete(3);
}
}