1)用 @Controller 定义一个控制器
注解 @Controller 指定一个特定的类担任控制器的角色。Spring 不要求你集成任何控制器基类或者引用 Servlet API。不过,你仍然可以根据需要使用指定的 Servlet 特性。
注解 @Controller 对于被注解的类来说就像一个模板(stereotype),指示它的角色。收发器(dispatcher)为被映射的方法扫描被注解的类,并检测注解 @RequestMapping(见下一部分)。
你可以在分发器的上下文中使用标准的 Spring Bean 定义,来显式地定义被注解的控制器。不过,@Controller 模板也允许自动检测,就像 Spring 通常支持的在类路径中自动检测组件类并自动为它们注册 Bean 定义。
为了能够自动检测到这样被注解的控制器,你要添加组件扫描到你的配置中。像下面的 XML 片段那样使用 Spring 的 context'命名空间:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<context:component-scan base-package="com.techmap.examples.controllers" />
......
</beans>
2)使用 @RequestMapping 映射请求
使用注解 @RequestMapping 映射一个 URL(比如:/contex)到一个类或者一个特定的处理方法上。典型地,类级别的注解映射一个指定的请求路径(或者是路径匹配模式)到一个控制器,使用额外的方法层注解缩小主要映射的范围。
下面是一个例子:
package com.techmap.examples.controllers;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/contex")
public class ContexController
{
/**
* 不指定 path 参数
*/
@RequestMapping(method = RequestMethod.GET)
public String get1()
{
return "/examples/targets/test1";
}
/**
* 带有 path 参数
*/
@RequestMapping(path = "/new", method = RequestMethod.GET)
public String get2()
{
return "/examples/targets/test2";
}
/**
* 带有 URI 模板
*/
@RequestMapping(path = "/{day}", method = RequestMethod.GET)
public String getForDay(@PathVariable @DateTimeFormat(iso = ISO.DATE) Date day, Model model)
{
System.out.println("--> " + new SimpleDateFormat("yyyy-MM-dd").format(day));
return "/examples/targets/test3";
}
}
3)测试例子
为使得例子可用,在上一篇的项目中添加下面三个 jsp 文件:test1.jsp、test3.jsp、test3.jsp。内容如下:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%
String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request
.getServerPort() + request.getContextPath() + "/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=basepath%>">
</head>
<body>
<h2>Test 1</h2>
</body>
</html>
代码中只有 test1.jsp,其他两个内容相同,只有<h2>中的内容不同,test2.jsp 中是<h2>Test 2</h2>,test3.jsp中是<h2>Test 3</h2>。它们所在的目录是:
4)改造一下 helloWorld.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%
String basepath = request.getScheme() + "://" + request.getServerName() + ":" + request
.getServerPort() + request.getContextPath() + "/";
%>
<!DOCTYPE html>
<html>
<head>
<base href="<%=basepath%>">
</head>
<body>
<h2>Hello World!</h2>
<h2>Test Controller</h2>
<a href="contex">Test1</a><br>
<a href="contex/new">Test2</a><br>
<a href="contex/2016-09-05">Test3</a><br>
</body>
</html>
5)开始测试
用上一篇中给出的路径进入 helloWorld.jsp,看到如下页面:
分别点击超链接 Test1、Test2、Test3,将会跳到上面定义的三个 test*.jsp 页面。值得注意的是,点击 Test3 时,控制台会打印出如下的信息:
...
DEBUG 2016-09-05 08:15:23,152 Last-Modified value for [/spring5mvc/contex/2016-09-05] is: -1 (DispatcherServlet.java:951)
--> 2016-09-05
DEBUG 2016-09-05 08:15:23,219 Invoking afterPropertiesSet() on bean with name '/examples/targets/test3'
...
这说明<a href="contex/2016-09-05">Test3</a>
中的日期字符串将作为参数传递到参数 day 上。
6)说明
在上面的例子中,注解 @RequestMapping 被用在了多处。第一处是类级别的,它指出这个控制器中的所有方法都与路径 /contex 相关。方法get1()上有一个 @RequestMapping 来进一步细化:它只接受 GET 请求,这意味着 HTTP GET 请求 /contex 将调用这个方法。方法 get2() 有一个相似的细化;方法 get2() 把 HTTP 方法定义和路径合并到了一起,这样 GET 请求 /contex/new 就可以被这个方法处理了。
方法 getForDay() 展示了另一种使用 @RequestMapping 的方式:URI 模板(后面介绍)。
像第一、二篇给出的 Hello World 例子那样,类级别的 @RequestMapping 不是必须的。没有它,所有的路径都是简单的绝对路径,而不是相对的。如果不指定 GET、PUT、POST 等,@RequestMapping 默认映射所有的HTTP方法。