MVC思想
MVC是一种软件编程思想,它认为,一个软件,不论其功能多么复杂,其内部的组件都可以划分为3个模块:
- M(model)模型:负责数据的封装和数据库的访问
- V(view)视图:负责生成页面,以及和用户的交互
- C(controller)控制器:负责调用Model和view
该思想认为,这三个模块的组件之间应该尽量彼此独立,互不干扰。
请简述MVC和model2的关系
model2是MVC思想的具体实现
发展:
1、
2、
3、
2、一个Serlvet响应多个url请求
1.每个请求url对应一组<servlet-mapping>
2.可使用 /* 或者 *.后缀 的方式来配
-
<url-pattern>/*
:所有请求都交给该Servlet
1.用户对服务器的请求还包括html/css/js/img等静态资源,这些请求不应该交给Servlet处理,因此配置 /* 不合适 -
<url-pattern>*.do
:所有以 .do 结尾的请求都交给该Servlet
1.localhast:8888/Servlet11/addUser.do
2.localhost:8080/Servlet11/action.do
3、练习题:
- Servlet01 : /*
- Servlet02 : /user/*
- Servlet03 : /user/addUser
- Servlet04 : *.do
如果请求url是如下几种情况,该由哪个Servlet响应?
- url=/user/addUser -> Servlet03
- url=/user/listUser -> Servlet02
- url=/user/addUser.do -> Servlet02
生效的原则:
- 谁最像就找谁
- *.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.具体应用:
-
Java或第三方工具已经提供的注解
-
- @override
- @Test
-
自定义注解
- 声明一个注解
- 勾选:
- @Retention(RUNTIME)
- 指定当前注解可以保留到哪个阶段
- SOURCE:当前注解仅保留到源码阶段,当源码被编译成class文件时,注解消失。
- CLASS:当前注解仅保留到.class文件阶段,当类被加载时,注解消失。
- RUNTIME:当前注解被保留到运行阶段,实例化之后,该注解依旧存在。
- @Target(METHOD)
- 指明当前注解可以添加到哪些位置。
- METHOD:该注解可以添加到方法上。
- @Retention(RUNTIME)
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、基于反射,可以实现以下操作:
- 查看类中的所有属性
- 查看类中的所有方法
- 动态创建一个类的实例
- 动态调用一个实例的对应方法
3、具体的API
- Class cz
- Class cz=Class.forName( “com.mysql.jdbc.Driver” );
- Class cz=obj.getClass();
- 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
- Class cz=Class.forName(“com.mysql.cj.jdbc.Driver”);
- Class cz=obj.getClass();
- 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.反射调用一个方法
- 0bject result=method.invoke(obj,args);
- result:该方法的返回值
- obj:调用该方法的实例
- args:调用该方法时传入的参数
- 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();
}
}
}