spring mvc:
Model (数据)
View (视图)
Controller (业务)
最上层是面向用户的视图层,中间一层是业务逻辑层,最下面一层是数据层。
把数据、展示、业务逻辑进行分离,每一层的变化可以不影响其他层,增加程序的可维护性和可扩展性。
请求、响应过程
View–>Controller–>Model–>Controller-View
MVC解决思路
1、请求路由:
根据请求能找到对应的业务控制类 (HandleMapping)
2、参数适配:
根据请求参数封装到对应的Model (HandlerAdapter)
3 、视图解析:
把经过业务处理的数据解析响应给View (ViewResolver、ModeAndView)
(二)SpringMVC流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
(三)SpringMVC核心组件讲解
1、前端控制器DispatcherServlet
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、处理器映射器HandlerMapping
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
6、视图View
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
(四)手写springMvc框架思路:
1、配置web.xml,加载自定义的DispatcherServlet。
2、初始化阶段,在DispatcherServlet类中,实现下面几个步骤:
加载配置类。
扫描当前项目下的所有文件。
拿到扫描到的类,通过反射机制,实例化。并且放到ioc容器中。
初始化path与方法的映射。
获取请求传入的参数并处理参数通过初始化好的handlerMapping中拿出url对应的方法名,反射调用。
3、运行阶段,每一次请求将会调用doGet或doPost方法,它会根据url请求去HandlerMapping中匹配到对应的Method,然后利用反射机制调用Controller中的url对应的方法,并得到结果返回。
准备阶段:
代码阶段:
public class DispatcherServlet extends HttpServlet {
//springmvc 容器存放bean
private ConcurrentHashMap<String, Object> mvcBeans = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, Object> mvcBeanUrl = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, String> mvcMethodUrl = new ConcurrentHashMap<>();
@Override
public void init(ServletConfig config) {
String packagePath = "com.zzw.cn.springmvc";
//1.进行报扫描获取当前包下面所有的类
List<Class<?>> classes = comscanPackage(packagePath);
try {
//2.初始化springmvcbean
initSpringMvcBean(classes);
} catch (Exception e) {
e.printStackTrace();
}
//3.将请求地址和方法进行映射
initHandMapping(mvcBeans);
}
public List<Class<?>> comscanPackage(String packagePath) {
List<Class<?>> classes = ClassUtils.getClasses(packagePath);
return classes;
}
/**
* 初始化sprignbean
*
* @param classes
* @throws Exception
*/
public void initSpringMvcBean(List<Class<?>> classes) throws Exception {
if (classes.size() == 0 || null == classes) {
throw new Exception("包扫描后的classes为null");
}
for (Class<?> aClass : classes) {
//获取被自定义注解的controller将其初始化到自定义sprignmvc容器中
AnController declaredAnnotation = aClass.getDeclaredAnnotation(AnController.class);
if (declaredAnnotation != null) {
//获取类的名字
String beanid = lowerFirstCapse(aClass.getSimpleName());
//获取对象
Object beanObj = aClass.newInstance();
//放入sprign容器
mvcBeans.put(beanid, beanObj);
}
}
}
/**
* 初始化HandlerMapping方法
*
* @param mvcBeans
*/
public void initHandMapping(ConcurrentHashMap<String, Object> mvcBeans) {
//遍历springmvc 获取注入的对象值
for (Map.Entry<String, Object> entry : mvcBeans.entrySet()) {
Object objValue = entry.getValue();
Class<?> aClass = objValue.getClass();
//获取当前类 判断是否有自定义的requestMapping注解
String mappingUrl = null;
AnRequestMapping anRequestMapping = aClass.getDeclaredAnnotation(AnRequestMapping.class);
if (anRequestMapping != null) {
mappingUrl = anRequestMapping.value();
}
//获取当前类所有方法,判断方法上是否有注解
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method method : declaredMethods) {
AnRequestMapping methodDeclaredAnnotation = method.getDeclaredAnnotation(AnRequestMapping.class);
if (methodDeclaredAnnotation != null) {
String methodUrl = methodDeclaredAnnotation.value();
mvcBeanUrl.put(mappingUrl + methodUrl, objValue);
mvcMethodUrl.put(mappingUrl + methodUrl, method.getName());
}
}
}
}
/**
* @param str
* @return 类名首字母小写
*/
public static String lowerFirstCapse(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doServelt(req, resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private void doServelt(HttpServletRequest req, HttpServletResponse resp) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServletException {
//获取请求地址
String requestUrl = req.getRequestURI();
//查找地址所对应bean
Object object = mvcBeanUrl.get(requestUrl);
if (object == null) {
resp.getWriter().println("sorry http is not exit 404");
return;
}
//获取请求的方法
String methodName = mvcMethodUrl.get(requestUrl);
if (methodName == null) {
resp.getWriter().println("sorry method is not exit 404");
return;
}
//通过构反射执行方法
Class<?> aClass = object.getClass();
Method method = aClass.getMethod(methodName);
String invoke = (String) method.invoke(object);
// 获取后缀信息
String suffix = ".jsp";
// 页面目录地址
String prefix = "/";
req.getRequestDispatcher(prefix + invoke + suffix).forward(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
请求:
参考链接:
https://www.cnblogs.com/hang-on/p/11419298.html