当前位置:   article > 正文

自己动手实现简易的springmvc_如何实现springmvc

如何实现springmvc

目录

实现过程思路分析

自定义注解

中央控制器DispatcherServlet

总结


实现过程思路分析

1、创建Maven工程
2、创建控制层、业务层代码(Controller、Service、自定义注解)、准备SpringMvc核心配置文件
3、准备前端控制器 ,创建一个Servlet,同时在web.xml文件中声明该前端控制器
4、创建Spring容器,通过DOM4J解析springmvc的XML文件
5、扫描springmvc中的控制器以及service类并实例化对象放入容器中
6、实现容器中对象的注入,比如将服务层对象注入至控制层
7、建立请求映射地址与控制器以及方法之间的映射关系
8、接收用户请求并进行分发操作
9、用户请求参数处理
10、控制器方法调用以及不同返回值数据处理

作业:封装用户请求参数

Springmvc核心配置文件:springmvc.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <!-- 配置创建容器时要扫描的包-->
  4. <component-scan base-package="com.baiqi.controller,com.baiqi.service"></component-scan>
  5. </beans>

web项目核心配置文件:web.xml

  1. <!DOCTYPE web-app PUBLIC
  2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app>
  5. <display-name>Archetype Created Web Application</display-name>
  6. <!--配置前端控制器-->
  7. <servlet>
  8. <servlet-name>DispatcherServlet</servlet-name>
  9. <servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
  10. <init-param>
  11. <param-name>contextConfigLocation</param-name>
  12. <param-value>classpath:springmvc.xml</param-value>
  13. </init-param>
  14. <!--Web服务器一旦启动,Servlet就会实例化创建对象,然后初始化(预备创建对象)-->
  15. <load-on-startup>1</load-on-startup>
  16. </servlet>
  17. <servlet-mapping>
  18. <servlet-name>DispatcherServlet</servlet-name>
  19. <url-pattern>/</url-pattern>
  20. </servlet-mapping>
  21. </web-app>

 

 

自定义注解

Controller.java

  1. package cn.huangyan.spring.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Documented
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Target({ElementType.TYPE})
  10. public @interface Controller {
  11. String value() default "";
  12. }

Service.java

  1. package cn.huangyan.spring.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Documented
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Target({ElementType.TYPE})
  10. public @interface Service {
  11. String value() default "";
  12. }

Autowired.java

  1. package cn.huangyan.spring.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Documented
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Target(ElementType.FIELD)
  10. public @interface Autowired {
  11. String value() default "";
  12. }

RequestMapping.java

  1. package cn.huangyan.spring.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Documented
  8. @Retention(RetentionPolicy.RUNTIME) //
  9. @Target({ElementType.TYPE,ElementType.METHOD})
  10. public @interface RequestMapping {
  11. String value() default "";
  12. }

注意:

  1. ElementType.TYPE表示定义的这个注解以后可以用在类上;
  2. ElementType.METHOD表示这个注解可以用在方法上;
  3. @Retention(RetentionPolicy.RUNTIME)  表示保留到运行时,运行时能通过反射获取到注解的相关信息

中央控制器DispatcherServlet

  1. package com.springmvc.servlet;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import com.springmvc.annotation.Controller;
  4. import com.springmvc.annotation.RequestMapping;
  5. import com.springmvc.annotation.ResponseBody;
  6. import com.springmvc.context.WebApplicationContext;
  7. import com.springmvc.handler.MyHandler;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.annotation.WebServlet;
  10. import javax.servlet.http.HttpServlet;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.IOException;
  14. import java.io.PrintWriter;
  15. import java.lang.reflect.Method;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. import java.util.Map;
  19. public class DispatcherServlet extends HttpServlet {
  20. //指定SpringMvc容器
  21. private WebApplicationContext webApplicationContext;
  22. //创建集合 用于存放 映射关系 映射地址 与 控制器.方法,用于发送请求直接从该集合中进行匹配
  23. List<MyHandler> handList = new ArrayList<>();
  24. @Override
  25. public void init() throws ServletException {
  26. //1、加载初始化参数 classpath:springmvc.xml
  27. String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
  28. //2、创建Springmvc容器
  29. webApplicationContext = new WebApplicationContext(contextConfigLocation);
  30. //3、进行初始化操作
  31. webApplicationContext.onRefresh();
  32. //4、初始化请求映射关系 /findUser ===》控制器.方法
  33. initHandlerMapping();
  34. }
  35. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  36. //进行请求分发处理
  37. doDispatcher(request,response);
  38. }
  39. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  40. this.doPost(request,response);
  41. }
  42. //进行请求分发处理
  43. public void doDispatcher(HttpServletRequest req, HttpServletResponse resp){
  44. //根据用户的请求地址 /findUser 查找Handler|Controller
  45. MyHandler myHandler = getHandler(req);
  46. try{
  47. if(myHandler == null){
  48. resp.getWriter().print("<h1>404 NOT FOUND!</h1>");
  49. }else{
  50. //调用处理方法之前 进行参数的注入
  51. //调用目标方法
  52. Object result = myHandler.getMethod().invoke(myHandler.getController());
  53. if(result instanceof String){
  54. //跳转JSP
  55. String viewName=(String)result;
  56. // forward:/success.jsp
  57. if(viewName.contains(":")){
  58. String viewType=viewName.split(":")[0];
  59. String viewPage=viewName.split(":")[1];
  60. if(viewType.equals("forward")){
  61. req.getRequestDispatcher(viewPage).forward(req,resp);
  62. }else{
  63. // redirect:/user.jsp
  64. resp.sendRedirect(viewPage);
  65. }
  66. }else{
  67. //默认就转发
  68. req.getRequestDispatcher(viewName).forward(req,resp);
  69. }
  70. }else{
  71. //返回JSON格式数据
  72. Method method = myHandler.getMethod();
  73. if(method.isAnnotationPresent(ResponseBody.class)){
  74. //将返回值转换成 json格式数据
  75. ObjectMapper objectMapper = new ObjectMapper();
  76. String json = objectMapper.writeValueAsString(result);
  77. resp.setContentType("text/html;charset=utf-8");
  78. PrintWriter writer = resp.getWriter();
  79. writer.print(json);
  80. writer.flush();
  81. writer.close();
  82. }
  83. }
  84. }
  85. }catch(Exception e){
  86. e.printStackTrace();
  87. }
  88. }
  89. //根据用户请求查找对应的Handler
  90. /***
  91. * 获取请求对应的handler
  92. * @param req
  93. * @return
  94. */
  95. public MyHandler getHandler(HttpServletRequest req) {
  96. // /findUser
  97. String requestURI = req.getRequestURI();
  98. for (MyHandler myHandler : handList) {
  99. //从容器的Handle取出URL 和 用户的请求地址进行匹配,找到满足条件的Handler
  100. if (myHandler.getUrl().equals(requestURI)) {
  101. return myHandler;
  102. }
  103. }
  104. return null;
  105. }
  106. //初始化请求映射关系
  107. public void initHandlerMapping(){
  108. for (Map.Entry<String, Object> entry : webApplicationContext.iocMap.entrySet()) {
  109. //获取bean的class类型
  110. Class<?> clazz = entry.getValue().getClass();
  111. if(clazz.isAnnotationPresent(Controller.class)){
  112. //获取bean中所有的方法,为这些方法建立映射关系
  113. Method[] methods = clazz.getDeclaredMethods();
  114. for (Method method : methods) {
  115. if(method.isAnnotationPresent(RequestMapping.class)){
  116. RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
  117. //获取注解中的值 /findUser
  118. String url = requestMapping.value();
  119. //建立 映射地址 与 控制器.方法
  120. MyHandler myHandler = new MyHandler(url,entry.getValue(),method);
  121. handList.add(myHandler);
  122. }
  123. }
  124. }
  125. }
  126. }
  127. }

  1. package com.springmvc.context;
  2. import com.springmvc.annotation.AutoWired;
  3. import com.springmvc.annotation.Controller;
  4. import com.springmvc.annotation.Service;
  5. import com.springmvc.xml.XmlPaser;
  6. import java.io.File;
  7. import java.lang.reflect.Field;
  8. import java.net.URL;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.concurrent.ConcurrentHashMap;
  13. /**
  14. * springMvc容器
  15. */
  16. public class WebApplicationContext {
  17. //classpath:springmvc.xml
  18. String contextConfigLocation;
  19. //定义集合 用于存放 bean 的权限名|包名.类名
  20. List<String> classNameList = new ArrayList<String>();
  21. //创建Map集合用于扮演IOC容器: key存放bean的名字 value存放bean实例
  22. public Map<String,Object> iocMap = new ConcurrentHashMap<>();
  23. public WebApplicationContext() {
  24. }
  25. public WebApplicationContext(String contextConfigLocation) {
  26. this.contextConfigLocation = contextConfigLocation;
  27. }
  28. /**
  29. * 初始化Spring容器
  30. */
  31. public void onRefresh(){
  32. //1、进行解析springmvc配置文件操作 ==》 com.baiqi.controller,com.baiqi.service
  33. String pack = XmlPaser.getbasePackage(contextConfigLocation.split(":")[1]);
  34. String[] packs = pack.split(",");
  35. //2、进行包扫描
  36. for(String pa : packs){
  37. excuteScanPackage(pa);
  38. }
  39. //3、实例化容器中bean
  40. executeInstance();
  41. //4、进行 自动注入操作
  42. executeAutoWired();
  43. }
  44. //进行自动注入操作
  45. public void executeAutoWired(){
  46. try {
  47. //从容器中 取出 bean ,然后判断 bean中是否有属性上使用 AutoWired,如果使用了搞注解,就需要进行自动注入操作
  48. for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
  49. //获取容器中的bean
  50. Object bean = entry.getValue();
  51. //获取bean中的属性
  52. Field[] fields = bean.getClass().getDeclaredFields();
  53. for (Field field : fields) {
  54. if(field.isAnnotationPresent(AutoWired.class)){
  55. //获取注解中的value值|该值就是bean的name
  56. AutoWired autoWiredAno = field.getAnnotation(AutoWired.class);
  57. String beanName = autoWiredAno.value();
  58. //取消检查机制
  59. field.setAccessible(true);
  60. field.set(bean,iocMap.get(beanName));
  61. }
  62. }
  63. }
  64. }catch(Exception e){
  65. e.printStackTrace();
  66. }
  67. }
  68. /**
  69. * 实例化容器中的bean
  70. */
  71. public void executeInstance(){
  72. try{
  73. // com.baiqi.controller.UserController com.baiqi.service.impl.UserServiceImpl
  74. for (String className : classNameList) {
  75. Class<?> clazz = Class.forName(className);
  76. if(clazz.isAnnotationPresent(Controller.class)){
  77. //控制层 bean
  78. String beanName = clazz.getSimpleName().substring(0,1).toLowerCase()+ clazz.getSimpleName().substring(1);
  79. iocMap.put(beanName,clazz.newInstance());
  80. }else if(clazz.isAnnotationPresent(Service.class)){
  81. //Service层 bean
  82. Service serviceAn = clazz.getAnnotation(Service.class);
  83. String beanName = serviceAn.value();
  84. iocMap.put(beanName,clazz.newInstance());
  85. }
  86. }
  87. }catch(Exception e){
  88. e.printStackTrace();
  89. }
  90. }
  91. /**
  92. * 扫描包
  93. */
  94. public void excuteScanPackage(String pack){
  95. // com.baiqi.controller ==> com/baiqi/controller
  96. URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
  97. String path = url.getFile();
  98. // /com/bruce/service
  99. File dir=new File(path);
  100. for(File f:dir.listFiles()){
  101. if(f.isDirectory()){
  102. //当前是一个文件目录 com.baiqi.service.impl
  103. excuteScanPackage(pack+"."+f.getName());
  104. }else{
  105. //文件目录下文件 获取全路径 UserController.class ==> com.baiqi.controller.UserController
  106. String className=pack+"."+f.getName().replaceAll(".class","");
  107. classNameList.add(className);
  108. }
  109. }
  110. }
  111. }

URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/,path = cn/huangyan/spring
        String filePath = url.getFile();
        File[] files = new File(filePath).listFiles();

  1. package com.springmvc.xml;
  2. import org.dom4j.Attribute;
  3. import org.dom4j.Document;
  4. import org.dom4j.DocumentException;
  5. import org.dom4j.Element;
  6. import org.dom4j.io.SAXReader;
  7. import java.io.InputStream;
  8. /**
  9. * @BelongsProject: SpringMvc
  10. * @Description: 解析springmvc.xml
  11. */
  12. public class XmlPaser {
  13. public static String getbasePackage(String xml){
  14. try {
  15. SAXReader saxReader=new SAXReader();
  16. InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
  17. //XML文档对象
  18. Document document = saxReader.read(inputStream);
  19. Element rootElement = document.getRootElement();
  20. Element componentScan = rootElement.element("component-scan");
  21. Attribute attribute = componentScan.attribute("base-package");
  22. String basePackage = attribute.getText();
  23. return basePackage;
  24. } catch (DocumentException e) {
  25. e.printStackTrace();
  26. } finally {
  27. }
  28. return "";
  29. }
  30. }

用于存储url和处理器的映射关系的基础组件

  1. package com.springmvc.handler;
  2. import java.lang.reflect.Method;
  3. /**
  4. * @BelongsProject: SpringMvc
  5. * @Description: TODO
  6. */
  7. public class MyHandler {
  8. //请求URL地址
  9. private String url;
  10. //后台控制器
  11. private Object controller;
  12. //控制器中指定的方法
  13. private Method method;
  14. public MyHandler() {
  15. super();
  16. // TODO Auto-generated constructor stub
  17. }
  18. public MyHandler(String url, Object controller, Method method) {
  19. super();
  20. this.url = url;
  21. this.controller = controller;
  22. this.method = method;
  23. }
  24. // 省略getter/setter方法
  25. }

总结

  • 学习如何通过包名,扫描定位到包名下的具体一个个的类文件,并对这些类文件进行解析
  • 学习如何通过反射获取字段的注解属性值,并通过反射给bean字段设值值

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号