SpringMVC框架

1. SpringMVC 入门案例
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。

三层架构:

深入理解springmvc架构 简述springmvc框架_web


①SpringMVC的概述

1. 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。

	2. Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供
		了构建 Web 应用程序的全功能 MVC 模块。
		
	3. 使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的
			SpringMVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。

② SpringMVC在三层架构中的位置

1. 表现层框架

③ SpringMVC和Struts2框架的对比

共同点: 
	它们都是表现层框架,都是基于MVC模型编写的。 
	
	它们的底层都离不开原始ServletAPI。 
	
	它们处理请求的机制都是一个核心控制器。 

区别: 
	Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter 
	
	Spring MVC 是基于方法设计的,而Struts2是基于类,Struts2每次执行都会创建一个动作类。所以Spring MVC 会稍微比 Struts2 快些。 
	
	Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
	
	Struts2 的OGNL 表达式使页面的开发效率相比Spring MVC 更高些,但执行效率并没有比JSTL提升,尤其是struts2的表单标签,远没有html执行效率高。

1.1 入门案例

①创建maven工程,webapp项目。导包。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>springmvc_day01_01_start</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <name>springmvc_day01_01_start Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <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>
  </properties>


  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.13.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.13.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>compile</scope>
    </dependency>

  </dependencies>


  <build>
    <finalName>springmvc_day01_01_start</finalName>
  </build>
</project>

②在web.xml中配置核心控制器

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--配置解决中文乱码的过滤器-->
  <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>

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


</web-app>

③resources目录下创springmvc.xml配置springmvc

<?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">

    <!--开启注解的扫描-->
    <context:component-scan base-package="org.example"></context:component-scan>

    <!--配置视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--配置自定义类型转换器-->
    <bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="org.example.utils.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!--开启springmvc注解的支持,并配置类型转换器使其生效,即conversion-service-->
    <mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
    
</beans>

④编写控制器并使用注解配置

@Controller
public class HelloController {

    /**
     * RequestMapping : 用于建立请求URL和处理请求方法之间的对应关系。
     * @return
     */
    @RequestMapping(path="/hello")
    public String sayHello(){
        System.out.println("Hello StringMVC");
        return "success";
    }

⑤创建success.jsp用于界面的跳转,当点击超链接时跳转。index.xml文件,指定url请求

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

    <h3>入门程序</h3>

    <a href="hello">入门程序</a>
   
</body>
</html>

⑥部署到Tomcat,启动运行。

1.2 案例执行过程分析

①springmvc的请求响应流程

深入理解springmvc架构 简述springmvc框架_spring_02

②整体流程

深入理解springmvc架构 简述springmvc框架_java_03

1.3 springMVC中的组件

①DispatcherServlet:前端控制器

用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

②HandlerMapping:处理器映射器

HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

③Handler:处理器

它就是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理。

④HandlerAdapter:处理器适配器

通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

⑤View Resolver:视图解析器

View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

⑥View:视图

SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

1.4 mvc:annotation-driven

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

1.5 RequestMapping注解

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

属性: 
	value:用于指定请求的URL。它和path属性的作用是一样的。 
	
	method:用于指定请求的方式。 
	
	params:用于指定限制请求参数的条件。它支持简单的表达式。
	要求请求参数的key和value必须和配置的一模一样。

1.5.1 params属性

/** 删除账户
 * @return
 */ 
 @RequestMapping(value="/removeAccount",params= {"accountName","money>100"}) 
 public String removeAccount()  { 
	 System.out.println("删除了账户"); 
 	return "success"; 
 }
jsp中的代码:
  <!-- 请求参数的示例 --> 
  <a href="account/removeAccount?accountName=aaa&money>100">删除账户,金额100</a> <br/>
   <a href="account/removeAccount?accountName=aaa&money>150">删除账户,金额150</a>

注意:
当我们点击第一个超链接时,可以访问成功。
当我们点击第二个超链接时,无法访问。

1.6 请求参数绑定

1.绑定机制

  • 表单提交的数据都是k=v格式,username=haha&password=123
  • SpingMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的。
  • 要求:提交表单的name和参数的名称是相同的。

① 一般情况:

<a href="account/findAccount?accountId=10">查询账户</a>

中请求参数是: accountId=10

/** 
*查询账户 
* @return 
* */ 
 @RequestMapping("/findAccount") 
 public String findAccount(Integer accountId) { 
	System.out.println("查询了账户。。。。"+accountId);
	}

②POJO类型作为参数

jsp:

<%--    把数据封装到Account类中--%>
    <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="user.uname"><br/>
    用户年龄:<input type="text" name="user.age"><br/>
    <input type="submit" value="提交"><br/>
    </form>

其中User作为Account类中的一个属性,如果要将数据封装到User类里的属性uname和age,需要通过user.uname实现。

③ POJO类包含集合类型

用户姓名:<input type="text" name="list[0].uname"><br/>
<%--把文本框的输入封装到user的uname中,在添加到list的0位置上
用户年龄:<input type="text" name="list[0].age"><br/>

<%--把文本框的输入封装到user的uname中,在添加到map中,map的key为字符串‘one’
用户姓名:<input type="text" name="map['one'].uname"><br/>
用户年龄:<input type="text" name="map['one'].age"><br/>
public class Account implements Serializable {

    private String username;
    private String password;
    private Double money;

    private List<User> list;
    private Map<String,User> map;

1.7 过滤器

在springmvc的配置web.xml文件进行配置时,dispatcherServlet对象会处理对应的URL,一般我们使用/,其表示对所有的url进行拦截,但是我们一般不会对静态资源进行拦截,因此需要在springmvc.xml中配置不需要拦截的数据。

<!-- location表示路径,mapping表示文件,**表示该目录下的文件以及子目录的文件 --> 
<mvc:resources location="/css/" mapping="/css/**"/> 
<mvc:resources location="/images/" mapping="/images/**"/>
 <mvc:resources location="/scripts/" mapping="/javascript/**"/>

说明:

location元素表示webapp目录下的static包下的所有文件;

mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b;

该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源

交由Servlet处理。

1.8 自定义类型转换器

对于有时输入的日期类型与库内的类型不匹配时,需要自定义类型转换器。

①创建对应的转换类,其需要实现Converter接口。

public class StringToDateConverter implements Converter<String,Date>{

    @Override
    public Date convert(String s) {
        //1.判断
        if(s == null){
            throw new RuntimeException("输入数据为空...");
        }
        DateFormat df = new SimpleDateFormat("yyyy-mm-dd");
        //2.把字符串转换为日期
        try {
            return df.parse(s);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

②在spring配置文件中配置类型转换器

<!--配置自定义类型转换器-->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="org.example.utils.StringToDateConverter"></bean>
        </set>
    </property>
</bean>

③在annotation-driven标签中引用配置的类型转换

<!--开启springmvc注解的支持,并配置类型转换器使其生效,即conversion-service-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>

1.9 常用注解

①RequestParam:

作用:
 		把请求中指定名称的参数给控制器中的形参赋值。
 		
		value:请求参数中的名称
		
		required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供,报错。
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name = "name") String username){
    System.out.println("well done");
    System.out.println(username);
    return "success";
}

<a href="anno/testRequestParam?name=哈哈">RequestParam</a>

②RequestBody:

作用:
	用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。
	
	required:是否必须有请求体。默认为true。当取值为true时,get请求方式会报错。如果为false,get请求得到的是null。
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
    System.out.println("well done");
    System.out.println(body);
    return "success";
}

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

③RequestVariable:

作用:
	用于绑定url中的占位符。例如:请求url中/delete/{id},这个{id}就是url占位符。
@RequestMapping(value = "/testPathVariable/{uid}")
public String testPathVariable(@PathVariable(name = "uid") String id){
    System.out.println("well done");
    System.out.println(id);
    return "success";
}

<a href="anno/testPathVariable/10">PathVariable</a>

④RequestHeader:

作用:
	用于获取请求消息头。
@RequestMapping(value = "/testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
    System.out.println("well done");
    System.out.println(header);
    return "success";

<a href="anno/testRequestHeader">RequestHeader</a>

深入理解springmvc架构 简述springmvc框架_spring_04


⑤CookieValue

作用:
	用于把指定cookie名称的值传入控制器方法参数。
@RequestMapping(value = "/testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
    System.out.println("well done");
    System.out.println(cookieValue);
    return "success";
}

<a href="anno/testCookieValue">CookieValue</a>

⑥ModelAttribute:

作用:
	出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。
		它可以修饰没有返回值的方法,也可以修饰有返回值的方法。
	出现在参数上,获取指定的数据给参数赋值。
@RequestMapping(value = "/testModelAttribute")
public String testModelAttribute(@ModelAttribute(value = "abc") User user){
    System.out.println("testModelAttribute执行完成了....");
    System.out.println(user);
    return "success";
}

@ModelAttribute
public void showUser(String uname, Map<String,User> map){
    System.out.println("showUser...........");
    //通过用户名查询数据库(模拟)
    User user = new User();
    user.setUname(uname);
    user.setAge(20);
    user.setDate(new Date());
    map.put("abc",user);
}

深入理解springmvc架构 简述springmvc框架_mvc_05

⑦SessionAttributes:

作用:
	用于多次执行控制器方法间的参数共享。
	value:用于指定存入的属性名称。
	type:用于指定存入的数据类型。
@SessionAttributes(value = {"msg"}) //把msg=布布存放到session域对象中
public class AnnoController {
@RequestMapping(value = "/testSessionAttributes")
    public String testSessionAttributes(Model model){
        System.out.println("testSessionAttribute执行完成了....");
        //底层会存储到request域对象中
        model.addAttribute("msg","布布");
        return "success";
    }

    /**
     * 从Session域中获取值
     * @param modelMap
     * @return
     */
    @RequestMapping(value = "/getSessionAttributes")
    public String getSessionAttributes(ModelMap modelMap){
        System.out.println("getSessionAttribute执行完成了....");
        //底层会存储到request域对象中
        String msg = (String)modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

    /**
     * 清楚session
     * @param status
     * @return
     */
    @RequestMapping(value = "/deleteSessionAttributes")
    public String deleteSessionAttributes(SessionStatus status){
        System.out.println("deleteSessionAttribute执行完成了....");
        status.setComplete();
        return "success";
    }
}

    <a href="anno/testSessionAttributes">TestSessionAttributes</a>
    <a href="anno/getSessionAttributes">GetSessionAttributes</a>
    <a href="anno/deleteSessionAttributes">DeleteSessionAttributes</a>

2. 响应数据和结果视图

2.1 ModelAndView

ModelAndView是springmvc提供的一个对象,该对象可以用作控制器方法的返回值。

①之前我们可以通过Model获取返回值。

@RequestMapping("/testString")
public String testString(Model model){
    System.out.println("testString方法执行了.....");
    //模拟从数据库中查询出user对象

    User user = new User();
    user.setUsername("妹妹");
    user.setPassword("13224");
    user.setAge(45);

    //model对象
    model.addAttribute("user",user);
    return "success";
}

    <a href="user/testString">TestString</a>

②也可以通过servlet的API获取

@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception{
    System.out.println("testVoid方法执行了.....");
    //编写请求转发的程序
    //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

    //重定向
    //response.sendRedirect(request.getContextPath() + "/index.jsp");

    //设置中文乱码
    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");

    //直接进行相应
    response.getWriter().print("你好");

    return;
}

<a href="user/testVoid">TestVoid</a>

③现在通过ModelAndView实现。

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    //创建ModelAndView
    ModelAndView mv = new ModelAndView();
    System.out.println("testModelAndView方法执行了.....");
    //模拟从数据库中查询出user对象

    User user = new User();
    user.setUsername("龙龙");
    user.setPassword("1232");
    user.setAge(45);

    //把user对象存储到mv对象中,也会把user对象存入到request对象
    mv.addObject("user",user);

    //跳转到哪个页面
    mv.setViewName("success");

    return mv;
}

<a href="user/testModelAndView">TestModelAndView</a>

2.2 转发和重定向

①forward转发和redirect重定向

/**
 * 关键字的方式进行转发或者重定向
 * 此方法不能使用视图解析器,必须手动指定跳转的页面
 * @param
 * @return
 */
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
    System.out.println("testForwardOrRedirect方法执行了.....");
    //请求的转发
    //return "forward:/WEB-INF/pages/success.jsp";

    //重定向:不能直接访问到pages下面的jsp
    return "redirect:/index.jsp";
}

<a href="user/testForwardOrRedirect">TestForwardOrRedirect</a>

2.3 ResponseBody响应json数据

作用:

该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端.

需要导入以下jar包:

深入理解springmvc架构 简述springmvc框架_spring_06

/**
     * 模拟异步请求响应
     */
    @RequestMapping("/testAjax")
    @ResponseBody
    public User testAjax(@RequestBody User user){
        System.out.println("testAjax方法执行了.....");
        //客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        //做响应,模拟查询数据库
        user.setUsername("haha");
        user.setAge(98);
        //做响应
        return user;
    }

<head>
    <title>Title</title>

    <script src="js/jquery.min.js"></script>

    <script>

        //页面加载,绑定单击事件
        $(function () {
            $("#btn").click(function () {
                //alert("hello everyone");
                //发送ajax请求
                $.ajax({
                    //编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"hehe","password":"123","age":36}',
                    dataType:"json",
                    type:"post",
                    success:function (data) {
                        //data服务器端响应的json的数据,进行解析
                        alert(data);
                        alert(data.username);
                        alert(data.password);
                        alert(data.age);
                    }
                });
            });
        });

    </script>

</head>

  <button id="btn">发送ajax请求</button>

3.springmvc实现文件上传

①文件上传的必要前提

1. form表单的enctype取值必须是:
			multipart/form-data(默认值是:application/x-www-form-urlencoded)
			enctype:表单请求正文的类型。
	2. method属性取值必须是post。
	3. 提供一个文件选择域<input type="file" />

②导包 commons-fileupload和commons-io

3.1 传统方式上传

@RequestMapping("/fileUpload1")
public String fileUpload1(HttpServletRequest request) throws Exception {
    System.out.println("文件上传...");
    //使用fileupload组件实现文件上传

    //上传的位置
    String path = request.getSession().getServletContext().getRealPath("/uploads/");
    //判断,该路径是否存在
    File file = new File(path);
    if(!file.exists()){
        file.mkdirs();
    }
    //解析request对象,获取上传文件项
    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    //解析request
    List<FileItem> items = upload.parseRequest(request);
    //遍历
    for(FileItem item : items){
        //判断,当前item对象是否是上传文件项
        if(item.isFormField()){
            //说明普通表单项
        }else{
            //说明上传文件项
            //获取上传文件的名称
            String filename = item.getName();
            //把文件的名称设置唯一值,uuid
            String uuid = UUID.randomUUID().toString().replace("-", "");
            filename = uuid + "_" + filename;
            //完成文件上传
            item.write(new File(path,filename));
            //删除临时文件
            item.delete();
        }
    }
    return "success";
}

    <h3>文件上传</h3>

    <form action="user/fileUpload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br>
        <input type="submit" value="上传">
    </form>

配置文件解析器:

<bean id="multipartResolver" <!--id的值是固定的-->
	class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!--设置上传文件的最大尺寸为10MB-->
    	<property name="maxUploadSize" value="10485760"></property>
</bean>

注意:
文件上传解析器id是固定的,不能起别名,否则无法实现请求参数的绑定。

3.2 springmvc方式的文件上传

@RequestMapping("/fileUpload2")
public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws Exception {
    System.out.println("springmvc文件上传...");
    //使用fileupload组件实现文件上传

    //上传的位置
    String path = request.getSession().getServletContext().getRealPath("/uploads/");
    //判断,该路径是否存在
    File file = new File(path);
    if(!file.exists()){
        file.mkdirs();
    }
    //说明上传文件项
    //获取上传文件的名称
    String filename = upload.getOriginalFilename();
    //把文件的名称设置唯一值,uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    filename = uuid + "_" + filename;
    //完成文件上传
    upload.transferTo(new File(path,filename));
    return "success";
}

    <form action="user/fileUpload2" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br>
        <input type="submit" value="上传">
    </form>

4. springmvc的异常处理

系统的dao,service,controller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行处理。

深入理解springmvc架构 简述springmvc框架_java_07


①编写异常类

public class SysException extends Exception {

    //存储提示信息的
    private String message;

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SysException(String message) {
        this.message = message;
    }
}

②编写jsp页面

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

    ${errorMsg}

</body>
</html>

③自定义异常处理器(需要实现HandlerExceptionResolver接口)

public class SysExceptionResolver implements HandlerExceptionResolver {

    /**
     * 处理异常业务逻辑
     * @param request
     * @param response
     * @param o
     * @param e
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
        //获取到异常对象
        SysException exception = null;
        if(e instanceof SysException){
            exception = (SysException) e;
        }else{
            e = new SysException("系统正在维护....");
        }
        //创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",exception.getMessage());
        mv.setViewName("error");
        return mv;
    }
}

④配置异常处理器

<!--配置异常处理器对象-->
    <bean id="sysExceptionResolver" class="org.example.exception.SysExceptionResolver"></bean>

⑤运行

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testException")
    public String testException() throws SysException{
        System.out.println("testException方法执行了.....");

        try {
            //模拟异常
            int a = 1 / 0;
        } catch (Exception e) {
            //打印异常信息
            e.printStackTrace();
            //抛出自定义异常信息
            throw new SysException("查询所有用户出现错误了.....");
        }

        return "success";
    }

}

⑥分析:
当运行服务器时,点击页面的超链接会执行testException方法,但是其存在异常,异常处理器获取到异常,执行对应的自定义异常处理器,根据异常的类型,跳转页面。

5.springmvc框架中的拦截器

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

过滤器和拦截器的区别:

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

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

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

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

自定义拦截器,必须实现HandlerInterceptor接口。

①自定义拦截器实现HandlerInterceptor接口

public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * 预处理,controller方法执行前执行的
     * return true表示放行。执行下一个拦截器,如果没有,执行controller中的方法
     * return false表示不放行。
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("MyInterceptor1执行了....前111111111111");
        //httpServletRequest.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(httpServletRequest,httpServletResponse);
        return true;
    }

    /**
     * 后处理的方法,controller方法执行后,success.jsp执行之前
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了....后1111111111111");
        //httpServletRequest.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(httpServletRequest,httpServletResponse);

    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("MyInterceptor1执行了....吼吼吼吼后111111111");

    }
}

②配置拦截器:此处配置了两个拦截器,根据配置的顺序不同,其执行的顺序也不同。

<!--配置拦截器-->
<mvc:interceptors>

    <!--配置拦截器1-->
    <mvc:interceptor>
        <!--要拦截的具体的方法-->
        <mvc:mapping path="/user/**"/>
        <!--不要拦截的方法
        <mvc:exclude-mapping path=""/>
        -->
        <!--配置拦截器对象-->
        <bean class="org.example.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>


    <!--配置拦截器2 :配置的拦截器顺序决定拦截的顺序-->
    <mvc:interceptor>
        <!--要拦截的具体的方法-->
        <mvc:mapping path="/**"/>
        <!--不要拦截的方法
        <mvc:exclude-mapping path=""/>
        -->
        <!--配置拦截器对象-->
        <bean class="org.example.interceptor.MyInterceptor2"></bean>
    </mvc:interceptor>


</mvc:interceptors>

③编写jsp文件

index.jsp

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

    <h3>拦截器</h3>

    <a href="user/testInterceptor">拦截器</a>

</body>
</html>

error.jsp

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

    <h3>错误页面</h3>

</body>
</html>

success.jsp

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

    <h3>执行成功</h3>

    <% System.out.println("success.jsp执行了...."); %>

</body>
</html>

④结果

深入理解springmvc架构 简述springmvc框架_深入理解springmvc架构_08

分析:多个拦截器的执行过程

深入理解springmvc架构 简述springmvc框架_spring_09