在MVC中最基本的概念就是:
在SpringMVC中对这些结构进行了封装:
名称 | 含义 |
---|---|
ModelAndView | 在同一个地方可以同时操作Model和View |
ModelMap | 数据承载对象,用于到后面渲染View,在RequestMapping的时候很有用 |
当然对处理流程也进行了封装:
名称 | 含义 |
---|---|
DispatcherServlet | 前置分发控制器,请求统一交给它处理 |
VelocityViewResolver | 通过name查找View |
HandlerInterceptor | 拦截器 |
DefaultAnnotationHandlerMapping | 类级别的@RequestMapping |
AnnotationMethodHandlerAdapter | 方法级别的@RequestMapping |
HandlerMethodArgumentResolver | 参数解析器 |
@RequestMapping | 映射规则 |
@Controller | 注入 |
@ModelAttribute | 被注释的方法在Controller中处理请求的方法之前执行 |
@PathVariable | 获取路径上的变量 |
用的最多的情况就是用户输入URL你给他返回一个页面:
@RequestMapping(value = "/abc") public ModelAndView handle() throws Exception { ModelAndView mv = new ModelAndView("abc"); mv.addObject("key", "abc"); return mv; }
在很多请求的时候需要返回JSON数据,只需要将字符串写出即可:
@RequestMapping(value = "/abc") public void handle(HttpServletResponse response) throws Exception { Map map = Maps.newHashMap(); map.put("123", 123); response.getOutputStream().write(JSON.toJSONString(map).getBytes()); response.getOutputStream().flush(); }
对于文件下载的场景也是类似的,不同之处是要指定文件名等:
@RequestMapping(value = "/abc") public void handle(HttpServletResponse response) throws Exception { OutputStream os = response.getOutputStream(); response.reset(); response.setHeader("Content-Disposition", "attachment; filename=file.txt"); response.setContentType("application/octet-stream; charset=utf-8"); os.write("hello".getBytes()); os.flush(); os.close(); }
从上面可以看到拿到HttpServletResponse之后就可以完全控制住返回值了,在SpringMVC中最简单、直接的获取方式是入参,HandlerMethodArgumentResolver会在解析参数的时候进行处理。在网上有看到用ModelAttribute的方式,这样貌似不是线程安全的吧~
对于HttpServletRequest更简单一些,可以使用RequestContextListener或者RequestContextFilter来做,另外更简单的可以直接注入:
@Resource HttpServletRequest request;
看起来很诡异,这个是如何注入的?其实这里的request只是一个代理,真正的处理过程可以看:
但是找了一圈没找到Response有类似的方法,所以,这种方式对Response可能行不通。其实我们自己也可以实现类似的功能,比如用HandlerInterceptor来搞:
public interface HandlerInterceptor { // 在方法之前执行 boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; // 在方法之后执行 void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; // 在请求处理完成的时候执行 void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;
我们在preHandle的时候将Request、Response写入ThreadLocal,用FactoryBean来在注入的时候生成代理对象,在调用代理对象的时候先从ThreadLocal中获取对象,再反射调用对象的方法。
从URL到Controller中的方法的映射也是一个需要注意的地方:
设置 | 匹配 |
---|---|
@RequestMapping(value = “/abc”) | /abc、/abc.*、/abc/ |
@RequestParam(“id”) | 限制参数中必须有id,并将其放到入参中 |
@RequestMapping(value = “/abc/{id}”) | REST风格,用@PathVariable(“id”)放到入参 |
@RequestMapping(value = “/{path:[0-9a-z-]+}”) | 支持正则表达式 |
@RequestMapping(method = RequestMethod.GET) | 方法过滤 |
@RequestMapping(params = “123”) | 参数过滤 |
@RequestMapping(headers = “abc”) | 头信息过滤 |
@RequestMapping(consumes = “application/json”) | 处理请求的提交内容类型过滤 |
@RequestMapping(produces = “application/json”) | 返回的内容类型过滤 |
在SpringMVC中整体的处理逻辑都在DispatcherServlet中完成,处理逻辑如下:
总体看下来比webx简单、好用一些。