1.SpringMVC 的流程走向
第一步:发起请求到前端控制器(DispatcherServlet).
第二步:前段控制器请求处理映射器(HandlerMapping)查找 Handler.
通过xml配置文件、注解。
第三步:处理映射器 HandlerMapping 向前端控制器返回 Handler.
第四步:前端控制器通过处理器适配器(HandlerAdapter)执行Handler.
第五步:处理器适配器执行Handler。
第六步:Handler执行完给处理器适配器(HandlerAdapter)返回ModelAndView.
第七步:处理器适配器(HandlerAdapter)向前端控制器(DispatcherServlet)返回ModelAndView.
ModelAndView是SpringMVC框架底层的一个对象,ModelAndView包括Model和View.
第八步:前段控制器(DispatcherServlet)请求视图解析器解析视图.
根据逻辑视图名解析成真正的视图(物理视图包括jsp、freemarker、excel、pdf等)
第九步:视图解析器向前端控制器返回View.
第十步:前端控制器进行视图渲染。
视图渲染:把模型数据(在ModelAndView对象中)填充到Request域(RequestScope).
第十一步:前端控制器向用户响应(Response)请求结果。
2.组件:
2.1.前端控制器(DispatcherServlet)(不需要程序员开发,除非进行底层封装)
作用:接收请求、响应结果。相当于转发器。
有中央处理器的作用,有了前端控制器(DispatcherServlet),减少了其它组件之间的耦合度。
2.2.处理映射器(HandlerMapping)(不需要程序员开发)
作用:根据请求url查找Handler.
2.3.处理器适配器(HandlerAdapter)(不需要程序员开发)
作用:按照特定的规则(HandlerAdapter要求的规则)去执行Handler.
2.4.Handler处理器(####需要程序员开发)
注意:开发Handler时,要按照HandlerAdapter的要求去开发,适配器才能正确去执行Handler.
2.5.视图解析器(ViewResovler)(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(View).
2.6.视图(View)($$$需要程序员开发jsp)
View是一个接口,实现类支持不同的类型(jsp、freemarker、pdf...)
3.入门程序:《商品订单管理》
3.1)需求分析:订单表、商品表、商品明细表、用户表
3.1.1数据库级别
订单表 hx_order
商品表 hx_shop
购买明细表 hx_orderDetail
用户表 hx_user
需求:商品订单查询
3.1.2 业务级别:
1.一个用户可以创建多个订单:用户表到订单表是一对多
2.一个订购单只能对应一个用户:订单表到用户表一对一
3.一个订单可以对应多个购买明细:订单表到购买明细表是一对多
4.一个购买明细只能对应一个订单:购买明细表到订单表是一对一
5.一个购买明细只能对应一个商品:购买明细表到商品表是一对一
6.一个商品可以以对应多个购买明细:商品表到购买明细表是一对多
7.用户表 1:n 订单表 1:n 购买明细表 1:1 商品表,结论:用户表 1:n 商品表
8.商品表 1:n 购买明细表 1:1 订单表 1:1 用户表,结论:商品表 1:n 用户表
9.用户表 n:n 商品表
3.1.3 业务流程:
1.管理员维护商品
2.用户挑选商品,购买,创建订单。
3.1.4.创建数据库:
/*
SQLyog v10.2
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Table structure for table `items` */
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*Table structure for table `orderdetail` */
CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL COMMENT '订单id',
`items_id` int(11) NOT NULL COMMENT '商品id',
`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*Table structure for table `orders` */
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*Table structure for table `user` */
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*
SQLyog v10.2
MySQL - 5.1.72-community : Database - mybatis
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*Data for the table `items` */
insert into `items`(`id`,`name`,`price`,`detail`,`pic`,`createtime`) values (1,'台式机',3000.0,'该电脑质量非常好!!!!',NULL,'2015-02-03 13:22:53'),(2,'笔记
本',6000.0,'笔记本性能好,质量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'背包',200.0,'名牌背包,容量大质量好!!!!',NULL,'2015-02-06 13:23:02');
/*Data for the table `orderdetail` */
insert into `orderdetail`(`id`,`orders_id`,`items_id`,`items_num`) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);
/*Data for the table `orders` */
insert into `orders`(`id`,`user_id`,`number`,`createtime`,`note`) values (3,1,'1000010','2015-02-04 13:22:35',NULL),(4,1,'1000011','2015-02-03
13:22:41',NULL),(5,10,'1000012','2015-02-12 16:13:23',NULL);
/*Data for the table `user` */
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'王五',NULL,'2',NULL),(10,'张三','2014-07-10','1','北京市'),(16,'张小明',NULL,'1','河
南
郑州'),(22,'陈小明',NULL,'1','河南郑州'),(24,'张三丰',NULL,'1','河南郑州'),(25,'陈小明',NULL,'1','河南郑州'),(26,'王五',NULL,NULL,NULL);
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
3.2.环境搭建:
jdk(8)、mysql(5.7.13)、eclipse(sts3.8.1)
spring jar
mybatis jar
辅助 jar
3.3.创建web工程
3.3.1.修改classes输出目录为WebRoot/WEB-INF/classes,WEB目录改为WebRoot方便使用导入到myeclipse
3.3.2.工程默认字符集修改为UTF-8
3.3.3.自动提示,加入.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,延迟时间改为150-200毫秒
3.3.4.编辑显示字体改为Courier New.
3.3.5.我这里使用的IDE为sts,的maven创建工程
3.3.6.pom.xml内容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.hxweb.web</groupId>
<artifactId>ssmhxweb</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ssmhxweb Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<!-- spring版本号 -->
<spring.version>4.3.1.RELEASE</spring.version>
<!-- mybatis版本号 -->
<mybatis.version>3.3.0</mybatis.version>
<!-- log4j日志文件管理包版本 -->
<slf4j.version>1.7.7</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</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-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis/spring包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- 导入java ee jar 包 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<!-- 导入DB2数据库连接 jar 包 -->
<dependency>
<groupId>db2jcc</groupId>
<artifactId>db2jcc</artifactId>
<version>1.4</version>
</dependency>
<!-- 导入Mysql数据库链接jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- 导入阿里巴巴数据库的jar包,用来在applicationContext.xml中配置数据库 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<!-- JSTL标签类 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 日志文件管理包 -->
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- Attention: Be sure nothing pulls in an old dependency with groupId
"freemarker" (without the "org."), because then you will end up with two
freemarker.jar-s and unpredictable behavior! -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.25-incubating</version>
</dependency>
<!-- 格式化对象,方便输出日志 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<!-- 映入JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.2</version>
</dependency>
<!-- 上传组件包 -->
<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>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.apache.bval</groupId>
<artifactId>bval-jsr</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- 表示开发的时候引入,发布的时候不会加载此包 -->
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>ssmhxweb</finalName>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
3.3.7.配置前端控制器
在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_3_0.xsd"
id="WebApp_ssmhxweb" version="3.0">
<display-name>ssmhxweb</display-name>
<!--配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation 1.配置springmvc需要加载的配置文件(配置处理器映射器、处理器适配器、处理器、视图解析器等)
2.如果不配置contextConfigLocation,就会默认加载/WEB-INF/servlet名称-servlet.xml (这里是springmvc-servlet.xml) -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 多种配置方式: 第一种:*.action,*.do 访问以.action、.do为结尾的由DispatcherServlet来解析。
第二种:/ 所有访问地址都由DispatcherServlet来解析,对应静态文件需要配置不由DispatcherServlet进行解析。
使用此种方式可以实现RESTFul风格的url
第三种:/* 这种配置方式存在问题(不要用这种方式):最终转发到一个jsp页面时,
仍然会由由DispatcherServlet解析jsp页面,不能根据jsp页面找到对应的Handler,会报错。也不符合我们设计思想。
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
3.3.8.配置处理器适配器
3.3.8.1.配置 <!-- 配置处理器适配器 :所有的处理器适配器都实现了HandlerAdapter接口 -->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
3.3.8.2.查看源码:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
此适配器能执行实现 Controller 的 Handler
public interface Controller {
/**
* Process the request and return a ModelAndView object which the DispatcherServlet
* will render. A {@code null} return value is not an error: it indicates that
* this object completed request processing itself and that there is therefore no
* ModelAndView to render.
* @param request current HTTP request
* @param response current HTTP response
* @return a ModelAndView to render, or {@code null} if handled directly
* @throws Exception in case of errors
*/
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
3.3.9.编写 Handler
需要实现 Controller 接口,才能由 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter适配器来执行。
package org.hxweb.web.ssm.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hxweb.web.ssm.pojo.Items;
import org.hxweb.web.ssm.pojo.Orders;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
*
* @author Administrator
*
*/
public class ItemsController1 implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*
* 调用service来查找 数据库,查询商品列表,这里使用静态数据模拟
*/
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items1 = new Items();
items1.setName("联想");
items1.setPrice(6000f);
items1.setDetail("联想 Tinkpad E430");
Items items2 = new Items();
items2.setName("戴尔");
items2.setPrice(5800f);
items2.setDetail("戴尔笔记本");
Items items3 = new Items();
items3.setName("华硕");
items3.setPrice(5900f);
items3.setDetail("华硕笔记本");
itemsList.add(items1);
itemsList.add(items2);
itemsList.add(items3);
//为返回ModelAndView填充数据和指定视图
ModelAndView modelAndView = new ModelAndView();
//相当于request.setAtttibute,在jsp页面可以通过itemsList获取商品列表数据
modelAndView.addObject("itemsList", itemsList);
//指定返回视图
modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
//返回ModelAndView
return modelAndView;
}
}
3.3.10.视图的编写
itemsList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!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>
<form action="${pageContext.request.contextPath }/item/queryItem.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/item/editItem.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
3.3.11.配置处理器映射器
<!-- 配置处理器映射器 :BeanNameUrlHandlerMapping映射器 把bean的name作为url查找,需要在配置Handler是指定bean的name(就是url) -->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
3.3.12.配置 Handler
将编写的 Handler 在 Spring 容器中加载
<!-- 配置 Handler -->
<bean name="/queryItems.action" class="org.hxweb.web.ssm.controller.ItemsController1"></bean>
3.3.13.配置视图解析器
需要配置解析jsp的视图解析器
<!-- 配置视图解析器 :InternalResourceViewResolver视图解析器,是解析jsp的视图解析器,默认支持jstl标签 需要有jstl的jar包-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
public class InternalResourceViewResolver extends UrlBasedViewResolver {
private static final boolean jstlPresent = ClassUtils.isPresent(
"javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());
private Boolean alwaysInclude;
3.3.14.调试
3.3.14.1调试目标访问地址: http://localhost:8080/ssmhxweb/queryItems.action
3.3.14.2.处理器映射器根据url找不到 Handler 报如下错误提示(先检查url输入是否正确):
HTTP Status 404 -
type Status report
message
description The requested resource is not available.
--------------------------------------------------------------------------------
Apache Tomcat/8.0.35
3.3.14.3.处理器映射器根据url找到了 Handler 转发jsp页面地址不正确,在对应Handler中改正对应jsp页面的地址:
HTTP Status 404 - /ssmhxweb/WEB-INF/jsp/items/itemsLists.jsp
type Status report
message /ssmhxweb/WEB-INF/jsp/items/itemsLists.jsp
description The requested resource is not available.
--------------------------------------------------------------------------------
Apache Tomcat/8.0.35
4.非注解的处理器映射器和适配器
5.注金额的处理器和适配器
6.源码分析
6.1.接收请求
调用doDispatch方法
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
6.2 前端控制器调用处理器映射器 得到 Handler
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
6.3 调用处理器适配器执行 Handler,得到执行结果 ModelAndView
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
6.4 视图渲染,将 model数据填充到 request 域
1.入口
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
render(mv, request, response);
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
2.视图渲染
render(mv, request, response);
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
3.视图解析得到view
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
//4.填充数据数据
view.render(mv.getModelInternal(), request, response);
//5.填充实现
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(request);
//6.具体填充
exposeModelAsRequestAttributes(model, request);
/**
* Expose the model objects in the given map as request attributes.
* Names will be taken from the model Map.
* This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}.
* @param model Map of model objects to expose
* @param request current HTTP request
*/
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
for (Map.Entry<String, Object> entry : model.entrySet()) {
String modelName = entry.getKey();
Object modelValue = entry.getValue();
if (modelValue != null) {
request.setAttribute(modelName, modelValue);
if (logger.isDebugEnabled()) {
logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
"] to request in view with name '" + getBeanName() + "'");
}
}
else {
request.removeAttribute(modelName);
if (logger.isDebugEnabled()) {
logger.debug("Removed model object '" + modelName +
"' from request in view with name '" + getBeanName() + "'");
}
}
}
}
5.小结
1.通过入门程序 掌握 springmvc前端控制器、处理器映射器、处理器适配器、视图解析器的执行流程,最好多看源码。
前端控制器url配置
1.*.action
2./
处理器映射器
非注解的处理器映射器
注解的处理器映射器
利用组件扫描来完成
@Controller @RequestMapping
不用在xml中配置url 和 Handler的映射关系。
处理器适配器
非注解的处理器适配器
注解的处理器适配器
注解的处理器适配器和注解的处理器映射器是配对使用的。
<!-- 使用组件扫描 Controller -->
<context:component-scan base-package="org.hxweb.web.ssm.controller"></context:component-scan>
<!-- 实际开发中使用用 mvc:annotation-driven 不用配置注解映射器和注解的适配器,注解的映射器和注解的适配器必须配对使用-->
<mvc:annotation-driven></mvc:annotation-driven>
视图解析器
<!-- 配置视图解析器 :InternalResourceViewResolver视图解析器,是解析jsp的视图解析器,默认支持jstl标签 需要有jstl的jar包-->
<!-- 配置视图解析器 :InternalResourceViewResolver视图解析器,是解析jsp的视图解析器,默认支持jstl标签 需要有jstl的jar包-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Handler 中不用指定前缀和后缀,代码简洁。