A Day In The Life

とあるプログラマの備忘録

パンくずリスト -実装編-

パンくずリスト実装編です。
たとえば以下のような画面遷移をしたとします。
画面フロー
ちょうど矢印の部分がActionForwardになるので、このActionForwardをActionが呼ばれるたびに以下のようにスタックに保存していきます。
スタックイメージ
こんな感じ。
これを実装していくわけです。
まずはスタック。

public class ForwardStack {
    Stack forwardStack = new Stack();
    public ActionForward pop() {
        return (ActionForward)forwardStack.pop();
    }
    public void push(ActionForward item) {
        forwardStack.push(item);
    }
    public ActionForward peek() {
        return (ActionForward)forwardStack.peek();
    }
    public boolean empty() {
        return forwardStack.empty();
    }
    public int search(String path) {
        int index = forwardStack.size();
        for(Iterator i = forwardStack.iterator(); i.hasNext(); index--) {
            ActionForward forward = (ActionForward)i.next();
            if(path.equals(forward.getPath())) {
                return index;
            }
        }
        return -1;
    }
    public Iterator iterator() {
        return forwardStack.iterator();
    }	
    public int size() {
        return forwardStack.size();
    }
}

まぁただのStackクラスのラッパーのようなもんです。
次にアクション。

public abstract class BaseAction extends DispatchAction {
    public ActionForward dispatchMethod(
            ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response, String name)
            throws Exception {
        ActionForward result = super.dispatchMethod(mapping, form, request, response, name);
        ForwardStack forwardStack = 
                (ForwardStack)request.getSession().getAttribute("ForwardStack");
        if(forwardStack == null) {
            forwardStack = new ForwardStack();
        }
        //同じパスのForwardがいたら以降のForwardを削除してやる
        int index = forwardStack.search(forward.getPath());
        if(index == -1) {
            forwardStack.push(forward);
        } else {
            for(int i = 0; i < index - 1; i++) {
                forwardStack.pop();
            }
        }
        request.getSession().setAttribute("ForwardStack", forwardStack);
        return result;
    }
}

11行目から18行目のスタックからForwardをpopするところがミソです。

この処理で画面を戻ろうが飛ぼうが問題なく表示できるようにしています。



あとはカスタムタグでセッションからスタックを取得してやればOKです。

public class TopicPathTag extends TagSupport {
    public int doStartTag() throws JspException {
        ForwardStack stack = (ForwardStack)TagUtils.getInstance().lookup(
            pageContext, "ForwardStack", "session");
        StringBuffer buf = new StringBuffer();
        for(Iterator i = stack.iterator(); i.hasNext();) {
            ActionForward forward = (ActionForward)i.next();
            buf.append(forward.getName());
            buf.append(" > ");
        }
        buf.deleteCharAt(buf.lastIndexOf(">"));
        try {	
            JspWriter out = pageContext.getOut();
            out.print(buf);
        } catch (IOException e) {
            throw new JspException(e);
        }
        return SKIP_BODY;
    }
}

パンくずリストの表示にはforwardタグのname属性を使います。

他にはActionForwardを継承してパンくずリスト表示用属性を追加するって方法もあります。

しかしここではあえてname属性を使用しています。この方がstruts-configがすっきりするからです。
ちなみにこのパンくずリスト

画面フロー
とか
画面フロー
みたいな画面遷移をしても問題なく動きます。

関連記事