您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

对SpringMVC注解开发的详解

2024/5/22 14:47:52发布36次查看
在springmvc 中,控制器controller 负责处理由dispatcherservlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个model ,然后再把该model 返回给对应的view 进行展示。在springmvc 中提供了一个非常简便的定义controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@controller 标记一个类是controller ,然后使用@requestmapping 和@requestparam 等一些注解用以定义url 请求和controller 方法之间的映射,这样的controller 就能被外界访问到。此外controller 不会直接依赖于httpservletrequest 和httpservletresponse 等httpservlet 对象,它们可以通过controller 的方法参数灵活的获取到。
@controller 用于标记在一个类上,使用它标记的类就是一个springmvc controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@requestmapping 注解。@controller 只是定义了一个控制器类,而使用@requestmapping 注解的方法才是真正处理请求的处理器。单单使用@controller 标记在一个类上还不能真正意义上的说它就是springmvc 的一个控制器类,因为这个时候spring 还不认识它。那么要如何做spring 才能认识它呢?这个时候就需要我们把这个控制器类交给spring 来管理。有两种方式:
(1)在springmvc 的配置文件中定义mycontroller 的bean 对象。
(2)在springmvc 的配置文件中告诉spring 该到哪里去找标记为@controller 的controller 控制器。
1.1校验理解
项目中,通常使用较多的是前端的校验,比如页面中js校验。对于安全要求较高的建议在服务器进行校验。
服务器校验:
控制层controller:校验页面请求的参数的合法性。在服务端控制层controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
持久层dao:一般是不校验的。
1.2springmvc校验需求springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。
校验思路:
页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示dao页面。
具体需求:
商品修改,添加校验(校验商品名称长度、生成日期的非空校验),如果校验出错,在商品修改页面显示错误信息。
1.3环境准备hibernate的校验框架validation所需要jar包:
1.4配置校验器 在classpath下springmvc.xml中配置:
    <!-- 校验器 --><bean id="validator"class="org.springframework.validation.beanvalidation.localvalidatorfactorybean"><!-- hibernate校验器--><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>
1.5将validator注入到处理器适配器中 在classpath下springmvc.xml中配置:
1.5.1配置方式1
1.5.2配置方式2<!-- 自定义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>
1.6在pojo中添加校验规则在itemscustom.java中添加校验规则:
/**  * 商品信息的扩展类  * @author joanna.yan  * */public class itemscustom extends items{//添加商品信息的扩展属性}
这里itemscustom直接继承的是items,所以我们在items中添加:
1.7customvalidationmessages.properties在classpath下新建customvalidationmessages.properties文件,配置校验错误信息:
1.8捕获校验错误信息一个bindingresult对应一个pojo。
1.9在页面显示校验错误信息1.9.1方式一在controller中将错误信息传到页面即可。
    //商品信息修改提交//在需要校验的pojo前添加@validated,在需要校验的pojo后边添加bindingresult bindingresult接收校验出错信息//注意:@validated和bindingresult bindingresult是配对出现,并且形参顺序是固定的(一前一后)。@requestmapping(/edititemssubmit)public string edititemssubmit(model model,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());             }//将错误信息传到页面model.addattribute(allerrors, allerrors);//出错,重新到商品页面return items/edititems;         }//调用service更新商品信息,页面需要将商品信息传到此方法        itemsservice.updateitems(id, itemscustom);        //重定向到商品的查询列表//        return redirect:queryitems.action;//页面转发//        return forward:queryitems.action;return success;     }
页面显示错误信息:
<c:if test="${allerrors!=null }"><c:foreach items="${allerrors }" var="error">${error.defaultmessage }<br/></c:foreach></c:if>
1.9.2方式二修改controller方法:
    //商品信息修改提交//在需要校验的pojo前添加@validated,在需要校验的pojo后边添加bindingresult bindingresult接收校验出错信息//注意:@validated和bindingresult bindingresult是配对出现,并且形参顺序是固定的(一前一后)。@requestmapping(/edititemssubmit)public string edititemssubmit(model model,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());             }//出错,重新到商品页面return items/edititems;         }//调用service更新商品信息,页面需要将商品信息传到此方法        itemsservice.updateitems(id, itemscustom);        //重定向到商品的查询列表//        return redirect:queryitems.action;//页面转发//        return forward:queryitems.action;return success;     }
商品修改页面显示错误信息:
页头:
<%@ page language="java" contenttype="text/html; charset=utf-8"pageencoding="utf-8"%><%@ taglib uri="" prefix="c" %><%@ taglib uri="" <%@ taglib prefix="spring" uri="" %>
在需要显示错误信息地方:
<spring:hasbinderrors name="item"><c:foreach items="${errors.allerrors}" var="error">${error.defaultmessage }<br/></c:foreach></spring:hasbinderrors>
<spring:hasbinderrors name="item">表示如果item参数绑定校验错误下边显示错误信息。
1.10分组校验1.10.1需求在pojo中定义校验规则,而pojo是被多个controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。
解决方法:
定义多个校验分组(其实是一个java接口),分组中定义有哪些规则。
每个controller方法使用不同的校验分组。
1.10.2校验分组/**  * 校验分组  * @author joanna.yan  * */public interface validgroup1 {//接口中不需要定义任何方法,仅是对不同的校验规则进行分组//此分组只校验商品名称长度}
/**  * 校验分组  * @author joanna.yan  * */public interface validgroup2 {//接口中不需要定义任何方法,仅是对不同的校验规则进行分组}
1.10.3在校验规则中添加分组
1.10.4在controller方法中使用指定分组的校验
1.10.4校验注解@null   被注释的元素必须为 null  
@notnull    被注释的元素必须不为 null  
@asserttrue     被注释的元素必须为 true  
@assertfalse    被注释的元素必须为 false  
@min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值  
@max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值  
@decimalmin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值  
@decimalmax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值  
@size(max=, min=)   被注释的元素的大小必须在指定的范围内  
@digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内  
@past   被注释的元素必须是一个过去的日期  
@future     被注释的元素必须是一个将来的日期  
@pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式  
hibernate validator 附加的 constraint  
@notblank(message =)   验证字符串非null,且长度必须大于0  
@email  被注释的元素必须是电子邮箱地址  
@length(min=,max=)  被注释的字符串的大小必须在指定的范围内  
@notempty   被注释的字符串的必须非空  
@range(min=,max=,message=)  被注释的元素必须在合适的范围内
2.数据回显2.1什么是数据回显提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。
2.2pojo数据回显方法springmvc默认对pojo数据进行回显,springmvc自动将形参中的pojo重新放回request域中,request的key为pojo的类名(首字母小写),如下:
controller方法:
    @requestmapping(/edititemsubmit)public string edititemsubmit(integer id,itemscustom itemscustom)throws exception{
springmvc自动将itemscustom放回request,相当于调用下边的代码:
model.addattribute(itemscustom, itemscustom);
jsp页面:
页面中的从“itemscustom”中取数据。
如果key不是pojo的类名(首字母小写),可以使用@modelattribute完成数据回显。
@modelattribute作用如下:
(1)绑定请求参数到pojo并且暴露为模型数据传到视图页面。
此方法可实现数据回显效果。
// 商品修改提交@requestmapping(/edititemsubmit)public string edititemsubmit(model model,@modelattribute(item) itemscustom itemscustom)
页面:
<tr><td>商品名称</td><td><input type="text" name="name" value="${item.name }"/></td></tr><tr><td>商品价格</td><td><input type="text" name="price" value="${item.price }"/></td></tr>
如果不用@modelattribute也可以使用model.addattribute(item, itemscustom)完成数据回显。
(2)将方法返回值暴露为模型数据传到视图页面
//商品分类@modelattribute(itemtypes)public map<string, string> getitemtypes(){                  map<string, string> itemtypes = new hashmap<string,string>();         itemtypes.put(101, 数码);         itemtypes.put(102, 母婴);        return itemtypes;     }
页面:
商品类型:<select name="itemtype"><c:foreach items="${itemtypes }" var="itemtype"><option value="${itemtype.key }">${itemtype.value }</option>        </c:foreach></select>
2.3简单类型数据回显最简单方法使用model。
//简单数据类型回显  model.addattribute(id, id);
3.异常处理器3.1异常处理思路系统中异常包括两类:预期异常和运行时异常runtimeexception,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、通过测试手段减少运行时异常的发生。
系统的dao、service、controller出现异常都通过throws exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
3.2自定义异常类对不同的异常类型定义异常类,继承exception。
package joanna.yan.ssm.exception;/**  * 系统自定义异常类,针对预期的异常。需要在程序中抛出此类异常。  * @author joanna.yan  * */public class customexception extends exception{//异常信息public string message;public customexception(string message) {super();this.message = message;     }public string getmessage() {return message;     }public void setmessage(string message) {this.message = message;     }      }
3.3全局异常处理器思路:
系统遇到异常,在程序中手动抛出,dao抛给service、service抛给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。
全局异常处理器处理思路:
解析出异常类型
如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示
如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
springmvc提供一个handlerexceptionresolver接口。
package joanna.yan.ssm.exception;import javax.servlet.http.httpservletrequest;import javax.servlet.http.httpservletresponse;import org.springframework.web.servlet.handlerexceptionresolver;import org.springframework.web.servlet.modelandview;public class customexceptionresolver implements handlerexceptionresolver{/* * ex:系统抛出的异常     */@overridepublic modelandview resolveexception(httpservletrequest request,             httpservletresponse repsonse, object handler, exception ex) {//handler就是处理器适配器要执行的handler对象(只有一个method)//1.解析出异常类型//2.如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示//3.如果该异常类型不是系统自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)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;     } }
3.4错误页面<%@ 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>错误提示</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0">    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="this is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css?1.1.11">-->   </head>
3.5在springmvc.xml配置全局异常处理器    <!-- 全局异常处理器 只要实现handlerexceptionresolver接口就是全局异常处理器--><bean class="joanna.yan.ssm.exception.customexceptionresolver"></bean>
3.6异常测试在controller、service、dao中任意一处需要手动抛出异常。
如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。
在商品修改的controller方法中抛出异常。
在service接口中抛出异常:
如果与业功能相关的异常,建议在service中抛出异常。
与业务功能没有关系的异常(比如形参校验),建议在controller中抛出。
上边的功能,建议在service中抛出异常。
 4.图片上传4.1配置虚拟目录在tomcat上配置图片虚拟目录,在tomcat下conf/server.xml中添加:
<context docbase="f:\develop\upload\temp" path="/pic" reloadable="false"/>
访问http://localhost:8080/pic即可访问f:\develop\upload\temp下的图片。
注意:在图片虚拟目录中,一定要将图片目录分级创建(提高i/o性能),一般我们采用按日期(年、月、日)进行分级创建。
4.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>
4.3加入上传图片的jar上边的解析器内部使用下边的jar进行图片上传。
4.4上传图片controller:
    @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{        //获取校验错误信息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(items, itemscustom);//简单数据类型回显model.addattribute(id, id);//出错,重新到商品页面return items/edititems;         }        //上传图片string originalfilename=items_pic.getoriginalfilename();if(items_pic!=null&&originalfilename!=null&&originalfilename.length()>0){//存储图片的物理路径string pic_path=f:\\develop\\upload\\temp\\;//新的图片名称string newfilename=uuid.randomuuid()+originalfilename.substring(originalfilename.lastindexof(.));//新图片file newfile=new file(pic_path+newfilename);//将内存中的数据写入磁盘            items_pic.transferto(newfile);//将新图片名称写到itemscustom中            itemscustom.setpic(newfilename);         }        //调用service更新商品信息,页面需要将商品信息传到此方法        itemsservice.updateitems(id, itemscustom);        //重定向到商品的查询列表//        return redirect:queryitems.action;//页面转发//        return forward:queryitems.action;return success;     }
页面:
form添加enctype=multipart/form-data,file的name与controller形参一致:
<form id="itemform" action="${pagecontext.request.contextpath }/items/edititemssubmit.action" method="post" enctype="multipart/form-data"><input type="hidden" name="id" value="${items.id }"/>修改商品信息:<table width="100%" border=1><tr><td>商品名称</td><td><input type="text" name="name" value="${items.name }"/></td></tr><tr><td>商品价格</td><td><input type="text" name="price" value="${items.price }"/></td></tr><tr><td>商品生产日期</td><td><input type="text" name="createtime" value="<fmt:formatdate value="${items.createtime}" pattern="yyyy-mm-dd hh:mm:ss"/>/></td></tr><tr><td>商品图片</td><td><c:if test="${items.pic !=null}"><img src="/pic/${items.pic}" width=100 height=100/><br/></c:if><input type="file" name="items_pic"/> </td></tr><tr><td>商品简介</td><td><textarea rows="3" cols="30" name="detail">${items.detail }</textarea></td></tr><tr><td colspan="2" align="center"><input type="submit" value="提交"/></td></tr></table></form>
5.json数据交互5.1为什么要进行json数据交互json数据格式在接口调用中、html页面中较常用,json格式比较简单,解析还比较方便。
比如:webserivce接口,传输json数据。
5.2springmvc进行json交互
(1)请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。
(2)请求key/value、输出json。次方法比较常用。
5.3环境准备 5.3.1加载json转换的jar包springmvc中使用jackson的包进行json转换(@requestbody和@responsebody使用下边的包进行json转换),如下:
5.3.2配置json转换器在classpath/springmvc.xml,注解适配器中加入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/>则不用定义上边的内容。
5.4json交互测试这里分输入json串输出json串和输入key/value输出json两种情况进行测试。
新建jsontest.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>json交互测试</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0">    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="this is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css?1.1.11">--><script type="text/javascript" src="${pagecontext.request.contextpath }/js/jquery-1.4.4.min.js?1.1.11"></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:999}',               success:function(data){//返回json结果                  alert(data);               }           });       }             //请求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=999',               success:function(data){//返回json结果                  alert(data);               }           });       }      </script>   </head>      <body><input type="button" onclick="requestjson()" value="请求json,输出的是json"/> <input type="button" onclick="responsejson()" value="请求key/value,输出的是json"/>   </body></html>
新建controller:
package joanna.yan.ssm.controller;import joanna.yan.ssm.po.itemscustom;import org.springframework.stereotype.controller;import org.springframework.web.bind.annotation.requestbody;import org.springframework.web.bind.annotation.requestmapping;import org.springframework.web.bind.annotation.responsebody; @controllerpublic class jsontest {//请求json串(商品信息),输出的竖json(商品信息)//@requestbody将请求的商品信息的json串转成itemscustom对象//@responsebody将itemscustom转成json输出@requestmapping(/requestjson)public @responsebody itemscustom requestjson(@requestbody itemscustom itemscustom){        return itemscustom;     }    //请求key/value,输出的竖json@requestmapping(/responsejson)public @responsebody itemscustom responsejson(itemscustom itemscustom){        return itemscustom;     } }
(1)测试输入json串输出是json串
(2)测试输入key/value输出是json串
6.restful支持6.1什么是restfulrestful架构,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以得到越来越多网站的采用。
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...
目前完全实现restful的系统很少,一般只实现(1)、(3),对于(2)我们一个方法经常会同时存在增删改查,实现起来太费劲了。
下面举例实现(1)、(2)。
6.2rest的例子6.2.1需求查询商品信息,返回json数据。
6.2.2controller定义方法,进行url映射使用rest风格的url,将查询商品信息的id传入controller。
输出json使用@responsebody将java对象输出json。
    //查询商品信息,输出json///itemsview/{id}里面的{id}表示占位符,通过@pathvariable获取占位符中的参数//如果占位符中的名称和形参名一致,在@pathvariable可以不指定名称@requestmapping(/itemsview/{id})public @responsebody itemscustom itemsview(@pathvariable(id) integer id) throws exception{         itemscustom itemscustom=itemsservice.finditemsbyid(id);return itemscustom;     }
6.2.3rest方法的前端控制器配置在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>  <load-on-startup>1</load-on-startup>   </servlet>   <servlet-mapping>     <servlet-name>springmvc_rest</servlet-name>     <url-pattern>/</url-pattern>   </servlet-mapping>
6.3对静态资源的解析配置前端控制器的url-parttern中指定/,对静态资源的解析出现问题:
在springmvc.xml中添加静态资源解析方法。
    <!-- 静态资源的解析 包括:js、css、img...--><mvc:resources location="/js/" mapping="/js/**"/>          <mvc:resources location="/img/" mapping="/img/**"/>
以上就是对springmvc注解开发的详解的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product