1

春の MVC プロジェクトとタイル 3 でいくつかの問題に直面しています。主な問題の 1 つはリスト属性に関するものです。私が作ろうとしているのは、究極のビューの記事のOptionsRendererように、を使用して一般的なタイル定義を作成することです(lit 属性が定義の外で定義されているため、記事に誤りがあります)。式を使用していくつかの属性を作成すると、このリスト属性を定義したにもかかわらず、その名前のリスト属性が見つからないため、テンプレート JSP で常に が取得されます。私のコードは次のとおりです。${options[myoptions]}IllegalStateExceptionmyoptions

tiles.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>

    <definition name="WILDCARD:*/*" template="/WEB-INF/view/template.jsp">
        <put-attribute name="meta" value="/WEB-INF/view/${options[folder]}/meta.jsp" />
        <put-attribute name="header" value="/WEB-INF/view/${options[folder]}/header.jsp" />
        <put-attribute name="body" value="/WEB-INF/view/${options[folder]}/{2}.jsp" />
        <put-attribute name="footer" value="/WEB-INF/view/${options[folder]}/footer.jsp" />

        <put-list-attribute name="folder">
            <add-list-attribute>
                <add-attribute value="{1}" />
                <add-attribute value="common" />
            </add-list-attribute>
        </put-list-attribute>
    </definition>
</tiles-definitions>

template.jsp

<%@ page language="java" pageEncoding="UTF-8"
    contentType="text/html; charset=utf-8" trimDirectiveWhitespaces="true"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<html>
<head>
<title>${dynamicTitle} - <fmt:message key="common.siteName" /></title>
<tiles:insertAttribute name="meta" />
</head>
<body>
    <div id="header">
        <tiles:insertAttribute name="header" />
    </div>
    <div id="body">
        <tiles:insertAttribute name="body" />
    </div>
    <div id="footer">
        <tiles:insertAttribute name="footer" />
    </div>
</body>
</html>

いくつかの解決策を試しましたが、結果はありませんでした。私の試行は次のとおりです。 1.<tiles:importAttribute name="folder"/>私の JSP で使用します。まったく違いはありません 2.<tiles:insertAttribute name="folder"/>私の JSP で使用します。属性が文字列ではないため、例外が発生しました。3.<tiles:putListAttribute name="folder">FULL_DEFINITION_HERE</tiles:putListAttribute>違いをまったく使用せずに JSP で属性を定義します。

上記の記事と、タイルのドキュメント、特にOptionsRenderer のドキュメントを参照しましたが、役に立ちません。ここで私が間違っていることを誰か教えてもらえますか? これはSpring MVCとは関係ないと思います。

4

2 に答える 2

1

また、OptionsRender を使用することもできませんでしたが、ディレクトリ階層でテンプレートを選択できるというアイデアが気に入りました。そこで、非常にうまく機能しているように見える独自のレンダラーを作成しました。有効なパスになる最初の選択肢を選択するパス構文「[CHOICE_1|CHOICE_2|...|CHOICE_n]」を実装しました。例は次のとおりです。

  <definition name="main/*/*" template="/WEB-INF/tiles/layout_main.jsp">
      <put-attribute name="top" value="/WEB-INF/tiles/[{1}/{2}|{1}|common]/top.jsp"/>
      <put-attribute name="content" value="/WEB-INF/tiles/[{1}/{2}|{1}|common]/content.jsp"/>
      <put-attribute name="footer" value="/WEB-INF/tiles/[{1}/{2}|{1}|common]/footer.jsp"/>
    </definition>

私の Renderer 実装は、choice パターンのいくつかの出現を置き換えることもできるはずです。OptionsRender はこのケースを処理していないようです。

これがRendererの実装です。最終的なビューの記事で説明されているように、Apache Tiles に統合する必要があります。おそらく、Apache Tiles の誰かが公式リリースに統合するでしょう。:-)

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tiles.request.Request;
import org.apache.tiles.request.render.Renderer;

public final class ChoiceRenderer implements Renderer {

    private static final Pattern CHOICE_PATTERN = Pattern.compile("\\[([^\\]]+)\\]");

    private final Renderer renderer;

    public ChoiceRenderer(Renderer renderer) {
        this.renderer = renderer;
    }

    @Override
    public boolean isRenderable(String path, Request request) {
        // only the overall format is checked, so no extra handling here
        return this.renderer.isRenderable(path, request);
    }

    @Override
    public void render(String path, Request request) throws IOException {
        Matcher matcher = CHOICE_PATTERN.matcher(path);
        List<String[]> groups = new ArrayList<String[]>();
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "{[" + groups.size() + "]}");
            groups.add(matcher.group(1).split("\\|"));
        }
        matcher.appendTail(sb);
        if (groups.isEmpty()) {
            this.renderer.render(path, request);
        } else {
            backtrackPaths(sb.toString(), request, groups, 0);
        }
    }

    private String backtrackPaths(String pathPattern, Request request, List<String[]> groups, int depth)
            throws IOException {
        String matchPath = null;
        String[] parts = groups.get(depth);
        for (int i = 0; i < parts.length; ++i) {
            String path = pathPattern.replace("{[" + depth + "]}", parts[i]);
            if (depth == groups.size() - 1) {
                if (isPathValid(path, request)) {
                    this.renderer.render(path, request);
                    matchPath = path;
                    break;
                }
            } else {
                matchPath = backtrackPaths(path, request, groups, depth + 1);
            }
        }
        return matchPath;
    }

    // TODO should we use caching here?
    private boolean isPathValid(String path, Request request) {
        boolean rtn = false;
        // apparently the corresponding Renderer method seems to check the
        // path's format only
        if (this.renderer.isRenderable(path, request)) {
            try {
                rtn = request.getApplicationContext().getResource(path) != null;
            } catch (IllegalArgumentException e) {
                // TODO the javadoc states that null will be returned, but
                // instead of it an exception is thrown.
                // Seems to be a bug?!
                boolean throwException = true;
                if (e.getCause() instanceof FileNotFoundException) {
                    FileNotFoundException fex = (FileNotFoundException) e.getCause();
                    throwException = fex.getMessage().indexOf(path) == -1;
                }
                if (throwException) {
                    // seems to be a different reason as our searched path
                    throw e;
                }
            }
        }
        return rtn;
    }
}
于 2013-05-16T08:29:34.257 に答える