简介
SpringMVC是基于MVC设计模式的一个开源框架,它是Spring框架的一部分。它是一个轻量级框架,用于开发Web应用程序,可以帮助开发者将业务逻辑和用户界面分离,提高应用程序的可维护性和可扩展性。
其核心原理流程大致为:
1. DispatcherServlet接收并分发请求
2.HandlerMapping将请求映射到对应的Controller处理器Controller处理器执行业务逻辑并返回ModelAndView对象
3.ViewResolver将ModelAndView对象映射为具体的视图
下面的组件介绍会显得有些八股文,但至关重要,文章后面会对所有组件进行源码解读。
组件介绍
DispatcherServlet
DispatcherServlet是SpringMVC的核心控制器,负责接收并分发所有的请求。它是一个Servlet,由Servlet容器管理。DispatcherServlet可以配置多个HandlerMapping和ViewResolver,通过HandlerMapping将请求映射到对应的Controller处理器,然后将Controller处理器执行的结果通过ViewResolver渲染成具体的视图。
HandlerMapping
HandlerMapping负责将请求映射到对应的Controller处理器,它可以根据不同的URL、HTTP方法等条件进行映射。SpringMVC提供了多个HandlerMapping的实现类,如RequestMappingHandlerMapping、SimpleUrlHandlerMapping等
Controller
Controller处理器是SpringMVC框架中的核心组件之一,负责处理请求并返回响应。Controller处理器可以是任何一个普通的Java类,只需要在类上添加@Controller注解或实现Controller接口即可。Controller处理器可以通过参数绑定获取请求中的数据,并将处理结果封装到ModelAndView对象中返回
ModelAndView
ModelAndView是Controller处理器返回的结果,它包含了处理结果和视图名称。处理结果可以是任何Java对象,它会被视图渲染引擎解析为HTML等格式。视图名称可以是一个逻辑名称,也可以是具体的视图文件路径
ViewResolver
ViewResolver负责将Controller处理器返回的ModelAndView对象映射为具体的视图,例如JSP(淘汰)、Velocity(淘汰)、Thymeleaf(常用)等。SpringMVC提供了多个ViewResolver的实现类,如InternalResourceViewResolver、VelocityViewResolver等.
源码解读
1.DispatcherServlet
直接上源码
public class DispatcherServlet extends HttpServlet {
private List<HandlerMapping> handlerMappings;
private List<ViewResolver> viewResolvers;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 根据请求路径查找HandlerMapping,得到对应的Controller处理器
HandlerExecutionChain chain = getHandler(request);
if (chain == null) {
// 没有找到对应的HandlerMapping,返回404错误
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
try {
// 执行Controller处理器,并获取ModelAndView对象
ModelAndView mav = chain.getHandler().handle(request, response);
// 根据ModelAndView对象查找ViewResolver,得到对应的视图
View view = resolveViewName(mav.getViewName());
// 渲染视图并返回响应
view.render(mav.getModel(), request, response);
} catch (Exception e) {
// 处理异常并返回错误页面
handleException(request, response, e);
}
}
private HandlerExecutionChain getHandler(HttpServletRequest request) {
// 遍历所有的HandlerMapping,找到匹配的处理器
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
private View resolveViewName(String viewName) {
// 遍历所有的ViewResolver,找到匹配的视图
for (ViewResolver vr : this.viewResolvers) {
View view = vr.resolveViewName(viewName);
if (view != null) {
return view;
}
}
return null;
}
}
从源码可以清晰看出DispatcherServlet流程
1.根据请求路径查找对应的HandlerMapping,得到对应的Controller处理器
2.然后执行Controller处理器并获取ModelAndView对象
3.最后根据ModelAndView对象查找对应的ViewResolver,得到具体的视图并渲染响应
2.HandlerMapping
HandlerMapping是一个接口,其中有两个方法:getHandler和registerHandlerMethod。
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
void registerHandlerMethod(Object handler, Method method, String mapping);
}
getHandler
getHandler方法用于获取处理当前请求的处理器及其拦截器链。它接收一个HttpServletRequest对象作为参数,返回一个HandlerExecutionChain对象。HandlerExecutionChain包含了一个处理器以及一组拦截器,它们会按照特定的顺序被执行。如果没有找到适合请求的处理器,则返回null。
registerHandlerMethodr
registerHandlerMethod方法用于将一个处理器方法注册到HandlerMapping中。它接收一个处理器对象、处理器方法以及该方法的请求映射作为参数。在这个方法中,可以使用一个适当的策略来确定请求映射与处理器方法之间的映射关系。
3.Controller
上面我提到过Controller处理器可以是任何一个普通的Java类。
@Controller 注解 Controller 类通常被注解为 @Controller,这个注解表示这个类是一个控制器,它可以接收 HTTP 请求并返回响应。
@RequestMapping 注解 Controller 类中的方法通常被注解为 @RequestMapping,这个注解指定了该方法所处理的 URL 请求路径,也可以指定 HTTP 请求方法类型,如 GET、POST、PUT、DELETE 等。
例如:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/list", method = RequestMethod.GET)
public ModelAndView listUsers() {
// ...
}
}
在上面的例子中,UserController 类被注解为 @Controller,并且指定了它所处理的请求路径为 "/user"。该类中的 listUsers() 方法被注解为 @RequestMapping,指定了该方法所处理的请求路径为 "/user/list",并且该方法只能处理 HTTP GET 请求。
处理方法是 Controller 中实际处理请求的方法。在 SpringMVC 中,处理方法通常返回 ModelAndView 或 ResponseEntity 类型的对象。
ModelAndView 对象用于渲染视图,它包含视图名称和模型数据。
ResponseEntity 对象用于返回 HTTP 响应,它包含响应状态码、响应头信息和响应体数据。
例如下面这个例子, listUsers() 方法返回一个 ModelAndView 对象,它的视图名称为 "user_list",模型数据为 userList.
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/list", method = RequestMethod.GET)
public ModelAndView listUsers() {
List<User> userList = userService.listUsers();
ModelAndView modelAndView = new ModelAndView("user_list");
modelAndView.addObject("userList", userList);
return modelAndView;
}
}
参数绑定 SpringMVC 支持将请求参数自动绑定到处理方法的参数中,这样可以方便地获取请求参数。常用的参数绑定方式有:
@PathVariable:用于将 URL 路径中的变量绑定到处理方法的参数中。
@RequestParam:用于将查询参数绑定到处理方法的参数中。
@RequestBody:用于将请求体中的数据绑定到处理方法的参数中。
例如:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView getUser(@PathVariable("id") Long id) {
User user = userService.getUser(id);
ModelAndView modelAndView = new ModelAndView("user_detail");
modelAndView.addObject("user", user);
return modelAndView;
}
@RequestMapping(value = "/search", method = RequestMethod.GET)
public ModelAndView searchUser(@RequestParam("name") String name) {
List<User> userList = userService.searchUser(name);
ModelAndView modelAndView = new ModelAndView("user_list");
modelAndView.addObject("userList", userList);
return modelAndView;
}
@RequestMapping(value = "/create", method = RequestMethod.POST)
public ModelAndView searchUser(@RequestBody("userInfo") User userInfo) {
//业务逻辑
return modelAndView;
}
4.ModelAndView
ModelAndView类是SpringMVC中用于绑定模型数据和视图的类,它包含以下几个属性:
model:模型数据。
viewName:要呈现的视图名称。
reference:要呈现的视图。
我们来看看它的构造方法,该构造方法接收视图名称和模型数据,并将它们保存在类的属性中
public ModelAndView(String viewName, Map<String, ?> model) {
this.viewName = viewName;
this.model = (model != null ? new HashMap<>(model) : null);
}
ModelAndView类还包含了一些getter和setter方法,以及一些常用的工具方法,如:
1.addObject(String attributeName, Object attributeValue):向模型中添加一个属性。
2.addObject(Object attributeValue):向模型中添加一个属性,属性名由类型推断得出。
3.getModelMap():返回模型数据的Map表示。
4.isEmpty():判断模型是否为空
5.ViewResolver
InternalResourceViewResolver是SpringMVC中最常用的视图解析器之一,它可以将逻辑视图名称解析为一个JSP视图对象。
InternalResourceViewResolver的源码包含以下几个重要的部分:
setViewClass(Class<? extends View> viewClass):设置视图的类型,默认为InternalResourceView。
setPrefix(String prefix):设置JSP/HTML/Thymeleaf文件的路径前缀。
setSuffix(String suffix):设置JSP/HTML/Thymeleaf文件的路径后缀。
resolveViewName()方法的实现如下
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
// 构造JSP文件的完整路径
String viewPath = getPrefix() + viewName + getSuffix();
// 创建InternalResourceView对象
InternalResourceView view = (InternalResourceView) getViewClass().newInstance();
// 设置视图的JSP文件路径
view.setUrl(viewPath);
// 返回视图对象
return view;
}
该方法首先构造了JSP/HTML/Thymeleaf文件的完整路径,然后创建了一个InternalResourceView对象,并设置其JSP/HTML/Thymeleaf文件路径,最后返回该视图对象.