Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)
分工明确
而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要;
无需继承API直接命令操作
由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象;
与spring无缝衔接
和Spring 其他框架无缝集成,是其它Web框架所不具备的;
适配任意类作为处理器
可适配,通过HandlerAdapter可以支持任意的类作为处理器;
支持简单定制
可定制性,HandlerMapping、ViewResolver等能够非常简单的定制;
功能强大
功能强大的数据验证、格式化、绑定机制;
灵活的单元测试
利用Spring提供的Mock对象能够非常简单的进行Web层单元测试;
更容易的主题与国际化
本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
强大的jsp标签库
强大的JSP标签库,使JSP编写更容易。
还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
1.首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2.DispatcherServlet——>HandlerMapping,HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
3.DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
4.HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
5.ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
6.View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
7.返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
用户发起请求到前端控制器(Controller)
前端控制器没有处理业务逻辑的能力,需要找到具体的模型对象处理(Handler),到处理器映射器(HandlerMapping)中查找Handler对象(Model)。
HandlerMapping返回执行链,包含了2部分内容: ① Handler对象、② 拦截器数组
前端处理器通过处理器适配器包装后执行Handler对象。
处理业务逻辑。
Handler处理完业务逻辑,返回ModelAndView对象,其中view是视图名称,不是真正的视图对象。
将ModelAndView返回给前端控制器。
视图解析器(ViewResolver)返回真正的视图对象(View)。
(此时前端控制器中既有视图又有Model对象数据)前端控制器根据模型数据和视图对象,进行视图渲染。
返回渲染后的视图(html/json/xml)返回。
给用户产生响应。
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
View:视图
springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
说明:在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。
需要用户开放的组件有handler、view
springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
struts2:filter
springmvc:servlet
struts2:底层是Servlet,参数基于属性封装,如果配置单例,会出现线程安全问题,所以配置多例
springmvc:底层是Servlet,单例
struts2:基于属性封装
springmvc:基于方法进行封装
创建工程
导jar包
写好页面
创建Controller
创建springmvc.xml
在web.xml中配置前端控制器
注解驱动的作用:
自动创建处理器映射器
自动创建处理器适配器
支持所有注解
支持json格式数据
springmvc接收参数方式:直接把接收参数变量放在方法中自动接收参数
1).再次编码
String(request.getParamter(“userName”).getBytes(“ISO8859-1”),”utf-8”)
2). server.xml设置 URIEncoding=”UTF-8”
1). 使用spring编码过滤器(web.xml),必须配置在前端控制器之前.
1).注解:@InitBinder:转换参数
2).自定义转换工具
在springmvc.xml中配置
1).HttpServletRequest:通过request对象获取请求信息
2).HttpServletResponse:通过response处理响应信息
3).HttpSession:通过session对象得到session中存放的对象
4).Model/ModelMap:ModelMap是Model接口的实现类,通过Model或ModelMap向页面传递数据.
model.addAttribute("item", item);
页面通过${item.XXXX}获取item对象的属性值。
如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据。
5).绑定简单类型:当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。从Request取参数的方法可以进一步简化。
参数类型推荐使用包装数据类型,因为基础数据类型不可以为null
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean
如果提交的参数很多,或者提交的表单中的内容很多的时候可以使用pojo接收数据。要求pojo对象中的属性名和表单中input的name属性一致。
如果是包装类型的POJO,包装对象.
页面定义:
Controller方法定义如下:
标签中varStatus属性常用参数总结下:
Controller
RequestMapping
RequestParam
Redirect
Forward
RequestBody/ResponseBody
@Controller:用于标识是处理器类.表示把我的控制器对象交给spring来创建。
Controller起作用:只需要扫描即可。
@RequestMapping :请求映射注解
用法举例:
@RequestMapping(“list.do”)
@RequestMapping(“/list.do”)
@RequestMapping(“list”)
@RequestMapping(value=”list”)
@RequestMapping(value=”list”,method.RequestMethod.POST)
get请求:
所有从浏览器直接发送的请求,都是get请求
href发送的请求都是get请求
post:
表单提交是post请求
ajax是post请求
3.URL路径映射
@RequestMapping:请求到处理器功能方法的映射规则;
URL路径映射:@RequestMapping(value=”/user”)或@RequestMapping(“/user”)
RequestMethod请求方法限定
4.URL模板映射
@RequestMapping(value="/useredit/{userId}”):{×××}
占位符请求的URL可以是
“/useredit/001”或“/useredit/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量
实现restFul,所有的url都是一个资源的链接,有利于搜索引擎对网址收录。
多个占位符
如果有多个pojo、并且里面具有相同的属性,解决方案:
我们使用包装类来包装pojo、经过包装的pojo相当于加了一层包结构。所以后面即使具有相同的属性也无所谓。
5.RequestParam
value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
@RequestParam(defaultValue=”1”,value=”myid”)
功能1:设置默认值
功能2:给参数定义别名,别名和页面传递参数匹配即可
6.Redirect
Contrller方法返回结果重定向到一个url地址.
redirect:add.do 与 redirect:/user/add.do” 在同一个类里面进行跳转。上面2个都可以实现跳转。但是有区别:第一个是同一个根路径下面跳转。第二个是在项目路径下进行跳转。
不同的类进行跳转只能使用:redirect:/user/add.do进行跳转。即是从项目路径下来查询。
redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。
由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/user/userlist.do后边加参数,如下:
/user/userlist.action?groupid=2&…..
7.Forward
controller方法执行后继续执行另一个controller方法。
return “forward:/user/userlist.action”;
forward方式相当于
“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到。
8.json数据交互
@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。
@RequestBody注解实现接收http请求的json数据,将json数据转换为java对象
@RequestBody/@ResponseBody要依赖Jackson
支持注解,注解映射器和注解适配器可以使用代替。
默认注册了注解映射器和注解适配器等bean。
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
1.自定义异常
全局异常解析接口 HandlerExceptionResolver
2.自定义异常处理器
3.新建错误提示页面
略
4.异常处理器配置
在springmvc.xml中配置:
采用跨服务器异步上传方式.
1.jar包
依赖:commons-io,commons-fileupload,jersey框架下的jar包
2.配置解析器
配置springmvc.xml
3.配置图片服务器权限
readonly
false
4.Controller编写
5.页面编写
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,是对http协议的诠释。
资源定位:互联网所有的事物都是资源,要求url中没有动词,只有名词。没有参数
Url格式:
blog.dn.net/beat_the_wo…
资源操作:使用put、delete、post、get,使用不同方法对资源进行操作。分别对应添加、删除、修改、查询。
1.前端控制器设置
2.静态资源访问
springmvc支持restFull风格软件架构模式:
没有扩展名
没有?方式传递参数,参数都在url链接中
springmvc提供url默认映射,映射:
@RequestMapping(“/item/deitItem/{id}”)
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
1.自定义拦截器
2.拦截器配置
在springmvc中配置
3.拦截器执行顺序
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
4.拦截器与过滤器的区别
过滤器Filter依赖于Servlet容器,基于回调函数,过滤范围大
拦截器Inerceptor依赖于框架容器,基于反射机制,只过滤请求
控制层采用springmvc、持久层使用mybatis实现.
1.需求
实现商品查询列表,从mysql数据库查询商品信息。
2.导jar包
包括:spring(包括springmvc)、mybatis、mybatis-spring整合包、数据库驱动、第三方连接池、日志等。
3.spring与mybatis整合
1).db.properties
2).log4j.properties
3).配置sqlMapConfig.xml
在classpath下创建mybatis/sqlMapConfig.xml
4).配置applicationContext.xml
5).配置ItemsMapper.xml
6).ItemsMapper.java
4.spring管理service
1).Service由spring管理。
2).spring对Service进行事务控制。
service层代码:
5.spring与springmvc整合
1).配置springmvc.xml
2).web.xml
3).Controller编写
1.为了避免中文乱码,需要实现指定jsp页面的编码为utf-8,但是如果遇到html页面的特殊标签可能会产生一些部分中文乱码
更好的解决方案可以用jsonp
maven坐标如下:
客户端
服务端
接收list数据
项目地址:
git.oschina.net/lemonzone20…
尝试了几个开源项目感觉这个效果最好,而且文旦详尽,需要注意的是
1、不支持css3特殊样式,html里如果有中文需要现在css样式里申明所用字体
2、项目里读取html时使用了freemark技术也但是我自己操作的时候利用总结一里的jsonp读取更加方便
文件上传到tomcat下的工程下,项目重新启动图片就没了
解决的思路:
在配置文件下配置路径
BASE_FILEUPLOAD_URL=/upload/username/type/year/month/
BASE_FILEUPLOAD_PATH=../../upload/username/type/year/month/
上传文件时读取该路径并进行拼接:
//文件上传目录路径
String savePath = pageContext.getServletContext().getRealPath(“/”) + BASE_FILEUPLOAD_PATH;
这样配置以后图片就上传到tomcat的一级目录下了
定义访问的时候url为localhost:8080//btkjsite_designcloud/before/getFile/upload/username/type/year/month/20160911.jpg
先根据访问的url找到图片的实际物理路径,再通过输入流读取文件,写入输出流在网页上把图片显示出来
任何mvc的框架,都是需要在web.xml中进行核心的配置的,struts2是一个过滤器,而SpringMVC则是一个servlet,但是配置方法大同小异,都是在web.xml中进行配置,配置方法如下:
再然后就是配置springMVC-servlet.xml,这个文件名之前说过,可以自定义路径与名称,如果不自定义,则一定要放在WEB-INFO下,注意引入正确的命名空间,然后加入核心分解解析器,就是解析url的请求,类似于stuts的配置文件,配置如下:
然后就是正式使用SpringMVC了,我们通常是用注解的方式,因为注解真的太好用了,省事好多,但是这里也简单介绍一下使用xml配置文件的方式来写一个简单的helloworld
1.1.配置文件的helloworld
首先新建一个类,这个类要实现Controller接口,然后实现它的一个ModelAndView方法,代码如下:
然后在springMVC-servlet.xml中配置一个bean:配置方法如下:
这种配置和struts2其实是一样的,name属性就是浏览器请求的url,而class就是它处理的类,而运行的方法,就是上面所继承的接口,然后在浏览器输入http://localhost:8080/springMVC/test,就可以跳转到welcome.jsp下,这是根据之前配置的视图分解解析器的前后缀前该方法返回的字符串拼接而成的。
1.2.基于注解的helloworld
使用注解就要简单得多了,首先是在springMVC-servlet.xml中配置扫描的包,这样spring就会自动根据注解来描述一些特定的注解,然后把这些bean装载进入spring容器中,配置如下:
然后,在指定的包,或者其子包下新建一个类,代码如下:
这样就不用再写配置文件,只要加上相应的注解就行,比如说这里的helloworld方法,只要在浏览器输入http://localhost:8080/project/hellowrold,就可以进入spring.jsp页面
2.1.类的@RequestMapping注解
刚才看到了@RequestMapping这个注解是用于给一个方法加上url的请求地址,不过,这个注解不仅仅可以加在方法上面,也可以加在类上面,代码如下图所示:
如上代码如示,如果同时在类与方法上面同时加上@RequestMapping注解的话,那么URL肯定不会是之前的那种写法了,现在要写成类的注解加上方法的注解,就是有点类似struts2中,的nameplace属性,那如如上代码,URL应该为http://localhost:8080/project/springMVC/testReuqestMapping
2.2.请求方式的设置
像我们平常提交一个表单,肯定会有get,与post这两个常用的请求,那么在springMVC中要如何设置呢?很简单,也是在@RequestMapping中使用,不过需要在方法的注解上面使用,代码如下:
这下在from表单中,或者异步请求中,就需要以post做为请求,不然会报错的,因为这里已经设置为了post,如果客户端再请求get,将会报错。
2.3.参数的规定与请求头的规定设置
我们都知道http请求会有着请求参数与请求头消息,那么在springMVC里面,是可以规范这些信息的,首先给一段代码示例:
无论是params,还是headers,都可以包含多个参数,以逗号相隔就行,如果不满足写了的条件,则就会报错,不允许请求资源。其次这两个属性还支持一些简单的表达式:
2.4.@RequestMapping映射中的通配符
在@RequestMapping的value属性中,还支持Ant格式的能配符:
/user/*/createUser 匹配/user/abcd/createUser
/user/**/createUser 匹配/user/aa/bb/cc/createUser
/user/?/createUser 匹配/user/a/createUser
这里就不作代码演示了,相信大家一看就懂,因为这种通配符真的太常见了
2.5.@RequestMapping与@PathVariable注解的一起使用
springMVC很灵活,它可以获取URL地址中的值,然后当作变量来输出,这里要使用@PathVariable注解,故名思意,就是路径变量的意思,通常的话,@PathVariable要使用,是一定要与@RequestMapping一起使用的,下面给出代码示例:
先在括号中加上注解,其中value就是@RequestMapping中占位符的声明,然后加上数据类型和定义的变量,这样就可以对其进行使用了
2.6.Rest风格的URL
通常的话,表单有着post,与get提交方式,而rest风格的URL,则有着get,post,put,delete这四种请求方式,但是浏览器却是只支持get与post,所以我们可以使用springMVC,把它进行转换,我们要利用org.springframework.web.filter.HiddenHttpMethodFilter这个类,这是一个过滤器,我们首先要在web.xml中配置它,请配置在第一个位置,不然的话,可能会先进入其它的过滤器,配置代码如下:
如上的配置,这个过滤器则会拦截所有的请求,我们可以看一下org.springframework.web.filter.HiddenHttpMethodFilter的部分源代码:
当这个过滤器拦截到一个请求时,就会先拿到这个请求的参数,它要满足两个条件,第一,浏览器发出的请求为post请示,第二,它还要有一个参数,参数名为_method,而它的值,则可以为get,post,delete,put,此时过滤器就会把post请求转换成相应的请求,不然的话就不进行转换,直接请求。至于添加_method参数的话,则可以使用hidden隐藏域,或者使用?拼接参数都可以。
下面就该是控制器的方法了,在本处第2小点中,有讲到@RequestMapping的请求方式的设置,只要把这个请求方式设置成对应的请求就行,比如说转换成了DELETE请求,则@RequestMapping也要写成对应的DELETE请求,不然会出错,示例代码如下:
此时,就可以正确转换请求方式了。
3.1.获取请求中的参数,@RequestParam
在获取类似这种: http://localhost:8080/project/test?user=a&password=2这种请求参数时,就需要用@RequestParam这个注解来获取,代码如下:
如上面注释所写,它常用这三个属性,value是参数名,但是如果只写了参数名的话,请求时,就必须带此参数,不然就会报错。如果把required属性设置为false,就可以使得该参数不传,还有defaultValue属性,此属性可以当浏览器没有传此参数时,给这个参数一个默认值
3.2.获取请求头的信息,@RequestHeader
之前也有提到过http的请求头的信息,那么这里就可以使用@RequestHeader注解来获取请求头的信息,它的使用方法与上面的@RequestParam是完全一样的,同样拥有value,requied,defaultValue这三个属性,而有代表的作用也是一样的,下面给出代码示例:
因为它的用法与本章第一点的获取请求参数的用法一样,所以这里就不作过多的说明,详细可以查看@RequestParam的用法
3.3.获取Cookie的信息,@CookieValue
在开发中,有很多情况都会用到Cookie,这里可以使用@CookieValue注解来获取,其使用方法与@RequestParam与@RequestHeader一样,这里就不过多叙述,给出示例代码:
它也有着三个属性,value,required,defaultValue,分别对应Cookie名,是否非空,默认值。
3.4.使用Pojo来获取请求中的大量参数
如果http请求中只有一两个参数,那么使用@RequestParam还可以,但是如果一个请求中带有着大量的参数,那么这样就有点麻烦了,那么springMVC就可以使用Pojo对象来获取这次请求中的所有参数,并且全部封装到这个对象里面,这种方式类似struts2的ModelDriver,相信使用过struts2的同学都清楚,这种方式极其简便,下面一边给代码,一边解释,首先给出请求的处理方法:
这里无需使用其它的注解,只需要在这个处理方法中加上一个类就行,那么springMVC就会自动把请求参数封装到你写好的类中,而且这种封装还支持级联操作,什么是级联操作呢?就是User类中的属性还有着另外的一个类,下面给出User类的代码:
由上面可见,其中不仅有普通的属性,还有着一个Address的类,我们再来看一下Address类的代码:
可以很清楚的看清User类与Address类的关系,那么像这种关系的对象,在浏览器form表单中的name属性该如何写呢?Address类中的字段,要加上address,比如address.province,或者address.city,其它的属性,就直接写User类中的属性就可以了。而这里为什么Address变成了小写的呢?其实这并不是什么命名规则,而是我在User类中就是这么定义的
这下没有什么问题了吧,我们再来看一下浏览器表单是怎么写的:
如上表单元素就可以看到表单的name属性是如何与User类对应的,其Address类中的属性,就以address.city。
下面来说一下这种请求方式的特点:
1.简便,不需要大量的@RequestParam注解。
2.与struts2的ModelDriver的用法差不多,只不过ModelDriver是接口,整个类里面所有的方法都可以使用。而springMVC中这个Pojo对象的作用仅仅是当前的处理方法中。
3.这种Pojo的使用中,浏览器的参数可以为空,就是可以不传参数,也不会报错,不像@RequestParam,如果不指定requried=false的话,还会报错。
4.1.使用Servlet原生API
在我们平常使用springMVC中,虽然说springMVC已经帮我们做了很多工作了,但是我们实际中还是会要用到Servlet的原生API,那这个时候要如何得到Servlet的原生对象呢?这里与struts2不同,springMVC是在方法中声明对应的参数来使用这些对象,而struts2则是调用相应的方法来得到这些对象。当然,对于没有学过struts2的同学,可以忽略,下面给出代码示例:
如上代码所示,直接在对应的处理方法里面声明这些需要使用的对象就可以了,那如果同时要使用Pojo来获得请求参数怎么办呢?这个不用担心,照常使用就行了,如上代码所示,同样声明了一个User类来接收参数,并不会有任何的影响。
4.2.使用Servlet原生API的原理(部分springMVC的源代码)
如果你想问,springMVC中的处理方法,里面可以支持哪些Servlet的原生API对象呢?或者你又想问,为什么可以照常的使用Pojo来获取请求参数呢?那么这里,我们先来看一下springMVC的源代码,然后再作解释:
从这里就可以说明了一个问题了,springMVC首先会通过反射技术得到这个方法里面的参数(源代码没有贴上,有兴趣的可以自行查看springMVC的源代码),然后比较这些参数的类型,是否与上面的九个类型想匹配,如果匹配成功,则返回这个对象,请注意,是与对象类型相匹配,而不是与形参名作匹配,所以这样,就不会使得Pojo无法工作了
4.3.springMVC支持哪些原生API
其实从4.2中的源代码中也是可以看到了,这里支持九种个对象,对应关系分别是:
5.1.简单的使用ModelAndView来向页面传递参数
实际开发中,总要大量的向页面中传递后台的数据,那么存放数据的方法也有多种多样,比如说存到request中,大家都知道是使用request.setAtrribute()来向request域中传递值,但是实际上springMVC给我们封装了更好的方法,那就是使用ModelAndView。
首先,方法的返回值,该由String变成ModelAndView,然后在处理方法中new一个ModelAndView对象,然后返回这个对象就可以了,对象中可以增加返回页面的字符,也可以向这个对象里面传递参数,现在给出一个简单的示例代码:
如上代码如示,我们可以使用构造方法给它传一个值,那就是它最终要返回的页面的值,或者使用setViewName方法来给它一个返回页面的名字。使用addObject方法来给这个模型添加数据,这是一个键值对的数据,然后返回这个ModelAndView对象。
5.2.使用参数Map来向页面传值
可以在执行方法中定义一个Map参数,然后在方法中,向map添加内容,然后在页面中根据map的键来取对应的值,也是存在request域中,下面给出代码示例:
这里面就是在方法中有着一个Map类型的参数,其实不仅仅可以是Map类型,还可以是Model与ModelMap类型的,因为最终传入的根本就不是Map,而是
org.springframework.validation.support.BindingAwareModelMap
5.3.使用@SessionAttributes注解,把值放到session域中
其实5.1和5.2所诉的内容,虽然是把后台数据传递到前台,但是全部都是放置到request域中,这里讲诉一下使用@SessionAtrributes注解,把后台数据同时放到session中。
首先介绍一下这个注解,这个注解只能放在类上面,而不能放在方法上面。它有两个属性,一个是value属性,一个是types属性,这两个数据都是数组,所以可以声明多个,其实不论是value属性,还是types属性,都可以把数据同时放到session域中,只不过value属性对应的是执行方法中的map集合的键,只要是对应的键,那么其值,也会同时被传递到session域中(这里之所以加上“同时”这个词,是因为它会同时存到request与session中),而types属性,则是放置类的集合,只要map集合中存的是该类的数据,则也会同时被放到request中,下面给示例代码:
如上代码所示,先是在类上面使用了@SessionScope注解,然后同时使用了value与types属性,第一个value属性的值”user”,则是testSessionAtrributes方法中map集合中的”user”的键,所以这一个键值对会被同时放入session域中,而第二个types的属性中的String.class,则是代表着这个类了,意思就是说,只要是map集合中放的String类型的数据,都会被放到session中。
注意:使用了value属性后,这个属性也就必须存在,意思就是说,必须有一个map,然后有一个user的键,不然会报错,当然,这个是可以解决的,后面会详细讲到。
5.4.@SessionAtrribute引发的异常
上一讲说到使用@SessionAtrribute来修饰一个类,就可以把一些值存放到session域中,但是如果找不到对应的值,就会报异常,这里可以用@ModelAtrribute来进行修饰,对它改名就可以了,代码如下:
或者加上一个有着@ModelAtrribute所修饰的方法,至于@ModelAtrribute注解,将会在第六章讲到。
6.1.简单介绍@ModelAtrribute及其运行流程
在我们开发中,会有这样一种情况,比如说我要修改一个人的信息,但是用户名是不让修改的,那么我在浏览器页面中肯定会有一个表单,里面有一个隐藏域的id,可以改密码,可以改邮箱,但是用户名不让修改,所以我们不能给用户名的输入框,然后用户修改完数据后,点击提交保存,然后发现这个时候用户名不见了!当然大家都会想到就是重新取出用户名,然后给这个对象赋值,或者先从数据库里面找到这个用户的对象,然后再来修改这个对象,而不是自己来创建对象,@ModelAtrribute注解就是基于这种情况的。
那么这种情况在springMVC中要如何实现呢?
首先给出执行的目标方法的代码:
这个代码很简单,只是使用Pojo来获取表单的参数,但是User类是不可能从表单得到用户名的,所以这个类就缺少了一个属性,如果这样存到数据库里面,是肯定要出问题的,那么按照之前所说,我们可以先得到这个User对象,然后给这个对象赋值,但是我们有着简化的方法,下面给出@ModelAtrribute注解的用法:
可以发现,上面的类是没有返回值的,但是经有一个map集合,我们把这个从数据库查出来的user对象放到了Map集合中,然后就不需要做什么了,然后上面的
testModelAtrribute方法执行的时候,就会自动把用户名给填充进去。
下面讲一个@ModelAtrribute注解的执行流程
1.执行@ModelAtrribute注解修饰的方法:从数据库中取出对象,并把对象放到了Map中,键为user
2.springMVC从Map集合中取出User对象,并把表单的请求参数赋值给user对象相应的属性
3.springMVC把上述对象传入目标方法的参数
4.这个user对象是存在request中,如果jsp表单中有对应的字段,还会自动填充表单
注意:在@ModelAtrribute修饰的方法中,放入Map时的键要和目标方法的参数名一致
6.2.@ModelAtrribute源代码分析
可以一边调试一边查看源代码,这里的源代码有点多,我就不贴出来了,有兴趣的同学可以自己看,我这里讲诉一下原理:
1.调用@ModelAtrribute注解修饰的方法,实际上是把@ModelAtrribute中的Map放到了implicitModel中。
2.解析请求处理器的标参数,实际上目标参数来自于WebDataBinder对象的target属性
(1).创建WebDataBinder对象
确定objectName属性,若传入的attrName属性为”“,则objectName为类名第一个字母小写
注意:atrributeName,若目标方法的Pojo属性使用了@ModelAtrribute注解来修饰,则atrributeName值即为@ModelAtrribute的value属性值
(2).确定target属性
>在implicitModel中查找atrrName对应的属性值,若存在ok,若不存在,则验证Hander,是否使用了@SessionAtrributes进行修饰,若使用了,则尝试从session中获取attrName所对应的属性值,若session中没有对应的值,则抛出异常
>若Hander没有使用@SessionAtrributes进行修饰,或@SessionAtrributes中没有使用value值指定的键和attrName相互匹配,则通过反射创建了Pojo对象,这个时候target就创建好了。
3.springMVC把表单的请求参数赋给了WebDataBinder的target属性
4.springMVC会把WebDataBinder的attrName和target给到implicitModel
5.把WebDataBinder的target作为参数传递给目标方法的入参
6.3.解决@ModelAtrribute注解中,map集合的键与执行目标方法的参数名不一致的情况
其实我们可以在目标方法里面的参数中,定义一个@ModelAtrribute注解,并把其值指定为@ModelAtrribute注解修饰的方法中的map的键,下面给出代码示例:
可以看到,目标方法的参数中,有着@ModelAtrribute修饰,其value属性为”abc”,再来看一下@ModelAtrribute所修饰的方法:
在这里就可是很显示的看到map是存放了一个”abc”的键。
7.1标签
在springMVC的配置文件中使用标签可以使得url不需要进入handler处理方法,就可以直接跳转页面,配置方法如下
根据如上的配置,就可以直接在浏览器中输入http://localhost:8080/project/good,就可以跳转至success.jsp页面,而无需进入handler处理方法,更不需要进行@RequestMapping映射。
但是如果仅仅是这样的配置,会有一个很大的问题,就是之前所写的handler处理方法全部都不能使用了,全部会进行报错,那么要怎么解决呢?可以在springMVC的配置文件中,写一个下面的标签,就不会有这样的问题了:
只要写上这样的一个标签,那么就可以解决上面的问题,而且也不要写任何参数。不过这个标签具体有什么用呢?后面会作介绍。
7.2.自定义视图
下面来讲一下自定义视图,使用它可以很好的和jfreechar或excel整合,下面来具体说明。
首先新建一个视图,新建一个类,继承view接口,然后覆盖里面的方法,代码如下:
如上所示,写一个类,继承View接口,然后覆盖里面的方法,就可以自己自定义视图了,但是目前这个视图还没有用,需要在springMVC的配置文件中进行配置,才能使用这个视图,配置方法如下:
只要在springMVC的配置文件中写如上的配置,那么这个视图就可以使用了,然后我们写一个handler处理方法,代码如下:
然后的话,我们输入如下url, http://localhost:8080/project/testView,就不会进行helloView.jsp,因为配置的解析视图的order值为最高,也就代表着它的优先级是最低的,所以会先执行我们自定义的视图,那么就会在浏览器中显示之前视图中向浏览器写的数据。
7.4.视图的重定向操作
上面所说的全部都是视图的转发,而不是重定向,这次我来讲一下重定向是怎么操作的。
只要字符串中以forward或者redirect开头,那么springMVC就会把它解析成关键字,然后进行相应的转发,或者重定向操作,下面给出示例代码:
上面就分别是重定向与转发操作,其实不止java代码,标签中的返回视图,也可以加上redirect或者forward字符串,也会进行相应的操作。
8.1 日期格式化
form表单向后台处理方法提交一个参数的时候,如果提交一个日期的数据,而后台接收的数据类型则是Date类型,那么springMVC肯定无法将其转换成,因为springMVC不知道你传的数据的格式是怎么样的,所以需要为接收的字段指定日期的格式,使用@DateTimeFormat注解,使用方法如下:
使用前提:需要在springMVC-servlet.xml的配置文件中配置,这个在开发中肯定会配置的,因为它有好多作用,如果不配置,则下面代码无效:
下面是目标方法的代码:
上面就是在接收的参数前面加了一个@DateTimeFormat注解,注解中写明pattern属性,写上日期的格式,然后在浏览器输入: http://localhost:8080/project/dateFormat?date=19951029,这样springMVC就可以把这个字符串转成Date日期了。
如果是使用Pojo,使用一个对象来接收参数,那么也是一样的,同样是在字段的上方,加上一个@DateTimeFormat注解,如下:
8.2.数字的格式化
除了日期的格式化,我们可能还会遇到数字的格式化,比如会计人员作账时,数字喜欢这样写 1,234,567.8 因为这样简单明了,但是如果由java直接来解析的话,肯定是不行的,因为这根本就不是一个Float类型的数据,肯定是要报错的,那么要如何呢?我们可以使用@NumberFormat()注解,这个注解的使用方式,和使用前提和8.1章节,日期的格式化是一样的,请先查看8.1章节,再看本章。
和之前一样,是肯定要配置的,不过这里就不详细说明了,下面给出执行方法的代码:
其使用方法,其实是和@DateTimeFormat是一样的,但是这里的参数有必要说明一样,”#“是代表数字,那么这个时候,就可以对其进行解析了。如果你传入的是一个正确的Float类型的数据,那么它会被正确的接收这个数字,如果不是一个Float类型的数据,那么springMVC会尝试使用@NumberFoamat注解的参数来尝试解析。
如输入的是http://locathost:8080/project?num=123,那么springMVC会解析成123.0,如果是http://locathost:8080/project?num=123.1,则会正常显示成123.1,那如果是http://locathost:8080/project?num=1,234,567.8这种特殊的写法,则也会正确的解析成1234567.8
8.3.数据的校验
数据的检验是使用Hibernate-validator的扩展注解,它是javaee6.0提出的JSR303的实现,使用它,可以用注解对数据进行校验,下面来说一下使用方法。
1.首先要导入jar包,这不是spring的jar包,需要下载Hibernate-validator的jar包,然后添加到项目工程中
2.其次是要在springMVC的配置文件中,即springMVC-servlet.xml中配置,不需要写其它的属性:
3.然后在字段面前加上对应的校验注解,下面以一个bean作一个简单的例子:
这样就会对使用了注解的字段进行校验,然后这样还不行,还需要指定目标执行方法,所以需要在执行方法上面也加上一个注解@Valid,这样加了这个注解的执行方法就会校验数据,下面给出目标方法的注解:
只要在这个方法上面加上@Valid注解,然后这个执行方法就会校验数据,校验的结果可以使用BindingResult对象显示,这个对象会不仅仅会保存数据校验的结果,还会保存数据类型转换的结果,所以都可以使用这个对象得到相应的信息,显示的方法如下面的代码如示。
注意:需要校验的bean对象与其绑定结果对象或错误对象是成对出现的,他们中间不允许声明其它的参数
8.4.JSR303的验证类型
通过上面的例子我们知道可以使用注解来验证数据类型,但是具体可以使用哪些注解呢,下面给出说明:
8.5.传递json类型的数据
而在springMVC中,使用json非常的简单,但是首先需要引进其它的一些jar包,那就是jackson,这是一个解析json的jar包,然后就可以直接使用了,下面给出代码示例:
如上如示,只要在执行方法的上面加上@ResponseBody注解,然后定义目标方法的返回值,其返回值可以是任意集合,也可以是任意对象,然后springMVC会自动将其转换成json
8.6.文件上传
springMVC也封装了文件上传,变的极其简单,但是需要引入common-io.jar与common.upload.jar包,然后需要在spinrgMVC-serlvet.xml中作如下的配置:
注意:id必须如上写法,不然会报错
然后给出处理方法的代码:
如果是多个文件上传,则改为数组,如果是单个,方式也是一样,与struts2的文件的上传极其的类似。
9.1.第一个拦截器
编写拦截器极其简单,只要编写一个类,实现HandlerInterceptor的方法,然后在springMVC的配置文件中配置这个类,就可以使用这个拦截器了。
首先给出配置文件的写法:
然后再来写FirstInterceptor这个拦截器,代码如下:
然后在每个执行方法调用之前,都会先进拦截器,这就是一个简单的拦截器的写法了。
9.2.拦截器的指定范围
在使用拦截器时候,并不一定要对所有的目标方法都进行拦截,所以我们可以只对指定的方法进行拦截,这就需要更改配置文件了,下面给出配置文件的写法:
只需要在中配置一个,然后指定其路径,就可以了,这个路径可以指定一个URL,也可以使用通配符。
9.3.拦截器的使用顺序
当同时定义了多个拦截器的时候,那么它的使用顺序是怎么样的呢?
preHandle是按配置文件中的顺序执行的
postHandle是按配置文件中的倒序执行的
afterCompletion是按配置文件中的倒序执行的