@Controller
@RestController
@RequestMapping
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping
@ResponseBody
@RequestParam, @PathVariable, @RequestBody
在开发中,我们经常会遇到两种不同的业务场景,这时我们需要根据实际需求选择不同的注解:
传统页面交互(MVC模式)
@Controller
。@ResponseBody
注解来返回JSON数据,但这会让方法的风格不一致。RESTful API开发
@RestController
会更方便,因为它默认添加了@ResponseBody
效果,简化了代码结构,减少了重复注解的写法。在Spring MVC框架中,@Controller主要用于标记一个类为控制器,从而接收和处理来自客户端的请求,返回视图名称或ModelAndView对象,供视图解析器解析后生成最终页面。
在Spring MVC架构中,DispatcherServlet扮演了前端控制器的角色,整个请求处理流程如下:
这种流程就类似于一个快递分拣中心:DispatcherServlet是分拣中心,通过查找和分发将包裹(请求)分发到正确的分拣员(Controller),最终将包裹送达收件人(客户端)。
下面是一个简单的@Controller示例代码,展示如何处理一个GET请求并返回一个视图页面:
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.ui.Model;
@Controller
public class SampleController {
// 处理GET请求,访问网址:http://localhost:8080/hello
@GetMapping("/hello")
public String hello(Model model) {
// 添加数据到Model,供前端页面使用
model.addAttribute("message", "Hello, World!");
// 返回视图名称,视图解析器将根据该名称查找实际视图(例如hello.jsp、hello.html)
return "hello";
}
}
在上面的代码中,需要注意:
必须引入的包:
通过@GetMapping注解,Spring将该方法映射到"/hello"路径。
返回的字符串"hello"是视图名,最终由ViewResolver处理后渲染为一个页面。
在现代Web开发中,@RestController注解为构建RESTful API提供了极大的便利,使得Controller中的方法可以直接返回数据而无需额外的视图解析处理。下面我们详细讲解@RestController的概念、优势、内部原理以及使用中的注意事项。
下面提供一段使用@RestController构建RESTful API接口的示例代码,展示如何返回JSON数据以及必须的import包信息:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
// @RestController组合了@Controller和@ResponseBody
@RestController
public class UserController {
// 处理 GET 请求,并返回一个用户示例(自动转换为JSON格式输出)
@GetMapping("/user")
public User getUser() {
return new User(1, "Alice");
}
}
// 示例用户实体类
package com.example.demo.model;
public class User {
private int id;
private String name;
// 必须的无参构造器
public User() {}
public User(int id, String name) {
this.id = id;
this.name = name;
}
// Getter和Setter方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在上述代码中,注意以下几点:
在Spring MVC开发中,@Controller和@RestController都是用来标识控制器类,但它们在功能和底层实现上存在一定的差异,适用于不同的业务场景。下面对两者进行详细的对比分析。
功能:
底层实现:
使用场景:
业务需求:
全局配置:
混用和方法标识:
性能和扩展:
在实际开发中,我们经常面临两类不同需求:一类是传统的页面渲染应用,另一类是RESTful API服务。下面分别通过案例展示如何使用@Controller和@RestController,并对比其代码结构及开发体验。
场景描述:构建一个简单的用户登录页面。Controller接收到请求后返回一个JSP或Thymeleaf页面,页面上包含一个表单,用户提交登录数据后服务器进行相应处理。
示例代码:
// 文件路径:com.example.demo.controller.LoginController.java
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class LoginController {
// 展示登录页面
@GetMapping("/login")
public String showLoginPage() {
// 返回视图名称,视图解析器将查找对应的login.html或login.jsp
return "login";
}
// 处理登录请求
@PostMapping("/login")
public String processLogin(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model) {
// 简单的用户名和密码校验(示例场景,实际应用需更安全的处理)
if("admin".equals(username) && "123456".equals(password)) {
model.addAttribute("message", "登录成功!");
return "welcome"; // 返回欢迎页视图
} else {
model.addAttribute("error", "用户名或密码错误!");
return "login"; // 返回登录页以便重新登录
}
}
}
在上面的@Controller案例中:
场景描述:构建一个简单的用户信息查询API。请求接口返回JSON格式的用户数据,供前端或其他服务调用。
示例代码:
// 文件路径:com.example.demo.controller.UserApiController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.User;
@RestController
public class UserApiController {
// API接口:通过用户id查询用户信息并以JSON格式返回
@GetMapping("/api/users/{id}")
public User getUserById(@PathVariable("id") int id) {
// 示例:构建一个用户对象,实际中可能通过数据库查询返回用户数据
return new User(id, "User" + id);
}
}
// 文件路径:com.example.demo/model/User.java
package com.example.demo.model;
public class User {
private int id;
private String name;
public User() {}
public User(int id, String name) {
this.id = id;
this.name = name;
}
// Getter和Setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在上面的@RestController案例中:
代码结构:
开发体验:
Controller开发体验:
• 需要定义多个视图文件,涉及前后端协同工作,前端与后端模板的对接测试较为复杂。
• 开发过程中需要关注ViewResolver、静态资源映射等Web配置事项。
RestController开发体验:
• 无需考虑视图解析、页面跳转等问题,开发者只需专注于业务逻辑和数据转换。
• 调试时可使用Postman、浏览器直接测试API接口,调试流程简单高效。
• 适合构建前后端完全分离的项目,前后端接口定义清晰。
总体来说:
在开发过程中,使用@Controller和@RestController可能会遇到一些常见问题。下面列出几种常见场景及相应的解决方案和调试技巧。
混用风险:
注意点:
调试技巧:
JSON返回格式错误:
页面解析问题:
配置和依赖管理:
模块间路径分离:
日志和监控: