前言:
SpringMVC最核心的就是DispatchServlet,所以要先对Servlet有一定的认识,然后就是反射注解ioc等相关知识
什么是MVC?
MVC是一种架构模式 --- 程序分层,分工合作,既相互独立,又协同工作
MVC是一种思考方式 --- 需要将什么信息展示给用户? 如何布局? 调用哪些业务逻辑?
MVC设计思想
MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。
视图(View)代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML、XML和Applet。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)处理。比如一个订单的视图只接受来自模型的数据并显示给用户,以及将用户界面的输入数据和请求传递给控制和模型。
模型(Model):就是业务流程/状态的处理以及业务规则的制定。业务流程的处理过程对其它层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。目前流行的EJB模型就是一个典型的应用例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉你按这种模型设计就可以利用某些技术组件,从而减少了技术上的困难。对一个开发者来说,就可以专注于业务模型的设计。MVC设计模式告诉我们,把应用的模型按一定的规则抽取出来,抽取的层次很重要,这也是判断开发人员是否优秀的设计依据。抽象与具体不能隔得太远,也不能太近。MVC并没有提供模型的设计方法,而只告诉你应该组织管理这些模型,以便于模型的重构和提高重用性。我们可以用对象编程来做比喻,MVC定义了一个顶级类,告诉它的子类你只能做这些,但没法限制你能做这些。这点对编程的开发人员非常重要。
业务模型还有一个很重要的模型那就是数据模型。数据模型主要指实体对象的数据 保存(持续化)。比如将一张订单保存到数据库,从数据库获取订单。我们可以将这个模型单独列出,所有有关数据库的操作只限制在该模型中。
控制(Controller)可以理解为从用户接收请求, 将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后, 并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。
MVC的优点
大部分用过程语言比如ASP、PHP开发出来的Web应用,初始的开发模板就是混合层的数据编程。例如,直接向数据库发送请求并用HTML显示,开发速度往往比较快,但由于数据页面的分离不是很直接,因而很难体现出业务模型的样子或者模型的重用性。产品设计弹性力度很小,很难满足用户的变化性需求。MVC要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好地体现。
首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按MVC设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。 其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。
再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。
控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制层可以说是包含了用户请求权限的概念。
最后,它还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。
思想:
MVC应用程序总是由三个部分组成.Event(事件)导致Controller改变Model或View,或者同时改变两者.只要Controller改变了Models的数据或者属性,所有依赖的View都会自动更新.类似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新自己 。
MVC模式是一个复杂的架构模式,其实现也显得非常复杂,但多种设计模式结合在一起,使MVC模式的实现变得相对简单易行.Views可以看作一棵树,显然可以用Composite Pattern来实现.Views和Models之间的关系可以用Observer Pattern体现.Controller控制Views的显示,可以用Strategy Pattern实现.Model通常是一个调停者,可采用Mediator Pattern来实现.
SpringMVC的原理:
1 首先用户发出请求,请求到达SpringMVC的前端控制器(DispatcherServlet),
2 前端控制器根据用户的url,请求处理器映射器(HandlerMapping)查找匹配该url的handler,并返回一个执行链(HandlerExecutionChain),
3 前端控制器再请求处理器适配器(HandlerAdapter)调用相应的handler进行处理并返回给前端控制器一modelAndView,
4 前端控制器再请求视图解析器(ViewResolver)对返回的逻辑视图进行解析,
5 最后前端控制器将返回的视图进行渲染并把数据装入到request域,返回给用户。
注:DispatcherServlet作为springMVC的前端控制器,负责接收用户的请求并根据用户的请求返回相应的视图给用户(分发调度)
补充:
为什么叫前端控制器?前端又是什么?
举个例子:假如你去医院看病,通过向分诊台的医院描述自己的病情,就可以得到医生的指导具体去看外科、内科或者神经科等等,这里我们的分诊台就扮演着前端控制器(Dispatcher)的角色,也叫做调度器,而各个科室就扮演着控制器(Controller)的角色,因为分诊台是在具体各个科室之前,所以这个模式就叫做前端控制器。
思路:
主要的核心编码是在Servlet初始化里面扫描所有需要的包并将被@Controller,@Service注解修饰的对象实例化放在一个容IOC器里面管理(k-v,className as key ),属性值注入:遍历IOC里面所有的bean对象,遍历每个对象里面的属性,利用反射机制将value映射给它,同时将所有被@RequestMapping修饰的控制器或者方法也放在一个容器里面管理(k-v), Servlet拦截并截取对应的uri 根据uri这个key获取相应的控制器与方法执行invoke操作
首先是xml配置,springmvc需要读取xml里面的配置,然后放在简单的一个集合数据模型里(Map),再然后就是装载用户的配置,扫描基准包,获取用户添加的注解,获取注解信息和配置的参数,再用spring的IOC初始化配置的Bean实例,自动注入类实例(比如contoller的依赖service、dao层mappeer等,等容器启动起来,如果有请求进来,就会按照路径映射对应的controller,再选择方法进行处理完成一系列操作后返回给客户端。

1.实现几个常用的注解@Controller,@Service,@RequestMapping @Autowired @ResponseBody
项目结构图

@Autowrite
package com.tom.annotation; import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowrite { String value() default ""; }
@Controller
package com.tom.annotation; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Controller { String value() default ""; }
@RequestMapping
package com.tom.annotation; import java.lang.annotation.*; @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequestMapping { String value() default ""; }
@ResponseBody
package com.tom.annotation; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ResponseBody { String value() default ""; }
@Service
package com.tom.annotation; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Service { String value() default ""; }
控制器TestController
package com.tom.controller; import com.tom.annotation.Autowrite; import com.tom.annotation.Controller; import com.tom.annotation.RequestMapping; import com.tom.annotation.ResponseBody; import com.tom.entity.User; import com.tom.service.TestService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Controller @RequestMapping(value = "/hello") public class TestController { @Autowrite(value = "TestService") private TestService testService; @RequestMapping(value = "/test") @ResponseBody public String test(){ testService.test(); return "Hello World"; } @RequestMapping(value = "/test01") @ResponseBody public User test01(String username, HttpServletRequest request, HttpServletResponse response, User user){ System.out.println("username:" + username); System.out.println("request:" + request); System.out.println("response:" + response); System.out.println("user:" + user); return user; } @RequestMapping(value = "/test02") public String test02(HttpServletRequest request){ testService.test(); request.setAttribute("msg","未进化的程序猿"); return "index"; } }
spring-mvc.xml 配置需要扫描的包路径
<?xml version="1.0" encoding ="UTF-8"?>
<beans>
<component-scan base-package="com.tom"></component-scan>
<viewResolver prefix="/WEB-INF/jsp/" subfix=".jsp"></viewResolver>
</beans>
解析spring-mvc.xml XML文件的工具类
package com.tom.utils; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.InputStream; import java.io.Reader; import java.net.URL; import java.util.Iterator; public class BeanXmlUtils { //读取默认xml文件的名字为ApplicationContext.xml private final static String config = "spring-mvc.xml"; //获取类路径下的自定义的xml文件的Document对象 public static Document getDocument() throws DocumentException { return getDocument(config); } //获取类路径下的自定义的xml文件的Document对象 public static Document getDocument(String config) throws DocumentException { return new SAXReader().read(BeanXmlUtils.class.getClassLoader().getResource(config)); } //获取类路径下的自定义的xml文件的Document对象 //xml文件的URL public static Document getDocument(URL url) throws DocumentException { return new SAXReader().read(url); } //获取类路径下的自定义的xml文件的Document对象 //xml文件的Reader public static Document getDocument(Reader reader) throws DocumentException { return new SAXReader().read(reader); } //获取类路径下的自定义的xml文件的Document对象 //xml文件的InputStream public static Document getDocument(InputStream inputStream) throws DocumentException { return new SAXReader().read(inputStream); } //获取Xml根元素 public static Element getRootElement(Document document){ return document.getRootElement(); } public static Element getRootElement(URL url) throws DocumentException { return getDocument(url).getRootElement(); } public static Element getRootElement(Reader reader) throws DocumentException { return getDocument(reader).getRootElement(); } public static Element getRootElement(InputStream inputStream) throws DocumentException { return getDocument(inputStream).getRootElement(); } public static Element getRootElement(String config) throws DocumentException { return getDocument(config).getRootElement(); } public static Element getRootElement() throws DocumentException { return getDocument(config).getRootElement(); } //输出元素的所有子元素的详细信息 public static void printElements(Element element){ System.out.println("获取当前名称:" + element.getName()); //获取属性信息 Iterator<Attribute> attributeIterator = element.attributeIterator(); while (attributeIterator.hasNext()){ Attribute attribute = attributeIterator.next(); System.out.println("属性:" + attribute.getName() + "---" + attribute.getText().trim()); } //获取属性value if(attributeIterator != null){ System.out.println("value:" + element.getTextTrim()); } //使用迭代器遍历,继续遍历子元素 Iterator<Element> elementIterator = element.elementIterator(); while (elementIterator.hasNext()){ Element element1 = elementIterator.next(); printElements(element1); } } //输出元素的所有子元素的详细信息 public static void printElements(String config) throws DocumentException { printElements(getRootElement(config)); } //类路径下默认xml文件ApplicationContext.xml输出元素的所有子元素的详细信息 public static void printElements() throws DocumentException { printElements(getRootElement(config)); } }
以上基本实现的springmvc的用法,但是他只是一个空壳,核心在下面
DispatcherServlet核心工作
package com.tom.servlet; import com.tom.annotation.*; import com.tom.entity.User; import com.tom.utils.BeanXmlUtils; import org.dom4j.DocumentException; import org.dom4j.Element; 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.UnsupportedEncodingException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.net.URL; import java.net.URLDecoder; import java.util.*; @SuppressWarnings(value = "all")//取消黄色警告线 public class DispatcherServlet extends HttpServlet { //项目的根路径 String project = this.getClass().getResource("/").getPath(); //保存扫描到的类到缓存中 private static List<String> classNames = new ArrayList<String>(); //保存实例化类到缓存中 private static Map<String,Object> instantiationClassMap = new HashMap<String, Object>(); //保存所有的Method方法到缓存中 private static Map<String,Method> mapping = new HashMap<String, Method>(); //前缀 String prefix = ""; //后缀 String subfix = ""; //容器启动时,完成类扫描、实例化,自动化装配,建立映射 //1、扫描工程路径,找到业务类 //2、实例化类 //3、自动装配 //4、建立映射关系 @Override public void init(ServletConfig config) throws ServletException { //初始化 String initParameter = config.getInitParameter("configurationLocal"); System.out.println("initParameter:" + initParameter); try { //URL解码 空格 会变成 %20 project = URLDecoder.decode(project,"UTF-8"); //1、获得XML文件,对XML文件进行解析 //获取根路径 Element rootElement = BeanXmlUtils.getRootElement(initParameter); //获取直接子节点 Element element = rootElement.element("component-scan"); System.out.println(element.getName()); String packageName = element.attributeValue("base-package"); System.out.println("value:"+packageName); Element viewResolver = rootElement.element("viewResolver"); prefix = viewResolver.attributeValue("prefix"); subfix = viewResolver.attributeValue("subfix"); //2、扫描工程路径,找到业务类 scanPackage(packageName); //测试有没有类保存到缓存中 // for(String str : classNames){ //// System.out.println("总共:"+classNames.size()); // System.out.println("保存Class的路径:" + str); // /* // 保存Class的路径:com.tom.annotation.Autowrite.class // 保存Class的路径:com.tom.annotation.Controller.class // 保存Class的路径:com.tom.annotation.RequestMapping.class // 保存Class的路径:com.tom.annotation.ResponseBody.class // 保存Class的路径:com.tom.annotation.Service.class // 保存Class的路径:com.tom.controller.TestController.class // 保存Class的路径:com.tom.entity.User.class // 保存Class的路径:com.tom.service.TestService.class // 保存Class的路径:com.tom.servlet.DispatcherServlet.class // 保存Class的路径:com.tom.test.Test.class // 保存Class的路径:com.tom.utils.BeanXmlUtils.class // */ // } //3、实例化类 instantiationClass(); //测试有没有实例化类到缓存中 Collection<Object> values = instantiationClassMap.values(); // for (Object value : values) { // System.out.println("实例化类:" + value); // /* // 实例化类:com.tom.service.TestService@60e06f90 // 实例化类:com.tom.controller.TestController@64f43fa7 // */ // } //4、自动装配 automatic_packaging(); //5、建立映射关系 mapping_relation(); //测试 Set<String> strings = mapping.keySet(); for (String string : strings) { Method method = mapping.get(string); System.out.println(string + ":" + method.getName()); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (DocumentException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } //建立映射关系 private void mapping_relation() { //判断保存的缓存的类是否为空 if(classNames.isEmpty() || instantiationClassMap.isEmpty()){ System.out.println("该缓存还没有存储值..."); return; } //遍历集合 Set<Map.Entry<String, Object>> entries = instantiationClassMap.entrySet(); for (Map.Entry<String, Object> entry : entries) { //获取实例化对象 Object o = entry.getValue(); //获取Class对象 Class<?> clazz = o.getClass(); //判断Class对象是否有@Controller注解 if (clazz.isAnnotationPresent(Controller.class)){ //获取@RequestMapping注解 RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class); //获取@RequestMapping注解的值 String value = requestMapping.value(); // System.out.println("@RequestMapping注解的值:" + value); //获取所有的方法 Method[] methods = clazz.getDeclaredMethods(); //遍历所有的方法 for (Method method : methods) { //判断所有的方法是否有@RequestMapping注解 if(method.isAnnotationPresent(RequestMapping.class)){ //获取@RequestMapping注解 RequestMapping requestMapping1 = method.getAnnotation(RequestMapping.class); //获取@RequestMapping注解的值 String value1 = requestMapping1.value(); // System.out.println("@RequestMapping注解的值:" + value1); //将所有的method方法放入到缓存中 mapping.put(value+value1,method); } } } } } //自动装配 private void automatic_packaging() throws IllegalAccessException { //判断保存的缓存的类是否为空 if(classNames.isEmpty() || instantiationClassMap.isEmpty()){ System.out.println("该缓存还没有存储值..."); return; } //遍历集合 Set<Map.Entry<String, Object>> entries = instantiationClassMap.entrySet(); for (Map.Entry<String, Object> entry : entries) { //获取实例化对象 Object o = entry.getValue(); //获取Class对象 Class<?> clazz = o.getClass(); //获取所有的字段 Field[] fields = clazz.getDeclaredFields(); //遍历所有的字段 for (Field field : fields) { //判断所有的字段是否有@Autowrite注解 if(field.isAnnotationPresent(Autowrite.class)){ //获取@Autowrite注解 Autowrite autowrite = field.getAnnotation(Autowrite.class); //获取@Autowrite注解的值 String value = autowrite.value(); // System.out.println("@Autowrite注解的值:" + value ); //暴力反射 field.setAccessible(true); //自动装配 field.set(o,instantiationClassMap.get(value)); } } } } //实例化类 private void instantiationClass() throws ClassNotFoundException, IllegalAccessException, InstantiationException { //判断保存的缓存的类是否为空 if(classNames.isEmpty()){ System.out.println("该缓存还没有存储值..."); return; } //遍历集合 for (String className : classNames) { //com.tom.annotation.Controller.class //首先,实例化是Class.ForName("com.tom.annotation.Controller"); //所以,要把它变成 --> com.tom.annotation.Controller String name = className.replaceAll(".class",""); // System.out.println("class的实例化类:" + name); //效果如下: /* class的实例化类:com.tom.annotation.Autowrite class的实例化类:com.tom.annotation.Controller class的实例化类:com.tom.annotation.RequestMapping class的实例化类:com.tom.annotation.ResponseBody class的实例化类:com.tom.annotation.Service class的实例化类:com.tom.controller.TestController class的实例化类:com.tom.entity.User class的实例化类:com.tom.service.TestService class的实例化类:com.tom.servlet.DispatcherServlet class的实例化类:com.tom.test.Test class的实例化类:com.tom.utils.BeanXmlUtils 保存Class的路径:com.tom.utils.BeanXmlUtils.class class的实例化类:com.tom.annotation.Autowrite class的实例化类:com.tom.annotation.Controller class的实例化类:com.tom.annotation.RequestMapping class的实例化类:com.tom.annotation.ResponseBody class的实例化类:com.tom.annotation.Service class的实例化类:com.tom.controller.TestController class的实例化类:com.tom.entity.User class的实例化类:com.tom.service.TestService class的实例化类:com.tom.servlet.DispatcherServlet class的实例化类:com.tom.test.Test class的实例化类:com.tom.utils.BeanXmlUtils */ //通过反射进行实例化 Class<?> clazz = Class.forName(name); //首先判断类上是否有@Controller注解和@Service注解 //@Controller注解 if(clazz.isAnnotationPresent(Controller.class)){ //实例化 Object o = clazz.newInstance(); //获取@RequestMapping注解 RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class); //获取@RequestMapping注解的值 String value = requestMapping.value(); // System.out.println("@RequestMapping注解的值:" + value); //将@RequestMapping注解的值存放到缓存中 instantiationClassMap.put(value,o); } //@Service注解 if(clazz.isAnnotationPresent(Service.class)){ //实例化 Object o = clazz.newInstance(); //获取@Service注解 Service service = clazz.getAnnotation(Service.class); //获取@Service注解的值 String value = service.value(); // System.out.println("@Service注解的值:" + value); //将@Service注解的值存放到缓存中 instantiationClassMap.put(value,o); } } } //扫描工程路径,找到业务类 private void scanPackage(String packageName) { //D:\Manual-implementation-springMVC\src\com\tom\controller\TestController.java //com.tom ---> com/tom/ String path = packageName.replaceAll("\\.","/"); //获取工程路径 URL url = this.getClass().getClassLoader().getResource("/" + path); //获取子目录下的所有目录和类 File file = new File(url.getFile()); File[] files = file.listFiles(); //遍历目录 for(File file1 : files){ //如果是目录,执行递归 if(file1.isDirectory()){ scanPackage(packageName+"."+ file1.getName()); }else{ //不是目录就是文件 classNames.add(packageName+"."+file1.getName()); } } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取请求的URI地址/Manual_implementation_springMVC/hello/test String requestURI = request.getRequestURI(); //获取contextPath对象 http://localhost:8080/Manual_implementation_springMVC/ String contextPath = request.getContextPath(); //将/Manual_implementation_springMVC/hello/test变为/hello/test String path = requestURI.replace(contextPath,""); System.out.println("path请求路径URI:" + path); //通过反射,动态的实现请求参数的绑定 Method method = mapping.get(path); System.out.println(method.getName()); //通过反射,获取实例化对象 Object o = instantiationClassMap.get("/" + path.split("/")[1]); //执行invoke方法 try { // Class<?> clazz = method.getDeclaringClass(); // Object o = clazz.newInstance(); Parameter[] parameters = method.getParameters(); Object[] objects = new Object[parameters.length]; //遍历所有的参数 for (int i = 0; i < parameters.length; i++) { //获取所有参数的名字 String name = parameters[i].getName(); // System.out.println(name); //获取所有参数的类型 Class<?> type = parameters[i].getType(); //判断参数类型是否是String.class if(type.equals(String.class)){ objects[i] = request.getParameter(name); System.out.println("name:---->" + request.getParameter(name)); }else if(type.equals(HttpServletRequest.class)){ //判断参数类型是否是HttpServletRequest.class objects[i] = request; }else if(type.equals(HttpServletResponse.class)){ //判断参数类型是否是HttpServletResponse.class objects[i] = response; }else if(type.equals(User.class)){ Object instance = type.newInstance(); //获取Class对象 Class<?> clazz = instance.getClass(); //获取所有的字段 Field[] fields = clazz.getDeclaredFields(); //遍历所有的字段 for (Field field : fields) { //获取所有字段的名字 String fieldName = field.getName(); //暴力反射 field.setAccessible(true); field.set(instance,request.getParameter(fieldName)); } objects[i] = instance; } } Object invoke = method.invoke(o, objects); //获取Method方法的返回值 String value = String.valueOf(invoke); //判断Method方法是否有@ResponseBody注解 if(method.isAnnotationPresent(ResponseBody.class)){ //通过response.getWrite()方法写出去 response.getWriter().write(value); }else{ if(invoke.getClass().equals(String.class)){ //请求转发 request.getRequestDispatcher(prefix+"/"+value+subfix).forward(request,response); }else{ response.setStatus(404); } } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
手动实现SpringMVC的效果
@Autowrite(value = "TestService") private TestService testService; @RequestMapping(value = "/test") @ResponseBody public String test(){ testService.test(); return "Hello World"; }


@RequestMapping(value = "/test01") @ResponseBody public User test01(String username, HttpServletRequest request, HttpServletResponse response, User user){ System.out.println("username:" + username); System.out.println("request:" + request); System.out.println("response:" + response); System.out.println("user:" + user); return user; }


@RequestMapping(value = "/test02") public String test02(HttpServletRequest request){ testService.test(); request.setAttribute("msg","未进化的程序猿"); return "index"; }
<%-- Created by IntelliJ IDEA. User: admin Date: 2020/10/7 Time: 14:20 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>${msg} 欢迎您...</h1> </body> </html>
<?xml version="1.0" encoding ="UTF-8"?>
<beans>
<component-scan base-package="com.tom"></component-scan>
<viewResolver prefix="/WEB-INF/jsp/" subfix=".jsp"></viewResolver>
</beans>

实现思路(只是个大概)
1.应用启动初始化操作
创建一个contextLoader实现ServletContextListener接口
创建applicationContext上下文,存储在servletContext中
读取xml配置文件获取扫描bean的包路径
通过配置路径获取带有注解的类
通过反射将类实例化,以类名首字母小写或注解上的值为key,实例化的对象为value,将bean存储在上下文中
2.初始化dispatchservlet
在web.xml中配置dispatchservlet,拦截所有请求
将所有类中的@requestMapping存储在一个map中,key为url,value为class
将class(controller)反射实例化存储在dispatchservlet的上下文中
从applicationContext获取bean,为filed注入实例
3.解析请求
dispatchservlet收到请求
通过threadLocal设置request和response方便在controller中使用。
根据url匹配到对应的class,根据class在dispatchservlet上下文中获取实例。
根据注解value找到对应的方法执行,返回视图。
浙公网安备 33010602011771号