SpringMVC学习

206 阅读12分钟

SpringMVC

服务器端分成三层架构

表现层 SpringMVC

业务层 Spring

持久层 Mybatis

MVC模型

Model JavaBean

View JSP

Controller Servlet

SpringMVC

基于Java实现MVC设计模式的轻量级Web框架。支持RESTful编程风格。

前端控制器(DispatcherServlet)

请求到处理器映射(HandlerMapping)

处理器适配器(HandlerAdapter)

视图解析器(ViewResolver)

处理器或页面控制器(Controller)

验证器( Validator)

命令对象(Command 请求参数绑定到的对象就叫命令对象)

表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)

SpringMVC 和 Struts2 的优略分析

共同点:

它们都是表现层框架,都是基于 MVC 模型编写的。

它们的底层都离不开原始 ServletAPI。

它们处理请求的机制都是一个核心控制器。

区别:

Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter 过滤器

Spring MVC 是基于方法设计的(单例),而 Struts2 是基于类(多例),Struts2 每次执行都会创建一个动作类。所 以 Spring MVC 会稍微比 Struts2 快些。

Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便 (JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注 解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)

Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提 升,尤其是 struts2 的表单标签,远没有 html 执行效率高。

SpringMVC入门

1 index.jsp 超链接标签

2 发送请求

3 编写类 编写方法 转发成功jsp界面

搭建环境

Maven问题

1 User setting file does not exist C:\Users\lenevo.m2\setting.xml 问题解决

将maven的安装目录\conf目录下的setting.xml拷贝到C:\Users*.m2目录下即可

2 导入过慢

增加配置 archetypeCatalog internal

Tomcat问题

配置tomcat 报错误 the selected directory is not a valid Tomcat home

创建Tomcat Server

入门程序

1 POM.XML设置

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>

<dependencies>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${spring.version}</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${spring.version}</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>${spring.version}</version>
</dependency>

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.0</version>
  <scope>provided</scope>
</dependency>
</dependencies>

2 配置核心控制器 配置DispatcherServlet

<!--  前端控制器 -->
<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: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>

3 编写springmvc.xml的配置文件 配置视图解析器

<?xml version="1.0" encoding="UTF-8"?>
<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">            
<!-- 配置spring创建容器时要扫描的包 -->    
<context:component-scan base-package="com.itheima"></context:component-scan>           
<!-- 配置视图解析器 -->    
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">   
<!-- 注意/ -->      
<property name="prefix" value="/WEB-INF/pages/"></property>        <property name="suffix" value=".jsp"></property>    
</bean>       
 <!-- 配置spring开启注解mvc的支持-->      
<mvc:annotation-driven></mvc:annotation-driven>
</beans>

问题

Type Status Report 消息 /springmvc01_01start_war/WEB-INF/pagesWord.jsp 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。

prefix路径没有成功缺少/

4 编写index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<%--    相对路径--%>
<a href="hello">入门程序</a>
</body>
</html>

5 HelloworldController 请求

@Controller
public class HelloworldController {

// 请求映射
@RequestMapping(path = "/hello")
public String sayHello() {
    System.out.println("Hello");
    return "Word";
}
}

6 跳转

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>success</h3>
</body>
</html>

index.jsp不能在web-INF下面。

入门程序说明

1 启动服务器加载一些配置文件

web.xml:

配置前端控制器

1)DispatcherServlet创建 配置load-on-startup标签:原来DispatcherServlet发请求才会创建对象。 一旦启动服务器DispatcherServlet自动创建对象。

2)springmvc.xml文件加载

classpath:springmvc.xml

springmvc.xml:

1)加载Bean对象 默认单例 开启注解扫描

2)视图解析器 InternalResourceViewResolver 跳转界面

3)开启SpringMVC注解支持@RequestMapping 请求可以执行

2 发送请求 处理请求

从index.jsp发送请求,

DispatcherServlet拦截请求(控制作用)/,

springmvc注解@RequestMapping,执行方法

方法执行完,前端控制器找视图解析器InternalResourceViewResolver(根据返回值)寻找jsp

响应

SpringMVC框架基于组件方式执行流程

1 发起请求Request (请求路径/hello)

2 前端控制器:

DispatcherServlet

接口用户请求响应

3 请求查找handler

处理器映射器

HandleMapping

让Controller类中方法去执行(@RequestMapping(path = "/hello")

4 返回执行链handler (Controller中的对应方法)

5 处理器适配器 HandleAdapter 去执行handler

6 执行handler(执行Controller中的对应方法)

7 执行ModelAndView (视图界面 jsp)

8 视图解析器ViewResolver

9 返回view到DispatcherServlet

10 渲染 数据到request域 视图:JSP Pdf

11 response响应

SpringMVC框架基于组件方式执行流程说明

1 mvc:annotation-driven</mvc:annotation-driven>

默认配置 处理器映射器 处理器适配器

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。

使用mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用 mvc:annotation-driven替代注解处理器和适配器的配置

RequestMapping 注解

用于建立请求 URL 和处理请求方法之间的对应关系。

@Target({ElementType.METHOD, ElementType.TYPE}) 元注解(方法 类:可以分模块开发) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { }

RequestMapping注解可以作用在方法和类上

  1. 作用在类上:第一级的访问目录
  2. 作用在方法上:第二级的访问目录
  3. 细节:路径可以不编写 / 表示应用的根目录开始
  4. 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /

RequestMapping 注解属性

@AliasFor别名

  1. value和path作用相同 映射路径(请求URL)
  2. method 请求方式 RequestMethod[]
  3. params 用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。

例如: params = {"accountName"},表示请求参数必须有 accountName
params = {"moeny!100"},表示请求参数中 money 不能是 100

<a href="user/testRequestMapping?username=tt">
RequestMapping注解
</a>

@RequestMapping(path = "/testRequestMapping", params = {"username"})

4. headers 发送的请求中必须包含的请求头

@RequestMapping(path = "/testRequestMapping", params = {"username"}, headers = {"Accept"})

SpringMVC请求参数绑定

提交表单的name和参数的名称是相同的(反射)

数据类型:

  1. 基本数据类型和字符串类型
  2. 实体类型(JavaBean)
  3. 集合数据类型(List、map集合等

1 创建类

	public class User implements Serializable {
    	private String uname;
    	private Integer age;
	}

	public class Account implements Serializable {

    	private String username;

    	private String password;

    	private double money;

    	/**
     	* 引用类型
     	*/
    	private User user;
	}

2
 
    <form action="param/saveAccount" method="">
        姓名:<input type="text" name="username" /><br/>
        密码:<input type="text" name="password" /><br/>
        金额:<input type="text" name="money" /><br/>
        用户姓名:<input type="text" name="user.uname" /><br/>
        用户年龄:<input type="text" name="user.age" /><br/>
        <input type="submit" value="提交" />
    </form>

3
 
	public String saveAccount(Account account) {
        System.out.println("testParam" + account);
        return "Word";
    }

1. 提交表单的name和JavaBean中的属性名称需要一致 
2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name

sett方法

~~~~集合类型例子:

	public class Account implements Serializable {

    private String username;

    private String password;

    private double money;

    private List<User> list;

    private Map<String, User> userMap;
	}

  	 <form action="param/saveAccount" method="post">
        姓名:<input type="text" name="username" /><br/>
        密码:<input type="text" name="password" /><br/>
        金额:<input type="text" name="money" /><br/>

        用户姓名:<input type="text" name="list[0].uname" /><br/>
        用户年龄:<input type="text" name="list[0].age" /><br/>

        用户姓名:<input type="text" name="userMap['a'].uname" /><br/>
        用户年龄:<input type="text" name="userMap['a'].age" /><br/>
        <input type="submit" value="提交" />
    </form>

#### SpringMVC请求参数中文乱码

post请求中文乱码

解决中文乱码的过滤器

	<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  	</filter>

  	<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  	</filter-mapping>

#### SpringMVC请求参数 自定义类型转换器

表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换

配置转换器 

	public class StringToDateConverter implements Converter<String, Date> {
    @Override
    /**
     *
     */
    public Date convert(String s) {
        if (s == null) throw new RuntimeException("!!!!");
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            return dateFormat.parse(s);
        } catch (Exception e) {
            throw new RuntimeException("!!!!");
        }
    }
	}

配置转换器 springmvc

    <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.util.StringToDateConverter"></bean>
            </set>
        </property>

    </bean>

启用转换器 

    <mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>

Servlet原生API

	@RequestMapping("/testServletAPI") 
	public String testServletAPI(HttpServletRequest request,        HttpServletResponse response, 
       HttpSession session) 
	{  
		 return "success"; 
	} 

### SpringMVC常用注解

1 RequestParam 

把请求中指定名称的参数给控制器中的形参赋值。

属性:

required:请求参数中是否必须提供此参数,默认值是true,必须提供 

代码:

    <a href="anno/testRequestParam?username=tt">RequestParam</a>

    @RequestMapping("/testRequestParam")
    public String testRequestParam(@RequestParam("username") String name) {
        System.out.println("testRequestParam" + name);
        return "Word";
    }

2 RequestBody 

用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。 
get 请求方式不适用。 

异步json使用

    <form action="anno/testRequestbody" method="post">
    用户姓名:<input type="text" name="uname" /><br/>
    用户年龄:<input type="text" name="age" /><br/>
    <input type="submit" value="提交" />

  	@RequestMapping("/testRequestbody")
    public String testRequestbody(@RequestBody String body) {
        System.out.println("testRequestbody" + body);
        return "Word";
    }

3 PathVaribale 

用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。  

url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

	<a href="anno/testPathVariavle/10">testPathVariavle</a>

    @RequestMapping("/testPathVariavle/{sid}")
    public String testPathVariavle(@PathVariable(name = "sid") String id) {
        System.out.println("testPathVariavle" + id);
        return "Word";
    }

REST 风格 URL 

restful编程风格

请求地址相同根据不同的请求方式获取。

占位符

4 RequestHeader 

用于获取请求消息头。

5 CookieValue 

用于把指定 cookie 名称的值传入控制器方法参数。

@CookieValue(value="JSESSIONID",required=false)

6 ModelAttribute 

作用方法和参数上。

出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可 以修饰有具体返回值的方法。 

输出:

3333333

testModelAttribut

场景:

我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数 据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题


    @RequestMapping("/testModelAttribute")
    public String testModelAttribute() {
        System.out.println("testModelAttribute");
        return "Word";
    }

    @ModelAttribute
    public void show() {
        System.out.println("3333333");
    }

基于 POJO 属性的基本使用: 

	/**
     * 先执行
     */
    @ModelAttribute
    public User show(String uname) {
        System.out.println("3333333");
        // 通过用户查询数据库
        User user = new User();
        user.setUname(uname);
        return user;
    }

    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(User user) {
        System.out.println("testModelAttribute");
        return "Word";
    }

基于 Map 的应用场景示例 1:ModelAttribute 修饰方法不带返回值 

	@ModelAttribute 
	public void showModel(String username,Map<String,User> map) { 
 	//模拟去数据库查询  
	User user = findUserByName(username); 
 	System.out.println("执行了 showModel 方法"+user);  
	map.put("abc",user); 
	}

	@RequestMapping("/updateUser") 
	public String testModelAttribute(@ModelAttribute("abc")User user) {  
	System.out.println("控制器中处理请求的方法:修改用户:"+user);  return "success"; 
	}


出现在参数上,获取指定的数据给参数赋值。 


7 SessionAttribute 

用于多次执行控制器方法间的参数共享

session 会话域对象

存入request域中

@SessionAttributes(value ={"username","password"},types={Integer.class}) 只能作用于类

	/** 
  	* 把数据存入 SessionAttribute   
  	* @param model   
  	* @return 
  	*  Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap   *  该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类   */  
   
  	@RequestMapping("/testPut")    	
	public String testPut(Model model){           
	model.addAttribute("username", "泰斯特");           model.addAttribute("password","123456");           model.addAttribute("age", 31);   
    //跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有 这几个参数          
	 return "success";       
	}

 	@RequestMapping("/testGet")       public String testGet(ModelMap model){          
	 System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a ge"));           return "success";       
	}   
             
	@RequestMapping("/testClean")        
	public String complete(SessionStatus sessionStatus){         
	sessionStatus.setComplete();           
		return "success";      
	 }

## SpringMVC 响应数据和结果视图

### SpringMVC 返回值分类

#### SpringMVC 字符串

controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。 

//指定逻辑视图名,经过视图解析器解析为 jsp 物理路径:/WEB-INF/pages/success.jsp 

	@RequestMapping("/testReturnString") public String testReturnString() 
	{  
	System.out.println("AccountController 的 testReturnString 方法执行了。。。。");  
	return "success"; 
	}

	@RequestMapping("/testString")
    public String testString(Model model) {
        System.out.println("testString");
        // 查询
        User user = new User();
        user.setUsername("测试");
        user.setPassword("123");
        user.setAge(11);
        // model 对象
        model.addAttribute("user", user);
        return "Word";
    }

#### SpringMVC void

	 @RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("testVoid");
        // 请求转发 不会自动到视图解析器需要自己手写地址
        request.getRequestDispatcher("/WEB-INF/pages/Word.jsp").forward(request, response);
        // 请求转发一次请求 不用编写项目名称
        // 重定向二次请求 用编写项目名称
        // 重定向 不能访问WEB-INF下面的资源
        response.sendRedirect(request.getContextPath()+"/index.jsp");
        // 设置中文乱码
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        // 直接响应
        response.getWriter().println("测试");
        return;
    }

#### SpringMVC ModelAndView 

ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView() {
        ModelAndView modelAndView = new ModelAndView();


        System.out.println("testModelAndView");
        User user = new User();
        user.setUsername("测试");
        user.setPassword("123");
        user.setAge(11);

        // 存到request域对象中
        modelAndView.addObject("user", user);

        // 跳转到界面 查找视图解析器 无需地址
        modelAndView.setViewName("Word");

        return modelAndView;
    }

### SpringMVC 转发和重定向

不能使用视图解析器 需要自己写路径

#### 转发

	@RequestMapping("/testForward")  
	public String testForward() {   
	System.out.println("AccountController 的 testForward 方法执行了。。。。"); 
	return "forward:/WEB-INF/pages/success.jsp";  
	} 

相当于“request.getRequestDispatcher("url").forward(request,response)”。

使用请求 转发,既可以转发到 jsp,也可以转发到其他的控制器方法。 


#### 重定向

	@RequestMapping("/testForward")  
	public String testForward() {   
	System.out.println("AccountController 的 testForward 方法执行了。。。。"); 
	return "redirect:index.jsp";  
	}

底层已经处理加上项目名称

如果是重定向到 jsp 页面,则 jsp 页面不 能写在 WEB-INF 目录中,否则无法找到。 


### SpringMVC  ResponseBody 响应 json 数据 

1 DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。

    <!--    拦截任何请求 会拦截静态资源文件-->
    <url-pattern>/</url-pattern>

解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件

1. location元素表示webapp目录下的包下的所有文件 
2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
 

	<!-- 设置静态资源不过滤 -->    
	<mvc:resources location="/css/" mapping="/css/**"/>  
	<!-- 样式 -->    
	<mvc:resources location="/images/" mapping="/images/**"/>  
	<!-- 图片 -->    
	<mvc:resources location="/js/" mapping="/js/**"/>  
	<!-- javascript -->

使用@RequestBody获取请求体数据

json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
 
	<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>

使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应

    @RequestMapping("/testjAax")
//    public void testjAax(@RequestBody String body) {
    public @ResponseBody User testjAax(@RequestBody User user) {
        System.out.println("testjAax");
        // 客户端发送ajax请求 后台把json字符串封装到user
        System.out.println(user);
        // 响应
        return user;
    }

### SpringMVC实现文件上传 

#### 文件上传的必要前提

A form 表单的 enctype 
取值必须是:multipart/form-data (表单分成几个部分)    
(默认值是:application/x-www-form-urlencoded)     
enctype:是表单请求正文的类型 

B method 属性取值必须是 Post 

C 提供一个文件选择域<input type=”file” />

#### 文件上传的原理

当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:    key=value&key=value&key=value 

当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成: 每一部分都是 MIME 类型描述的正文 

-----------------------------7de1a433602ac   分界符 
Content-Disposition: form-data; name="userName"  协议头 
 
aaa              协议的正文 
-----------------------------7de1a433602ac 
Content-Disposition: form-data; name="file"; 
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt" 
Content-Type: text/plain         协议的类型(MIME 类型) 
 
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
-----------------------------7de1a433602ac--

#### SpringMVC文件上传的原理

发送请求-> 前端控制器 -> 文件解析器(解析request) -> 前端控制器返回upload  -> controller fileupload(MultipartFile upload)

 	<form action="file/fileUpload1" method="post" enctype="multipart/form-data">
        文件 <input type="file" name="upload" /><br/>
        <input type="submit" value="创" />
    </form>

name="upload" 和 fileupload(MultipartFile upload)里的MultipartFile 必须一样。

文件解析器需要配置CommonsMultipartResolver  id="multipartResolver" 固定

#### SpringMVC跨服务器方式文件上传

 

#### 文件上传的传统代码:

    @RequestMapping("/fileUpload1")
    public String fileUpload1(HttpServletRequest request) throws Exception {
        System.out.println("fileUpload1");

        // 上传位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        File file = new File(path);
        if (!file.exists()) {
            file.mkdir();
        }

        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload fileUpload = new ServletFileUpload(factory);

        List<FileItem> items = fileUpload.parseRequest(request);

        for (FileItem item: items) {
            if (item.isFormField()) {
                // 普通表单
            } else {
                // 上传文件
                // 获取上传文件名
                String filename = item.getName();
                //
                filename += UUID.randomUUID().toString().replace("-", "");
                item.write(new File(path, filename));
                // 删除临时文件
                item.delete();
            }
        }

        return "Word";
    }

    <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.4</version>
    </dependency>

#### SpringMVC文件上传的代码

1 springMvc.xml

    <!--    配置文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="maxUploadSize" value="10485760"></property>
    </bean>

2

	@RequestMapping("fileUpload2")
    public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("fileUpload2");

        // 上传位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        System.out.println(path);
        File file = new File(path);
        if (!file.exists()) {
            file.mkdir();
        }

        // 上传文件
        // 获取上传文件名
        String filename = upload.getOriginalFilename();
        //
        filename += UUID.randomUUID().toString().replace("-", "");
        upload.transferTo(new File(path, filename));
        return "Word";
    }

## SpringMVC中的异常处理 

异常处理器组件

1 自定义异常类

	public class SpringException extends Exception {

    // 异常信息
    public String meaasge;

    public String getMeaasge() {
        return meaasge;
    }

    public void setMeaasge(String meaasge) {
        this.meaasge = meaasge;
    }

    public SpringException(String message) {
        this.meaasge = message;
    }
	}

2 异常处理器

	public class SpringExceptionHandler implements HandlerExceptionResolver {

    /**
     * 异常业务逻辑
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 获取异常对象
        SpringException ee = null;
        if (e instanceof SpringException) {
            ee = (SpringException)e;
        } else {
            ee = new SpringException("44444");
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", ee.getMeaasge());
        modelAndView.setViewName("error");
        return modelAndView;
    }
	}

3 配置异常处理器(跳转界面)

	<!--    异常处理器-->
    <bean id="springExceptionHandler" class="com.exception.SpringExceptionHandler"></bean>

	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
	<head>
    <title>Title</title>
	</head>
	<body>

    ${msg}
	</body>
	</html>

## SpringMVC中的拦截器

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。 

拦截器链 多个拦截器

拦截器(代码1 放行 代码2) ->  Controller

过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。  

拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。  

过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。  

拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦 截的

它也是 AOP 思想的具体应用。 

### 自定义拦截器

1 编写拦截器

	public class IntercepterController implements HandlerInterceptor {

    /**
     * 预处理 controller执行前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
	//        return true; // 放行 执行下一个拦截器 如果没有 执行controller
	//        return false; // 不放行 可以转发 到错误界面
        System.out.println("preHandle");
        return true;
    }

    /**
     * 后处理 controller执行完毕 Word.jsp 之前    可以转发
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle 后");
    }

    /**
     * 最后执行 Word.jsp后面
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

2 配置拦截器

	<!--    配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
	<!--            要拦截的具体方法 /** 所有方法 -->
            <mvc:mapping path="/user/*"/>
	!--            不要拦截的具体方法-->
	<!--            <mvc:exclude-mapping path=""/>-->
	<!--            配置拦截器对象-->
            <bean class="com.controller.intercepter.IntercepterController"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

配置多个拦截器:

  	<!-- 配置拦截器 -->    
	<mvc:interceptors>       
	<mvc:interceptor>            
	<!-- 哪些方法进行拦截 -->            
	<mvc:mapping path="/user/*"/>            
	<!-- 哪些方法不进行拦截             
	<mvc:exclude-mapping path=""/>            

    <!-- 注册拦截器对象 -->            
	<bean class="cn.itcast.demo1.MyInterceptor1"/>        
	</mvc:interceptor>                
	<mvc:interceptor>            
	<!-- 哪些方法进行拦截 -->            
	<mvc:mapping path="/**"/>           
	<!-- 注册拦截器对象 -->            
	<bean class="cn.itcast.demo1.MyInterceptor2"/>        
	</mvc:interceptor>    
	</mvc:interceptors>

拦截器1(代码1)->  拦截器2(代码1) => Controller -> 

拦截器2(代码2) -> 拦截器1(代码2)