javascript
js如何在当前页面加载springmvc返回的页面_手写SpringMVC学习
前面我們學習了spring框架源碼,做了一些自己手寫的學習,最近,我們開始學習springMVC框架的學習 ,springMVC框架,相信大家不陌生了,所以這里不做過多的介紹了。
SpringMVC以DispatcherServlet為核心,負責協調和組織不同組件以完成請求處理并返回響應的工作,實現了MVC模式。想要實現自己的SpringMVC框架,需要從以下幾點入手:
1、了解SpringMVC運行流程及九大組件
2、梳理自己的SpringMVC的設計思路
3、實現自己的SpringMVC框架
一、SpringMVC流程圖
二、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的九大組件
protected void initStrategies(ApplicationContext context) {
//用于處理上傳請求。處理方法是將普通的request包裝成MultipartHttpServletRequest,后者可以直接調用getFile方法獲取File.
initMultipartResolver(context);
//SpringMVC主要有兩個地方用到了Locale:一是ViewResolver視圖解析的時候;二是用到國際化資源或者主題的時候。
initLocaleResolver(context);
//用于解析主題。SpringMVC中一個主題對應一個properties文件,里面存放著跟當前主題相關的所有資源、
//如圖片、css樣式等。SpringMVC的主題也支持國際化,
initThemeResolver(context);
//用來查找Handler的。
initHandlerMappings(context);
//從名字上看,它就是一個適配器。Servlet需要的處理方法的結構卻是固定的,都是以request和response為參數的方法。
//如何讓固定的Servlet處理方法調用靈活的Handler來進行處理呢?這就是HandlerAdapter要做的事情
initHandlerAdapters(context);
//其它組件都是用來干活的。在干活的過程中難免會出現問題,出問題后怎么辦呢?
//這就需要有一個專門的角色對異常情況進行處理,在SpringMVC中就是HandlerExceptionResolver。
initHandlerExceptionResolvers(context);
//有的Handler處理完后并沒有設置View也沒有設置ViewName,這時就需要從request獲取ViewName了,
//如何從request中獲取ViewName就是RequestToViewNameTranslator要做的事情了。
initRequestToViewNameTranslator(context);
//ViewResolver用來將String類型的視圖名和Locale解析為View類型的視圖。
//View是用來渲染頁面的,也就是將程序返回的參數填入模板里,生成html(也可能是其它類型)文件。
initViewResolvers(context);
//用來管理FlashMap的,FlashMap主要用在redirect重定向中傳遞參數。
initFlashMapManager(context);
}
四、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類中,實現下面幾個步驟:
3、運行階段,每一次請求將會調用doGet或doPost方法,它會根據url請求去HandlerMapping中匹配到對應的Method,然后利用反射機制調用Controller中的url對應的方法,并得到結果返回。
六、代碼實現
在SpringMVC的框架實現中,少不了一些基本的注入類,例如:@Controller、@RequestMapping、@RequestParam等等,在上一篇文章中,根據需要實現的代碼塊,需要自定義一些注解類:
@MyController
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyController {String value() default "";@MyRequestMapping
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestMapping {String value() default ""; }@MyAutowired
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAutowired {boolean required() default true; }@MyRequestParam
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyRequestParam {String value() default ""; }@MyService
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyService {String value() default ""; }web.xm加載
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><display-name>spring_mvc</display-name><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>com.spring.dispathcer.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping> </web-app>ClassUtils工具類封裝
public class ClassUtils {/*** 從包package中獲取所有的Class** @param pack* @return*/public static List<Class<?>> getClasses(String packageName) {// 第一個class類的集合List<Class<?>> classes = new ArrayList<Class<?>>();// 是否循環迭代boolean recursive = true;// 獲取包的名字 并進行替換String packageDirName = packageName.replace('.', '/');// 定義一個枚舉的集合 并進行循環來處理這個目錄下的thingsEnumeration<URL> dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);// 循環迭代下去while (dirs.hasMoreElements()) {// 獲取下一個元素URL url = dirs.nextElement();// 得到協議的名稱String protocol = url.getProtocol();// 如果是以文件的形式保存在服務器上if ("file".equals(protocol)) {// 獲取包的物理路徑String filePath = URLDecoder.decode(url.getFile(), "UTF-8");// 以文件的方式掃描整個包下的文件 并添加到集合中findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);} else if ("jar".equals(protocol)) {// 如果是jar包文件// 定義一個JarFileJarFile jar;try {// 獲取jarjar = ((JarURLConnection) url.openConnection()).getJarFile();// 從此jar包 得到一個枚舉類Enumeration<JarEntry> entries = jar.entries();// 同樣的進行循環迭代while (entries.hasMoreElements()) {// 獲取jar里的一個實體 可以是目錄 和一些jar包里的其他文件 如META-INF等文件JarEntry entry = entries.nextElement();String name = entry.getName();// 如果是以/開頭的if (name.charAt(0) == '/') {// 獲取后面的字符串name = name.substring(1);}// 如果前半部分和定義的包名相同if (name.startsWith(packageDirName)) {int idx = name.lastIndexOf('/');// 如果以"/"結尾 是一個包if (idx != -1) {// 獲取包名 把"/"替換成"."packageName = name.substring(0, idx).replace('/', '.');}// 如果可以迭代下去 并且是一個包if ((idx != -1) || recursive) {// 如果是一個.class文件 而且不是目錄if (name.endsWith(".class") && !entry.isDirectory()) {// 去掉后面的".class" 獲取真正的類名String className = name.substring(packageName.length() + 1, name.length() - 6);try {// 添加到classesclasses.add(Class.forName(packageName + '.' + className));} catch (ClassNotFoundException e) {e.printStackTrace();}}}}}} catch (IOException e) {e.printStackTrace();}}}} catch (IOException e) {e.printStackTrace();}return classes;}/*** 以文件的形式來獲取包下的所有Class** @param packageName* @param packagePath* @param recursive* @param classes*/public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,List<Class<?>> classes) {// 獲取此包的目錄 建立一個FileFile dir = new File(packagePath);// 如果不存在或者 也不是目錄就直接返回if (!dir.exists() || !dir.isDirectory()) {return;}// 如果存在 就獲取包下的所有文件 包括目錄File[] dirfiles = dir.listFiles(new FileFilter() {// 自定義過濾規則 如果可以循環(包含子目錄) 或則是以.class結尾的文件(編譯好的java類文件)@Overridepublic boolean accept(File file) {return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));}});// 循環所有文件for (File file : dirfiles) {// 如果是目錄 則繼續掃描if (file.isDirectory()) {findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,classes);} else {// 如果是java類文件 去掉后面的.class 只留下類名String className = file.getName().substring(0, file.getName().length() - 6);try {// 添加到集合中去classes.add(Class.forName(packageName + '.' + className));} catch (ClassNotFoundException e) {e.printStackTrace();}}}} }未完待續。。。。
總結
以上是生活随笔為你收集整理的js如何在当前页面加载springmvc返回的页面_手写SpringMVC学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php头尾分离,laravel怎么做模板
- 下一篇: 已达成计算机的连接数最大值无法再,已达到