首先声明:本文全部摘自或改编:黑马程序员ssm学习教程(内部含有本人个人见解,如有错误,请帮忙指出,十分感谢)
1. 课程计划
第一天
1、SpringMVC介绍
2、入门程序
3、SpringMVC架构讲解
a) 框架结构
b) 组件说明
4、SpringMVC整合MyBatis
5、参数绑定
a) SpringMVC默认支持的类型
b) 简单数据类型
c) Pojo类型
d) Pojo包装类型
e) 自定义参数绑定
6、SpringMVC和Struts2的区别
第二天
1、高级参数绑定
a) 数组类型的参数绑定
b) List类型的绑定
2、@RequestMapping注解的使用
3、Controller方法返回值
4、SpringMVC中异常处理
5、图片上传处理
6、Json数据交互
7、SpringMVC实现RESTful
8、拦截器
开始学习ssm的最后一个知识点--springMVC学习:
0.目录:
1.springMVC可以和Mybatis进行整合,其实还是Mybatis和spring的整合,因为springMVC和spring是一家的,无缝整合,所以可写成springMVC与Mybatis的整合
2.struts2中的参数绑定:3种方法 某个类里建立个成员变量声明 多实例
spring MVC 在方法的形参上绑定,不以成员变量为主 单实例
1.SpringMVC介绍
1.springMVC是什么
Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来,如下图:
spring迎合apache,mybatis迎合spring,看jar包,spring开头和mybatis开头,哈哈。
2.springMVC处理流程
如图:
1.前端控制器:老大,和struts2中的file过滤器一样,放在web.xml中
2.处理器:小弟,负责将老大给他的请求处理
3.jsp页面:动态,经过标签渲染后将转化为HTML页面并返回给老大
4.用户
2.入门程序
1.导包
2.加入配置文件
web.xml
配置前端控制器(老大):
key-value:中name和配置监视器一样,是因为spring和spring MVC是一家的所以放配置文件也是放在一起
配置完web.xml之后开始配置上文中提到的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: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">
</beans>
3.建立controller
struts2叫action层,但是spring MVC叫controller层(也叫Handler(处理器)层--小弟)
但是加上注解之后需要扫描,所以在springmvc中加上
4.加入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="${itemList }" 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 }/itemEdit.action?id=${item.id}">修改</a></td> </tr> </c:forEach> </table> </form> </body> </html>
5.创建entity
分析页面,查看页面需要的数据,如下图:
创建商品entity
public class Item { // 商品id private int id; // 商品名称 private String name; // 商品价格 private double price; // 商品创建时间
private Date createtime; // 商品描述 private String detail; 创建带参数的构造器 set/get。。。 }
6.继续修改ItemController
在类上添加@Controller注解,把Controller交由Spring管理
在方法上面添加@RequestMapping注解,里面指定请求的url。其中“.action“可以加也可以不加。
@Controller public class ItemController { // @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配 // action可以写也可以不写 @RequestMapping(value = "/item/itemList.action") public ModelAndView queryItemList() { // 创建页面需要显示的商品数据(假数据)
List<Items> list = new ArrayList<Items>();
list.add(new Items(1, "1华为 荣耀8", 2399f, new Date(), "质量好!1"));
list.add(new Items(2, "2华为 荣耀8", 2399f, new Date(), "质量好!2"));
list.add(new Items(3, "3华为 荣耀8", 2399f, new Date(), "质量好!3"));
list.add(new Items(4, "4华为 荣耀8", 2399f, new Date(), "质量好!4"));
list.add(new Items(5, "5华为 荣耀8", 2399f, new Date(), "质量好!5"));
list.add(new Items(6, "6华为 荣耀8", 2399f, new Date(), "质量好!6"));
// 创建ModelAndView,用来存放数据和视图 ModelAndView modelAndView = new ModelAndView(); // 设置数据到模型中 modelAndView.addObject("itemList", list); // 设置视图jsp,需要设置视图的物理地址 modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp"); return modelAndView; } }
3.框架结构
个人描述:1.首先用户向老大(前端控制器,需要配置)发送请求(网址),2.然后老大交给处理器映射器(三大组件之一)处理器映射器处理后,3.返回拦截和Handler给老大,4.老大再把Handler给处理器适配器(三大组件之一),5.执行处理器(自己写:即通常所说的contorller层,或action层),6.之后返回ModelAndView(public ModelAndView itemList()),7.再把它交给老大,8.老大再请求视图解析器(三大组件之一)解析视图,9.解析过后将整个页面作为一个View对象返回给老大,10.之后老大渲染视图(即将模型数据填充至视图(jsp页面:自己写)中),11.将最终的HTML页面返回给用户,即响应用户。
2.架构流程
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、执行处理器(Controller,也叫后端控制器)。
6、Controller执行完成返回ModelAndView
7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、ViewReslover解析后返回具体View
10、DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
DispatcherServlet响应用户
3.说明:
在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。
需要用户开发的组件有handler、view
4.默认加载的驱动:
1.
从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。
在springmvc.xml配置文件中配置如下:
<!-- 配置处理器映射器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
注解描述:
@RequestMapping:定义请求url到处理器功能方法的映射
2.
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
在springmvc.xml配置文件中配置如下:
<!-- 配置处理器适配器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
3.
由于上面两个配置过于繁琐,所以在springmvc中加入了注解驱动(在springmvc.xml配置文件中配置):
4.
视图解析器原本不用配置,但是每次写方法时都要写一次
所以在springmvc.xml中
<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置逻辑视图的前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 配置逻辑视图的后缀 -->
<property name="suffix" value=".jsp" />
</bean>
这样只需写intemList即可
4.整合Mybatis-spring-springmvc
1.首先将Mybatis和spring整合
bean-dao.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- spring和hibernate*************************************** --> <!-- 配置c3p0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///springmvc"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <!-- ******************************************************* --> <!--********************************************** --> <!-- mybatis的工厂 --> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:sqlMapConfig.xml"></property> </bean> <!-- mapper动态代理开发 扫描--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 基本包 --> <property name="basePackage" value="com.springmvc.dao"> </property> </bean> <!-- ************************************************************* --> </beans>
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 设置别名 --> <typeAliases> <!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 --> <package name="com.springmvc.entity" /> </typeAliases> </configuration>
jar包:
在web.xml中配置监听器:
这样就可以连上数据库了,使用mybatis的逆向工程生成entity(已指定基本包)和dao(已指定别名),到此mybatis和spring的整合完毕。
2.整合springmvc
web.xml
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: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"> <!-- 扫描@Controller @Service --> <context:component-scan base-package="com.springmvc"></context:component-scan> <!-- 注解驱动 --> <mvc:annotation-driven/> <!-- 视图解析器 --> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置逻辑视图的前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 配置逻辑视图的后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans>
ok,三大框架整合完毕~
注:三个配置文件 applicationContext-dao.xml(
配置数据源、配置SqlSessionFactory、mapper扫描器。
), applicationContext-service.xml(
由springmvc.xml中对@Service的扫描替代
),applicationContext-trans.xml(
事务
)
实现商品列表的显示(连接数据库,不是假数据)
建立service层
在service实现类中写入:
1.
注释,说明功能
2.
注解,说明是service层
3.
注解,完成dao的注入
4.
调用dao的方法
5.
将方法粘贴到service接口一份
ItemService
package com.springmvc.service; import java.util.List; import com.springmvc.entity.Items; public interface ItemService { public List<Items> selectItemsList(); }
ItemServiceImpl
package com.springmvc.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.springmvc.dao.ItemsMapper; import com.springmvc.entity.Items; /** * 查询商品信息 * * @author 檽米糍 * */ @Service public class ItemServiceImpl implements ItemService { @Autowired public ItemsMapper itemsMapper; //查询商品列表(所有) public List<Items> selectItemsList(){ return itemsMapper.selectByExampleWithBLOBs(null); } }
建立controller层
6.
controller注释
7.
注解,说明是controller层
8.
注入service层
9.
写出访问路径
10.
调用service层方法实现功能
ItemController
package com.springmvc.controller; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.springmvc.entity.Items; import com.springmvc.service.ItemService; /** * 商品管理 * * @author 檽米糍 * */ @Controller public class ItemController { @Autowired private ItemService itemService; //入门程序 返回 包名+类名+方法名 @RequestMapping(value = "/item/itemList.action") public ModelAndView itemList() { //连接mysql List<Items> list = itemService.selectItemsList(); ModelAndView mav = new ModelAndView(); //数据 mav.addObject("itemList", list); mav.setViewName("itemList"); return mav; } }
完成~
记录一个可能会出现的错误:java.lang.NoSuchMethodException: com.springmvc.entity.Items.<init>()
原因:Items类中可能没有无参构造函数
我在改过之后还是一直报错,发现重启一遍tomcat之后就好了。。。= =
另,我把c3p0连接池改成druid(德鲁伊)了,需要再导入一个jar包:
配置如下:
<context:property-placeholder location="classpath:db.properties"/> <!-- 配置druid连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
db.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///XXX
jdbc.username=XXX
jdbc.password=XXX
5.参数绑定
注:后台的.action可以省略,但是输入网址时不能把.action省略掉。因为老大(前端控制器)不能识别不加.action的,但是到后台的时候表明已经筛选过了
1. 默认支持的参数类型
需求是:打开商品编辑页面,展示商品信息。
分析:
编辑商品信息,首先要显示商品详情
需要根据商品id查询商品信息,然后展示到页面。
请求的url:/itemEdit.action
参数:id(商品id)
响应结果:商品编辑页面,展示商品详细信息。
先写出serviceImpl
然后复制一份到service
开始着手写controller
1.
先看跳入方法的路径是:
2.
需要从请求的参数中把请求的id取出来。
Id包含在Request对象中。可以从Request对象中取id。
想获得Request对象只需要在Controller方法的形参中添加一个参数即可。Springmvc框架会自动把Request对象传递给方法。
3.
注意:传入参数:id 传出参数:item 传到页面:editItem
4.editItem.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> <!-- 上传图片是需要指定属性 enctype="multipart/form-data" --> <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> --> <form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" method="post"> <input type="hidden" name="id" value="${item.id }" /> 修改商品信息: <table width="100%" border=1> <tr> <td>商品名称</td> <td><input type="text" name="name" value="${item.name }" /></td> </tr> <tr> <td>商品价格</td> <td><input type="text" name="price" value="${item.price }" /></td> </tr> <%-- <tr> <td>商品生产日期</td> <td><input type="text" name="createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td> </tr> <tr> <td>商品图片</td> <td> <c:if test="${item.pic !=null}"> <img src="/pic/${item.pic}" width=100 height=100/> <br/> </c:if> <input type="file" name="pictureFile"/> </td> </tr> --%> <tr> <td>商品简介</td> <td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea> </td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="提交" /> </td> </tr> </table> </form> </body> </html>
2.绑定简单类型
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
但是如果非要名称不同:使用注解也行
但是@RequestParam标签用上之后有个巨大弊端:不能为null
所以
才是完整版,这样写不方便,所以推荐请求的参数名称和处理器形参名称一致
3.绑定pojo类型
需求:将页面修改后的商品信息保存到数据库中。
分析:
请求的url:/updateItem.action
参数:表单中的数据。
响应内容:更新成功页面
1.使用一个实体类接受表单数据
这里有一个items(ps:pojo对象中的属性名和表单中input的name属性一致)
2.
写serviceImpl
(ps:看注入参数是否为空需要在mapper.xml里进行<if>判断,提交的表单中不要有日期类型的数据,否则会报400错误。如果想提交日期类型的数据需要用到后面的自定义参数绑定的内容。)
3.
复制一份到service
4.
写controller实现
5.
写success.jsp
随便写个测试就行。
完成:发现数据库中的确被修改,但是form表单post提交之后成乱码了。。。
解决post提交乱码问题:
在web.xml中配置过滤器
4.绑定包装pojo
需求:使用包装的pojo接收商品信息的查询条件。
需要重新定义一个包装类QueryVo
package com.springmvc.entity; public class QueryVo { private Items items; public Items getItems() { return items; } public void setItems(Items items) { this.items = items; } }
修改controller:
jsp页面:
得到参数
5.自定义参数类型绑定
1. 需求
在商品修改页面可以修改商品的生产日期,并且根据业务需求自定义日期格式。
2. 需求分析
由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。
前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。
一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器,可以在此标签上进行配置。
3. 修改jsp页面
如下图修改itemEdit.jsp页面,显示时间
4. 自定义Converter
//Converter<S, T>
//S:source,需要转换的源的类型
//T:target,需要转换的目标类型
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
try {
// 把字符串转换为日期类型
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(source);
return date;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 如果转换异常则返回空
return null;
}
}
5. 配置Converter
我们同时可以配置多个的转换器。
<!-- 配置注解驱动 --> <!-- 如果配置此标签,可以不用配置... --> <mvc:annotation-driven conversion-service="conversionService" /> <!-- 转换器配置 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.itcast.springmvc.converter.DateConverter" /> </set> </property> </bean>
6. springmvc与struts2不同
1、 springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过滤器。
2、 springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
3、 Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面。Jsp视图解析器默认使用jstl。