javascript
ant指定servlet版本_阅读SpringMVC源码前,不妨看下简易版本SpringMVC框架的搭建
開發環境:windows10、idea、jdk1.8、apache-tomcat-9.0.0.M3
SpringMVC框架是基于Servlet設計的,所以如果你知道SpringMVC,但是沒聽過道Servlet,那你就應該先去學習下Servlet的知識點了。以下我所描述的SpringMVC框架都是簡易版本SpringMVC框架。該框架主要是以請求為驅動,其核心是DispatcherServlet類,它實際上就是一個Servlet,底層實現的也是Servlet。在SpringMVC框架中DispatcherServlet主要做兩件事,
第一 :處理請求路徑到各個Handler之間的映射,這里的Handler就類似我們平時使用的Controller,也就是struts里邊的action,這時候需要使用一個HandlerMapping的東西,也就是一個map來保存映射關系,并且需要在初始化的時候就保存,這就使用到了Servlet生命周期中初始化階段所調用的init()方法;
第二 :將用戶請求分發到各個具體的Handler,并且將請求交給Handler中的具體方法去處理,然后就接收返回回來的ModelAndView,查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖,視圖負責將結果顯示到客戶端。
首先我們先新建一個Java Enterprise項目,也就是一個java web項目
新建JavaWeb項目
?
項目建立好之后,在web.xml中我們先做簡單的配置,將客戶端所有的請求交給DispatcherServlet這個類去處理。
<?xml version="1.0" encoding="UTF-8"?>dispatcherServletcom.zhainan.springmvc.servlet.DispatcherServletdispatcherServlet/*接下來就是最為重要的DispatcherServlet實現:
public class DispatcherServlet extends HttpServlet { private Map handlerBeanMap; @Override public void init() throws ServletException { handlerBeanMap = new HashMap(); for (String name : ClassUtils.getAllClassesFromPackage("com.zhainan.springmvc.handler")) { try { Class clz = Class.forName(name); for (Method method : clz.getDeclaredMethods()) { RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); if (requestMapping != null) { String path = requestMapping.value(); handlerBeanMap.put(path, new HandlerBean(name, method.getName())); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doDispatch(req, resp); } private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException { String path = req.getPathInfo(); HandlerBean handlerBean = handlerBeanMap.get(path); if (handlerBean == null) handlerBean = new HandlerBean("com.zhainan.springmvc.handler.DefaultHandler", "doService"); try { Class clz = Class.forName(handlerBean.getBeanName()); for (Method method : clz.getDeclaredMethods()) { if (handlerBean.getMethodName().equals(method.getName())) { Parameter[] parameters = method.getParameters(); Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class); if (requestParam != null) { String parameterName = requestParam.value(); args[i] = req.getParameter(parameterName); } if (parameters[i].getType() == HttpServletResponse.class) { args[i] = resp; } } ModelAndView view = (ModelAndView) method.invoke(clz.newInstance(), args); new ViewResolver().render(view, req, resp); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }}可以看到簡易SpringMVC框架中的DispatcherServlet直接繼承自HttpServlet,重寫了它的init()方法和doGet()方法,init()方法先保存請求路徑到各個Handler之間的映射,當然這里邊就涉及了類ClassUtils中的一個重要方法和一個類HandlerBean,以及一些關鍵注解
ClassUtils類:根據包名定位到文件夾,然后根據讀取該包下所有class文件,最后根據包名和文件名,構造返回的完整類名.
public class ClassUtils { public static List getAllClassesFromPackage(String packageName){ List classNames = new ArrayList(); String pkg = "com.zhainan.springmvc.handler"; String relPath = pkg.replace('.', '/'); URL resource = Thread.currentThread().getContextClassLoader().getResource(relPath); if (resource == null) { throw new RuntimeException("Unexpected problem: No resource for " + relPath); } File f = new File(resource.getPath()); String[] files = f.list(); for (int i = 0; i < files.length; i++) { String fileName = files[i]; String className = null; String fileNm = null; if (fileName.endsWith(".class")) { fileNm = fileName.substring(0, fileName.length() - 6); className = pkg + '.' + fileNm; } if (className != null) { classNames.add(className); } } return classNames; }}HandlerBean類:具體Handler和其中處理方法的對應關系
public class HandlerBean { private String beanName; private String methodName; public HandlerBean(String beanName, String methodName) { this.beanName = beanName; this.methodName = methodName; } public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; }}注解RequestMapping:和Controller里邊的RequestMapping是一樣的道理,將請求路徑映射到某個具體方法
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestMapping { String value() default "";}注解RequestParam:和Controller里邊的RequestParam一樣,請求路徑中的請求參數接收
@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestParam { String value() default "";}注解PathVariable:和Controller里邊的PathVariable一樣,請求路徑中的路徑變量接收
@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface PathVariable { String value() default "";}doGet()方法直接調用類里邊的doDispatch()方法用于將用戶請求分發到各個具體的Handler去處理。接收返回回來的ModelAndView,查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖,視圖負責將結果顯示到客戶端。
首先來看看我們的Handler實現,在Demo中我定義了兩個Handler
DefaultHandler:用于處理默認請求
public class DefaultHandler { public void doService(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().write("this is index page !"); }}DemoHandler:用于處理指定路徑的請求,可以在這編寫相關的API
public class DemoHandler { @RequestMapping(value = "/test") public void test(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().write("test
"); } @RequestMapping(value = "/demo") public ModelAndView demo(@RequestParam(value = "name") String name, @RequestParam(value = "age") String age) { Map model = new HashMap(); model.put("name", name); model.put("age", age); return new ModelAndView(model, "my.view"); }}除此之外,還可以去編寫其他的Handler,如同Controller一樣去處理各類請求。
接下來就是關于視圖的處理了,先來看下ModelAndView
ModelAndView:ModelAndView中包含了模型(Model)和視圖(View),Handler處理完具體的業務邏輯后可以返回對應的模型和需要返回的視圖
public class ModelAndView { private Map model; private String viewName; public ModelAndView(Map model, String viewName) { this.model = model; this.viewName = viewName; } public Map getModel() { return model; } public void setModel(Map model) { this.model = model; } public String getViewName() { return viewName; } public void setViewName(String viewName) { this.viewName = viewName; }}然后再編寫一個小型的試圖解析功能
先定義一個接口View
public interface View { public void render(ModelAndView view, HttpServletRequest request, HttpServletResponse response) throws IOException;}然后定義一個淚ViewResolver去實現View的render()方法
public class ViewResolver implements View { @Override public void render(ModelAndView view, HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); String viewName = view.getViewName(); String content = loadTemplate(request.getServletContext().getResourceAsStream("/WEB-INF/" + viewName)); content = parseTemplate(view.getModel(), content); writer.write(content); } private String loadTemplate(InputStream is) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder content = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { content.append(line); } return content.toString(); } private String parseTemplate(Map model, String template) { for (Map.Entry entry : model.entrySet()) { String key = entry.getKey(); String matchedKey = String.format("${%s}", key); template = template.replaceAll(matchedKey, entry.getValue()); } return template; }}最后就是視圖文件了,demo中定義了一個簡單的視圖文件my.view
testhello,my name is ${name},${age} years old.
最終還是要展示下效果
?
?
附上項目基本結構圖和別人家的SpringMVC實現原理圖幫助理解
項目基本結構圖:
?
別人家的SpringMVC實現原理圖:
?
項目Git地址:https://gitee.com/lvchang/springmvc_demo.git
--|END|--
歡迎搜索個人微信公眾號“宅男一號”加入宅基地,給你帶來更多IT內容分享!
?
總結
以上是生活随笔為你收集整理的ant指定servlet版本_阅读SpringMVC源码前,不妨看下简易版本SpringMVC框架的搭建的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 已知三个用不同数制表示的整数_数制的概念
- 下一篇: gradle idea java ssm