springmvc教程(4)
springmvc教程系列
springmvc史上最好教程(2)
springmvc史上最好教程(1)springmvc史上最好教程(3)
2注解開(kāi)發(fā)-高級(jí)
2.1上傳圖片
2.1.1配置虛擬目錄
2.1.2配置解析器
<!-- 文件上傳 --><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 設(shè)置上傳文件的最大尺寸為5MB --><property name="maxUploadSize"><value>5242880</value></property></bean>2.1.3jar包
CommonsMultipartResolver解析器依賴commons-fileupload和commons-io,加入如下jar包:
2.1.4單個(gè)圖片上傳
1、controller:
//商品修改提交@RequestMapping("/editItemSubmit")public String editItemSubmit(Items items, MultipartFile pictureFile)throws Exception{//原始文件名稱String pictureFile_name = pictureFile.getOriginalFilename();//新文件名稱String newFileName = UUID.randomUUID().toString()+pictureFile_name.substring(pictureFile_name.lastIndexOf("."));//上傳圖片F(xiàn)ile uploadPic = new java.io.File("F:/develop/upload/temp/"+newFileName);if(!uploadPic.exists()){uploadPic.mkdirs();}//向磁盤寫文件pictureFile.transferTo(uploadPic);.....2、 頁(yè)面:
form添加enctype="multipart/form-data":
<form id="itemForm"action="${pageContext.request.contextPath }/item/editItemSubmit.action"method="post" enctype="multipart/form-data"><input type="hidden" name="pic" value="${item.pic }" />file的name與controller形參一致:
<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>2.2Validation(了解)
b/s系統(tǒng)中對(duì)http請(qǐng)求數(shù)據(jù)的校驗(yàn)多數(shù)在客戶端進(jìn)行,這也是出于簡(jiǎn)單及用戶體驗(yàn)性上考慮,但是在一些安全性要求高的系統(tǒng)中服務(wù)端校驗(yàn)是不可缺少的,本節(jié)主要學(xué)習(xí)springmvc實(shí)現(xiàn)控制層添加校驗(yàn)。
Spring3支持JSR-303驗(yàn)證框架,JSR-303是JAVA EE 6中的一項(xiàng)子規(guī)范,叫做Bean Validation,官方參考實(shí)現(xiàn)是Hibernate Validator(與Hibernate ORM沒(méi)有關(guān)系),JSR 303用于對(duì)Java Bean中的字段的值進(jìn)行驗(yàn)證。
2.2.1需求
對(duì)商品信息進(jìn)行校驗(yàn),是否必須,輸入數(shù)據(jù)合法性。
2.2.2加入jar包
2.2.3配置validator
<!-- 校驗(yàn)錯(cuò)誤信息配置文件 --><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><bean id="validator"class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"><property name="providerClass" value="org.hibernate.validator.HibernateValidator" /><!-- 如果不指定則默認(rèn)使用classpath下的ValidationMessages.properties --><property name="validationMessageSource" ref="messageSource" /></bean>2.2.4將validator加到處理器適配器
配置方式1:
<!-- 自定義webBinder --><bean id="customBinder"class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"><property name="validator" ref="validator" /></bean><!-- 注解適配器 --><beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="webBindingInitializer" ref="customBinder"></property></bean>
配置方式2:
<mvc:annotation-driven validator="validator"> </mvc:annotation-driven>2.2.5添加驗(yàn)證規(guī)則
public class Items {private Integer id;@Size(min=1,max=30,message="{item.name.length.illigel}")private String name;@NotEmpty(message="{pic.is.null}")private String pic;2.2.6錯(cuò)誤消息文件CustomValidationMessages
item.name.length.illigel=商品在名稱在1到3個(gè)字符之間
pic.is.null=請(qǐng)上傳圖片
如果在eclipse中編輯properties文件無(wú)法看到中文則參考“Eclipse開(kāi)發(fā)環(huán)境配置-indigo.docx”添加propedit插件。
2.2.7捕獲錯(cuò)誤
修改Controller方法:
// 商品修改提交@RequestMapping("/editItemSubmit")public String editItemSubmit(@Validated @ModelAttribute("item") Items items,BindingResult result,@RequestParam("pictureFile") MultipartFile[] pictureFile,Model model)throws Exception {//如果存在校驗(yàn)錯(cuò)誤則轉(zhuǎn)到商品修改頁(yè)面if (result.hasErrors()) {List<ObjectError> errors = result.getAllErrors();for(ObjectError objectError:errors){System.out.println(objectError.getCode());System.out.println(objectError.getDefaultMessage());}return "item/editItem";}注意:添加@Validated表示在對(duì)items參數(shù)綁定時(shí)進(jìn)行校驗(yàn),校驗(yàn)信息寫入BindingResult中,在要校驗(yàn)的pojo后邊添加BingdingResult, 一個(gè)BindingResult對(duì)應(yīng)一個(gè)pojo,且BingdingResult放在pojo的后邊。
商品修改頁(yè)面:
頁(yè)頭:
<%@ 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" <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>在需要顯示錯(cuò)誤信息地方:
<spring:hasBindErrors name="item"><c:forEach items="${errors.allErrors}" var="error">${error.defaultMessage }<br/></c:forEach></spring:hasBindErrors>說(shuō)明:
<spring:hasBindErrors name="item">表示如果item參數(shù)綁定校驗(yàn)錯(cuò)誤下邊顯示錯(cuò)誤信息。
2.2.8分組校驗(yàn)
如果兩處校驗(yàn)使用同一個(gè)Items類則可以設(shè)定校驗(yàn)分組。
定義分組:
分組就是一個(gè)標(biāo)識(shí),這里定義一個(gè)接口:
public interface ValidGroup1 {}public interface ValidGroup2 {}指定分組校驗(yàn):
public class Items {private Integer id;//這里指定分組ValidGroup1,此@Size校驗(yàn)只適用ValidGroup1校驗(yàn)@Size(min=1,max=30,message="{item.name.length.illigel}",groups={ValidGroup1.class})private String name;// 商品修改提交@RequestMapping("/editItemSubmit")public String editItemSubmit(@Validated(value={ValidGroup1.class}) @ModelAttribute("item") Items items,BindingResult result,@RequestParam("pictureFile") MultipartFile[] pictureFile,Model model)throws Exception {在@Validated中添加value={ValidGroup1.class}表示商品修改使用了ValidGroup1分組校驗(yàn)規(guī)則,也可以指定多個(gè)分組中間用逗號(hào)分隔,
@Validated(value={ValidGroup1.class,ValidGroup2.class})
2.3異常處理器
springmvc在處理請(qǐng)求過(guò)程中出現(xiàn)異常信息交由異常處理器進(jìn)行處理,自定義異常處理器可以實(shí)現(xiàn)一個(gè)系統(tǒng)的異常處理邏輯。
2.3.1異常處理思路
系統(tǒng)中異常包括兩類:預(yù)期異常和運(yùn)行時(shí)異常RuntimeException,前者通過(guò)捕獲異常從而獲取異常信息,后者主要通過(guò)規(guī)范代碼開(kāi)發(fā)、測(cè)試通過(guò)手段減少運(yùn)行時(shí)異常的發(fā)生。
系統(tǒng)的dao、service、controller出現(xiàn)都通過(guò)throws Exception向上拋出,最后由springmvc前端控制器交由異常處理器進(jìn)行異常處理,如下圖:
2.3.2自定義異常類
為了區(qū)別不同的異常通常根據(jù)異常類型自定義異常類,這里我們創(chuàng)建一個(gè)自定義系統(tǒng)異常,如果controller、service、dao拋出此類異常說(shuō)明是系統(tǒng)預(yù)期處理的異常信息。
public class CustomException extends Exception {/** serialVersionUID*/private static final long serialVersionUID = -5212079010855161498L;public CustomException(String message){super(message);this.message = message;}//異常信息private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}2.3.3自定義異常處理器
public class CustomExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) {ex.printStackTrace();CustomException customException = null;//如果拋出的是系統(tǒng)自定義異常則直接轉(zhuǎn)換if(ex instanceof CustomException){customException = (CustomException)ex;}else{//如果拋出的不是系統(tǒng)自定義異常則重新構(gòu)造一個(gè)未知錯(cuò)誤異常。customException = new CustomException("未知錯(cuò)誤,請(qǐng)與系統(tǒng)管理 員聯(lián)系!");}ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("message", customException.getMessage());modelAndView.setViewName("error");return modelAndView;}}2.3.4錯(cuò)誤頁(yè)面
<%@ 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>錯(cuò)誤頁(yè)面</title></head><body>您的操作出現(xiàn)錯(cuò)誤如下:<br/>${message }</body></html>2.3.5異常處理器配置
在springmvc.xml中添加:
<!-- 異常處理器 --><bean id="handlerExceptionResolver" class="cn.itcast.ssm.controller.exceptionResolver.CustomExceptionResolver"/>2.3.6異常測(cè)試
修改商品信息,id輸入錯(cuò)誤提示商品信息不存在。
修改controller方法“editItem”,調(diào)用service查詢商品信息,如果商品信息為空則拋出異常:
// 調(diào)用service查詢商品信息Items item = itemService.findItemById(id);if(item == null){throw new CustomException("商品信息不存在!");}請(qǐng)自行實(shí)現(xiàn)在service、dao中跑出異常。
2.4json數(shù)據(jù)交互
2.4.1@RequestBody
作用:
@RequestBody注解用于讀取http請(qǐng)求的內(nèi)容(字符串),通過(guò)springmvc提供的HttpMessageConverter接口將讀到的內(nèi)容轉(zhuǎn)換為json、xml等格式的數(shù)據(jù)并綁定到controller方法的參數(shù)上。
本例子應(yīng)用:
@RequestBody注解實(shí)現(xiàn)接收http請(qǐng)求的json數(shù)據(jù),將json數(shù)據(jù)轉(zhuǎn)換為java對(duì)象
2.4.2@ResponseBody
作用:
該注解用于將Controller的方法返回的對(duì)象,通過(guò)HttpMessageConverter接口轉(zhuǎn)換為指定格式的數(shù)據(jù)如:json,xml等,通過(guò)Response響應(yīng)給客戶端
本例子應(yīng)用:
@ResponseBody注解實(shí)現(xiàn)將controller方法返回對(duì)象轉(zhuǎn)換為json響應(yīng)給客戶端
2.4.3請(qǐng)求json,響應(yīng)json實(shí)現(xiàn):
2.4.3.1環(huán)境準(zhǔn)備
Springmvc默認(rèn)用MappingJacksonHttpMessageConverter對(duì)json數(shù)據(jù)進(jìn)行轉(zhuǎn)換,需要加入jackson的包,如下:
2.4.3.2配置json轉(zhuǎn)換器
在注解適配器中加入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 />則不用定義上邊的內(nèi)容。
2.4.3.3controller編寫
// 商品修改提交json信息,響應(yīng)json信息@RequestMapping("/editItemSubmit_RequestJson")public @ResponseBody Items editItemSubmit_RequestJson(@RequestBody Items items) throws Exception {System.out.println(items);//itemService.saveItem(items);return items;}2.4.3.4頁(yè)面js方法編寫:
引入 js:
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
//請(qǐng)求json響應(yīng)jsonfunction request_json(){$.ajax({type:"post",url:"${pageContext.request.contextPath }/item/editItemSubmit_RequestJson.action",contentType:"application/json;charset=utf-8",data:'{"name":"測(cè)試商品","price":99.9}',success:function(data){alert(data);}});}2.4.3.5測(cè)試結(jié)果:
從上圖可以看出請(qǐng)求的數(shù)據(jù)是json格式
2.4.4Form提交,響應(yīng)json實(shí)現(xiàn):
采用form提交是最常用的作法,通常有post和get兩種方法,響應(yīng)json數(shù)據(jù)是為了方便客戶端處理,實(shí)現(xiàn)如下:
2.4.4.1環(huán)境準(zhǔn)備
同第一個(gè)例子
2.4.4.2controller編寫
// 商品修改提交,提交普通form表單數(shù)據(jù),響應(yīng)json@RequestMapping("/editItemSubmit_ResponseJson")public @ResponseBody Items editItemSubmit_ResponseJson(Items items) throws Exception {System.out.println(items);//itemService.saveItem(items);return items;}2.4.4.3頁(yè)面js方法編寫:
function formsubmit(){var user = " name=測(cè)試商品&price=99.9";alert(user);$.ajax({type:'post',//這里改為get也可以正常執(zhí)行url:'${pageContext.request.contextPath}/item/ editItemSubmit_RequestJson.action',//ContentType沒(méi)指定將默認(rèn)為:application/x-www-form-urlencodeddata:user,success:function(data){alert(data.name);}})}從上邊的js代碼看出,已去掉ContentType的定義,ContentType默認(rèn)為:application/x-www-form-urlencoded格式。
2.4.4.4測(cè)試結(jié)果:
從上圖可以看出請(qǐng)求的數(shù)據(jù)是標(biāo)準(zhǔn)的key/value格式。
2.4.4.5jquery的form插件插件
針對(duì)上邊第二種方法,可以使用jquery的form插件提交form表單,實(shí)現(xiàn)ajax提交form表單,如下:
引用js:
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery.form.min.js"></script>
js方法如下:
function response_json() {//form對(duì)象var formObj = $("#itemForm");//執(zhí)行ajax提交formObj.ajaxSubmit({dataType : "json",//設(shè)置預(yù)期服務(wù)端返回jsonsuccess : function(responseText) {alert(responseText);}});}2.4.5小結(jié)
實(shí)際開(kāi)發(fā)中常用第二種方法,請(qǐng)求key/value數(shù)據(jù),響應(yīng)json結(jié)果,方便客戶端對(duì)結(jié)果進(jìn)行解析。
2.5RESTful支持
2.5.1需求
RESTful方式商品修改、商品查詢。
2.5.2添加DispatcherServlet的rest配置
<servlet><servlet-name>springmvc-servlet-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-servlet-rest</servlet-name><url-pattern>/</url-pattern></servlet-mapping>2.5.3URL模板模式映射
@RequestMapping(value="/editItem/{item_id}"):{×××}占位符,請(qǐng)求的URL可以是“/editItem/1”或“/editItem/2”,通過(guò)在方法中使用@PathVariable獲取{×××}中的×××變量。
@RequestMapping("/ editItem/{item_id}") public String useredit(@PathVariable("item_id ") String id,Model model) throws Exception{//方法中使用@PathVariable獲取useried的值,使用model傳回頁(yè)面model.addAttribute("userid", userid);return"/user/useredit";}如果RequestMapping中表示為"/editItem/{id}",id和形參名稱一致,@PathVariable不用指定名稱。
商品查詢的controller方法也改為rest實(shí)現(xiàn):
// 查詢商品列表@RequestMapping("/queryItem")public ModelAndView queryItem() throws Exception {// 商品列表List<Items> itemsList = itemService.findItemsList(null);// 創(chuàng)建modelAndView準(zhǔn)備填充數(shù)據(jù)、設(shè)置視圖ModelAndView modelAndView = new ModelAndView();// 填充數(shù)據(jù)modelAndView.addObject("itemsList", itemsList);// 視圖modelAndView.setViewName("item/itemsList");return modelAndView;}2.5.4靜態(tài)資源訪問(wèn)<mvc:resources>
spring mvc 的<mvc:resources mapping="" location="">實(shí)現(xiàn)對(duì)靜態(tài)資源進(jìn)行映射訪問(wèn)。
如下是對(duì)js文件訪問(wèn)配置:
<mvc:resources location="/js/" mapping="/js/**"/>
3攔截器
3.1定義
Spring Web MVC 的處理器攔截器類似于Servlet 開(kāi)發(fā)中的過(guò)濾器Filter,用于對(duì)處理器進(jìn)行預(yù)處理和后處理。
3.2攔截器定義
實(shí)現(xiàn)HandlerInterceptor接口,如下:
Public class HandlerInterceptor1 implements HandlerInterceptor{/*** controller執(zhí)行前調(diào)用此方法* 返回true表示繼續(xù)執(zhí)行,返回false中止執(zhí)行* 這里可以加入登錄校驗(yàn)、權(quán)限攔截等*/@OverridePublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {// TODO Auto-generated method stubReturn false;}/*** controller執(zhí)行后但未返回視圖前調(diào)用此方法* 這里可在返回用戶前對(duì)模型數(shù)據(jù)進(jìn)行加工處理,比如這里加入公用信息以便頁(yè)面顯示*/@OverridePublic void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {// TODO Auto-generated method stub}/*** controller執(zhí)行后且視圖返回后調(diào)用此方法* 這里可得到執(zhí)行controller時(shí)的異常信息* 這里可記錄操作日志,資源清理等*/@OverridePublic void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)throws Exception {// TODO Auto-generated method stub}}
3.3攔截器配置
3.3.1針對(duì)某種mapping配置攔截器
<beanclass="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"/>
3.3.2針對(duì)所有mapping配置全局?jǐn)r截器
<!--攔截器 --><mvc:interceptors><!--多個(gè)攔截器,順序執(zhí)行 --><mvc:interceptor><mvc:mapping path="/**"/><bean class="cn.itcast.springmvc.filter.HandlerInterceptor1"></bean></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="cn.itcast.springmvc.filter.HandlerInterceptor2"></bean></mvc:interceptor></mvc:interceptors>
3.4正常流程測(cè)試
3.4.1代碼:
定義兩個(gè)攔截器分別為:HandlerInterceptor1和HandlerInteptor2,每個(gè)攔截器的preHandler方法都返回true。
3.4.2運(yùn)行流程
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor2..postHandle..
HandlerInterceptor1..postHandle..
HandlerInterceptor2..afterCompletion..
HandlerInterceptor1..afterCompletion..
3.5中斷流程測(cè)試
3.5.1代碼:
定義兩個(gè)攔截器分別為:HandlerInterceptor1和HandlerInteptor2。
3.5.2運(yùn)行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,運(yùn)行流程如下:
HandlerInterceptor1..preHandle..
從日志看出第一個(gè)攔截器的preHandler方法返回false后第一個(gè)攔截器只執(zhí)行了preHandler方法,其它兩個(gè)方法沒(méi)有執(zhí)行,第二個(gè)攔截器的所有方法不執(zhí)行,且controller也不執(zhí)行了。
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,運(yùn)行流程如下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
從日志看出第二個(gè)攔截器的preHandler方法返回false后第一個(gè)攔截器的postHandler沒(méi)有執(zhí)行,第二個(gè)攔截器的postHandler和afterCompletion沒(méi)有執(zhí)行,且controller也不執(zhí)行了。
總結(jié):
preHandle按攔截器定義順序調(diào)用
postHandler按攔截器定義逆序調(diào)用
afterCompletion按攔截器定義逆序調(diào)用
postHandler在攔截器鏈內(nèi)所有攔截器返成功調(diào)用
afterCompletion只有preHandle返回true才調(diào)用
3.6攔截器應(yīng)用
3.6.1用戶身份認(rèn)證
Public class LoginInterceptorimplements HandlerInterceptor{@OverridePublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)throws Exception {//如果是登錄頁(yè)面則放行if(request.getRequestURI().indexOf("login.action")>=0){return true;}HttpSession session = request.getSession();//如果用戶已登錄也放行if(session.getAttribute("user")!=null){return true;}//用戶沒(méi)有登錄挑戰(zhàn)到登錄頁(yè)面request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);return false;}}3.6.2用戶登陸controller
//登陸頁(yè)面@RequestMapping("/login")public String login(Model model)throws Exception{return "login";}//登陸提交//userid:用戶賬號(hào),pwd:密碼@RequestMapping("/loginsubmit")public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{//向session記錄用戶身份信息session.setAttribute("activeUser", userid);return "redirect:item/queryItem.action";}//退出@RequestMapping("/logout")public String logout(HttpSession session)throws Exception{//session過(guò)期session.invalidate();return "redirect:item/queryItem.action";}總結(jié)
以上是生活随笔為你收集整理的springmvc教程(4)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: shiro教程(1)-基于url权限管理
- 下一篇: springmvc教程--RESTful