文章目录
一、MVC 概述
1、自定义MVC框架步骤
(1)自定义业务控制器,在业务控制器上添加@Controller
和@RequestMapping("请求地址")
。
@Controller
public class UserController {
@RequestMapping("select")
public String select() {
System.out.println("执行查询");
return "redirect:selectSuccess.html";
}
@RequestMapping("insert")
public String insert() {
System.out.println("执行新增");
return "insertSuccess.html";
}
}
- @Controller 注解的作用是标记一个类为业务控制器
- @RequestMapping 注解的作用是对方法以及执行该方法的请求进行映射
(2)在src下定义 mvc.xml 文件,该文件用于配置业务控制器的包名,便于框架扫描
<?xml version="1.0" encoding="UTF-8"?>
<mvc>
<package>com.woniu.controller</package>
</mvc>
(3)定义监听器,读取 xml 文件获取包名,从服务器中获取该包中每一个类的类名
@WebListener
public class ContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void contextInitialized(ServletContextEvent event) {
// 扫描某个 包中所有的类
// 读取xml文件 获取用户存放业务控制器的包名
SAXReader saxReader = new SAXReader();
// 通过类加载器来获取类加载器加载java文件的根目录
InputStream is = this.getClass().getClassLoader().getResourceAsStream("mvc.xml");
try {
Document document = saxReader.read(is);
Element root = document.getRootElement();
String pn = root.element("package").getText();
//packageName将.替换为/
String packageName = pn.replace(".", "/");
//获取服务器java代码的跟路径
URL url = this.getClass().getClassLoader().getResource("");
String path = url.getPath();
//去掉最前面的/
path = path.substring(1);
//将classes目录+包的目录组合成为包的绝对路径
String pack = path+packageName;
File dir = new File(pack);
//取出该文件夹下所有的文件
File[] files = dir.listFiles();
//循环便利所有的文件 判断后缀是否是class后缀
//定义键值对用于存储所有的请求地址映射信息
Map<String,Mapping> map = new HashMap<String,Mapping>();
for(File file:files) {
if(file.getName().endsWith(".class")) {
//条件成立说明该文件 是一个java类 扫描该java类上的注解
//截取出文件的文件名不包括后缀
String classPrefix = file.getName().substring(0,file.getName().lastIndexOf("."));
String className = pn+"."+classPrefix;
//获取类的信息
Class c = Class.forName(className);
//判断当前类上是否有@Controller注解
if(c.isAnnotationPresent(Controller.class)) {
//遍历所有的方法
Method[] methods = c.getDeclaredMethods();
for(Method method:methods) {
//检查方法上是否有@RequestMapping注解
if(method.isAnnotationPresent(RequestMapping.class)) {
//封装为Mapping对象
Mapping mapping = new Mapping();
mapping.setClassInfo(c);
mapping.setMethod(method);
mapping.setName(method.getAnnotation(RequestMapping.class).value());
map.put(mapping.getName(), mapping);
}
}
}
}
}
//将键值对保存到application作用域中
event.getServletContext().setAttribute("map", map);
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过类名获取类的字节码信息,通过扫描每一个方法上的注解,将请求地址—类—方法形成一个映射信息封装为 Mapping 对象,将对象保存到一个键值对中,将键值对保存到 application 作用域中
(4)自定义过滤器或者是 Servlet,用来作为分发请求核心控制器
public class DisparcherServlet extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求地址
String uri = request.getRequestURI();
uri = uri.substring(uri.lastIndexOf("/")+1);
String requestName = uri.substring(0,uri.lastIndexOf("."));
//从application中取出键值对
Map<String,Mapping> map = (Map<String, Mapping>) request.getServletContext().getAttribute("map");
Mapping mapping = map.get(requestName);
//通过映射信息中的classinfo实例化业务控制器
Class c = mapping.getClassInfo();
try {
Object object = c.newInstance();
Method method = mapping.getMethod();
String result = (String) method.invoke(object, null);
//判断业务控制器返回的字符串是否包含:
if(result.indexOf(":") == -1) {
request.getRequestDispatcher(result).forward(request, response);
}else {
if("redirect".equals(result.split(":")[0])) {
response.sendRedirect(result.split(":")[1]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5)在核心控制器中取出请求地址,通过请求地址名称获取该请求地址的映射信息,通过映射信息中的 classinfo 和 method 实现业务控制器方法的调用,在通过业务控制器返回的页面地址实现响应
public class Mapping {
private String name;
private Class classInfo;
private Method method;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Class getClassInfo() {
return classInfo;
}
public void setClassInfo(Class classInfo) {
this.classInfo = classInfo;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
(6)web.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>mvc</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>com.woniu.mvc.servlet.DisparcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
(7)前端简单页面示例
① 发送请求
<body>
<a href="select.do">测试查询</a>
<a href="insert.do">测试新增</a>
</body>
② 查询成功返回页面 selectSuccess.html
<body>
<h1>查询成功</h1>
</body>
③ 新增成功返回页面 insertSuccess.html
<body>
<h1>新增成功</h1>
</body>