IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> MVC框架实现 -> 正文阅读

[Java知识库]MVC框架实现

1 背景

之前编写的项目,每个请求都需要一个servlet来响应。我们可以优化代码结构,让多个请求可以被一个servlet接收,然后分发给不同的方法进行处理。

2 原理

  • 定义一个servlet,接收某一大类的请求(比如*.do);
  • 定义一个分发处理类,保存请求地址uri和处理方法之间的映射关系;
  • 由servlet接收请求,调用分发处理类的get方法,找到能够处理此请求的对象(注意java是面向对象的,因此能够处理请求的方法一定是封装在对象里的)
  • 由对象.方法进行请求处理。

2.1 方法绑定请求地址

通过注解的形式,可以实现

  • 请求地址与方法之间的绑定。
  • 确定方法的返回值是一个返回页面地址,还是一段文字内容。(通过定义两个类型的注解实现区分)

3 实现

3.1 定义servlet:

3.1.1 web.xml

  • 定义哪一类请求会进到此servlet中
  • 定义properties的地址
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
            <servlet-name>a</servlet-name>
        <servlet-class>com.kkb.xzk.mvc.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contentConfigLocation</param-name>
            <param-value>application.properties</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>a</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

3.1.2 DispatcherServlet

  • init方法:在servlet加载时自动执行。在这个方法中将url和方法(类对象)之间的绑定关系读到map里
  • service方法:根据请求uri地址找到map中的对象方法调用执行即可
package com.kkb.xzk.mvc;

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.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author: HanDing
 * @Description:
 * @Date Created in 2021-08-02 18:09
 * @Modified By:
 */
public class DispatcherServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        //取得properties文件路径
        String path = config.getInitParameter("contentConfigLocation");
        //获得properties的读取流
        InputStream in = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
        //加载properties里定义的类名称
        HandlerMapping.load(in);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri = req.getRequestURI();
        HandlerMapping.MVCMapping mapping = HandlerMapping.get(uri);
        if(mapping == null){
            resp.sendError(404, "请求未找到!");
            return;
        }
        Method method = mapping.getMethod();
        Object obj = mapping.getObj();
        ResponseType responseType = mapping.getResponseType();
        try {
            String result = (String) method.invoke(obj, req, resp);
            if(responseType == ResponseType.TEXT){ //返回的是一段文字数据
                resp.getWriter().print(result);
            }else if(responseType == ResponseType.VIEW){ //返回的是重定向页面
                resp.sendRedirect(result);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

3.2 定义properties:保存参与请求处理的类

properties里的每一行的value都代表一个类名,表示这个类的0-n个方法会参与到请求处理之中

#在这里保存所有会参与处理请求的类名称
a=com.kkb.xzk.test.Login

3.3 注解定义:区分方法的返回值是一段文本还是返回页面

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
    String value(); // 保存的是请求地址
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseView {
    String value(); //保存的是请求地址,以反射的形式传递给方法
}

3.4 枚举定义:以枚举的形式区分方法的返回值类型

public enum ResponseType {
    TEXT,VIEW;
}

3.5 定义映射池类:将uri和方法做绑定

package com.kkb.xzk.mvc;

import com.kkb.xzk.mvc.annotation.ResponseBody;
import com.kkb.xzk.mvc.annotation.ResponseView;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author: HanDing
 * @Description:
 * @Date Created in 2021-08-02 18:21
 * @Modified By:
 */
public class HandlerMapping {
    private static Map<String, MVCMapping> data = new HashMap<>();
    public static HandlerMapping.MVCMapping get(String uri){
        return data.get(uri);
    }
    public static void load(InputStream in){
        Properties ppt = new Properties();
        try {
            ppt.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Collection<Object> classPaths = ppt.values();
        for (Object classPath : classPaths) {
            String className = (String) classPath;
            try {
                Class clazz = Class.forName(className);
                Object obj = clazz.getDeclaredConstructor().newInstance();
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    Annotation[] annotations = method.getAnnotations();
                    if(annotations != null && annotations.length > 0) {
                        for (Annotation annotation : annotations) {
                            if (annotation instanceof ResponseBody) { //这个方法被ResponseBody注解修饰
                                String uri = ((ResponseBody) annotation).value(); //得到请求地址
                                MVCMapping mapping = new MVCMapping();
                                mapping.setMethod(method);
                                mapping.setObj(obj);
                                mapping.setResponseType(ResponseType.TEXT);
                                Object o = data.put(uri, mapping);
                                if(o != null){ //说明请求uri已经存在了,这里是重复输入
                                    throw new RuntimeException("请求重复:"+uri);
                                }
                            } else if (annotation instanceof ResponseView) { //这个方法被ResponseView注解修饰
                                String uri = ((ResponseView) annotation).value(); //得到请求地址
                                MVCMapping mapping = new MVCMapping();
                                mapping.setMethod(method);
                                mapping.setObj(obj);
                                mapping.setResponseType(ResponseType.VIEW);
                                Object o = data.put(uri, mapping);
                                if(o != null){ //说明请求uri已经存在了,这里是重复输入
                                    throw new RuntimeException("请求重复:"+uri);
                                }
                            }
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    public static class MVCMapping{
        private Object obj; //处理请求的对象
        private Method method; //处理请求的方法
        private ResponseType responseType; // 请求的返回类型

        public Object getObj() {
            return obj;
        }

        public void setObj(Object obj) {
            this.obj = obj;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }

        public ResponseType getResponseType() {
            return responseType;
        }

        public void setResponseType(ResponseType responseType) {
            this.responseType = responseType;
        }
    }
}

3.6 自定义请求处理方法

public class Login {
    @ResponseBody("/login.do")
    public String login(HttpServletRequest req, HttpServletResponse resp){
        return "登录成功!";
    }

    @ResponseView("/reg.do")
    public String reg(HttpServletRequest req, HttpServletResponse resp){
        return "success.jsp";
    }
}

3.7 流程总结

请求 -> DispatcherServlet -> 根据uri找到MVCMapping对象 -> 方法调用处理请求

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 11:01:36  更:2021-08-03 11:02:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 13:10:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码