简体   繁体   English

如何将GWT Place URL从默认的“:”更改为“/”?

[英]How to change GWT Place URL from the default “:” to “/”?

By default, a GWT Place URL consists of the Place's simple class name (like "HelloPlace") followed by a colon (:) and the token returned by the PlaceTokenizer. 默认情况下,GWT Place URL包含Place的简单类名(如“HelloPlace”),后跟冒号(:)和PlaceTokenizer返回的标记。

My question is how can I change ":" to be "/"? 我的问题是如何将“:”改为“/”?

I just made my own PlaceHistoryMapper that directly implements the interface instead of using AbstractPlaceHistoryMapper: 我刚刚创建了自己的PlaceHistoryMapper,它直接实现了接口,而不是使用AbstractPlaceHistoryMapper:

public class AppPlaceHistoryMapper implements PlaceHistoryMapper
{
    String delimiter = "/";

    @Override
    public Place getPlace(String token)
    {

        String[] tokens = token.split(delimiter, 2); 

            if (tokens[0].equals("HelloPlace"))
                 ...
    }

    @Override
    public String getToken(Place place)
    {
        if (place instanceof HelloPlace)
        {
            return "HelloPlace" + delimiter + whatever;
        }
        else ...
    }
}

It's certainly extra code to write, but you can control your url structure all in one place, and use slashes instead of colons! 这肯定是额外的代码编写,但你可以在一个地方控制你的url结构,并使用斜杠而不是冒号!

Here is how to customize the delimiter , while using the standard GWT places. 以下是如何在使用标准GWT位置时自定义分隔符 (PlaceHistoryMapper) (PlaceHistoryMapper)

Nothing else needs to be changed; 没有别的东西需要改变; it works with the standard way of using Places and Tokenizers. 它适用于使用Places和Tokenizers的标准方法。

Insert into gwt.xml 插入gwt.xml

 <generate-with
  class="com.google.gwt.place.rebind.CustomPlaceHistoryMapperGenerator">
  <when-type-assignable class="com.google.gwt.place.shared.PlaceHistoryMapper" />
 </generate-with>

Add CustomAbstractPlaceHistoryMapper 添加CustomAbstractPlaceHistoryMapper

package com.siderakis.client.mvp;

import com.google.gwt.place.impl.AbstractPlaceHistoryMapper;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;

public abstract class CustomAbstractPlaceHistoryMapper extends AbstractPlaceHistoryMapper {
 public final static String DELIMITER = "/";

 public static class CustomPrefixAndToken extends PrefixAndToken {
  public CustomPrefixAndToken(String prefix, String token) {
   super(prefix, token);
   assert prefix != null && !prefix.contains(DELIMITER);
  }

  @Override
  public String toString() {
   return (prefix.length() == 0) ? token : prefix + DELIMITER + token;
  }

 }

 @Override
 public Place getPlace(String token) {
  int colonAt = token.indexOf(DELIMITER);
  String initial;
  String rest;
  if (colonAt >= 0) {
   initial = token.substring(0, colonAt);
   rest = token.substring(colonAt + 1);
  } else {
   initial = "";
   rest = token;
  }
  PlaceTokenizer tokenizer = getTokenizer(initial);
  if (tokenizer != null) {
   return tokenizer.getPlace(rest);
  }
  return null;
 }

}

Add CustomPlaceHistoryMapperGenerator 添加CustomPlaceHistoryMapperGenerator

/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.place.rebind;

import java.io.PrintWriter;

import com.siderakis.client.mvp.CustomAbstractPlaceHistoryMapper;
import com.siderakis.client.mvp.CustomAbstractPlaceHistoryMapper.CustomPrefixAndToken;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceTokenizer;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

/**
 * Generates implementations of
 * {@link com.google.gwt.place.shared.PlaceHistoryMapper PlaceHistoryMapper}.
 */
public class CustomPlaceHistoryMapperGenerator extends Generator {
  private PlaceHistoryGeneratorContext context;

  @Override
  public String generate(TreeLogger logger, GeneratorContext generatorContext,
      String interfaceName) throws UnableToCompleteException {

    context = PlaceHistoryGeneratorContext.create(logger,
        generatorContext.getTypeOracle(), interfaceName);

    if (context == null) {
      return null;
    }

    PrintWriter out = generatorContext.tryCreate(logger, context.packageName,
        context.implName);

    if (out != null) {
      generateOnce(generatorContext, context, out);
    }

    return context.packageName + "." + context.implName;
  }

  private void generateOnce(GeneratorContext generatorContext, PlaceHistoryGeneratorContext context,
      PrintWriter out) throws UnableToCompleteException {

    TreeLogger logger = context.logger.branch(TreeLogger.DEBUG, String.format(
        "Generating implementation of %s", context.interfaceType.getName()));
    ClassSourceFileComposerFactory f = new ClassSourceFileComposerFactory(
        context.packageName, context.implName);

    String superClassName = String.format("%s<%s>",
        CustomAbstractPlaceHistoryMapper.class.getSimpleName(),
        context.factoryType == null ? "Void" : context.factoryType.getName());
    f.setSuperclass(superClassName);
    f.addImplementedInterface(context.interfaceType.getName());

    f.addImport(CustomAbstractPlaceHistoryMapper.class.getName());
    f.addImport(context.interfaceType.getQualifiedSourceName());

    f.addImport(CustomAbstractPlaceHistoryMapper.class.getCanonicalName());
    if (context.factoryType != null) {
      f.addImport(context.factoryType.getQualifiedSourceName());
    }

    f.addImport(Place.class.getCanonicalName());
    f.addImport(PlaceTokenizer.class.getCanonicalName());
    f.addImport(CustomPrefixAndToken.class.getCanonicalName());

    f.addImport(GWT.class.getCanonicalName());

    SourceWriter sw = f.createSourceWriter(generatorContext, out);
    sw.println();

    writeGetPrefixAndToken(context, sw);
    sw.println();

    writeGetTokenizer(context, sw);
    sw.println();

    sw.outdent();
    sw.println("}");
    generatorContext.commit(logger, out);
  }

  private void writeGetPrefixAndToken(PlaceHistoryGeneratorContext context,
      SourceWriter sw) throws UnableToCompleteException {
    sw.println("protected CustomPrefixAndToken getPrefixAndToken(Place newPlace) {");
    sw.indent();
    for (JClassType placeType : context.getPlaceTypes()) {
      String placeTypeName = placeType.getQualifiedSourceName();
      String prefix = context.getPrefix(placeType);

      sw.println("if (newPlace instanceof " + placeTypeName + ") {");
      sw.indent();
      sw.println(placeTypeName + " place = (" + placeTypeName + ") newPlace;");

      JMethod getter = context.getTokenizerGetter(prefix);
      if (getter != null) {
        sw.println(String.format("return new CustomPrefixAndToken(\"%s\", "
            + "factory.%s().getToken(place));", escape(prefix),
            getter.getName()));
      } else {
        sw.println(String.format(
            "PlaceTokenizer<%s> t = GWT.create(%s.class);", placeTypeName,
            context.getTokenizerType(prefix).getQualifiedSourceName()));
        sw.println(String.format("return new CustomPrefixAndToken(\"%s\", "
            + "t.getToken((%s) place));", escape(prefix), placeTypeName));
      }

      sw.outdent();
      sw.println("}");
    }

    sw.println("return null;");
    sw.outdent();
    sw.println("}");
  }

  private void writeGetTokenizer(PlaceHistoryGeneratorContext context,
      SourceWriter sw) throws UnableToCompleteException {
    sw.println("protected PlaceTokenizer getTokenizer(String prefix) {");
    sw.indent();

    for (String prefix : context.getPrefixes()) {
      JMethod getter = context.getTokenizerGetter(prefix);

      sw.println("if (\"" + escape(prefix) + "\".equals(prefix)) {");
      sw.indent();

      if (getter != null) {
        sw.println("return factory." + getter.getName() + "();");
      } else {
        sw.println(String.format("return GWT.create(%s.class);",
            context.getTokenizerType(prefix).getQualifiedSourceName()));
      }

      sw.outdent();
      sw.println("}");
    }

    sw.println("return null;");
    sw.outdent();
    sw.println("}");
    sw.outdent();
  }

}

Good question. 好问题。 The problem is, that this is hard-coded into AbstractPlaceHistoryMapper : 问题是,这是硬编码到AbstractPlaceHistoryMapper

AbstractPlaceHistoryMapper.PrefixAndToken.toString(): AbstractPlaceHistoryMapper.PrefixAndToken.toString():

return (prefix.length() == 0) ? token : prefix + ":" + token;

AbstractPlaceHistoryMapper.getPlace(String token): AbstractPlaceHistoryMapper.getPlace(String token):

int colonAt = token.indexOf(':');
...

And AbstractPlaceHistoryMapper is hard-coded into PlaceHistoryMapperGenerator . AbstractPlaceHistoryMapper被硬编码到PlaceHistoryMapperGenerator

It would probably be possible to exchange the generator by supplying your own module xml file, and reconfiguring the binding, but overall, I would consider this as "basically not configurable". 可能可以通过提供自己的模块xml文件来交换生成器,并重新配置绑定,但总的来说,我认为这“基本上不可配置”。 (But see Riley's answer for a good alternative without declarative Tokenizer configuration!) (但是,如果没有声明性的Tokenizer配置,请参阅Riley的答案!)

)

I really appreciated the answers, thanks SO for making me optimize my time (I was following in debugger where my getToken() method was called, and it's getting through listeners, handlers, magicians and funny stuff like that :-) 我真的很感激答案,谢谢你让我优化我的时间(我在调试器中跟随我的getToken()方法被调用,并且它通过听众,处理程序,魔术师和有趣的东西得到:-)

So thinking of the HistoryMapper is perfect, but the solution if you want to add a crawler is a lot simpler since you just need to add an extra '!' 因此,想想HistoryMapper是完美的,但是如果你想添加一个爬虫的解决方案要简单得多,因为你只需要添加额外的'!' after the bookmark hash #! 书签哈希#后!

So it is enough to simply decorate the original result with an extra character. 所以只需用额外的字符来装饰原始结果就足够了。

public class PlaceHistoryMapperDecorator implements PlaceHistoryMapper {
private static final String CRAWLER_PREFIX = "!";
protected PlaceHistoryMapper delegateHistoryMapper;

public PlaceHistoryMapperDecorator(PlaceHistoryMapper delegateHistoryMapper) {
    this.delegateHistoryMapper = delegateHistoryMapper;
}

@Override
public Place getPlace(String token) {
    String cleanToken = token;
    if (token.startsWith(CRAWLER_PREFIX))
        cleanToken = token.substring(CRAWLER_PREFIX.length());
    else {
        if (token.length() > 0)
            System.err.println("there might be an error: can't find crawler prefix in " + token);
    }
    return delegateHistoryMapper.getPlace(cleanToken);
}

@Override
public String getToken(Place place) {
    return CRAWLER_PREFIX + delegateHistoryMapper.getToken(place);
}

} }

Then you pass that new instance to your PlaceHistoryHandler and that's it 然后将新实例传递给PlaceHistoryHandler,就是这样

        PlaceHistoryMapperDecorator historyMapperDecorator = new PlaceHistoryMapperDecorator((PlaceHistoryMapper) GWT.create(AppPlaceHistoryMapper.class));
    PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapperDecorator);

I tested it before posting this message, it works fine :-) 我在发布此消息之前对其进行了测试,它运行正常:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM