手写MVC(1)

MVC思想

MVC是一种软件编程思想,它认为,一个软件,不论其功能多么复杂,其内部的组件都可以划分为3个模块:

  1. M(model)模型:负责数据的封装和数据库的访问
  2. V(view)视图:负责生成页面,以及和用户的交互
  3. C(controller)控制器:负责调用Model和view

该思想认为,这三个模块的组件之间应该尽量彼此独立,互不干扰。

请简述MVC和model2的关系

model2是MVC思想的具体实现
在这里插入图片描述
发展:
1、
在这里插入图片描述
2、
在这里插入图片描述

3、

在这里插入图片描述

2、一个Serlvet响应多个url请求

1.每个请求url对应一组<servlet-mapping>
2.可使用 /* 或者 *.后缀 的方式来配

  1. <url-pattern>/*:所有请求都交给该Servlet
    1.用户对服务器的请求还包括html/css/js/img等静态资源,这些请求不应该交给Servlet处理,因此配置 /* 不合适

  2. <url-pattern>*.do:所有以 .do 结尾的请求都交给该Servlet
    1.localhast:8888/Servlet11/addUser.do
    2.localhost:8080/Servlet11/action.do

3、练习题:

  1. Servlet01 : /*
  2. Servlet02 : /user/*
  3. Servlet03 : /user/addUser
  4. Servlet04 : *.do

如果请求url是如下几种情况,该由哪个Servlet响应?

  1. url=/user/addUser -> Servlet03
  2. url=/user/listUser -> Servlet02
  3. url=/user/addUser.do -> Servlet02

生效的原则:

  1. 谁最像就找谁
  2. *.do 的优先级是最低的

具体实现:以展示员工列表为例:
在这里插入图片描述
在这里插入图片描述
DispatcherServlet:

package mvc;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
	protected void service(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//获取ServletContext对象
		ServletContext sc = getServletContext();
		//读取web.xml中配置的初始化参数
		String encode = sc.getInitParameter("encode");
		
		//1.处理乱码
		request.setCharacterEncoding(encode);
		response.setContentType("text/html;charset="+encode);
		
		//2.调用子控制器对应的方法
		EmpController controller = new EmpController();
		String path = controller.listEmp(request);
		//path
		path = "/WEB-INF/jsp/"+path+".jsp";
		
		request.getRequestDispatcher(path).forward(request, response);
		
	}

}

web.xml:

    <!-- 为当前项目配置通用的字符编码,配置在web.xml的根目录下 -->
	<context-param>
		<param-name>encode</param-name>
		<param-value>utf-8</param-value>
	</context-param>


    <!-- 对比filter中的配置 -->
    <filter>
		<display-name>EncodingFilter</display-name>
		<filter-name>EncodingFilter</filter-name>
		<filter-class>filter.EncodingFilter</filter-class>
		<!-- 为当前filter配置字符编码,配置在filter标签内 -->
		<init-param>
			<param-name>encode</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>


EmpController:

package mvc;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import cn.tedu.dao.EmpDao;
import cn.tedu.entity.Emp;

public class EmpController {
	/**
	 * 列出所有员工的方法
	 * @param request 存储查询的数据,用来传递给jsp
	 * @return 请求转发的路径
	 */
	public String listEmp(HttpServletRequest request) {
		EmpDao dao = new EmpDao();
		List<Emp> list = dao.findAll();
		request.setAttribute("list", list);
		
		return "list";
	}
	
	
}

在这里插入图片描述

1、注解

1.注解是java1.5之后提供的一项代码标注技术

2.具体应用:

  1. Java或第三方工具已经提供的注解

    1. @override
    2. @Test
  2. 自定义注解

    1. 声明一个注解
    2. 勾选:
      1. @Retention(RUNTIME)
        1. 指定当前注解可以保留到哪个阶段
        2. SOURCE:当前注解仅保留到源码阶段,当源码被编译成class文件时,注解消失。
        3. CLASS:当前注解仅保留到.class文件阶段,当类被加载时,注解消失。
        4. RUNTIME:当前注解被保留到运行阶段,实例化之后,该注解依旧存在。
      2. @Target(METHOD)
        1. 指明当前注解可以添加到哪些位置。
        2. METHOD:该注解可以添加到方法上。
package mvc;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface RequestMapping {
	//返回该注解的属性值
	String value();
}

2、反射

1、是Java在java.lang.reflect包下提供的一组高级工具

2、基于反射,可以实现以下操作:

  1. 查看类中的所有属性
  2. 查看类中的所有方法
  3. 动态创建一个类的实例
  4. 动态调用一个实例的对应方法

3、具体的API

  1. Class cz
    1. Class cz=Class.forName( “com.mysql.jdbc.Driver” );
    2. Class cz=obj.getClass();
    3. Class cz=Person.Class;

反射概念理解:以面向对象思想来理解:
在这里插入图片描述
在这里插入图片描述
反射练习:

1、通过反射获取一个类的属性和方法:

package demo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {

	public static void main(String[] args) {
		//String str = "abc";
		//test(str);
		
		//List<String> list = new ArrayList<String>();
		//Iterator<String> it = list.iterator();
		//test(it);
		
		//利用test2方法,查看java.lang.String的属性和方法
		try {
            //Class.forName():类加载,通过 "包名.类名" 找到对应的 .class文件,然后将其加载到内存当中,然后由JVM自动创建一个Class类型的对象,来代表加载好的.class文件
			Class cz = Class.forName("java.lang.String");
			test2(cz);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
	
	public static void test(Object obj) {
		//获取该实例的Class对象
		Class cz = obj.getClass();
		
		//查看该类的所有属性
		Field[] fs = cz.getDeclaredFields();
		for(Field f : fs) {
			System.out.println(f);
		}
		
		
		System.out.println("------------------------------------------------------------");
		//查看该类的所有方法
		Method[] ms = cz.getDeclaredMethods();
		for(Method m : ms) {
			System.out.println(m);
		}
		
	}
	
	
	public static void test2(Class cz) {
		Field[] fs = cz.getDeclaredFields();
		for(Field f : fs) {
			System.out.println(f);
		}
		
		System.out.println("----------------------------------------------------");
		
		Method[] ms = cz.getDeclaredMethods();
		for(Method m : ms) {
			System.out.println(m);
		}
				
	}
	
	
}

2、通过反射获取一个类的所有注解和注解的value:

以获取Demo类的注解为例:


package demo;

import mvc.RequestMapping;
import org.junit.Test;

public class Demo {
	@RequestMapping(value = "/list.do")
	public void listEmp() {}
	
	@RequestMapping(value = "/add.do")
	public void addEmp() {}
	
	@Test
	public void test() {}
	
}






package demo;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import mvc.RequestMapping;

public class Test2 {

	public static void main(String[] args) throws Exception {
		Class cz = Class.forName("demo.Demo");
		Method[] ms = cz.getDeclaredMethods();
		for(Method m : ms) {
			Annotation[] as = m.getAnnotations();
			if(as != null) {
				for(Annotation a : as) {
					System.out.println(a);
					
					//如果a注解是RequestMapping类型
					if(a instanceof RequestMapping) {
						RequestMapping rm = (RequestMapping)a;
						String value = rm.value();
						System.out.println("value="+value);
					}
					
				}
			}
		}
		
	}

}


具体的API

1、Class cz

  1. Class cz=Class.forName(“com.mysql.cj.jdbc.Driver”);
  2. Class cz=obj.getClass();
  3. Class cz=Person.class;

2.获取所有属性
4. Field[] fs=cz.getDeclaredFields();

3.获取所有方法
5. Method[] ms=cz.getDeclaredMethods();

4.获取一个方法上声明的所有注解
6. Annotation[] as=method.getAnnotations();

5.获取一个方法上指定类型的注解
RequestMapping rm=method.getAnnotation(RequestMapping.class);

6.反射调用一个方法

  1. 0bject result=method.invoke(obj,args);
  2. result:该方法的返回值
  3. obj:调用该方法的实例
  4. args:调用该方法时传入的参数
  5. 0bject. … args,代表可变长度参数,即可以不传,可以传1个,也可以传多个。

7.反射创建一个类的实例
Object obj=cz.newInstance();

练习:

提示用户输入 包名.类名:
提示用户输入 url:

package demo;

import java.lang.reflect.Method;
import java.util.Scanner;

import mvc.RequestMapping;

public class Test4 {

	public static void main(String[] args) throws Exception {
		Scanner in = new Scanner(System.in);	
		System.out.println("请输入包名.类名:");
		String className = in.nextLine();
		System.out.println("请输入url:");
		String url = in.nextLine();
		
		Class cz = Class.forName(className);
		Object obj = cz.newInstance();
		
		Method[] ms = cz.getDeclaredMethods();
		for(Method m : ms) {
			RequestMapping rm = m.getAnnotation(RequestMapping.class);
			if(rm != null) {
				if(url.equals(rm.value())) {
					Object result = m.invoke(obj);
					System.out.println(result);
				}
			}
		}
		
		
	}

}


对 DispatcherServlet 的 改进:

package mvc;

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获取ServletContext对象
		ServletContext sc = getServletContext();
		// 读取web.xml中配置的初始化参数
		String encode = sc.getInitParameter("encode");

		// 1.处理乱码
		request.setCharacterEncoding(encode);
		response.setContentType("text/html;charset=" + encode);

		// 2.调用子控制器对应的方法
		// 获取用户请求的url
		// http://localhost:8080/Servlet11/admin/list.do
		// /Servlet11/admin/list.do
		String url = request.getRequestURI();
		// 截取资源路径,下标从0开始
		url = url.substring(request.getContextPath().length());
		
		try {
			// 加载子控制器
			Class cz = Class.forName("mvc.EmpController");
			// 反射创建子控制器实例,供后续反射调用使用
			Object obj = cz.newInstance();
			// 获取子控制器中所有的方法
			Method[] ms = cz.getDeclaredMethods();
			// 声明一个变量,用于关联后续查找到的方法
			Method findM = null;
			// 遍历子控制器中所有的方法
			for (Method m : ms) {
				// 获取一个方法上添加 RequestMapping 类型的注解
				RequestMapping rm = m.getAnnotation(RequestMapping.class);
				if (rm != null) {// 存在RequestMapping类型的注解的方法
					// 将用户的url与注解值进行比对
					if (url.equals(rm.value())) {
						// 如果一致,使用 findM 引入该方法
						findM = m;
						break;
					}
				}
			}
			// findM不为null,说明子控制器中有与用户请求url相对应的方法
			if (findM != null) {
				// 反射调用该方法
				String path = (String) findM.invoke(obj, request);
				// 将方法返回的路径拼接成完整的资源路径
				// list -> /WEB-INF/jsp/list.jsp
				path = "/WEB-INF/jsp/" + path + ".jsp";
				request.getRequestDispatcher(path).forward(request, response);
			} else {
				response.setStatus(404);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值