SpringMVC[3]--处理器映射器和适配器

本文章将从两种配置方式讲起,一般根据项目需求选择合适的方式:

  • 非注解的配置方式(基于XML的资源配置)
  • 注解的配置方式(基于Annotation注解的配置)
    补:注解是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,以执行相应的处理。

1. 非注解的处理器映射器和适配器

1.1 非注解的处理器映射器(HandlerMapping)

  • BeanNameUrlHandlerMapping
     映射规则:将bean的name作为url进行查找,需要在配置Handler时指定bean name(即url)。
    样例:
<!--配置合适的处理器映射器(HandleMapping)-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--可以被url映射的Handler的bean-->
<bean name="/queryFruits_test.action" class="cn.com.mvc.controller.FruitsControllerTest"/>
  • SimpleUrlHandlerMapping
     映射规则:通过内部参数配置请求的url和handler的映射关系。
    样例:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="someCheckInterceptor1"/>
            <ref bean="someCheckInterceptor2"/>
        </list>
    </property>
    <property name="mappings">
        <props>
            <prop key="user.action">userController</prop>
            <prop key="product.action">productController</prop>
            <prop key="other.action">otherController</prop>
        </props>
    </property>
</bean>

 上面代码中,可以通过property属性配置拦截器和相关的Handler处理器的URL的映射关系。在样例中添加了两个拦截器配置,和三个Handler处理器的URl映射。
针对前一篇文章的具体事例:

<!--这里没用到拦截器-->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/queryFruits_test.action">fruitsController</prop>
        </props>
    </property>
</bean>

<bean id="fruitsController" class="cn.com.mvc.controller.FruitsControllerTest"/>

访问 localhost:8080/queryFruits_test.action就可以执行对应的controller

  • ControllerClassNameHandlerMapping
     映射规则:可以使用CoC惯例优先原则(conventionover configuration)的方式来处理请求,对于普通的Controller,会把其类名“xxxController”映射到“/xxx”的请求URL。对于MultiActionController类型的Controller,ControllerClassNameHandlerMapping会把其类名“xxxController”以及其中的方法“yyy”映射到“/xxx/yyy.action”(.action对应设置的dispatcher-servlet的url-pattern)的请求URL。
    样例:
<bean class="org.sprigframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

1.2 非注解的处理器适配器(HandlerAdapter)

  • SimpleControllerHandlerAdapter
    其支持所有实现了Controller接口的Handler控制器。
    例如:
public class FruitsControllerTest implements Controller{
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //模拟Service获取水果商品列表
        FruitsService fruitsService = new FruitsService();
        List<Fruits> fruitsList = fruitsService.queryFruitsList();
        //返回ModelAndView
        ModelAndView modelAndView = new ModelAndView();
        //相当于request的setAttribut,在JSP页面中通过fruitsList获取数据
        modelAndView.addObject("fruitsList",fruitsList);
        //指定视图
        modelAndView.setViewName("fruitsList");
        return modelAndView;
    }
}
<!--配置处理器映射器(HandleMapping)-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--配置处理器适配器(HandlerAdapter)-->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/queryFruits_test.action">fruitsController</prop>
        </props>
    </property>
</bean>

<bean id="fruitsController" class="cn.com.mvc.controller.FruitsControllerTest"/>

这里例子的详细内容上一节有讲: SpringMVC[2]--框架搭建

  • HttpRequestHandlerAdapter
package cn.com.mvc.controller;

import cn.com.mvc.model.Fruits;
import cn.com.mvc.service.FruitsService;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class FruitsControllerTest2 implements HttpRequestHandler {

    private FruitsService fruitsService = new FruitsService();
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //模拟Service获取水果列表
        List<Fruits> fruitsList = fruitsService.queryFruitsList();
        //设置模型数据
        request.setAttribute("fruitsList",fruitsList);
        //设置转发视图
        request.getRequestDispatcher("/WEB-INF/jsp/fruitsList.jsp").forward(request, response);
    }
}

HandlerMapping中添加配置:

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/queryFruits_test1.action">fruitsController</prop>
            <prop key="/queryFruits_test2.action">fruitsController2</prop>
        </props>
    </property>
</bean>
<bean id="fruitsController" class="cn.com.mvc.controller.FruitsControllerTest"/>
<bean id="fruitsController2" class="cn.com.mvc.controller.FruitsControllerTest2"/>

访问地址:localhost:8080/queryFruits_test2.action

这里还可以讲List信息拼接为JSON串,然后以JSON格式返回给用户,并使用response的writer对象直接写出返回数据:

package cn.com.mvc.controller;

import cn.com.mvc.model.Fruits;
import cn.com.mvc.service.FruitsService;
import org.springframework.web.HttpRequestHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class FruitsControllerTest2 implements HttpRequestHandler {

    private FruitsService fruitsService = new FruitsService();
    @Override
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //模拟Service获取水果列表
        List<Fruits> fruitsList = fruitsService.queryFruitsList();
        //将fruitsList转换为JSON串
        String jsonInfo = convertListToJson(fruitsList);
        //设置返回格式
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        //写出JSON串
        response.getWriter().write(jsonInfo);
    }

    private String convertListToJson(List<Fruits> fruitsList){
        StringBuilder builder = new StringBuilder();
        builder.append('[');
        for (Fruits fruits: fruitsList){
            builder.append('{');
            builder.append("\"name\":\"").append(fruits.getName()).append("\",");
            builder.append("\"prive\":\"").append(fruits.getPrice()).append("\",");
            builder.append("\"producing_area\":\"").append(fruits.getProducing_area()).append("\"");
            builder.append("},");
        }
        builder.deleteCharAt(builder.length()-1);
        builder.append(']');
        return builder.toString();
    }
}
URL请求处理结果.png

注:不在springmvc.xml中设置HandlerMapping和HandlerAdapter,程序依然会照常运行。其原因是它会默认执行SpringMVC所依赖jar包中的一个默认配置文件DispatcherServlet.properties,其默认映射器为BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,默认的适配器为HttpRequestHandlerAdapter和AnnotationMethodHandlerAdapter。

2.注解的处理器映射器和适配器

优点:非注解有一个缺陷,就是一个Handler类中只能编写一个方法,这对于大量请求处理逻辑就会捉襟见肘了,而这种问题通过注解的方式就可以轻松解决。

  • Spring3.1之前,SpringMVC的默认注解HandlerMapping和HandlerAdapter分别是:DefaultAnnotationHandlerMappingAnnotationMethodHandlerAdapter,位于org.springframework.web.servlet.mvc.annotation核心包下。
  • Spring3.1之后,之前的默认注解已经被列为过期,基本不再使用,其增加了新的基于注解的HandlerMapping和HandlerAdapter,分别是:RequestMappingHandlerMappingRequestMappingHandlerAdapter,位于org.springframework.web.servlet.mvc.method.annotation核心包下

2.1配置注解的处理器适配器和映射器,有两种配置方式:

  • 第一种配置方式
    和之前的非注解配置方式一样,声明相关的bean及实现即可:
<!--注解映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--注解适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
  • 第二种配置方式
    使用 <mvc:annotation-driven/> 标签来配置,该标签会自动注册处理器映射器和适配器。
    在实际开发中,为了提高开发效率,使用最多的就是annotation-driver标签的配置。
<mvc:annotation-driven/>

2.2 开发Handler处理器层

package cn.com.mvc.controller;

import cn.com.mvc.model.Fruits;
import cn.com.mvc.service.FruitsService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

//注解的Handler类
//使用@Controller来标记它是一个控制器
@Controller
public class FruitsControllerTest3 {

   private FruitsService fruitsService = new FruitsService();
   //商品查询列表
   //@RequestMapping实现对queryFruitsList方法和url进行映射,一个方法对应一个url
   //一般建议url和方法名写成一样
   @RequestMapping("/queryFruitsList")
   public ModelAndView queryFruitsList() throws Exception{
       //模拟Service获取水果商品列表
       List<Fruits> fruitsList = fruitsService.queryFruitsList();
       //返回ModelAndView
       ModelAndView modelAndView = new ModelAndView();
       //相当于request的setAttribute,在JSP页面中通过fruitsList获取数据
       modelAndView.addObject("fruitsList",fruitsList);
       //指定视图
       modelAndView.setViewName("fruitsList");

       return  modelAndView;
   }
}

2.3 让注解的HandlerMapping和HandlerAdapter找到注解Handler

有种方式实现,都是在springmvc.xml配置文件中天蝎配置信息:

  • 方法一
<bean class="cn.com.mvc.controller.FruitsControllerTest3"/>
  • 方法二
<context:component-scan base-package="cn.com.mvc.controller"></context:component-scan>

访问地址:localhost:8080/queryFruitsList.action
成功结果:


使用注解测试结果.png

注意:如果测试过程中出现“java.lang.IllegalArgumentException”,则说明使用了JDK 8.0的环境,由于Spring 3.x版本不支持JDK8.0,因此需要更换编译环境。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容