简易版框架
1.项目需求
用一个通用的控制器,进行开发一个web应用程序,只添加相应的配置,就可以通过控制器就可以调用相应的模型和视图的功能
2.初始设计
2.1项目结构
2.2项目搭建
2.3加载配置文件
1.加载配置文件beans标签的依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
2.用于加载核心文件----自定义文件mymvc.xml
就像mvc框架的核心文件springmvc_config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<!-- 一个bean就相当于一个controller对象-->
<bean class="com.demomvc.web.controller.HelloController"/>
</beans>
3.定义一个关键的DispatcherServlet类,让这个类接收所有请求,并且加载配置文件
package com.demomvc.web.servlet;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
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.util.ArrayList;
import java.util.List;
/**
* 用于处理请求和加载配置映射的控制器
* @author miracle
* @date 2022年, 05月, 04日, 11:29
*/
public class DispatcherServlet extends HttpServlet {
/**
* 调用之前,先读取配置文件的属性所指的类加载并创建出对象
*/
@Override
public void init() {
//1.加载读取mymvc.xml配置文件
InputStream in = getClass().getClassLoader().getResourceAsStream("mymvc.xml");
//2.加载数据结构(树状的结构),
SAXReader saxReader = new SAXReader();
//3.创建对象,并保存下来
List<Object> beans = new ArrayList<>();
try {
//返回一个document对象,一个树状的结构
Document read = saxReader.read(in);
//获取xml文件的根路径
Element root = read.getRootElement();
//获取根节点中的所有子节点
List<Element> elements = root.elements();
//读取每个子节点的class的值进行类加载对象
for (Element element : elements) {
//获取子节点的属性值--值对应的就是类的全称名称
String s = element.attributeValue("class");
//关键信息,创建对象
Object bean = Class.forName(s).getConstructor().newInstance();
//保存对象
beans.add(bean);
System.out.println("属性值 = " + s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.一个控制器类
,HelloController类
测试
public class HelloController {
/**
* 一个方法对应一个请求地址
*/
@RequestMapping("/hello")
public String hello(){
//业务逻辑代码
System.out.println("我已知晓了");
return "1111";
}
}
5.关键的注解@RequestMapper(自定义)
@ResponseMapper(可写可不写)
package com.demomvc.web.annotation;
import java.lang.annotation.*;
/**
* 用于映射规则:请求地址和那个对象的处理方法进行映射
* @author Miracle
*/
@Documented
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
/**
* url的地址
*/
String value() default "";
}
package com.demomvc.web.annotation;
import java.lang.annotation.*;
/**
* @author Miracle
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseBody {
//设置响应体的编码方式
String charSet() default "text/html; charset=UTF-8";
}
2.4初始化参数
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.demomvc.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 接收所有的请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
3.结构设计
3.1项目结构
3.2处理器设计
1.创建一个Handler对象(进行url对象的映射)
package com.demomvc.web.processor;
import java.lang.reflect.Method;
/**
* 用于处理那个类和那个方法进行映射
* @author miracle
*/
public class Handler {
/**
* 类的对象
*/
private Object object;
/**
* 类中的方法
*/
private Method method;
public Handler() {
}
public Handler(Object object, Method method) {
this.object = object;
this.method = method;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
@Override
public String toString() {
return "Handler{" +
"object=" + object +
", method=" + method +
'}';
}
}
2.在 DispatcheServlet类的init()的方法补全
public void init() {
//1.加载读取mymvc.xml配置文件
InputStream in = getClass().getClassLoader().getResourceAsStream("mymvc.xml");
//2.加载数据结构(树状的结构),
SAXReader saxReader = new SAXReader();
//3.创建对象,并保存下来
List<Object> beans = new ArrayList<>();
try {
//返回一个document对象,一个树状的结构
Document read = saxReader.read(in);
//获取xml文件的根路径
Element root = read.getRootElement();
//获取根节点中的所有子节点
List<Element> elements = root.elements();
//读取每个子节点的class的值进行类加载对象
for (Method method : methods) {
//判断方法上是否有注解
if(method.isAnnotationPresent(RequestMapping.class)){
//获取方法上的注解
RequestMapping declaredAnnotation = method.getDeclaredAnnotation(RequestMapping.class);
//获取注解的值--url
String value = declaredAnnotation.value();
//添加
handlers.put(value, new Handler(bean,method));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3.控制器和处理器(HandlerMapping)进行映射关联,process(List beans)
package com.demomvc.web.processor;
import com.demomvc.web.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* url和方法进行映射
* @author miracle
* @date 2022年, 05月, 06日, 10:47
*/
public class HandlerMapping {
/**
* 一个key对应一个方法的映射
*/
private final Map<String, Handler> handlers = new HashMap<>();
/**
* 获取path对应的Handler对象
* @param path 请求路径
* @return handler对象
*/
public Handler getHandler(String path){
return handlers.get(path);
}
/**
* path和handler对象进行捆绑
* @param beans Controller对象
*/
public void process(List<Object> beans) {
//遍历集合中的对象
for (Object bean : beans) {
//获取实例化对象
Class<?> aClass = bean.getClass();
//获取声明的方法
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
//获取方法上的注解
method.getDeclaredAnnotationsByType(RequestMapping.class);
RequestMapping declaredAnnotation = method.getDeclaredAnnotation(RequestMapping.class);
//获取注解的值--url
String value = declaredAnnotation.value();
//添加
handlers.put(value, new Handler(bean,method));
}
}
System.out.println("handlers = " + handlers);
}
}
到这里地址和对象就可以进行映射了,还有一个重点(servlet和控制器进行连接)
这里的业务层比较多。。。。。
3.3界面跳转模块开发
这里实现一个简单的业务
1.在DispatcherServlet中的serivce方法进行补全
public void service(ServletRequest req, ServletResponse res) {
//强制HttpServletRequest对象
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)res;
//获取请求路径
String requestURI= request.getRequestURI();
System.out.println("uri=" + requestURI);
//拿到地址和控制器对象的映射
Handler handler = handlerMapping.getHandler(requestURI);
//判断是否为空
Optional.ofNullable(handler).ifPresent(u->{
//不为空是执行方法的内容
Method method = u.getMethod();
try {
String invoke = (String) method.invoke(handler.getObject());
if (method.isAnnotationPresent(ResponseBody.class)) {
//获取相应编码方式
String s = method.getAnnotation(ResponseBody.class).charSet();
//设置编码方式
response.setContentType(s);
//说明返回的结果是数据
response.getWriter().println("执行的结果:"+invoke);
}else{
// 返回的结果是页面
if (invoke.startsWith("redirect:")) {
//重定向
response.sendRedirect(invoke.substring(invoke.indexOf(":")+1));
}else {
//转发
request.getRequestDispatcher(invoke).forward(request,response);
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
ndRedirect(invoke.substring(invoke.indexOf(“:”)+1));
}else {
//转发
request.getRequestDispatcher(invoke).forward(request,response);
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
}