首页 > 编程语言 > 详细

Spring MVC -- 基于注解的控制器

时间:2019-05-06 22:28:57      阅读:214      评论:0      收藏:0      [点我收藏+]

Spring MVC -- Spring MVC入门中,我们创建了两个采用传统风格控制器的Spring MVC应用程序,其控制器是实现了Controller接口。Spring 2.5版本引入了一个新途径:使用控制器注释类型。本篇博客将介绍基于注解的控制器,以及各种对应用程序有用的注解类型。

一 Spring MVC注解类型

使用基于注解的控制器具有以下优点:

  • 一个控制器可以处理多个动作(而实现了Controller接口的一个控制器只能处理一个动作)。这就允许将相关的操作写在同一个控制器类中,从而减少应用程序中类的数量;
  • 基于注解的控制器的请求映射不需要存储在配置文件中。使用RequestMapping注释类型,可以对同一个方法进行请求处理;

Controller和RequestMapping注解类型是Spring MVC API最重要的两个注解类型,本节将会重点介绍着两个,并简要介绍一些其它不太流行的注解类型。

1、Controller注解类型

org.springframework.stereotype.Controller注解类型位于spring-context-x.x.x.RELEASE.jar包下,用于指示Spring类的实例是一个控制器。下面是一个带注解@Controller的例子:

package com.example.controller;

import org.springframework.stereotype.Controller;
...

@Controller
public class CustomerController {
    //request-handing methods here
}

Spring使用扫描机制来找到应用程序中所有基于注解的控制器类。为了保证Spring能找到控制器,需要完成两件事情:

1)需要在Spring MVC的配置文件中声明,spring-context,如下所示:

<beans 
   ...
  xmlns:context="http://www.springframework.org/schema/context"
   ...
>
... </beans
>

2)需要应用<component-scan/>元素,如下所示:

<context:component-scan base-package="basePackage"/>

请在<component-scan/>元素中指定控制器类的基本包。例如,若所有的控制器类都在com.example.controller及其子包下,则需要编写一个如下所示的<component-scan/>元素:

<context:component-scan base-package="com.example.controller"/>

现在整个在配置文件看上去如下所示:

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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.xsd">
    <context:component-scan base-package="com.example.controller"/>    
</beans>

清确保所有控制器类都在基本包下,并且不要指定一个太广泛的基本包,因为这样会使得Spring MVC扫描了无关的包。

2、RequestMapping注解类型

现在,我们需要在控制器器类的内部为每一个动作开发相应的处理函数。要让Spring知道用哪一种方法来处理它的动作,需要使用org.springframework.web.bind.annotation.RequestMapping注解类型来将动作映射到相应的处理函数。

RequestMapping注解类型的作用同其名字所暗示的:将一个请求映射到一个方法。使用@RequestMapping注解一种方法(或者类)。

一个采用@RequestMapping注解的方法将成为一个请求处理方法,并由调度程序在接收到对应URL请求时调用。

下面是一个控制器类,使用@RequestMapping注解了inputCustomer()方法:

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class CustomerController {

    @RequestMapping(value="/input-customer")
    public String inputCustomer() {
        //do something   here
        return "CustomerForm";
    }
}

使用RequestMapping注解的value属性将URL映射到方法。在上面的例子中,我们将input-customer映射到inputCustomer()方法。这样可以使用如下URL访问inputCustomer()方法:

http://domain/context/input-customer

由于value属性是RequestMapping注解的默认属性,因此,若只有唯一的属性,则可以省略属性名称。话句话说,如下两个标注含义相同:

@RequestMapping(value="input-customer")
@RequestMapping("input-customer")

但是有多个属性时,就必须写入value属性名称。

请求映射的值value可以是一个空字符串,此时该方法被映射到以下网址:

http://domain/context

RequestMapping除了具有value属性外,还有其它属性。例如,method属性用来指示该方法仅处理哪些HTTP方法。

例如,仅当在HTTP POST或PUT方法时,才访问到下面的processOrder()方法:

...
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
...
    @RequestMapping(value="/process-order",
               method={RequestMethod.POST,RequestMethod.PUT})
    public String processOrder() {
        //do something   here
        return "OrderForm";
    }
...

若method属性只有一个HTTP方法值,则无需花括号,例如:

@RequestMapping(value="/process-order",method=RequestMethod.POST)

如果没有指定method属性值,则请求处理方法可以处理任意HTTP方法。

此外,RequestMapping注解类型也可以用来注解一个控制器类,如下所示:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
... 
@Controller 
@RequestMapping(value="/customer") 
public class CustomerController {
   ... 
}

在这种情况下,所有的方法都将映射为相对于类级别的请求。例如,下面的deleteCustomer()方法:

...
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
...
@Controller
@RequestMapping(value="/customer")
public class CustomerController {

    @RequestMapping(value="/delete",
             method={RequestMethod.POST,RequestMethod.PUT})
    public String deleteCustomer() {
        //do something here
        return ...;
    }
}    

由于控制器类的映射使用"/customer",而deleteCustomer()方法映射为"/delete",则如下URL方法会映射到deleteCustomer()方法上:

http://domain/context/customer/delete

二 编写请求处理方法

每个请求处理方法可以有多个不同类型的参数,以及一个多种类型的返回结果。例如,如果在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确的传递给方法:

   @RequestMapping(value="/uri")
    public String myMethod(HttpSession session) {
        ...
        session.addAttribute(key,value);
        ...
    }

或者,如果需要访问客户端语言环境和HttpServletRequest对象,则可以在方法签名上包括这样的参数:

   @RequestMapping(value="/uri")
    public String myOtherMethod(HttpServletRequest request,Locale locale) {
        ...
        //access Locale and HttpServletRequest here
        ...
    }

下面是可以在请求处理方法中出现的参数类型:

  • javax.servlet.ServletRequest或javax.servlet.http.HttpServletRequest;
  • javax.servlet.ServletResponse或javax.servlet.http.HttpServletResponse;
  • javax.servlet.http.HttpSession;
  • org.springframework.web.context.request.WebRequest或org.springframework.web.context.request.NativeWebRequest;
  • java.util.Locale;
  • java.io.InputStream或java.io.Reader;
  • java.io.OutputStream或java.io.Writer;
  • java.security.Principal;
  • HttpEntity<?>paramters;
  • org.springframework.ui.Model;
  • org.springframework.ui.ModelMap;
  • org.springframework.web.servlet.mvc.support.RedirectAttributes.;
  • org.springframework.validation.Errors;
  • org.springframework.validation.BindingResult;
  • 命令或表单对象;
  • org.springframework.web.bind.support.SessionStatus;
  • org.springframework.web.util.UriComponentsBuilder;
  • 带@PathVariable、@MatrixVariable、@RequestParam、@RequestHeader、@RequestBody或@RequestPart注解的对象;

特别重要的是org.springframework.ui.Model类型。这不是一个Servlet API类型,而是一个包含java.util.Map字段的Spring MVC类型。每次调用请求处理方法时,Spring MVC都创建Model对象,用于增加需要显示在视图中的属性,这些属性就可以像被添加到HttpServletRequest那样访问了。。

请求处理方法可以返回如下类型的对象:

  • ModelAndView;
  • Model;
  • 包含模型的属性的Map;
  • View;
  • 代表逻辑视图名的String;
  • void;
  • 提供对Servlet的访问,以响应HTTP头部和内容HttpEntity或ReponseEntity对象;
  • Callable;
  • 其它任意类型,Spring将其视作输出给View的对象模型;

三 应用基于注解的控制器

本节将创建一个名为annotated1的应用,展示了包含有两个请求处理方法的一个控制器类。该应用和Spring MVC -- Spring MVC入门中应用的主要区别是:annotated1的控制器类使用了注解@Controller,而不是实现Controller接口。此外,Spring配置文件也增加了一些元素。

1、目录结构

annotated1应用的目录结构如下:

技术分享图片

注意:annotated1应用只有一个控制器类,而不是两个。

2、配置文件

 annotated1应用由两个配置文件:

  • 第一个为部署描述符(web.xml文件)中注册Spring MVC的DispatcherServlet;
  • 第二个为springmvc-config.xml,即Spring MVC的配置文件;

部署描述符(web.xml文件):

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 
        xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
            http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
            
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/springmvc-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>    
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

在部署描述符中的<servlert-mapping/>元素,Spring MVC的DispatcherServlet的URL模式设置为"/",因为这所有的请求(包括那些用于静态资源)都被映射到DispatcherServlet。为了正确处理静态资源需要在Spring MVC配置文件中添加一些<resources/>元素

Spring MVC配置文件(springmvc-servlet.xml):

<?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:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd     
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="controller"/>
    <mvc:annotation-driven/>
    <mvc:resources mapping="/css/*" location="/css/"/>
    <mvc:resources mapping="/*.html" location="/"/>
    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

Spring MVC的配置文件中最主要的是<component-scan/>元素,这是要指示Spring MVC扫描目标包中的控制器类,本例是controller包。

接下来是<annotation-driven/>元素,该元素做了很多事情,其中包括注册用于控制器注解的bean对象;

最后是<resources/>元素,用于指示Spring MVC哪些静态资源需要单独处理(不通过DispatcherServlet)。

在上面的配置中,有两个<resources/>元素。第一个确保在/css目录下的所有文件可见,第二个允许显示所有的/.html文件。

注意:如果没有<annotation-driven/>元素,<resources/>元素会阻止任意控制器被调用。若不需要使用<resources/>元素,则不需要<annotation-driven/>元素元素。

3、Controller类

如前所述,使用Controller注解类型的一个优点在于:一个控制器类可以包含多个请求处理方法。ProductController类中有inputProduct()和saveProduct()两个请求处理方法:

package controller;

import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import domain.Product;
import form.ProductForm;

@Controller
public class ProductController {

    private static final Log logger = LogFactory.getLog(ProductController.class);

    @RequestMapping(value="/input-product")
    public String inputProduct() {
        logger.info("inputProduct called");
        return "ProductForm";
    }

    @RequestMapping(value="/save-product")
    public String saveProduct(ProductForm productForm, Model model) {
        logger.info("saveProduct called");
        // no need to create and instantiate a ProductForm
        // create Product
        Product product = new Product();
        product.setName(productForm.getName());
        product.setDescription(productForm.getDescription());
        try {
            product.setPrice(new BigDecimal(productForm.getPrice()));
        } catch (NumberFormatException e) {
        }

        // add product

        model.addAttribute("product", product);
        return "ProductDetails";
    }
}

其中saveProduct()方法的第二个参数是org.springframework.ui.Model类型。无论是否会使用,Spring MVC都会在每一个请求处理方法被调用时创建一个Model实例,用于增加需要显示在视图中的属性。例如,通过调用model.addAttribute()来增加Product对象:

        model.addAttribute("product", product);

Product对象就可以像被添加到HttpServletRequest那样访问了。

4、视图

annotated1应用程序包含两个jsp页面:ProductForm.jsp页面和ProductDetails页面:

ProductForm.jsp:

<!DOCTYPE HTML>
<html>
<head>
<title>Add Product Form</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>

<div id="global">
<form action="save-product" method="post">
    <fieldset>
        <legend>Add a product</legend>
        <p>
            <label for="name">Product Name: </label>
            <input type="text" id="name" name="name" 
                tabindex="1">
        </p>
        <p>
            <label for="description">Description: </label>
            <input type="text" id="description" 
                name="description" tabindex="2">
        </p>
        <p>
            <label for="price">Price: </label>
            <input type="text" id="price" name="price" 
                tabindex="3">
        </p>
        <p id="buttons">
            <input id="reset" type="reset" tabindex="4">
            <input id="submit" type="submit" tabindex="5" 
                value="Add Product">
        </p>
    </fieldset>
</form>
</div>
</body>
</html>

ProductDetails.jsp:

<!DOCTYPE HTML>
<html>
<head>
<title>Save Product</title>
<style type="text/css">@import url(css/main.css);</style>
</head>
<body>
<div id="global">
    <h4>The product has been saved.</h4>
    <p>
        <h5>Details:</h5>
        Product Name: ${product.name}<br/>
        Description: ${product.description}<br/>
        Price: $${product.price}
    </p>
</div>
</body>
</html>

ProductDetails页面通过EL表达式语言访问product对象的各种属性。

main.css:

技术分享图片
#global {
    text-align: left;
    border: 1px solid #dedede;
    background: #efefef;
    width: 560px;
    padding: 20px;
    margin: 100px auto;
}

form {
  font:100% verdana;
  min-width: 500px;
  max-width: 600px;
  width: 560px;
}

form fieldset {
  border-color: #bdbebf;
  border-width: 3px;
  margin: 0;
}

legend {
    font-size: 1.3em;
}

form label { 
    width: 250px;
    display: block;
    float: left;
    text-align: right;
    padding: 2px;
}

#buttons {
    text-align: right;
}
#errors, li {
    color: red;
}
View Code

5、测试应用

将项目部署到tomcat服务器,然后启动服务器,假设示例应用运行在本机的8000端口上,则可以通过如下URL访问应用:

http://localhost:8008/annotated1/input-product

会看到如下产品表单页面:

 技术分享图片

在表单中输入相应的值后单击Add Product按钮,会调用saveProduct()方法,在下一页中看到产品属性:

技术分享图片

参考文章

[1]Spring MVC学习指南

Spring MVC -- 基于注解的控制器

原文:https://www.cnblogs.com/zyly/p/10819732.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!