【问题标题】:Tiles 3 List attributes not working properlyTiles 3 List 属性无法正常工作
【发布时间】:2013-01-28 10:34:41
【问题描述】:

我的 spring MVC 项目和图块 3 遇到了几个问题,其中一个主要问题是列表属性。我要做的是使用OptionsRenderer 创建一个通用的tile 定义,就像the ultimate view article 一样(文章中有一个错误,因为 lit 属性是在定义之外定义的,这是错误的)。当我使用${options[myoptions]} 表达式创建一些属性时,我总是在我的模板JSP 中得到IllegalStateException,因为缺少名称为myoptions 的列表属性,即使我定义了这个列表属性。我的代码如下:

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>

模板.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. 在我的 JSP 中使用&lt;tiles:importAttribute name="folder"/&gt;。完全没有区别 2. 在我的 JSP 中使用&lt;tiles:insertAttribute name="folder"/&gt;。我遇到了一个异常,因为属性不是字符串。 3.在JSP中使用&lt;tiles:putListAttribute name="folder"&gt;FULL_DEFINITION_HERE&lt;/tiles:putListAttribute&gt;定义属性完全没有区别。

我已经参考了上面提到的文章,tiles documentation 特别是OptionsRenderer documentation 没有用。谁能告诉我我在这里做错了什么?我相信这与spring MVC无关。

【问题讨论】:

    标签: spring spring-mvc tiles


    【解决方案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>
    

    我的渲染器实现也应该能够替换选择模式的几次出现。 OptionsRender 似乎无法处理这种情况。

    这里是渲染器的实现。它必须像ultimate view article 中描述的那样集成到 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;
        }
    }
    

    【讨论】:

    • 您是否还有兴趣再次尝试 OptionsRenderer?如果您想在此处添加功能,请向我们提交补丁(通过 jira 问题)! issues.apache.org/jira/browse/TILES
    【解决方案2】:

    请从${options 中删除$

    【讨论】:

      猜你喜欢
      • 2015-04-09
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-13
      • 2013-09-07
      相关资源
      最近更新 更多