SpringMVC从入门到掌握


文章目录

  • SpringMVC从入门到掌握
  • 1. SpringMvc的概述
  • 2. SpringMvc的搭建
  • 3. SpringMvc的常用注解总结
  • 4. 实体对象绑定请求参数
  • 5. 处理数据模型
  • 6. 关于重定向与转发
  • 7. REST的描述
  • 8. REST的限制与优点
  • 9. HTTP请求的四种状态
  • 10. 数据转换器
  • 创建测试方法
  • 11. 数据校验
  • hibernate Validator扩展注解
  • 12. 基于Accept-Language实现国际化
  • 13. 基于HttpSession实现国际化(多种手动语言切换)
  • 14. 拦截器
  • 15. 文件的上传与下载
  • 16. 异常的处理方式


1. SpringMvc的概述
  • Spring MVC为展现层提供的基于MVC设计理念的优秀Web框架,是目前最主流的MVC框架之一。
  • Spring3.0后全面超越了Struts2,称为最优秀的MVC框架。
  • Spring MVC通过一套MVC注解,让POJO称为处理请求的控制器,无需实现任何接口。
  • 支持REST风格的Web请求。采用了松散耦合可插拔组件结构,比其它MVC框架更具扩展性和灵活性。
2. SpringMvc的搭建
  1. 导入依赖
<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>5.1.1.RELEASE</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>javax.servlet-api</artifactId>
	    <version>4.0.1</version>
	    <scope>provided</scope>
	</dependency>
	<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
	<dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>jstl</artifactId>
	    <version>1.2</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
	<dependency>
	    <groupId>com.fasterxml.jackson.core</groupId>
	    <artifactId>jackson-databind</artifactId>
	    <version>2.9.7</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
	<dependency>
		<groupId>org.hibernate.validator</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>6.0.13.Final</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
		<version>2.0.1.Final</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
	<dependency>
		<groupId>org.jboss.logging</groupId>
		<artifactId>jboss-logging</artifactId>
		<version>3.3.2.Final</version>
	</dependency>
  1. 配置xml文件
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
           <!-- SpringMVC配置文件路径 -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.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>
<!-- 注意:如果没有配置 init-param 设置文件路径,SpringMvc默认回去WEB-INF下查询 servlet-nameservlet.xml -->
  1. 创建处理类
    注解
@Controller // 修饰类为一个控制器
  public class HelloWorld { 
    @RequestMapping("/hello") // 修饰方法(或类)的请求路径
    public String hello(){
        System.out.println("hello spring mvc");
        return "hello"; // 视图
    }
  }
<!-- 配置Spring MVC自动扫描的路径 -->
  <context:component-scan base-package="com.*.controller" />
   <!-- 配置视图解析器 将视图返回字符串解析到:/WEB-INF/view/返回值.jsp 下-->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 视图前缀 -->
    <property name="prefix" value="/WEB-INF/view/" />
    <!-- 视图后置 -->
    <property name="suffix" value=".jsp" />
  </bean>

接口

public class HelloWorld implements Controller{
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("HelloWorld");
        return new ModelAndView("hello"); // 视图
    }
  }
<!-- name:代表访问路径 class:指定控制器类 -->
  <bean name="/helloworld" class="com.znsd.controller.HelloWorld" />

两种方式,推荐使用注解 (不是必须,分情况而待)

3. SpringMvc的常用注解总结
  • @Component:一个普通的Bean类。
  • @Repository :用于标注持久层DAO类
  • @Service :用于标注业务层类
  • @Controller :用于标注控制器类
  • @RequestMapping:
  • 类定义处:提供初步的映射信息,为该类下所有请求方法添加前缀。
  • 方法定义处:提供进一步的映射信息,提供方法的请求路径。
@Controller
  @RequestMapping("world") // 类似Struts2的@Namespace(命名空间)
  public class HelloWorld { 
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("hello spring mvc");
        return "hello";
    }
  }
  1. @RequestMapping 的 value、method、params及heads分别表示请求url,请求方法,请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可以让请求更加精确化。
  2. 在@RequestMapping 中 还支持 Ant风格的URL。
  • ?:匹配文件中一个字符。
  • *:匹配文件中任意字符。
  • **:匹配多层路径。
/user/*/create:匹配/user/aaa/create,/user/bbb/crate
  /user/**/create:匹配/user/create,/user/aaa/bbb/create
  /user/create??:匹配/user/createaa,/user/createbb
  • @PathVariable:URL模版方式
// @PathVariable:用来映射URL中的占位符。映射的变量名必须和占位符中的名称一致。
  @RequestMapping("/delete/{userid}")
  public String delete(@PathVariable("userid")int userid) {
    System.out.println("userid=" + userid);
    return "hello";
  }
  • @RequestParam:获取请求参数
// @RequtParam:获取页面传递过来的参数,GET和POST都支持。
 @RequestMapping("/testRequestParam")
 public String testRequestParam(@RequestParam("username")String username, @RequestParam("age")int age){
    System.out.println("username=" + username);
    System.out.println("age=" + age);
    return "hello";
  }

@RequestParam 还有三个属性

  • value:指定参数的名称
  • required:指定参数是否为必填 (boolean)
  • defaultValue:指定参数的默认值
  • @RequestHeader:获取请求头内容
// 请求头包含了若干的属性,用来获取客户端的信息。通过@RequestHeader可以用来获取请求头中的信息
  @RequestMapping("/testRequestHeader")
  public String testRequestHeader(@RequestHeader("Accept-Language") String language){
    System.out.println("language=" + language);
    return "hello";
  }
  • @CookiValue:获取客户端Cookie
// @CookieValue:用来获取客户端Cookie信息。
  @RequestMapping("/testCookieValue")
  public String testCookieValue(@CookieValue("JSESSIONID")String sessionid){
    System.out.println("sessionid=" + sessionid);
    return "hello";
  }
  • @ResponseBody:标识为Json返回
  • 需要导入依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
	<dependency>
	    <groupId>com.fasterxml.jackson.core</groupId>
	    <artifactId>jackson-databind</artifactId>
	    <version>2.9.7</version>
	</dependency>
@ResponseBody
@RequestMapping(value="/testJackson",method=RequestMethod.GET)
public Student testJackson() {
	User user = new User();
	user.setName("李相如");
	return user;
}
4. 实体对象绑定请求参数
<!-- name必须和对象属性名一至 -->
<form action="world/user/create" method="post">
    姓名:<input type="text" name="name"><br>
    密码:<input type="text" name="pass"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交" />
 </form>
public class User {
    private String name;
    private String pass;
    private int age;
  }
// Spring MVC会直接将页面元素和实体对象进行匹配,自动转换为实体对象.并且支持级联属性。如address.city等。
  @RequestMapping(value = "/user/create", method = RequestMethod.POST)
  public String createUser(User user) {
    System.out.println(user.toString());
    return "hello";
  }
5. 处理数据模型

Spring MVC提供一下几种途径返回模型数据:

  • ModeAndView:将处理方法的返回类型设置为ModeAndView,方法体即可通过该模型对象添加模型数据。
  • 控制器处理方法如果返回ModelAndView,即包含视图信息,也包含模型信息。
  • 构造方法:提供了多种构造方法的重载
  • 添加模型数据:
  • ModelAndView addObject(String attributeName, Object attributeValue);
  • ModelAndView addAllObjects(Map modelMap) ;
  • 添加视图
  • void setView(View view);
  • void setViewName(String viewName);
@RequestMapping("/testModelAndView")
  public ModelAndView testModelAndView(){
    ModelAndView modelAndView = new ModelAndView("hello");
    //添加单个值
    modelAndView.addObject("h","Hello Spring MVC");     
    return modelAndView;
  }
  • Map及Model形参:当形参为Map,Model,ModelMap时,处理方法返回时,Map中的数据会自动添加到模型中。
  • Spring MVC在内部使用了一个Model接口存储模型数据。
  • Spring MVC在调用方法前会创建一个隐含的模型对象作为数据模型的存储容器。如果传入的参数为Map或者Model类型,SpringMVC会自动将对象保存到模型数据中。
@RequestMapping("/testMap")
  public String testMap(Map<String,Object> map){
    map.put("mapdata", "map data");
    return "hello";
  }
  • @SessionAttributes:将模型中的某个属性存储到Session中,以便多个请求之间共享这个属性。
  • 如果希望在多个请求之间共享某个模型的数据,则可以在控制器类上标注一个@SessionAttributes,SpringMVC会将对应的属性存储到Session中。
  • @SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些类型放到Session中。
  • @SessionAttributes(types=User.class) :将隐含模型中所有类型为User属性添加到Session中。
  • @SessionAttributes(value={“user1”,“user2”}):将user1对象和user2放入Session中。
// 保存到Session中
 @SessionAttributes("user")
  @Controller
  @RequestMapping("world")
  public class HelloWorld {
    @RequestMapping("/testSession")
    public String testSession(Map<String,Object> map){
        User user = new User();
        user.setUsername("zhangsan");
        user.setUserpass("123");
        user.setAge(20);
        map.put("user", user);
        return "hello";
    }
  }
  • @SessionAttributes只能用来修饰类。
  • @ModelAttribute:方法形参标记该注解后,形参对象就会放到模型中。
  • 在方法定义上定义@ModelAttribute注解:
  • SpringMVC调用方法前,会优先调用方法上标注了@ModelAttributes的方法。
  • 将@ModelAttributes中的属性保存到map中,可以在执行表单提交生成对象之前,替换执行方法同名的形参。
@ModelAttribute
public void before(Map<String, Object> map,User user) {
	user.setName("123");
	user.setPass("123456);
	map.put("userInfo", user);
}

@RequestMapping(value="/testModelAttribute")
	public String testModelAttribute(User user) {
	student.setName("456");
	System.out.println(user);
	return "success";
}
### 自定义视图
// 添加一个自定义视图,实现View接口。
  @Component  //把视图放到IOC容器里面 ,这里视图的名字就是helloView
  public class HelloView implements View {

    @Override
    public String getContentType() {
        return "text/html";
    }

    @Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        response.getWriter().println("hello view current time : " + new Date());
    }
  }
<!-- 通过BeanNameViewResolver定义名称视图解析器。 -->
  <!-- BeanNameViewResolver 解析器:使用视图的名字来解析视图 -->
  <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
    <!-- order值越小优先级越高 -->
    <!-- InternalResourceViewResolver的order值是inter的最大值,所以一般来说都是最后调用的 -->
    <property name="order" value="100" />
  </bean>
  <!-- 在Spring 配置文件中将自定义视图的包添加到自动扫描路径中。 -->
  <context:component-scan base-package="com.znsd.springmvc.view" />
@RequestMapping(value="/testCustomView",method=RequestMethod.GET)
public ModelAndView testCustomView() {
	return new ModelAndView(new HelloView());
}
6. 关于重定向与转发
  • 一般情况下,控制器返回字符串类型的值会被当成逻辑视图名进行处理。
  • 如果返回字符串中带有forward:或者redirect:前缀时,SpringMVC会将其进行特殊处理。将forward:和redirect:作为指示符,其后面字符串作为url来处理。
// 当使用转发与重定向时 springmvc不会使用视图解析配置前后缀不会添加,转发可以访问WEB-INF下文件,重定向不能
  @RequestMapping("forward")
  public String testForward() {
      return "forward:/success.jsp"; // 会完成一个到 success.jsp的转发操作。
  }

  @RequestMapping("redirect")
  public String testRedirect() {
      return "redirect:/success.jsp"; // 会完成一个到 success.jsp的重定向操作。
  }
7. REST的描述
  • 用URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作
  • REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)
  • Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。例如:web_service/studentInfo----获取学生信息
  • 用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转
  • GET 获取资源/POST 新建资源/PUT 更新资源/DELETE 删除资源
  • Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。当然还可以压缩HTTP传输时的数据
  • 用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等
8. REST的限制与优点
  • 客户-服务器(Client-Server)客户端服务器分离 ,
  • 提高用户界面的便携性(操作简单)
  • 通过简化服务器提高可伸缩性(高性能,低成本)
  • 允许组件分别优化(可以让服务端和客户端分别进行改进和优化)
  • 无状态(Stateless):客户端的每个请求要包含服务器所需要的所有信息
  • 提高可见性(可以单独考虑每个请求)
  • 提高了可靠性(更容易从局部故障中修复)
  • 提高可扩展性(降低了服务器资源使用)
  • 缓存(Cachable)
  • 减少交互次数,交互的平均延迟
  • 分层系统(Layered System)
  • 系统组件不需要知道与他交流组件之外的事情。封装服务,引入中间层,限制了系统的复杂性,提高可扩展性
  • 统一接口(Uniform Interface)
  • 提高交互的可见性,鼓励单独改善组件
  • 支持按需代码(Code-On-Demand 可选)
  • 提高可扩展性
9. HTTP请求的四种状态
  • GET:获取资源
  • POST:新建资源
  • PUT:更新资源
  • DELETE:删除资源
10. 数据转换器
  1. 自定义数据转换器
@Component
public class MyConverter implements Converter<String, User> {

	@Override
	public Student convert(String source) {//前台传过来一串字符串,通过split分割成一个String数组
		String [] str = source.split("-");
		User user = new User();
		user.setName(str[0]);
		user.setPass(str[1]);
		return user;
	}

}
  1. 将自定义的数据转换器放入SpringMvc提供的转换器中
<!-- FormattingConversionServiceFactoryBean 包含了 ConversionServiceFactoryBean ,既可以数据转换也可以数据格式化 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<property name="converters">
			<set>
				<ref bean="myConverter" />
			</set>
		</property>
</bean>
  1. 将转换器注册到annotation-driven中
<!-- 该配置为springmvc基础配置,很多功能需要该注解来协调,建议配置文件配完后加入该注解 -->
<mvc:annotation-driven conversion-service="conversionService" />
  1. 创建jsp
<a href="handler/testConverter.action?studentInfo=3-第十三-?">testConverter</a>
创建测试方法
@RequestMapping(value="/testConverter",method=RequestMethod.GET)
public ModelAndView testConverter(@RequestParam("studentInfo") Student student) {
	System.out.println(student);
	return new ModelAndView("success");
}
11. 数据校验

注意:springMvc是没有校验的,它使用的校验是Hibernate框架的

  1. 导入依赖
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
	<dependency>
		<groupId>org.hibernate.validator</groupId>
		<artifactId>hibernate-validator</artifactId>
		<version>6.0.13.Final</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
	<dependency>
		<groupId>javax.validation</groupId>
		<artifactId>validation-api</artifactId>
		<version>2.0.1.Final</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.jboss.logging/jboss-logging -->
	<dependency>
		<groupId>org.jboss.logging</groupId>
		<artifactId>jboss-logging</artifactId>
		<version>3.3.2.Final</version>
	</dependency>
  </dependencies>
  1. 在相应字段添加校验注解
@Email
private String email;

注解

说明

@Null

必须为null

@NotNull

必须不为null

@AssertTrue

必须为true

@AssertFalse

必须为false

@Min(value)

必须为一个数字,其值必须大于等于指定的最小值

@Max(value)

必须为一个数字,其值必须小于等于指定的最小值

@DecimalMin(value)

必须为一个数字,其值必须大于等于指定的最小值

@DecimalMax(value)

必须为一个数字,其值必须小于等于指定的最小值

@Size(max,min)

元素的大小必须在指定范围内

@Digits(int,fraction)

必须是一个数字,其值必须在可接受范围内

@Past

必须是一个过去的日期

@Future

必须是一个将来的日期

@Pattern(value)

其值必须符合指定的正则表达式

hibernate Validator扩展注解
  • Hibernate Validator是JSR3.0的一个扩展组件,除支持所有标准的效验注解外,它还支持以下扩展注解

注解

说明

@Email

被修饰的元素必须是电子邮件

@Length

被修饰的元素长度必须在指定的范围内

@NotEmpty

被修饰的元素必须非空

@Range

被修饰的元素必须在合适的范围内

  1. 编写测试方法
@RequestMapping(value="/testFormat",method=RequestMethod.POST)
public String testFormat(@Valid User user, BindingResult result,Map<String, Object> map) {
    if (result.getErrorCount() > 0) {
        for (FieldError error : result.getFieldErrors()) {
            System.out.println("------>"+error.getDefaultMessage());
            map.put("errors", result.getFieldErrors());
        }
    }
    return "login";
}
12. 基于Accept-Language实现国际化
  1. 编写properties
    i18n_zh_CN.properties
resource.name=\u5148\u751F
resource.msg=\u4F60\u597D

i18n_en_US.properties

resource.name=先生
resource.msg=你好
  1. 配置bean
<!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="i18n" />
	</bean>
  1. 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
	<fmt:message key="resource.describe" />
	<fmt:message key="resource.oneself" /> 
</body>
</html>

是跟据当前地区转换页面可以设置浏览器语言查看出效果

13. 基于HttpSession实现国际化(多种手动语言切换)
  1. 编写properties
    i18n_zh_CN.properties
resource.name=\u5148\u751F
resource.msg=\u4F60\u597D

i18n_en_US.properties

resource.name=先生
resource.msg=你好
  1. 配置bean
<!-- 国际化 springmvc会自动扫描id为messageSource的bean 然后把该bean的配置介入 -->
	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
		<property name="basename" value="i18n" />
	</bean>
<!-- 自定义国际化 -->
	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" >
		<property name="defaultLocale" value="zh_CN" />	<!-- 默认为中文 -->
	</bean> 
    <mvc:interceptors>
      <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> <!-- 需放在拦截器中 -->
    </mvc:interceptors>
  1. 创建视图并且导入<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
	<fmt:message key="resource.describe" />
	<fmt:message key="resource.oneself" /> 
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<!-- start 使用message 标签配置需要显示的国际化文本,  locale  对应国际化文件中对应的键的名称  -->
    <a href="hello.action?locale=zh_CN">Chinese</a>
	<a href="hello.action?locale=en_US">English</a>
</body>
</html>
14. 拦截器
  1. bean实现拦截器
package com.znsd.springmvc.expand;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor implements HandlerInterceptor {

  /**
     * 进入目标方法之前调用
     * 返回true:则继续调用后续的拦截器和目标方法
     * 返回false:则不会调用后续的拦截器和目标方法
     * 使用场景:权限控制、日志处理、事务...
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("FirstInterceptor.preHandle()");
        return true;
    }

    /**
     * 调用目标方法之后,在渲染页面之前调用
     * 使用场景:
     * 1.需要改变request对象中的值
     * 2.需要修改modelAndView中的值
     * 3.修改转向的视图
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("FirstInterceptor.postHandle()");
    }

    /**
     * 渲染页面完成之后调用
     * 使用场景:做一些销毁工作
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("FirstInterceptor.afterCompletion()");
    }
	
}
  1. 自定义拦截器
<mvc:interceptors>
      <mvc:interceptor>
      	<mvc:mapping path="/handler/testInterceptor.action"/>
      	<bean class="com.znsd.springmvc.expand.MyInterceptor" />
      </mvc:interceptor>
    </mvc:interceptors>
15. 文件的上传与下载
  1. jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
  <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="handler/fileupload.action" method="post" enctype="multipart/form-data">
	    <input type="file" name="file" /> 
	    <input type="submit" value="上传" />
	</form>
</body>
</html>
  1. handler
package com.znsd.springmvc.handler;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.ServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/handler")
public class DemoHandler {

	@RequestMapping("/fileupload")
	public String fileupload(ServletRequest request, @RequestParam("file") MultipartFile file, Model model)
	    throws IOException {
	    if (!file.isEmpty()) {
	        String imageurl = saveFile(request, file);
	        model.addAttribute("imageurl", imageurl);
	    } else {
	        model.addAttribute("message", "请选择要上传的文件");
	    }
	    return "success";
	}
    
    // 下载
    @RequestMapping("/downFile")
	  public ResponseEntity<byte[]> testdownFile(HttpSession session) throws IOException {
	      ServletContext servletContext = session.getServletContext();
	      InputStream in = servletContext.getResourceAsStream("downloads/down.txt");
	      byte[] bytes = FileCopyUtils.copyToByteArray(in);

	      HttpHeaders header = new HttpHeaders();
	      header.add("Content-Disposition", "attachment;filename=down.txt");

	      ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(bytes, header, HttpStatus.OK);
	      return entity;
	  }
	
	private String saveFile(ServletRequest request, MultipartFile file) throws IOException {
	    // 获取文件的上传路径
	    String uploadPath = request.getServletContext().getRealPath("uploads");
	    System.out.println(uploadPath);
	    File uploadPathFile = new File(uploadPath);
	    if (!uploadPathFile.exists()) {
	        uploadPathFile.mkdirs();
	    }
	    // 获取文件名称
	    String filename = file.getOriginalFilename();
	    // 截取文件后缀
	    String fileext = filename.substring(filename.lastIndexOf("."));
	    // 生成新的随机文件名称
	    String newfileName = UUID.randomUUID() + fileext;
	    // 文件保存路径
	    File savePath = new File(uploadPath + "/" + newfileName);
	    // 上传文件
	    file.transferTo(savePath);
	    return "uploads/" + newfileName;
	}
}
16. 异常的处理方式
  1. 配置xml
<!-- 配置使用SimpleMappingExceptionResolver来映射异常 -->
  <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
      <!-- 给异常命名一个别名 -->
      <property name="exceptionAttribute" value="ex"></property>
      <property name="exceptionMappings">
          <props>
              <!-- 一定要异常的全类名。 表示出现异常,就跳转到error.jsp视图 -->
              <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
          </props>
      </property>
  </bean>
  1. @ExceptionHandler注解实现异常处理异常类
/**
 * 全局异常处理类,在项目中推荐使用全局异常处理类去处理所有异常信息
 * @author Administrator
 */
@ControllerAdvice
public class ExceptionHandlerAdvice {


    /**
     * 在项目总如果没有对异常有页面要求,那么一个异常页面就够了
     * 有些项目需要对每一类型的异常都有对象异常页面,比如前台的异常处理、后台异常处理
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    @ExceptionHandler(value = { NullPointerException.class, IndexOutOfBoundsException.class })
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // 如果要将异常传递到视图中(jsp页面),必须使用ModelAndView来进行数据传递
        // 不能使用Map形参的方式,否则会报错
        System.out.println("ExceptionHandlerAdvice.resolveException()");
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("ex", ex);
        ModelAndView mv = new ModelAndView("error", map);
        return mv;
    }
}
  1. HandlerExceptionResolver 接口自定义异常处理器
@Component // 将自定义异常类装载到spring容器中
  public class CustomeException implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        Map<String, Object> map = new HashMap<String, Object>();
        if (ex instanceof NullPointerException) {
            map.put("ex", ex);
            return new ModelAndView("nullPointer", map); // 指定异常对应的视图页面
        } 
        if (ex instanceof IndexOutOfBoundsException) {
            return new ModelAndView("indexOutOf", map); // 指定异常对应的视图页面
        }
        return new ModelAndView("error", map);
    }
  }