16 springmvc校验
16.1 校验理解
项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。
- 服务端校验:
- 控制层controller:校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
- 业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
- 持久层dao:一般是不校验的。
16.2 springmvc校验需求
springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。
- 校验思路:
- 页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
- 具体需求:
- 商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。
16.3 环境准备
hibernate的校验框架validation所需要jar包:
16.4 配置校验器
在springmvc.xml配置文件中配置:
<!-- 校验器 -->
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<!-- 校验器-->
<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
<!--
指定校验使用的资源文件,在文件中配置校验的错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties
-->
<property name="validationMessageSource" ref="messageSource" />
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- 资源文件名-->
<property name="basenames">
<list>
<value>classpath:CustomValidationMessages</value>
</list>
</property>
<!-- 资源文件编码格式 -->
<property name="fileEncodings" value="utf-8" />
<!-- 对资源文件内容缓存时间,单位秒 -->
<property name="cacheSeconds" value="120" />
</bean>
之后在工程的源文件夹config下创建CustomValidationMessages.properties配置文件,用来配置校验错误信息。
16.5 校验器注入到处理器适配器
<mvc:annotation-driven conversion-service="conversionService"
validator="validator"></mvc:annotation-driven>
16.6 在pojo中添加校验规则
在ItemsCustom.java中添加校验规则:
public class Items {
private Integer id;
//校验名称在1-30个字符之内
@Size(min=1,max=30,message="{items.name.length.error}")
private String name;
//商品生产日期不能为空
@NotNull(message="{items.createtime.isNull}")
private Date ceatime;
16.7 CustomValidationMessages.properties
在CustomValidationMessages.properties配置校验错误信息:
#添加校验错误提示信息
items.name.length.error=请输入1-30个字符的商品名称
items.createtime.isNull=请输入商品生产日期
16.8 捕获校验错误信息(@Validated与BindingResult)
//商品修改提交
//在需要校验的pojo前边加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
//注意:@Validatedh和BindingResult bindingResult是配对出现,并且在形参中出现的顺序是固定的(一前一后)
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(HttpServletRequest request,Integer id,
@Validated ItemsCustom itemsCustom,BindingResult bindingResult) throws Exception {
//校验错误信息
if(bindingResult.hasErrors()) {
//输出错误信息
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
}
itemsService.update(id, itemsCustom);
//重定向到商品的查询列表
return "redirect:queryItems.action";
}
16.9 在页面显示校验错误信息
在controller中将错误信息传到页面即可。
//获取校验错误信息
if(bindingResult.hasErrors()){
//输出错误信息
List<ObjectError> allErrors=bindingResult.getAllErrors();
for(ObjectError objectError:allErrors){
//输出错误信息
System.out.println(objectError.getDefaultMessage());
}
//将错误传到页面
model.addAttribute("allErrors",allErrors);
//出错之后要跳转的页面
return "items/editItems";
}
页面显示错误信息:
在商品编辑页面editItems.jsp中显示错误信息:
<!-- 显示错误信息 -->
<c:if test="${allErrors!=null}">
<c:forEach items="${allErrors}" var="error">
<font color="red">${error.defaultMessage}</font><br/>
</c:forEach>
</c:if>
16.10 分组校验
16.10.1 需求
上一次我们学习了validation校验的配置和使用方法,我们不难发现会有一些问题:
在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。
解决方法:
定义多个校验分组(其实是一个java接口),分组中定义有哪些规则
每个controller方法使用不同的校验分组
16.10.2 校验分组
我们在工程中新建一个包cn.edu.hpu.ssm.controller.validation,并在包中创建两个校验分组接口;
-
其中ValidGroup1.java:
public interface ValidGroup1 { //此接口不需要定义任何方法,仅是对不同校验规则进行分组 //此分组只校验商品名称长度 }
-
ValidGroup2.java:
public interface ValidGroup2 { //接口中不需要定义任何方法,仅是对不同的校验规则进行分组 //其它 }
16.10.3 在校验规则中添加分组
public class Items {
private Integer id;
//校验名称在1-30个字符之内
//groups:用来标识此校验属于哪个分组,groups可以定义多个分组
@Size(min=1,max=30,message="{items.name.length.error}",groups={ValidGroup1.class})
private String name;
16.10.4 在controller方法使用指定分组的校验
//商品信息修改提交
//在需要校验的pojo前边加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
//注意:@Validatedh和BindingResult bindingResult是配对出现,并且在形参中出现的顺序是固定的(一前一后)
//value={ValidGroup1.class}指定使用ValidGroup1分组的校验
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model,
HttpServletRequest request,Integer id,
@Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,
BindingResult bindingResult)throws Exception{
//代码省略
}
17 数据回显
17.1 什么是数据回显
提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。
17.2 pojo数据回显方法
17.2.1 springmvc默认对pojo数据进行回显。
pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)
说白了就是items类
items类在网页中取name的写法是: i t e m s . n a m e , 也 就 是 r e q u e s t 域 的 k e y 是 i t e m s , 也 就 是 当 初 c o n t r o l l e r 方 法 中 包 装 进 去 的 v a l u e 的 k e y ( m o d e l . a d d A t t r i b u t e ( " i t e m s " , i t e m s ) ; ) , 如 果 在 网 页 中 改 为 {items.name},也就是request域的key是items,也就是当初controller方法中包装进去的value的key(model.addAttribute("items",items);),如果在网页中改为 items.name,也就是request域的key是items,也就是当初controller方法中包装进去的value的key(model.addAttribute("items",items);),如果在网页中改为{items22.name}就取不出来值了,因为key不对了,当然也就无法使用springmvc的默认回显方法了。
为了防止这种错误或者是为了让回显数据配置更加轻松,我们可以使用@ModelAttribute指定pojo回显到页面在request中的key
如:(现在我们把当初controller方法中包装进去的value的key改为items22(model.addAttribute(“items22”,items)😉,此时如果不用@ModelAttribute注解,springmvc默认的回显机制会默认从request域中寻找key为items(pojo类首字母小写)的value,结果就是找不到。已经经过验证)
//商品信息修改提交
//在需要校验的pojo前边加@Validated,在需要校验的pojo后边添加BindingResult bindingResult接收校验出错信息
//注意:@Validatedh和BindingResult bindingResult是配对出现,并且在形参中出现的顺序是固定的(一前一后)
//value={ValidGroup1.class}指定使用ValidGroup1分组的校验
//@ModelAttribute可以指定pojo回显到页面在request中的key
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model,
HttpServletRequest request,
Integer id,
@ModelAttribute("items22") @Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,
BindingResult bindingResult)throws Exception{
//具体修改方法略
}
修改页面:
<%@ 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>
<!-- 显示错误信息 -->
<c:if test="${allErrors!=null}">
<c:forEach items="${allErrors}" var="error">
<font color="red">${error.defaultMessage}</font><br/>
</c:forEach>
</c:if>
<form id="itemForm" action="${pageContext.request.contextPath }/items/editItemsSubmit.action" method="post" >
<input type="hidden" name="id" value="${items22.id }"/>
修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${items22.name }"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${items22.price }"/></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime" value="<fmt:formatDate value="${items22.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">${items22.detail }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
17.2.2 @ModelAttribute还可以将方法的返回值传到页面
在商品查询列表页面,通过商品类型查询商品信息。
在controller中定义商品类型查询方法,最终将商品类型传到页面。
//商品分类
//itemTypes表示最终将方法返回值放在request中的key
@ModelAttribute("itemtypes")
public Map<String,String> getItemTypes(){
//先使用静态数据测试
Map<String,String> itemTypes=new HashMap<String,String>();
itemTypes.put("101", "数码");
itemTypes.put("102", "母婴");
return itemTypes;
}
页面上可以得到itemTypes数据(不需要URL请求)。
商品类型:
<select name="itemtype">
<c:forEach items="${itemtypes}" var="itemtype">
<option value="${itemtype.key}">${itemtype.value }</option>
</c:forEach>
</select>
17.2.3 使用最简单方法使用model,可以不用@ModelAttribute
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model,HttpServletRequest request,Integer id,
@Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,BindingResult bindingResult)
throws Exception{
//获取校验错误信息
if(bindingResult.hasErrors()){
//输出错误信息
List<ObjectError> allErrors=bindingResult.getAllErrors();
for(ObjectError objectError:allErrors){
//输出错误信息
System.out.println(objectError.getDefaultMessage());
}
//将错误传到页面
model.addAttribute("allErrors",allErrors);
//可以直接使用model将提交pojo回显到页面
model.addAttribute("items22",itemsCustom);
//出错之后要跳转的页面
return "items/editItems";
}
//调用service更新商品信息,页面需要将商品信息传到此方法
itemsService.updateItems(id, itemsCustom);
//重定向到商品的查询列表
return "redirect:queryItems.action";
}
17.3 简单类型数据回显
使用最简单方法使用model。
还是使用model或者request去封装跳转即可
model.addAttribute("id",id);
18 异常处理
18.1 异常处理思路
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
18.2 自定义异常类
对不同的异常类型定义异常类,继承Exception。
public class CustomException extends Exception {
private String message;
public CustomException(String message) {
super(message);
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
18.3 全局异常处理器
-
思路:
- 系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。
-
全局异常处理器处理思路:
- 解析出异常类型。
- 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示。
- 如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)。
-
springmvc提供一个HandlerExceptionResolver接口
public class CustomExceptionResolver implements HandlerExceptionResolver { //系统抛出异常 @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //handler就是处理器适配器要执行的Handler对象(只有method) //解析出异常类型。 //如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示。 CustomException customException = null; if(ex instanceof CustomException) { customException = (CustomException)ex; } else { //如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)。 customException = new CustomException("未知错误"); } String message = customException.getMessage(); ModelAndView modelAndView = new ModelAndView(); //将错误信息传送到页面 modelAndView.addObject("message", message); //指向到错误界面 modelAndView.setViewName("error"); return modelAndView; } }
18.4 错误页面
在WEB-INF/jsp文件夹下创建error.jsp页面,内容为:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>error</title>
</head>
<body>
${message } <br>
</body>
</html>
18.5 在springmvc.xml配置全局异常处理器
<!--
全局异常处理器
只要你实现了HandlerExceptionResolver接口,这个
类就是一个全局异常处理器
-->
<bean class="cn.itcast.ssm.exception.CustomExceptionResolver" />
18.6 异常测试
在controller、service、dao中任意一处需要手动抛出异常。
如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。
在商品修改的controller方法中抛出异常。
@RequestMapping(value="/editItems",method={RequestMethod.POST,RequestMethod.GET})
//@RequestParam里面指定reuqest传入参数和形参进行绑定。
//通过required属性指定参数是否必须要传入
//通过defaultValue可以设置默认值,如果id参数没有传入,将默认值和形参绑定
public String editItems(Model model,
@RequestParam(value="id",required=true,defaultValue="") Integer items_id)throws Exception{
//调用service根据商品id查询商品信息
ItemsCustom itemsCustom=itemsService.findItemsById(items_id);
//判断商品是否为空,根据id没有查到商品,提示用户商品信息并不存在
if(itemsCustom==null){
throw new CustomException("商品的修改信息不存在!");
}
//通过形参中的model将model数据传到页面
//相当于modelAndView.addObject方法
model.addAttribute("items22",itemsCustom);
return "items/editItems";
}
其中上面用到的service方法:
@Override
public ItemsCustom findItemsById(Integer id) throws Exception {
Items items=itemsMapper.selectByPrimaryKey(id);
//中间对商品信息进行业务处理
//...
//最终返回ItemsCustom
ItemsCustom itemsCustom=null;
//将item的内容拷贝到itemsCustom
if(items!=null){
itemsCustom=new ItemsCustom();
BeanUtils.copyProperties(items, itemsCustom);
}
return itemsCustom;
}
同样在Service中也可以抛出异常
如果与业务功能相关的异常,建议在service中抛出异常。
与业务功能没有关系的异常,建议在controller中抛出。
上边的功能,建议在service中抛出异常。
19 上传图片
19.1 需求
在修改商品页面,添加上传商品图片功能。
19.2 springmvc中对多部件类型解析
在页面form中提交enctype="multipart/form-data"
的数据时,需要springmvc对multipart类型的数据进行解析。
在springmvc.xml中配置multipart类型解析器。
<!-- 文件上传 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
注:在电商企业开发的时候,是需要单独建立图片服务器的,这里我们仅仅在tomcat服务器的本工厂下使用一个文件夹来存放图片
19.3 加入上传图片的jar
上边的解析内部使用下边的jar进行图片上传。
19.4 创建图片虚拟 目录 存储图片
- 通过图形界面配置:
-
也可以直接修改tomcat的配置:
在conf/server.xml文件,添加虚拟目录(注意是在最下方的Host标签对中添加):<Context docBase="D:\JAVA\temp" path="/pic" reloadable="false"/>
测试:我们在D:\JAVA\temp下放置一个名为yuanchuanggongzuoshi.png的图片,重启服务器后直接访问http://localhost:8080/pic/yuanchuanggongzuoshi.png路径就可以直接看到图片,所以我们的配置是成功的。(以后我们上传数据往物理路径D:\JAVA\temp下去上传,查看图片往/pic下去查)
注意:在图片虚拟目录 中,一定将图片目录分级创建(提高i/o性能),一般我们采用按日期(年、月、日)进行分级创建。
19.5 上传图片代码
19.5.1 页面
<tr>
<td>商品图片</td>
<td>
<c:if test="${items22.pic !=null}">
<img src="/pic/${items22.pic }" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="items_pic"/>
</td>
</tr>
注意:"/pic"路径是绝对路径,不要加${pageContext.request.contextPath }/…
19.5.2 controller方法
修改:商品修改controller方法:
//商品修改提交
//@ModelAttribute可以指定pojo回显到页面在request中的key
@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(Model model,
HttpServletRequest request,
Integer id,
@Validated(value={ValidGroup1.class}) ItemsCustom itemsCustom,
BindingResult bindingResult,
MultipartFile items_pic//接收商品图片
) throws Exception {
//校验错误信息
if(bindingResult.hasErrors()) {
//输出错误信息
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
System.out.println(objectError.getDefaultMessage());
}
//将错误传到页面
model.addAttribute("allErrors",allErrors);
//可以直接使用model将提交pojo回显到页面
model.addAttribute("items22", itemsCustom);
//出错之后要跳转的页面
return "items/editItems";
}
//上传图片原始名称
String originalFileName = items_pic.getOriginalFilename();
//上传图片
if(items_pic != null && originalFileName != "" && originalFileName.length() > 0) {
//存储图片的物理路径
String pic_path = "D:\\JAVA\\temp\\";
//新图片名称
String newFileName = UUID.randomUUID()
+originalFileName.substring(originalFileName.lastIndexOf("."));
File newfile = new File(pic_path+newFileName);
//将内存中的数据写入磁盘
items_pic.transferTo(newfile);
//将新的图片名写到itemsCustom
itemsCustom.setPic(newFileName);
}
itemsService.update(id, itemsCustom);
//重定向到商品的查询列表
return "redirect:queryItems.action";
}
19.6 缺陷
问题:
编辑时如果不修改图片,直接提交的时候图片就没了。原因是,图片所在的type=file的input标签中没有value,当提交form表单的时候会将空值提交上去,在数据库存储阶段,如果你没有判断items_pic的空,空的图片路径,就会覆盖数据库原有的图片路径。
解决这个问题的方法就是,在存储图片相关信息时,判断前端传来的图片值是否为空,如果为空则不要update该字段。
20 json数据交互
20.1 为什么要进行json数据交互
json数据格式在接口调用中、html页面中较常用,json格式比较简单,解析还比较方便。
比如:webservice接口,传输json数据.
20.2 springmvc进行json交互
- 请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。
- 请求key/value、输出json。此方法比较常用。
20.3 环境准备
20.3.1 加载json转的jar包
-
springmvc中使用jackson的包进行json转换(@requestBody和@responseBody使用下边的包进行json转),如下:
jackson-core-asl-1.9.11.jar
jackson-mapper-asl-1.9.11.jar -
@RequestBody作用:
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。 -
本例子应用:
@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象 -
@ResponseBody作用:
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如: json,xml等,通过Response响应给客户端 -
本例子应用:
@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
20.3.2 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 /> 则不用定义上边的内容。
20.4 json交互测试
20.4.1 输入json串,输出是json串
20.4.1.1 jsp页面
使用jquery的ajax提交json串,对输出的json结果进行解析。
使用jduery别忘记引入jquery-1.4.4.min.js
<%@ 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>json交互测试</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
//请求为json,响应为json
function requestJson(){
$.ajax({
type:'post',
url:'${pageContext.request.contextPath }/requestJson.action',
contentType:'application/json;charset=utf-8',
//数据格式是json串,商品信息
data:'{"name":"手机","price":"100"}',
success:function(data){//返回json结果
alert(data);
}
});
}
</script>
</head>
<body>
<input type="button" οnclick="requestJson()" value="请求的是json,输出的是json"/>
</body>
</html>
20.4.1.2 controller
//json交互测试
@Controller
public class JsonText {
//请求json(商品信息),输出json(商品信息)
//@RequestBody将请求的商品信息的json串转成itemsCustom对象
//@ResponseBody将itemsCustom转成json格式输出
@RequestMapping("/requestJson")
public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){
//@ResponseBody将itemsCustom转成json格式输出
return itemsCustom;
}
}
20.4.1.3 测试结果
20.4.2 输入key/value,输出是json串
20.4.2.1 jsp页面
使用jquery的ajax提交key/value串,对输出的json结果进行解析。
<%@ 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>json交互测试</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
//请求为key/value,响应为json
function responseJson(){
$.ajax({
type:'post',
url:'${pageContext.request.contextPath }/responseJson.action',
//请求的是key/value,这里不需要指定contentType,因为默认就是key/value类型
//contentType:'application/json;charset=utf-8',
//数据格式是json串,商品信息
data:'{"name":"手机","price":"100"}',
success:function(data){//返回json结果
alert(data);
}
});
}
</script>
</head>
<body>
<input type="button" οnclick="responseJson()" value="请求的是key/value,输出的是json"/>
</body>
</html>
20.4.2.2 controller
//json交互测试
@Controller
public class JsonText {
//请求key/value(商品信息),输出json(商品信息)
@RequestMapping("/responseJson")
public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){
//@ResponseBody将itemsCustom转成json格式输出
System.out.println("前台传过来得商品名:"+itemsCustom.getName());
return itemsCustom;
}
}
20.4.2.3 测试
后台控制台输出了"前台传过来的商品名:手机",且查看http数据可以看到json数据的反馈。
21 springmvc对RESTful支持
21.1 什么是RESTful
RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
RESTful-表现层状态转换(即Representational State Transfer的缩写)其实是一个开发理念,是对http的很好的诠释。
(1)对url进行规范,写RESTful格式的url
非REST的url:http://…/queryItems.action?id=001&type=T01
REST的url风格:http://…/items/001
特点:url简洁,将参数通过url传到服务端
(2)http的方法规范
不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加。。。
后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加。
(3)对http的contentType规范
请求时指定contentType,要json数据,设置成json格式的type。。
21.2 REST的例子
21.2.1 需求
查询商品信息,返回json数据。
21.2.2 controller
定义方法,进行url映射使用REST风格的url,将查询商品信息的id传入controller .
输出json使用@ResponseBody将java对象输出json。
//查询商品信息,输出json
///itemsView/{id}里面的{id}表示将这个位置的参数传到@PathVariable指定名称中
@RequestMapping("/itemsView/{id}")
public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id)throws Exception{
//调用service查询商品信息
ItemsCustom itemsCustom=itemsService.findItemsById(id);
return itemsCustom;
}
@RequestMapping(value="/ itemsView/{id}")
:{xxx}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{xxx}中的xxx变量。
@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。
如果RequestMapping中表示为"/ itemsView /{id}",id和形参名称一致,@PathVariable不用指定名称。
21.2.3 REST方法的前端控制器配置
在web.xml配置:
<!-- SpringMvc前端控制器,rest配置 -->
<servlet>
<servlet-name>springmvc_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>springmvc_rest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
21.3 对静态资源的解析
配置前端控制器的url-parttern中指定/,对静态资源的解析出现问题:
在springmvc.xml中添加静态资源解析方法。
<!-- 静态资源的解析
包括:js/css/img... -->
<resources location="/js/" mapping="/js/**" />
<resources location="/img/" mapping="/img/**" />
<resources location="/css/" mapping="/css/**" />