springmvc详解(一):入门程序
目录
2.4.5、在springmvc.xml中配置编写的Handler
3.1、非注解处理器适配器HttpRequestHandlerAdapter
3.2、非注解处理器映射器SimpleUrlHandlerMapping
5.1、springmvc开发步骤:针对注解式的,非注解了解就好
一、什么是springmvc
1.1、springmvc的地位
springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。
springmvc是一个基于mvc的web框架。
1.2、springmvc框架(工作原理)
工作原理:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler
可以根据xml配置、注解进行查找
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView
ModelAndView是springmvc框架的一个底层对象,包括 Model和view
第八步:前端控制器请求视图解析器去进行视图解析
根据逻辑视图名解析成真正的视图(jsp)
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果
涉及到的组件分析:
1、前端控制器DispatcherServlet(不需要程序员开发)
作用:接收请求,响应结果,相当于转发器,中央处理器。
有了DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)
作用:根据请求的url查找Handler
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、处理器Handler(需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器View resolver(不需要程序员开发)
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6、视图View(需要程序员开发jsp)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
从组件分析可以知道:我们需要重点开发的是处理器Handler(或者Controller)和视图View;至于前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器HandlerAdapter、视图解析器View resolver都是现成的,我们只需要把他们配置好就可以直接使用。
二、入门程序
2.1、背景需求
以案例作为驱动。
springmvc和mybaits使用一个案例(商品订单管理)。
功能需求:商品列表查询
2.2、环境准备
数据库:mysql5.5(其他也可以)
java环境:jdk1.8(eclipse或者IDEA都可以)
spring版本:spring4
需要的jar包:ssm全部jar包,参照https://mp.csdn.net/postedit/86485520这篇博客,百度云免费下载。
2.3、工程结构
2.4、组件配置及开发
2.4.1、配置前端控制器
在web.xml中配置前端控制器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>springmvcfirst</display-name>
<!-- springmvc前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation配置springmvc加载的配置文件(配置处理器映射器、适配器等等)
如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml)
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
第一种:*.action,访问以.action结尾 由DispatcherServlet进行解析
第二种:/,所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置
不让DispatcherServlet进行解析
使用此种方式可以实现 RESTful风格的url
第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时,
仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。
-->
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
web.xml文件中主要做了这几件事:
1、配置了前端控制器DispatcherServlet
2、加载了springmvc的配置文件contextConfigLocation
3、指定url的解析方式
2.4.2、配置处理器适配器
在springmvc.xml文件中配置处理器适配器
<!-- 处理器适配器一:要求编写的Handler实现 Controller接口。 所有处理器适配器都实现 HandlerAdapter接口 -->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
这里先使用SimpleControllerHandlerAdapter这个非注解处理器适配器。(接下来会介绍另一个非注解的处理器适配器,以及注解的处理器适配器)
非注解处理器适配器SimpleControllerHandlerAdapter要求:编写的Handler实现 Controller接口。
2.4.3、开发Handler
Handler是一个类,存于Controler包下
package cn.itcast.ssm.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import cn.itcast.ssm.po.Items;
public class ItemsController1 implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
//下边的路径,如果在视图解析器中配置jsp路径的前缀和jsp路径的后缀,修改为
//modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
//上边的路径配置可以不在程序中指定jsp路径的前缀和jsp路径的后缀
modelAndView.setViewName("items/itemsList");
return modelAndView;
}
}
2.4.4、视图编写
编写itemsList.jsp文件,存于/springmvcfirst/WebRoot/WEB-INF/jsp/items/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>
2.4.5、在springmvc.xml中配置编写的Handler
<!-- 配置Handler -->
<bean name="/queryItems_test.action" class="cn.itcast.ssm.controller.ItemsController1" />
2.4.6、配置处理器映射器
在springmvc.xml文件中配置
<!-- 处理器映射器 将bean的name作为url进行查找 ,需要在配置Handler时指定beanname(就是url)
所有的映射器都实现 HandlerMapping接口。
-->
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
2.4.7、配置视图解析器
在springmvc.xml文件中配置
<!-- 视图解析器
解析jsp解析,默认使用jstl标签,classpath下的得有jstl的包
-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置jsp路径的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 配置jsp路径的后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
2.4.8、部署调试
Debug方式执行Service打开浏览器,输入相应的Handler的url即可。
2.4.9、相关错误
处理器映射器根据url找不到Handler,报下边的错误。说明url错误。
处理器映射器根据url找到了Handler,转发的jsp页面找到,报下边的错误,说明jsp页面地址错误了。
2.4.10、入门程序总结
由上面的组件分析可以知道,我们在web.xml我文件中配置了前端控制器、加载了springmvc的配置文件
在springmvc.xml中配置了处理器适配器、处理器映射器、Handler、视图解析器
入门程序中的处理器适配器使用的是SimpleControllerHandlerAdapter,它要求编写的Handler实现 Controller接口。
入门程序中的处理器映射器使用的是BeanNameUrlHandlerMapping,也就是需要在配置Handler时指定beanname,该处理器映射器才能找到它。
接下来我们会使用另一个非注解处理器适配器和处理器映射器,也会对Handler有相应的要求。
三、非注解的处理器适配器和映射器
上面我们已经实现了springmvc的第一个程序,其中的处理器适配器使用的是SimpleControllerHandlerAdapter,处理器映射器使用的是BeanNameUrlHandlerMapping。接下来我们使用另一个处理器适配器HttpRequestHandlerAdapter,另一个处理器映射器SimpleUrlHandlerMapping。
3.1、非注解处理器适配器HttpRequestHandlerAdapter
<!-- 另一个非注解的适配器二 :要求编写的Handler实现 HttpRequestHandler接口-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
理器适配器HttpRequestHandlerAdapter要求:编写的Handler实现 HttpRequestHandler接口
于是我们再写一个Handler
package cn.itcast.ssm.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import cn.itcast.ssm.po.Items;
public class ItemsController2 implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//设置模型数据
request.setAttribute("itemsList", itemsList);
//设置转发的视图
request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward
(request, response);
//使用此方法可以通过修改response,设置响应的数据格式,比如响应json数据
/*
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");*/
}
}
3.2、非注解处理器映射器SimpleUrlHandlerMapping
<!--处理器映射器二:简单url映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- 对itemsController1进行url映射,url是/queryItems1.action -->
<prop key="/queryItems1.action">itemsController1</prop>
<prop key="/queryItems2.action">itemsController1</prop>
<prop key="/queryItems3.action">itemsController2</prop>
</props>
</property>
</bean>
3.3、部署调试
我们对后配置的非注解处理器适配器HttpRequestHandlerAdapter和非注解处理器映射器SimpleUrlHandlerMapping进行调试
Debug方式执行Service打开浏览器,输入相应的Handler的url即可。
3.4、非注解的处理器适配器和映射器总结
通过上面的讲解,估计大家也发现了,不同的处理器适配器对编写的Handler有不同的要求,严重限制了我们的开发。同时springmvc.xml文件中可以存在多个不同的处理器适配器和映射器,如果这样一个一个的显示配置,工作量是繁琐繁重的。于是,就引出了注解的处理器映射器和适配器,他可以解决非注解方式存在的弊端。
四、注解的处理器映射器和适配器
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping注解映射器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping注解映射器。
在spring3.1之前使用org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter注解适配器。
在spring3.1之后使用org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter注解适配器。
大家对照自己的spring版本相应使用(我是用的是3.1之后的RequestMappingHandlerMapping和RequestMappingHandlerAdapter)
4.1、配置注解映射器和适配器。
<!--注解映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation
.RequestMappingHandlerMapping"/>
注解适配器
<bean class="org.springframework.web.servlet.mvc.method.annotation
.RequestMappingHandlerAdapter"/> -->
<!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
mvc:annotation-driven默认加载很多的参数绑定方法,
比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的
RequestMappingHandlerMapping和RequestMappingHandlerAdapter
实际开发时使用mvc:annotation-driven
-->
<mvc:annotation-driven></mvc:annotation-driven>
建议使用mvc:annotation-driven,而不使用注解处理器和适配器的单个配置。
4.2、开发注解Handler
package cn.itcast.ssm.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import cn.itcast.ssm.po.Items;
//使用Controller标识它是一个控制器
@Controller
public class ItemsController3 {
//商品查询列表
//@RequestMapping实现 对queryItems方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样
@RequestMapping("/queryItems")
public ModelAndView quertItems() throws Exception{
//调用service查找 数据库,查询商品列表,这里使用静态数据模拟
List<Items> itemsList = new ArrayList<Items>();
//向list中填充静态数据
Items items_1 = new Items();
items_1.setName("联想笔记本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430 联想笔记本电脑!");
Items items_2 = new Items();
items_2.setName("苹果手机");
items_2.setPrice(5000f);
items_2.setDetail("iphone6苹果手机!");
itemsList.add(items_1);
itemsList.add(items_2);
//返回ModelAndView
ModelAndView modelAndView = new ModelAndView();
//相当 于request的setAttribut,在jsp页面中通过itemsList取数据
modelAndView.addObject("itemsList", itemsList);
//指定视图
//下边的路径,如果在视图解析器中配置jsp路径的前缀和jsp路径的后缀,修改为
//modelAndView.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
//上边的路径配置可以不在程序中指定jsp路径的前缀和jsp路径的后缀
modelAndView.setViewName("items/itemsList");
return modelAndView;
}
//定义其它的方法
//商品添加
//商品修改
}
使用Controller标识该类是一个控制器
@RequestMapping实现 对queryItems方法和url进行映射,一个方法对应一个url
4.3、在spring容器中加载Handler
<!-- 对于注解的Handler可以单个配置
实际开发中建议使用组件扫描
-->
<!-- <bean class="cn.itcast.ssm.controller.ItemsController3" /> -->
<!-- 可以扫描controller、service、...这里让扫描controller,指定controller的包-->
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
4.4、部署调试
五、入门程序总结
5.1、springmvc开发步骤:针对注解式的,非注解了解就好
1、准备环境,导入jar包
2、建立好工程结构,在web.xml文件中配置前端控制器DispatcherServlet、加载springmvc的配置文件
3、开发注解式的Handler(非注解式的了解就好)
4、编写视图
5、在springmvc.xml配置文件中加载注解的Handler(扫描Controller所在的包)、配置注解的处理器和映射器(mvc:annotation-driven)、配置视图解析器
6、部署调试
完整的springmvc.xml配置文件如下:(web.xml文件参照2.4.1)
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 对于注解的Handler可以单个配置
实际开发中建议使用组件扫描
-->
<!-- <bean class="cn.itcast.ssm.controller.ItemsController3" /> -->
<!-- 可以扫描controller、service、...这里让扫描controller,指定controller的包-->
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>
<!--注解映射器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
注解适配器
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
<!-- 使用 mvc:annotation-driven代替上边注解映射器和注解适配器配置
mvc:annotation-driven默认加载很多的参数绑定方法,
比如json转换解析器就默认加载了,如果使用mvc:annotation-driven不用配置上边的RequestMappingHandlerMapping和RequestMappingHandlerAdapter
实际开发时使用mvc:annotation-driven
-->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 视图解析器
解析jsp解析,默认使用jstl标签,classpath下的得有jstl的包
-->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置jsp路径的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 配置jsp路径的后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
5.2、springmvc框架详解
这里针对1.2部分再做一个更细微的解释
1、浏览器发送请求,请求具体发到谁呢?先发到前端控制器,也就是说所有的请求都给发到前端控制器,前端控制器是所有请求的入口,但前端控制器不能处理业务请求,它只是一个请求的转发。
2、谁来处理业务请求呢?Handler处理器来真正处理业务请求,那么问题来了,前端控制器如何来找到这个Handler处理器呢?处理器映射器记录的就是请求的url和处理的方法之间的映射关系,这个映射关系是怎么建立起来的呢?就是通过@RequestMapping这个注解来建立起来的,这个映射关系就相当于一个Map(key-value这种形式),key就是请求的url,value就是处理的Handler。现在,前端控制器拿到这个请求之后,要找到对应的Handler,怎么找呢?就要找处理器映射器,问它请求谁来处理?
4、处理器映射器会根据你请求的url来找对应的处理器,找不到就会报错,如果找到之后,这时,它就会返回一个处理器执行链,这个处理器执行链里面除了有Handler之外,还有拦截器(这儿我们可以开发自己的拦截器),然后返回给前端控制器。
5、前端控制器依然不能处理这个业务请求,它这时做的还有另外一件事情,因为返回Handler,它也不知道这个Handler是什么类型,因为在spring mvc中Handler除了可以是注解形式的之外,其实还可以是非注解形式的(非注解形式我们一般不用),前端控制器并不知道这个Handler到底是什么类型的,那就没办法执行它,那总得找个东西执行,这时它就会把这个事交给另外一个组件来处理,这个组件就叫处理器适配器,这个处理器适配器就是来适配不同类型的Handler。它就会根据你不同类型的Handler来选择不同类型的适配器来执行它。
6、假如当前Handler是注解形式的,那么它就会选择注解形式的处理器适配器来执行这个Handler。Handler就执行了,也就是说我们Controller类中的那个方法就执行了,方法执行之后,里面的业务就处理了。
7、业务处理之后,最后返回一个ModelAndView。处理器适配器拿到这个结果是没有用的,它的作用就是执行这个Handler,把这个Handler执行完之后,它的事就做完了。
8、做完之后,拿到这个返回结果,那么它会原封不动地把这个返回结果扔给前端控制器,这时处理器适配器的事就做完了。
前端控制器拿到这个ModelAndView,它还是没有办法处理,它还是不能返回html,这时它要找到相应的jsp,因为ModelAndView即包含模型又包含视图,这个视图指定我们要用谁来渲染这个数据。我们要渲染数据,这时它就要找一个视图解析器来解析这个视图,由于这个视图也有很多种(我们最常见的视图是jsp,除了jsp,其实还有其他的,比如说还可以是报表,还可以是pdf,还可以是freemaker等),它会找不同的视图解析器来处理。因为现在我们最常用的视图是jsp,所以它就找到jsp对应的视图解析器。
9、找到这个视图解析器,它来把这个视图解析,解析完了之后它会返回一个View对象。
最后我们再调用这个视图解析器的渲染视图这个过程,渲染视图这个过程其实就是对于我们的jsp来说,就是把这个数据渲染成html。
10、最终渲染成html之后,就响应给用户。
六、参考文献
1、黑马程序员