# Spring MVC 簡單實現
![](https://i.imgur.com/ze9pmDK.png)
![](https://i.imgur.com/t0Xos4U.png)
奮戰三天,差不多完成一些框架比較常用的功能,接下來是 mybitis 實現?
* 支持 get/post
* aop
* 自動注入
* 內建tomcat
# main
進入點
```java
public class Test {
public static void main(String[] args) throws LifecycleException, InterruptedException, ServletException {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext ();}
}
```
# MyRequestMapping
進入點
```java
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
```
# MyRequestParam
進入點
```java
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
```
# AnnotationConfigApplicationContext
```java
public class AnnotationConfigApplicationContext {
public UtilsScan tmp = new UtilsScan();
public AnnotationConfigApplicationContext () throws LifecycleException {
}
public Object getBean (String className)
{
for (Map<String, Object> map : tmp.ioclist ){
Object object = map.get(className);
if(object!=null)
{
return object;
}
}
return null;
}
}
```
# pom
仿照 spring boot
自我引入tomcat 注意與引入的 servlet 匹配
``` xml
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.37</version>
</dependency>
```
# UtilsScan
新增 initHandlerMapping ,簡單來說就是 去掃相對的 註解和相對應的 class 和 method 然後把它個別塞到相對印的 map
這邊可以看到我是用 url 和 method 去做匹配
```java
public class UtilsScan {
public static List<Map <String , Object>> ioclist = new ArrayList<>();
public static List<Map <String , Object>> proxyioclist = new ArrayList<>();
private Properties properties = new Properties();
private static Map<String, Method> handlerMapping = new HashMap<>();
private static Map<String, Object> controllerMap =new HashMap<>();
public UtilsScan() throws LifecycleException {
UtilsScan.doScan();
java.io.File file = new java.io.File("." );
int port = 8080;
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("temp");
tomcat.setPort(port);
String contextPath = "/";
String docBase = file.getAbsolutePath();
Context context = tomcat.addContext(contextPath, docBase);
HttpServlet servlet = new MyDispatcherServlet(handlerMapping,controllerMap);
String servletName = "MyDispatcherServlet";
String urlPattern = "/*";
tomcat.addServlet(contextPath, servletName, servlet);
context.addServletMappingDecoded(urlPattern, servletName);
tomcat.start();
tomcat.getServer().await();
// ServletConfig tmp =this.getServletConfig();
// doLoadConfig(tmp.getInitParameter("contextConfigLocation"));
//
// UtilsScan.doScan();
}
public static void doScan(){
String packagePath = "D:\\Programming\\spring\\minispringcore\\minispring\\src\\main\\java\\com\\spring\\demo";
File file = new File (packagePath );
String[] childFile = file.list();
for (String fileName : childFile) {
System.out.println(fileName);
File childfiletmp = new File( packagePath +"\\" +fileName);
String classFileName[] = childfiletmp.list();
for (String className : classFileName ){
if(className.equals("aop") || className.equals("run") || className.equals("MyDispatcherServlet") )
continue;
className = className.substring(0,className.indexOf("."));
Object object = null;
try {
System.out.println("com.spring." + fileName +"." + className);
Class classtmp = Class.forName("com.spring.demo." + fileName +"." + className);
if(classtmp.isAnnotationPresent(ComponentTest.class))
{
object = classtmp.newInstance();
Map<String , Object> map= new HashMap<>();
map.put(classtmp.getSimpleName() , object);
ioclist.add(map);
// System.out.println( "ADD ComponentTest 註解 :"+object.getClass().getSimpleName()+"object :" +object);
}
} catch(InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
System.out.println("ioclist hash map : "+ioclist);
/*
Autowired
*/
checkAnnotation();
initHandlerMapping();
}
private void doLoadConfig(String location){
//把web.xml中的contextConfigLocation对应value值的文件加载到流里面
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location);
try {
//用Properties文件加载文件里的内容
properties.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
//关流
if(null!=resourceAsStream){
try {
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void initHandlerMapping(){
if(ioclist.isEmpty()){
return;
}
try {
for (Map <String , Object> annotations: ioclist ){
for ( String annotationkv : annotations.keySet()){
Object tempObject = annotations.get(annotationkv);
Class tempClass = tempObject.getClass();
ComponentTest[] tempType = (ComponentTest[]) tempClass.getAnnotationsByType(ComponentTest.class);
String tempClassType=null;
String baseUrl ="";
try {
tempClassType = tempType[0].value()[0];
System.out.println(tempType[0].value()[0]);
} catch ( Exception e){
tempClassType ="";
}
if (tempClassType.equals("Controller") ) {
MyRequestMapping[] tempType2 = (MyRequestMapping[]) tempClass.getAnnotationsByType(MyRequestMapping.class);
baseUrl = tempType2[0].value();
Method[] methods = tempClass.getMethods();
for (Method method : methods) {
if(!method.isAnnotationPresent(MyRequestMapping.class)){
continue;
}
MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
String url = annotation.value();
url =(baseUrl+"/"+url).replaceAll("/+", "/");
handlerMapping.put(url,method);
controllerMap.put(url,tempObject);
System.out.println(url+","+method);
}
// if(tempClass.isAnnotationPresent(MyRequestMapping.class)){
// MyRequestMapping annotation = tempClass.getAnnotation(MyRequestMapping.class);
// baseUrl=annotation.value();
// }
}
}
}
// for (Map.Entry<String, Object> entry: ioclist.entrySet()) {
// Class<? extends Object> clazz = entry.getValue().getClass();
// if(!clazz.isAnnotationPresent(ComponentTest.class)){
// continue;
// }
//
// //拼url时,是controller头的url拼上方法上的url
// String baseUrl ="";
// if(clazz.isAnnotationPresent(MyRequestMapping.class)){
// MyRequestMapping annotation = clazz.getAnnotation(MyRequestMapping.class);
// baseUrl=annotation.value();
// }
// Method[] methods = clazz.getMethods();
// for (Method method : methods) {
// if(!method.isAnnotationPresent(MyRequestMapping.class)){
// continue;
// }
// MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
// String url = annotation.value();
//
// url =(baseUrl+"/"+url).replaceAll("/+", "/");
// handlerMapping.put(url,method);
// controllerMap.put(url,clazz.newInstance());
// System.out.println(url+","+method);
// }
//
// }
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkAnnotation() {
//Autowired
for (Map <String , Object> annotations: ioclist ){
for ( String annotationkv : annotations.keySet()){
Object tempObject = annotations.get(annotationkv);
Class tempClass = tempObject.getClass();
ComponentTest[] tempType = (ComponentTest[]) tempClass.getAnnotationsByType(ComponentTest.class);
String tempClassType=null;
try {
tempClassType = tempType[0].value()[0];
System.out.println(tempType[0].value()[0]);
} catch ( Exception e){
tempClassType ="";
}
if (tempClassType.equals("Default") || tempClassType.equals("") || tempClassType.equals("Controller") ) {
Field[] fields = tempClass.getDeclaredFields();
for (Field tempfield : fields) {
// System.out.println(tempfield.value());
if (tempfield.isAnnotationPresent(Autowired.class)) {
String targetName = tempfield.getType().getSimpleName();
for (Map<String, Object> annotationchilds : ioclist) {
for (String annotationchildkv : annotationchilds.keySet()) {
if (annotationchilds.get(annotationchildkv).getClass().getSimpleName().equals(targetName)) {
tempfield.setAccessible(true);
try {
tempfield.set(tempObject, annotationchilds.get(targetName));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
//aop
for (Map <String , Object> annotations: ioclist ){
for ( String annotationkv : annotations.keySet()){
Object tempObject = annotations.get(annotationkv);
Class tempClass = tempObject.getClass();
ComponentTest[] tempType = (ComponentTest[]) tempClass.getAnnotationsByType(ComponentTest.class);
String tempClassType=null;
try {
tempClassType = tempType[0].value()[0];
System.out.println(tempType[0].value()[0]);
} catch ( Exception e){
tempClassType ="";
}
if(tempClassType.equals("Aspect")) {
Method[] Methods = tempClass.getMethods();
for (Method method : Methods)
{
Before[] filters = method.getAnnotationsByType(Before.class);
Annotation[][] tttt= method.getParameterAnnotations();
Parameter[] parameters = method.getParameters();
Class[] parameterTypes = method.getParameterTypes();
Advice AfterAdvice = null;
for(Before filter : filters) {
for (int i = 0 ; i <filter.value().length ; i ++){
System.out.println(filter.value()[i]);
}
Map<String , Object> map= new HashMap<>();
try {
for (Map <String , Object> annotations2: ioclist ){
for ( String annotationkv2 : annotations2.keySet()){
Object tempObject2 = annotations2.get(annotationkv2);
Class tempClass2 = tempObject2.getClass();
if(tempClass2.getName().equals(filter.value()[0].toString())){
//System.out.println(filter.value()[1].toString());
Method aopmethod = tempClass.getMethod(filter.value()[1].toString(),null);
AfterAdvice = new BeforeAdvice(tempObject2, aopmethod,tempObject);
Object helloServiceProxy = UtilsScan.getProxy(tempObject2, AfterAdvice);
map.put(tempClass2.getSimpleName() , helloServiceProxy);
//ioclist.remove(tempObject2);
for (int x =0 ; x < ioclist.size() ; x ++)
{
if(ioclist.get(x).keySet().equals( annotations2.keySet()))
{
//System.out.println(map);
ioclist.set(x,map);
//System.out.println("ioclist hash map : "+ioclist);
break;
}
}
}
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
}
}
}
}
/**
* 把字符串的首字母小写
* @param name
* @return
*/
private String toLowerFirstWord(String name){
char[] charArray = name.toCharArray();
charArray[0] += 32;
return String.valueOf(charArray);
}
public static Object getProxy(Object bean, Advice advice) {
return Proxy.newProxyInstance(UtilsScan.class.getClassLoader(),
bean.getClass().getInterfaces(), advice);
}
// public static void main(String[] args) {
// doLoadConfig(config.getInitParameter("contextConfigLocation"));
// UtilsScan.doScan();
// }
}
```
# MyDispatcherServlet
``` java
package com.spring.demo.servlet;
import com.spring.demo.anno.ComponentTest;
import com.spring.demo.anno.MyRequestMapping;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
public class MyDispatcherServlet extends HttpServlet{
private Properties properties = new Properties();
private List<String> classNames = new ArrayList<>();
private Map<String, Object> ioc = new HashMap<>();
private Map<String, Method> handlerMapping = new HashMap<>();
private Map<String, Object> controllerMap =new HashMap<>();
public MyDispatcherServlet (Map<String, Method> tmp ,Map<String, Object> tmp2){
this.handlerMapping = tmp;
this.controllerMap = tmp2;
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("MyDispatcherServlet init");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 統一攔截請求
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
//統一攔截請求
doDispatch(req,resp);
} catch (Exception e) {
resp.getWriter().write("500!! Server Exception");
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if(handlerMapping.isEmpty()){
return;
}
String url =req.getRequestURI();
String contextPath = req.getContextPath();
url=url.replace(contextPath, "").replaceAll("/+", "/");
if(!this.handlerMapping.containsKey(url)){
resp.getWriter().write("404 NOT FOUND!");
return;
}
Method method =this.handlerMapping.get(url);
//取得參數所有型態
Class<?>[] parameterTypes = method.getParameterTypes();
//取得請求參數
Map<String, String[]> parameterMap = req.getParameterMap();
//儲存請求參數
Object [] paramValues= new Object[parameterTypes.length];
Map<String, String> params = new HashMap<>();
//List keys = new ArrayList(parameterMap.keySet());
String responseString ="";
//方法的参数列表
for (int i = 0; i<parameterTypes.length; i++){
//處理參數
String requestParam = parameterTypes[i].getSimpleName();
if (requestParam.equals("HttpServletRequest")){
//對參數做處理
paramValues[i]=req;
continue;
}
if (requestParam.equals("HttpServletResponse")){
paramValues[i]=resp;
continue;
}
if(requestParam.equals("String")){
for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
String value =Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
params.put(param.getKey(),value);
}
}
}
for (Map.Entry<String, String> param : params.entrySet()) {
responseString+= param.getKey() +":" +param.getValue() + "\n";
}
//反射調用
try {
Object tmp = method.invoke(this.controllerMap.get(url), paramValues);
resp.getWriter().write( "doTest method success! \n"+responseString
+"return type :"+method.getReturnType() + ": value :" + (String)tmp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
# Controller
``` java
@ComponentTest("Controller")
@MyRequestMapping("/test")
public class IndexController {
@Autowired
IndexServiceimpl service;
@MyRequestMapping("/doTest")
public String test1(@MyRequestParam("param") String param,
@MyRequestParam("param2") String param2){
service.index();
return "jojo";
}
}
```
# run !
//get
![](https://i.imgur.com/vwB5GzJ.png)
//post
![](https://i.imgur.com/nP1VznY.png)
//error
![](https://i.imgur.com/DB6THlX.png)
![](https://i.imgur.com/PbKcq3G.png)