java 自己动手做框架之MVC
来源:互联网 发布:下一代网络结构和特点 编辑:程序博客网 时间:2024/06/04 18:27
开发工具 :Eclipse Tomcat
依赖jar包 :Gson
1.定义一个核心Servlet
MyServet.java
package com.zking.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.zking.utils.RequestProcessing;/** * 核心Servlet 如果没有此类整个框架没什么用 * @author Administrator * */@WebServlet(urlPatterns = "*.action")public class MyServlet extends HttpServlet { private static final long serialVersionUID = -6919158984346575416L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestProcessing processing = new RequestProcessing(request, response); processing.init(); }}
RequestProcessing.java
package com.zking.utils;import java.io.IOException;import java.io.PrintWriter;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.zking.annotation.Controller;import com.zking.annotation.RequestMapping;import com.zking.annotation.RespnoseBody;import com.zking.type.MethodType;/** * 请求处理类 * * @author Administrator * */public class RequestProcessing { private HttpServletRequest request; private HttpServletResponse response; private static List<Object> controllerObj = new ArrayList<>(); public RequestProcessing(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; } public void init() throws IOException, ServletException { //获得所有带有Controller类的Class对象 List<Class<?>> list = ClassScanUtil.getClassByController(); //获得path 如/index.action String path = null; { String url = request.getRequestURI(); String contextpath = request.getContextPath(); path = url.substring(contextpath.length(), url.length()); } //调用控制器的速度 为保证控制器唯一 顾不能超过一 int count = 0; //遍历所有控制器 直到找到匹配的控制器为止 for (int i = 0; i < list.size(); i++) { Class<?> cls = list.get(i); //获得类中带有RequestMapping注解的方法 Method[] methods = MethodFilterUtil.getMethodByRequestMapping(cls.getMethods()); for (Method method : methods) { //获得该方法的RequestMapping注解 RequestMapping mapping = method.getAnnotation(RequestMapping.class); //判断该方法是否是当前和当前请求的url对应 if (path.equals(mapping.path() + ".action")) { //判断该方法是否支持当前请求方式 if (isMethod(mapping, EnumHandleUtil.getMethodTypeByMethod(request.getMethod()))) { try { //判断该url对应的方法是否调用过了 if (count > 1) { throw new RuntimeException("重复url"); } //创建该控制器的对象 Controller controller = cls.getAnnotation(Controller.class); Object obj = null; //判断当前控制器是否是单例模式 if (controller.singleCase()) { int index = contains(cls); if (index >= 0) { obj = controllerObj.get(i); }else { obj = cls.newInstance(); controllerObj.add(obj); } }else { obj = cls.newInstance(); } //获得当前方法的所有形式参数类型 Class<?>[] clss = method.getParameterTypes(); //调用该方法 Object object = MethodInvokeUtil.Invoke(method, obj, clss, request, response); if (object != null) { //判断该方法是否带有RespnoseBody注解 (如果有那么序列话json并输入到控制台) if (method.getAnnotation(RespnoseBody.class) == null) { //判断该方法返回值是否为String (如果是那么判断是重定向还是请求转发) if (object instanceof String) { String p = object.toString(); if (p.contains("redirect:")) { response.sendRedirect(request.getContextPath() + p.substring(p.lastIndexOf("/")) + ".action"); }else { request.getRequestDispatcher("/" + p + ".jsp").forward(request, response); } } }else{ //将对象转为json并以UTF-8的方式打印到浏览器(依赖gson) print(object); } } //方法调用完成后 标识变量增加 count++; } catch (Exception e) { e.printStackTrace(); } } } } } /** * 如果没有找到对应控制器方法返回错误页面 */ if (count == 0) { response.setCharacterEncoding("utf-8"); response.setStatus(404); request.getRequestDispatcher("/err/err.jsp").forward(request, response); } } /** * 判断该方法是否支持当前请求类型 * @param mapping * @param type * @return */ private boolean isMethod(RequestMapping mapping, MethodType type) { if (mapping.method() == type) { return true; } else if (mapping.method() == MethodType.ALL) { return true; } return false; } /** * 将对象转为json并输出到浏览器 * @param object * @throws IOException */ private void print(Object object) throws IOException{ if (object instanceof String || object instanceof Character || object instanceof Short || object instanceof Integer || object instanceof Byte || object instanceof Long ||object instanceof Float || object instanceof Double) { response.setCharacterEncoding("utf-8"); PrintWriter pw = response.getWriter(); pw.write(object.toString()); pw.close(); }else { //获得当前线程的类加载器 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Object gson = null; try { Class<?> cls = classLoader.loadClass("com.google.gson.Gson"); Method method = cls.getMethod("toJson", Object.class); gson = cls.newInstance(); //调用Gson的toJson方法生成json String json = (String) method.invoke(gson, object); response.setCharacterEncoding("utf-8"); PrintWriter pw = response.getWriter(); pw.write(json); pw.close(); } catch (Exception e) { System.err.println("没有在您的项目中找到Gson"); } if (gson == null) { response.setCharacterEncoding("utf-8"); PrintWriter pw = response.getWriter(); pw.write("没有在您的项目中找到Gson"); pw.close(); } } } public int contains(Class<?> cls){ for (int i = 0; i < controllerObj.size(); i++) { if (cls == controllerObj.get(i).getClass()) { return i; } } return -1; }}
ClassScanUtil.java
package com.zking.utils;import java.io.File;import java.lang.annotation.Annotation;import java.util.ArrayList;import java.util.List;import com.zking.annotation.Controller;public class ClassScanUtil { /** * 获得所有类的全限定名 * @param files * @param 请传null * @return */ private synchronized static List<String> getAllClass(File[] files,List<String> strings) { if (strings == null) { strings = new ArrayList<>(); } for (File file : files) { if (file.isFile()) { if (file.getName().contains(".class")) { // 全限类名 等于项目路径减去类路径 String classPath = file.getPath() .substring(new File(ClassScanUtil.class.getResource("/").getFile()).getPath().length() + 1, file.getPath().lastIndexOf(".class")) .replace("\\", "."); strings.add(classPath); } } if (file.isDirectory()) { getAllClass(file.listFiles(),strings); } } return strings; } private static List<Class<?>> controllerClass = new ArrayList<>(); /** * 获得所有带Controller的类Class对象 * @return */ public static List<Class<?>> getClassByController() { if (controllerClass.size() <= 0) { synchronized(ClassScanUtil.class){ if (controllerClass.size() > 0) { return controllerClass; } File file = new File(ClassScanUtil.class.getResource("/").getFile()); File[] files = file.listFiles(); List<String> strings = getAllClass(files, null); for (int i = 0; i < strings.size(); i++) { try { Class<?> cls = Class.forName(strings.get(i)); Annotation annotation = cls.getAnnotation(Controller.class); if (annotation != null) { controllerClass.add(cls); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } return controllerClass; } } return controllerClass; } /** * 请空集合 * 使用场景 Tomcat为热启动时 可以将Controller设置为单例模式 然后在控制器的构造方法中调用 (这样就类扫描器就会重新去扫描) * 不建议使用 因为控制器为单例模式的话会造成数据冲突 */ @Deprecated public static void clearControllerClass(){ if (controllerClass.size() > 0) { synchronized (ClassScanUtil.class) { if (controllerClass.size() > 0) { controllerClass.clear(); } } } } /** * 增加一个类 (请保证这个类绝对有Controller这个注解) * 使用场景和注意事项同clearControllerClass * @param cls */ @Deprecated public synchronized static void addControllerClass(Class<?> cls){ int c = 0; for (int i = 0; i < controllerClass.size(); i++) { if (cls == controllerClass.get(i).getClass()) { c++; } } if (c == 0) { controllerClass.add(cls); } } /** * 增加一个类 (请保证这个类绝对有Controller这个注解) * 使用场景和注意事项同clearControllerClass * @param className * @throws ClassNotFoundException */ @Deprecated public static void addControllerClass(String className) throws ClassNotFoundException{ addControllerClass(Class.forName(className)); }}
MethodFilterUtil.java
package com.zking.utils;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import com.zking.annotation.RequestMapping;public class MethodFilterUtil { /** * 获得带有RequestMapping注解的方法 * @param methods * @return */ public static Method[] getMethodByRequestMapping(Method[] methods){ List<Method> list = new ArrayList<>(); for (Method method : methods) { if (method.getAnnotation(RequestMapping.class) != null) { list.add(method); } } Method[] methods2 = new Method[list.size()]; for (int i = 0; i < list.size(); i++) { methods2[i] = list.get(i); } return methods2; }}
MethodType.java
package com.zking.type;/** * 请求类型枚举 * @author Administrator * */public enum MethodType { ALL, GET, POST, UPDATE, DELETE}
EnumHandleUtil.java
package com.zking.utils;import com.zking.type.MethodType;public class EnumHandleUtil { /** * 根据请求类型字符串返回请求类型枚举 * @param method * @return */ public static MethodType getMethodTypeByMethod(String method){ method = method.toLowerCase(); MethodType type = MethodType.ALL; if (method.equals("get")) { type = MethodType.GET; }else if(method.equals("post")){ type = MethodType.POST; }else if(method.equals("update")){ type = MethodType.UPDATE; }else if(method.equals("delete")){ type = MethodType.DELETE; } return type; }}
MethodInvokeUtil.java
package com.zking.utils;import java.io.PrintWriter;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.zking.annotation.Param;public class MethodInvokeUtil { /** * 调用控制器方法 * @param method * @param obj * @param classes * @param request * @param response * @return * @throws Exception */ public static Object Invoke(Method method,Object obj,Class<?>[] classes,HttpServletRequest request,HttpServletResponse response) throws Exception{ //声明参数集合 List<Object> objects = new ArrayList<>(); //判断参数类型 进行注入 for (int i = 0; i < classes.length; i++) { if (classes[i] == HttpServletRequest.class) { objects.add(request); }else if (classes[i] == HttpServletResponse.class) { objects.add(response); }else if(classes[i] == HttpSession.class){ objects.add(request.getSession(true)); }else if(classes[i] == PrintWriter.class){ response.setCharacterEncoding("utf-8"); objects.add(response.getWriter()); }else { //如果是普通参数 那么判断它是否有表单参数注解 Annotation[][] annotations = method.getParameterAnnotations(); Param param = null; if (annotations[i].length > 0) { Annotation annotation = annotations[i][0]; if (annotation.annotationType() == Param.class) { param = (Param) annotation; } } //如果有表单参数注解 那么取出表单的值进行注入 if (param != null) { //请求参数处理 RequestParameter parameter = new RequestParameter(method,request, response,objects,classes[i],param); //初始化 parameter.init(); }else { //判断是否是值类型 if (classes[i] == Integer.class || classes[i] == int.class) { objects.add(0); }else if(classes[i] == Short.class || classes[i] == short.class){ objects.add(0); }else if(classes[i] == Byte.class || classes[i] == byte.class){ objects.add(0); }else if(classes[i] == Long.class || classes[i] == long.class){ objects.add(0f); }else if(classes[i] == Float.class || classes[i] == float.class){ objects.add(0f); }else if(classes[i] == Double.class || classes[i] == double.class){ objects.add(0.0); }else { //如果不是值类型 那么以null填充 objects.add(null); } } } } //通过反射调用方法 Object object = method.invoke(obj, objects.toArray()); return object; }}
RequestParameter.java
package com.zking.utils;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.List;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.zking.annotation.Param;public class RequestParameter { private HttpServletRequest request; private HttpServletResponse response; private List<Object> list = null; private Class<?> cls; private Method method; private Param param; public RequestParameter(Method method, HttpServletRequest request, HttpServletResponse response, List<Object> list, Class<?> cls, Param param) { this.method = method; this.request = request; this.response = response; this.list = list; this.cls = cls; this.param = param; } public void init() throws IOException { // 将编码设置成utf-8 request.setCharacterEncoding("utf-8"); setValue(); } /** * 给方法参数设置 */ public void setValue() { // 获得Param注解的name属性值 String paramName = param.name(); if (!paramName.equals("")) { // 判断是否是八大基本数据类型 setValue(request.getParameter(paramName)); }else{ Object object = null; try { object = cls.newInstance(); } catch (InstantiationException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IllegalAccessException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } if (object != null) { Field[] fields = cls.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); try { setValue(fields[i], object, request.getParameter(fields[i].getName())); } catch (IllegalArgumentException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } list.add(object); } } public void setValue(Object object){ if(cls == Integer.class || cls == int.class){ if (object == null) { list.add(0); }else { list.add(Integer.parseInt(object.toString())); } }else if(cls == Short.class || cls == short.class){ if (object == null) { list.add(0); }else { list.add(Short.parseShort(object.toString())); } }else if(cls == Byte.class || cls == byte.class){ if (object == null) { list.add(0); }else { list.add(Byte.parseByte(object.toString())); } }else if(cls == Long.class || cls == long.class){ if (object == null) { list.add(0l); }else { list.add(Long.parseLong(object.toString())); } }else if(cls == Float.class || cls == float.class){ if (object == null) { list.add(0f); }else { list.add(Float.parseFloat(object.toString())); } }else if(cls == Double.class || cls == double.class){ if (object == null) { list.add(0.0); }else { list.add(Double.parseDouble(object.toString())); } }else if(cls == Character.class || cls == char.class){ if (object == null) { list.add((char)0); }else { list.add(object.toString().charAt(0)); } }else if(cls == String.class){ if (object == null) { list.add(null); }else{ list.add(object.toString()); } } } public void setValue(Field field,Object object,Object value) throws NumberFormatException, IllegalArgumentException, IllegalAccessException{ Class<?> paramcls = field.getType(); if (object != null) { if(paramcls == Integer.class || paramcls == int.class){ if (value == null) { field.set(object, 0); }else { field.set(object, Integer.parseInt(value.toString())); } }else if(paramcls == Short.class || paramcls == short.class){ if (value == null) { field.set(object, 0); }else { field.set(object, Short.parseShort(value.toString())); } }else if(paramcls == Byte.class || paramcls == byte.class){ if (value == null) { field.set(object, 0); }else { field.set(object, Byte.parseByte(value.toString())); } }else if(paramcls == Long.class || paramcls == long.class){ if (value == null) { field.set(object, 0l); }else { field.set(object, Long.parseLong(value.toString())); } }else if(paramcls == Float.class || paramcls == float.class){ if (value == null) { field.set(object, 0f); }else { field.set(object, Float.parseFloat(value.toString())); } }else if(paramcls == Double.class || paramcls == double.class){ if (value == null) { field.set(object, 0.0); }else { field.set(object, Double.parseDouble(value.toString())); } }else if(paramcls == Character.class || paramcls == char.class){ if (value == null) { field.set(object, (char)0); }else { field.set(object, value.toString().charAt(0)); } }else if(paramcls == String.class){ if (value == null) { field.set(object, null); }else { field.set(object, value.toString()); } } } }}
详情请见源码 链接:链接:链接:http://pan.baidu.com/s/1hs4y53A 密码:11bl
Tomcat 6.0
web.xml
<servlet> <servlet-name>myServlet</servlet-name> <servlet-class>com.zking.servlet.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myServlet</servlet-name> <!--只能写这个--> <url-pattern>*.action</url-pattern> </servlet-mapping>
Tomcat7.0 且 是动态web3.0 以上无需配置web.xml
使用方法 与SpringMVC一致
只需要将类声明为Controller 方法声明为RequestMapping
请求url为设置的加.action 只能是.action其他的不行
比如
package com.zking.controller;import com.zking.annotation.Controller;import com.zking.annotation.Param;import com.zking.annotation.RequestMapping;import com.zking.annotation.RespnoseBody;import com.zking.entity.Person;//@Controller 原型模式 @Controller(singleCase=true)(单例模式)@Controllerpublic class HelloController { @RespnoseBody @RequestMapping(path="/index") public String index(@Param Person person,@Param(name ="address") String address,@Param(name="phone") long phone){ System.out.println(hashCode()); System.out.println(person); System.out.println(address); System.out.println(phone); return "helloWord"; }}
@RequestMapping(path="/index",method=MethodType.ALL)
那么请求url就是 index.action
参数path必须是/开头
其他与Spring MVC使用一致
0 0
- java 自己动手做框架之MVC
- 4.自己动手写Java Web框架-MVC++
- 自己动手做Web框架—MVC+Front Controller
- 自己动手做Web框架—MVC+Front Controller
- 自己动手写MVC框架
- 自己动手写javaweb mvc框架 之 项目准备
- 3.自己动手写Java Web框架-MVC初体验
- 自己动手写PHP MVC框架
- 自己动手写PHP MVC框架
- 自己动手写PHP MVC框架
- 自己动手写PHP MVC框架
- 自己动手搭建MVC之二
- 自己动手搭建MVC之三
- 自己动手搭建MVC之四
- 自己动手搭建MVC之五
- 自己动手创建简单的MVC框架
- 自己动手模仿 springmvc 写一个 mvc框架
- 自己动手模仿 springmvc 写一个 mvc框架
- Codeforces 766 C Mahmoud and a Message(DP)
- Mysql MySQLSyntaxErrorException Row size too large
- URL结构分解
- Object.GetInstanceID
- [bigdata-042]从头搭建 spring+mvc+boot+tomcat
- java 自己动手做框架之MVC
- PAT-B1040. 有几个PAT
- 数据结构实验之栈一:进制转换
- 安卓开发-高级Admin激活和使用
- Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined)
- 反射(基础知识)
- linux如何使用gcc生成静态库和动态库
- 解决无法使用SecureCRT或Xshell登录vmware ubuntu14.04问题
- 防守阵地 I FZU - 2168