基於配置的自訂的簡單struts(瞭解struts原理),struts原理

來源:互聯網
上載者:User

基於配置的自訂的簡單struts(瞭解struts原理),struts原理

             struts的基於配置的action跳轉方式使用起來特別方便,對此我也模仿struts的action,實現一個自己定義的通過設定檔配置action進行簡單的操作:

       首先,可以知道sturts是通過過濾器來攔截瀏覽器發送的請求,再在過濾器裡進行操作,實現這個流程。

       那麼,我們也定義一個filter在我們的程式中:

      

public class StrutsFilter implements Filter{     public void doFilter(ServletRequest arg0, ServletResponse arg1,FilterChain arg2) throws       IOException, ServletException {     {            }}


       同樣,對所有請求進行攔截,在web.xml中進行配置:

<?xml version="1.0" encoding="UTF-8"?><web-app id="WebApp_9" 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>Struts Blank</display-name>    <filter>        <filter-name>struts2</filter-name>        <filter-class>com.yc.frame.filter.StrutsFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>struts2</filter-name>        <url-pattern>*</url-pattern>    </filter-mapping>    <welcome-file-list>        <welcome-file>index.jsp</welcome-file>    </welcome-file-list></web-app>
      當然,struts中最重要的就是struts.xml的這個設定檔,在這裡分析設定檔可以知道,struts必然是先解析出xml,然後將解析的xml以一個資料結構儲存,利用反射找到相應的Action子類,再用反射啟用裡面的配置的方法或者預設的execute方法,既然邏輯出來了,那麼要如何設定資料結構對xml解析出來的檔案進行儲存呢?

struts.xml如下:

<?xml version="1.0" encoding="UTF-8" ?><struts>  <!-- 自訂的Struts -->    <package name="default" namespace="/"  >     <action name="user.action" class="com.yc.frame.actions.UserAction" method="add">            <result name="success"  type="direct">a.jsp</result>             <result name="fail" type="direct">a.jsp</result>     </action>    <!--多個action-->    </package></struts>


在這裡,每個節點對應一個類, 由於xml中有對應的層級關係,所以在設計這些類時,也要將這些類的層級關係體現出來,才能準確的對資料進行處理和操作:

//package節點對應的節點類,它應該有一個actioin節點類的集合<pre name="code" class="java">自然要提供getset方法(get,set省略)

public class PackageWrapper implements Serializable{/** * */private static final long serialVersionUID = -7700027765680530207L;private String namespace;private Map<String,ActionWrapper> actionMap=new HashMap<String,ActionWrapper>();
}
//action節點類,同時也要有result類的節點集合,
<pre name="code" class="java">(get,set省略)



public class ActionWrapper implements Serializable{
    /**
     *
     */
    private static final long serialVersionUID = -4176005261524671229L;
    private String className;
    private String methodName;
    private Map<String,ResultWrapper> resultMap=new HashMap<String,ResultWrapper>();
}
package com.yc.frame.wrapper;

//result節點的節點類

public class ResultWrapper implements Serializable {

    private String type;
    private String value;
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
     那麼,自然要先將他們解析存好,再進行操作,所以,在filter的init方法裡進行初始化存好。這裡用的是dom4j對他解析:(解析就省略了,有需要的請留言給源碼哦!)

    最核心的環節就是將資料讀取出來後取出action的實體類,利用反射找到對應的方法,執行action的方法得到返回值,最後判斷result的type,執行跳轉頁面,是不是清晰了一點?

   

//1.解析請求HttpServletRequest request=(HttpServletRequest)arg0;HttpServletResponse response=(HttpServletResponse)arg1;String servletPath=request.getServletPath();//這個是請求的資源路徑名//判斷請求的路徑名是否actionif(servletPath.lastIndexOf(".action")==-1){arg2.doFilter(request, response);}else{try {//地址格式為:cccc/user.action     /user.actionint lastSlashIndex = servletPath.lastIndexOf("/");String requestActionName = servletPath.substring(lastSlashIndex + 1);String nameSpaceName = servletPath.substring(0,lastSlashIndex);//這個是總項目後面那個檔案夾地址//2.到map中找到這個actionPackageWrapper packageWrapper = null;//TODO://這裡為什麼要用這個entry?for (Map.Entry<String, PackageWrapper> entry : packagesMap.entrySet()) {PackageWrapper pw = entry.getValue();pw.getNamespace().equals(nameSpaceName);packageWrapper = pw;break;}//3.反射產生action的對象//4.啟用這個action的execute方法//5.得到這個execute返回的StringActionWrapper actionWrapper = packageWrapper.getActionMap().get(requestActionName);String actionClassName = actionWrapper.getClassName();Class c = Class.forName(actionClassName);Object obj1=c.newInstance();//TODO://這裡通過packageWrapper獲得攔截器的集合List<Interceptor> interceptors=new ArrayList<Interceptor>();List<InterceptorWrapper> iw=packageWrapper.getInterceptorList();if(iw.size()>0){for(int i=0;i<iw.size();i++){InterceptorWrapper interceptorWrapper=iw.get(i);String inname=interceptorWrapper.getName();String inclassName=interceptorWrapper.getClassName();if(inclassName.toLowerCase().endsWith(inname.toLowerCase()+"interceptor")){Class interceptor = Class.forName(inclassName);Object obj=interceptor.newInstance();interceptors.add(((Interceptor)obj));}}actionInvokation=new ActionInvokation(interceptors,((Action)obj1));}String result = invokeActionMethod(request,c, requestActionName,actionWrapper);//6.到map中找到這個String對應的result;ResultWrapper resultWrapper=actionWrapper.getResultMap().get(result);//7.轉寄到這個result上String dispatcherType=resultWrapper.getType();String page=resultWrapper.getValue();if(dispatcherType!=null&&!"".equals(dispatcherType)){if("direct".equals(dispatcherType)){String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";response.sendRedirect(basePath+page);}}else{request.getRequestDispatcher(page).forward(request, response);}} catch (Exception e) {e.printStackTrace();request.getSession().setAttribute("ycexeption", e.getMessage());}}}/** * 這個方法是對result中的方法進行啟用,通過傳過來的反射執行個體和action的名字以及拿到的method名字 * @param c * @param requestActionName * @param actionWrapper * @return * @throws SecurityException  * @throws NoSuchMethodException  */private String invokeActionMethod(HttpServletRequest request,Class c,String requestActionName,ActionWrapper actionWrapper) throws Exception{String requestResult="";Object obj=c.newInstance();//這裡完成注入參數的工作injectParameterToAction(request, obj, c);//如果methodname為空白,則執行action中的execute方法if(actionWrapper.getMethodName()==null||"".equals(actionWrapper.getMethodName())){requestResult=((Action)obj).execute();}else{ //否則執行action中的配置的方法String methodName=actionWrapper.getMethodName();Method m=c.getMethod(methodName, null);requestResult=(String) m.invoke(obj, null);}return requestResult;}//注入參數private void injectParameterToAction(HttpServletRequest request,Object obj,Class c) throws Exception, IllegalAccessException, IllegalArgumentException, InvocationTargetException{//基本類型的注入//1.從request中取出所有的健值對,轉成Map setName Map<String,String[]> map=parseRequest(request);//2.從c中找出各個要注入的方法 getMthod方法名Method [] ms=c.getMethods();//3.反向啟用方法,注入參數for(Method m:ms){String methodName=m.getName();if(map.containsKey(methodName)){String[] values=map.get(methodName);if(values.length==1){String s=values[0];String type=m.getParameterTypes()[0].getName();if (m.getParameterTypes()[0].getName().equals("java.lang.Integer")|| m.getParameterTypes()[0].getName().equals("int")) {// 啟用方法,傳進去值m.invoke(obj, Integer.parseInt(s));continue;} else if (m.getParameterTypes()[0].getName().equals("java.lang.Double")|| m.getParameterTypes()[0].getName().equals("double")) {m.invoke(obj, Double.parseDouble(s));continue;} else if (m.getParameterTypes()[0].getName().equals("java.lang.Float")|| m.getParameterTypes()[0].getName().equals("float")) {m.invoke(obj, Float.parseFloat(s));continue;} else if (m.getParameterTypes()[0].getName().equals("java.lang.String")|| m.getParameterTypes()[0].getName().equals("String")) {m.invoke(obj, s);continue;} }}}}private Map<String, String[]> parseRequest(HttpServletRequest request) {Map<String,String[]> map=new HashMap<String,String[]>();Enumeration<String> enu=request.getParameterNames();while(enu.hasMoreElements()){String name=enu.nextElement();String methodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);map.put(methodName, request.getParameterValues(name));}return map;}public void init(FilterConfig config) throws ServletException {//讀取設定檔   Struts.xml  =》Maprealpath=config.getServletContext().getRealPath("/");packagesMap=parseStrutsXml();}
解析xml檔案省略了,這是我自己實現的一個最簡單的struts,當然強大的struts我只是模仿了皮毛中的皮毛,歡迎來討論和相互學習。


  


著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.