Browse Source

青涩知夏-创建了项目

青涩知夏 4 years ago
commit
e674635ebb

+ 17 - 0
.gitignore

@@ -0,0 +1,17 @@
+# IntelliJ project files
+.idea/
+*.iml
+out
+gen
+
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+!/.mvn/wrapper/maven-wrapper.jar

+ 180 - 0
pom.xml

@@ -0,0 +1,180 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>cn.nosum.vip.mvc</groupId>
+	<artifactId>nosum-spring</artifactId>
+	<version>1.0</version>
+	<packaging>war</packaging>
+
+	<dependencies>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.4</version>
+			<scope>provided</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<finalName>${artifactId}</finalName>
+		<resources>
+			<resource>
+				<directory>${basedir}/src/main/resources</directory>
+				<includes>
+					<include>**/*</include>
+				</includes>
+			</resource>
+			<resource>
+				<directory>${basedir}/src/main/java</directory>
+				<excludes>
+					<exclude>**/*.java</exclude>
+					<exclude>**/*.class</exclude>
+				</excludes>
+			</resource>
+		</resources>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+					<encoding>UTF-8</encoding>
+					<compilerArguments>
+						<verbose />
+						<bootclasspath>${java.home}/lib/rt.jar</bootclasspath>
+					</compilerArguments>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<artifactId>maven-resources-plugin</artifactId>
+				<version>2.5</version>
+				<executions>
+					<execution>
+						<id>copy-resources</id>
+						<!-- here the phase you need -->
+						<phase>validate</phase>
+						<goals>
+							<goal>copy-resources</goal>
+						</goals>
+						<configuration>
+							<encoding>UTF-8</encoding>
+							<outputDirectory>${basedir}/target/classes</outputDirectory>
+							<resources>
+								<resource>
+									<directory>src/main/resources</directory>
+									<includes>
+										<include>**/*.*</include>
+									</includes>
+									<filtering>true</filtering>
+								</resource>
+							</resources>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.mortbay.jetty</groupId>
+				<artifactId>maven-jetty-plugin</artifactId>
+				<version>6.1.26</version>
+				<configuration>
+					<webDefaultXml>src/main/resources/webdefault.xml</webDefaultXml>
+					<contextPath>/</contextPath>
+					<connectors>
+						<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
+							<port>8080</port>
+						</connector>
+					</connectors>
+					<scanIntervalSeconds>0</scanIntervalSeconds>
+					<scanTargetPatterns>
+						<scanTargetPattern>
+							<directory>src/main/webapp</directory>
+							<includes>
+								<include>**/*.xml</include>
+								<include>**/*.properties</include>
+							</includes>
+						</scanTargetPattern>
+					</scanTargetPatterns>
+					<systemProperties>
+						<systemProperty>
+							<name>
+								javax.xml.parsers.DocumentBuilderFactory
+							</name>
+							<value>
+								com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
+							</value>
+						</systemProperty>
+						<systemProperty>
+							<name>
+								javax.xml.parsers.SAXParserFactory
+							</name>
+							<value>
+								com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
+							</value>
+						</systemProperty>
+						<systemProperty>
+							<name>
+								javax.xml.transform.TransformerFactory
+							</name>
+							<value>
+								com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
+							</value>
+						</systemProperty>
+						<systemProperty>
+							<name>org.eclipse.jetty.util.URI.charset</name>
+							<value>UTF-8</value>
+						</systemProperty>
+					</systemProperties>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<archive>
+						<addMavenDescriptor>false</addMavenDescriptor>
+					</archive>
+					<webResources>
+						<resource>
+							<!-- this is relative to the pom.xml directory -->
+							<directory>src/main/resources/</directory>
+							<targetPath>WEB-INF/classes</targetPath>
+							<includes>
+								<include>**/*.*</include>
+							</includes>
+							<!-- <excludes>
+								<exclude>**/local</exclude>
+								<exclude>**/test</exclude>
+								<exclude>**/product</exclude>
+							</excludes> -->
+							<filtering>true</filtering>
+						</resource>
+						<resource>
+							<!-- this is relative to the pom.xml directory -->
+							<directory>src/main/resources</directory>
+							<targetPath>WEB-INF/classes</targetPath>
+							<filtering>true</filtering>
+						</resource>
+					</webResources>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.zeroturnaround</groupId>
+				<artifactId>javarebel-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<id>generate-rebel-xml</id>
+						<phase>process-resources</phase>
+						<goals>
+							<goal>generate</goal>
+						</goals>
+					</execution>
+				</executions>
+				<version>1.0.5</version>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 56 - 0
src/main/java/cn/nosum/demo/mvc/action/DemoAction.java

@@ -0,0 +1,56 @@
+package cn.nosum.demo.mvc.action;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cn.nosum.demo.service.IDemoService;
+import cn.nosum.framework.mvc.annotation.Autowired;
+import cn.nosum.framework.mvc.annotation.Controller;
+import cn.nosum.framework.mvc.annotation.RequestMapping;
+import cn.nosum.framework.mvc.annotation.RequestParam;
+
+
+//虽然,用法一样,但是没有功能
+@Controller
+@RequestMapping("/demo")
+public class DemoAction {
+
+  	@Autowired
+	private IDemoService demoService;
+
+	@RequestMapping("/query")
+	public void query(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name){
+		String result = demoService.get(name);
+		try {
+			resp.getWriter().write(result);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping("/add")
+	public void add(HttpServletRequest req, HttpServletResponse resp, @RequestParam("a") Integer a, @RequestParam("b") Integer b){
+		try {
+			resp.getWriter().write(a + "+" + b + "=" + (a + b));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping("/sub")
+	public void add(HttpServletRequest req, HttpServletResponse resp, @RequestParam("a") Double a, @RequestParam("b") Double b){
+		try {
+			resp.getWriter().write(a + "-" + b + "=" + (a - b));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@RequestMapping("/remove")
+	public String  remove(@RequestParam("id") Integer id){
+		return "" + id;
+	}
+
+}

+ 23 - 0
src/main/java/cn/nosum/demo/mvc/action/TwoAction.java

@@ -0,0 +1,23 @@
+package cn.nosum.demo.mvc.action;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cn.nosum.demo.service.IDemoService;
+
+public class TwoAction {
+	
+	private IDemoService demoService;
+
+	public void edit(HttpServletRequest req,HttpServletResponse resp, String name){
+		String result = demoService.get(name);
+		try {
+			resp.getWriter().write(result);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+}

+ 8 - 0
src/main/java/cn/nosum/demo/service/IDemoService.java

@@ -0,0 +1,8 @@
+package cn.nosum.demo.service;
+
+
+public interface IDemoService {
+	
+	String get(String name);
+	
+}

+ 16 - 0
src/main/java/cn/nosum/demo/service/impl/DemoService.java

@@ -0,0 +1,16 @@
+package cn.nosum.demo.service.impl;
+
+import cn.nosum.demo.service.IDemoService;
+import cn.nosum.framework.mvc.annotation.Service;
+
+/**
+ * 核心业务逻辑
+ */
+@Service
+public class DemoService implements IDemoService{
+
+	public String get(String name) {
+		return "My name is " + name + ",from service.";
+	}
+
+}

+ 10 - 0
src/main/java/cn/nosum/framework/mvc/annotation/Autowired.java

@@ -0,0 +1,10 @@
+package cn.nosum.framework.mvc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Autowired {
+    String value() default "";
+}

+ 10 - 0
src/main/java/cn/nosum/framework/mvc/annotation/Controller.java

@@ -0,0 +1,10 @@
+package cn.nosum.framework.mvc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Controller {
+    String value() default "";
+}

+ 10 - 0
src/main/java/cn/nosum/framework/mvc/annotation/RequestMapping.java

@@ -0,0 +1,10 @@
+package cn.nosum.framework.mvc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE,ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RequestMapping {
+    String value() default "";
+}

+ 10 - 0
src/main/java/cn/nosum/framework/mvc/annotation/RequestParam.java

@@ -0,0 +1,10 @@
+package cn.nosum.framework.mvc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RequestParam {
+    String value() default "";
+}

+ 10 - 0
src/main/java/cn/nosum/framework/mvc/annotation/Service.java

@@ -0,0 +1,10 @@
+package cn.nosum.framework.mvc.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Service {
+    String value() default "";
+}

+ 177 - 0
src/main/java/cn/nosum/framework/mvc/v1/servlet/DispatcherServlet.java

@@ -0,0 +1,177 @@
+package cn.nosum.framework.mvc.v1.servlet;
+
+import cn.nosum.framework.mvc.annotation.Autowired;
+import cn.nosum.framework.mvc.annotation.Controller;
+import cn.nosum.framework.mvc.annotation.RequestMapping;
+import cn.nosum.framework.mvc.annotation.Service;
+
+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.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.*;
+
+public class DispatcherServlet extends HttpServlet {
+    private Map<String, Object> mapping = new HashMap<String, Object>();
+
+    @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 Exception " + Arrays.toString(e.getStackTrace()));
+        }
+    }
+
+    /**
+     * 进行URL的映射
+     */
+    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
+        String url = req.getRequestURI();
+        String contextPath = req.getContextPath();
+        // 去除 URL 中的前缀并且将多个 / 替换为一个
+        url = url.replace(contextPath, "").replaceAll("/+", "/");
+        // 找不到页面
+        if (!this.mapping.containsKey(url)) {
+            resp.getWriter().write("404 Not Found!!");
+            return;
+        }
+        // 根据 URL 取得对应的方法映射
+        Method method = (Method) this.mapping.get(url);
+        // 取得所有的参数
+        Map<String, String[]> params = req.getParameterMap();
+        // 调用方法
+        method.invoke(this.mapping.get(method.getDeclaringClass().getName()), new Object[]{req, resp, params.get("name")[0]});
+    }
+
+    /**
+     * 初始化所有的相关的类,IOC容器、servletBean
+     */
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        InputStream is = null;
+        try {
+            Properties configContext = new Properties();
+            // 取得 application.properties
+            is = this.getClass().getClassLoader().getResourceAsStream(config.getInitParameter("contextConfigLocation"));
+            configContext.load(is);
+            // 获取定义的扫描包路径
+            String scanPackage = configContext.getProperty("scanPackage");
+            // 将指定路径中的类名进行缓存
+            doScanner(scanPackage);
+            // 初始化 IOC 容器
+            for (String className : mapping.keySet()) {
+                if (!className.contains(".")) {
+                    continue;
+                }
+                Class<?> clazz = Class.forName(className);
+                if (clazz.isAnnotationPresent(Controller.class)) {
+                    // 保存 Controller 实例
+                    mapping.put(className, clazz.getDeclaredConstructor().newInstance());
+                    String baseUrl = "";
+                    if (clazz.isAnnotationPresent(RequestMapping.class)) {
+                        RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
+                        baseUrl = requestMapping.value();
+                    }
+                    Method[] methods = clazz.getMethods();
+                    for (Method method : methods) {
+                        if (!method.isAnnotationPresent(RequestMapping.class)) {
+                            continue;
+                        }
+                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
+                        String url = (baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
+                        // 保存 URL 对应的方法引用
+                        mapping.put(url, method);
+                        System.out.println("Mapped " + url + "," + method);
+                    }
+                } else if (clazz.isAnnotationPresent(Service.class)) {
+                    Service service = clazz.getAnnotation(Service.class);
+                    String beanName = service.value();
+                    if ("".equals(beanName)) {
+                        beanName = clazz.getName();
+                    }
+                    Object instance = clazz.getDeclaredConstructor().newInstance();
+                    mapping.put(beanName, instance);
+                    // 如果当前实例具备有父接口,保存父接口包名
+                    for (Class<?> i : clazz.getInterfaces()) {
+                        mapping.put(i.getName(), instance);
+                    }
+                } else {
+                    continue;
+                }
+            }
+
+            // 依赖注入
+            for (Object object : mapping.values()) {
+                if (object == null) {
+                    continue;
+                }
+                Class clazz = object.getClass();
+                if (clazz.isAnnotationPresent(Controller.class)) {
+                    // 取得所有的成员变量
+                    Field[] fields = clazz.getDeclaredFields();
+                    for (Field field : fields) {
+                        if (!field.isAnnotationPresent(Autowired.class)) { continue; }
+                        Autowired autowired = field.getAnnotation(Autowired.class);
+                        String beanName = autowired.value();
+                        if ("".equals(beanName)) {
+                            beanName = field.getType().getName();
+                        }
+                        field.setAccessible(true);
+                        try {
+                            // 从容器中,注入实例
+                            field.set(mapping.get(clazz.getName()), mapping.get(beanName));
+                        } catch (IllegalAccessException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+        } catch (Exception ignored) {
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        System.out.print("MVC Framework is init");
+    }
+
+
+    /**
+     * 将指定路径中的 class 名称保存
+     */
+    private void doScanner(String scanPackage) {
+        // 将 . 替换为 /
+        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
+        File classDir = new File(url.getFile());
+        // 扫描包所有的 class 文件
+        for (File file : classDir.listFiles()) {
+            if (file.isDirectory()) {
+                // 如果是文件夹,递归调用
+                doScanner(scanPackage + "." + file.getName());
+            } else {
+                if (!file.getName().endsWith(".class")) {
+                    continue;
+                }
+                String clazzName = (scanPackage + "." + file.getName().replace(".class", ""));
+                mapping.put(clazzName, null);
+            }
+        }
+    }
+}

+ 246 - 0
src/main/java/cn/nosum/framework/mvc/v2/servlet/DispatcherServlet.java

@@ -0,0 +1,246 @@
+package cn.nosum.framework.mvc.v2.servlet;
+
+import cn.nosum.framework.mvc.annotation.*;
+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.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.*;
+import java.io.File;
+
+public class DispatcherServlet extends HttpServlet {
+    private Properties contextConfig = new Properties();
+
+    //享元模式,缓存
+    private List<String> classNames = new ArrayList<String>();
+
+    //IoC容器,key默认是类名首字母小写,value就是对应的实例对象
+    private Map<String,Object> ioc = new HashMap<String,Object>();
+
+    // 保存 URL 与对应执行方法的映射
+    private Map<String,Method> handlerMapping = new HashMap<String, Method>();
+
+    @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 {
+            //6、委派,根据URL去找到一个对应的Method并通过response返回
+            doDispatch(req,resp);
+        } catch (Exception e) {
+            e.printStackTrace();
+            resp.getWriter().write("500 Exception,Detail : " + Arrays.toString(e.getStackTrace()));
+        }
+
+    }
+
+    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
+        String url = req.getRequestURI();
+        String contextPath = req.getContextPath();
+        url = url.replaceAll(contextPath,"").replaceAll("/+","/");
+
+        if(!this.handlerMapping.containsKey(url)){
+            resp.getWriter().write("404 Not Found!!!");
+            return;
+        }
+
+        Map<String,String[]> params = req.getParameterMap();
+
+        Method method = this.handlerMapping.get(url);
+
+        //获取形参列表
+        Class<?> [] parameterTypes = method.getParameterTypes();
+        Object [] paramValues = new Object[parameterTypes.length];
+
+        for (int i = 0; i < parameterTypes.length; i++) {
+            Class parameterType = parameterTypes[i];
+            if(parameterType == HttpServletRequest.class){
+                paramValues[i] = req;
+            }else if(parameterType == HttpServletResponse.class){
+                paramValues[i] = resp;
+            }else if(parameterType == String.class){
+                // 需要通过运行时的状态才可以拿到
+                Annotation[] [] pa = method.getParameterAnnotations();
+                for (int j = 0; j < pa.length ; j ++) {
+                    for(Annotation annotation : pa[i]){
+                        if(annotation instanceof RequestParam){
+                            String paramName = ((RequestParam) annotation).value();
+                            if(!"".equals(paramName.trim())){
+                               String value = Arrays.toString(params.get(paramName))
+                                       .replaceAll("\\[|\\]","")
+                                       .replaceAll("\\s+",",");
+                                paramValues[i] = value;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        // 通过 method 获取对应的类
+        String beanName = toLowerFirstCase(method.getDeclaringClass().getSimpleName());
+        // 从 ioc 中获取对应的类并且执行
+        method.invoke(ioc.get(beanName),paramValues);
+
+    }
+
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        //1、加载配置文件
+        doLoadConfig(config.getInitParameter("contextConfigLocation"));
+
+        //2、扫描相关的类
+        doScanner(contextConfig.getProperty("scanPackage"));
+
+        //==============IoC部分==============
+        //3、初始化IoC容器,将扫描到的相关的类实例化,保存到IcC容器中
+        doInstance();
+
+        //AOP,新生成的代理对象
+
+        //==============DI部分==============
+        //4、完成依赖注入
+        doAutowired();
+
+        //==============MVC部分==============
+        //5、初始化HandlerMapping
+        doInitHandlerMapping();
+
+        System.out.println("Spring framework is init.");
+    }
+
+    private void doInitHandlerMapping() {
+        if(ioc.isEmpty()){ return;}
+        for (Map.Entry<String,Object> entry : ioc.entrySet()) {
+            Class<?> clazz = entry.getValue().getClass();
+            if(!clazz.isAnnotationPresent(Controller.class)){ continue; }
+            String baseUrl = "";
+            if(clazz.isAnnotationPresent(RequestMapping.class)){
+                // 取得类配置的 url
+                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
+                baseUrl = requestMapping.value();
+            }
+
+            // 只获取 public 的方法
+            for (Method method : clazz.getMethods()) {
+                if(!method.isAnnotationPresent(RequestMapping.class)){continue;}
+                // 提取每个方法配置的 url
+                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
+                String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+","/");
+                handlerMapping.put(url,method);
+                System.out.println("Mapped : " + url + "," + method);
+            }
+        }
+    }
+
+    private void doAutowired() {
+        if(ioc.isEmpty()){return;}
+        for (Map.Entry<String,Object> entry : ioc.entrySet()) {
+            // 把所有 private/protected/default/public 修饰字段都取出来
+            for (Field field : entry.getValue().getClass().getDeclaredFields()) {
+                if(!field.isAnnotationPresent(Autowired.class)){ continue; }
+
+                Autowired autowired = field.getAnnotation(Autowired.class);
+
+                // 没有自定义的beanName,根据类型注入
+                String beanName = autowired.value().trim();
+                if("".equals(beanName)){
+                    beanName = field.getType().getName();
+                }
+                // 赋值
+                try {
+                    field.setAccessible(true);
+                    field.set(entry.getValue(),ioc.get(beanName));
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private void doInstance() {
+        if(classNames.isEmpty()){return;}
+
+        try {
+            for (String className : classNames) {
+                Class<?> clazz = Class.forName(className);
+
+                if(clazz.isAnnotationPresent(Controller.class)) {
+                    String beanName = toLowerFirstCase(clazz.getSimpleName());
+                    Object instance = clazz.newInstance();
+                    ioc.put(beanName, instance);
+                }else if(clazz.isAnnotationPresent(Service.class)){
+                    // 获取自定义的名称
+                    String beanName = clazz.getAnnotation(Service.class).value();
+                    if("".equals(beanName.trim())){
+                        beanName = toLowerFirstCase(clazz.getSimpleName());
+                    }
+                    Object instance = clazz.newInstance();
+                    ioc.put(beanName, instance);
+
+                    // 如果是接口,只能有一个实现,否则抛出异常
+                    for (Class<?> i : clazz.getInterfaces()) {
+                        if(ioc.containsKey(i.getName())){
+                            throw new Exception("The " + i.getName() + " is exists!!");
+                        }
+                        ioc.put(i.getName(),instance);
+                    }
+                }else{
+                    continue;
+                }
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+    }
+
+    private void doScanner(String scanPackage) {
+        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.","/"));
+        File classPath = new File(url.getFile());
+
+        //当成是一个 ClassPath 文件夹
+        for (File file : classPath.listFiles()) {
+            if(file.isDirectory()){
+                doScanner(scanPackage + "." + file.getName());
+            }else {
+                if(!file.getName().endsWith(".class")){continue;}
+                // 全类名 = 包名.类名
+                String className = (scanPackage + "." + file.getName().replace(".class", ""));
+                classNames.add(className);
+            }
+        }
+    }
+
+    private void doLoadConfig(String contextConfigLocation) {
+        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
+        try {
+            contextConfig.load(is);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }finally {
+            if(null != is){
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private String toLowerFirstCase(String simpleName) {
+        char [] chars = simpleName.toCharArray();
+        chars[0] += 32;
+        return String.valueOf(chars);
+    }
+}

+ 353 - 0
src/main/java/cn/nosum/framework/mvc/v3/servlet/GPDispatcherServlet.java

@@ -0,0 +1,353 @@
+package cn.nosum.framework.mvc.v3.servlet;
+
+import cn.nosum.framework.mvc.annotation.*;
+import cn.nosum.framework.mvc.annotation.*;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.*;
+
+public class GPDispatcherServlet extends HttpServlet {
+
+    //保存application.properties配置文件中的内容
+    private Properties contextConfig = new Properties();
+
+    //保存扫描的所有的类名
+    private List<String> classNames = new ArrayList<String>();
+
+    // IOC容器
+    private Map<String, Object> ioc = new HashMap<String, Object>();
+
+    // 保存url和Method的对应关系
+    private List<Handler> handlerMapping = new ArrayList<Handler>();
+
+    @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 {
+
+        //6、调用,运行阶段
+        try {
+            doDispatch(req, resp);
+        } catch (Exception e) {
+            e.printStackTrace();
+            resp.getWriter().write("500 Exection,Detail : " + Arrays.toString(e.getStackTrace()));
+        }
+
+
+    }
+
+    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
+        Handler handler = getHandler(req);
+        if (handler == null) {
+            resp.getWriter().write("404 Not Found!!!");
+            return;
+        }
+        //获得方法的形参列表
+        Class<?>[] paramTypes = handler.getParamTypes();
+        Object[] paramValues = new Object[paramTypes.length];
+        Map<String, String[]> params = req.getParameterMap();
+        for (Map.Entry<String, String[]> parm : params.entrySet()) {
+            String value = Arrays.toString(parm.getValue())
+                    .replaceAll("\\[|\\]", "")
+                    .replaceAll("\\s", ",");
+            if (!handler.paramIndexMapping.containsKey(parm.getKey())) {
+                continue;
+            }
+            int index = handler.paramIndexMapping.get(parm.getKey());
+            paramValues[index] = convert(paramTypes[index], value);
+        }
+
+        if (handler.paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
+            int reqIndex = handler.paramIndexMapping.get(HttpServletRequest.class.getName());
+            paramValues[reqIndex] = req;
+        }
+
+        if (handler.paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
+            int respIndex = handler.paramIndexMapping.get(HttpServletResponse.class.getName());
+            paramValues[respIndex] = resp;
+        }
+
+        Object returnValue = handler.method.invoke(handler.controller, paramValues);
+        if (returnValue == null || returnValue instanceof Void) {
+            return;
+        }
+        resp.getWriter().write(returnValue.toString());
+    }
+
+    private Handler getHandler(HttpServletRequest req) {
+        if (handlerMapping.isEmpty()) {
+            return null;
+        }
+        // 绝对路径
+        String url = req.getRequestURI();
+        // 处理成相对路径
+        String contextPath = req.getContextPath();
+        url = url.replaceAll(contextPath, "").replaceAll("/+", "/");
+        for (Handler handler : this.handlerMapping) {
+            Matcher matcher = handler.getPattern().matcher(url);
+            if (!matcher.matches()) {
+                continue;
+            }
+            return handler;
+        }
+        return null;
+    }
+
+    //url传过来的参数都是String类型的,HTTP是基于字符串协议
+    //只需要把String转换为任意类型就好
+    private Object convert(Class<?> type, String value) {
+        //如果是int
+        if (Integer.class == type) {
+            return Integer.valueOf(value);
+        } else if (Double.class == type) {
+            return Double.valueOf(value);
+        }
+        //如果还有double或者其他类型,继续加if
+        //这时候,我们应该想到策略模式了
+        //在这里暂时不实现,希望小伙伴自己来实现
+        return value;
+    }
+
+
+    //初始化阶段
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+
+        //1、加载配置文件
+        doLoadConfig(config.getInitParameter("contextConfigLocation"));
+        //2、扫描相关的类
+        doScanner(contextConfig.getProperty("scanPackage"));
+        //3、初始化扫描到的类,并且将它们放入到ICO容器之中
+        doInstance();
+        //4、完成依赖注入
+        doAutowired();
+        //5、初始化HandlerMapping
+        initHandlerMapping();
+        System.out.println("Spring framework is init.");
+
+    }
+
+
+    //初始化url和Method的一对一对应关系
+    private void initHandlerMapping() {
+        if (ioc.isEmpty()) {
+            return;
+        }
+        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
+            Class<?> clazz = entry.getValue().getClass();
+            if (!clazz.isAnnotationPresent(Controller.class)) {
+                continue;
+            }
+            //保存写在类上面的@GPRequestMapping("/demo")
+            String baseUrl = "";
+            if (clazz.isAnnotationPresent(RequestMapping.class)) {
+                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
+                baseUrl = requestMapping.value();
+            }
+            //默认获取所有的 public方法
+            for (Method method : clazz.getMethods()) {
+                if (!method.isAnnotationPresent(RequestMapping.class)) {
+                    continue;
+                }
+                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
+                //优化
+                String regex = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
+                Pattern pattern = Pattern.compile(regex);
+                this.handlerMapping.add(new Handler(pattern, entry.getValue(), method));
+                System.out.println("Mapped :" + pattern + "," + method);
+            }
+        }
+    }
+
+    //自动依赖注入
+    private void doAutowired() {
+        if (ioc.isEmpty()) {
+            return;
+        }
+        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
+            //Declared 所有的,特定的 字段,包括 private/protected/default
+            //正常来说,普通的OOP编程只能拿到public的属性
+            Field[] fields = entry.getValue().getClass().getDeclaredFields();
+            for (Field field : fields) {
+                if (!field.isAnnotationPresent(Autowired.class)) {
+                    continue;
+                }
+                Autowired autowired = field.getAnnotation(Autowired.class);
+                //如果用户没有自定义beanName,默认就根据类型注入
+                //这个地方省去了对类名首字母小写的情况的判断,这个作为课后作业
+                //小伙伴们自己去完善
+                String beanName = autowired.value().trim();
+                if ("".equals(beanName)) {
+                    //获得接口的类型,作为key待会拿这个key到ioc容器中去取值
+                    beanName = field.getType().getName();
+                }
+
+                //如果是public以外的修饰符,只要加了@Autowired注解,都要强制赋值
+                //反射中叫做暴力访问, 强吻
+                field.setAccessible(true);
+
+                try {
+                    //用反射机制,动态给字段赋值
+                    field.set(entry.getValue(), ioc.get(beanName));
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private void doInstance() {
+        //初始化,为DI做准备
+        if (classNames.isEmpty()) {
+            return;
+        }
+        try {
+            for (String className : classNames) {
+                Class<?> clazz = Class.forName(className);
+                if (clazz.isAnnotationPresent(Controller.class)) {
+                    Object instance = clazz.newInstance();
+                    String beanName = toLowerFirstCase(clazz.getSimpleName());
+                    ioc.put(beanName, instance);
+                } else if (clazz.isAnnotationPresent(Service.class)) {
+                    Service service = clazz.getAnnotation(Service.class);
+                    String beanName = service.value();
+                    if ("".equals(beanName.trim())) {
+                        beanName = toLowerFirstCase(clazz.getSimpleName());
+                    }
+
+                    Object instance = clazz.newInstance();
+                    ioc.put(beanName, instance);
+                    for (Class<?> i : clazz.getInterfaces()) {
+                        if (ioc.containsKey(i.getName())) {
+                            throw new Exception("The “" + i.getName() + "” is exists!!");
+                        }
+                        ioc.put(i.getName(), instance);
+                    }
+                } else {
+                    continue;
+                }
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    //扫描出相关的类
+    private void doScanner(String scanPackage) {
+        URL url = this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));
+        File classPath = new File(url.getFile());
+        for (File file : classPath.listFiles()) {
+            if (file.isDirectory()) {
+                doScanner(scanPackage + "." + file.getName());
+            } else {
+                if (!file.getName().endsWith(".class")) {
+                    continue;
+                }
+                String className = (scanPackage + "." + file.getName().replace(".class", ""));
+                classNames.add(className);
+            }
+        }
+    }
+
+
+    //加载配置文件
+    private void doLoadConfig(String contextConfigLocation) {
+        // 直接从类路径下找到Spring主配置文件所在的路径
+        // 并且将其读取出来放到Properties对象中
+        // 相对于scanPackage=cn.nosum.demo 从文件中保存到了内存中
+        InputStream fis = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
+        try {
+            contextConfig.load(fis);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (null != fis) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    public class Handler {
+        private Pattern pattern;  //正则
+        private Method method;
+        private Object controller;
+        private Class<?>[] paramTypes;
+        // 形参列表
+        // 参数的名字作为key,参数的顺序,位置作为值
+        private Map<String, Integer> paramIndexMapping;
+
+        public Handler(Pattern pattern, Object controller, Method method) {
+            this.pattern = pattern;
+            this.method = method;
+            this.controller = controller;
+            paramTypes = method.getParameterTypes();
+            paramIndexMapping = new HashMap<String, Integer>();
+            putParamIndexMapping(method);
+        }
+
+        /**
+         *  提取方法中加了注解的参数并且保存
+         */
+        private void putParamIndexMapping(Method method) {
+            // 取得方法中参数的注解,得到的是一个二维数组
+            // 一个方法有多个参数,一个参数可以有多个注解
+            Annotation[][] pa = method.getParameterAnnotations();
+            for (int i = 0; i < pa.length; i++) {
+                for (Annotation annotation : pa[i]) {
+                    if (annotation instanceof RequestParam) {
+                        String paramName = ((RequestParam) annotation).value();
+                        if (!"".equals(paramName.trim())) {
+                            paramIndexMapping.put(paramName, i);
+                        }
+                    }
+                }
+            }
+            // 提取方法中的request和response参数
+            Class<?>[] paramsTypes = method.getParameterTypes();
+            for (int i = 0; i < paramsTypes.length; i++) {
+                Class<?> type = paramsTypes[i];
+                if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
+                    paramIndexMapping.put(type.getName(), i);
+                }
+            }
+        }
+
+        public Pattern getPattern() { return pattern; }
+        public Method getMethod() { return method; }
+        public Object getController() { return controller; }
+        public Class<?>[] getParamTypes() { return paramTypes; }
+    }
+
+    private String toLowerFirstCase(String simpleName) {
+        char[] chars = simpleName.toCharArray();
+        chars[0] += 32;
+        return String.valueOf(chars);
+    }
+}
+
+
+

+ 1 - 0
src/main/resources/application.properties

@@ -0,0 +1 @@
+scanPackage=cn.nosum.demo

+ 410 - 0
src/main/resources/webdefault.xml

@@ -0,0 +1,410 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!-- ===================================================================== -->
+<!-- This file contains the default descriptor for web applications.       -->
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<!-- The intent of this descriptor is to include jetty specific or common  -->
+<!-- configuration for all webapps.   If a context has a webdefault.xml    -->
+<!-- descriptor, it is applied before the contexts own web.xml file        -->
+<!--                                                                       -->
+<!-- A context may be assigned a default descriptor by:                    -->
+<!--  + Calling WebApplicationContext.setDefaultsDescriptor                -->
+<!--  + Passed an arg to addWebApplications                                -->
+<!--                                                                       -->
+<!-- This file is used both as the resource within the jetty.jar (which is -->
+<!-- used as the default if no explicit defaults descriptor is set) and it -->
+<!-- is copied to the etc directory of the Jetty distro and explicitly     -->
+<!-- by the jetty.xml file.                                                -->
+<!--                                                                       -->
+<!-- ===================================================================== -->
+<web-app 
+   xmlns="http://java.sun.com/xml/ns/javaee" 
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
+   metadata-complete="true"
+   version="2.5"> 
+
+  <description>
+    Default web.xml file.  
+    This file is applied to a Web application before it's own WEB_INF/web.xml file
+  </description>
+
+
+  <!-- ==================================================================== -->
+  <!-- Context params to control Session Cookies                            -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- UNCOMMENT TO ACTIVATE
+  <context-param>
+    <param-name>org.mortbay.jetty.servlet.SessionDomain</param-name>
+    <param-value>127.0.0.1</param-value>
+  </context-param>
+
+  <context-param>
+    <param-name>org.mortbay.jetty.servlet.SessionPath</param-name>
+    <param-value>/</param-value>
+  </context-param>
+
+  <context-param>
+    <param-name>org.mortbay.jetty.servlet.MaxAge</param-name>
+    <param-value>-1</param-value>
+  </context-param>
+  -->
+
+  <context-param>
+    <param-name>org.mortbay.jetty.webapp.NoTLDJarPattern</param-name>
+    <param-value>start.jar|ant-.*\.jar|dojo-.*\.jar|jetty-.*\.jar|jsp-api-.*\.jar|junit-.*\.jar|servlet-api-.*\.jar|dnsns\.jar|rt\.jar|jsse\.jar|tools\.jar|sunpkcs11\.jar|sunjce_provider\.jar|xerces.*\.jar</param-value>
+  </context-param>
+            
+
+
+  <!-- ==================================================================== -->
+  <!-- The default servlet.                                                 -->
+  <!-- This servlet, normally mapped to /, provides the handling for static -->
+  <!-- content, OPTIONS and TRACE methods for the context.                  -->
+  <!-- The following initParameters are supported:                          -->
+  <!--                                                                      -->
+  <!--   acceptRanges     If true, range requests and responses are         -->
+  <!--                    supported                                         -->
+  <!--                                                                      -->
+  <!--   dirAllowed       If true, directory listings are returned if no    -->
+  <!--                    welcome file is found. Else 403 Forbidden.        -->
+  <!--                                                                      -->
+  <!--   welcomeServlets  If true, attempt to dispatch to welcome files     -->
+  <!--                    that are servlets, if no matching static          --> 
+  <!--                    resources can be found.                           -->
+  <!--                                                                      -->
+  <!--   redirectWelcome  If true, redirect welcome file requests           -->
+  <!--                    else use request dispatcher forwards              -->
+  <!--                                                                      -->
+  <!--   gzip             If set to true, then static content will be served--> 
+  <!--                    as gzip content encoded if a matching resource is -->
+  <!--                    found ending with ".gz"                           -->
+  <!--                                                                      -->
+  <!--   resoureBase      Can be set to replace the context resource base   -->
+  <!--                                                                      -->
+  <!--   relativeResourceBase                                               -->
+  <!--                    Set with a pathname relative to the base of the   -->
+  <!--                    servlet context root. Useful for only serving     -->
+  <!--                    static content from only specific subdirectories. -->
+  <!--                                                                      -->
+  <!--   useFileMappedBuffer                                                -->
+  <!--                    If set to true (the default), a  memory mapped    -->
+  <!--                    file buffer will be used to serve static content  -->
+  <!--                    when using an NIO connector. Setting this value   -->
+  <!--                    to false means that a direct buffer will be used  -->
+  <!--                    instead. If you are having trouble with Windows   -->
+  <!--                    file locking, set this to false.                  -->
+  <!--                                                                      -->
+  <!--  cacheControl      If set, all static content will have this value   -->
+  <!--                    set as the cache-control header.                  -->
+  <!--                                                                      -->
+  <!--  maxCacheSize      Maximum size of the static resource cache         -->
+  <!--                                                                      -->
+  <!--  maxCachedFileSize Maximum size of any single file in the cache      -->
+  <!--                                                                      -->
+  <!--  maxCachedFiles    Maximum number of files in the cache              -->
+  <!--                                                                      -->
+  <!--  cacheType         "nio", "bio" or "both" to determine the type(s)   -->
+  <!--                    of resource cache. A bio cached buffer may be used-->
+  <!--                    by nio but is not as efficient as a nio buffer.   -->
+  <!--                    An nio cached buffer may not be used by bio.      -->
+  <!--                                                                      -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <servlet>
+    <servlet-name>default</servlet-name>
+    <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
+    <init-param>
+      <param-name>acceptRanges</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>dirAllowed</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>welcomeServlets</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>redirectWelcome</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCacheSize</param-name>
+      <param-value>256000000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCachedFileSize</param-name>
+      <param-value>10000000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>maxCachedFiles</param-name>
+      <param-value>1000</param-value>
+    </init-param>
+    <init-param>
+      <param-name>cacheType</param-name>
+      <param-value>both</param-value>
+    </init-param>
+    <init-param>
+      <param-name>gzip</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>useFileMappedBuffer</param-name>
+      <param-value>false</param-value>
+    </init-param>  
+    <!--
+    <init-param>
+      <param-name>cacheControl</param-name>
+      <param-value>max-age=3600,public</param-value>
+    </init-param>
+    -->
+    <load-on-startup>0</load-on-startup>
+  </servlet> 
+
+  <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
+  
+
+  <!-- ==================================================================== -->
+  <!-- JSP Servlet                                                          -->
+  <!-- This is the jasper JSP servlet from the jakarta project              -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
+  <!-- used by Glassfish to support JSP pages.  Traditionally, this servlet -->
+  <!-- is mapped to URL patterh "*.jsp".  This servlet supports the         -->
+  <!-- following initialization parameters (default values are in square    -->
+  <!-- brackets):                                                           -->
+  <!--                                                                      -->
+  <!--   checkInterval       If development is false and reloading is true, -->
+  <!--                       background compiles are enabled. checkInterval -->
+  <!--                       is the time in seconds between checks to see   -->
+  <!--                       if a JSP page needs to be recompiled. [300]    -->
+  <!--                                                                      -->
+  <!--   compiler            Which compiler Ant should use to compile JSP   -->
+  <!--                       pages.  See the Ant documenation for more      -->
+  <!--                       information. [javac]                           -->
+  <!--                                                                      -->
+  <!--   classdebuginfo      Should the class file be compiled with         -->
+  <!--                       debugging information?  [true]                 -->
+  <!--                                                                      -->
+  <!--   classpath           What class path should I use while compiling   -->
+  <!--                       generated servlets?  [Created dynamically      -->
+  <!--                       based on the current web application]          -->
+  <!--                       Set to ? to make the container explicitly set  -->
+  <!--                       this parameter.                                -->
+  <!--                                                                      -->
+  <!--   development         Is Jasper used in development mode (will check -->
+  <!--                       for JSP modification on every access)?  [true] -->
+  <!--                                                                      -->
+  <!--   enablePooling       Determines whether tag handler pooling is      -->
+  <!--                       enabled  [true]                                -->
+  <!--                                                                      -->
+  <!--   fork                Tell Ant to fork compiles of JSP pages so that -->
+  <!--                       a separate JVM is used for JSP page compiles   -->
+  <!--                       from the one Tomcat is running in. [true]      -->
+  <!--                                                                      -->
+  <!--   ieClassId           The class-id value to be sent to Internet      -->
+  <!--                       Explorer when using <jsp:plugin> tags.         -->
+  <!--                       [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93]   -->
+  <!--                                                                      -->
+  <!--   javaEncoding        Java file encoding to use for generating java  -->
+  <!--                       source files. [UTF-8]                          -->
+  <!--                                                                      -->
+  <!--   keepgenerated       Should we keep the generated Java source code  -->
+  <!--                       for each page instead of deleting it? [true]   -->
+  <!--                                                                      -->
+  <!--   logVerbosityLevel   The level of detailed messages to be produced  -->
+  <!--                       by this servlet.  Increasing levels cause the  -->
+  <!--                       generation of more messages.  Valid values are -->
+  <!--                       FATAL, ERROR, WARNING, INFORMATION, and DEBUG. -->
+  <!--                       [WARNING]                                      -->
+  <!--                                                                      -->
+  <!--   mappedfile          Should we generate static content with one     -->
+  <!--                       print statement per input line, to ease        -->
+  <!--                       debugging?  [false]                            -->
+  <!--                                                                      -->
+  <!--                                                                      -->
+  <!--   reloading           Should Jasper check for modified JSPs?  [true] -->
+  <!--                                                                      -->
+  <!--   suppressSmap        Should the generation of SMAP info for JSR45   -->
+  <!--                       debugging be suppressed?  [false]              -->
+  <!--                                                                      -->
+  <!--   dumpSmap            Should the SMAP info for JSR45 debugging be    -->
+  <!--                       dumped to a file? [false]                      -->
+  <!--                       False if suppressSmap is true                  -->
+  <!--                                                                      -->
+  <!--   scratchdir          What scratch directory should we use when      -->
+  <!--                       compiling JSP pages?  [default work directory  -->
+  <!--                       for the current web application]               -->
+  <!--                                                                      -->
+  <!--   tagpoolMaxSize      The maximum tag handler pool size  [5]         -->
+  <!--                                                                      -->
+  <!--   xpoweredBy          Determines whether X-Powered-By response       -->
+  <!--                       header is added by generated servlet  [false]  -->
+  <!--                                                                      -->
+  <!-- If you wish to use Jikes to compile JSP pages:                       -->
+  <!--   Set the init parameter "compiler" to "jikes".  Define              -->
+  <!--   the property "-Dbuild.compiler.emacs=true" when starting Jetty     -->
+  <!--   to cause Jikes to emit error messages in a format compatible with  -->
+  <!--   Jasper.                                                            -->
+  <!--   If you get an error reporting that jikes can't use UTF-8 encoding, -->
+  <!--   try setting the init parameter "javaEncoding" to "ISO-8859-1".     -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <servlet id="jsp">
+    <servlet-name>jsp</servlet-name>
+    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+    <init-param>
+        <param-name>logVerbosityLevel</param-name>
+        <param-value>DEBUG</param-value>
+    </init-param>
+    <init-param>
+        <param-name>fork</param-name>
+        <param-value>false</param-value>
+    </init-param>
+    <init-param>
+        <param-name>xpoweredBy</param-name>
+        <param-value>false</param-value>
+    </init-param>
+    <!--  
+    <init-param>
+        <param-name>classpath</param-name>
+        <param-value>?</param-value>
+    </init-param>
+    -->
+    <load-on-startup>0</load-on-startup>
+  </servlet>
+
+  <servlet-mapping> 
+    <servlet-name>jsp</servlet-name> 
+    <url-pattern>*.jsp</url-pattern> 
+    <url-pattern>*.jspf</url-pattern>
+    <url-pattern>*.jspx</url-pattern>
+    <url-pattern>*.xsp</url-pattern>
+    <url-pattern>*.JSP</url-pattern> 
+    <url-pattern>*.JSPF</url-pattern>
+    <url-pattern>*.JSPX</url-pattern>
+    <url-pattern>*.XSP</url-pattern>
+  </servlet-mapping>
+  
+  <!-- ==================================================================== -->
+  <!-- Dynamic Servlet Invoker.                                             -->
+  <!-- This servlet invokes anonymous servlets that have not been defined   -->
+  <!-- in the web.xml or by other means. The first element of the pathInfo  -->
+  <!-- of a request passed to the envoker is treated as a servlet name for  -->
+  <!-- an existing servlet, or as a class name of a new servlet.            -->
+  <!-- This servlet is normally mapped to /servlet/*                        -->
+  <!-- This servlet support the following initParams:                       -->
+  <!--                                                                      -->
+  <!--  nonContextServlets       If false, the invoker can only load        -->
+  <!--                           servlets from the contexts classloader.    -->
+  <!--                           This is false by default and setting this  -->
+  <!--                           to true may have security implications.    -->
+  <!--                                                                      -->
+  <!--  verbose                  If true, log dynamic loads                 -->
+  <!--                                                                      -->
+  <!--  *                        All other parameters are copied to the     -->
+  <!--                           each dynamic servlet as init parameters    -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- Uncomment for dynamic invocation
+  <servlet>
+    <servlet-name>invoker</servlet-name>
+    <servlet-class>org.mortbay.jetty.servlet.Invoker</servlet-class>
+    <init-param>
+      <param-name>verbose</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>nonContextServlets</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <init-param>
+      <param-name>dynamicParam</param-name>
+      <param-value>anyValue</param-value>
+    </init-param>
+    <load-on-startup>0</load-on-startup>
+  </servlet>
+
+  <servlet-mapping> <servlet-name>invoker</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping>
+  -->
+
+
+
+  <!-- ==================================================================== -->
+  <session-config>
+    <session-timeout>30</session-timeout>
+  </session-config>
+
+  <!-- ==================================================================== -->
+  <!-- Default MIME mappings                                                -->
+  <!-- The default MIME mappings are provided by the mime.properties        -->
+  <!-- resource in the org.mortbay.jetty.jar file.  Additional or modified  -->
+  <!-- mappings may be specified here                                       -->
+  <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -->
+  <!-- UNCOMMENT TO ACTIVATE
+  <mime-mapping>
+    <extension>mysuffix</extension>
+    <mime-type>mymime/type</mime-type>
+  </mime-mapping>
+  -->
+
+  <!-- ==================================================================== -->
+  <welcome-file-list>
+    <welcome-file>index.html</welcome-file>
+    <welcome-file>index.htm</welcome-file>
+    <welcome-file>index.jsp</welcome-file>
+  </welcome-file-list>
+
+  <!-- ==================================================================== -->
+  <locale-encoding-mapping-list>
+    <locale-encoding-mapping><locale>ar</locale><encoding>ISO-8859-6</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>be</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>bg</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ca</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>cs</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>da</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>de</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>el</locale><encoding>ISO-8859-7</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>en</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>es</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>et</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>fi</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>fr</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>hr</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>hu</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>is</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>it</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>iw</locale><encoding>ISO-8859-8</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ja</locale><encoding>Shift_JIS</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ko</locale><encoding>EUC-KR</encoding></locale-encoding-mapping>     
+    <locale-encoding-mapping><locale>lt</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>lv</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>mk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>nl</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>no</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>pl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>pt</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ro</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>ru</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sh</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sk</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sl</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sq</locale><encoding>ISO-8859-2</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sr</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>sv</locale><encoding>ISO-8859-1</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>tr</locale><encoding>ISO-8859-9</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>uk</locale><encoding>ISO-8859-5</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>zh</locale><encoding>GB2312</encoding></locale-encoding-mapping>
+    <locale-encoding-mapping><locale>zh_TW</locale><encoding>Big5</encoding></locale-encoding-mapping>   
+  </locale-encoding-mapping-list>
+  
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>Disable TRACE</web-resource-name>
+      <url-pattern>/</url-pattern>
+      <http-method>TRACE</http-method>
+    </web-resource-collection>
+    <auth-constraint/>
+  </security-constraint>
+  
+</web-app>
+

+ 23 - 0
src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,23 @@
+<?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/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
+	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+	version="2.4">
+	<display-name>Gupao Web Application</display-name>
+	<servlet>
+		<servlet-name>mvc</servlet-name>
+		<servlet-class>cn.nosum.framework.mvc.v2.servlet.DispatcherServlet</servlet-class>
+		<init-param>
+			<param-name>contextConfigLocation</param-name>
+			<param-value>application.properties</param-value>
+		</init-param>
+
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>mvc</servlet-name>
+		<url-pattern>/*</url-pattern>
+	</servlet-mapping>
+</web-app>
+