背景
为何要用MVC框架?首先我们知道不用框架的话,在javaweb项目中每个请求都要写一个servlet,并且要在web.xml中对每个servlet类的映射作配置,不方便开发,因此引入MVC框架。
工作原理
简单的说MVC框架就是为了简化开发,在service中初始化配置文件获取到请求地址与对应servlet类的映射关系,通过反射和注解等技术动态获取到对应的类和方法,从而对不同的请求作出不同的响应。
看图说话:
根据图中示意介绍一下流程(带源码):
1.首先写一个公共的servlet类:DispatcherServlet,所有请求过来都用它做处理,同时在web.xml中配置它:
2.类继承自HttpServlet,重现两个方法,其中init方法加载配置文件,读取并保存到一个映射池中;service方法获取用户请求地址,并在池中找到对应方法,通过反射机制获取对应类和方法进行相应的处理并返回结果。
@WebServlet(name = "DispatcherServlet", value = "/DispatcherServlet")
public class DispatcherServlet extends javax.servlet.http.HttpServlet {@Overridepublic void init(ServletConfig config) throws ServletException {//获取配置文件名称并读取配置文件String path = config.getInitParameter("contentConfigLocation");InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);HandlerMapping.load(is);}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取请求uriString uri = req.getRequestURI();HandlerMapping.MVCMapping mapping=HandlerMapping.get(uri);if (mapping==null){resp.sendError(404,"自定义MVC:映射地址不存在"+uri);return;}Object obj=mapping.getObj();Method method=mapping.getMethod();Object result=null;try {result=method.invoke(obj,req,resp);} catch (IllegalAccessException e){e.printStackTrace();} catch (InvocationTargetException e){e.printStackTrace();}switch (mapping.getType()){case TEXT:resp.getWriter().write((String) result);break;case VIEW:resp.sendRedirect((String) result);}}
}
3.编写映射池对象:HandlerMapping
成员变量data用于保存请求地址和对应的MVCMapping(一个自定义的对象,用于保存每个地址对应的一个类、方法和注解方式);
成员函数get()通过用户输入的地址获取对应的MVCMapping;
成员函数load() 用于加载配置文件,并将其保存到hashmap中;
public class HandlerMapping {private static Map<String,MVCMapping> data=new HashMap<>();public static MVCMapping get(String uri){return data.get(uri);}//根据用户传入的地址获取到对应的方法public static void load(InputStream is){Properties ppt=new Properties();try {ppt.load(is);} catch (IOException e) {e.printStackTrace();}//获取类Collection<Object> values=ppt.values();for (Object obj:values){String classname=(String) obj;//类名称//通过反射加载类try {//加载每个类Class c=Class.forName(classname);//创建类对象Object cobj=c.getConstructor().newInstance();//获取方法Method[] methods=c.getMethods();for (Method m:methods){//获取该方法中所有注解Annotation[] as=m.getAnnotations();if(as!=null) {for (Annotation ann:as){if (ann instanceof ResponseBody) {//instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回falseMVCMapping mapping=new MVCMapping(cobj,m,ResponseType.TEXT);//生成一个映射器包括类对象、方法和注解类型Object o=data.put(((ResponseBody) ann).value(),mapping);if (o!=null){throw new RuntimeException("请求地址重复:"+((ResponseBody) ann).value());}}else if (ann instanceof ResponseView){MVCMapping mapping=new MVCMapping(cobj,m,ResponseType.VIEW);Object o=data.put(((ResponseView) ann).value(),mapping);if (o!=null){throw new RuntimeException("请求地址重复:"+((ResponseView) ann).value());}}}}}} catch (Exception e) {e.printStackTrace();}}}public static class MVCMapping{private Object obj;//对象:映射器中包含了大量的网址与方法的关系,每个对象封装了一个方法用于处理请求private Method method;//方法private ResponseType type;//枚举:分别处理不同的注解public MVCMapping() {}public MVCMapping(Object obj, Method method, ResponseType type) {this.obj = obj;this.method = method;this.type = type;}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 getType() {return type;}public void setType(ResponseType type) {this.type = type;}}
}
MVCMaping对象用于保存类、对象和注解方式,分别提供了get和set方法。
4.定义注解:
这里设置两个注解,一个给用户返回处理结果字符串类型,另一个返回页面跳转地址。
ResponseBody.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//返回一个值或数据
public @interface ResponseBody {String value();
}
ResponseView.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//返回一个跳转的页面
public @interface ResponseView {String value();
}
ResponseType.java
public enum ResponseType {TEXT,VIEW;
}
5.写处理各种请求的类和方法,例如:
public class UserController {@ResponseBody("/login.do")public String login(HttpServletRequest req, HttpServletResponse resp){return "登陆成功";}@ResponseView("/reg.do")public String reg(HttpServletRequest req, HttpServletResponse resp){return "success.jsp";}
}
6.配置文件:
application.properties:左边自己定义右边写对应的类
a=com.lxj.controller.UserController
7.over
一个最简单的MVC框架写完了。
最后
以上内容是个人自己理解后的总结,如有不对或疑问请大神批评指正。