SpringMVC笔记

目录

 

QuickStart

重要注解

1.把数据封装到bean中且bean中有引用类型user。name的值与bean 的参数必须完全一致,自动封装,引用的类型用 级联user.uname

1.把数据封装Account类中,类中存在list和map的集合

 2.springmvc.xml里面配置自定义类型转换器并开启

 3.获取原生API

4.属性注解

         Restful风格:

        基于HiddentHttpMethodFilter的Restful风格Controller实现

1.filter完全实现类​

2 . .jsp

3. controller

1.model.addAttribute("username", "泰斯特");     添加

 2.model.get("username")得到

 3.public String complete(SessionStatus sessionStatus){                 sessionStatus.setComplete();  删除session

Controller返回值类型

1.String

2.void,404异常请求的页面为————方法名.jsp

1.forward请求转发

2.redirect重定向

1.使用@RequestBody注解参数获取请求体数据,获取JSON对象

使用@RequestBody注解返回值类型,将响应数据转换为json格式送给前端

文件上传

导入依赖,pom.xml

2. jsp

3. controller.java

原理分析:​

SpringMVC跨服务器上传

SpringMVC异常处理器

1. 编写异常消息传递类/+你

2. 跳转的错误页面error.jsp

3. 编写自定义异常处理器接口完全实现类

4.  配置自定义异常处理(拦截)器bean对象

 

拦截器

1.  编写HandlerInterceptor 接口 完全实现类

2. 配置拦截器bean以及拦截范围

3.测试运行结果

4.实例:

Web-App标签子标签顺序

SSM整合之Spring框架的配置路径问题



QuickStart

 

基础配置

 

  1. 创建maven项目
    选择archetype:maven-archetype-webapp
    注:如果创建项目过慢,输入<archetypeCatalog,internal>在创建项目Properties的时候

  2. 补全工程文件目录
    java,resource,并mark directory为Re/Source root

  3. 在pom中引入依赖

 

	<!-- 编译版本修改为1.8 -->
	<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版本锁定 -->
        <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>

 

 

  1. web.xml配置核心控制器DispatcherServlet和中文乱码过滤器

 

<!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>

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

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

</web-app>

 

输入<servlet生成两行,第二行为没写完的<光标下移,然后输入servlet-class补全,然后在<servlet-class></servlet-class>内输入
DispatcherServlet,就可自动生成。init-param与servlet-mapping都需要自己手动输入,不自动匹配。
提示:init-param不需要输入,如果没有指定使用默认值:/WEB-INF/<servlet-name>-servlet.xml


1.在类路径Resouce文件下创建springmvc.xml文件(选择创建Spring XML即可)。


以上配置完毕,就可以部署在Tomcat上。当然只有一个index.jsp页面罢了


进阶配置


1.在index.jsp上使用<a/>标签
【入口页面】

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
	<body>
		<h2>Hello World!</h2>
		<a href="hello" >新手程序,但是我好像都懂hhhh</a>
	</body>
</html>


1.   新建controller类
【控制器】
2个要点
第一个是使用@Controller标记这个类为控制器
第二个是使用@RequestMapping(path = “/hello”)标记接收的请求url为/hello

 

package cn.itcast.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 控制器标记
 */
@Controller
public class HellowController {
    /**
     * 接收请求路徑为`hello`千萬別寫反斜杠/
     * @return
     */
    @RequestMapping(path = "/hello")
    public String sayHello() {
        System.out.println("Hello SpringMVC!!");
        return "success";
    }
}

 

 

  1. 在WEB-INF中創建pages文件夾
    裏面放置跳轉的jsp頁面,這個路徑由SpringMVC-servlet.xml配置文件中 視圖解析器 決定的。

  2. 新建success JSP頁面
    【跳轉頁面】

 

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

 

 

  1. 修改springMVC.xml配置
    1個要點:在springMVC的視圖解析器中,配置pages文件的路徑【可以不在WEB-INF中】

               视图解析器可以根据服务方法的返回值,自动的拼接最终的viewName数据.

                  viewName= prefix + 服务方法返回值 + suffix

                          /jsp/+ ok + .jsp -> /jsp/ok.jsp

                  前后缀的使用限制: 不能处理带有forward|redirec前缀的服务方法返回值.

                  前后缀只能处理请求转发,不能处理响应重定向的字符串返回结果.

<?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:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		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-4.0.xsd">
	
	<!-- 只扫描带有controller注解的控制器 -->
	<context:component-scan base-package="com.atguigu.mybatis" use-default-filters="false">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- 视图解析器InternalResourceViewResolver -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<!-- 处理动态,静态资源两个MVC标签,重要**不僅僅是注解還代表注冊各種SpringMVC組件xxx器** -->
	<mvc:annotation-driven></mvc:annotation-driven>
	<mvc:default-servlet-handler/>
</beans>

 

 

<mvc:annotation-driven>说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用<mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping(处理映射器)
和RequestMappingHandlerAdapter(处理适配器)
可用在SpringMVC.xml配置文件中使用 <mvc:annotation-driven>
替代注解处理器和适配器的配置。

 

入門SpringMVC圖解

 

入門級

 

詳細SpringMVC圖解

个人理解:
前端控制器DispatchServlet:只是中转站,传入request请求,返回response响应。这个中间经它的调用有
1.处理器映射器2.处理器适配器3.视图解析器4.动静态页面


处理器映射器handlermapping:将传入的请求路径进行解析,生成这个请求路径+背后全部需要的其他请求的执行链Chain。返回给前端控制器。


处理器适配器HandlerAdapter:将由前端控制器转发的执行链中的全部servlet执行,返回Model结果数据和View需要的页面


视图解析器ViewResolver:将由前端控制器转发的View页面 拼装 为完整的页面访问路径


视图:渲染–由前端控制器装载model数据到返回的具体页面request域中


注:爲什么这个前端控制器这么累,是因爲和Spring IOC容器一样,降低这些组件閒的相互耦合.

 

重要注解

 

  • @RequestMapping()

 

出现位置:  
	类上:请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。   
	功用:使 URL 访问可以按照模块化管理:   
		例如:    
			账户模块:     /account/add     /account/update   /account/delete     ... 
   			订单模块:     /order/add       /order/update     /order/delete 
  		实例:
  		@RequestMapping("/account") ,使 URL 更加精细【将重複性的类名从方法上的requestmapping中抽取出来放在上面而已】。  

  	方法上:请求 URL 的第二级访问目录。
  		实例:
  		@RequestMapping(path="/add"),path,可写可不写,如果是一个参数时

属性:  
	value:用于指定请求的 URL。它和 path 属性的作用是一样的。  
	method:用于指定请求的方式(get/post/head/put/patch/delete/options/trace)可单个,可多个值。
		实例:
			@RequestMapping(value="/saveAccount",method=RequestMethod.POST)
			@RequestMapping(value="/saveAccount",method={RequestMethod.POST,RequestMethod.GET})
		注:<a></a>使用get方法

	params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。 可单多   
			半实例:   
				params = {"accountName"},表示请求参数必须有 accountName这个参数(属性)    
				params = {"moeny!100"},表示请求参数中 money 不能是 100。  
	headers:用于指定请求消息头的条件 限制。  
			半实例:
				headers = {"Accept"}

	注意:   以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。 

 

1.把数据封装到bean中且bean中有引用类型user。name的值与bean 的参数必须完全一致,自动封装,引用的类型用 级联user.uname

  把数据封装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="提交" />
    </form>
@Controller
@RequestMapping("/param")
public class ParamController {
/**
     * 请求参数绑定把数据封装到JavaBean的类中
     * @return
     */
    @RequestMapping("/saveAccount")
    public String saveAccount(Account account){
        System.out.println("执行了...");
        System.out.println(account);
        return "success";
    }
}

 

  • @RequestParam()

 

1.把数据封装Account类中,类中存在list和map的集合

  private List<User> list;
  private Map<String,User> map;
<form action="param/saveAccount" method="post">
        姓名:<input type="text" name="username" /><br/>
        密码:<input type="text" name="password" /><br/>
        金额:<input type="text" name="money" /><br/>


        <!--封装到List的第0个位置-->
        用户姓名:<input type="text" name="list[0].uname" /><br/>
        用户年龄:<input type="text" name="list[0].age" /><br/>

        
        
        <!--封装到map的key是"one"的value中-->
        用户姓名:<input type="text" name="map['one'].uname" /><br/>
        用户年龄:<input type="text" name="map['one'].age" /><br/>
        <input type="submit" value="提交" />
    </form>

 2.springmvc.xml里面配置自定义类型转换器并开启

    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="cn.itcast.utils.StringToDateConverter"/>
            </set>
        </property>

           <!-- 开启SpringMVC框架注解的支持 -->
        <mvc:annotation-driven conversion-service="conversionService"/>

    </bean>
package cn.itcast.utils;

import org.springframework.core.convert.converter.Converter;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 把字符串转换日期
 */
public class StringToDateConverter implements Converter<String,Date>{

    /**
     * String source    传入进来字符串
     * @param source
     * @return
     */
    public Date convert(String source) {
        // 判断
        if(source == null){
            throw new RuntimeException("请您传入数据");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        try {
            // 把字符串转换日期
            return df.parse(source);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换出现错误");
        }
    }

}

 3.获取原生API

  /**
     * 原生的API
     * @return
     */
    @RequestMapping("/testServlet")
    public String testServlet(HttpServletRequest request, HttpServletResponse response){
        System.out.println("执行了...");
        System.out.println(request);

        HttpSession session = request.getSession();
        System.out.println(session);

        ServletContext servletContext = session.getServletContext();
        System.out.println(servletContext);

        System.out.println(response);
        return "success";
    }

4.属性注解

	作用:  指定(从前台传入后台的)参数名称,给控制器中的形参赋值。 
	属性:  
			value=name:请求参数中的名称。  
			required:请求参数中是否必须提供此参数。默认值为true必须提供,如果不提供将报错。
			defaultValue:默认值
	实例:
			@RequestMapping("/useRequestParam") 
			public String useRequestParam(
				@RequestParam("name")String username,
				@RequestParam(value="age",required=false)Integer age)
			{  
				System.out.println(username+","+age);  
				return "success"; 
			}

 

  • @RequestBody()获取请求体的内容

GET请求方法是将所有参数封装在url上,而POST方法则是封装成一个对象【所以Form表单是POST请求】
请求体包含Form表单内容,controller函数形参只能写一个@RequestBody String body

作用:    用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。  
            get 请求方式不适用
            【异步的时候会用到。传递Json数据,封装的时候用到@RequestBody】
属性:  required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。
                     如果取值 为 false,get 请求得到是 null

    @RequestMapping("/testRequestBody")
    public String testRequestBody(@RequestBody String body){
        System.out.println("执行了...");
        System.out.println(body);
        return "success";
    }

实例:如果表单为,username:abc,age:12。则请求体为:username=abc&age=12

  • @PathVaribale()

       作用: 

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

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

       属性: 

                 value:用于指定 url 中占位符名称。 

                 required:是否必须提供占位符。

jsp 代码:

<!-- PathVariable 注解 --> 
<a href="springmvc/usePathVariable/100">pathVariable 注解</a> 

 

controller 代碼:

	@RequestMapping("/usePathVariable/{id}") 
	public String usePathVariable(@PathVariable("id") Integer id){
		System.out.println(id);  
		return "success"; 
	}

 


Restful风格:

个人理解——用不同的请求方法+佔位符来区分相同请求路径调用的不同方法——>用最简单的方法来实现复杂重复的代码
对于缓存的优点是——共用一个局部缓存,因爲路径上访问的都是这个Controller类对象,利于管理。


rest
Rest案例:
restcase

 

  • 基于HiddentHttpMethodFilter的Restful风格Controller实现

 

由于浏览器 form 表单只支持 GET 与 POST 请求(a标签支持的是GET),而 DELETE、PUT 等 method 并不支持
Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。
这样就可以实现@PathVaribale()注解的功用,创建Restful风格代码。


【除了这个filter,还可以通过WebClient类,直接调用静态方法模拟各种请求方式。以及浏览器插件也可以做到】

使用方式:

  1. 在web.xml中添加此filter過濾器
  2. 请求方式必须使用 post 请求。
  3. 按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

 

1.filter完全实现类
hhmfilter


原理:虽然form表单只能发post或者get
但下面有一行input 隐藏域<input type="hidden" name="_method" value="PUT">
这个会被filter拦截到,从而将post请求转换为put请求。

 

2 . .jsp

 

	<!-- 保存 --> 
	<form action="springmvc/testRestPOST" method="post"> 
		用户名称:<input type="text" name="username"><br/>  <!-- <input type="hidden" name="_method" value="POST"> --> 
	 	<input type="submit" value=" 保存 "> 
	 </form> 
	 	<hr/> 
	<!-- 更新 --> 
	<form action="springmvc/testRestPUT/1" method="post"> 
		用户名称:<input type="text" name="username"><br/>   
		<input type="hidden" name="_method" value="PUT"> 
	 	<input type="submit" value=" 更新 "> 
	</form>
	<hr/> 
	<!-- 删除 --> 
	<form action="springmvc/testRestDELETE/1" method="post"> 
 		<input type="hidden" name="_method" value="DELETE"> 
 		<input type="submit" value=" 删除 "> 
 	</form>
 	<hr/> 
	<!-- 查询一个 --> 
	<form action="springmvc/testRestGET/1" method="post"> 
		<input type="hidden" name="_method" value="GET"> 
 		<input type="submit" value=" 查询 ">
 	</form>  

 

3. controller

 

	/** 
 	* post 请求:保存  
 	* @param username  
 	* @return  */ 
 	@RequestMapping(value="/testRestPOST",method=RequestMethod.POST) 
 	public String testRestfulURLPOST(User user){  
 		System.out.println("rest post"+user);  
 		return "success"; 
 	}     
 	/** 
 	* put 请求:更新  
 	* @param username  
 	* @return  */ 
 	@RequestMapping(value="/testRestPUT/{id}",method=RequestMethod.PUT) 
 	public String testRestfulURLPUT(@PathVariable("id")Integer id,User user){  
 		System.out.println("rest put "+id+","+user);  
 		return "success"; 
 	}   
 	/** 
 	* post 请求:删除  
 	* @param username  
 	* @return  */ 
 	@RequestMapping(value="/testRestDELETE/{id}",method=RequestMethod.DELETE) 
 	public String testRestfulURLDELETE(@PathVariable("id")Integer id){  
 		System.out.println("rest delete "+id); 
 		return "success"; 
 	}   
  	/** 
 	* post 请求:查询  
 	* @param username  
 	* @return  */ 
 	@RequestMapping(value="/testRestGET/{id}",method=RequestMethod.GET) 
 	public String testRestfulURLGET(@PathVariable("id")Integer id){  
 		System.out.println("rest get  "+id);  
 		return "success"; 
 	} 

 

 

  • @RequestHeader

    属性:    value 指定Header名称(前端具有的属性),获得Accept头的值
                    required

实例:
    public String testRequestHeader(@RequestHeader(value="Accept") String header, {
        System.out.println(header);
        return "redirect:/param.jsp";
    }

 

 

  • @RequestCookie,得到JESSIONID

 

	属性:	value 指定Cookie名称(前端/session具有的属性),
			required

	实例:	public getCookie(@RequestCookie(value=“JSESSIONID”)String cookie){}

 

  • @ModelAttribute

 

	位置:	方法头上,controller方法形参前
	作用:	有该注解的方法(不需要写@RequestMapping),会在请求路径url的controller方法==先执行==。
	属性:	value 获取传入参数的key值,key可以是数据库类名,也可以是map<key,value>的key

	应用场景:在表单提交用户资料修改的时候,数据库POJO类的某些属性是定死的,肯定不允许修改的,那么这些属性值如何赋予?
			 【先将不可修改的数据项查询出来,直接传递给请求路径url的controller方法】就會用到这个注解

 

 

实例:

  1. 只有1个需要@ModelAttribute传递前置参数的情况,不需要使用Map

 

	@RequestMapping(/user/save)
	public String testModelAttribute(User user){
	}

	@ModelAttribute
	public User searchUser(String name){
		User user = new User();
		user.setName();
		user.setAge();
		user.setDate();
		return user
	}

 

 

@ModelAttribute

     public User serchUser(String name)内set赋值的属性值会通过return user传入

并且这个请求路径url的controller方法会再从网页前端获取user属性值,并覆盖掉@ModeAttribute的set置入的属性值。

 

@RequestMapping(/user/save)
public String testModelAttribute(User user)

 

 

2.  多个需要@ModelAttribute传递前置参数的情况,使用Map<String,T>存儲並通过指定@ModelAttribute String 传递的参数

 

	@RequestMapping(/user/save)
	public String testModelAttribute(@ModelAttribute("abc") User user){
	}

	@ModelAttribute
	public void searchUser(String name,Map<String,User> map){
		User user = new User();
		user.setName();
		user.setAge();
		user.setDate();
		map.put("abc",user)
	}

 

  • @SessionAttribute()

1.model.addAttribute("username", "泰斯特");     添加

 2.model.get("username")得到

 3.public String complete(SessionStatus sessionStatus){         
        sessionStatus.setComplete();  删除session

 

	作用:  用于controller类的多个方法间参数共享。 
	属性:  
			name=value:用于指定存入的属性名称  
		    type:用于指定存入的数据类型。 
	位置:	controller类上注解

 

实例:

 

	<!-- SessionAttribute 注解的使用 --> 
	<a href="springmvc/testPut">存入 SessionAttribute</a> <hr/> 
	<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/> 
	<a href="springmvc/testClean">清除 SessionAttribute</a>

 

注:Model接口是替代Request类的存在,降低耦合,该接口有一个完全实现类ModelMap/ExtendedModelMap,可用于取出Session对象内属性

 

@Controller("sessionAttributeController") 
@RequestMapping("/springmvc") 
@SessionAttributes(value={"username","password"},types={Integer.class}) 
public class SessionAttributeController {    /** 
  * 把数据存入 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";        
    }
}

 

 

請求參數綁定(映射)

 

表单中请求参数都是基于 key=value
SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,作为前端控制器中的方法的参数进行绑定,内置映射規則。

 

支持的數據類型

 

基本类型参数      :   包括基本类型和String类型 
POJO类型参数      :   包括实体类,以及关联的实体类 
数组和集合类型参数 :   包括 List 结构和 Map 结构的集合(包括数组) 
 
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。

 

 

映射規則

 

基本类型或者String类型:  
	要求参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写) 
POJO类型,或者它的关联对象:  
	要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。 
集合类型,有两种方式: 
	第一种:   要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
			  	给 List 集合中的元素赋值,使用下标。   
			  	给 Map 集合中的元素赋值,使用键值对。  
   	第二种:   接收的请求参数是 json 格式数据。需要借助一个注解实现

注意:  它还可以实现一些数据类型自动转换。内置转换器在:org.springframework.core.convert.support包

 

 

Java數據類型轉換如下:
transition

 

參數傳遞

 

  1. 少量參數
    一兩個方法所需的參數,直接在url中使用?``&傳遞即可
    只要求,傳遞的參數名與方法的參數名相同即可。

  2. 多個參數
    少量參數可以用? aaa=value1 & bbb=value2 & ...與符號來傳遞多個參數到後臺
    如果再多,可以用JavaBean來傳遞【使用form表單提交請求,而不是href=url】

 

JavaBean要求:
1.實現序列化接口 implements Serializable
2.所有的屬性有Set Get ToString方法

 

JSP form表單要求:
input name屬性值必須是與Javabean類的屬性名相同。不同則JavaBean的Set方法就找不到封裝失敗

 

Controller類方法將 參數寫為JavaBean類形參即可。(真的方便啊)
實例:

 

	@RequestMapping("/saveAccount")
    public String saveAccount(Account account){
        System.out.println("执行了...");
        System.out.println(account);
        return "success";
    }

 

 

  1. Javabean包含關聯類屬性
    如果Javabean的屬性關聯另一個對象,則在JSP 表單中name值=關聯類.屬性名
    例如:A 有 B類 屬性,B類有2個屬性 name age,則 JSP表單中 name=“b.name”//name="b.age"即可
    當然,一定要生成對應屬性的Get/Set方法,toString。

  2. List/Map集合屬性
    前提:對應屬性的Get/Set方法,toString

 

實例:

 

	JavaBean Account:
	    private List<User> list;
   	 	private Map<String,User> map;
   	JavaBean User:
   		private String uname;
    	private Integer age;
   	JSP:
   		<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="map['one'].uname" /><br/>
	        用户年龄:<input type="text" name="map['one'].age" /><br/>
	        <input type="submit" value="提交" />
   		</form>

 

 

自定義類型轉換器

 

SpringMVC 可以實現 2000/10/20 自動轉換為 日期類型
但不能識別 2000-10-20

 

  1. 繼承Converter接口,實現自定義轉換器類

 

package cn.itcast.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

//繼承Converter接口
public class StringToDateConverter implements Converter<String,Date> {
    /**
     * 页面传入的字符串s,返回转换完的Date类型变量df。
     * 下面为实现Converter接口的声明函数
     * @param s
     * @return
     */
    @Override
    public Date convert(String s) {
    	//判斷字符串
        if (s == null){
            throw new RuntimeException("空数据内容");
        }
        DateFormat df = new SimpleDateFormat("yyyy-mm-dd");
        try {
            return df.parse(s);
        } catch (Exception e) {
            throw new RuntimeException("格式错误");
        }
    }
}

 

 

  1. 配置springmvc(springmvc-service).xml注入這個自定義轉換器bean對象

 

	<!-- 配置自定义转换器,不覆盖,不写也默认启动-->
    <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="cn.itcast.converter.StringToDateConverter"></bean>
            </set>
        </property>
    </bean>

    <!-- 配置spring开启注解mvc的支持,開啓自定義轉換器設置,不覆蓋默認Spring Core轉換器
		 這裏默認開啓conversionService(Spring Core)-->
    <mvc:annotation-driven conversion-service="conversionService2"></mvc:annotation-driven>

 

 

获取/传递原生Servlet API对象

 

Request Response對象
直接在Controller方法的形參中聲明即可得到
HttpServletRequest request,
HttpServletResponse response,
HttpSession session

 

    /**
     * 原生的API
     * @return
     */
    @RequestMapping("/testServlet")
    public String testServlet(HttpServletRequest request, HttpServletResponse response){
        System.out.println("执行了...");
        System.out.println(request);

        HttpSession session = request.getSession();
        System.out.println(session);

        ServletContext servletContext = session.getServletContext();
        System.out.println(servletContext);

        System.out.println(response);
        return "success";
    }

 

 

解决Post提交方法的中文乱码


SpringMVC可以通过 设置过滤器filter(CharacterEncodingFilter)拦截所有的servlet请求,进行request处理。
web.xml

 

    <!--配置解决中文乱码的过滤器 放置在listener servlet配置前,Spring的context-param*配置后-->
    <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裏對request對象進行設置

 

Controller返回值类型

 

  • 开启EL表达式

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

 

1.String

Controller类中的方法返回字符串可以指定逻辑视图的名称,根据视图解析器为实际视图的访问地址

实例:
controller.java

 

	@RequestMapping(value="/hello")    
	public String sayHello() {        
		System.out.println("Hello SpringMVC!!");        
		// 跳转到XX页面        
		return "success";    
	}

 

 

2.void,404异常请求的页面为————方法名.jsp

 

如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
但是controller方法确实执行了。404异常请求的页面为————方法名.jsp

 

例如请求的方法是
@@RequestMapping(value="/user")
@RequestMapping(value="/initUpdate")
则异常为 找不到默认跳转【前缀】user/initUpdate【.jsp】的页面。

 

消除404:
1.手动请求跳转页面【转发】
问题1:手动request不经过视图解析器,所以要写完整路径
问题2:如果这个controller方法后续还有其他方法执行,如果不想执行,则写return;即可

 

2.重定向页面
转发是可以直接进入到具体路径的页面,重定向是重新发了一个新的请求
新的请求是不允许直接进入具体路径的页面需要request.getContextPath()

 

3.直接回复字节流至客户端

 

实例:

 

	@RequestMapping("/testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("testVoid方法执行了...");
        // 手动请求转发————手动request不经过视图解析器,所以要写完整路径
        //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;
    }

 

 

  • ModelAndView对象

 

ModelAndView对象是Spring提供的一个对象,可以用来调整t跳转的JSP视图
个人理解:与手动转发请求的区别只是在于是否通过springmvc的视图解析器,return 的底层就是ModelAndView

 

实例
controller.java

 

	@RequestMapping(value = "/findAll")
    public ModelAndView findAll() throws Exception {
        ModelAndView mv = new ModelAndView();

        // 模拟从数据库中查询所有的用户信息
        List<User> users = new ArrayList<>();
        User user1 = new User();
        user1.setUsername("张三");
        user1.setPassword("123");

        User user2 = new User();
        user2.setUsername("赵四");
        user2.setPassword("456");

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

        // 跳转到list.jsp的页面
        mv.setViewName("list");

        return mv;

 

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title></head>
<body>

    <h3>查询所有的数据</h3>
    <c:forEach items="${ users }" var="user">
        ${ user.username }
    </c:forEach>

</body>
</html>

 

 

  • SpringMVC提供的转发与重定向关键字

1.forward请求转发

重点!!:不走视图解析器,写完整路径,以及可以转发至controller类其他方法的请求路径

实例:

 

@RequestMapping("/delete")    
public String delete() throws Exception {        
	System.out.println("delete方法执行了...");        
	// return "forward:/WEB-INF/pages/success.jsp";        
	return "forward:/user/findAll";    
}

 

2.redirect重定向

重点!!:redirect底层封装了request.getContextPath(),所以不需要写了,同样也不经过视图解析器,【重定向也可以到controller类其他方法的请求路径】

 

实例:

 

@RequestMapping("/count")    
public String count() throws Exception {        
	System.out.println("count方法执行了...");        
	return "redirect:/add.jsp";        
	// return "redirect:/user/findAll";    
}

 

 

  • @ResponseBody() 响应json数据

 

多应用于ajax异步请求,接受json格式数据在服务器。

 

  1. 前置问题
    web.xml里面配置的拦截器DispatcherServlet会拦截到所有的资源。静态资源(img、css、js)也会被拦截到,从而不能被使用。
    解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置

 

配置springmvc.xml

 

<!-- 第一种配置 -->
<!-- 设置根目录下某些子目录的文件(静态资源)不拦截 -->    
<!-- <mvc:resources location="/css/" mapping="/css/**"/>   
<mvc:resources location="/images/" mapping="/images/**"/>  
<mvc:resources location="/js/" mapping="/js/**"/> -->

<!-- 第二种 -->
<!-- 处理动态,静态资源两个MVC标签,annotation-driven不仅仅是开启注解还代表注册各种SpringMVC组件xxx器 -->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:default-servlet-handler/>

 

 

location元素表示webapp目录下的包下的所有文件
mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
注意:<mvc:default-servlet-handler/>必须放在最后

 

1.使用@RequestBody注解参数获取请求体数据,获取JSON对象

 

controller.java

 

@RequestMapping("/testJson")    
public void testJson(@RequestBody String body) {        
	System.out.println(body);    
}

            输出:{"username":"hehe","password":"123","age":30}

 

Ajax.jsp

 

<header>
	<script>
        //绑定btn按钮的单击事件
        $(function(){
            $("#btn").click(function(){
                // alert("hello btn");
                // 发送ajax请求
                $.ajax({
                    // 编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"hehe","password":"123","age":30}',
                    //后端相应的返回值类型
                    dataType:"json",
                    type:"post",
                    //成功传至服务器后,Ajax执行的success函数
                    success:function(data){
                    }
                });

            });
        });
    </script>
</header>
<body>
	<button id="btn">发送ajax的请求</button>
</body>

 

 

  1. 使用@RequestBody注解返回值类型,将响应数据转换为json格式送给前端

第一步,客户端发送ajax请求,传入的是json字符串(请求体内)由SpringMVC框架自动转换封装到bean
第二步,@ResponseBody 注在返回值类型Address前,自动将Address类型转换为json格式数据响应给客户端

进阶版:使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端
前置要求:jackson3个jar包(annotations,databind,core)
Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入 jackson 包。

 

pom.xml的dependencies标签内引入依赖

 

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

 

controller.java

 

@RequestMapping("/testJson")  
//客户端发送ajax请求,传入的是json字符串(请求体内)由SpringMVC框架自动转换封装到address
//@ResponseBody 注在返回值类型Address前,自动将Address类型转换为json格式数据响应给客户端
public @ResponseBody Address testJson(@RequestBody Address address) {
	JavaBean中        
	System.out.println(address);        
	address.setAddressName("上海");        
	return address;    
}

 

 

客户端发送ajax请求,传入到controller方法的是json字符串(请求体内)由SpringMVC框架自动转换封装到JavaBean中
@ResponseBody注在返回值类型Address前,自动将Address类型(Javabean)转换为json格式数据响应给客户端

 

ajax.jsp

 

$(function(){        
 	// 绑定点击事件        
 	$("#btn").click(function(){            
 		$.ajax({                
 		url:"user/testJson",                
 		contentType:"application/json;charset=UTF-8",
        data:'{"addressName":"哈哈","addressNum":100}',
        dataType:"json",                
        type:"post",                
        success:function(data){                    
        	alert(data);                    
        	alert(data.addressName);                
        	}            
        });        
    });    
});

 

 

文件上传

前提条件

    A form 表单的 enctype(表单请求正文的类型) 取值必须是:multipart/form-data      
                                    (默认值是:application/x-www-form-urlencoded)
    B method 属性取值必须是 Post (get方法是将请求体写在URL里的。有大小限制)
    C 提供一个文件选择域<input type=”file” />

上传原理

不论是传输字符串,还是传输文件,都是通过form表单,其实文件只是长度很长的字符串罢了。

当 form 表单的 enctype=”application/x-www-form-urlencoded”时,
form 表单的正文内容是键值对+&:    key=value&key=value&key=value

当 form 表单的 enctype 取值为 Mutilpart/form-data 不是默认值时,request.getParameter()将失效。
请求正文内容就变成: 每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac   分界符
Content-Disposition: form-data; name="userName"  协议头
aaa              协议的正文(文件内容)
-----------------------------7de1a433602ac

那么我们的工作就是,解析Post请求方法的请求体,将文件内容、文件名拆分出来,然后在服务器指定路径下建立同名文件

 

自己来写很麻烦,借助第三方工具实现上传

使用SpringMVC框架内置MultipartFile对象

方法一:需要自己解析(不推荐)

  • 步骤

使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileuploadcommons-io
commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始依赖commons-io包。

 

  1. 导入依赖,pom.xml

 

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

 

2. jsp

 

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

 

3. controller.java

 

	/**
     * 文件上传     * @throws Exception
     */
    @RequestMapping(value = "/fileupload")
    public String fileupload(HttpServletRequest request) throws Exception {
        // 定义服务器端上传文件的目录 最后的/写不写都行
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 创建File对象,一会向该路径下上传文件【注意是在tomcat服务器下而不是Target】
        File file = new File(path);
        // 判断路径是否存在,如果不存在,创建该路径
        if (!file.exists()) {
            file.mkdirs();
        }
        // 创建磁盘文件项工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload fileUpload = new ServletFileUpload(factory);
        // 解析request对象
        List<FileItem> list = fileUpload.parseRequest(request);
        // 遍历
        for (FileItem fileItem : list) {
            // 判断文件项是普通表单,还是上传的文件
            if (fileItem.isFormField()) {
            } else {
                // 上传文件项
                // 获取到上传文件的名称                
                String filename = fileItem.getName();
                //解决重名文件覆盖,随机生成,把文件名设置为唯一值
                String uuid = UUID.randomUUID().ToString.replace("-","");
                filename = uuid + filename;
                // 上传文件                
                fileItem.write(new File(file, filename));
                //删除临时文件
                fileItem.delete();
            }
        }
        return "success";
    }

 

方法二:Spring框架内部MultipartFile对象实现上传(推荐)

SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件
注意:形参变量名称必须和前端表单<input type="file" name="upload"/>的 name属性名称相同。

 

与上面的第三方工具比较的优势:
1.不需要引入jar包,减少依赖
2.不需要再解析request,springMVC封装好了,在前端控制器中调用文件解析器对象来帮助解析。
3.代码简洁,干净。

 

原理分析:
实现原理

代码们:


1. jsp

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

 

 

2.  springmvc.xml中配置解析器

配置文件解析器对象,要求id名称必须multipartResolver ,不能随意起名字

<property name="maxUploadSize" value="10485760"/>   设置最大文件大小

<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->    
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        
	<property name="maxUploadSize" value="10485760"/>    
</bean>

 

 

3.   controller.java

 

	@RequestMapping(value = "/fileupload2")
    public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("SpringMVC方式的文件上传...");
        // 先获取到要上传的文件目录        
        String path = request.getSession().getServletContext().getRealPath("/uploads");
        // 创建File对象,一会向该路径下上传文件        
        File file = new File(path);
        // 判断路径是否存在,如果不存在,创建该路径        
        if (!file.exists()) {
            file.mkdirs();
        }
        // 获取到上传文件的名称        
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        // 把文件的名称唯一化        
        filename = uuid + "_" + filename;
        // 上传文件        
        upload.transferTo(new File(file, filename));
        return "success";
    }

 

 

SpringMVC跨服务器上传

 

    在实际开发中,为了提升模块功能的性能会单独的将一台服务器或多台作为集群服务器来延展增强功能来服务更多的用户。
    例如:  
        应用服务器:负责部署我们的应用  
        数据库服务器:运行我们的数据库  
        缓存和消息服务器:负责处理大并发访问的缓存和消息  
        文件服务器:负责存储用户上传文件的服务器。

 

1.引入依賴jar包


pom.xml

 

	<dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-core</artifactId>
        <version>1.18.1</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.18.1</version>
    </dependency>

 

2.index.jsp

 

<h3>跨服务器的文件上传</h3>        
<form action="user/fileupload3" method="post" enctype="multipart/form-data">        
	选择文件:<input type="file" name="upload"/><br/>        
	<input type="submit" value="上传文件"/>    
</form>

 

 

3.controller.java
本地文件对象创建改变為服务资源器对象,由服务器资源对象来进行文件书写。

 

	@RequestMapping(value = "/fileupload3")
    public String fileupload3(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("SpringMVC跨服务器文件上传...");
        // 定义图片服务器的请求路径
        String path = "http://localhost:9090/springmvc_day02_03fileService_war/uploads/";

        // 获取到上传文件的名称
        String filename = upload.getOriginalFilename();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        // 把文件的名称唯一化
        filename = uuid + "_" + filename;
        // 向图片服务器上传文件
        // 创建客户端对象
        Client client = Client.create();
        // 连接图片服务器
        WebResource webResource = client.resource(path + filename);
        // 上传文件
        webResource.put(upload.getBytes());
        return "success";
    }

 

 

SpringMVC异常处理器

 

系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息, 后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端 控制器交由异常处理器进行异常处理

 

exception

 

具体操作


1. 编写异常消息传递类/+你

 

public class customException extends Exception {
    //消息对象
    private String message;
    //构造函数
    public customException(String message) {
        this.message = message;
    }
    //get方法
    public String getMessage() {
        return message;
    }
}

 

 

2. 跳转的错误页面
error.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>执行失败</title></head>
<body>
执行失败!
${message }

</body>
</html>

 

 

3. 编写自定义异常处理器接口完全实现类

 

public class customExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        e.printStackTrace();
        customException customException = null;
        if (e instanceof customException) {
            customException = (customException) e;
        } else {
            customException = new customException("系统错误,请与系统管理 员联系!");
        }
        //携带信息,跳转到error.jsp页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("message", customException.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }
}

 

 

4.  配置自定义异常处理(拦截)器bean对象


spring.xml

 

	<!-- 配置自定义异常处理器 -->
    <bean id="handlerExceptionResolver" class="cn.itcast.eResolver.customExceptionResolver"/>

 


流程示意图


原理:所有的异常都会经过前端控制器,那么在前端控制器做人为的异常拦截(处理)将可识别的异常情况s,通过手写代码设置特别响应s
这样就不会给用户看一坨Tomcat的报错了。


customException类,主要功能是获取xxx.jsp页面抛出的异常,在异常被捕获的时候,并将异常信息传递给customExceptionResolver异常处理器,由异常处理器保存异常信息至modelAndView对象并跳转页面至error.jsp

異常攔截器

 


拦截器

 

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理,也就是AOP思想具体应用的一种

 

拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺 序联结成一条链。
在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

interceptor

  • 拦截器与过滤器filter的区别

过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。  
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。

过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。  
拦截器它是只会拦截访问請求——控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦 截

 

  • 实现自定义拦截器步骤


自定义拦截器, 要求必须实现:HandlerInterceptor 接口


一个拦截器


1.  编写HandlerInterceptor 接口 完全实现类

HandlerInterceptorDemo1.java

public class HandlerInterceptorDemo1 implements HandlerInterceptor {
	/**
     * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
     * 返回值:true表示放行,(如调用下一个拦截器或处理器);
     * false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
   	*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器preHandle拦截方法执行了,但放行了");
        //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理回调方法,controller后jsp前执行。实现处理器的后处理(但在渲染视图之前)。
     * 此时我们可以通过modelAndView(模型和视图对象),对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
    */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器postHandle后处理方法执行了,无法拦截,但可手动跳转");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);跳转到error.jsp,但是success.jsp依旧执行
    }

    /**
    * 整个请求处理完毕回调方法,success.jsp后执行。即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,
    * 还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
   */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion (final)方法执行了");
    }
}

 


2. 配置拦截器bean以及拦截范围


springmvc.xml

 

	<!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
        	<!--  要拦截的具体方法-->
                <!--  所有controller都拦截-->
            <mvc:mapping path="/**"/>
                <!--  不要拦截的具体方法
            <mvc:exclude-mapping path=""/>
                 -->
                <!--配置拦截器对象-->
            <bean id="handlerInterceptorDemo1" class="cn.itcast.interceptor.HandlerInterceptorDemo1"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

 

index.jsp

 

<html>
<body>
	<h2>Hello World!</h2>
	<a href="user/testInterceptor">Sout</a>
</body>
</html>

 

 

success.jsp

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h2>You are Success!!</h2>
    <% System.out.println("success.jsp页面渲染了");%>
</body>
</html>

 

 

3.测试运行结果

拦截器preHandle拦截方法执行了,但放行了
Controller类的testInterceptor方法执行了…
拦截器postHandle后处理方法执行了,无法拦截,但可手动跳转
success.jsp页面渲染了
afterCompletion (final)方法执行了

 

特殊情况:
当preHandle方法中写了手动跳转页面则不继续执行postHandle方法,即便写了return true;

但仍会继续执行afterCompletion

 

4.实例:


HandlerInterceptorDemo1完全实现类.java

 

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器preHandle拦截方法执行了,但放行了");
        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
        return true;
    }

 

 

success.jsp

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h2>You are Success!!</h2>
    <% System.out.println("suceesss.jsp页面渲染了");%>
</body>
</html>

 

 

測試执行结果:
preHandle 拦截器拦截了
suceesss.jsp页面渲染了
afterCompletion 方法执行了

 

  • 多个拦截器


按照springMVC中<mvc:interceptor />再配置多个,写同名同路经的完全实现类即可。

 

如何调用:   
        按拦截器定义顺序调用   
何时调用:   
        只要配置了都会调用    
有什么用:   
        如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true。   
        如果程序员决定不需要再调用其他的组件去处理请求,则返回 false.

        [注:false对客户端来说就是空白页面]

 

测试執行结果
拦截器1preHandle
拦截器2preHandle
controller
拦截器2postHandle
拦截器1postHandle
success.jsp渲染
拦截器2afterCompletion
拦截器1afterCompletion

 

Web-App标签子标签顺序

 

<!ELEMENT web-app (icon?, display-name?, description?, distributable?,

context-param*, filter*, filter-mapping*, listener*, servlet*,servlet-mapping*,

session-config?, mime-mapping*, welcome-file-list?,error-page*,
taglib*, resource-env-ref*, resource-ref*, security-constraint*,
login-config?, security-role*, env-entry*, ejb-ref*,  ejb-local-ref*)>

 

SSM整合之Spring框架的配置路径问题

 

  1. web.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <display-name>MyBatis_06_ssm</display-name>
  
    <!-- Spring默認配置 -->
  	<!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- SpringMVC前端控制器(核心) -->
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<!-- 設置前端控制器控制範圍 -->
	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
  
</web-app>

spring整合Mybatis在applicationContext.xml里面整合

提示:如果在eclipse中安装了Spring IDE插件则这里的Spring和SpringMVC标签都直接Alt+/选择#ContextLoaderListener
#dispatcherservlet即可添加


注意:关於SpringMVC中的<init-param/>以及Spring<context-param/>
SpringMVC的配置文件路径可以根据默认约定:
使用前端控制器(servlet)的servlet-name,"/WEB-INF/"+servlet-name+"-servlet.xml"
也就是/WEB-INF/spring-servlet.xml。


Spring的配置文件若没有通过context-param标签指定,则其param-name值默认是contextConfigLocation,param-value默认是/WEB-INF/applicationContext.xml。


一般来説,Spring的配置文件都是在类路径下
也就是需要写明param-value=classpath:applicationContext.xml
以及配置spring,必须要有listener标签。


---------------------
作者:今心木目
来源:CSDN
原文:https://blog.csdn.net/a1051826842/article/details/94333327
版权声明:本文为作者原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值