模仿struts2做一个简单控制器,easycontroller
综述:1.在启动服务器的时候,执行SoFilter过滤器的init方法时 加载一个easyCotroller.properties 配置文件,然后解析这个配置文件,把所有的对象放到一个容器中,每个key值对应一个对象,这个key就是control层的访问类的classId,value就是这个访问类的实例,然后每次请求都是从容器中取。
2.我在index.jsp 发送一个请求,然后经过过滤器, 在doFilter方法中从容器中找到我要访问的对象 然后通过反射调用对象的方法 完成页面的跳转
下面是具体流程:
新建一个javaweb项目,然后绑定到tomcat服务器上去,WebContent\WEB-INF配置如下
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name> 2013_0818easycontroller </display-name> <!--eayscontroller的核心控制器 所有的请求的经过这里 然后在这里进行调度 --> <filter> <filter-name>Sofilter</filter-name> <filter-class>cn.learnself.filter.SoFilter</filter-class> </filter> <filter-mapping> <filter-name>Sofilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 做一个测试用的servler --> <servlet> <servlet-name>bs</servlet-name> <servlet-class>cn.learnself.servlet.BaseServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>bs</servlet-name> <url-pattern>/bs</url-pattern> </servlet-mapping> <!-- 项目默认首页 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
--------------------------------------------------------------------------
然后在src\cn\learnself\filter 包下有1个类和一个properties配置文件
package cn.learnself.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.common.CallUtil; import cn.learnself.common.CallUtil2; import cn.learnself.common.CallUtil3; import cn.learnself.common.FileUtil; public class SoFilter implements Filter{ public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { System.out.println("dofilter"); CallUtil callUtil = new CallUtil(); CallUtil2 callUtil2 = new CallUtil2(); CallUtil3 callUtil3 = new CallUtil3(); HttpServletRequest request =(HttpServletRequest)arg0; HttpServletResponse response=(HttpServletResponse)arg1; // System.out.println(request.getRequestURI()); //2013_0818learnself/HelloWord/setName.so // System.out.println(request.getServletPath());//HelloWord/setName.so String url_str = request.getServletPath();//HelloWord/setName.so if(url_str.endsWith(".so")){ url_str.substring(0, url_str.indexOf("!")); String class_name=url_str.substring(url_str.lastIndexOf("/")+1, url_str.indexOf("!"));//HelloWord String method_name= url_str.substring(url_str.indexOf("!")+1, url_str.indexOf(".so")); // System.out.println(class_name); // // System.out.println(method_name); try { // Class cls = Class.forName("cn.learnself.test."+class_name); // Object o = cls.newInstance(); // Method method = cls.getMethod("setName",String.class); // method.invoke(o, "zhangsan"); // new CallUtil().deliver(request,response, "cn.learnself.test."+class_name, method_name); 最一开始做的 // callUtil.deliver(request,response, callUtil.getCompleteUrl(class_name), method_name); // callUtil2.deliver(request,response, class_name, method_name); callUtil3.deliver(request,response, class_name, method_name); } catch (Exception e) { e.printStackTrace(); } }else{ arg2.doFilter(arg0, arg1); } } public void init(FilterConfig arg0) throws ServletException { FileUtil.parseXml(); System.out.println("init......"); } public void destroy() { } }
src\cn\learnself\filter\easycontroller.properties 这个配置文件有两句代码 key是control层每个访问类的ClassId value 就是这个类在项目下的全路径加类名
HelloWord=cn.learnself.test.HelloWord
RegisterUser=cn.learnself.control.RegisterUser
-------------------------------------------------------------------------
src\cn\learnself\common 这个包下有4个类
package cn.learnself.common; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.filter.SoFilter; /** * @description:通过反射 完成对要访问的控制器实现类的调用,不足 每次访问一个类 到用 newInstance 加载进内存 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com * @version easy-controller-version201301 */ public class CallUtil { public void deliver(HttpServletRequest re, HttpServletResponse rs,String class_name_complete,String method_name){ try { Class cls = Class.forName(class_name_complete); Object o = cls.newInstance(); Method method = cls.getMethod(method_name,WebContext.class); method.invoke(o, new WebContext(re,rs)); } catch (Exception e) { e.printStackTrace(); } } public String getCompleteUrl(String className){ String complete_className=""; Properties prop = new Properties(); try { InputStream ips = SoFilter.class.getResourceAsStream("easycontroller.properties"); prop.load(ips); ips.close(); complete_className = prop.getProperty(className); } catch (Exception e) { e.printStackTrace(); } return complete_className; } }
package cn.learnself.common; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.filter.SoFilter; /** * @description: 通过容器获取要访问的 控制器对象 然后通过反射 完成 对方法的调用, * 好处:保证了 每次请求都始终使用一个对象 ,不足:页面跳转的时候 还需要在方法中做 转发或重定向,重复率太高 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com * @version easy-controller-version201301 */ public class CallUtil2 { public void deliver(HttpServletRequest re, HttpServletResponse rs,String class_name,String method_name){ try { // FileUtil fu = new FileUtil(); // Class cl = (Class)fu.classCoatainer.get(class_name); // 从容器中取出对象 Map map = FileUtil.classCoatainer; Object o = map.get(class_name); // 从容器中取出对象 Method method = o.getClass().getMethod(method_name,WebContext.class); method.invoke(o, new WebContext(re,rs)); // 现在我要做的是 从容器中取出的对象是Object ,而我要把Object 转换成有用的实际对象,然后用这个对象来调用她的方法 // 我如何从一个对象 获取这个对象的类型呢 // o.getClass(). System.out.println("22222222"+o); } catch (Exception e) { e.printStackTrace(); } } public String getCompleteUrl(String className){ String complete_className=""; Properties prop = new Properties(); try { InputStream ips = SoFilter.class.getResourceAsStream("easycontroller.properties"); prop.load(ips); ips.close(); complete_className = prop.getProperty(className); } catch (Exception e) { e.printStackTrace(); } return complete_className; } }
package cn.learnself.common; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Map; import java.util.Properties; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.filter.SoFilter; /** * @description: 通过容器获取要访问的 控制器对象 然后通过反射 完成 对方法的调用, * 控制 转发在此类中完成, 不足:我控制器类方法返回的的必须jsp的全路径 可以改为返回url_id 然后在配置文件中读取全路径 * 通过配置文件读取 有没有是转发还是重定向的标志 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com * @version easy-controller-version201301 */ public class CallUtil3 { public void deliver(HttpServletRequest re, HttpServletResponse rs,String class_name,String method_name){ try { Map map = FileUtil.classCoatainer; Object o = map.get(class_name); // 从容器中取出对象 Method method = o.getClass().getMethod(method_name,WebContext.class); String url_str=(String)method.invoke(o, new WebContext(re,rs)); System.out.println(url_str); if(url_str!=null&&!"".equals(url_str)){ RequestDispatcher rd = re.getRequestDispatcher(url_str+".jsp"); rd.forward(re,rs); } } catch (Exception e) { e.printStackTrace(); } } public String getCompleteUrl(String className){ String complete_className=""; Properties prop = new Properties(); try { InputStream ips = SoFilter.class.getResourceAsStream("easycontroller.properties"); prop.load(ips); ips.close(); complete_className = prop.getProperty(className); } catch (Exception e) { e.printStackTrace(); } return complete_className; } }
package cn.learnself.common; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Set; import cn.learnself.filter.SoFilter; /** * @description: 用来解析配置文件的一个类 完后做一个容器 把多有对象都方里边去 在init方法中用到 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com * @version easy-controller-version201301 */ public class FileUtil { public static Map classCoatainer = new HashMap(); public static void parseXml(){ String classId=""; String complete_className=""; Properties prop = new Properties(); try { InputStream ips = SoFilter.class.getResourceAsStream("easycontroller.properties"); prop.load(ips); ips.close(); // 然后开始解析这个.properties 文件 生成所有对象 放到容器中 Set keySet= prop.keySet(); for(Object key: keySet){ // System.out.println(key.toString()); classId =key.toString(); complete_className = prop.getProperty(classId); Class cls = Class.forName(complete_className); Object o = cls.newInstance(); classCoatainer.put(classId, o); // classCoatainer.put(classId, cls); } } catch (Exception e) { e.printStackTrace(); } // System.out.println(classCoatainer); } }
package cn.learnself.common; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @description: 控制器中的参数对象 封装 request和response * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com * @version easy-controller-version201301 */ public class WebContext { public HttpServletRequest request; public HttpServletResponse response; public WebContext(HttpServletRequest req, HttpServletResponse res){ request=req; response=res; } }
src\cn\learnself\control 包下有一个类
package cn.learnself.control; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.common.WebContext; /** * @description: 控制器 测试用的 注册用户接收参数 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com */ public class RegisterUser { public void register(WebContext webc) throws Exception{ HttpServletRequest request= webc.request; HttpServletResponse response= webc.response; String name = request.getParameter("name"); System.out.println(name); // response.sendRedirect("HelloWord.jsp"); // System.out.println(request.getRequestURI()); request.setAttribute("name", name); //转发 最常用 RequestDispatcher rd = request.getRequestDispatcher("HelloWord.jsp"); rd.forward(request,response); } } // 写在过滤器里边容易执行两次 ,而我的被url访问的类 记没有继承Servlet 也不是action ,如何做转发和重定向呢 // 写一个超类 用来做webc 的继承 2 动态代理, 不用这个过滤器来实现,使用动态代理,在我访问的时候 其实是访问的我的代理类, // 如果用过滤器来实现 可能执行两次了 当 // 仔细学学spring 把spring 和项目结合起来,让spring 做类实例化 // 过滤器主要是判断用户有没有登录 有没有对应的权限 来访问路径
src\cn\learnself\servlet
package cn.learnself.servlet; import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @description: 一个普通的servlet 重定向访问了两次 过滤器的doFilter * */ public class BaseServlet extends HttpServlet{ public void doGet(HttpServletRequest re, HttpServletResponse rs){ System.out.println("访问到了"); try { rs.sendRedirect("BaseServlet.jsp"); } catch (IOException e) { e.printStackTrace(); } } }
\src\cn\learnself\test
package cn.learnself.test; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.learnself.common.FileUtil; import cn.learnself.common.WebContext; /** * @description: 控制器 测试页面的跳转 和反射是否成功 * @author 令狐冲之12 * @date 2013-08-25 * @mail 1055592535@qq.com */ public class HelloWord { public void setName(WebContext webc) throws Exception{ HttpServletRequest request= webc.request; HttpServletResponse response= webc.response; // 如果使用重定向 则经过 两次过滤器的doFilter 第一次是我访问到request url Helloword!setName.so, // 第二次是request 的url HelloWord.jsp 这是我在 这里定义的 ,所以在jsp中得不到这个name值,所以不常用重定向 // 如果用 转发 只发送一次请求,只访问了一次url Helloword!setName.so,HelloWord.jsp是转发过去的 不经过 过滤器的doFilter // 使用重定向控制页面跳转 // response.sendRedirect("HelloWord.jsp"); // System.out.println(request.getRequestURI()); Map map = FileUtil.classCoatainer; Object o = map.get("HelloWord"); // 从容器中取出对象 System.out.println("0000000000"+o); // 看内存地址和 Filter是否一样 request.setAttribute("name", "qinyinglian"); //转发 最常用 RequestDispatcher rd = request.getRequestDispatcher("HelloWord.jsp"); rd.forward(request,response); } public String setAge(WebContext webc) throws Exception{ HttpServletRequest request= webc.request; HttpServletResponse response= webc.response; request.setAttribute("age", "26"); return "HelloWord_setAge"; // 注意这个是全路径 } }
index.jsp WebContent\index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <body> <!-- 可以看出 当我的请求要访问 bs 的Servlet 的时候 是先经过了过滤器 , 我用了重定向 到BaseServlet.jsp 重新发送请求又经过了一次过滤器 --> <a href="bs">测试访问BaseServlet类是否经过过滤器</a> <br/><br/> <a href="HelloWord!setName.so">访问HelloWord类setName方法</a> <br/><br/> <table><tr><td>测试get请求 访问RegisterUser类register方法:</td></tr> <tr><td> <form action="RegisterUser!register.so"> <input type="text" name="name" /> <input type="submit" value="提交"/> </form></td></tr> </table> <br/><br/> <table><tr><td>测试post请求 访问RegisterUser类register方法::</td></tr> <tr><td> <form action="RegisterUser!register.so" method="post"> <input type="text" name="name" /> <input type="submit" value="提交"/> </form> </td></tr> </table> <br/> <br/> <a href="HelloWord!setAge.so">访问控制器的类的一个方法,方法有返回值 是字符串url</a> </body>
HelloWord.jsp 路径 WebContent\HelloWord.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> helloword.jsp <br> <% String name=(String)request.getAttribute("name"); %> <input type="text" name="name" value="<%=name%>" /> </body> </html>
WebContent\HelloWord_setAge.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> helloword_setAge.jsp <br> <% String age=(String)request.getAttribute("age"); %> <input type="text" name="name" value="<%=age%>" /> </body> </html>
BaseServlet.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <body> baseservlet.jsp </body>
备注,需要一个servelt的包,其他包不需要

浙公网安备 33010602011771号