Spring 学习源码示例

一、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 注入
  1. 创建实体类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;
    }
}
  1. 编写配置文件 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>
  1. 编写测试代码。
@Test
//通过setter设值注入对象依赖的属性
public void test1(){
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person person = (Person) app.getBean("app_person");
    System.out.println(person);
}
  1. 控制台打印结果。
普通数据类型的注入(直接传递的值):{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 有参构造函数注入
  1. 创建实体类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;
    }
}
  1. 编写配置文件 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>
  1. 编写测试代码
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext2.xml");
Person person = (Person) app.getBean("app_person");
System.out.println(person);
  1. 控制台打印结果。
普通数据类型的注入(直接传递的值):{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开发的源码示例

  1. 导入 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>
  1. 创建目标接口和目标类(内部有切点)
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;
    }
}
  1. 创建切面类(内部有通知方法,亦称增强方法)
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;
    }
}
  1. 将目标类和切面类的对象创建权交给 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>
  1. 编写测试代码
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实现事务管理的源码示例

  1. 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>
  1. application.xml(引入tx命名空间,并配置事务增强和事务 AOP 织入。jdbc.properties文件参考:五、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: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>
  1. domain层
package com.example.xml.domain;

public class Account {
    private int id;
    private String user_name;
    private double user_balance;
    //有参+无参构造方法
    //getter()+setter()
    //重写toString()
}
  1. 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);
    }
}
  1. 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);
    }
}
  1. 测试事务控制转账业务代码
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入门案例

需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。

  1. 导入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>
  1. 在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>
  1. 创建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>
  1. 创建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>
  1. 访问测试地址
http://localhost:8080/springmvc1/quick 

六、Spring MVC实现文件上传

单文件上传源码示例:

  1. 添加依赖
<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>
  1. 配置多媒体解析器
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="maxUploadSize" value="500000"/>
</bean>
  1. 前端页面
<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>
  1. 后台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[] 即可。

  1. 前端页面
<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>
  1. 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拦截器

  1. 创建拦截器类实现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....");
    }
}
  1. 配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--/**对所有资源执行拦截操作-->
        <mvc:mapping path="/**"/>
        <bean class="com.example.interceptor.MyInterceptor1"/>
    </mvc:interceptor>
</mvc:interceptors>
  1. 测试拦截器的拦截效果
@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;
    }
}
  1. JSP页面
<html>
<body>
<h2>Hello World! ${name}</h2>
</body>
</html>

八、Spring MVC拦截器的使用案例

用户登录权限控制。需求:用户没有登录的情况下,不能对后台菜单进行访问操作,点击菜单跳转到登录页面,只有用户登录成功后才能进行后台功能的操作。源码如下。

  1. 判断用户是否登录。判断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;
    }
}
  1. 在登陆页面输入用户名密码,点击登陆,通过用户名密码进行查询,如果登陆成功,则将用户信息实体存入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;
}
  1. 配置拦截器。找到项目案例的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 自定义自己的异常处理器。有如下四步。

  1. 创建异常处理器类实现 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;
    }
}
  1. 在spring-mvc.xml文件中配置异常处理器。
<bean class="com.itheima.exception.MyExceptionResolver"/>
  1. 编写异常页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
	<title>Title</title>
</head>
<body>
	这是一个最终异常的显示页面:${info}
</body>
</html>
  1. 测试异常跳转。
@RequestMapping("/quick22")
@ResponseBody
public void quickMethod22() throws IOException, ParseException {
    Object str = "abc";
    Integer i = (Integer) str;
    return "index";
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值