SpringMVC

  1. SpringMVC框架理解

SpringMVC处理流程

在这里插入图片描述

配置前端控制器,拦截请求
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_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>springmvc-first</display-name>
	<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>

	<!-- 配置SpringMVC前端控制器 -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 指定SpringMVC配置文件 -->
		<!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-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结尾的请求进入SpringMVC
			1. /*  拦截所有请求 jsp js png css都拦截.(建议不使用)
			2. *.action *.do  拦截以action do结尾的请求
			3. /  拦截除jsp外的所有请求.(建议使用)
		 -->
		<url-pattern>*.action</url-pattern>
	</servlet-mapping>
</web-app>

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扫描包 -->
	<context:component-scan base-package="cn.itcast.springmvc.controller" />

</beans>

创建ItemController
ItemController是一个普通的java类,不需要实现任何接口。
需要在类上添加@Controller注解,把Controller交由Spring管理
在方法上面添加@RequestMapping注解,里面指定请求的url。其中“.action”可以加也可以不加
model存储数据实际上就是对request.setAttribute的封装

@Controller
public class 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"));

		// 创建ModelAndView,用来存放数据和视图
		ModelAndView modelAndView = new ModelAndView();
		// 设置数据到模型中
		modelAndView.addObject("list", list);
		// 设置视图jsp,需要设置视图的物理地址
		modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp");

		return modelAndView;
	}
}

Springmvc架构

三大组件:
  处理器映射器:分析请求路径,找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给前端控制器
  处理器适配器:调用相应的处理器,把得到的结果ModelAndView返回给前端控制器
  视图解析器:解析ModelAndView,读取对应的jsp页面到内存中,形成View对象返回给前端控制器

前端控制器对View进行渲染视图(即将模型数据填充至视图中),并将视图响应给用户
(处理器即Controller层)
一个中心,三个组件
springmvc架构图
我们没有做任何配置就可以使用这些组件,是因为框架已经默认加载这些组件了.

注解映射器和适配器
处理器映射器

?  注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射。根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。
HandlerMethod对象中封装url对应的方法Method。

?  从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。

springmvc.xml

<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />

处理器适配器
  注解式处理器适配器,对标记@ResquestMapping的方法进行适配。

从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。

<!-- 配置处理器适配器 -->
<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配置文件中配置如下:

<!-- 配置controller扫描包 -->
	<context:component-scan base-package="cn.itcast.springmvc.controller" />

<!-- 注解驱动 -->
	<mvc:annotation-driven />

<!-- 配置视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 配置逻辑视图的前缀 -->
		<property name="prefix" value="/WEB-INF/jsp/" />
		<!-- 配置逻辑视图的后缀 -->
		<property name="suffix" value=".jsp" />
	</bean>

整合SpringMVC与Mybatis

只需将spring与mybatis整合,springmvc和spring无缝整合,只需将springmvc.xml放入src并在web.xml中配置前端控制器即可.

参数绑定

springmvc的controller层是单例模式,因此不能使用成员变量接受参数.
每次请求不会直接使用对应的方法,而是以其为模板复制一份到本地线程中运行,即方法的副本

默认参数绑定
原生Servlet的方法
处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值(request,response,session,model)

	@RequestMapping(value = "/item/toEdit.action")
	public ModelAndView toEdit(HttpServletRequest request,HttpServletResponse response,HttpSession session,Model model) {
		//获取参数
		request.getParameter("id");
		...
	}

简单类型绑定
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
这样,从Request取参数的方法就可以进一步简化。
  支持的数据类型
参数类型推荐使用包装数据类型,因为基础数据类型不可以为null
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean

	@RequestMapping(value = "/item/toEdit.action")
	public ModelAndView toEdit(Integer id) {
		Item item = itemService.queryItemById(id);
		ModelAndView mav = new ModelAndView();
		mav.addObject("item",items);
		mav.setViewName("editItem");
		return mav;
	}

若两边名称不一致,需要使用@RequestParam标签进行参数绑定
使用该标签,则参数默认不能为空,否则会报错.可以使用required=false,defaultValue="1"解决

	@RequestMapping(value = "/item/toEdit.action")
	public ModelAndView toEdit(@RequestParam(value="id",required=false,defaultValue="1") Integer abc) {
		...
	}

pojo类型绑定
如果提交的参数很多,或者提交的表单中的内容很多的时候,可以使用简单类型接受数据,也可以使用pojo接收数据。
要求:请求的参数名称和pojo的属性名称一致,会自动将请求参数赋值给pojo的属性

	@RequestMapping(value="/updateitem.action")
	public ModelAndView updateItem(Item items) {
		itemService.updateItemsById(items);
		ModelAndView mav = new ModelAndView();
		mav.setViewName("success");
		return mav;
	}

解决post乱码问题
web.xml

<!-- 解决post请求乱码问题 -->
	<filter>
		<filter-name>encoding</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<!-- 设置编码参是UTF8 -->
		<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>/*</url-pattern>
	</filter-mapping>

包装pojo绑定
需求:使用包装的pojo接受商品信息的查询条件
包装对象定义:

public class QueryVo {
	private Item item;
	set/get...
}

页面传递参数名称设为:item.id/item.name

	// 绑定包装数据类型
	@RequestMapping("/queryItem")
	public String queryItem(QueryVo vo) {
		System.out.println(vo.getItem().getId());
		System.out.println(vo.getItem().getName());

		return "success";
	}

自定义参数绑定
需求:在商品修改页面可以修改商品的生产日期,并且根据业务需求自定义日期格式

由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。

前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。

一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器,可以在此标签上进行配置。

自定义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) {
			e.printStackTrace();
		}
		// 如果转换异常则返回空
		return null;
	}
}

配置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>

高级参数绑定

数组
Controller方法中可以用String[]接收,或者pojo的String[]属性接收。两种方式任选其一即可
在这里插入图片描述

/**
 * 包装类型 绑定数组类型,可以使用两种方式,pojo的属性接收,和直接接收
 * 
 * @param queryVo
 * @return
 */
@RequestMapping("queryItem")
public String queryItem(QueryVo queryVo, Integer[] ids) {

	System.out.println(queryVo.getItem().getId());
	System.out.println(queryVo.getItem().getName());

	System.out.println(queryVo.getIds().length);
	System.out.println(ids.length);

	return "success";
}

集合List
List中存放对象,并将定义的List放在包装类QueryVo中
在这里插入图片描述
jsp表单:

<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>

@RequestMapping

映射路径的注解
value = “url路径”
 若Controller类中所有方法的路径都有共同的前缀,则可以在类上加@RequestMapping(value=“前缀”)
method =
  RequestMethod.POST
  RequestMethod.GET
  {RequestMethod.POST,RequestMethod.GET}
(若不写method,则任何方法都可以)

从路径中获取参数

@RequestMapping(value = "/{id}/{str}") 
public ModelAndView helloWorld(@PathVariable String id, @PathVariable String str) { 
	System.out.println(id); 
	System.out.println(str); 
	return new ModelAndView("/helloWorld"); 
}

Controller层方法返回值

1. ModelAndView
  带数据Model,View返回视图路径

2. String(建议,数据与视图分离,解耦)
  return 返回路径名,返回数据通过形参上的Model的setAttribute方法,相当于request

@RequestMapping("xxx")
public String xxx(Model model){
	model.addAttribute("x",xxx);
	return "xxx";
	//重定向
	return "redirect:/itemEdit.action?itemId=" + item.getId();
	// 继续执行另一个方法
	// 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址
	// 转发并没有执行新的request和response,所以之前的请求参数都存在
	return "forward:/itemEdit.action";
}

3. void(适合ajax异步请求,无需跳转视图,response返回数据)

@RequestMapping("xxx")
public void xxx(HttpServletRequest request,HttpServletResponse response,Model model){
	//model.addAttribute("xxx",xxx);
	//request.getRequestDispatcher("xxx").forward(request,response);
	response.getWriter().print("{\"abc\":123}");
}

异常处理器

springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑
  
异常处理思路
  系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生
  系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理
在这里插入图片描述

自定义异常类
  为了区别不同的异常,通常根据异常类型进行区分,这里我们创建一个自定义系统异常
  如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息

public class MyException extends Exception {
	// 异常信息
	private String message;

	public MyException() {
		super();
	}

	public MyException(String message) {
		super();
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

}

自定义异常处理器

public class CustomHandleException implements HandlerExceptionResolver {

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception exception) {
		//Object handler是发生异常的地方,是字符串:包名+类名+方法名(形参)
		// 定义异常信息
		String msg;
		// 判断异常类型
		if (exception instanceof MyException) {
			// 如果是自定义异常,读取异常信息
			msg = exception.getMessage();
		} else {
			// 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
			Writer out = new StringWriter();
			PrintWriter s = new PrintWriter(out);
			exception.printStackTrace(s);
			msg = out.toString();
		}
		
		// 把错误信息发给相关人员,邮件,短信等方式
		// TODO

		// 返回错误页面,给用户友好页面显示错误信息
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("msg", msg);
		modelAndView.setViewName("error");

		return modelAndView;
	}
}

异常处理器配置

springmvc.xml
<!-- 配置全局异常处理器 -->
<bean id="customHandleException" 	class="cn.itcast.ssm.exception.CustomHandleException"/>

错误页面

<%@ 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>

	<h1>系统发生异常了!</h1>
	<br />
	<h1>异常信息</h1>
	<br />
	<h2>${msg }</h2>

</body>
</html>

异常测试

@RequestMapping(value = { "itemList", "itemListAll" })
public ModelAndView queryItemList() throws Exception {
	// 自定义异常
	if (true) {
		throw new MyException("自定义异常出现了~");
	}

	// 运行时异常
	int a = 1 / 0;

	// 查询商品数据
	List<Item> list = this.itemService.queryItemList();
	// 创建ModelAndView,设置逻辑视图名
	ModelAndView mv = new ModelAndView("itemList");
	// 把商品数据放到模型中
	mv.addObject("itemList", list);

	return mv;
}

上传图片/文件

加入jar包
在这里插入图片描述

配置上传解析器
springmvc.xml

<!-- 文件上传,id必须设置为multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<!-- 设置文件上传大小 -->
	<property name="maxUploadSize" value="5000000" />
</bean>

jsp页面
在这里插入图片描述
在这里插入图片描述

图片上传

@RequestMapping("updateItem")
public String updateItemById(Item item, MultipartFile pictureFile) throws Exception {
	// 图片上传
	// 设置图片名称,不能重复,可以使用uuid
	String picName = UUID.randomUUID().toString();

	// 获取文件名
	String oriName = pictureFile.getOriginalFilename();
	// 获取图片后缀
	String extName = oriName.substring(oriName.lastIndexOf("."));

	// 开始上传
	pictureFile.transferTo(new File("C:/upload/image/" + picName + extName));

	// 设置图片名到商品中
	item.setPic(picName + extName);
	// ---------------------------------------------
	// 更新商品
	this.itemService.updateItemById(item);

	return "forward:/itemEdit.action";
}

json数据交互

加入jar包
如果需要springMVC支持json,必须加入json的处理jar
在这里插入图片描述

jsp页面通过ajax请求发送json字符串

$(function(){
	var params = '{"id" : 1,"name" : "test","price" : 99.9}';
	$.ajax({
		url : "${pageContext.request.contextPath}/json.action",
		data : params,
		contentType : "application/json;charset=UTF-8",//发送数据的格式为json
		type : "post",
		dataType : "json",
		success : function(data){
			alert(data.name);
		}
	});
});

Controller方法
@ResponseBody 和 @RequestBody 的作用
@requestBody注解的使用

@RequestMapping("/json.action")
@ResponseBody
public Items json(@RequestBody Items items){
	return items;
}

拦截器

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>

SpringMVC与Struts2区别

  1. SpringMVC入口是一个servlet前端控制器.Struts2入口是一个filter过滤器
  2. SpringMVC在方法的形参上绑定请求参数.Struts2在属性上绑定请求参数
  3. SpringMVC是单例的(基于方法开发).Struts2是多例的(基于类开发)
  4. SpringMVC返回数据通过request域.Struts2通过值栈中的ActionContext数据中心
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页