摘要:網上很多關于的分析,但很少有手動實現的,這里通過一個簡單的實現基本功能,僅供學習參考。下面編寫一個和測試下代碼如下代碼如下請求學習交流,歡迎加群
網上很多關于springmvc的分析,但很少有手動實現的,這里通過一個簡單的demo實現mvc基本功能,僅供學習參考。
我們先簡單了解下springmvc請求流程,如下圖:
從圖上得知,最先處理請求的是dispatcherServlet,它接受請求并查詢得到攔截器鏈HandlerExecutionChain,HandlerAdapter經過適配器調用具體的處理器(Controller).
查看源碼可以到spring-webmvc.jar中,org.springframework.web.servlet/DispatcherServlet.class,其中方法doDispatch()完成了一個請求到返回數據的完整操作.
下面我們開始動手了,先創建一個javaweb工程,寫一個Servlet,如下:
@WebServlet(urlPatterns = "/*", loadOnStartup = 1) public class DispatcherServlet extends HttpServlet { private ListclzList = new ArrayList<>(); private Map beansMap = new HashMap<>(); private Map urlMapping = new HashMap<>(); @Override public void init() throws ServletException { try { //掃描配置 這里是包名 scanPackages("com.iti.smvc"); //實例化對象 doInstance(); //建立對象之間的依賴ioc ioc(); //建立url到controller的映射 doMapping(); } catch (Exception e) { e.printStackTrace(); } } }
注:servlet3.0不再需要web.xml, 這里將成員變量寫入servlet并不是很好的實現,會導致線程不安全
這個servlet要做一些初始化的工作,如:
1.掃描包名,將class對象裝入clzList列表
2.遍歷clzList列表,實例化有Controller和Service標注的類
3.依賴注入,將service注入到controller
4.建立url與controller中方法url的mapping關系
我們依次來實現他們:
下面的是掃描配置方法
private void scanPackages(String packageUrl) { String fileUrl = getClass().getClassLoader().getResource("/"+packageUrl.replaceAll(".", "/")).getFile(); File scanfile = new File(fileUrl); String[] fileList = scanfile.list(); for (String fileName: fileList) { File file = new File(fileUrl+fileName); if (file.isDirectory()) { scanPackages(packageUrl + "." + fileName);; } else { clzList.add(packageUrl + "." + fileName.replace(".class", "")); } } }
接著是對象實例化:
private void doInstance() throws Exception{ if (clzList.size()>0) { for (String clzName : clzList) { Class> clzClass = Class.forName(clzName); if (clzClass.isAnnotationPresent(Controller.class)) { //for controller RequestMapping rm = clzClass.getAnnotation(RequestMapping.class); beansMap.put(rm.value(), clzClass.newInstance()); } else if (clzClass.isAnnotationPresent(Service.class)) { Service service = clzClass.getAnnotation(Service.class); beansMap.put(service.value(), clzClass.newInstance()); } } } }
接著是依賴注入,其實是反射:
private void ioc() throws Exception{ if (beansMap.size()>0) { for (Map.Entryentry : beansMap.entrySet()) { Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { Qualifier anno = field.getAnnotation(Qualifier.class); field.set(entry.getValue(), beansMap.get(anno.value())); } } } } }
最后是建立請求url與controller的mapping關系,如下:
private void doMapping() { if (beansMap.size()>0) { for (Map.Entryentry: beansMap.entrySet()) { Class extends Object> obj = entry.getValue().getClass(); if (obj.isAnnotationPresent(Controller.class)){ RequestMapping rm = obj.getAnnotation(RequestMapping.class); Method[] methods = obj.getMethods(); for (Method method: methods) { if (method.isAnnotationPresent(RequestMapping.class)) { RequestMapping anno = method.getAnnotation(RequestMapping.class); urlMapping.put(rm.value() + anno.value(), method); } } } } } }
還要把注解創建下:
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Controller { String value() default ""; } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Qualifier { String value() default ""; } @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestMapping { String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Service { String value() default ""; }
此時就可以啟動服務完成初始化工作了
下面我們要創建一個sevice方法來接收url請求
@Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); String contextPath = req.getContextPath(); //得到請求地址 String path = requestURI.replace(contextPath, ""); Method method = (Method)urlMapping.get(path); if (method != null) { try { Object obj = method.invoke(beansMap.get("/"+path.split("/")[1])); resp.getOutputStream().write(obj.toString().getBytes()); } catch (Exception e) { e.printStackTrace(); } } }
上面是得到請求url,然后從urlMapping得到要調用的method,再通過反射調用,最后通過outputStream輸出到瀏覽器上。
下面編寫一個controller和service測試下
controller代碼如下:
@Controller @RequestMapping("/hello") public class HelloController { @Autowired @Qualifier("helloservice") Helloservice helloservice; @RequestMapping("/sayHello") public String sayHello() { //System.out.println(helloservice.hello()); return "controller"; } }
service代碼如下:
@Service("helloservice") public class Helloservice { public String hello() { return "hello"; } }
請求url:http://localhost:8080/hello/sayHello
學習交流,歡迎加群:64691032
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76973.html
摘要:引言剛考完期末,再也不用考試啦最近學習了慕課網的實戰課手寫,劍指開源框架靈魂。最近將本課程和看透結合起來學習,感覺受益匪淺,同時,糾正了我之前對的一些誤解。誤解洪荒時代的當年,開發都需要手動去實現。為了解決太多的問題,引入了,進行統一調度。 引言 剛考完期末,再也不用考試啦!!! 最近學習了慕課網的實戰課《手寫SpringMVC,劍指開源框架靈魂》。 showImg(https://s...
摘要:也就是說映射器就是用于處理什么樣的請求提交給處理。這和是一樣的提交參數的用戶名編號提交配置處理請求注冊映射器包框架接收參數設置無參構造器,里邊調用方法,傳入要封裝的對象這里的對象就表示已經封裝好的了對象了。 什么是SpringMVC? SpringMVC是Spring家族的一員,Spring是將現在開發中流行的組件進行組合而成的一個框架!它用在基于MVC的表現層開發,類似于struts...
摘要:只要有一個攔截器不放行,不能執行完成號不放行和號不放行測試結果總結只有前邊的攔截器方法放行,下邊的攔截器的才執行。至于他們的攔截器鏈的調用順序,和的是沒有差別的。 前言 本博文主要講解的知識點如下: 校驗器 統一處理異常 RESTful 攔截器 Validation 在我們的Struts2中,我們是繼承ActionSupport來實現校驗的...它有兩種方式來實現校驗的功能 手寫...
摘要:接口聲明并實現接口聲明一個接口新建一個類,并實現接口單元測試單元測試是為了驗證第步中接口的方法。中新增類使用實現單元測試指定注入的配置文件使用標準的注釋來告訴使用在中新增類文件運行單元測試右鍵運行結果到此,我們已經搭建了一個基于的項目環境。 本文詳細講述如何搭建一個Spring+SpringMVC+Maven+Mybatis+MySQL項目環境。eclipse、maven 及 mysq...
閱讀 351·2024-11-07 18:25
閱讀 130598·2024-02-01 10:43
閱讀 914·2024-01-31 14:58
閱讀 879·2024-01-31 14:54
閱讀 82884·2024-01-29 17:11
閱讀 3176·2024-01-25 14:55
閱讀 2028·2023-06-02 13:36
閱讀 3108·2023-05-23 10:26