<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks
    本文為原創,歡迎轉載,轉載請注明出處BlogJava

    chain:基本用途是構造成一條動作鏈。前一個Action將控制權轉交給后一個Action,而前一個Action的狀態在后一個Action里仍然保持著。
    我現在有一個場景,FirstAction 通過chain的方式,將控制權交給 SecondAction。FirstAction對應的頁面代碼為first.ftl,SecondAction對應的頁面代碼為second.ftl。
    假設我們的FirstAction如下定義:
    public class FirstAction extends ActionSupport{

        
    private String input1 = null;  // 由first.ftl頁面輸入值
        private String input2 = null;  // 由first.ftl頁面輸入值
        private CustomUser user = null;// 并不在first.ftl頁面上有相關元素綁定

        
    public String execute() throws Exception {
            
    //做一些事情,生成了CustomUser
            setCustomUser(ret);

            
    return "toSecond";
        }


        
    // getter setter
    }


    意思很明確了,通過first.ftl的輸入,到DB中或其他,生成了我們的CustomUser對象,這個CustomUser對象將要在SecondAction使用。
    于是我們想到了要配置FirstAction 的 name為toSecond的 Result type為 chain,將 生成的CustomUser對象傳遞到 SecondAction中,
    我們也這樣做了,但是 經過調試,發現在SecondAction中沒有得到 FirstAction中的CustomUser對象。
    SecondAction是這樣實現的:
    public class SecondAction extends ActionSupport{
        
    private CustomUser user = null;

        
    public String execute() throws Exception {
            
    // 利用user做事情或顯示在頁面上
        }


        
    // getter setter
    }


    看一下ChainingInterceptor.java的實現,發現有這樣的注釋:
    An interceptor that copies all the properties of every object in the value stack to the currently executing object.

    在 FirstAction 中CustomUser user 并沒有在 value stack 中,所以沒有拷貝到SecondAction中。

    知道了問題所在,就要解決。首先是想換一種方式去做,將我們要傳遞的參數通過 其他 Result type 如redirectAction去傳遞。
    例如:

    <result type="redirectAction" name="toSecond">
        
    <param name="actionName">SecondAction</param>
        
    <param name="method">execute</param>
        
    <param name="user">${user}</param>
    </result>

    但這樣做的缺點是,
    1.我們要在瀏覽器上看到很長很亂的URL(如果超過URL長度限制那就更悲劇了)。
    2.暴露這些參數總感覺很不爽。
    3.自定義的對象不能用這種方式傳遞,要么傳String、或JsonObject等。

    另外一個解決辦法:
    因為Result type為chain時,在執行SecondAction時,它的上一個Action,也就是FirstAction的實例并沒有被銷毀,FirstAction的實例被加入到了ValueStack中。
    所以,實現的思路就是,增加一個攔截器,在執行Actioin前判斷一下,當前Action是否需要從前面的Action實例中獲取數據。

    這個可以通過注解的方式告訴攔截器,當前的action需要什么樣的對象。

    思路明確了,來看看代碼:
    注解類:ChainTransParam.java

     
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ChainTransParam {
        String fieldName() 
    default "";
    }

    攔截器實現:ChainParameterInterceptor.java
    /**
     * Result type 為chain時 可通過注解的方式實現參數傳遞 此參數為前置Action的成員變量、并提供getter方法
     * 此參數并不要求一定要在值棧中
     * 
     * 
    @author liming
     
    */

    public class ChainParameterInterceptor extends AbstractInterceptor {

        
    private static final long serialVersionUID = -8279316685527646358L;

        @Override
        
    public String intercept(ActionInvocation invocation) throws Exception {
            ValueStack stack 
    = invocation.getStack();
            CompoundRoot root 
    = stack.getRoot();

            
    // 值棧不為null 且已經有前置Action
            
    // 棧最頂層(index = 0)為當前Action、緊接著(index = 1) 為前置Action
            if (root == null || root.size() <= 2{
                
    return invocation.invoke();
            }


            
    // 當前Action對象
            Object target = invocation.getAction();

            Field[] fields 
    = target.getClass().getDeclaredFields();

            
    // 遍歷此Action對象的屬性 是否有RecieveData注解
            for (Field field : fields) {
                
    if (field.isAnnotationPresent(ChainTransParam.class)) {
                    ChainTransParam rData 
    = field.getAnnotation(ChainTransParam.class);
                    
    // 取得源數據字段名
                    String fromName = rData.fieldName();
                    fromName 
    = StringUtils.isEmpty(fromName) ? field.getName() : fromName;

                    
    // 取得最近的前置Action
                    Object srcAction = root.get(1);

                    
    // 取得對應字段的值
                    Object value = ReflectionUtils.getFieldValue(srcAction, srcAction.getClass(), field.getName());
                    
    // 設定值
                    ReflectionUtils.setFieldValue(target, field.getName(), field.getType(), value);
                }

            }


            
    return invocation.invoke();
        }


        @SuppressWarnings(
    "unused")
        
    private Object findFieldValue(CompoundRoot root, Field field) {
            Object value 
    = null;

            
    int size = root.size();

            
    // 按順序遍歷前置Action
            for (int index = 1; index < size; index++{
                Object srcAction 
    = root.get(index);

                Object tmp 
    = ReflectionUtils.getFieldValue(srcAction, srcAction.getClass(), field.getName());
                
    // 取得對應字段的值 則返回
                
    // 問題:如果前置Action中該字段本身就為null 則無法處理
                if (tmp != null{
                    
    break;
                }

            }


            
    return value;
        }

    }


    在攔截器的實現中,我是只取得前一個Action中的數據,并沒有迭代尋找整個ValueStack的Action,也是可以這樣實現的,請看我的findFieldValue方法的實現,但這個方法在此攔截器中并沒有使用上。因為我不想這樣做。

    代碼完畢之后,配置好攔截器,

    我們只要在 SecondAction中 這樣定義即可:

    public class SecondAction extends ActionSupport{
        @ChainTransParam
        
    private CustomUser user = null;

        
    public String execute() throws Exception {
            
    // 利用user做事情或顯示在頁面上
        }


        
    // getter setter
    }

    當在執行SecondAction之前,攔截器會去查找FirstAction,是否有 user 對象,有則將值拷貝到 SecondAction 中。
    ChainTransParam 注解 允許輸入參數名,沒有輸入則默認根據變量名去查找。

    注:Struts2 Reference里的意思是不提倡使用Result Type Chain。


    另:ReflectionUtils.java 實現:
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    public abstract class ReflectionUtils {
        
    private static final Log logger = LogFactory.getLog(ReflectionUtils.class);

        
    public static void setFieldValue(Object target, String fname, Class<?> ftype, Object fvalue) {
            setFieldValue(target, target.getClass(), fname, ftype, fvalue);
        }


        
    public static void setFieldValue(Object target, Class<?> clazz, String fname, Class<?> ftype, Object fvalue) {
            
    if (target == null || fname == null || "".equals(fname)
                    
    || (fvalue != null && !ftype.isAssignableFrom(fvalue.getClass()))) {
                
    return;
            }


            
    try {
                Method method 
    = clazz.getDeclaredMethod(
                        
    "set" + Character.toUpperCase(fname.charAt(0)) + fname.substring(1), ftype);
                
    //if (!Modifier.isPublic(method.getModifiers())) {
                method.setAccessible(true);
                
    //}
                method.invoke(target, fvalue);

            }

            
    catch (Exception me) {
                
    if (logger.isDebugEnabled()) {
                    logger.debug(me);
                }


                
    try {
                    Field field 
    = clazz.getDeclaredField(fname);
                    
    //if (!Modifier.isPublic(field.getModifiers())) {
                    field.setAccessible(true);
                    
    //}
                    field.set(target, fvalue);
                }

                
    catch (Exception fe) {
                    
    if (logger.isDebugEnabled()) {
                        logger.debug(fe);
                    }

                }

            }

        }


        
    public static Object getFieldValue(Object target, String fname) {
            
    return getFieldValue(target, target.getClass(), fname);
        }


        
    public static Object getFieldValue(Object target, Class<?> clazz, String fname) {
            
    if (target == null || fname == null || "".equals(fname)) {
                
    return null;
            }


            
    boolean exCatched = false;
            
    try {
                String methodname 
    = "get" + StringUtils.capitalize(fname);
                Method method 
    = clazz.getDeclaredMethod(methodname);
                
    //if (!Modifier.isPublic(method.getModifiers())) {
                method.setAccessible(true);
                
    //}
                return method.invoke(target);
            }

            
    catch (NoSuchMethodException e) {
                exCatched 
    = true;
            }

            
    catch (InvocationTargetException e) {
                exCatched 
    = true;
            }

            
    catch (IllegalAccessException e) {
                exCatched 
    = true;
            }


            
    if (exCatched) {
                
    try {
                    Field field 
    = clazz.getDeclaredField(fname);
                    
    //if (!Modifier.isPublic(field.getModifiers())) {
                    field.setAccessible(true);
                    
    //}
                    return field.get(target);
                }

                
    catch (Exception fe) {
                    
    if (logger.isDebugEnabled()) {
                        logger.debug(fe);
                    }

                }

            }

            
    return null;
        }


    }
    posted on 2010-11-19 17:25 李 明 閱讀(5329) 評論(2)  編輯  收藏 所屬分類: Struts2

    評論

    # re: 基于Struts2 Result Type為chain 的Action之間數據傳遞 2010-11-21 19:32 濤濤
    很不錯,值得學習  回復  更多評論
      

    # re: 基于Struts2 Result Type為chain 的Action之間數據傳遞 2010-11-24 12:04 dfasssssssssssssssssssssssssssssssssssssssssssssss
    fadsfasd  回復  更多評論
      

    主站蜘蛛池模板: 国产99视频精品免费专区| 欧洲美女大片免费播放器视频| 美女在线视频观看影院免费天天看| 亚洲精品无码久久久| 一级中文字幕免费乱码专区| 亚洲日韩VA无码中文字幕| caoporn国产精品免费| 亚洲人成无码www久久久| 国产成人精品免费大全| 久久精品亚洲乱码伦伦中文| 中国一级特黄的片子免费 | 免费国产a国产片高清网站| 亚洲国产精品嫩草影院| 国产大片线上免费看| 午夜免费国产体验区免费的| 爱情岛论坛网亚洲品质自拍| 中文字幕无码免费久久| 亚洲福利一区二区| 在线观看无码的免费网站| 国产成人亚洲综合a∨| 亚洲一级特黄无码片| 久操免费在线观看| 亚洲国产超清无码专区| 日韩高清免费在线观看| 免费国产污网站在线观看不要卡| 亚洲熟妇av一区二区三区| 最近新韩国日本免费观看| 77777午夜亚洲| 国产乱辈通伦影片在线播放亚洲 | 亚洲一区二区三区不卡在线播放| 国语成本人片免费av无码| 无码AV动漫精品一区二区免费| 亚洲韩国—中文字幕| 免费爱爱的视频太爽了| 国产福利免费视频 | 亚洲人成电影网站免费| 国产亚洲男人的天堂在线观看| 亚洲av综合avav中文| 18禁无遮挡无码网站免费| 中文字幕版免费电影网站| 亚洲精品国产日韩|