Spring MVC 简介
什么是Spring MVC?
Spring MVC是Spring Framework的一部分,是一个基于Java的Web MVC框架。它采用Model-View-Controller设计模式,帮助开发者构建灵活、松耦合的Web应用程序。
MVC架构
Model(模型)
负责业务逻辑和数据处理。
View(视图)
负责展示数据给用户。
Controller(控制器)
负责接收用户请求,调用模型处理业务,选择视图展示结果。
Client → Controller → Service → Repository → Database
↓
View → ClientSpring MVC核心组件
1. DispatcherServlet
前端控制器,负责请求分发。
java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// 配置
}2. Controller
处理HTTP请求。
java
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id, Model model) {
User user = userService.getUserById(id);
model.addAttribute("user", user);
return "user-detail";
}
}3. HandlerMapping
将请求映射到处理器。
4. HandlerAdapter
执行处理器。
5. ViewResolver
解析视图名称。
java
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}@Controller vs @RestController
@Controller
返回视图名称。
java
@Controller
public class PageController {
@GetMapping("/home")
public String home(Model model) {
model.addAttribute("message", "Welcome");
return "home"; // 返回视图名称
}
}@RestController
直接返回数据(JSON/XML),相当于@Controller + @ResponseBody。
java
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id); // 自动转换为JSON
}
}请求映射
@RequestMapping
java
@Controller
@RequestMapping("/products")
public class ProductController {
// GET /products
@RequestMapping(method = RequestMethod.GET)
public String list() {
return "product-list";
}
// POST /products
@RequestMapping(method = RequestMethod.POST)
public String create(@ModelAttribute Product product) {
productService.save(product);
return "redirect:/products";
}
}简化注解
java
@RestController
@RequestMapping("/api/products")
public class ProductApiController {
@GetMapping // GET请求
public List<Product> list() {
return productService.findAll();
}
@PostMapping // POST请求
public Product create(@RequestBody Product product) {
return productService.save(product);
}
@PutMapping("/{id}") // PUT请求
public Product update(@PathVariable Long id, @RequestBody Product product) {
return productService.update(id, product);
}
@DeleteMapping("/{id}") // DELETE请求
public void delete(@PathVariable Long id) {
productService.delete(id);
}
@PatchMapping("/{id}") // PATCH请求
public Product partialUpdate(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
return productService.partialUpdate(id, updates);
}
}参数绑定
1. @PathVariable - 路径变量
java
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
// 多个路径变量
@GetMapping("/users/{userId}/orders/{orderId}")
public Order getUserOrder(@PathVariable Long userId, @PathVariable Long orderId) {
return orderService.getOrder(userId, orderId);
}
// 自定义变量名
@GetMapping("/users/{id}")
public User getUser(@PathVariable("id") Long userId) {
return userService.getUserById(userId);
}2. @RequestParam - 查询参数
java
// GET /search?keyword=spring&page=1&size=10
@GetMapping("/search")
public List<Product> search(
@RequestParam String keyword,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
return productService.search(keyword, page, size);
}
// 可选参数
@GetMapping("/users")
public List<User> getUsers(@RequestParam(required = false) String name) {
if (name != null) {
return userService.findByName(name);
}
return userService.findAll();
}3. @RequestBody - 请求体
java
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
// 配合@Valid进行校验
@PostMapping("/users")
public User createUser(@Valid @RequestBody User user) {
return userService.save(user);
}4. @RequestHeader - 请求头
java
@GetMapping("/info")
public String getInfo(
@RequestHeader("User-Agent") String userAgent,
@RequestHeader(value = "Authorization", required = false) String token) {
return "User-Agent: " + userAgent;
}5. @CookieValue - Cookie值
java
@GetMapping("/preference")
public String getPreference(@CookieValue(value = "theme", defaultValue = "light") String theme) {
return "Current theme: " + theme;
}6. @ModelAttribute - 表单绑定
java
@PostMapping("/register")
public String register(@ModelAttribute User user) {
userService.register(user);
return "redirect:/login";
}7. @SessionAttribute - 会话属性
java
@GetMapping("/profile")
public String profile(@SessionAttribute("currentUser") User user, Model model) {
model.addAttribute("user", user);
return "profile";
}返回类型
1. String - 视图名称
java
@GetMapping("/home")
public String home() {
return "home"; // 返回home.jsp
}2. ModelAndView
java
@GetMapping("/user/{id}")
public ModelAndView getUser(@PathVariable Long id) {
ModelAndView mav = new ModelAndView("user-detail");
User user = userService.getUserById(id);
mav.addObject("user", user);
return mav;
}3. ResponseEntity
java
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.getUserById(id);
if (user == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(user);
}
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity
.created(URI.create("/api/users/" + savedUser.getId()))
.body(savedUser);
}4. void - 异步处理
java
@GetMapping("/async")
public void asyncProcess(HttpServletResponse response) throws IOException {
// 异步处理
response.getWriter().write("Processing...");
}5. 对象 - 自动转JSON
java
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.getUserById(id); // 自动转换为JSON
}完整CRUD示例
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// 查询所有用户
@GetMapping
public ResponseEntity<List<User>> getAllUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page<User> userPage = userService.findAll(PageRequest.of(page, size));
return ResponseEntity.ok(userPage.getContent());
}
// 根据ID查询用户
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.getUserById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// 创建用户
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity
.created(URI.create("/api/users/" + savedUser.getId()))
.body(savedUser);
}
// 更新用户
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@Valid @RequestBody User user) {
return userService.update(id, user)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
if (userService.delete(id)) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
}异常处理
局部异常处理
java
@RestController
public class UserController {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(ex.getMessage());
}
}全局异常处理
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
ErrorResponse error = new ErrorResponse(404, ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse error = new ErrorResponse(500, "内部服务器错误");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
}拦截器
java
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
System.out.println("请求URL: " + request.getRequestURI());
return true; // 返回true继续处理,false中断
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) {
System.out.println("请求处理完成");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
System.out.println("视图渲染完成");
}
}
// 注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggingInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
}
}跨域配置
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
// 或使用注解
@CrossOrigin(origins = "http://localhost:3000")
@RestController
public class UserController {
// ...
}