MyBatis+Spring MVC开发指南(四)
前言
这篇博客是这个系列的最后一篇,涉及Spring+Spring MVC+MyBatis之间的整合、Controller的写法分析、异常处理、JSON交互,RESTful支持、拦截器等。
Spring、Spring MVC、MyBatis整合思路分析
Spring、Spring MVC、MyBatis集成原理图在这里,我并不会给出Spring/Spring MVC/MyBatis整合的每一个细节,而是分析它们整合的思路!
第一,我们需要让Spring整合Web,说白了就是让Spring管理Bean,并进行依赖注入等。方法很简单,就是在web.xml配置一个listener让它去加载Spring的配置文件。
第二,我们需要让Spring MVC整合Web,就是在web.xml中去配置前端控制器,指明Spring MVC的配置文件在哪里及servlet-mapping。
第三,要知道Spring MVC是Spring的一个web模块而已,它们之间无需整合。
第四,要整合MyBatis,其实就是把SqlSessionFactoryBean以及Mapper接口的管理交给Spring。
第五,注意注解的配置,想一想涉及哪些呢?
比如,Spring MVC基于注解的处理器映射器、处理器适配器;
比如,Spring IOC涉及到的注解、以及组件注解等;
总结来说,就是Spring负责Mapper、Service、Controller的管理(实例化以及依赖注入),还会对Service进行事务控制,可见Spring就是整合的核心!
分析:Controller到底该如何写?
Controller类,首先来说,应该打上@Controller注解,同时应该让Spring可以扫描到。
为了对url进行分类管理,可以在Controller上打上@RequestMapping注解。
我们知道HTTP请求,常用的有POST和GET2种方式,那么可以在方法上利用@RequestMapping进行限定。
Spring MVC是基于方法链的,那么Controller的方法定义就很特别了。特别在哪里呢?
参数需要绑定(@RequestParam),甚至是需要完成自定义的转化后在绑定;(如不使用注解需要参数名称一致;自定义参数绑定需要实现Converter接口并进行相关配置,要知道HandlerApdater是执行Handler的,所以应该配置到处理器适配器上)
是否有的参数可以不用传递?或者可以指定默认值呢?
对于数组、集合、MAP等这些复杂的类型,参数绑定需要注意什么呢?(List/Map的绑定,必须借助POJO,也就是说POJO中要存在List/Map属性才可以绑定)
参数校验如何做呢?(使用@Validated,并在处理器适配器上进行配置)
对于形参列表,哪些有着特殊的含义?(Model/ModelMap/HttpServletRequest/HttpServletResponse/HttpSession这些可以直接使用!)
对于形参列表中的POJO,Spring MVC会自动的放置到request域,并可以通过@ModelAttribute来指定key;而对于形参列表中的简单类型,Spring MVC并没有这样做。无论何时,都不要忘了最简单的方式:通过Model的addAttribute方法可以直接设置数据到request域!
方法的返回值,可以返回ModelAndView,还可以返回什么呢?JSON该如何返回?可不可以返回void呢?(要么是返回逻辑视图,可以ModelAndView指定,也可以通过返回String指明逻辑视图;要么是返回响应流数据,比如通过AJAX请求JSON数据。)
如何实现重定向呢?(默认的ModelAndView就是forward的,重定向的话需要明确指明redirect;注意重定向意味着URL地址栏发生变化且Request域失效)
上面的分析,不禁让人想到了以前Struts2的Action开发,那么Spring MVC和Struts2有哪些区别呢?
第一,直观上来说,Spring MVC基于方法开发,而Struts2基于类开发;
第二,从参数绑定来看,Struts2是基于类的成员变量进行绑定的,为了避免多线程问题,是多例的;而Spring MVC可以看到都是绑定到方法的形参列表上,方法执行完毕就销毁了,可见Spring MVC是基于单例的!而且有一点你一定有感触,那就是Struts2的Action中的成员变量实在是太多了,而且到底哪些变量被哪些方法所使用到,并不能一目了然,而Spring MVC却帮助我们做到了!
第三,以前工作中,有时候就会收到Struts2需要升级的邮件,因为存在的一些漏洞和安全隐患;而Spring MVC使用这么久呢,还没听到这些“负面新闻”!
Spring MVC如何进行异常处理?
异常处理框架通过上图,相信你会明白,Spring MVC通过提供一个全局的异常处理器进行统一的异常处理。具体做法如下:
第一,定义好你的系统的一些异常类型(extends Exception)
第二,定义一个全局的异常处理器(实现HandlerExceptionResolver接口),在这里,我们可以进行异常类型判断,ModelAndView设置等
第三,在spring-mvc.xml配置中,通过<bean>标签加载这个异常处理器即可。
JSON交互
@ResponseBodySpring MVC对JSON的支持,无非表现在2个方面:
第一,请求过来的是JSON数据类型,那么Spring MVC可以将其转化为Java对象;
第二,Spring MVC可以把Java对象转化成JSON予以客户端响应;
在实际开发中,用的最多的就是把Java对象转成JSON返回给客户端。
实际上,在基于注解的处理器适配器中已经默认支持了对JSON的处理,所以无需我们做其他配置了!
Spring MVC使用jackson进行JSON处理,因此需要加入jackson的依赖(jackson-core-asl、jackson-mapper-asl)。
说白了,@ResponseBody都干了些什么呢?
无非就是往response的流中写了点JSON数据,并告诉浏览器我给你的是JSON数据类型喔(application/json),仅此而已!
与@ResponseBody对应的,就是@RequestBody,无非就是把请求类型为JSON的数据转化成对应的Java对象而已。
RESTful支持
RESTful,即Representational State Trasfer,本质上就是HTTP开发理念而已。
它其实对HTTP开发主要提出了3点规范:
第一,对URL进行规范
非RESTful风格: http://.../findUserById.do?id=xxx
RESTful风格: http://.../user/xxx
你可以看到,RESTful风格的URL不在存在KEY/VALUE了。
第二,HTTP的方法进行规范
如果是查询user,那么使用GET方法;如果是新增,那么使用POST;如果是删除,使用delete方法。
到这里,你应该有点感触了,那就是说我们访问一个URL,需要通过不同的HTTP METHOD来进行区分处理。这个就有点麻烦了,实质上,在实际开发中,能够做到这一点的,太少了!
第三,对HTTP的content-type进行规范
也就是说,在请求的时候,就指定了需要响应的content-type。
目前,对RESTful的应用大都停留在第一点。
上面,介绍了RESTful的一些概念,那么Spring MVC该如何支持呢?
第一,要知道RESTful不存在KEY/VALUE,那么显然,我们需要将http://.../user/xxx中的xxx映射到形参列表上。
因此,对于@RequestMapping而言,需要使用{xxx}这种占位符,然后在利用@PathVariable("xxx")进行绑定到形参上。
第二, 你应该发现了RESTful这种风格的URL是没有后缀的(什么.do .action都没有了),那么我们的前端控制器的URL映射只能配置成/了,那么问题就来了。什么问题呢,就是对静态资源的访问问题。
需要修改web.xml指明CSS/JS/IMG等静态资源的处理方式。(网上例子很多,这里我主要谈思路,就不多说了)
拦截器
HandlerInterceptor接口拦截器,有很多应用场景,比如用户认证、统一日志处理等。
自定义拦截器需要实现HandlerInterceptor接口,提供3个方法的实现。这3个方法,顾名思义,不过需要注意的是preHandle返回的是boolean,也就是说如果返回false,那么postHandler/afterCompletion不会执行。
在拦截器中,我们可以通过request获取URL,获取Session中的用户数据,还可以设置跳转地址等。
注意拦截器需要配置,也就是说我们需要对什么样的URL进行拦截,如果放行才让HandlerAdapter去执行Handler。(在Spring MVC配置XML中使用<mvc:interceptors>即可)