在 Spring Boot 中,@Controller 注解是专门用于处理 Http 请求处理的,是以 MVC 为核心的设计思想的控制层。@RestController 则是 @Controller 的衍生注解。

本项目源码下载

1 Spring Boot Controller

1.1 原理

Spring Boot 本身就 Spring MVC 的简化版本。是在 Spring MVC 的基础上实现了自动配置,简化了开发人员开发过程。

Spring MVC 是通过一个叫 DispatcherServlet 前端控制器的来拦截请求的。而在 Spring Boot 中 使用自动配置把 DispatcherServlet 前端控制器自动配置到框架中。

例如,我们来解析 /users 这个请求

  1. DispatcherServlet 前端控制器拦截请求 /users
  2. servlet 决定使用哪个 handler 处理
  3. Spring 检测哪个控制器匹配 /users,Spring 从 @RquestMapping 中查找出需要的信息
  4. Spring 找到正确的 Controller 方法后,开始执行 Controller 方法
  5. 返回 users 对象列表
  6. 根据与客户端交互需要返回 Json 或者 Xml 格式

1.2 相关注解

在 Spring Boot 中使用到 @Controller 及相关的注解如下,主要分为三个层面进行,请求前,处理中,返回。

应用场景 注解 注解说明
处理请求 @Controller 处理 Http 请求
处理请求 @RestController @Controller 的衍生注解
路由请求 @RequestMapping 路由请求 可以设置各种操作方法
路由请求 @GetMapping GET 方法的路由
路由请求 @PostMapping POST 方法的路由
路由请求 @PutMapping PUT 方法的路由
路由请求 @DeleteMapping DELETE 方法的路由
请求参数 @PathVariable 处理请求 url 路径中的参数 /user/{id}
请求参数 @RequestParam 处理问号后面的参数
请求参数 @RequestBody 请求参数以json格式提交
返回参数 @ResponseBody 返回 json 格式

注意以上注解需要强调的是 @RestController 是 @Controller 的子集。

@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 是 @RequestMapping 的子集。所以实际上我们只需要掌握 @Controller 和 @RequestMapping 就可以了。

1.3 @Controller 与 @RestController 区别

@Controller 包括了 @RestController。@RestController 是 Spring4 后新加的注解,从 RestController 类源码可以看出 @RestController 是 @Controller 和 @ResponseBody 两个注解的结合体。

@Controller=@RestController+@ResponseBody

如下 @RestController 的源码可以看出他们的关系

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}

1.4 @Controller 与 @RestController应用场景

  • @Controller 一般应用在有返回界面的应用场景下.

    例如,管理后台使用了 thymeleaf 作为模板开发,需要从后台直接返回 Model 对象到前台,那么这时候就需要使用 @Controller 来注解。

  • @RestController 如果只是接口,那么就用 RestController 来注解.

    例如前端页面全部使用了 Html、Jquery来开发,通过 Ajax 请求服务端接口,那么接口就使用 @RestController 统一注解。

1.5 @RequestMapping 说明

首先我们来看看 @RequestMapping 的源码,我在上面加了注释

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default ""; //指定请求的实际地址
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
//指定请求的method类型, GET、POST、PUT、DELETE等
RequestMethod[] method() default {};
//指定request中必须包含某些参数值是,才让该方法处理。
String[] params() default {};
//指定request中必须包含某些指定的header值,才能让该方法处理请求。
String[] headers() default {};
//指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
String[] consumes() default {};
//指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
String[] produces() default {};
}

示例说明:

示例 说明
@RequestMapping("/index") 默认为 GET 方法的路由 /index
@RequestMapping(value="/index",method = RequestMethod.GET) 同上面一条
@RequestMapping(value="/add",method = RequestMethod.POST) 路由为 /add 的 POST 请求
@RequestMapping(value="/add",method = RequestMethod.POST),consumes="application/json" 路由为 /add 的 POST 请求,但仅仅处理 application/json 的请求
@RequestMapping(value="/add",method = RequestMethod.POST),produces="application/json" 路由为 /add 的 POST 请求,强调返回为 JSON 格式
@RequestMapping(value="/add",method = RequestMethod.POST),params="myParam=xyz" 路由为 /add 的 POST 请求,但仅仅处理头部包括 myParam=xyz 的请求
@RequestMapping(value="/add",method = RequestMethod.POST),headers="Referer=http://www.xyz.com/" 路由为 /add 的 POST 请求,但仅仅处理 来源为 www.xyz.com 的请求

2 @Controller 和 @RestController 示例

本章节,将对两个注解配合其他注解编写一系列示例,为了演示 @Controller 返回对应页面功能,我们在示例中引入了 thymeleaf 模板。具体在 pom.xml 中有说明。

编号 路由 Http方法 方法说明
1 /user/index GET 获取用户列表并返回列表页面
1 /user/add GET 用户新增页面
1 /user/save POST 新增用户的api
1 /user/edit GET 用户编辑的页面
1 /user/update POST 编辑用户的api
1 /user/del GET 删除用户页面
1 /user/deleted POST 删除用户页面的api

2.1 新建 Spring Boot 项目

  1. File > New > Project,如下图选择 Spring Initializr 然后点击 【Next】下一步
  2. 填写 GroupId(包名)、Artifact(项目名) 即可。点击 下一步

    groupId=com.fishpro

    artifactId=restcontroller
  3. 选择依赖 Spring Web Starter 前面打钩,在模板列中勾选 thymeleaf
  4. 项目名设置为 spring-boot-study-restcontroller.

2.2 依赖 Pom.xml 配置

本项目引入了 web 和 thymeleaf ,具体一人如下代码:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<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>

并把配置文件重命名为 application.yml ,修改默认测试端口

server:
port: 8087

2.3 基于 @Controller 的示例代码

本代码实例中新增了如下页面,注意 templates 表示 /resources/tempalates/controller 表示 com.fishpro.restcontroller.controller 包。

  • controller/UserController.java 控制层-用户类
  • domain/UserDO.java 用户控实体类
  • templates/user/index.html 视图-用户列表页面
  • templates/user/add.html 视图-新增用户页面
  • templates/user/edit.html 视图-编辑用户页面

2.3.1 返回用户列表信息 /user/index

本项目源码下载

首先构件一个虚拟的用户数据

  /**
* 模拟一组数据
* */
private List<UserDO> getData(){
List<UserDO> list=new ArrayList<>(); UserDO userDO=new UserDO();
userDO.setUserId(1);
userDO.setUserName("admin");
list.add(userDO); userDO=new UserDO();
userDO.setUserId(2);
userDO.setUserName("heike");
list.add(userDO); userDO=new UserDO();
userDO.setUserId(3);
userDO.setUserName("tom");
list.add(userDO); userDO=new UserDO();
userDO.setUserId(4);
userDO.setUserName("mac");
list.add(userDO); return list;
}

1 创建一个用户列表页面 /user/index

UserController 增加方法如下图所示,使用 @RequestMapping 注解,注意 @RequestMapping(method = RequestMethod.GET,value = "/index") 等于 @RequestMapping(value = "/index") 也等于 @RequestMapping("/index") 也等于 @GetMapping("/index")

 /**
* GET 返回用户列表信息
* */
@RequestMapping(method = RequestMethod.GET,value = "/index")
public String index(Model model){
List<UserDO> list =getData();
model.addAttribute("list",list);//返回 用户 list
return "user/index";
}

2 创建 templates/index.html 对应上面的路由 /user/index

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="title"> </div>
<div th:each="user :${list}">
用户ID:<span th:text="${user.userId}"></span>
用户名:<span th:text="${user.userName}"></span>
</div>
</body>
</html>

3 在浏览器中查看

右键 RestControllerApplication > Run 在浏览器输入 http://localhost:8087/user/index

用户ID:1 用户名:admin
用户ID:2 用户名:heike
用户ID:3 用户名:tom
用户ID:4 用户名:mac

2.3.3 新增用户页面 /user/add

本项目源码下载

在 UserController 中增加 add 路由 /user/add

UserController 增加方法如下图所示,使用 @RequestMapping 注解,并创建了两个路由

  • /user/add 对应前端页面
  • /user/save 对应前端页面提交按钮的接口
 /**
* GET 返回add页面
* @GetMapping("/add") = @RequestMapping(method = RequestMethod.GET,value = "/add")
* */
@GetMapping("/add")
public String add(){
return "user/add";
}
/**
* POST 新增用户api
* @return 返回 map对象
* */
@RequestMapping(method = RequestMethod.POST,value = "/save")
@ResponseBody
public Object save(UserDO user){
List<UserDO> list= getData();
list.add(user);//模拟向列表中增加数据
Map<String,Object> map=new HashMap<>();
if(null==user){ map.put("status",3);
map.put("message","没有传任何对象");
return map;
}
map.put("status",0);
map.put("data",user);
return map;
}

创建 templates/add.htm 文件对应路由 /user/add

在对应的 templates/add.html中增加代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户新增页面</title>
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.js"></script>
</head>
<body>
<form id="form1">
<div> <input name="userId" id="userId" placeholder="请输入userid"></div>
<div> <input name="userName" id="userName" placeholder="请输入username"></div>
<div> <input type="button" value="新增" id="btnSave"/></div>
</form>
<script>
$(function () { $("#btnSave").click(function () {
$.ajax({
cache: true,
type: "POST",
url: "/user/save",
data:$('#form1').serialize(),
dataType:"json",
async: false,
error: function (request) {
console.log("Connection error");
},
success: function (data) {
if (data.code == 0) {
console.log("成功");
} else {
console.log("失败");
} }
});
}); });
</script>
</body>
</html>

在浏览器中测试效果

右键 RestControllerApplication > Run 在浏览器输入 http://localhost:8087/user/add

2.3.3 编辑用户页面 /user/edit

这部分代码原理同 2.3.2 代码原理 通过构件一个编辑页面,点击编辑页面的【保存】提交到后端的 api 中。

本示例中创建了2个接口 1个文件

  • /user/edit 对应前端页面
  • /user/update 对应前端页面提交按钮的接口
  • /templates/user/edit.html
 /**
* GET 返回编辑页面
* @GetMapping("/edit/{id}") = @RequestMapping(method = RequestMethod.GET,value = "/edit/{id}")
* @PathVariable("id") 表示路由中的动态参数部分
* @param id 表示要编辑的用户id
* @param model 表示将要输出到页面的 Model 对象
* @return 返回到 user/edit页面
* */
@GetMapping("/edit/{id}")
public String edit(@PathVariable("id") String id, Model model){
UserDO user =new UserDO();
user.setUserId(3);
user.setUserName("fishpro");
model.addAttribute("user",user);
return "user/edit";
} /**
* POST 修改用户api
* @RequestBody 表示参数使用 json 对象传输
* @return 返回 map对象
* */
@PostMapping("/update")
@ResponseBody
public Object update(@RequestBody UserDO user){
Map<String,Object> map=new HashMap<>();
if(null==user){ map.put("status",3);
map.put("message","没有传任何对象");
return map;
}
//更新逻辑
map.put("status",0);
return map;
}

edit.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户编辑页面</title>
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.js"></script>
</head>
<body>
<form id="form1">
<div> <input name="userId" id="userId" placeholder="请输入userid" th:value=${user.userId}> </div>
<div> <input name="userName" id="userName" placeholder="请输入username" th:value=${user.userName}></div>
<div> <input type="button" value="新增" id="btnSave"/></div>
</form>
<script>
$(function () { $("#btnSave").click(function () {
$.ajax({
cache: true,
type: "POST",
url: "/user/update",
data:$('#form1').serialize(),
dataType:"json",
async: false,
error: function (request) {
console.log("Connection error");
},
success: function (data) {
if (data.code == 0) {
console.log("成功");
} else {
console.log("失败");
}
}
});
}); });
</script>
</body>
</html>

本项目源码下载

2.3.3 删除用户 /user/delete

本项目源码下载

/**
* POST 修改用户api
* @return 返回 map对象
* */
@PostMapping("/delete/{id}")
@ResponseBody
public Object delete(@PathVariable("id") Integer id){
List<UserDO> list= getData();
UserDO userDO=null;
for (UserDO user:list
) {
if(id.equals(user.getUserId().toString())){
//删除用户
userDO=user;
break;
}
} Map<String,Object> map=new HashMap<>();
map.put("status",0);
map.put("data",userDO);
return map;
}

2.4 基于 @RestController 的示例代码

本章节中是基于 2.3版本中的接口,其实是一样的功能,详细见下面的代码,为了完成代码功能示例,我们新建了 UserRestController.java,不同的是 我们给类加了 @RestController 修饰符。

@RestController
@RequestMapping("user2")
public class UserRestController {
//从 UserController 搬过来代码即可
}

本项目源码下载


关联阅读:

Spring Boot Thymeleaf 模板引擎的使用

Spring Boot RESTful api

Spring Boot Log 日志使用教程

Spring Boot 全局异常处理

Spring Boot Web 开发@Controller @RestController 使用教程的更多相关文章

  1. Springboot 系列(六)Spring Boot web 开发之拦截器和三大组件

    1. 拦截器 Springboot 中的 Interceptor 拦截器也就是 mvc 中的拦截器,只是省去了 xml 配置部分.并没有本质的不同,都是通过实现 HandlerInterceptor ...

  2. Springboot 系列(七)Spring Boot web 开发之异常错误处理机制剖析

    前言 相信大家在刚开始体验 Springboot 的时候一定会经常碰到这个页面,也就是访问一个不存在的页面的默认返回页面. 如果是其他客户端请求,如接口测试工具,会默认返回JSON数据. { &quo ...

  3. Springboot 系列(五)Spring Boot web 开发之静态资源和模版引擎

    前言 Spring Boot 天生的适合 web 应用开发,它可以快速的嵌入 Tomcat, Jetty 或 Netty 用于包含一个 HTTP 服务器.且开发十分简单,只需要引入 web 开发所需的 ...

  4. Spring Boot Web 开发注解篇

    本文提纲 1. spring-boot-starter-web 依赖概述 1.1 spring-boot-starter-web 职责 1.2 spring-boot-starter-web 依赖关系 ...

  5. spring boot系列(二)spring boot web开发

    json 接口开发 在以前的spring 开发的时候需要我们提供json接口的时候需要做如下配置: 1 添加jackjson等jar包 2 配置spring controller扫描 3 对接的方法添 ...

  6. 四、Spring Boot Web开发

    四.Web开发 1.简介 使用SpringBoot: 1).创建SpringBoot应用,选中我们需要的模块: 2).SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可 ...

  7. (5)Spring Boot web开发 --- Restful CRUD

    文章目录 `@RestController` vs `@Controller` 默认访问首页 设置项目名 国际化 登陆 & 拦截 Restful 风格 @RestController vs @ ...

  8. 4.Spring Boot web开发

    1.创建一个web模块 (1).创建SpringBoot应用,选中我们需要的模块: (2).SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来 (3).自己编 ...

  9. Spring Boot Web开发中Thymeleaf模板引擎的使用

    这里使用的是idea 1.新建Spring Boot项目 File-->New-->Project...,然后选择左边的Spring Initializr-->Next,可根据自己的 ...

随机推荐

  1. rancher三节点k8s集群部署例子

    rancher三节点k8s集群部署例子 待办 https://rorschachchan.github.io/2019/07/25/使用Rancher2-1部署k8s/

  2. ffmpeg-- audio decoder

    测试代码来源于:http://ffmpeg.org/doxygen/trunk/decode_audio_8c-example.html /* * Copyright (c) 2001 Fabrice ...

  3. Module build failed: TypeError: this.getResolve is not a function at Object.loader sass报错!(亲测有效!~~)

    vue安装node-sass编译报错 在搭建vue脚手架 或者是在vue项目中,想使用sass的功能,需先安装如下 npm install node-sass --save-dev //安装node- ...

  4. C++泛型算法总结

    1 accumulate(b,e,T) 累和(基础和为T) 注意T的类型必须和序列中元素类型相同,如double序列后面的T就必须是0.0,如果是0就会把序列中的数当成int进行求和 2 count( ...

  5. xv6 trapframe定义的位置

    在x86.h的最下面,真是把我找吐了,MD

  6. 空字符串(“”)和null和空格字符串(" ")的区别

    1.类型 null表示的是一个对象的值,而并不是一个字符串.例如声明一个对象的引用,String a = null ;""表示的是一个空字符串,也就是说它的长度为0,但它是一个字符 ...

  7. 生成树计数模板 spoj 104 (不用逆元的模板)

    /* 这种题,没理解,只是记一记如何做而已: 生成树的计数--Matrix-Tree定理 题目:SPOJ104(Highways) 题目大意: *一个有n座城市的组成国家,城市1至n编号,其中一些城市 ...

  8. Go性能调优

    文章引用自   Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 pr ...

  9. 【资源分享】Gmod-Expression2 - 自定义像素画生成

    *作者:BUI* 可自定义制作属于你的像素画(默认为Sans) 第77行的COLOR可编辑你想要的颜色(RGB值) 1,2,3,4分别代表第77行所定义的颜色(0代表不显示) 视频地址:传送链接 @n ...

  10. C:数组基础

    数组 在程序设计中,为了方便处理数据把具有相同类型的若干变量按有序形式组织起来--称为数组. 数组就是在内存中连续的相同类型的变量空间.同一个数组所有的成员都是相同的数据类型,同时所有的成员在内存中的 ...