Spring MVC核心理解与相关知识点
MVC是什么
MVC不单单只属于Spring,他更是一种设计模式、他最重要的目的便是“解耦”
M(Model,模型 ):数据+业务逻辑。比如
Student类,StudentService。V(View,视图):展示数据界面。比如JSP、或者是现代返回JSON格式的前端页面。
C(Controller,控制器):接收用户请求,调用Model,最后选择View来展示。
流程:用户触发键鼠监听 →Controllerna拿到请求→调Service拿到数据(Model**)→把数据交给View渲染→返回HTML给浏览器。
Spring MVC ** 就是把这个流程在Java Web 环境里面实现的一套框架。
核心组件与处理流程
Spring MVC 最核心的就是一个 前端控制器(Font Controller)——DispatcherServlet 。
一个请求的完整声明周期
请求到达
DispatcherServlet。DispatcherServlet找HandlerMapping:谁出来这个路由路径HandelerMapping返回一个HandlerEXecutionChain(包含Controller和拦截器)DispatcherServlet找HandlerAdapterHandlerAdapter执行具体方法(期间会做参数绑定、类型转换、校验等)方法返回
ModelAndView(或@ResponseBody直接返回数据)若有视图名,
ViewResolver解析出真正的JSP等视图渲染视图,响应给浏览器。
Controller与注解
@Controller & @RestController
@Controller // 声明这是一个控制器类,方法通常返回视图名
public class TeacherController { ... }
@RestController // = @Controller + @ResponseBody,所有方法默认返回 JSON
public class TeacherRestController { ... }
@RequestMapping 及衍生注解
@RequestMapping("/teacher") // 类级别映射
public class TeacherController {
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String list() { ... } // 等价于 @GetMapping("/list")
}
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 等都是 @RequestMapping 的快捷方式。
参数绑定注解
把参数自动封装成对象
Spring 可以直接将表单字段或 JSON ** 映射成一个 Java Bean。
表单提交示例:
错误: Language jsp is not included in this bundle. You may want to load it from external source.
@PostMapping("/teacher/save")
public String save(@ModelAttribute Teacher teacher) {
// teacher 对象已被自动填充 name 和 age
teacherService.save(teacher);
return "redirect:/teacher/list";
}
底层原理:DataBinder + BeanWrapper 负责属性拷贝。
自定义类型转换器: String → Date
很多时候,请求参数是 String,但你想转成 Date、LocalDate 或自定义类型。
Spring 内置的转换器和格式化器
Converter<S, T>:源类型 → 目标类型,如
StringToDateConverter。Formatter:专为字符串和对象互转设计,支持国际化,适合
String <-> Date。
自定义一个 String → Date 的 Converter 示例
@Component
public class StringToDateConverter implements Converter<String, Date> {
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String source) {
try {
return format.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException("日期格式必须为 yyyy-MM-dd");
}
}
}
在 Spring Boot ** 中,只需让它被容器管理(@Component)就会自动注册到转换器链。
在传统 Spring MVC XML 中,需要配置 FormattingConversionServiceFactoryBean。
使用场景
@GetMapping("/teacher/search")
public String searchByDate(@RequestParam("date") Date date) {
// /teacher/search?date=2025-01-01 → date 直接转换好
}
如果转换失败,会抛出 TypeMismatchException,我们可以用异常处理来统一返回友好信息。
拦截器(Interceptor)和过滤器(Filter)
两者都可以在请求前后做手脚,但层级不同。
定义拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 检查 session 中是否有用户
if (request.getSession().getAttribute("user") == null) {
response.sendRedirect("/login");
return false; // 不放行
}
return true;
}
}
注册拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/teacher/**") // 要拦截的
.excludePathPatterns("/teacher/login"); // 排除的
}
}
异常处理
局部异常处理
@Controller
public class TeacherController {
@ExceptionHandler(TeacherNotFoundException.class)
public String handleNotFound(TeacherNotFoundException ex, Model model) {
model.addAttribute("msg", ex.getMessage());
return "error/404"; // 返回错误视图
}
}
全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public Map<String, String> handleValidation(MethodArgumentNotValidException ex) {
// 返回校验失败信息,如 {"name":"不能为空"}
...
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public Map<String, String> handleGeneral(Exception ex) {
return Map.of("error", "服务器内部错误");
}
}