学习SpringMVC——通过注解使用SpringMVC

来源:互联网 发布:上瘾网络剧花絮视频 编辑:程序博客网 时间:2024/06/05 20:29

在上一篇博客中,写了一个简单的SpringMVC应用,其中的处理器适配器、处理器映射器、控制类/handler都是通过xml标签配置的。抛开配置的繁琐不说,基于xml的配置存在一个很大的缺点,即一个Controller/Handler类只能处理一个请求,因为只有handleRequest()方法才能处理请求并返回视图。这个问题可以通过注解来解决。相对于xml文件的配置,使用注解使用SpringMVC,具有以下两个优点:

  1. 一个控制器类可以处理多个请求(动作);
  2. 代码便于阅读和维护,因为控制器类和请求映射不需要存储在配置文件中,而是直接写在了方法的注解上。

这篇博客将使用注解来修改之前的SpringMVC应用。

一、导入jar包

我在测试的过程中,遇到了这个异常:java.lang.ClassNotFoundException: org.springframework.aop.TargetSource,异常原因是缺少aop的jar包,导入之后一切正常。这里让我很疑惑的是,应用中并没有使用到aop,没有导入这个jar包应该没有问题,这里先不深究,如果有大神知道原因,恳请留言指导。最后的jar包如下图所示:
这里写图片描述

二、Controller注解

要使用@Controller注解,需要在springmvc.xml文件中指定扫描基础包,如下:

<!-- 指定需要扫描的包 --><context:component-scan base-package="controller"></context:component-scan><context:component-scan base-package="model"></context:component-scan>

实际上,<context:component-scan base-package="###"></context:component-scan>是Spring框架指定哪些包需要扫描的配置方法。有一个良好的习惯是,不要指定太过广泛的基本包,不要嫌麻烦,有几个包需要扫描就写几个<context:component-scan base-package="###"></context:component-scan>
接下来,就可以直接在控制器类添加@Controller注解了,如下:

package controller;import org.springframework.stereotype.Controller;@Controller("inputInfo")public class InputProductController1 {    //省略了方法}

三、RequestMapping注解

要使用@RequestMapping注解,需要在springmvc.xml文件中指定以下内容:

<!-- 配置注解适配器 --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /><!-- 配置注解映射器 --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />

与上述配置方式相比,下面这种配置方式更为推荐:

<mvc:annotation-driven></mvc:annotation-driven><mvc:resources location="/css/" mapping="/css/**"></mvc:resources><mvc:resources location="/*.html" mapping="/"></mvc:resources>

(1)<mvc:annotation-driven></mvc:annotation-driven>做了很多事情,包括指定注解适配器和注解映射器,还提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson);
(2)<mvc:resources>指定了哪些静态资源需要单独处理,而不经过前端控制器(DispatcherServlet)处理。在将dispatcherservlet的URL模式设置为“/”时(如下所示),这个标签是必须的,这样可以保证正确地处理静态资源。

<!-- 配置前端控制器DispatcherServlet --><servlet>  <servlet-name>springmvc</servlet-name>  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  <init-param>      <param-name>contextConfigLocation</param-name>      <param-value>classpath:springmvc1.xml</param-value>  </init-param></servlet><servlet-mapping>  <servlet-name>springmvc</servlet-name>  <url-pattern>/</url-pattern></servlet-mapping>  

四、编写Controller类

将之前的SpringMVC应用的Controller类进行修改,这里分别命名为InputProductController1和SaveProductController1,代码如下:
(1)InputProductController1:

package controller;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;@Controller("inputInfo")public class InputProductController1 {    private final Log logger = LogFactory.getLog(this.getClass());    @RequestMapping(value="inputProduct")    public String inputProduct(){        logger.info("Call the method!");        return "productForm";    }    @RequestMapping("/inputProduct1")    public ModelAndView inputProduct1(){        logger.info("Call the method2!");        ModelAndView view = new ModelAndView();        view.setViewName("productForm");        return view;    }}

上面的代码中,包含了两个方法,使用了两种@RequestMapping的写法,实际上,这两种写法是完全等效的,均指定了方法相对应的URL。
@RequestMapping还有另一个属性method,该属性用来指示方法仅仅处理那些HTTP方法。例如,仅当在HTTP POST方法时,才访问下面的processOrder方法(这个例子与本文中的SpringMVC应用没有任何关系)。

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

(2)SaveProductController1:

package controller;import java.io.UnsupportedEncodingException;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;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 org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.servlet.ModelAndView;import model.Product;@Controllerpublic class SaveProductController1 {    private final Log logger = LogFactory.getLog("log");    @Resource()    private Product product;    @RequestMapping(value="/saveProduct")    public ModelAndView saveProduct(HttpServletRequest request,HttpServletResponse response,@RequestParam String name,@RequestParam String description,@RequestParam String price){        logger.info("test");        try {            request.setCharacterEncoding("UTF-8");            logger.info(name);            logger.info(description);            logger.info(price);        } catch (UnsupportedEncodingException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        /*        product.setName(request.getParameter("name"));        product.setDescription(request.getParameter("description"));        product.setPrice(request.getParameter("price"));        */        product.setName(name);        product.setDescription(description);        product.setPrice(price);        ModelAndView modelAndView = new ModelAndView();        modelAndView.addObject("product", product);        modelAndView.setViewName("productDetails");        return modelAndView;    }    @RequestMapping(value="/saveProduct1")    public ModelAndView saveProduct1(Product product){        logger.info("saveProduct1 been called!");        ModelAndView modelAndView = new ModelAndView();        modelAndView.addObject("product", product);        modelAndView.setViewName("productDetails");        return modelAndView;    }}

上述代码中使用了@RequestParam注解,该注解代替了request.getParameter方法,可以解析request中的参数。但是这样的写法会导致方法的形参冗长,不便于阅读和后期维护,上述代码中的saveProduct1方法是另一种更加优秀的获取页面请求信息的方法,这种方法需要一个Product类。下面附上Product类的代码和productForm.jsp页面的代码:

Product类

package model;import org.springframework.stereotype.Component;@Component("product")public class Product {    private String name;    private String description;    private String price;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }    public String getPrice() {        return price;    }    public void setPrice(String price) {        this.price = price;    }}

productForm.jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body>    <div id="global">        <form action="saveProduct1" method="post">            <fieldset>                <legend>Add a product</legend>                <label for="name">Product Name:</label>                <input type="text" id="name" name="name" tabindex="1"><br>                <label for="description">Description:</label>                <input type="text" id="description" name="description" tabindex="2"><br>                <label for="price">Price:</label>                <input type="text" id="price" name="price" tabindex="3"><br>                <div id="buttons">                    <label for="dummy"></label>                    <input id="reset" type="reset" tabindex="4">                    <input id="submit" type="submit" tabindex="5">                </div>            </fieldset>        </form>    </div></body></html>

博客内容就写到这里,如有错误之处,还请留言指正。

原创粉丝点击