本文章将从两种配置方式讲起,一般根据项目需求选择合适的方式:
- 非注解的配置方式(基于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();
}
}
注:不在springmvc.xml中设置HandlerMapping和HandlerAdapter,程序依然会照常运行。其原因是它会默认执行SpringMVC所依赖jar包中的一个默认配置文件DispatcherServlet.properties,其默认映射器为BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping,默认的适配器为HttpRequestHandlerAdapter和AnnotationMethodHandlerAdapter。
2.注解的处理器映射器和适配器
优点:非注解有一个缺陷,就是一个Handler类中只能编写一个方法,这对于大量请求处理逻辑就会捉襟见肘了,而这种问题通过注解的方式就可以轻松解决。
- Spring3.1之前,SpringMVC的默认注解HandlerMapping和HandlerAdapter分别是:DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdapter,位于org.springframework.web.servlet.mvc.annotation核心包下。
- Spring3.1之后,之前的默认注解已经被列为过期,基本不再使用,其增加了新的基于注解的HandlerMapping和HandlerAdapter,分别是:RequestMappingHandlerMapping、RequestMappingHandlerAdapter,位于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
成功结果:
注意:如果测试过程中出现“java.lang.IllegalArgumentException”,则说明使用了JDK 8.0的环境,由于Spring 3.x版本不支持JDK8.0,因此需要更换编译环境。