手写springmvc流程思路指导

代码地址:https://gitee.com/it_feiyue/feiyue-mvc.git

1、创建maven工程(此过程比较简单,不详细介绍)

图示为项目结构:

2、创建控制层、业务层代码(Controller、Service自定义注解)、准备springmvc核心配置文件

2-1、创建自定义注解

@Controller

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

@Service

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

@RequestMapping

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

@AutoWired

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
    String value();
}

2-2、准备控制层代码、业务层代码

控制层:

@Controller
public class UserController {

    @AutoWired("userService")
    UserService userService;
    //定义方法
    @RequestMapping("/findUser")
    public String findUser(){
        //调用服务层
        userService.findUser();
        return "success.jsp";
    }

}

业务层:

接口:

public interface UserService {
    String findUser();
}

实现类:

@Service(value="userService")
public class UserServiceImpl implements UserService {
    @Override
    public String findUser() {
        System.out.println("====调用UserServiceImpl === findUser===");
        return null;
    }
}

2-3、准备springmvc核心配置文件

web.xml配置前端控制器:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>


    <!--配置前端控制器-->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--Web服务器一旦启动,Servlet就会实例化创建对象,然后初始化(预备创建对象)-->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

springmvc.xml配置要扫描的包:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <!-- 配置创建容器时要扫描的包-->
    <component-scan base-package="com.feiyue.controller,com.feiyue.service"></component-scan>

</beans>

3、准备前端控制器,创建一个servlet,同时在web.xml中声明该前端控制器

创建DispatcherServlet及前端控制器:

public class DispatcherServlet extends HttpServlet {}

4、创建springmvc容器,通过dom4j解析springmvc的配置文件

/**
 * @author FEIYUE
 * @description springmvc容器
 * @date 2020/10/22
 */
public class WebApplicationContext {}
public class XmlPaser {

    public static String getBasePackage(String xml){
        try {
            SAXReader saxReader = new SAXReader();
            InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
            //xml文档对象
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Element componentScan = rootElement.element("component-scan");
            Attribute attribute = componentScan.attribute("base-package");
            String basePackage = attribute.getText();
            return basePackage;
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
        }
        return "";
    }
}

5、扫描springmvc中的控制器及Service类,并实例化对象放入到容器中

/**
     * 实例化容器中的bean
     */
    private void executeInstance() {
        try {
            //包名.类名
            for (String className : classNameList) {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)){
                    //控制层bean
                    String beanName = clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1);
                    iocMap.put(beanName,clazz.newInstance());
                }else if (clazz.isAnnotationPresent(Service.class)){
                    //业务层bean
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    iocMap.put(beanName,clazz.newInstance());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

6、实现容器中对象的注入,比如向控制层中注入服务层

/**
     * 进行自动注入操作
     */
    private void executeAutoWired() {
        try {
            //从容器中取出bean,然后判断bean中是否有属性上使用AutoWired,如果使用了该注解,就需要进行自动注入操作
            for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
                //获取容器中的bean
                Object bean = entry.getValue();
                //获取bean中的属性
                Field[] fields = bean.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(AutoWired.class)){
                       //获取注解中的value值
                        AutoWired autoWired = field.getAnnotation(AutoWired.class);
                        String beanName = autoWired.value();
                        //从容器中获取实例
                        Object realBean = iocMap.get(beanName);
                        field.setAccessible(true);
                        field.set(bean,realBean);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

7、建立请求映射地址与控制器及方法之间的映射关系

 /**
     * 初始化请求映射关系
     */
    private void initHandlerMapping() {
        for (Map.Entry<String, Object> entry : webApplicationContext.iocMap.entrySet()) {
            //获取bean的class类型
            Class<?> clazz = entry.getValue().getClass();
            if (clazz.isAnnotationPresent(Controller.class)){
                //获取bean中的所有方法,为这些方法建立映射关系
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        //获取注解中的值 /findUser
                        String url = requestMapping.value();
                        //建立映射地址和控制器中方法的关系
                        MyHandler handler = new MyHandler(url, entry.getValue(), method);
                        handlerList.add(handler);
                    }


                }
            }
        }
    }

8、接受用户请求并进行分发操作

@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 {
        //进行请求分发处理
        doDispatcher(req,resp);
    }

    /**
     * 进行请求分发处理
     * @param req
     * @param resp
     */
    private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) {
        //根据用户请求查找对应的handler
        MyHandler myHandler = getHandler(req);
        try {
            if (null == myHandler){
                resp.getWriter().print("404 NOT FOUND");
            }else {
                //调用处理方法之前 进行参数注入

                //调用目标方法
                Object result = myHandler.getMethod().invoke(myHandler.getController());
                if (result instanceof String){
                    //跳转jsp
                    String viewName = (String)result;
                    //forward:/success.jsp
                    if (viewName.contains(":")) {
                        String viewType = viewName.split(":")[0];
                        String viewPage = viewName.split(":")[1];
                        if (viewType.equals("forward")){
                            req.getRequestDispatcher(viewPage).forward(req,resp);
                        }else {
                            //redirect:/user.jsp
                            resp.sendRedirect(viewPage);
                        }
                    }else {
                        //默认是转发
                        req.getRequestDispatcher(viewName).forward(req,resp);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

9、用户请求参数处理

10、控制器方法调用以及不同返回值数据处理

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值