【02】springmvc高级知识

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

springmvc高级知识

文章目录

0.复习

0.1springmvc框架

(1)DispatcherServlet前端控制器:接收request,进行response

(2)HandlerMapping处理器映射器:根据url查找Handler。(可以通过xml配置方式,注解方式)

(3)HandlerAdapter处理器适配器:根据特定规则去执行Handler,编写Handler时需要按照HandlerAdapter的要求去编写。

(4)Handler处理器(后端控制器):需要程序员去编写,常用注解开发方式。

(5)Handler处理器执行后结果是ModelAndView,具体开发时Handler返回方法值类型包括 :ModelAndView、String(逻辑视图名)、void(通过在Handler形参中添加request和response,类似原始 servlet开发方式,注意:可以通过指定response响应的结果类型实现json数据输出)

(6)View resolver视图解析器:根据逻辑视图名生成真正的视图(在springmvc中使用View对象表示)

(7)View视图:jsp页面,仅是数据展示,没有业务逻辑。

0.2注解开发

(1)使用注解方式的处理器映射器和适配器:

	<!--注解映射器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--注解适配器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

(2)在实际开发,使用mvc:annotation-driven代替上边处理器映射器和适配器配置。

(3)@controller注解必须要加,作用标识类是一个Handler处理器。

(4)@requestMapping注解必须要加,作用:

  • 对url和Handler的方法进行映射。
  • 可以窄化请求映射,设置Handler的根路径,url就是根路径+子路径请求方式
  • 可以限制http请求的方法

(4)映射成功后,springmvc框架生成一个Handler对象,对象中只包括一个映射成功的method。

0.3注解开发中参数绑定

(1)将request请求过来的key/value的数据(理解一个串),通过转换(参数绑定的一部分),将key/value串转成形参,将转换后的结果传给形参(整个参数绑定过程)。

0.3.1springmvc所支持参数绑定

(1)默认支持很多类型,HttpServletRequest、response、session、model/modelMap(将模型数据填充到request域)

(2)支持简单数据类型,整型、字符串、日期。

  • 只要保证request请求的参数名和形参名称一致,自动绑定成功

  • 如果request请求的参数名和形参名称不一致,可以使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边。

(3)支持pojo类型

  • 只要保证request请求的参数名称和pojo中的属性名一致,自动将request请求的参数设置到pojo的属性中。

  • 注意:形参中即有pojo类型又有简单类型,参数绑定互不影响。

0.3.2自定义参数绑定
0.3.2.1日期类型绑定自定义

(1)定义的Converter<源类型,目标类型>接口实现类,比如:

Converter<String,Date>表示:将请求的日期数据串转成java中的日期类型。
				注意:要转换的目标类型一定和接收的pojo中的属性类型一致。
				将定义的Converter实现类注入到处理器适配器中。
<mvc:annotation-driven conversion-service="conversionService">
</mvc:annotation-driven>

<!-- conversionService -->
<bean id="conversionService"
		class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
		<!-- 转换器 -->
		<property name="converters">
			<list>
				<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>
			</list>
		</property>
</bean>

0.4springmvc和struts2区别

(1)springmvc面向方法开发的(更接近service接口的开发方式),struts2面向类开发。

(2)springmvc可以单例开发,struts2只能是多例开发。

1.课程安排

1.1上午

(1)在商品查询和商品修改功能案例驱动下进行学习:

  • 包装类型pojo参数绑定(掌握)。
  • 集合类型的参数绑定:数组、list、map…
  • 商品修改添加校验,学习springmvc提供校验validation(使用的是hibernate校验框架)
  • 数据回显
  • 统一异常处理(掌握)

1.2下午

  • 上传图片
  • json数据交互
  • RESTful支持
  • 拦截器

2.包装类型pojo参数绑定

2.1需求

(1)商品查询controller方法中实现商品查询条件传入。

2.2实现方法

(1)第一种方法:在形参中 添加HttpServletRequest request参数,通过request接收查询条件参数。

(2)第二种方法:在形参中让包装类型的pojo接收查询条件参数。

(3)分析:

  • 页面传参数的特点:复杂,多样性。条件包括 :用户账号、商品编号、订单信息。。。
  • 如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。
  • 建议使用包装类型的pojo,pojo中属性是pojo。

2.3页面参数和controller方法形参定义

(1)页面参数:

商品名称:<input name="itemsCustom.name" />

注意:itemsCustom和包装pojo中的属性一致即可。

(2)controller方法形参:

public ModelAndView queryItems(HttpServletRequest request,ItemsQueryVo itemsQueryVo) throws Exception

在这里插入图片描述

3.集合类型绑定

3.1数组绑定

3.1.1需求

(1)商品批量删除,用户在页面选择多个商品,批量删除。

3.1.2表现层实现

(1)关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。

(2)页面定义:

<c:forEach items="${itemsList }" var="item">
<tr>
	<td><input type="checkbox" name="items_id" value="${item.id}"/></td>
	<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 }/items/editItems.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>

(3)controller方法定义:

	/**
	 * 指量删除商品
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/deleteItems")
	public String deleteItems(Integer[] items_id) throws Exception {

3.2list绑定

3.2.1需求
1)通常在需要批量提交数据时,将提交的数据绑定到list<pojo>中,比如:成绩录入(录入多门课成绩,批量提交),

(2)本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。

3.2.2表现层实现

(1)controller方法定义:

  • 进入批量商品修改页面(页面样式参考商品列表实现)

  • 批量修改商品提交

使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list<pojo>属性
public class ItemsQueryVo {
	/**
	 * 1.商品信息
	 */
	private Items items;
	
	/**
	 * 2.为了系统的可扩展性,对原始生成的po进行扩展
	 */
	private ItemsCustom itemsCustom;
	
	/**
	 * 3.批量商品信息 
	 */
	private List<ItemsCustom> itemsList;

/**
	 * 批量修改商品提交
	 * 通过ItemsQueryVo itemsQueryVo接收批量修改的商品信息,将商品信息存储到itemsQueryVo中itemsList属性中
	 */
	public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo)throws Exception {
		
		return "success";
	}

(2)页面定义

<c:forEach items="${itemsList}" var="item" varStatus="status">
<tr>
	<td><input type="text" name="itemsList[${status.index}].name" value="${item.name}"/></td>
	<td><input type="text" name="itemsList[${status.index}].price" value="${item.price}"/></td>
	<td><input type="text" name="itemsList[${status.index}].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
	<td><input type="text" name="itemsList[${status.index}].detail" value="${item.detail}"/></td>
</tr>
</c:forEach>

在这里插入图片描述

3.3Map绑定

(1)也通过在包装pojo中定义map类型属性。

(2)在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。

(3)包装类中定义Map对象如下:


public class QueryVo {
private Map<String, Object> itemInfo = new HashMap<String, Object>();
  //get/set方法..
}

(4)页面定义如下:

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

(5)Contrller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{
System.out.println(queryVo.getStudentinfo());
}

4.springmvc校验

4.1校验理解

(1)项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。

(2)服务端校验:

  • 控制层conroller:校验页面请求的参数的合法性。在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)

  • 业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。

  • 持久层dao:一般是不校验的。

4.2springmvc校验需求

(1)springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。

(2)校验思路:

  • 页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
    具体需求:

  • 商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。

4.3环境准备

(1)hibernate的校验框架validation所需要jar包:

在这里插入图片描述

4.4配置校验器

	<!-- 5.校验器 -->
	<bean id="validator"
		class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
		<!-- 5.1校验器-->
		<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
		<!-- 5.2指定校验使用的资源文件,如果不指定则默认使用classpath下的ValidationMessages.properties -->
		<property name="validationMessageSource" ref="messageSource" />
	</bean>
	
	<!-- 6.校验错误信息配置文件 -->
	<bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<!-- 6.1资源文件名-->
		<property name="basenames">   
       	 <list>    
            <value>classpath:CustomValidationMessages</value> 
       	 </list>   
    	</property>
		<!-- 
			6.2资源文件编码格式
			6.2.1低版本中配置的属性为<property name="fileEncodings" value="utf-8">,会导致控制器在读取
			CustomValidationMessages.properties属性文件中的中文错误信息乱码,属性名改为defaultEncoding即可解决此乱码问题
		 -->
		<property name="defaultEncoding" value="utf-8"/>
		<!-- 6.3对资源文件内容缓存时间,单位秒 -->
		<property name="cacheSeconds" value="120" />
	</bean>

4.5校验器注入到处理器适配器中

		<mvc:annotation-driven 
			conversion-service="conversionService" 
			validator="validator"></mvc:annotation-driven>

4.6在pojo中添加校验规则

在ItemsCustom.java中添加校验规则:
在这里插入图片描述

4.7CustomValidationMessages.properties

在CustomValidationMessages.properties配置校验错误信息:

#添加校验错误的提示信息
items.name.length.error=请输入1到30个字符的商品名称
items.createtime.isnull=请输入商品的生产日期

4.8 捕获校验错误信息

	/**
	 * 商品信息修改提交
	 * 1.在需要校验的pojo前添加@Validated注解
	 * 2.在需要校验的后面添加BindingResult bindingResult参数,用于接收校验出错信息
	 * 3.注意:如果需要校验多个pojo,@Validated和 BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/editItemsSubmit")
	public String editItemsSubmit(HttpServletRequest request,Integer id,
			@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{
		//1.获取校验错误信息
		if(bindingResult.hasErrors()) {
			//1.1输出错误信息
			List<ObjectError> allErrors = bindingResult.getAllErrors();
			
			for(ObjectError err : allErrors) {
				System.out.println(err.getDefaultMessage());
			}
		}

4.9在页面显示校验错误信息

(1)在controller中将错误信息传到页面即可。

/**
	 * 商品信息修改提交
	 * 1.在需要校验的pojo前添加@Validated注解
	 * 2.在需要校验的后面添加BindingResult bindingResult参数,用于接收校验出错信息
	 * 3.注意:如果需要校验多个pojo,@Validated和 BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/editItemsSubmit")
	public String editItemsSubmit(Model model, HttpServletRequest request,Integer id,
			@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{
		//1.获取校验错误信息
		if(bindingResult.hasErrors()) {
			//1.1输出错误信息
			List<ObjectError> allErrors = bindingResult.getAllErrors();
			
			for(ObjectError err : allErrors) {
				System.out.println(err.getDefaultMessage());
			}
			
			//1.2将错误信息传到页面
			model.addAttribute("allErrors",allErrors);
			//1.3出错重新跳转到商品出错页面
			return "items/editItems";
		}
		
		//2.调用service更新商品信息,页面需要将商品信息传到此方法
		itemsService.updateItems(id, itemsCustom);
		
		//return "forward:queryItems.action";
		return "success";
	}

(2)页面显示错误信息:

<!-- 显示错误信息 -->
<div style="color:#d82828;">
	<c:if test="${null != allErrors}">
		<c:forEach items="${allErrors}" var="error">
			${error.defaultMessage}<br/>
		</c:forEach>
	</c:if>
</div>

4.10分组校验

4.10.1需求

(1)在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。

(2)解决方法:

  • 定义多个校验分组(其实是一个java接口),分组中定义有哪些规则

  • 每个controller方法使用不同的校验分组

4.10.2校验分组
public interface ValidGroup1 {
	/*
	 * 1.接口中不需要定义任何方法,仅是对不同的校验规则进行分组
	 * 2.此分组只校验商品名称的长度
	 */
}
4.10.3在校验规则中添加分组

(1)校验规则是在pojo中定义的

/**
	     * 校验名字在1-30个字符中间
	     * (1)message是提示较验出错所显示的信息
	     *(2)groups:是用于标识此校验属于哪个分组,groups可以定义多个分组
     */
    @Size(min=1,max=30,message="{items.name.length.error}",groups = {ValidGroup1.class})
    private String name;
4.10.4在controller方法使用指定分组的校验
/**
	 * 商品信息修改提交
	 * 1.在需要校验的pojo前添加@Validated注解
	 * 2.在需要校验的后面添加BindingResult bindingResult参数,用于接收校验出错信息
	 * 3.注意:如果需要校验多个pojo,@Validated和 BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)
	 * 4.@Validated(value= {ValidGroup1.class}):指定只使用ValidGroup1分组的校验
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/editItemsSubmit")
	public String editItemsSubmit(Model model, HttpServletRequest request,Integer id,
			@Validated(value= {ValidGroup1.class}) ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception{

5.数据回显

5.1什么是数据回显?

提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。

5.2pojo数据回显方法

(1)springmvc默认对pojo数据进行回显。

  • pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

  • 使用@ModelAttribute指定pojo回显到页面在request中的key

在这里插入图片描述

(2)@ModelAttribute还可以将方法的返回值传到页面

  • 在商品查询列表页面,通过商品类型查询商品信息。
  • 在controller中定义商品类型查询方法,最终将商品类型传到页面。
/**
	 * 商品分类
	 * 1.@ModelAttribute("itemTypes"):表示将最终方法的返回值放到request中的key
	 * @return
	 */
	@ModelAttribute("itemTypes")
	public Map<String,String> getItemTypes(){
		Map<String,String> itemTypes = new HashMap<String,String>();
		itemTypes.put("101", "数码");
		itemTypes.put("102", "母婴");
		return itemTypes;
	}

页面上可以得到itemTypes数据。

商品类型:
<select name="itemtype">
	<c:forEach items="${itemTypes}" var="itemtype">
		<option value="${itemtype.key}">${itemtype.value}</option>
	</c:forEach>
</select>

(3)使用最简单方法使用model,可以不用@ModelAttribute

在这里插入图片描述

5.3简单类型数据回显

使用最简单方法使用model。


model.addAttribute("id", id);

6.异常处理

6.1异常处理思路

(1)系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

(2)系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

在这里插入图片描述

(3)springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

6.2 自定义异常类

(1)对不同的异常类型定义异常类,继承Exception。

/**
 * 系统自定义异常类
 */
public class CustomException extends Exception {
	
	private static final long serialVersionUID = 6963818125442716459L;
	
	/**
	 * 异常信息
	 * (1)针对预期的异常,需要在程序中抛出此类的异常
	 */
	public String message;
	
	public CustomException(String message) {
		super(message);
		this.message = message;
	}

	public String getMessage() {
		return message;
	}

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

6.3全局异常处理器

6.3.1思路

(1)系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。

(2)全局异常处理器处理思路:

  • 解析出异常类型
  • 如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
  • 如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)

(3)springmvc提供一个HandlerExceptionResolver接口

/**
 * 全局异常处理器
*/
public class CustomExceptionResolver implements HandlerExceptionResolver{

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		/*
		 * 1.handler就是处理器适配器要执行Handler对象(只有method)
		 */
		
		/*
		 * 2. 解析出异常类型
		 */
		/*String message = null;
		if(ex instanceof CustomException) {
			message = ((CustomException)ex).getMessage();
		}else {
			message = "未知错误";
		}*/
		
		CustomException customException = null;
		if(ex instanceof CustomException) {
			//3. 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示
			customException = (CustomException)ex;
		}else {
			//4.如果 异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
			customException = new CustomException("未知错误");
		}
		
		String message = customException.getMessage();
		
		ModelAndView modelAndView = new ModelAndView();
		
		//5.将错误信息传到页面
		modelAndView.addObject("message",message);
		
		//6.指向到错误页面
		modelAndView.setViewName("error");
		return modelAndView;
	}

}

6.4错误页面

<%@ 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>错误提示</title>
</head>
<body>
${message}
</body>
</html>

6.5在springmvc.xml配置全局异常处理器

	<!-- 
		7.全局异常处理器
		7.1只要实现HandlerExceptionResolver接口,就是全局异常处理器,只会有一个全局异常处理器类起作用
	 -->
	<bean class="com.gdc.ssm.exception.CustomExceptionResolver"/>

6.6异常测试

(1)在controller、service、dao中任意一处需要手动抛出异常。
(2)如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常(3)说明是一个运行时异常,在错误页面只显示“未知错误”。

6.6.1在商品修改的controller方法中抛出异常

在这里插入图片描述

6.6.2在service接口中抛出异常

在这里插入图片描述

(1)如果与业务功能相关的异常,建议在service中抛出异常。

(2)与业务功能没有关系的异常,建议在controller中抛出。

上边的功能,建议在service中抛出异常。

7.上传图片

7.1需求

在修改商品页面,添加上传商品图片功能。

7.2springmvc中对多部件类型解析

(1)在 页面form中提交enctype="multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析。

(2)在springmvc.xml中配置multipart类型解析器。

	<!-- 8.文件上传 -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 8.1设置上传文件的最大尺寸为5MB -->
		<property name="maxUploadSize">
			<value>5242880</value>
		</property>
	</bean>

7.3加入上传图片的jar

上边的解析器内部使用下边的jar进行图片上传。

在这里插入图片描述

7.4创建图片虚拟 目录 存储图片

7.4.1通过图形界面配置

(1)双击tomcat服务器,点击Modules就可以打开该界面

在这里插入图片描述

(2)图片上传到服务端,还得让图片能够下载下来,在正式项目里央会建立一个图片服务器,单独有一个服务器,用于存放图片的。

(3)我们的服务器是用tomcat,在我们的tomcat当中建一个目录作为我们的服务器,创建一个图片的虚拟目录存储图片。

7.4.2也可以直接修改tomcat的配置

在conf/server.xml文件,添加虚拟目录 :

<Context docBase="E:\develop\upload\temp" path="/pic" reloadable="true" />

注意:在图片虚拟目录 中,一定将图片目录分级创建(提高i/o性能),一般我们采用按日期(年、月、日)进行分级创建。

7.5上传图片代码

7.5.1页面
<tr>
	<td>商品图片</td>
	<td>
		<c:if test="${null != items.pic}">
			<img src="/pic/${items.pic}" width=100 height=100/>
			<br/>
		</c:if>
		<input type="file"  name="items_pic"/> 
	</td>
</tr>
7.5.2controller方法

修改:商品修改controller方法:

	/**
	 * 商品信息修改提交
	 * 1.在需要校验的pojo前添加@Validated注解
	 * 2.在需要校验的后面添加BindingResult bindingResult参数,用于接收校验出错信息
	 * 3.注意:如果需要校验多个pojo,@Validated和 BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)
	 * 4.@Validated(value= {ValidGroup1.class}):指定只使用ValidGroup1分组的校验
	 * 5.@ModelAttribute("items")可以指定pojo回显到页面在request中的key
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/editItemsSubmit")
	public String editItemsSubmit(Model model, 
			HttpServletRequest request,Integer id,
			@ModelAttribute("items") @Validated(value= {ValidGroup1.class}) ItemsCustom itemsCustom,
			BindingResult bindingResult,
			MultipartFile items_pic //用来接收商品的图片
			) throws Exception{
		//1.获取校验错误信息
		if(bindingResult.hasErrors()) {
			//1.1输出错误信息
			List<ObjectError> allErrors = bindingResult.getAllErrors();
			
			for(ObjectError err : allErrors) {
				System.out.println(err.getDefaultMessage());
			}
			
			//1.2将错误信息传到页面
			model.addAttribute("allErrors",allErrors);
			
			//1.3发生错误后页面数据回显,这是最简单的数据回显方式
			model.addAttribute("items",itemsCustom);
			model.addAttribute("id", id);
			
			//1.4出错重新跳转到商品出错页面
			return "items/editItems";
		}
		
		//2.上传图片
		//2.2上传的图片的原始名称
		String originalFilename = items_pic.getOriginalFilename();
		
		if(null != items_pic && null != originalFilename && originalFilename.length()>0) {
			//2.1存储图片的物理路径
			String pic_path = "E:\\develop\\upload\\temp\\";
			
			
			//2.3新的图片名称
			String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
			//2.4新图片
			File newFile = new File(pic_path + newFileName);
			//2.5将内存中的数据写入磁盘
			items_pic.transferTo(newFile);
			//2.6将新的图片名称写到itemsCustom属性名当中
			itemsCustom.setPic(newFileName);
		}
		
		//3.调用service更新商品信息,页面需要将商品信息传到此方法
		itemsService.updateItems(id, itemsCustom);
		
		//return "forward:queryItems.action";
		return "success";
	}

在这里插入图片描述

8.json数据交互

8.1为什么要进行json数据交互

(1)json数据格式在接口调用中、html页面中较常用,json格式比较简单,解析还比较方便。
比如:webservice接口,传输json数据.

8.2springmvc进行json交互

在这里插入图片描述

(1)请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。

(2)请求key/value、输出json。此方法比较常用。

8.3环境准备

8.3.1加载json转的jar包

springmvc中使用jackson的包进行json转换(@requestBody和@responseBody使用下边的包进行json转),如下:

在这里插入图片描述

8.3.2配置json转换器

在注解适配器中加入messageConverters

<!--注解适配器 -->
	<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>

注意:如果使用<mvc:annotation-driven /> 则不用定义上边的内容。

8.4json交互测试

8.4.1输入json串,输出是json串
8.4.1.1jsp页面

使用jquery的ajax提交json串,对输出的json结果进行解析。

//1.请求的是json,输出的也是json
	function requestJson(){
		$.ajax({
			type:'post',
			url:'${pageContext.request.contextPath}/requestJson.action',
			contentType:'application/json;charset=utf-8',
			data:'{"name":"手机","price":999}',//商品信息
			success:function(data){//返回json结果
				alert(data);
			}
		});
	}
8.4.1.2controller
@Controller
public class JsonTest {
	/**
	 * 1.请求json串(商品信息),然后输出响应json(商品信息)
	 * 1.1@RequestBody:表示将请求的商品信息的json串转成itemsCustom对象
	 * 1.2@ResponseBody:表示将itemsCustom转成json输出
	 * @param itemsCustom
	 * @return
	 */
	@RequestMapping("/requestJson")
	public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom) {
		return itemsCustom;
	}
}

8.4.1.3测试结果

在这里插入图片描述

8.4.2输入key/value,输出是json串
8.4.2.1jsp页面

使用jquery的ajax提交key/value串,对输出的json结果进行解析。

	//2.请求的是key/value,输出的是json
	function responseJson(){
		$.ajax({
			type:'post',
			url:'${pageContext.request.contextPath}/responseJson.action',
			//2.1请求的是key/value这里不需要指定contentType,因为默认就是key/value类型
			//contentType:'application/json;charset=UTF-8',
			data:'name=abc&price=999',//商品信息
			success:function(data){//返回json结果
				alert(data);
			}
		});
	}
8.4.2.2controller
	@RequestMapping("/responseJson")
	public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom) {
		return itemsCustom;
	}
8.4.2.3测试

在这里插入图片描述

9.RESTful支持

9.1什么是RESTful

(1)RESTful架构,就是目前最流行的一种互联网软件架构。

(2)它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

(3)RESTful(即Representational State Transfer的缩写,意为表现层的状态转换)其实是一个开发理念,是对http的很好的诠释。

(4)HTTP就是用在表现层,我们写的BS架构的确是在表现层用的最多,HTTP定义这个协议的初终是什么呢?就是互联网的任何东西(文本、图片、歌曲、一种服务)都可以通过HTTP来访问。

(5)HTTP访问的资源叫什么呢?
叫资源。

(6)访问的资源最终是要在表现层展示,但是访问的资源除了查看资源,我还会怎么办呢?还有可能会修改、删除资源,这就是HTTP设置的初终,互联网中任何的东西都是资源。

9.1.1对url进行规范,写RESTful格式的url

(1)非REST的url:http://…/queryItems.action?id=001&type=T01

(2)REST的url风格:http://…/items/001

(3)特点:url简洁,将参数通过url传到服务端

9.1.2http的方法规范

(1)不管是删除、添加、更新。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加…

(2)后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。

9.1.3对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type。

9.2REST的例子

9.2.1需求

查询商品信息,返回json数据。

9.2.2controller

(1)定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller .

(2)输出json使用@ResponseBody将java对象输出json。

(3)多参数绑定

在这里插入图片描述

	/**
	 * 查询商品信息,输出json
	 * 1./itemsView/{id}中的id表示将这个位置的参数要传到@PathVariable("id")指定名称中。
	 */
	@RequestMapping("/itemsView/{id}")
	public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id) throws Exception{
		//1.1.调用service查询商品信息
		ItemsCustom itemsCustom = itemsService.findItemsById(id);
		return itemsCustom;
	}
1@RequestMapping(value="/ itemsView/{id}"){×××}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{×××}中的×××变量。

(2@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。

(3)如果RequestMapping中表示为"/itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称。
9.2.3REST方法的前端控制器配置

在web.xml配置:

  <!-- springmvc前端控制器,rest配置 -->
  <servlet>
  	<servlet-name>spring_rest</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<init-param>
	  	<param-name>contextConfigLocation</param-name>
	  	<param-value>classpath:spring/springmvc.xml</param-value>
  	</init-param>
  </servlet>

  <servlet-mapping>
  	<servlet-name>spring_rest</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>

9.3对静态资源的解析

(1)配置前端控制器的url-parttern中指定/,对静态资源的解析出现问题:

在这里插入图片描述

(2)需要在springmvc.xml中添加静态资源解析方法。

	<!-- 
		9.静态资源的解析
		9.1包括:js、css、img...
		9.2location访问js打头的,
		9.3mapping要映射到js里面的所有文件
	 -->
	 <mvc:resources location="/js/" mapping="/js/**"/>
	 <mvc:resources location="/img/" mapping="/img/**"/>

10.拦截器

10.1拦截定义

定义拦截器,实现HandlerInterceptor接口。接口中提供三个方法。

package com.gdc.ssm.intercepter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 测试拦截器1
 */
public class HandlerIntercepter1 implements HandlerInterceptor{

	/**
	 * 1.进入Handler方法之彰执行
	 * 1.1用于身份认证、身份授权
	 * 1.2比如身份认证,如果认证不通过,表示当前用户没有登录,需要此方法拦截不再向下执行
	 * 
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		/*
		 * 1.2.1return false表示拦截住,不向下执行
		 * 1.2.2return true表示放行
		 */
		return false;
	}

	/**
	 * 2.进入Handler方法之后,返回ModelAndView之前执行
	 * 2.1应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里面统一的指定视图
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
	}

	/**
	 * 3.执行Handler完成执行此方法
	 * 3.1应用场景:统一异常处理,统一的日志处理
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		
	}

}

10.2拦截器配置

10.2.1针对HandlerMapping配置

(1)springmvc拦截器针对HandlerMapping(处理器映射器)进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该 HandlerMapping映射成功的handler最终使用该拦截器。

<bean
	class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="handlerInterceptor1"/>
			<ref bean="handlerInterceptor2"/>
		</list>
	</property>
</bean>
	<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
	<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

一般不推荐使用。

10.2.2类似全局的拦截器

(1)springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。

	<!--10.拦截器 -->
	<mvc:interceptors>
		<!--10.1多个拦截器,顺序执行 -->
		<mvc:interceptor>
			<!-- 10.1.1表示拦截所有url包括子url路径 -->
			<mvc:mapping path="/**"/>
			<bean class="com.gdc.ssm.intercepter.HandlerIntercepter1"/>
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.gdc.ssm.intercepter.HandlerIntercepter2"/>
		</mvc:interceptor>
	</mvc:interceptors>

10.3拦截测试

10.3.1测试需求

测试多个拦截器各个方法执行时机。

10.3.2编写两个拦截

在这里插入图片描述

10.3.3两个拦截器都放行

执行结果:

HandlerIntercepter1 ... preHandle
HandlerIntercepter2 ... preHandle
HandlerIntercepter2 ... postHandle
HandlerIntercepter1 ... postHandle
HandlerIntercepter2 ... afterCompletion
HandlerIntercepter1 ... afterCompletion

总结:

(1)preHandle方法按顺序执行,

(2)postHandle和afterCompletion按拦截器配置的逆向顺序执行。

10.3.4拦截器1放行,拦截器2不放行

执行结果:

HandlerIntercepter1 ... preHandle
HandlerIntercepter2 ... preHandle
HandlerIntercepter1 ... afterCompletion

总结:

(1)拦截器1放行,拦截器2 preHandle才会执行。

(2)拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。

(3)只要有一个拦截器不放行,postHandle不会执行。

10.3.1拦截器1不放行,拦截器2不放行
	HandlerIntercepter1 ... preHandle

总结:

(1)拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。

(2)拦截器1 preHandle不放行,拦截器2不执行。

10.3.2小结

(1)根据测试结果,对拦截器应用。

(2)比如:统一日志处理拦截器,需要该 拦截器preHandle一定要放行,且将它放在拦截器链接中第一个位置。

(3)比如:登陆认证拦截器,放在拦截器链接中第一个位置。权限校验拦截器,放在登陆认证拦截器之后。(因为登陆通过后才校验权限)

10.4拦截器应用(实现登陆认证)

10.4.1需求

(1)用户请求url
(2)拦截器进行拦截校验

  • 如果请求的url是公开地址(无需登陆即可访问的url),让放行
  • 如果用户session 不存在跳转到登陆页面
  • 如果用户session存在放行,继续操作。
10.4.2登陆controller方法
package com.gdc.ssm.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
	//1.登录
	@RequestMapping("/login")
	public String login(HttpSession session,String username,String password) throws Exception {
		//1.1调用service进行用户身份认证
		
		//1.2在session中保存用户身份的信息
		session.setAttribute("username", username);
		
		//1.3重定向到商品的列表,跳转到商品查询页面
		return "redirect:/items/queryItems.action";
	}
	
	//2.退出
	public String logout(HttpSession session) throws Exception{
		
		//2.1清除session
		session.invalidate();
		
		//2.2重定向到商品的列表,跳转到商品查询页面
		return "redirect:/items/queryItems.action";
	}
	
}

10.4.3登陆认证拦截实现
10.4.3.1代码实现
/**
 * 1.登录认证拦截器
 */
public class LoginIntercepter implements HandlerInterceptor{

	/**
	 * 1.进入Handler方法之彰执行
	 * 1.1用于身份认证、身份授权
	 * 1.2比如身份认证,如果认证不通过,表示当前用户没有登录,需要此方法拦截不再向下执行
	 * 
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		//1.获取请求的url
		String url = request.getRequestURI();
		
		//2.判断url是否是公开地址(实际使用时将公开地址配置在配置文件中),这里公开地址就是登录提交的地址
		if(url.indexOf("login.action") >= 0) {
			//2.1如果要进行登录提交,旅行
			return true;
		}
		
		//3.判断session
		HttpSession session = request.getSession();
		//3.1从session中取出用户身份信息
		String username = (String) session.getAttribute("username");
		if(null != username) {
			//3.1.1身份信息存在,放行
			return true;
		}
		
		//4.执行到这里,表示前面都没有放行,表示用户身份需要认证,需要跳转到登录页面
		request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
	
		return false;
	}
10.4.3.2拦截器配置
	<!--10.拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.gdc.ssm.intercepter.LoginIntercepter"/>
		</mvc:interceptor>
		<!--10.1多个拦截器,顺序执行 -->
		<mvc:interceptor>
			<!-- 10.1.1表示拦截所有url包括子url路径 -->
			<mvc:mapping path="/**"/>
			<bean class="com.gdc.ssm.intercepter.HandlerIntercepter1"/>
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.gdc.ssm.intercepter.HandlerIntercepter2"/>
		</mvc:interceptor>
	</mvc:interceptors>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值