SpringMVC框架(二)

SpringMVC框架(二)

第6章 视图解析

6.1 SpringMVC如何解析视图概述

1) 不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。
在这里插入图片描述
2) 视图解析源码分析:重要的两个接口
在这里插入图片描述
在这里插入图片描述

3) 断点调试源码
在这里插入图片描述
4) 流程图
在这里插入图片描述

6.2 视图和视图解析器

1) 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图
2) Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图
3) 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦

6.3 视图

1) 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户,主要就是完成转发或者是重定向的操作。
2) 为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口:
在这里插入图片描述

3) 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

6.4 常用的视图实现类

在这里插入图片描述

6.5 JstlView

1) 若项目中使用了JSTL,则SpringMVC 会自动把视图由InternalResourceView转为 JstlView (断点调试,将JSTL的jar包增加到项目中,视图解析器会自动修改为JstlView)
2) 若使用 JSTL 的 fmt 标签则需要在 SpringMVC 的配置文件中配置国际化资源文件
在这里插入图片描述

3) 若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

6.5.1 实验代码

1)增加jstl标签 jar包(断点调试,这时的View对象就是JstlView)
在这里插入图片描述

6.6 视图解析器

1) SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。
2) 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。
3) 所有的视图解析器都必须实现 ViewResolver 接口:
在这里插入图片描述

6.7 常用的视图解析器实现类

在这里插入图片描述
1) 程序员可以选择一种视图解析器或混用多种视图解析器
2) 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
3) SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常
4) InternalResourceViewResolver
① JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器:
在这里插入图片描述

6.8 mvc:view-controller标签

1)若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

<!-- 直接配置响应的页面:无需经过控制器来执行结果 -->
<mvc:view-controller path="/success" view-name="success"/>

2)请求的路径:
http://localhost:8080/SpringMVC_02_View/success

3)配置mvc:view-controller会导致其他请求路径失效
解决办法:

<!-- 在实际开发过程中都需要配置mvc:annotation-driven标签,后面讲,这里先配置上 -->
<mvc:annotation-driven/>

6.9 重定向

1) 关于重定向
① 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
② 如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
③ redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
④ forward:success.jsp:会完成一个到 success.jsp 的转发操作
2) 定义页面链接
testRedirect
3) 定义控制器方法

@RequestMapping("/testRedirect")
public String testRedirect(){
System.out.println("testRedirect");
return "redirect:/index.jsp";
//return "forward:/index.jsp";
}

4) 源码分析:重定向原理

  1. 源码分析:重定向原理
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    • return “forward:/index.jsp”
    在这里插入图片描述

第7章 综合案例RESTRUL_CRUD

7.1 RESTRUL_CRUD_需求

7.1.1 显示所有员工信息

1) URI:emps
2) 请求方式:GET
3) 显示效果
在这里插入图片描述

7.1.2 添加操作-去往添加页面

1) 显示添加页面:
2) URI:emp
3) 请求方式:GET
4) 显示效果
在这里插入图片描述

7.1.3 添加操作-添加员工

1) 添加员工信息:
2) URI:emp
3) 请求方式:POST
4) 显示效果:完成添加,重定向到 list 页面。
在这里插入图片描述

7.1.4 删除操作

1) URL:emp/{id}
2) 请求方式:DELETE
3) 删除后效果:对应记录从数据表中删除

7.1.5 修改操作-去往修改页面

1) URI:emp/{id}
2) 请求方式:GET
3) 显示效果:回显表单。

7.1.6 修改操作-修改员工

1) URI:emp
2) 请求方式:PUT
3) 显示效果:完成修改,重定向到 list 页面。

7.1.7 相关的类

省略了Service层,为了教学方便

1) 实体类:Employee、Department
2) Handler:EmployeeHandler
3) Dao:EmployeeDao、DepartmentDao
在这里插入图片描述

7.1.8 相关的页面

1) list.jsp
2) input.jsp
3) edit.jsp

7.2 搭建开发环境

1) 拷贝jar包

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2) 创建配置文件:springmvc.xml 增加context,mvc,beans名称空间。

<?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">
 
<!-- 配置扫描的包:com.atguigu.springmvc.crud -->
<context:component-scan base-package="com.atguigu.springmvc"/>
 
<!-- 配置视图解析器:默认采用转发 -->
<bean id="internalResourceViewResolver" 
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"></property>
</bean> 
</beans>

3) 配置核心控制器:web.xml

<servlet>
<servlet-name>springDispatcherServlet</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>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

4) 将 POST 请求转换为 PUT 或 DELETE 请求REST过滤器

  <filter>
          <filter-name>HiddenHttpMethodFilter</filter-name>
          <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
          <filter-name>HiddenHttpMethodFilter</filter-name>
          <url-pattern>/*</url-pattern>
  </filter-mapping>

5) 创建相关页面

/WEB-INF/views/list.jsp
index.jsp

6) 增加实体类
在这里插入图片描述在这里插入图片描述
7) 增加DAO类

package com.atguigu.springmvc.crud.dao;
 
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
 
import com.atguigu.springmvc.crud.entities.Department;
import com.atguigu.springmvc.crud.entities.Employee;
 
@Repository
public class EmployeeDao {
 
private static Map<Integer, Employee> employees = null;
 
@Autowired
private DepartmentDao departmentDao;
 
static{
employees = new HashMap<Integer, Employee>();
 
employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));
}
 
private static Integer initId = 1006;
 
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
} 
employee.setDepartment(departmentDao.getDepartment(
employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}
 
public Collection<Employee> getAll(){
return employees.values();
}
 
public Employee get(Integer id){
return employees.get(id);
}
 
public void delete(Integer id){
employees.remove(id);
}
}	package com.atguigu.springmvc.crud.dao;
 
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
 
import org.springframework.stereotype.Repository;
 
import com.atguigu.springmvc.crud.entities.Department;
 
@Repository
public class DepartmentDao {
 
private static Map<Integer, Department> departments = null;
 
static{
departments = new LinkedHashMap<Integer, Department>();
 
departments.put(101, new Department(101, "D-AA"));
departments.put(102, new Department(102, "D-BB"));
departments.put(103, new Department(103, "D-CC"));
departments.put(104, new Department(104, "D-DD"));
departments.put(105, new Department(105, "D-EE"));
}
 
public Collection<Department> getDepartments(){
return departments.values();
}
 
public Department getDepartment(Integer id){
return departments.get(id);
}
 
}

7.3 RESTRUL_CRUD_显示所有员工信息

1) 增加页面链接

<a href="empList">To Employee List</a>

2) 增加处理器

package com.atguigu.springmvc.crud.handlers;
 
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
import com.atguigu.springmvc.crud.dao.EmployeeDao;
 
@Controller
public class EmployeeHandler {
 
@Autowired
private EmployeeDao employeeDao ;
 
@RequestMapping("/empList")
public String empList(Map<String,Object> map){
map.put("empList", employeeDao.getAll());        //默认存放到request域中        
return "list";
} 
}
3)	SpringMVC中没遍历的标签,需要使用jstl标签进行集合遍历增加jstl标签库jar包
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
    
<!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>

<c:if test="${empty requestScope.empList }">
对不起,没有找到任何员工!
</c:if>
<c:if test="${!empty requestScope.empList }">
<table border="1" cellpadding="10" cellspacing="0">                
<tr>
<td>EmpId</td>
<td>LastName</td>
<td>Gender</td>
<td>Email</td>
<td>DepartmentName</td>
<td>Edit</td>
<td>Delete</td>
</tr>
<c:forEach items="${requestScope.empList }" var="emp">
<tr>
<td>${emp.id }</td>
<td>${emp.lastName }</td>
<td>${emp.gender==0?"Female":"Male" }</td>
<td>${emp.email }</td>
<td>${emp.department.departmentName }</td>
<td><a href="">Edit</a></td>
<td><a href="">Delete</a></td>
</tr>                
</c:forEach>        
</table>
</c:if>
 
</body>
</html>

7.4 RESTRUL_CRUD_添加操作

1) 在list.jsp上增加连接

<a href="empInput">Add Employee</a>

2) 增加处理器方法

@RequestMapping(value="/empInput",method=RequestMethod.GET)
public String empInput(Map<String,Object> map){
map.put("deptList", departmentDao.getDepartments());
//解决错误:java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
Employee employee = new Employee();
//map.put("command", employee);
map.put("employee", employee);
return "add";
}

3) 显示添加页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!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>
 
<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
 -->
 <form:form action="empAdd" method="POST" modelAttribute="employee">
         LastName : <form:input path="lastName"/><br><br>
         Email : <form:input path="email"/><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
        Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form> 
</body>
</html>

4) 显示表单信息时,会报错:

HTTP Status 500 - 
 
type Exception report
message 
description The server encountered an internal error () that prevented it from fulfilling this request.
exception 
org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/views/add.jsp at line 18
15:                         ② 表单回显
16:          -->
17:          <form:form action="empAdd" method="POST">
18:                  LastName : <form:input path="lastName"/>
19:                  Email : <form:input path="email"/>
20:                  <%
21:                          Map<String,String> map = new HashMap<String,String>();
Stacktrace:
        org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:410)
        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:337)
        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
        org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:266)
        org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1225)
        org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1012)
        org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
        org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)
        org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
        org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
root cause 
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
        org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)

7.5 使用Spring的表单标签 可以更方便的回显数据

1) 通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
2) form 标签
 一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的。
 只要满足该最佳条件的契约,form:form 标签就无需通过 action 属性指定表单提交的 URL
 可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean,如果该属性值也不存在,则会发生错误。
3) SpringMVC 提供了多个表单组件标签,如 form:input/、form:select/ 等,用以绑定表单字段的属性值,它们的共有属性如下:
 path:表单字段,对应 html 元素的 name 属性,支持级联属性
 htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true
 cssClass:表单组件对应的 CSS 样式类名
 cssErrorClass:表单组件的数据存在错误时,采取的 CSS 样式
4) form:input、form:password、form:hidden、form:textarea:对应 HTML 表单的 text、password、hidden、textarea 标签
5) form:radiobutton:单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中
6) form:radiobuttons:单选框组标签,用于构造多个单选框
 items:可以是一个 List、String[] 或 Map
 itemValue:指定 radio 的 value 值。可以是集合中 bean 的一个属性值
 itemLabel:指定 radio 的 label 值
 delimiter:多个单选框可以通过 delimiter 指定分隔符
7) form:checkbox:复选框组件。用于构造单个复选框
8) form:checkboxs:用于构造多个复选框。使用方式同 form:radiobuttons 标签
9) form:select:用于构造下拉框组件。使用方式同 form:radiobuttons 标签
10) form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签
11) form:errors:显示表单组件或数据校验所对应的错误
 <form:errors path= “” /> :显示表单所有的错误
 <form:errors path= “user
” /> :显示所有以 user 为前缀的属性对应的错误
 <form:errors path= “username” /> :显示特定表单对象属性的错误

7.6 添加员工实验代码

1) 表单

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!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>
 
<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
 -->
 <form:form action="empAdd" method="POST" modelAttribute="employee">
         LastName : <form:input path="lastName" /><br><br>
         Email : <form:input path="email" /><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
         Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form> 
</body>
</html>

2) 控制器方法

@Controller
public class EmployeeHandler {
@RequestMapping(value="/empAdd",method=RequestMethod.POST)
public String empAdd(Employee employee){
employeeDao.save(employee);
return "redirect:/empList";
}
}

7.7 RESTRUL_CRUD_删除操作&处理静态资源

7.7.1 删除实验代码

1) 页面链接

<td><a href="/empDelete/${emp.id }">Delete</a></td>

2) 控制器方法

@RequestMapping(value="/empDelete/{id}" ,method=RequestMethod.DELETE)
public String empDelete(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/empList";
}

7.7.2 HiddenHttpMethodFilter过滤器

发起请求,无法执行,因为delete请求必须通过post请求转换为delete请求,借助:HiddenHttpMethodFilter过滤器

7.7.3 需要使用jQuery来转换请求方式

1) 加入jQuery库文件

/scripts/jquery-1.9.1.min.js

2) jQuery库文件不起作用
警告: No mapping found for HTTP request with URI [/SpringMVC_03_RESTFul_CRUD/scripts/jquery-1.9.1.min.js] in DispatcherServlet with name ‘springDispatcherServlet’
在这里插入图片描述
3) 解决办法,SpringMVC 处理静态资源
① 为什么会有这样的问题:
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀,若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。
②解决: 在 SpringMVC 的配置文件中配置 mvc:default-servlet-handler/
4) 配置后,原来的请求又不好使了
需要配置<mvc:annotation-driven />

7.7.4 关于mvc:default-servlet-handler/作用

<!-- 
<mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,
就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
一般 WEB 应用服务器默认的 Servlet 的名称都是 default。
若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定        
参考:CATALINA_HOME/config/web.xml
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
该标签属性default-servlet-name默认值是"default",可以省略。        
<mvc:default-servlet-handler/>        
 -->
<mvc:default-servlet-handler default-servlet-name="default"/>
	7.7.5 通过jQuery转换为DELETE请求
<td><a class="delete" href="empDelete/${emp.id }">Delete</a></td>
<form action="" method="post">
<input type="hidden" name="_method" value="DELETE"/>
</form>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
var href = $(this).attr("href");
$("form").attr("action",href).submit();
return false ;
});
});
</script>

7.7.6 删除操作流程图解

在这里插入图片描述

7.8 RESTRUL_CRUD_修改操作

7.8.1 根据id查询员工对象,表单回显

1) 页面链接

<td><a href="empEdit/${emp.id }">Edit</a></td>

2) 控制器方法

//修改员工 - 表单回显
@RequestMapping(value="/empEdit/{id}",method=RequestMethod.GET)
public String empEdit(@PathVariable("id") Integer id,Map<String,Object> map){
map.put("employee", employeeDao.get(id));
map.put("deptList",departmentDao.getDepartments());
return "edit";
}

3) 修改页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>
 
<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
修改功能需要增加绝对路径,相对路径会报错,路径不对
 -->
 <form:form action="${pageContext.request.contextPath }/empUpdate" 
method="POST" modelAttribute="employee">                        
<%--
         LastName : <form:input path="lastName" /><br><br>
          --%>
                 <form:hidden path="id"/>
                 <input type="hidden" name="_method" value="PUT">
                 <%-- 这里不要使用form:hidden标签,否则会报错。 
<form:hidden path="_method" value="PUT"/>
                         Spring的隐含标签,没有value属性,同时,path指定的值,在模型对象中也没有这个属性(_method),所以回显时会报错。
                         org.springframework.beans.NotReadablePropertyException: 
                         Invalid property '_method' of bean class [com.atguigu.springmvc.crud.entities.Employee]: 
                         Bean property '_method' is not readable or has an invalid getter method: 
                         Does the return type of the getter match the parameter type of the setter?
                  --%>
                          
         Email : <form:input path="email" /><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
         Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form>
</body>
</html>

7.8.2 提交表单,修改数据

1) 控制器方法

@RequestMapping(value="/empUpdate",method=RequestMethod.PUT)
public String empUpdate(Employee employee){
employeeDao.save(employee);              
return "redirect:/empList";
}

第8章 处理JSON

8.1 返回JSON

1) 加入 jar 包:

http://wiki.fasterxml.com/JacksonDownload/   下载地址
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar

2) 编写目标方法,使其返回 JSON 对应的对象或集合

@ResponseBody  //SpringMVC对JSON的支持
@RequestMapping("/testJSON")
public Collection<Employee> testJSON(){
return employeeDao.getAll();
}

3) 增加页面代码:index.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>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){ 
$("#testJSON").click(function(){
 
var url = this.href ;
var args = {};
$.post(url,args,function(data){
for(var i=0; i<data.length; i++){
var id = data[i].id;
var lastName = data[i].lastName ;
alert(id+" - " + lastName);
}
});
 
return false ;
});                
});
</script>
 
</head>
<body>
 
<a href="empList">To Employee List</a>
<br><br>
 
<a id="testJSON" href="testJSON">testJSON</a>
 
</body>
</html>

4) 测试
在这里插入图片描述

8.2 HttpMessageConverter原理

8.2.1 HttpMessageConverter

1) HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息
2) HttpMessageConverter接口定义的方法:
① Boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
② Boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。
③ List getSupportMediaTypes():该转换器支持的媒体类型。
④ T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型的对象。
⑤ void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType。
在这里插入图片描述

package org.springframework.http;
 
import java.io.IOException;
import java.io.InputStream;
 
public interface HttpInputMessage extends HttpMessage {
 
InputStream getBody() throws IOException;
 
}	package org.springframework.http;
 
import java.io.IOException;
import java.io.OutputStream;
 
public interface HttpOutputMessage extends HttpMessage {
 
OutputStream getBody() throws IOException;
 
}

在这里插入图片描述
3) DispatcherServlet 默认装配 RequestMappingHandlerAdapter ,
而 RequestMappingHandlerAdapter 默认装配如下 HttpMessageConverter:
在这里插入图片描述

4) 加入 jackson jar 包后, RequestMappingHandlerAdapter
装配的 HttpMessageConverter 如下:
在这里插入图片描述
默认情况下数组长度是6个;增加了jackson的包,后多个一个
MappingJackson2HttpMessageConverter 就是它进行了数据的转换处理,负责json数据的处理
在这里插入图片描述

第9章 文件上传

9.1 文件上传

1) Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。
2) Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver
3) Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver
在这里插入图片描述

4) 配置 MultipartResolver
defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容,为了让CommonsMultipartResolver 正确工作,必须先将 Jakarta Commons FileUpload 及 Jakarta Commons io 的类包添加到类路径下。
在这里插入图片描述

9.2 文件上传示例

1) 拷贝jar包
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
这两个有依赖关系
严重: Servlet /SpringMVC_06_FileUpload threw load() exception

java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory

2) 配置文件上传解析器

<!-- 配置文件上传解析器
id必须是"multipartResolver",否则,会报错误:
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?
 -->
<bean id="multipartResolver"这个必须有啊   
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>

3) 上传页面

<%@ 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>Insert title here</title>
</head>
<body>
<form action="testUpload" method="post" enctype="multipart/form-data">
文件: <input type="file" name="file"/><br><br>
描述: <input type="text" name="desc"/><br><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>

4) 控制器方法

package com.atguigu.springmvc.crud.handlers;
 
import java.io.IOException;
import java.io.InputStream;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
 
@Controller
public class UploadHandler {
 
@RequestMapping(value="/testUpload",method=RequestMethod.POST)
public String testUpload(@RequestParam(value="desc",required=false) String desc, @RequestParam("file") MultipartFile multipartFile) throws IOException{                
System.out.println("desc : "+desc);
System.out.println("OriginalFilename : "+multipartFile.getOriginalFilename());
InputStream inputStream = multipartFile.getInputStream();
System.out.println("inputStream.available() : "+inputStream.available());
System.out.println("inputStream : "+inputStream);

return "success"; //增加成功页面: /views/success.jsp
}
}

9.3 思考多个文件上传?

在这里插入图片描述

第10章 拦截器

10.1 自定义拦截器概述

1) Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口 或者可以继承HandlerInterceptorAdapter适配器类
① preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
② postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
③ afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

10.2 实验代码(单个拦截器)

1) 自定义拦截器类

package com.atguigu.springmvc.interceptors;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
} 
}

2) 配置拦截器 (如果使用了注解,可以用ref的方式配置拦截器)

<mvc:interceptors>
<!-- 声明自定义拦截器 -->
<bean id="firstHandlerInterceptor"
      class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
</mvc:interceptors>

3) 断点调试拦截器执行流程
在这里插入图片描述
4) 拦截器方法执行顺序(小总结)
在这里插入图片描述

10.3 实验代码(多个拦截器)

1) 自定义拦截器类(两个)

package com.atguigu.springmvc.interceptors;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
}
 
}	package com.atguigu.springmvc.interceptors;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class SecondHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
}
 
}

2) 配置自定义拦截器

<mvc:interceptors>
<!-- 声明自定义拦截器 -->
<bean id="firstHandlerInterceptor"
  class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
<!-- 配置拦截器引用 -->
<mvc:interceptor>                        
<mvc:mapping path="/empList"/>
<!-- <mvc:exclude-mapping path="/empList"/> -->
<bean id="secondHandlerInterceptor"
         class="com.atguigu.springmvc.interceptors.SecondHandlerInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
两个都是返回true :
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
两个都是返回false:
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
true,false
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
false,true 
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
 

10.4 多个拦截方法的执行顺序

1) 关于执行顺序

com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor – preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion

2) 执行顺序图解
在这里插入图片描述
3) 从源代码的执行角度分析流程:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}

在这里插入图片描述

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}

在这里插入图片描述

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
 
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}

在这里插入图片描述
在这里插入图片描述
4) 源码分析:分析interceptorIndex的值情况
在这里插入图片描述

第11章 运行流程图解

11.1 流程图

在这里插入图片描述

11.2 Spring工作流程描述

1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
2) DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):
判断请求URI对应的映射
① 不存在:
 再判断是否配置了mvc:default-servlet-handler:
 如果没配置,则控制台报映射查找不到,客户端展示404错误
 如果有配置,则执行目标资源(一般为静态资源,如:JS,CSS,HTML)
② 存在:
 执行下面流程
3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
5) 如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
① HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
② 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
③ 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
④ 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
8) 此时将开始执行拦截器的postHandle(…)方法【逆向】
9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
10) 在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
11) 将渲染结果返回给客户端

11.3 源码解析

11.3.1 搭建环境

1) 拷贝jar包

spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2) 配置文件web.xml

<servlet>
<servlet-name>springDispatcherServlet</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>springDispatcherServlet</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: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">
 
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/>
 
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
 
</beans>

11.3.2 完成HelloWorld

1) 页面链接

<a href="helloworld">Hello World</a>

2) 控制器方法

package com.atguigu.springmvc.handler;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class HelloWorldHandler { 
@RequestMapping("/helloworld")
public String testHello(){ 
System.out.println("Hello,SpringMVC..."); 
return "success";
} 
}

3) 成功页面:/views/success.jsp

<h3>Success Page</h3>

11.3.3 Debug实验

1) 正常流程,运行出结果
2) 没有配置mvc:default-servlet-handler/,测试,直接报404
① http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2
四月 20, 2016 11:53:19 上午 org.springframework.web.servlet.PageNotFound noHandlerFound
警告: No mapping found for HTTP request with URI [/SpringMVC_09_WorkFlow/helloworld2] in DispatcherServlet with name ‘springDispatcherServlet’
② http://localhost:8080/SpringMVC_09_WorkFlow/test.html
四月 20, 2016 11:54:16 上午 org.springframework.web.servlet.PageNotFound noHandlerFound
警告: No mapping found for HTTP request with URI [/SpringMVC_09_WorkFlow/test.html] in DispatcherServlet with name ‘springDispatcherServlet’
3) 配置mvc:default-servlet-handler/,测试,会去查找目标资源
4) 测试,依然发生错误,这时,需要配置:mvc:annotation-driven/,否则,映射解析不好使。
在这里插入图片描述

11.3.4 Debug流程分析

1) HandlerExecutionChain mappedHandler;包含了拦截器和处理器方法;
DispatcherServlet L902 916
org.springframework.web.servlet.HandlerExecutionChain
Handler execution chain, consisting of handler object and any handler interceptors. Returned by
HandlerMapping’s HandlerMapping.getHandler method.
在这里插入图片描述
2) HandlerMapping

 org.springframework.web.servlet.HandlerMapping
Interface to be implemented by objects that define a mapping between requests and handler objects. 
This class can be implemented by application developers, although this is not necessary, as org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping and org.springframework.web.servlet.handler.SimpleUrlHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. 
HandlerMapping implementations can support mapped interceptors but do not have to. A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor's preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true. 
The ability to parameterize this mapping is a powerful and unusual capability of this MVC framework. For example, it is possible to write a custom mapping based on session state, cookie state or many other variables. No other MVC framework seems to be equally flexible. 
Note: Implementations can implement the org.springframework.core.Ordered interface to be able to specify a sorting order and thus a priority for getting applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.

3) 没有配置mvc:default-servlet-handler/,mvc:annotation-driven/,发送一个不存在资源的请求路径,mappedHandler为null
 http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2
在这里插入图片描述
在这里插入图片描述

4) 配置mvc:default-servlet-handler/,mvc:annotation-driven/,发送一个不存在资源的请求路径
 http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2
 mappedHandler不为null,原因是当循环simpleUrlHandlerMapping时,当做静态资源处理
在这里插入图片描述

11.3.5 断点

在这里插入图片描述

第12章 Spring整合SpringMVC

12.1 Spring 与SpringMVC的整合问题:

1) 需要进行 Spring 整合 SpringMVC 吗 ?
2) 还是否需要再加入 Spring 的 IOC 容器 ?
3) 是否需要在web.xml 文件中配置启动 Spring IOC 容器的 ContextLoaderListener ?
需要: 通常情况下, 类似于数据源, 事务, 整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中).
实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao.
不需要: 都放在 SpringMVC 的配置文件中. 也可以分多个 Spring 的配置文件, 然后使
用 import 节点导入其他的配置文件
4)如何启动Spring IOC容器?
非WEB环境:直接在main方法或者是junit 测试方法中通过new操作来创建。
WEB环境:我们希望Springloc 容器在WEB应用服务器启动时就被创建
通过监听器来监听 ServletContext对象的创建,监听到ServletContext对象被创建,就创建 SpringIOC容器。并且将容器对象绑定到ServletContext中,让所有的 web组件能共享到IOC容器对象。

12.2 Spring整合SpringMVC_解决方案配置监听器

1) 监听器配置

<!-- 配置启动 Spring IOC 容器的 Listener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2) 创建Spring的bean的配置文件:beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/>
 
<!-- 配置数据源, 整合其他框架, 事务等. -->
 
</beans>

3) springmvc配置文件:springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns: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">
 
<!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/> 
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"
   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
 
<mvc:default-servlet-handler/> 
<mvc:annotation-driven/> 
</beans>

在HelloWorldHandler、UserService类中增加构造方法,启动服务器,查看构造器执行情况。
问题: 若 Spring 的 IOC 容器和 SpringMVC 的 IOC 容器扫描的包有重合的部分, 就会导致有的 bean 会被创建 2 次.
解决方法:
1.使 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分.
2.使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解

springmvc.xml
<context:component-scan base-package="com.atguigu.springmvc" use-default-filters="false">
<context:include-filter type="annotation"
           expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"
           expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
 
beans.xml
<context:component-scan base-package="com.atguigu.springmvc">
<context:exclude-filter type="annotation"
        expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation"
        expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 配置数据源, 整合其他框架, 事务等. -->

12.3 SpringIOC 容器和 SpringMVC IOC 容器的关系

SpringMVC 的 IOC 容器中的 bean 可以来引用 Spring IOC 容器中的 bean.
返回来呢 ? 反之则不行. Spring IOC 容器中的 bean 却不能来引用 SpringMVC IOC 容器中的 bean
1) 在 Spring MVC 配置文件中引用业务层的 Bean
2) 多个 Spring IOC 容器之间可以设置为父子关系,以实现良好的解耦。
3) Spring MVC WEB 层容器可作为 “业务层” Spring 容器的子容器:
即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值