芋道 Spring Boot SpringMVC 入门

本文介绍了如何使用Spring Boot集成SpringMVC,通过注解快速创建RESTful API接口,并实现全局统一的返回结果。内容包括SpringMVC的注解使用、MockMvc测试接口、全局异常处理、HandlerInterceptor拦截器、以及CORS跨域配置。文章还讨论了使用HandlerInterceptor处理请求的优缺点,提供了使用Servlet、Filter和Listener的配置示例,并探讨了Fastjson与SpringMVC的整合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击上方“芋道源码”,选择“设为星标

做积极的人,而不是积极废人!

源码精品专栏

 

摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/SpringMVC/ 「芋道源码」欢迎转载,保留摘要,谢谢!

  • 1. 概述

  • 2. 快速入门

  • 3. 测试接口

  • 4. 全局统一返回

  • 5. 全局异常处理

  • 6. HandlerInterceptor 拦截器

  • 7. Servlet、Filter、Listener

  • 8. Cors 跨域

  • 9. HttpMessageConverter 消息转换器

  • 10. 整合 Fastjson

  • 666. 彩蛋


本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-23 目录。

原创不易,给点个 Star 嘿,一起冲鸭!

1. 概述

如果胖友接触 Java Web 开发比较早,那么可能会了解到如下 Web MVC 框架,当年是 Struts2 与 SpringMVC 双雄争霸的年代。甚至说,我们在面试的时候,就特问:“SpringMVC 和 Struts2 的区别是什么?”。

关于这个问题,如果感兴趣,可以看看 《Struts2 和 SpringMVC 区别?》 讨论。

而现在,SpringMVC 基本已经统治 Web MVC 框架,相信胖友已经很少接触非使用 SpringMVC 的项目了。在艿艿实习那会,大概是 2011 年的时候,还经历了一次将项目从 Struts2 迁移到 SpringMVC 。

相比来说,SpringMVC 的易用性与性能都优于 Struts2 ,整体实现也更加清晰明了。当然,更更更重要的是,它有个好爸爸,Spring 极强的体系与社区活跃度。

因为是一篇 Spring Boot 集成 SpringMVC 入门的文章,艿艿就不多哔哔了,直接快速入门,遨游起来。不过还是提一句,SpringMVC 处理请求的整体流程,一定要能倒背如流。

2. 快速入门

示例代码对应仓库:lab-springmvc-23-01 。

本小节,我们会使用 spring-boot-starter-web 实现 SpringMVC 的自动化配置。然后实现用户的增删改查接口。接口列表如下:

请求方法 URL 功能
GET /users 查询用户列表
GET /users/{id} 获得指定用户编号的用户
POST /users 添加用户
PUT /users/{id} 更新指定用户编号的用户
DELETE /users/{id} 删除指定用户编号的用户

下面,开始遨游~

2.1 注解

可能有胖友之前未使用过 SpringMVC ,所以在这个小节,我们来说下它提供的注解。

  • @Controller

  • @RestController

  • @RequestMapping

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @RequestParam

  • @PathVariable

已经了解过的胖友,可以快速略过或不看。

2.1.1 @Controller

@Controller 注解,添加在类上,表示这是控制器 Controller 对象。属性如下:

  • name 属性:该 Controller 对象的 Bean 名字。允许空。

@RestController 注解,添加在类上,是 @Controller@ResponseBody 的组合注解,直接使用接口方法的返回结果,经过 JSON/XML 等序列化方式,最终返回。也就是说,无需使用 InternalResourceViewResolver 解析视图,返回 HTML 结果。

目前主流的架构,都是 前后端分离 的架构,后端只需要提供 API 接口,仅仅返回数据。而视图部分的工作,全部交给前端来做。也因此,我们项目中 99.99% 使用 @RestController 注解。

往往,我们提供的 API 接口,都是 Restful 或者类 Restful 风格,所以不了解的胖友,推荐看看如下两篇文章:

  • 《RESTful API 最佳实践》

  • 《跟着 Github 学习 Restful HTTP API 的优雅设计》

2.1.2 @RequestMapping

@RequestMapping 注解,添加在类或方法上,标记该类/方法对应接口的配置信息。

@RequestMapping 注解的常用属性,如下:

  • path 属性:接口路径。[] 数组,可以填写多个接口路径。

  • values 属性:和 path 属性相同,是它的别名。

  • method 属性:请求方法 RequestMethod ,可以填写 GETPOSTPOSTDELETE 等等。[] 数组,可以填写多个请求方法。如果为空,表示匹配所有请求方法。

@RequestMapping 注解的不常用属性,如下:

  • name 属性:接口名。一般情况下,我们不填写。

  • params 属性:请求参数需要包含值的参数名。可以填写多个参数名。如果为空,表示匹配所有请你求方法。

  • headers 属性:和 params 类似,只是从参数名变成请求头

  • consumes 属性:和 params 类似,只是从参数名变成请求头的提交内容类型( Content-Type )

  • produces 属性:和 params 类似,只是从参数名变成请求头的( Accept )可接受类型

    艿艿:关于 consumesproduces 属性,可以看看 《Http 请求中 Content-Type 和 Accept 讲解以及在 Spring MVC 中的应用》 文章,更加详细。

考虑到让开发更加方便,Spring 给每种请求方法提供了对应的注解:

  • @GetMapping 注解:对应 @GET 请求方法的 @RequestMapping 注解。

  • @PostMapping 注解:对应 @POST 请求方法的 @RequestMapping 注解。

  • @PutMapping 注解:对应 @PUT 请求方法的 @RequestMapping 注解。

  • @DeleteMapping 注解:对应 @DELETE 请求方法的 @RequestMapping 注解。

  • 还有其它几个,就不一一列举了。

2.1.3 @RequestParam

@RequestParam 注解,添加在方法参数上,标记该方法参数对应的请求参数的信息。属性如下:

  • name 属性:对应的请求参数名。如果为空,则直接使用方法上的参数变量名。

  • value 属性:和 name 属性相同,是它的别名。

  • required 属性:参数是否必须传。默认为 true ,表示必传。

  • defaultValue 属性:参数默认值。

@PathVariable 注解,添加在方法参数上,标记接口路径和方法参数的映射关系。具体的,我们在示例中来看。相比 @RequestParam 注解,少一个 defaultValue 属性。

下面,让我们快速编写一个 SpringMVC 的示例。

2.2 引入依赖

pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-springmvc-23-01</artifactId>

    <dependencies>
        <!-- 实现对 Spring MVC 的自动化配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。

2.3 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

先暂时不启动项目。等我们添加好 Controller 。

2.4 UserController

cn.iocoder.springboot.lab23.springmvc 包路径下,创建 UserController 类。代码如下:

// UserController.java

@RestController
@RequestMapping("/users")
public class UserController {

    /**
     * 查询用户列表
     *
     * @return 用户列表
     */
    @GetMapping("")
    public List<UserVO> list() {
        // 查询列表
        List<UserVO> result = new ArrayList<>();
        result.add(new UserVO().setId(1).setUsername("yudaoyuanma"));
        result.add(new UserVO().setId(2).setUsername("woshiyutou"));
        result.add(new UserVO().setId(3).setUsername("chifanshuijiao"));
        // 返回列表
        return result;
    }

    /**
     * 获得指定用户编号的用户
     *
     * @param id 用户编号
     * @return 用户
     */
    @GetMapping("/{id}")
    public UserVO get(@PathVariable("id") Integer id) {
        // 查询并返回用户
        return new UserVO().setId(id).setUsername("username:" + id);
    }

    /**
     * 添加用户
     *
     * @param addDTO 添加用户信息 DTO
     * @return 添加成功的用户编号
     */
    @PostMapping("")
    public Integer add(UserAddDTO addDTO) {
        // 插入用户记录,返回编号
        Integer returnId = 1;
        // 返回用户编号
        return returnId;
    }

    /**
     * 更新指定用户编号的用户
     *
     * @param id 用户编号
     * @param updateDTO 更新用户信息 DTO
     * @return 是否修改成功
     */
    @PutMapping("/{id}")
    public Boolean update(@PathVariable("id") Integer id, UserUpdateDTO updateDTO) {
        // 将 id 设置到 updateDTO 中
        updateDTO.setId(id);
        // 更新用户记录
        Boolean success = true;
        // 返回更新是否成功
        return success;
    }

    /**
     * 删除指定用户编号的用户
     *
     * @param id 用户编号
     * @return 是否删除成功
     */
    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable("id") Integer id) {
        // 删除用户记录
        Boolean success = false;
        // 返回是否更新成功
        return success;
    }

}
  • 在类上,添加 @RestController 注解,表示直接返回接口结果。默认情况下,使用 JSON 作为序列化方式。

  • 在类上,添加 @RequestMapping("/users") 注解,表示 UserController 所有接口路径,以 /users 开头。

  • #list() 方法,查询用户列表。请求对应 GET /users,请求结果为:

    [
        {
            "id": 1,
            "username": "yudaoyuanma"
        },
        {
            "id": 2,
            "username": "woshiyutou"
        },
        {
            "id": 3,
            "username": "chifanshuijiao"
        }
    ]
    
    • 其中,UserVO 为用户返回 VO 类。

  • #get(Integer id) 方法,获得指定用户编号的用户。请求对应 GET /users/{id} 【路径参数】,请求你结果为:

    {
        "id": 1,
        "username": "username:1"
    }
    
  • #add(UserAddDTO addDTO) 方法,添加用户。请求对应 POST /users ,请求结果为:

    1
    
    • 因为我们这里返回的是 Integer 类型,对于非 POJO 对象,所以无需使用 JSON 序列化返回。

    • 其中,UserAddDTO 为用户添加 DTO 类。

  • #update(Integer id, UserUpdateDTO updateDTO) 方法,更新指定用户编号的用户。请求对应 PUT /users/{id} 【路径参数】,请求结果为:

    true
    
    • 其中,UserUpdateDTO 为用户更新 DTO 类。

  • #delete(Integer id) 方法,删除指定用户编号的用户。请求对应 DELETE /users/{id} 【路径参数】,请求结果为:

    false
    

以上的测试,肯定需要通过运行 Application ,启动项目。这里,补充下它的启动日志如下:

2019-11-15 18:46:00.671  INFO 99493 --- [           main] c.i.s.lab23.springmvc.Application        : Starting Application on MacBook-Pro-8 with PID 99493 (/Users/yunai/Java/SpringBoot-Labs/lab-23/lab-springmvc-23-01/target/classes started by yunai in /Users/yunai/Java/SpringBoot-Labs)
2019-11-15 18:46:00.673  INFO 99493 --- [           main] c.i.s.lab23.springmvc.Application        : No active profile set, falling back to default profiles: default
2019-11-15 18:46:01.593  INFO 99493 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-11-15 18:46:01.613  INFO 99493 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-11-15 18:46:01.613  INFO 99493 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.16]
2019-11-15 18:46:01.619  INFO 99493 --- [           main] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/yunai/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2019-11-15 18:46:01.684  INFO 99493 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-11-15 18:46:01.684  INFO 99493 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 976 ms
2019-11-15 18:46:01.844  INFO 99493 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-11-15 18:46:01.987  INFO 99493 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-11-15 18:46:01.990  INFO 99493 --- [           main] c.i.s.lab23.springmvc.Application        : Started Application in 1.559 seconds (JVM running for 2.146)
  • 我们可以看到,Spring Boot 在启动 SpringMVC 时,会默认初始化一个内嵌的 Tomcat ,监听 8080 端口的请求。

2.5 UserController2

在日常的项目开发中,艿艿只使用 GETPOST 请求方法。主要是,实际场景下,因为业务比较复杂,标准的 Restful API 并不能满足所有的操作。例如说,订单有用户取消,管理员取消,修改收货地址,评价等等操作。所以,我们更多的是,提供 Restful API 。

对于 SpringMVC 提供的 @PathVariable 路径参数,艿艿目前也并没有在项目中使用,主要原因如下:

  • 1、封装的权限框架,基于 URL 作为权限标识,暂时是不支持带有路径参数的 URL 。

  • 2、基于 URL 进行告警,而带有路径参数的 URL ,“相同” URL 实际对应的是不同的 URL ,导致无法很方便的实现按照单位时间请求错误次数告警。

  • 3、@PathVariable 路径参数的 URL ,会带来一定的 SpringMVC 的性能下滑。具体可以看看 《SpringMVC RESTful 性能优化》 文章。

所以,我们创建 UserController2 类,修改 API 接口。最终代码如下:

// UserController2.java

@RestController
@RequestMapping("/users2")
public class UserContr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值