1. 程式人生 > >手寫SpringMVC-實戰篇

手寫SpringMVC-實戰篇

       有了手寫SpringMVC的思路,不知道大家是否已經開始實現呢?現在就為大家開始以上一篇文章《手寫SpringMVC-思路篇》的思路來一步步的實現SpringMVC的手寫,讓大家也能在SpringMVC的實現上有個初步的認識。此篇文章可能有些長,希望大家可以一邊看,一邊動手按照提供的程式碼(此篇文章程式碼有些多)來實現。

一、先還是給大家看看程式碼的結構

上述的就是目前的服務端段程式碼,在專案的src->main->webapp->WEB-INF下建立一個web.xml檔案,在專案啟動的時候,載入web.xml檔案,注入DispatcherServlet,實現後續的例項注入和初始化,並實現web的URL訪問服務端,實現資料的響應。

二、考慮定義註解類

   在SpringMVC的框架實現中,少不了一些基本的注入類,例如:@Controller、@RequestMapping、@RequestParam等等,在上一篇文章中,根據需要實現的程式碼塊,需要自定義一些註解類:

@CustomController   

@CustomRequestMapping

@CustomQualifier

@CustomRequestParam

@CustomService

這些分別對應著Spring+SpringMVC呼叫的實現註解,我們現在手動來寫入這些註解。此處不過多的講述,大家可以看文章手寫SpringMVC-思路篇

》中的第一部分,與SpringMVC的註解來對應理解。

註解[email protected]   

package com.ygsoft.custom.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomController {
	String value() default "";
}

註解[email protected]

package com.ygsoft.custom.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequestMapping {
	String value() default "";
}

註解[email protected]

package com.ygsoft.custom.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomQualifier {
	String value() default "";
}

註解[email protected]

package com.ygsoft.custom.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomRequestParam {
	String value() default "";
}

註解[email protected]

package com.ygsoft.custom.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomService {
	String value() default "";
}

如果大家對註解定義不熟悉,最好去百度下,理解下如何自定義註解。

三、建立Controller和Service層

此部分和SpringMVC的實現程式碼一樣,只是這部分的註解都是上一步定義的註解類來實現。

Controller層:

package com.ygsoft.custom.controller;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomController;
import com.ygsoft.custom.annotation.CustomQualifier;
import com.ygsoft.custom.annotation.CustomRequestMapping;
import com.ygsoft.custom.annotation.CustomRequestParam;
import com.ygsoft.custom.service.MyService;

@CustomController
@CustomRequestMapping("/custom")
public class MyController {
	
	@CustomQualifier("MyServiceImpl")
	private MyService myService;
	
	@CustomRequestMapping("/query")
	public void query(HttpServletRequest request, HttpServletResponse response,
			@CustomRequestParam("name")String name, @CustomRequestParam("age")String age) {
		PrintWriter pw;
		try {
			PrintWriter writer = response.getWriter();
			String result = myService.query(name, age);
			writer.write(result);
		} catch (IOException e) {
			e.printStackTrace();
		}
	} 
	
}

Service層:

package com.ygsoft.custom.service;

public interface MyService {
	public String query(String name, String age);
}

Service的impl層:

package com.ygsoft.custom.service.impl;

import com.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.service.MyService;

@CustomService("MyServiceImpl")
public class MyServiceImpl implements MyService{

	@Override
	public String query(String name, String age) {
		return "name:" + name + ";age:" + age;
	}

}

四、建立DispatcherServlet類,並通過web.xml載入

web.xml:載入我們自己寫的MyDispatcherServlet和讀取配置檔案。

<?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>maven_handmvc</display-name>
  <servlet>
  	<servlet-name>DispatcherServlet</servlet-name>
  	<servlet-class>com.ygsoft.custom.servlet.DispatcherServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>DispatcherServlet</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

DispatcherServlet:本質上,我們自定義的DispatcherServlet是繼承了HttpServlet,主要是實現init()、doGet()、doPost()方法,init()方法,就是初始化基本的beans,並例項化controller層中的定義的service的變數,同時實現對映URL請求的Path和方法;doGet()、doPost()目前給的是doGet()呼叫doPost(),所以doPost()主要是實現引數的解析,並通過反射的機制實現方法的呼叫。

package com.ygsoft.custom.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomController;
import com.ygsoft.custom.annotation.CustomQualifier;
import com.ygsoft.custom.annotation.CustomRequestMapping;
import com.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.controller.MyController;
import com.ygsoft.custom.handlerAdapter.HandlerAdapterService;

public class DispatcherServlet extends HttpServlet {

	// 存在當前載入的所有的類
	List<String> classNames = new ArrayList<String>();
	
	// 儲存IOC容器的MAP
	Map<String, Object> beans = new HashMap<>();
	
	// 儲存路徑和方法的對映關係
	Map<String, Object> handlerMap = new HashMap<String, Object>();
	
	public DispatcherServlet() {
		System.out.println("DispatchServlet()........");
	}
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("init()............");
		
		// 1.掃描需要的例項化的類
		doScanPackage("com.ygsoft.custom");
		System.out.println("當前檔案下所有的class類.......");
		for(String name: classNames) {
			System.out.println(name);
		}
		
		// 2.例項化
		doInstance();
		System.out.println("當前例項化的物件資訊.........");
		for(Map.Entry<String, Object> map: beans.entrySet()) {
			System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
		}
		
		// 3.將IOC容器中的service物件設定給controller層定義的field上
		doIoc();
		
		// 4.建立path與method的對映關係
		handlerMapping();
		System.out.println("Controller層的path和方法對映.........");
		for(Map.Entry<String, Object> map: handlerMap.entrySet()) {
			System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
		}
	}

	private void doScanPackage(String basePackage) {
		URL resource = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));
		String fileStr = resource.getFile();
//		System.out.println(fileStr);
		File file = new File(fileStr);
		String[] listFiles = file.list();
		for(String path: listFiles) {
			File filePath = new File(fileStr + path);
			// 如果當前是目錄,則遞迴
			if(filePath.isDirectory()) {
				doScanPackage(basePackage + "." + path);
			// 如果是檔案,則直接新增到classNames
			} else {
				classNames.add(basePackage + "." + filePath.getName());
			}
		}
	}
	
	// 通過儲存的classnames的類字串來反射例項化物件,並存儲與beans的Map中
	// com.ygsoft.custom.annotation.CustomController.class =>com.ygsoft.custom.annotation.CustomController
	private void doInstance() {
		if(classNames.isEmpty()) {
			System.out.println("doScanner Fail....");
		}
		
		// 開始例項化物件,通過反射來實現
		for(String className: classNames) {
			String cn = className.replaceAll(".class", "");
			try {
				Class<?> clazz = Class.forName(cn);
				// 判斷當前類是否有註解CustomController類,獲取設定的CustomeRequestMapping的值
				if(clazz.isAnnotationPresent(CustomController.class)) {
					// 通過CustomeRequestMapping獲取值,作為beans的key
					CustomRequestMapping requestMapping = clazz.getAnnotation(CustomRequestMapping.class);
					String key = requestMapping.value();
					// beans的vaue為例項化物件
					Object value = clazz.newInstance();
					beans.put(key, value);
				// 判斷當前的類是否有註解CustomService(考慮Service層),獲取值
				} else if(clazz.isAnnotationPresent(CustomService.class)) {
					// 通過CustomService獲取值,作為beans的key
					CustomService service = clazz.getAnnotation(CustomService.class);
					String key = service.value();
					
					// beans的vaue為例項化物件
					Object value = clazz.newInstance();
					beans.put(key, value);
				} else {
					continue;
				}
				
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private void doIoc() {
		if(beans.isEmpty()) {
			System.out.println("no class is instance......");
			return;
		}
		for(Map.Entry<String, Object> map: beans.entrySet()) {
			// 獲取例項
			Object instance = map.getValue();
			
			// 獲取類
			Class<?> clazz = instance.getClass();
			// 如果當前是CustomController類,則獲取類中定義的field來設定其物件
			if(clazz.isAnnotationPresent(CustomController.class)) {
				// 獲取全部的成員變數
				Field[] fields = clazz.getDeclaredFields();
				for(Field field: fields) {
					// 如果當前的成員變數使用註解CustomRequestMapping進行處理
					if(field.isAnnotationPresent(CustomQualifier.class)) {
						// 獲取當前成員變數的註解值
						CustomQualifier qualifier = field.getAnnotation(CustomQualifier.class);
						String value = qualifier.value();
						
						// 由於此類成員變數設定為private,需要強行設定
						field.setAccessible(true);
						
						// 將beans的例項化物件賦值給當前的變數
						try {
							field.set(instance, beans.get(value));
						} catch (IllegalArgumentException e) {
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							e.printStackTrace();
						}
					} else {
						continue;
					}
				}
			}
		}
	}
	
	private void handlerMapping() {
		if(beans.isEmpty()) {
			System.out.println("no class is instance......");
			return;
		}
		for(Map.Entry<String, Object> map: beans.entrySet()) {
			// 獲取當前的物件
			Object instance = map.getValue();
			
			// 獲取當前的類
			Class<?> clazz = instance.getClass();
			// 獲取註解當前為Controller的類
			if(clazz.isAnnotationPresent(CustomController.class)) {
				// 獲取類上的路徑
				CustomRequestMapping clazzRm = clazz.getAnnotation(CustomRequestMapping.class);
				String clazzPath = clazzRm.value();
				
				// 處理方法
				Method[] methods = clazz.getMethods();
				for(Method method: methods) {
					// 判斷註解為RequestMapping
					if(method.isAnnotationPresent(CustomRequestMapping.class)) {
						// 獲取方法上的路徑
						CustomRequestMapping methodRm = method.getAnnotation(CustomRequestMapping.class);
						String methodPath = methodRm.value();
						
						// 將類上的路徑+方法上的路徑 設定為key,方法設定為value
						handlerMap.put(clazzPath + methodPath, method);
					} else {
						continue;
					}
				}
			} else {
				continue;
			}
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("doGet()............");
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("doPost()............");
		
		// 通過req獲取請求的uri /maven_handmvc/custom/query
		String uri = req.getRequestURI();
		
		// /maven_handmvc
		String context = req.getContextPath();
		String path = uri.replaceAll(context, "");
		
		// 通過當前的path獲取handlerMap的方法名
		Method method = (Method) handlerMap.get(path);
		// 獲取beans容器中的bean
		MyController instance = (MyController) beans.get("/" + path.split("/")[1]);
		
		// 處理引數
		HandlerAdapterService ha = (HandlerAdapterService) beans.get("customHandlerAdapter"); 
		Object[] args = ha.handle(req, resp, method, beans);
		
		// 通過反射來實現方法的呼叫
		try {
			method.invoke(instance, args);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void destroy() {
		System.out.println("destroy()............");
	}

	
}

DispatcherServlet類的實現中涉及到下面幾個步驟:

  • 在init方法中:

// 1.掃描需要的例項化的類
 doScanPackage("com.ygsoft.custom");
// 2.例項化
doInstance();
// 3.將IOC容器中的service物件設定給controller層定義的field上
doIoc();
 // 4.建立path與method的對映關係
handlerMapping();

  • 在doGet()和doPost()中:

主要是處理方法的引數,其中使用了策略模式來實現引數的處理,具體的可以看後續的程式碼。

 // 處理引數
        HandlerAdapterService ha = (HandlerAdapterService) beans.get("customHandlerAdapter"); 
        Object[] args = ha.handle(req, resp, method, beans);
        
 // 通過反射來實現方法的呼叫
        try {
            method.invoke(instance, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

五、引數處理涉及的類

其實此部分的實現,可以不用這麼複雜,由於個人學習,想將設計模式-策略模式使用到此部分,所以就有了下面的程式碼,其實這部分大家認為理解比較困難,或者不好理解,大家可以使用簡單的方式來實現。

使用反射呼叫實現的程式碼為:method.invoke(instance, args); 其中涉及的引數變數為args,目前的實現中請求的引數為HttpServletRequest request, HttpServletResponse response,
            @CustomRequestParam("name")String name, @CustomRequestParam("age")String age

可以通過Annotation[][] annotations = method.getParameterAnnotations();獲取所有的引數的註解 與Class<?>[] paramTypes = method.getParameterTypes();獲取所有引數的型別進行遍歷將args賦值,然後再通過上面的反射進行呼叫。

下面的程式碼是使用了策略模式來實現,大家可以借鑑,可以研究下。

HandlerAdapterService:定義一個處理引數介面

package com.ygsoft.custom.handlerAdapter;

import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerAdapterService {
	public Object[] handle(HttpServletRequest req, HttpServletResponse resp,
			Method method, Map<String, Object> beans);
}

CustomHandlerAdapter:處理引數的實現類

package com.ygsoft.custom.handlerAdapter;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomService;
import com.ygsoft.custom.argumentResolver.ArgumentResolver;

@CustomService("customHandlerAdapter")
public class CustomHandlerAdapter implements HandlerAdapterService {

	@Override
	public Object[] handle(HttpServletRequest req, HttpServletResponse resp,
			Method method, Map<String, Object> beans) {
		//獲取方法中含義的引數
		Class<?>[] paramClazzs = method.getParameterTypes();
		System.out.println("======當前需要解析的引數對應的類=========");
		for(Class<?> clazz: paramClazzs) {
			System.out.println(clazz);
		}
		
		// 定義一個返回引數的結果集
		Object[] args = new Object[paramClazzs.length];
//		Object[] args = {req, resp, "chenyanwu", "20"};
		
		// 定義一個ArgumentResolver實現類的Map
		Map<String, Object> argumentResolvers = getBeansOfType(beans, ArgumentResolver.class);
		
		System.out.println("======當前需要解析的引數對應的類例項化=========");
		for(Map.Entry<String, Object> map: argumentResolvers.entrySet()) {
			System.out.println("key:" + map.getKey() + "; value:" + map.getValue());
		}
		
		//定義引數索引
		int paramIndex = 0;
		//定義陣列下標索引
		int i = 0; 
		// 開始處理引數
		for(Class<?> paramClazz: paramClazzs) {
			//哪個引數對應了哪個引數解析類,用策略模式來找
            for (Map.Entry<String, Object> entry : argumentResolvers.entrySet()) {
                ArgumentResolver ar = (ArgumentResolver)entry.getValue();
                
                if (ar.support(paramClazz, paramIndex, method)) {
                    args[i++] = ar.argumentResolver(req,
                            resp,
                            paramClazz,
                            paramIndex,
                            method);
                }
            }
            paramIndex++;
		}
		
		return args;
	}

	/**
	 * @param beans IOC容器中全部的bean
	 * @param intfType 定義的ArgumentResolver類
	 * @return
	 */
	private Map<String, Object> getBeansOfType(Map<String, Object> beans,
			Class<ArgumentResolver> intfType) {
		Map<String, Object> resultBeans = new HashMap<>();
		for(Map.Entry<String, Object> map: beans.entrySet()) {
			// 獲取滿足ArgumentResolver介面的bean
			Class<?>[] intfs = map.getValue().getClass().getInterfaces();
			
			if(intfs != null && intfs.length >0) {
				for(Class<?> intf: intfs) {
					// 將滿足的bean儲存在resultBeans中
					if(intf.isAssignableFrom(intfType)) {
						resultBeans.put(map.getKey(), map.getValue());
					}
				}
			}
		}
		return resultBeans;
	}

}

引數類:

ArgumentResolver:

package com.ygsoft.custom.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface ArgumentResolver {
	/**
	 * 判斷當前的類是繼承於ArgumentResolver
	 * @param type 當前引數註解的類物件
	 * @param paramIndex 引數下標
	 * @param method 當前的方法
	 * @return
	 */
	public boolean support(Class<?> type, int paramIndex, Method method);
	
	/**
	 * 
	 * @param request
	 * @param response
	 * @param type
	 * @param paramIndex
	 * @param method
	 * @return
	 */
	public Object argumentResolver(HttpServletRequest request,
	            HttpServletResponse response, Class<?> type, 
	            int paramIndex,
	            Method method);
}

HttpServletRequestArgumentResolver:處理Request請求引數

package com.ygsoft.custom.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomService;

@CustomService("httpServletRequestArgumentResolver")
public class HttpServletRequestArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		return ServletRequest.class.isAssignableFrom(type);
	}

	@Override
	public Object argumentResolver(HttpServletRequest request,
			HttpServletResponse response, Class<?> type, int paramIndex,
			Method method) {
		return request;
	}

}

HttpServletResponseArgumentResolver:處理Response引數

package com.ygsoft.custom.argumentResolver;

import java.lang.reflect.Method;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomService;

@CustomService("httpServletResponseArgumentResolver")
public class HttpServletResponseArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		return ServletResponse.class.isAssignableFrom(type);
	}

	@Override
	public Object argumentResolver(HttpServletRequest request,
			HttpServletResponse response, Class<?> type, int paramIndex,
			Method method) {
		return response;
	}

}

RequestParamArgumentResolver:處理自定義的引數

package com.ygsoft.custom.argumentResolver;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.ygsoft.custom.annotation.CustomRequestParam;
import com.ygsoft.custom.annotation.CustomService;

@CustomService("requestParamArgumentResolver")
public class RequestParamArgumentResolver implements ArgumentResolver {

	@Override
	public boolean support(Class<?> type, int paramIndex, Method method) {
		// type = class java.lang.String
		// @CustomRequestParam("name")String name
		//獲取當前方法的引數
		Annotation[][] an = method.getParameterAnnotations();
		Annotation[] paramAns = an[paramIndex];
		
		for (Annotation paramAn : paramAns) {
        	//判斷傳進的paramAn.getClass()是不是 CustomRequestParam 型別
        	if (CustomRequestParam.class.isAssignableFrom(paramAn.getClass())) {
                return true;
            }
        }
		
		return false;
	}

	@Override
	public Object argumentResolver(HttpServletRequest request,
			HttpServletResponse response, Class<?> type, int paramIndex,
			Method method) {
		
		//獲取當前方法的引數
		Annotation[][] an = method.getParameterAnnotations();
		Annotation[] paramAns = an[paramIndex];
		
		for (Annotation paramAn : paramAns) {
        	//判斷傳進的paramAn.getClass()是不是 CustomRequestParam 型別
        	if (CustomRequestParam.class.isAssignableFrom(paramAn.getClass())) {
                CustomRequestParam cr = (CustomRequestParam) paramAn;
                String value = cr.value();
                
                return request.getParameter(value);
            }
        }
		return null;
	}

}

6.啟動服務,在URL輸入請求地址:

返回的結果為:

掃描關注:全棧工程師成長記
一個可以交流的平臺,目的是為了做一個影響最有影響力的人的平臺。

相關推薦

SpringMVC-實戰

       有了手寫SpringMVC的思路,不知道大家是否已經開始實現呢?現在就為大家開始以上一篇文章《手寫SpringMVC-思路篇》的思路來一步步的實現SpringMVC的手寫,讓大家也能在SpringMVC的實現上有個初步的認識。此篇文章可能有些長,希望大家可以一邊

SpringMVC實戰,從Spring底層原始碼分析與設計

課程內容: 1,三分鐘熟悉Spring底層原始碼,你只需準備好鮮花即可; 2,Spring原始碼很可怕?那是因為你沒聽過James的課; 3,快速熟悉原始碼基礎,洞析SpringMVC與Spring框架關係; 4,@Controller,@Service這些註解算什麼,一

SpringMVC到SpringBoot框架專案實戰

引言 Spring Boot其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 通過這種方式,springboot是一個快速整合第三方框架的,簡化了xml的配置,專案中再也不包含web.xml檔案了

轉載:SpringMVC框架

javaee 作用 小寫 繼承 inf group css finally 減少 帶你手寫一個SpringMVC框架(有助於理解springMVC) 鏈接:https://my.oschina.net/liughDevelop 作者:我叫劉半仙 Spring

跟我一起造輪子 springmvc

targe leg unit nco 容器 ner 並且 dir 有關   作為java程序員,項目中使用到的主流框架多多少少和spring有關聯,在面試的過程難免會問一些spring springmvc spring boot的東西,比如設計模式的使用、 怎麽實現spri

spring事務(6)-----SpringMVC模式(@RequestMapping和@Controller註解)

一,spring原生態的程式碼分析 1.1,首先,我們先來認識一下SpringMVC的主要元件   前端控制器(DisatcherServlet):接收請求,響應結果,返回可以是json,String等資料型別,也可以是頁面(Model)。   處理器對映器(HandlerMap

高手過招「效能優化/純SpringMVC框架/MySql優化/微服務」

效能優化那些絕招,一般人我不告訴他 1,支付寶介面的介面如何正確呼叫; 2,從併發程式設計角度來提高系統性能; 3,系統響應的速度縮短N倍的祕密; 4,從Futuretask類原始碼分析到手寫; 5,快速提升Web專案吞吐量;   300行精華程式碼:純手寫SpringMVC框

SpringMVC

相信用過SpringMVC的同學都會對它愛不釋手,它作為MVC框架使用起來簡直就是享受。時間久了相信會問它到底是怎麼實現的呢,今天我們來揭開其神祕的面紗。 這裡我們通過寫一個簡單的例子來模擬SpringMVC的基本原理,希望能夠對愛提問的人有所幫助 1.web.xml中配

springMVC學習心得及springMVC簡單實現

springMVC學習心得及手寫springMVC簡單實現 Spring 是一個企業級開發框架,為解決企業級專案開發過於複雜而建立的,框架的主要優勢之一就是分層架構,允許開發者自主選擇元件。 Spring 的兩大核心機制是 IoC(控制反轉)和 AOP(面向切面程式設計),從開發的角度

springmvc原理詳解(springmvc

最近在複習框架 在網上搜了寫資料 和原理 今天總結一下 希望能加深點映像  不足之處請大家指出 我就不畫流程圖了 直接通過程式碼來了解springmvc的執行機制和原理 回想用springmvc用到最多的是什麼?當然是controller和RequestMapping註解啦

SpringMVC迷你版

步驟 實現思路: 配置階段 1:在web.xml檔案中配置相應的DispatcherServlet的類路徑 2:指定application.properties的檔案路徑

SpringMVC架構,用註解實現springmvc過程(動腦學院Jack老師課後自己練習的體會)

標籤: 1、第一步,首先搭建如下架構,其中,annotation中放置自己編寫的註解,主要包括service controller qualifier RequestMapping 第二步:完成對應的annotation: package com.cn.annotation; import java.

兩小時springmvc框架

這篇文章是學習咕泡學院tom老師手寫一個spring框架視訊而來,程式碼基本複製原文,稍作修改。可以幫助我們理解springmvc實現的大致原理。 1、構建maven工程,只需要匯入javax.servlet-api的依賴。另外配置,直接通過tomcat外掛來啟動專案。

SpringMVC (一) 簡要版,去除冗餘複雜程式碼,Spring核心功能

github 地址 :https://github.com/yjy91913/jerry-mvcframework 只是閒來無事寫的簡化版,僅供大家理解SpringMvc的運作原理) 瞭解了springMVC的原始碼,寫一個功能簡單可以實現的springM

看看一個老程序員如何SpringMVC

精華 conf name isp com ner 容器 並保存 結果 人見人愛的Spring已然不僅僅只是一個框架了。如今,Spring已然成為了一個生態。但深入了解Spring的卻寥寥無幾。這裏,我帶大家一起來看看,我是如何手寫Spring的。我將結合對Spring十多年

SpringMVC框架,用註解實現springmvc過程

開發十年,就只剩下這套架構體系了! >>>   

ORM入門(一)

物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向物件程式語言裡不同型別系統的資料之間的轉換 [1]  。從效果上說,它其實是建立了一個可在程式語言裡使用的--“虛擬物件資料庫”。 面向物件是從軟

機器學習實戰(第二)-k-近鄰演算法開發識別系統

   上一篇文章中,我們學習了使用k近鄰演算法改進約會網站,實現了通過一些資料的輸入判斷人員屬於哪一個分類。但是上篇文章基於的資料都是我們能夠簡單理解的數字資訊,本篇文章我們在人不太容易看懂的資料上使用分類器。這篇文章中我們將一步步構造使用k-近鄰分類器的手寫識別系統。為了

spring+springmvc+mybatis框架——Mybatis

  整合Mybatis是本專案中的一個難點。實現功能:1 動態繫結使用者輸入引數2 Mybatis的resultType動態繫結返回實體類。3 在spring中的介面注入4 xml版本的mapper注入。 關於Mybatis的優秀文章給大家推薦兩個1 手寫簡化版mybatis

KNN 演算法-實戰-如何識別數字

> **公號:碼農充電站pro** > **主頁:** 上篇文章介紹了[KNN 演算法的原理](https://www.cnblogs.com/codeshell/p/14072586.html),今天來介紹如何**使用KNN 演算法識別手寫數字**? ### 1,手寫數字資料集 手寫數字資料集是一個用