SpringMVC:二、注解开发和RESTful风格

3、基于注解的SpringMVC

SpringMVC 实际开发中,我们通常都会采用注解开发。

3.1、配置文件

web.xml:注册 DispatcherServlet

  • 关联配置文件
  • 启动优先级
  • <url-pattern>
    • /:匹配所有请求,不包括 JSP
    • /*:匹配所有请求及 JSP
    • 如果填写了/*Controller 处理业务后返回的 JSP页面会再次被拦截请求,会无限嵌套。
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_4_0.xsd"
         version="4.0">

    <!-- 注册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:springmvc-servlet.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>

springmvc-servlet.xml

基于配置的SpringMVC的配置相比:

  • 添加注解支持,不再需要手动注册 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: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
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫描包 -->
    <context:component-scan base-package="indi.jaywee.controller"/>
    <!-- 过滤静态资源 -->
    <mvc:default-servlet-handler/>
    <!-- 注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

3.2、Controller

HelloController

@Controller
public class HelloController {

    /**
     * 使用 @RequestMapping注解来处理映射关系,后接请求路径(如"/hello")
     * 方式一:使用 ModelAndView来封装模型和视图,返回 ModelAndView
     */
    @RequestMapping("/hello")
    public ModelAndView hello(ModelAndView mv) {
        // 可以调用Service层方法,获取模型对象
        
        // 添加数据模型
        mv.addObject("msg", "Hello Annotation:ModelAndView");
        // 封装要渲染、跳转的视图
        mv.setViewName("hello");

        return mv;
    }

    /**
     * 使用 @RequestMapping注解来处理映射关系,后接请求路径(如"/hello")
     * 方式二:使用 Model来封装模型,返回 ViewName
     */
    @RequestMapping("/hello1")
    public String hello(Model model) {
        // 可以调用Service层方法,获取模型对象
        
        // 添加数据模型
        model.addAttribute("msg", "Hello Annotation:Model");
        // 返回视图
        return "hello";
    }
}

3.3、跳转页面及结果

hello.jsp

<h1>${msg}</h1>

测试结果

SpringMVC:二、注解开发和RESTful风格

3.4、小结

注解开发 SpringMVC 全步骤

  1. 新建 Maven 工程,导入依赖;
  2. 删除 src 目录,作为父工程;
  3. 新建 module,添加 web 框架支持:在项目结构中手动添加 lib 目录;
  4. web.xml:注册 DispatcherServlet
    • 关联配置文件;
    • 启动优先级;
  5. springmvc-servlet.xml:添加注解支持、内部资源视图解析器;
  6. 编写 Controller,使用注解;
  7. 编写页面。

基于配置 VS 基于注解

  1. web.xml 完全相同;

  2. springmvc-servlet.xml

    • 基于配置:处理器映射、处理器适配器、内部资源视图解析器;

      • 处理器映射:默认配置,不需要显式配置;

      • 处理器适配器:默认配置,不需要显式配置;

      • 内部资源视图解析器:必须显式配置;

      • Controller 注册到 IOC 容器中:相当于原来在 web.xml 中注册 Servlet

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!-- 处理器映射 -->
            <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
            <!-- 处理器适配 -->
            <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
            <!-- 视图解析 -->
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                  id="internalResourceViewResolver">
                <!-- 前缀 -->
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <!-- 后缀 -->
                <property name="suffix" value=".jsp"/>
            </bean>
        
            <!-- 注册Controller -->
            <bean id="/hello" class="indi.jaywee.controller.HelloController"/>
        
        </beans>
        
    • 基于注解Spring 注解开发

      • 扫描包:扫描指定包下的 Bean ,被扫描的 Bean 中包含的类级别的注解才会生效,Bean 才会被注册到容器中;

      • 过滤静态资源:如 CSSJSHTMLMP3MP4...

      • 注解驱动:在 Spring 中一般使用 @RequestMapping 注解来处理映射关系,使用该注解需要注册处理器映射处理器适配器annotation-driven 自动注入以上两个实例;

      • 内部资源视图解析器。

        <!-- 扫描包 -->
        <context:component-scan base-package="indi.jaywee.controller"/>
        <!-- 过滤静态资源 -->
        <mvc:default-servlet-handler/>
        <!-- 注解驱动 -->
        <mvc:annotation-driven/>
        <!-- 视图解析 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
              id="internalResourceViewResolver">
            <!-- 前缀 -->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!-- 后缀 -->
            <property name="suffix" value=".jsp"/>
        </bean>
        
  3. Controller

    • 基于配置

      • 继承 Controller 接口,重写 handleRequest 方法;

      • 通过 ModelAndView 封装模型和视图,返回 ModelAndView

        public class HelloController implements Controller {
            @Override
            public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        		...
            }
        }
        
      • 需要在 springmvc-servlet.xml 中注册 Bean 并映射请求路径;

        <bean id="/hello" class="indi.jaywee.controller.HelloController"/>
        
      • 如果有多个请求,通过获取参数判断方法名实现 Controller 复用,或编写多个 Controller

    • 基于注解

      • 使用 @Controller 注解来注册 Bean,自定义方法;

      • 通过 ModelAndView 封装模型和视图,返回 ModelAndView。或通过 Model 封装模型,返回视图名;

      • 在方法上使用@RequestMapping("/xxx")来映射请求路径:

        @Controller
        public class HelloController {
        
            @RequestMapping("/hello1")
            public String hello(Model model) {
                ...
            }
        }
        
      • 如果有多个请求,自定义编写多个方法。

@RequestMapping

@RequestMapping 注解用于映射请求 URL 到控制器类或处理程序方法,,可以作为类级别、类内部的注解。

  • 在类上没有使用,只在方法上使用:直接访问类内部注解的映射路径

    例如:映射的路径是/hello

    @Controller
    public class HelloController {
        
        @RequestMapping("/hello")
        public ModelAndView hello(ModelAndView mv) {
    		...
        }
    }
    
  • 在类上和方法上都使用:访问类级别注解的映射路径 / 类内部注解的映射路径,即类级别注解的映射路径作为父路径:

    例如:映射的路径是myHello / hello

    @Controller
    @RequestMapping("/myHello ")
    public class HelloController {
        
        @RequestMapping("/hello")
        public ModelAndView hello(ModelAndView mv) {
    		...
        }
    }
    

4、RESTful风格

4.1、概念

RESTful 是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。

基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

4.2、功能

  • 资源:互联网所有的事物都可以被抽象为资源

  • 资源操作:使用不同方法操作资源,POST(添加)、DELETE(删除)、PUT(更新)、GET(查询);

传统方法操作资源:通过不同的请求参数来实现不同的功能,请求地址不同

  • 添加:http://127.0.0.1/item/insertItem.action
  • 删除:http://127.0.0.1/item/deleteItem.action?id=1
  • 更新:http://127.0.0.1/item/updateItem.action
  • 查询:http://127.0.0.1/item/getItem.action?id=1

RESTful风格操作资源:通过不同的请求方式来实现不同的功能,请求地址相同

  • 添加:http://127.0.0.1/item
  • 删除:http://127.0.0.1/item/1
  • 更新:http://127.0.0.1/item
  • 查询:http://127.0.0.1/item/1

4.3、测试

Controller

使用 @PathVariable 注解,将参数值绑定到 URI 模板变量上。

@Controller
public class RestfulController {

    @RequestMapping("/addition/{a}/{b}")
    public String addition(@PathVariable int a,@PathVariable int b, Model model) {
        int result = a + b;
        model.addAttribute("result", "结果:" + result);

        return "test";
    }
}

跳转视图test.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>result</title>
</head>
<body>
${result}
</body>
</html>

测试

  • 正确输入

    SpringMVC:二、注解开发和RESTful风格

  • 错误输入:客户端请求的语法错误

    SpringMVC:二、注解开发和RESTful风格

method属性

使用 method 属性约束请求的类型,指定类型的请求才可访问。

@RequestMapping(value = "/multiplication/{a}/{b}", method = RequestMethod.POST)
public String multiplication(@PathVariable int a, @PathVariable int b, Model model) {
    int result = a * b;
    model.addAttribute("result", "结果:" + result);

    return "test";
}

也可以使用 @RequestMapping 的衍生注解:@PostMapping

@PostMapping("/multiplication/{a}/{b}")
public String multiplication(@PathVariable int a, @PathVariable int b, Model model) {
    int result = a * b;
    model.addAttribute("result", "结果:" + result);

    return "test";
}

测试:通过地址栏访问默认是 GET 请求,而方法指定的是 POST 请求,报 405

SpringMVC:二、注解开发和RESTful风格

将方法改为 GET 请求之后,正常访问

SpringMVC:二、注解开发和RESTful风格

4.4、请求类型

@RequestMapping 注解能够处理 HTTP 请求的方法,包括 GET, PUT, POST, DELETE , PATCH 等等。

  • 所有的地址栏请求默认都会是 HTTP GET 类型的。

  • @RequestMapping 注解有以下几个变体,是组合注解

    • @GetMapping
    • @PostMapping
    • @PutMapping
    • @DeleteMapping
    • @PatchMapping
    • 以上注解相当于:@RequestMapping(method =RequestMethod.XXX)
上一篇:/bin/sh^M: bad interpreter:没有那个文件或目录解决


下一篇:Spring MVC异常处理