SpringMVC介绍
Spring web mvc 和Struts2都属于表现层的框架,它是Spring框架的一部分
SpringMVC处理流程
入门程序
创建工程
导入jar包
在web.xml中配置前端控制器DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
在上面的url-pattern中拦截规则有如下:
- /* 表示拦截所有 jsp js png .css 会全部拦截
- *.action *.do 拦截以do action 结尾的请求
- / 拦截所有(不包括jsp) 包含 .js .png .css
创建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置controller扫描包-->
<context:component-scan base-package="cn.probuing.springmvc.controller"/>
</beans>
创建pojo
public class Item {
// 商品id
private int id;
// 商品名称
private String name;
// 商品价格
private double price;
// 商品创建时间
private Date createtime;
// 商品描述
private String detail;
创建带参数的构造器
set/get。。。
}
创建ItemController
ItemController是一个普通的java类,不需要实现任何接口
需要再类上添加@Controller注解,将Controller交由Spring管理
在方法上面添加@RequestMapping注解 里面指定请求的url
@RequestMapping("/itemList.action")
public ModelAndView queryItemList() {
// 创建页面需要显示的商品数据
// 创建页面需要显示的商品数据
List<Items> list = new ArrayList<>();
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 mav = new ModelAndView();
//设置视图跳转名称
mav.setViewName("WEB-INF/jsp/itemList.jsp");
//设置model数据
mav.addObject("itemList", list);
return mav;
}
启动测试
SpringMVC架构
框架结构
组件说明
以下组件通常由SpringMVC提供实现
前端控制器 DispatcherServlet
用户请求到达前端控制器,它就相当于MVC模式中的C,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispathcerServlet的存在降低了各个组件之间的耦合性
处理器映射器 HandlerMapping
HandlerMapping负责根据用户请求url找到Handler(处理器)springmvc提供了不同的映射器实现不同的映射方式。
Handler处理器
Handler是继DispathcerServlet前端控制器的后端控制器,在DispathcerServlet的控制下Handler对具体的用户请求进行处理 由于Handler涉及到具体的用户业务请求,所以一般情况需要自己开发Handler
HandlerAdapter 处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更对类型的处理器进行执行
ViewResolver 视图解析器
ViewResolver 负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给客户
View视图
springmvc框架提供了很多View视图类型的支持,包括:jstlView、freemarkerView、pdfView等
说明
在SpringMVC的各个组件中,处理器映射器,处理器适配器、视图解析器称为SpringMVC的三大组件
需要用户开发的组件是:Handler View
注解映射器和适配器
配置处理器映射器
注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射。根据@RequestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。
HandlerMethod对象中封装URL对应的方法Method
从Spring3.1开始,废除了DefaultAnnotationHandlerMapping的使用 拓建使用RequestMappingHandlerMapping完成注解式处理器映射
在springmvc.xml配置文件中配置如下
<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
配置处理器适配器
注解式处理器适配器,对标记@RequestMapping的方法进行适配
从Spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式适配器适配
在springmvc.xml配置文件中配置如下
<!--配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
注解驱动
直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来加载 SpringMVC使用 <mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter
可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的设置
<mvc:annotation-driven/>
视图解析器
视图解析器使用SpringMVC框架默认的InternalResourceViewResolver,这个视图解析器支持JSP视图解析
在springmvc.xml配置文件中配置如下
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置逻辑视图前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--配置逻辑视图后缀-->
<property name="suffix" value=".jsp"/>
</bean>
修改ItemController
// @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
// action可以写也可以不写
@RequestMapping("/itemList.action")
public ModelAndView queryItemList() {
// 创建页面需要显示的商品数据
List<Item> list = new ArrayList<>();
list.add(new Item(1, "1华为 荣耀8", 2399, new Date(), "质量好!1"));
list.add(new Item(2, "2华为 荣耀8", 2399, new Date(), "质量好!2"));
list.add(new Item(3, "3华为 荣耀8", 2399, new Date(), "质量好!3"));
list.add(new Item(4, "4华为 荣耀8", 2399, new Date(), "质量好!4"));
list.add(new Item(5, "5华为 荣耀8", 2399, new Date(), "质量好!5"));
list.add(new Item(6, "6华为 荣耀8", 2399, new Date(), "质量好!6"));
// 创建ModelAndView,用来存放数据和视图
ModelAndView modelAndView = new ModelAndView();
// 设置数据到模型中
modelAndView.addObject("itemList", list);
// 设置视图jsp,需要设置视图的物理地址
// modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp");
// 配置好视图解析器前缀和后缀,这里只需要设置逻辑视图就可以了。
// 视图解析器根据前缀+逻辑视图名+后缀拼接出来物理路径
modelAndView.setViewName("itemList");
return modelAndView;
}
整合mybatis
整合目标:控制层采用SpringMVC 持久层采用mybatis
导入jar包
创建数据库配置文件db.properties
- db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://140.210.70.23:3306/springmvc?characterEncoding=utf-8
jdbc.username=appUser
jdbc.password=AA1122BB
web.xml
- 在web.xml加入Spring监听器 ContextLoaderListener 并指定Spring配置文件
- web.xml文件中配置SpringMVC的前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--指定配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--spring mvc 前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml
- 在springmvc中配置controller扫描包
- 视图解析器
- 注解驱动
<?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扫描包-->
<context:component-scan base-package="cn.probuing.springmvc.controller"/>
<!--配置处理器映射器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
<!--配置处理器适配器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
<!--注解驱动-->
<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>
applicationContext.xml
- spring配置文件中配置 数据库文件,连接池
- 配置mybatis的工厂并指定核心配置文件的位置
- 指定mapper动态代理开发的扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:property-placeholder location="classpath:db.properties"/>
<!-- 数据库连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
</bean>
<!-- Mybatis的工厂 -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 核心配置文件的位置 -->
<property name="configLocation" value="classpath:SqlMapConfig.xml"/>
</bean>
<!-- Mapper动态代理开发 扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 基本包 -->
<property name="basePackage" value="cn.probuing.springmvc.dao"/>
</bean>
</beans>
参数绑定
在开发中 需要从请求的参数中把请求的id取出来
id包含在Request对象中,可以从Request对象中取id
想获得Request对象需要再Controller方法的形参中添加一个参数即可。Springmvc框架会自动把Request对象传递给方法
jsp页面
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
Controller
/**
* 通过id查询商品
*
* @param request
* @return
*/
@RequestMapping("/itemEdit")
public ModelAndView queryItemById(HttpServletRequest request) {
String strId = request.getParameter("id");
Items items = itemService.queryItemById(Integer.valueOf(strId));
//传递结果回页面
ModelAndView mva = new ModelAndView();
mva.setViewName("editItem");
//设置数据
mva.addObject("item", items);
return mva;
}
默认支持的参数类型
处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值
- HttpServletRequest 通过request对象获取请求信息
- HttpServletResponse 通过response处理响应信息
- HttpSession 通过session对象得到session中存放的对象
Model/ModelMap
Model
除了ModelAndView之外,还可以使用Model来向页面传递数据
Model是一个接口,在参数里直接声明model即可
如果使用Model则可以不适用ModelAndView对象,Model对象可以向页面传递数据View对象则可以使用String返回值替代
不管是Model还是ModelAndView其本质都是使用Request对象向jsp传递数据
/**
* 根据id查询商品,使用Model
*
* @param request
* @param model
* @return
*/
@RequestMapping("/itemEdit")
public String queryItemById(HttpServletRequest request, Model model) {
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
// 把结果传递给页面
// ModelAndView modelAndView = new ModelAndView();
// 把商品数据放在模型中
// modelAndView.addObject("item", item);
// 设置逻辑视图
// modelAndView.setViewName("itemEdit");
// 把商品数据放在模型中
model.addAttribute("item", item);
return "itemEdit";
}
ModelMap
ModelMap是Model接口的实现类,也可以通过ModelMap向页面传递数据。
使用Model和ModelMap的效果一样,如果直接使用Model,springmvc会实例化ModelMap
* @param request
* @param model
* @return
*/
@RequestMapping("/itemEdit")
public String queryItemById(HttpServletRequest request, ModelMap model) {
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
// 把结果传递给页面
// ModelAndView modelAndView = new ModelAndView();
// 把商品数据放在模型中
// modelAndView.addObject("item", item);
// 设置逻辑视图
// modelAndView.setViewName("itemEdit");
// 把商品数据放在模型中
model.addAttribute("item", item);
return "itemEdit";
}
绑定简单类型
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。这样从Request取参数的方法就可以进一步简化
/**
* 根据id查询商品,绑定简单数据类型
*
* @param id
* @param model
* @return
*/
@RequestMapping("/itemEdit")
public String queryItemById(int id, ModelMap model) {
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
// 把商品数据放在模型中
model.addAttribute("item", item);
return "itemEdit";
}
支持绑定的数据类型
参数类型推荐使用包装数据类型,因为基础数据类型不可以为null
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean
说明:对于布尔类型的参数,请求的参数值为true或false。或者1或0
请求url:
http://localhost:8080/xxx.action?id=2&status=false
处理器方法:
public String editItem(Model model,Integer id,Boolean status)
@RequestParam
使用@RequestParam常用于处理简单类型的绑定
- value 参数名字,即入参的请求参数名字
required 是否必须 默认是true 表示请求中一定要有响应的参数 否则报错
default 默认值,表示如果请求中没有同名参数时的默认值
@RequestMapping("/itemEdit")
public String queryItemById(@RequestParam(value = "itemId", required = true, defaultValue = "1") Integer id,
ModelMap modelMap) {
// 根据id查询商品数据
Item item = this.itemService.queryItemById(id);
// 把商品数据放在模型中
modelMap.addAttribute("item", item);
return "itemEdit";
}
绑定POJO类型
如果提交的参数很多,或者提交的表单中的内容很多的时候,可以使用简单类型接受数据,也可以使用pojo接收数据。
- 要求:pojo对象中的属性名和表单中的input的name属性一致
Controller
@RequestMapping(value = "/updateitem.action")
public String updateitem(Items items) {
itemService.updateItemsById(items);
return "success";
}
- 处理乱码问题
加入过滤器
<!--编码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
绑定包装POJO
创建包装的POJO QueryVo
package cn.probuing.springmvc.pojo;
/**
* @Auther: wxblack-mac
* @Date: 2018/8/28 17:45
* @Description:
*/
public class QueryVo {
private Items items;
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
}
jsp页面
<!-- <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="items.id" value="${item.id }" /> 修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="items.name" value="${item.name }" /></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="items.price" value="${item.price }" /></td>
</tr>
自定义参数绑定
有时候参数无法被springmvc转换,我们需要自定义转换参数
自定义Converter 实现Converter接口 泛型为 源类型和转换后的类型
/**
* @Auther: wxblack-mac
* @Date: 2018/8/28 19:05
* DataConverter
* S:需要转换的源的类型
* T:需要转换的目标类型
*/
public class DataConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
//转换s
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
Date date = sdf.parse(s);
return date;
} catch (ParseException e) {
return null;
}
}
}
配置转换器Converter
在springmvc.xml文件中
<!--配置转换器工厂bean-->
<bean id="conversionservicefactorybean"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!--配置转换器-->
<property name="converters">
<list>
<!--指定自定义转换器实现类-->
<bean class="cn.probuing.springmvc.converters.DataConverter"/>
</list>
</property>
</bean>
高级参数绑定
数组参数
@RequestMapping(value = "deletes.action")
public String deletes(Integer[] ids) {
for (Integer id : ids) {
System.out.println(id+"111");
}
return "success";
}
集合参数
<c:forEach items="${itemList }" var="item" varStatus="s">
<tr>
<td><input type="checkbox" name="ids" value="${item.id}"/></td>
<td>
<input type="hidden" name="itemList[${s.index}].id" value="${item.id }"/>
<input type="text" name="itemList[${s.index}].name" value="${item.name }"/>
</td>
<td><input type="text" name="itemList[${s.index}].price" value="${item.price }"/></td>
<td><input type="text" name="itemList[${s.index}].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
<td><input type="text" name="itemList[${s.index}].detail" value="${item.detail }"/></td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
SpringMVC和Struts2区别
- 1、SpringMVC的入口是一个Servlet即前端控制器。而Struts2入口是一个filter过滤器
- 2、SpringMVC请求参数传递到方法的形参,Struts2传递参数是通过类的属性
- 3、SpringMVC是基于方法开发(一个url对应一个方法),可以设计成单例或者多例
- 4、Struts采用值栈存储请求和响应数据,通过OGNL存储数据 SpringMVC通过参数计息期将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面,jsp视图解析器默认使用jstl
@RequestMapping
通过@RequestMapping注解可以定义不同的处理器映射规则
URL路径映射
@RequestMapping(value="item")或者 @RequestMapping("/item")
value是一个数组,可以将多个url映射到同一个方法
/**
* 查询商品列表
* @return
*/
@RequestMapping(value = { "itemList", "itemListAll" })
public ModelAndView queryItemList() {
// 查询商品数据
List<Item> list = this.itemService.queryItemList();
// 创建ModelAndView,设置逻辑视图名
ModelAndView mv = new ModelAndView("itemList");
// 把商品数据放到模型中
mv.addObject("itemList", list);
return mv;
}
添加到类上 窄化路径
对于重复的父路径可以使用URL放在类上可以指定简化的类路径
//@RequestMapping("item")
public class ItemController {
请求方法限定
method={RequestMethod.POST,RequestMethod.GET} 指定请求方式
- 限定GET方法
@RequestMapping(method = RequestMethod.GET)
- 限定POST方法
@RequestMapping(method = RequestMethod.POST)
Controller方法返回值
返回ModelAndView
controller 方法中定义ModelAndView对象并返回,对象中可添加moedel数据,指定View
返回void
在Controller方法形参上可以定义request和response
适合json 和 ajax请求时的方式
/**
* 返回void测试
*
* @param request
* @param response
* @throws Exception
*/
@RequestMapping("queryItem")
public void queryItem(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1 使用request进行转发
// request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request,
// response);
// 2 使用response进行重定向到编辑页面
// response.sendRedirect("/springmvc-web2/itemEdit.action");
// 3 使用response直接显示
response.getWriter().print("{\"abc\":123}");
}
返回字符串
逻辑视图名
controller 方法返回字符串可以指定逻辑视图名,通过视图解析为物理视图地址
Redirect重定向
Controller方法返回字符串可以重定向到一个url地址
/**
* 更新商品
*
* @param item
* @return
*/
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
this.itemService.updateItemById(item);
// 修改商品成功后,重定向到商品编辑页面
// 重定向后浏览器地址栏变更为重定向的地址,
// 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
// 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
return "redirect:/itemEdit.action?itemId=" + item.getId();
}
forward转发
Controllrer方法执行后继续执行另一个Controller方法
/**
* 更新商品
*
* @param item
* @return
*/
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
this.itemService.updateItemById(item);
// 修改商品成功后,重定向到商品编辑页面
// 重定向后浏览器地址栏变更为重定向的地址,
// 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
// 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
// return "redirect:/itemEdit.action?itemId=" + item.getId();
// 修改商品成功后,继续执行另一个方法
// 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址,
// 转发并没有执行新的request和response,所以之前的请求参数都存在
return "forward:/itemEdit.action";
}
异常处理器
Springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑
异常处理思路
系统中异常包括两类:预期异常和运行时异常,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常发生
异常处理器自定义实现类
实现HandlerExceptionResolver接口
/**
* @Auther: wxblack-mac
* @Date: 2018/8/30 14:50
* @Description:
*/
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
System.out.println(o);
ModelAndView mav = new ModelAndView();
mav.addObject("error", "未知异常");
mav.setViewName("error");
return mav;
}
}
方法形参中:httpServletRequest 请求对象 httpServletResponse 响应对象
Object o:异常信息封装 包名+类名+方法名
Exception e:异常对象
返回的ModelAndView 可以指定视图和数据
配置异常处理
<!--自定义异常处理-->
<bean class="cn.probuing.springmvc.exceptionhandler.MyExceptionHandler"/>
上传图片
加入上传图片的jar包
配置文件上传解析器
- 文件上传解析器 id必须设置为multipartResolver
<!--配置文件文件上传解析器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="commonsMultipartResolver">
<!--设置文件大小-->
<property name="maxUploadSize" value="5000000"/>
</bean>
jsp页面
<form id="itemForm" action="{item.id }"/> 修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="items.name" value="{item.price }"/></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="items.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="items.detail">${item.detail }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
java代码
方法接收时,图片形参的名字必须要和jsp页面 传递的图片的name一致
@RequestMapping(value = "/updateitem.action")
public String updateitem(QueryVo vo, MultipartFile pictureFile) throws IOException {
//创建图片名称
String picName = UUID.randomUUID().toString().replaceAll("-", "");
//获取文件名
String oriName = pictureFile.getOriginalFilename();
//获取图片后缀
String ext = FilenameUtils.getExtension(oriName);
//保存图片
pictureFile.transferTo(new File("/Users/wxblack-mac/pic/" + picName + "." + ext));
//保存数据库
vo.getItems().setPic(picName + "." + ext);
itemService.updateItemsById(vo.getItems());
return "redirect:/itemEdit.action?id=" + vo.getItems().getId();
}
JSON数据交互
@RequestBody
@RequestBody注解用于读取http请求的内容,通过springmvc提供的HttpMessageConverter接口将读取到的内容转换为java对象并绑定到Controller方法的参数上
@ResponseBody
@ReponseBody注解用于将Controller的方法返回的对象,通过SpringMVC提供的HttpMessageConverter接口转换为指定格式的数据。通过Response响应到客户端
加入jar包
Controller
@RequestMapping(value = "/json.action")
public @ResponseBody
Items json(@RequestBody Items items) {
return items;
}
JS发送Json数据
$(function () {
var params = '{"id": 1,"name": "测试商品","price": 99.9,"detail": "测试商品描述","pic": "123456.jpg"}';
alert(params);
$.ajax({
url: "${pageContext.request.contextPath}/json.action",
data: params,
contentType: "application/json;charset=UTF-8",
type: "post",
dataType: "json",
success: function (data) {
alert(data.name);
}
});
});
配置Json转换器
如果不适用注解驱动,就需要给处理器适配器配置json转换器
在springmvc.xml配置文件中,给处理器适配器加入json转换器
<!--处理器适配器 -->
<bean class=*"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"*>
<property name=*"messageConverters"*>
<list>
<bean class=*"org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"*></bean>
</list>
</property>
</bean>
RESTful支持
什么是restful?
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制
传统方式操作资源
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
测试
- 首先我们指定参数注入在地址中,在地址中的参数使用{}包裹并使用@PathVariable指定地址中的参数,对应到方法的形参中
/**
* 通过id查询商品
*
* @return
*/
@RequestMapping("/itemEdit/{id}.html")
public ModelAndView queryItemByIdRestFul(@PathVariable Integer id) {
Items items = itemService.queryItemById(id);
//传递结果回页面
ModelAndView mva = new ModelAndView();
mva.setViewName("editItem");
//设置数据
mva.addObject("item", items);
return mva;
}
-
访问
拦截器
定义
SpringMVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理
public class HandlerInterceptor1 implements HandlerInterceptor {
// controller执行后且视图返回后调用此方法
// 这里可得到执行controller时的异常信息
// 这里可记录操作日志
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("HandlerInterceptor1....afterCompletion");
}
// controller执行后但未返回视图前调用此方法
// 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("HandlerInterceptor1....postHandle");
}
// Controller执行前调用此方法
// 返回true表示继续执行,返回false中止执行
// 这里可以加入登录校验、权限拦截等
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("HandlerInterceptor1....preHandle");
// 设置为true,测试使用
return true;
}
}
拦截器定义 springmvc.xml
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1" />
</mvc:interceptor>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置具体的拦截器 -->
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
多个拦截器调用总结
按照配置执行后,我们可以看到 preHandler方法返回false后第一个拦截器只执行了preHandler方法,其他的两个方法没有执行,第二个拦截器的所有方法不执行,且Controller也不执行了
HandlerInterceptor1的preHandler方法返回true HandlerInterceptor2返回false时,我们可以看到第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了
preHandler按拦截器定义的顺序调用
postHandler按拦截器定义的顺序逆序调用
afterCompletion按拦截器定义顺序逆序调用
postHandler在拦截器链内所有拦截器返回成功调用,在多个拦截器时,只有所有拦截器的preHandler返回成功时 才会执行postHandler方法
afterCompletion只有preHandle 返回true才调用 在多个拦截器时,只要当前