文章目录
- 一、Spring IoC 控制反转的案例
- 二、Spring 依赖注入方式(两种)的源码示例
- 2.1 setter 注入
- 2.2 有参构造函数注入
- 三、Spring 基于XML的AOP开发的源码示例
- 四、Spring 基于XML实现事务管理的源码示例
- 五、Spring MVC入门案例
- 六、Spring MVC实现文件上传
- 七、快速入门使用Spring MVC拦截器
- 八、Spring MVC拦截器的使用案例
- 九、Spring MVC自定义异常处理器
一、Spring IoC 控制反转的案例
首先用 Maven 快速搭建出 Web 项目后,在 pom.xml
文件中导入 Spring 开发的基本包坐标:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
第二步,编写 DAO层的 UserDao 接口和它的实现类:
public interface UserDao {
public void save();
}
package com.itheima.dao.impl;
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("执行save()方法");
}
}
第三步,创建 Spring 核心配置文件 applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"></bean>
</beans>
第四步,使用 Spring 的 API 获得 Bean 实例:
@Test
public void test1(){
//获取Spring ApplicationContext容器的实现类,并调用getBean()方法创建对象
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
二、Spring 依赖注入方式(两种)的源码示例
2.1 setter 注入
- 创建实体类Person。添加一个默认的无参构造函数(在没有其他有参构造函数的情况下,可省略不添加),并为所有需要注入的属性提供一个 setXxx() 方法。
package com.example.domain;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class Person {
//普通数据类型
private int pid;
private String pname;
//引用数据类型
private Student student;
//集合数据类型
private List<String> lists;
private Map<String, Student> maps;
private Properties properties;
//……
//生成getXxx() and setXxx()方法
//……
@Override
public String toString() {
return "普通数据类型的注入(直接传递的值):{pid=" + pid + ",pname=" + pname + '}' + '\n' +
"引用数据类型Student的注入:{student=" + student + '}' + '\n' +
"集合数据类型(List<String>)的注入:{lists=" + lists + '}' + '\n' +
"集合数据类型( Map<String,User> )的注入:{maps=" + maps + '}' + '\n' +
"集合数据类型(Properties)的注入:{properties=" + properties + '}';
}
}
其中的引用数据类型 Student.java :
package com.example.domain;
public class Student {
private int sid;
private String sname;
//……
//生成getXxx() and setXxx()方法
//……
@Override
public String toString() {
return "sid=" + sid + ", sname=" + sname;
}
}
- 编写配置文件 applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="app_person" class="com.example.domain.Person">
<!-- 使用 setter 设值注入Person对象依赖的各个属性,用 property 标签。 -->
<!-- 如果是直接传递一个值,应该使用 value 属性。 -->
<property name="pid" value="1"></property>
<property name="pname" value="张三"></property>
<!-- 如果不是直接传递一个值,应该使用 ref 属性。 -->
<property name="student" ref="app_student0"></property>
<property name="lists">
<list>
<value>list集合1</value>
<value>list集合2</value>
</list>
</property>
<property name="maps">
<map>
<entry key="m1">
<ref bean="app_student1"></ref>
</entry>
<entry key="m2">
<ref bean="app_student2"></ref>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">周八</prop>
<prop key="p2">吴九</prop>
</props>
</property>
</bean>
<bean id="app_student0" class="com.example.domain.Student">
<property name="sid" value="2"></property>
<property name="sname" value="李四"></property>
</bean>
<bean id="app_student1" class="com.example.domain.Student">
<property name="sid" value="1"></property>
<property name="sname" value="map_王五"></property>
</bean>
<bean id="app_student2" class="com.example.domain.Student">
<property name="sid" value="2"></property>
<property name="sname" value="map_赵六"></property>
</bean>
</beans>
- 编写测试代码。
@Test
//通过setter设值注入对象依赖的属性
public void test1(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) app.getBean("app_person");
System.out.println(person);
}
- 控制台打印结果。
普通数据类型的注入(直接传递的值):{pid=1,pname=张三}
引用数据类型Student的注入:{student=sid=2, sname=李四}
集合数据类型(List<String>)的注入:{lists=[list集合1, list集合2]}
集合数据类型( Map<String,User> )的注入:{maps={m1=sid=1, sname=map_王五, m2=sid=2, sname=map_赵六}}
集合数据类型(Properties)的注入:{properties={p2=吴九, p1=周八}}
2.2 有参构造函数注入
- 创建实体类Person,添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性。
package com.example.domain;
import java.util.List;
import java.util.Map;
import java.util.Properties;
//Person实体类包括引用类型 Teacher 类,基本数据类以及集合数据类型。
public class Person {
//普通数据类型
private int pid;
private String pname;
//引用数据类型
private Student student;
//集合数据类型
private List<String> lists;
private Map<String, Student> maps;
private Properties properties;
public Person() {
}
//有参构造函数
public Person(int pid, String pname,
Student student,
List<String> lists,
Map<String, Student> maps,
Properties properties) {
this.pid = pid;
this.pname = pname;
this.student = student;
this.lists = lists;
this.maps = maps;
this.properties = properties;
}
@Override
public String toString() {
return "普通数据类型的注入(直接传递的值):{pid=" + pid + ",pname=" + pname + '}' + '\n' +
"引用数据类型Student的注入:{student=" + student + '}' + '\n' +
"集合数据类型(List<String>)的注入:{lists=" + lists + '}' + '\n' +
"集合数据类型( Map<String,User> )的注入:{maps=" + maps + '}' + '\n' +
"集合数据类型(Properties)的注入:{properties=" + properties + '}';
}
}
其中的引用数据类型 Student.java :
package com.example.domain;
public class Student {
private int sid;
private String sname;
public Student() {
}
//有参构造函数
public Student(int sid, String sname) {
this.sid = sid;
this.sname = sname;
}
@Override
public String toString() {
return "sid=" + sid + ", sname=" + sname;
}
}
- 编写配置文件 applicationContext2.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="app_person" class="com.example.domain.Person">
<!-- 使用 有参构造函数注入Person对象依赖的各个属性,用 constructor-arg 标签。 -->
<!-- index:参数的位置,从0开始计算。
type:指的是参数的类型,在有多个构造函数时,可以用type来区分,要是能确定是哪个构造函数,可以不用写type。
value:给基本类型赋值。
ref:给引用类型赋值。 -->
<constructor-arg index="0" type="int" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="张三三"></constructor-arg>
<constructor-arg index="2" type="com.example.domain.Student" ref="app_student0"></constructor-arg>
<constructor-arg index="3" type="java.util.List">
<list>
<value>list集合11</value>
<value>list集合22</value>
</list>
</constructor-arg>
<constructor-arg index="4" type="java.util.Map">
<map>
<entry key="m1">
<ref bean="app_student1"></ref>
</entry>
<entry key="m2">
<ref bean="app_student2"></ref>
</entry>
</map>
</constructor-arg>
<constructor-arg index="5" type="java.util.Properties">
<props>
<prop key="p1">周八八</prop>
<prop key="p2">吴九九</prop>
</props>
</constructor-arg>
</bean>
<bean id="app_student0" class="com.example.domain.Student">
<constructor-arg index="0" type="int" value="2"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="李四四"></constructor-arg>
</bean>
<bean id="app_student1" class="com.example.domain.Student">
<constructor-arg index="0" type="int" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="map_王五五"></constructor-arg>
</bean>
<bean id="app_student2" class="com.example.domain.Student">
<constructor-arg index="0" type="int" value="2"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="map_赵六六"></constructor-arg>
</bean>
</beans>
- 编写测试代码
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext2.xml");
Person person = (Person) app.getBean("app_person");
System.out.println(person);
- 控制台打印结果。
普通数据类型的注入(直接传递的值):{pid=1,pname=张三三}
引用数据类型Student的注入:{student=sid=2, sname=李四四}
集合数据类型(List<String>)的注入:{lists=[list集合11, list集合22]}
集合数据类型( Map<String,User> )的注入:{maps={m1=sid=1, sname=map_王五五, m2=sid=2, sname=map_赵六六}}
集合数据类型(Properties)的注入:{properties={p2=吴九九, p1=周八八}}
三、Spring 基于XML的AOP开发的源码示例
- 导入 AOP 相关坐标
<!--导入spring的context坐标,context依赖aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--SpringJUnit4ClassRunner-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
- 创建目标接口和目标类(内部有切点)
package com.example.xmlaop;
public interface TargetInterface {
void save();
}
package com.example.xmlaop;
public class Target implements TargetInterface{
@Override
public void save() {
System.out.println("save() running");
//人为制造异常,测试异常抛出通知
//int i = 1/0;
}
}
- 创建切面类(内部有通知方法,亦称增强方法)
package com.example.xmlaop;
import org.aspectj.lang.ProceedingJoinPoint;
public class Aspect {
public void xmlAopBefore(){
System.out.println("前置通知");
}
public void xmlAopAfter(){
System.out.println("最终通知");
}
public void xmlAopAfterReturning(){
System.out.println("后置通知");
}
public void xmlAopAfterThrowing(){
System.out.println("异常抛出通知");
}
public Object xmlAopAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知(前)");
Object proceed = pjp.proceed();
System.out.println("环绕通知(后)");
return proceed;
}
}
- 将目标类和切面类的对象创建权交给 Spring,并在 applicationContext.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd ">
<!--目标对象-->
<bean id="xmlAopTarget" class="com.example.xmlaop.Target"></bean>
<!--切面对象。切面=切点+通知-->
<bean id="xmlAopAspect" class="com.example.xmlaop.Aspect"></bean>
<!--配置织入:告诉spring框架 哪些方法(切点)需要进行哪些增强(前置、后置...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="xmlAopAspect">
<!--抽取切点表达式-->
<aop:pointcut id="xmlAopPrintCut1" expression="execution(* com.example.xmlaop.*.*(..))"/>
<!--切面:切点+通知-->
<!--<aop:before method="xmlAopBefore" pointcut-ref="xmlAopPrintCut1"/>-->
<!--<aop:after method="xmlAopAfter" pointcut-ref="xmlAopPrintCut1"/>-->
<!--<aop:after-returning method="xmlAopAfterReturning" pointcut-ref="xmlAopPrintCut1"/>-->
<!--<aop:after-throwing method="xmlAopAfterThrowing" pointcut-ref="xmlAopPrintCut1"/>-->
<aop:around method="xmlAopAround" pointcut-ref="xmlAopPrintCut1"/>
</aop:aspect>
</aop:config>
</beans>
- 编写测试代码
package com.example.test;
import com.example.xmlaop.TargetInterface;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Autowired
private TargetInterface target;
@Test
public void Test1(){
target.save();
}
}
四、Spring 基于XML实现事务管理的源码示例
- pom.xml
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--@Test、Spring集成Junit、SpringJUnit4ClassRunner-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--导入spring的context坐标,context依赖aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<!--c3p0-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--jdbcTemplate-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--事务Transaction-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
- application.xml(引入tx命名空间,并配置事务增强和事务 AOP 织入
<?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: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 ">
<!--引入 jdbc.properties 中的配置-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--定义数据源 Bean-->
<bean id="dataSource_aop" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--给jdbcTemplate注入依赖属性-->
<bean id="jdbcTemplate_aop" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource_aop"/>
</bean>
<bean id="accountDao_aop" class="com.example.xml.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate_aop"/>
</bean>
<!--目标对象 内部的方法就是切点-->
<bean id="accountService_aop" class="com.example.xml.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao_aop"/>
</bean>
<!--配置平台事务管理器-->
<bean id="transactionManager_aop" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource_aop"/>
</bean>
<!--通知 事务的增强-->
<tx:advice id="txAdvice_aop" transaction-manager="transactionManager_aop">
<!--设置事务的属性信息的-->
<tx:attributes>
<!--每个方法可以配置不同的事务参数-->
<!--<tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>-->
<tx:method name="transferAccounts" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
<!--任意方法都使用默认的事务参数-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置事务的aop织入:<aop:advisor>-->
<aop:config>
<aop:pointcut id="txPointcut_aop" expression="execution(* com.example.xml.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice_aop" pointcut-ref="txPointcut_aop"/>
</aop:config>
</beans>
- domain层
package com.example.xml.domain;
public class Account {
private int id;
private String user_name;
private double user_balance;
//有参+无参构造方法
//getter()+setter()
//重写toString()
}
- dao层
package com.example.xml.dao;
public interface AccountDao {
void addMoney(String nameIn, double amountMoney);
void subMoney(String nameOut, double amountMoney);
}
package com.example.xml.dao.impl;
import com.example.xml.dao.AccountDao;
import org.springframework.jdbc.core.JdbcTemplate;
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void addMoney(String nameIn, double amountMoney) {
String sql = "update user_money set user_balance = user_balance + ? where user_name = ?";
jdbcTemplate.update(sql, amountMoney, nameIn);
}
@Override
public void subMoney(String nameOut, double amountMoney) {
String sql = "update user_money set user_balance = user_balance - ? where user_name = ?";
jdbcTemplate.update(sql, amountMoney, nameOut);
}
}
- service层
package com.example.xml.service;
public interface AccountService {
void transferAccounts(String nameIn, String nameOut, double money);
}
package com.example.xml.service.impl;
import com.example.xml.dao.AccountDao;
import com.example.xml.service.AccountService;
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao){
this.accountDao = accountDao;
}
@Override
public void transferAccounts(String nameIn, String nameOut, double money) {
accountDao.addMoney(nameIn, money);
//人为制造异常:java.lang.ArithmeticException: / by zero
//int i = 1/0;
accountDao.subMoney(nameOut, money);
}
}
- 测试事务控制转账业务代码
package com.example.xml.test;
import com.example.xml.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TxXmlTest {
@Test
public void test1() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = app.getBean(AccountService.class);
accountService.transferAccounts("郭襄","张三非", 500);
}
}
五、Spring MVC入门案例
需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。
- 导入Spring和SpringMVC的坐标、导入Servlet和Jsp的坐标
<!--Spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--SpringMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--Servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--Jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
- 在web.xml配置SpringMVC的核心控制器
<servlet>
<servlet-name>DispatcherServlet</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>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- 创建Controller和业务方法,给业务方法配置注解。创建视图页面index.jsp
package com.example.controller;
//import ……
@Controller
public class QuickController {
@RequestMapping("/quick")
public String quickMethod(){
System.out.println("quickMethod running.....");
return "index";
}
}
<html>
<body>
<h2>Hello SpringMVC!</h2>
</body>
</html>
- 创建spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<!--配置注解扫描-->
<context:component-scan base-package="com.example.controller"/>
</beans>
- 访问测试地址
http://localhost:8080/springmvc1/quick
六、Spring MVC实现文件上传
单文件上传源码示例:
- 添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
- 配置多媒体解析器
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="500000"/>
</bean>
- 前端页面
<form action="${pageContext.request.contextPath}/user/quick23" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br/>
文件1<input type="file" name="uploadFile"><br/>
<input type="submit" value="提交">
</form>
- 后台Java代码
@RequestMapping(value="/quick22")
@ResponseBody
public void save22(String username, MultipartFile uploadFile) throws IOException {
System.out.println(username);
//获得上传文件的名称
String originalFilename = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("C:\\upload\\"+originalFilename));
}
多文件上传源码示例:
多文件上传,只需要将页面修改为多个文件上传项,将方法参数 MultipartFile 类型修改为 MultipartFile[] 即可。
- 前端页面
<form action="${pageContext.request.contextPath}/user/quick23" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br/>
文件1<input type="file" name="uploadFile"><br/>
文件2<input type="file" name="uploadFile"><br/>
<input type="submit" value="提交">
</form>
- Java代码
@RequestMapping(value="/quick23")
@ResponseBody
public void save23(String username, MultipartFile[] uploadFile) throws IOException {
System.out.println(username);
for (MultipartFile multipartFile : uploadFile) {
String originalFilename = multipartFile.getOriginalFilename();
multipartFile.transferTo(new File("C:\\upload\\"+originalFilename));
}
}
七、快速入门使用Spring MVC拦截器
- 创建拦截器类实现HandlerInterceptor接口
package com.example.interceptor;
//import ……
public class MyInterceptor1 implements HandlerInterceptor {
//在目标方法执行之前 执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
System.out.println("preHandle.....");
}
//在目标方法执行之后 视图对象返回之前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
System.out.println("postHandle...");
}
//在流程都执行完毕后 执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("afterCompletion....");
}
}
- 配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--/**对所有资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.example.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
- 测试拦截器的拦截效果
@Controller
public class TargetController {
//编写Controller,发请求到controller,跳转页面
@RequestMapping("/target")
public ModelAndView show(){
System.out.println("目标资源执行......");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","itcast");
modelAndView.setViewName("index");
return modelAndView;
}
}
- JSP页面
<html>
<body>
<h2>Hello World! ${name}</h2>
</body>
</html>
八、Spring MVC拦截器的使用案例
用户登录权限控制。需求:用户没有登录的情况下,不能对后台菜单进行访问操作,点击菜单跳转到登录页面,只有用户登录成功后才能进行后台功能的操作。源码如下。
- 判断用户是否登录。判断session中有没有user,如果没有登陆则先去登陆,如果已经登陆则直接放行访问目标资源。
public class PrivilegeInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
//逻辑:判断用户是否登录 本质:判断session中有没有user
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if(user==null){
//没有登录
response.sendRedirect(request.getContextPath()+"/login.jsp");
return false;
}
//放行 访问目标资源
return true;
}
}
- 在登陆页面输入用户名密码,点击登陆,通过用户名密码进行查询,如果登陆成功,则将用户信息实体存入session,然后跳转到首页,如果登陆失败则继续回到登陆页面。在UserController中编写登陆逻辑:
@RequestMapping("/login")
public String login(String username,String password,HttpSession session){
User user = userService.login(username,password);
if(user!=null){
//登录成功 将user存储到session
session.setAttribute("user",user);
return "redirect:/index.jsp";
}
return "redirect:/login.jsp";
}
service层代码:
//service层
public User login(String username, String password) {
try {
User user = userDao.findByUsernameAndPassword(username,password);
return user;
}catch (EmptyResultDataAccessException e){
return null;
}
}
dao层代码:
//dao层
/*JdbcTemplate.queryForObject对象如果查询不到数据会抛异常,导致程序无法达到预期效果,如何来解决该问题?在service业务层处理来自dao层的异常,如果出现异常service层返回null,而不是将异常抛给controller。*/
public User findByUsernameAndPassword(String username, String password) throws EmptyResultDataAccessException{
User user = jdbcTemplate.queryForObject("select * from sys_user where username=? and password=?", new BeanPropertyRowMapper<User>(User.class), username, password);
return user;
}
- 配置拦截器。找到项目案例的spring-mvc.xm,添加拦截+排除拦截资源的配置:
<!--配置权限拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--配置对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<!--配置哪些资源排除拦截操作-->
<mvc:exclude-mapping path="/user/login"/>
<bean class="com.itheima.interceptor.PrivilegeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
九、Spring MVC自定义异常处理器
实现Spring的异常处理接口 HandlerExceptionResolver
自定义自己的异常处理器。有如下四步。
- 创建异常处理器类实现
HandlerExceptionResolver
。
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object o, Exception e) {
//处理异常的代码实现
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
if(e instanceof ClassCastException){
modelAndView.addObject("info", "类型转换异常");
}
modelAndView.setViewName("exceptionPage");//exceptionPage.jsp
return modelAndView;
}
}
- 在spring-mvc.xml文件中配置异常处理器。
<bean class="com.itheima.exception.MyExceptionResolver"/>
- 编写异常页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
这是一个最终异常的显示页面:${info}
</body>
</html>
- 测试异常跳转。
@RequestMapping("/quick22")
@ResponseBody
public void quickMethod22() throws IOException, ParseException {
Object str = "abc";
Integer i = (Integer) str;
return "index";
}