2011-01-04 4 views
3

Prenez cette requête HTTP Chaîne:paramètres de filtre de chaîne de requête (en utilisant goyave?)

foo=fooValue&bar=barValue&phleem=phleemValue 

Ou celui-ci:

bar=barValue&phleem=phleemValue&foo=someOtherFoo 

Quelle serait la meilleure façon de supprimer le paramètre foo?

Toutes les solutions Java sont les bienvenues, mais Guava préfère.

(Il n'y a pas ServletContext disponibles, les méthodes de Servlet ne va pas aider)

Mise à jour: La méthode doit gérer plusieurs paramètres à supprimer.

Répondre

3

Ce n'est pas la solution la plus élégante, mais fonctionne comme prévu:

private String removeParameter(String string, final String parameterName) { 
    List<String> list = newArrayList(string.split("&")); 

    Collection<String> filtered = Collections2.filter(list, new Predicate<String>() { 
     public boolean apply(String s) { 
      return !s.startsWith(parameterName + "="); 
     } 
    }); 

    return Joiner.on("&").join(filtered); 
} 

MISE À JOUR

Pour gérer plusieurs paramètres:

@Test 
public void removesMultipleParametersFromQuery() throws Exception { 
    String result = removeParameters("foo=fooValue&zee=lalal&bar=barValue&phleem=phleemValue", "foo", "bar"); 
    assertThat(result, is("zee=lalal&phleem=phleemValue")); 
} 

private String removeParameters(String query, final String...parameterNames) { 
    List<String> list = newArrayList(query.split("&")); 
    return Joiner.on("&").join(filter(list, startsWithAnyOf(parameterNames))); 
} 

private Predicate<String> startsWithAnyOf(final String[] parameterNames) { 
    return new Predicate<String>() { 
     public boolean apply(String s) { 
      return !Iterables.any(newArrayList(parameterNames), isPrefixOf(s)); 
     } 
    }; 
} 

private Predicate<String> isPrefixOf(final String string){ 
    return new Predicate<String>() { 
     public boolean apply(String candidate) { 
      return string.startsWith(candidate); 
     } 
    }; 
} 
1

Voici ma propre solution (mais c'est moche comme l'enfer):

public static String removeParameters(final String queryString, 
    final String... paramNames){ 
    Iterable<Predicate<CharSequence>> innerPredicates; 
    if(paramNames.length == 0){ 
     innerPredicates = Collections.emptySet(); 
    } else{ 
     innerPredicates = 
      Iterables.transform(
      Arrays.asList(paramNames), 
       new Function<String, Predicate<CharSequence>>(){ 

        @Override 
        public Predicate<CharSequence> apply(
         final String input){ 

         return Predicates.contains(
          Pattern.compile("^" 
          + Pattern.quote(input) + "=") 
         ); 
        } 
       }); 
    } 

    final Predicate<CharSequence> predicate = 
     Predicates.not(Predicates.or(innerPredicates)); 
    return Joiner.on("&").join(
     Iterables.filter(Splitter.on('&').split(queryString), predicate)); 
} 
1

Je voudrais avoir quelque chose à lire la chaîne de requête en tant que Multimap<String, String> à une extrémité et quelque chose à écrire un Multimap<String, String> en format de chaîne de requête sur l'autre. Ensuite, cela est aussi simple que d'appeler removeAll(parameter) pour chaque paramètre que vous souhaitez supprimer de la chaîne de requête. Ne pas traiter avec quelque chose comme ça String brut, sauf aux points où vous devez absolument.

est ici un code pour cela:

private static final Splitter QUERY_SPLITTER = Splitter.on(CharMatcher.anyOf("&;")); 
private static final Joiner QUERY_JOINER = Joiner.on('&'); 
private static final EntrySplitFunction ENTRY_SPLITTER = 
    new EntrySplitFunction(Splitter.on('=')); 
private static final EntryJoinFunction ENTRY_JOINER = 
    new EntryJoinFunction(Joiner.on('=').useForNull("")); 

public static Multimap<String, String> parseQueryString(String queryString) { 
    Multimap<String, String> result = HashMultimap.create(); 
    Iterable<String> entryStrings = QUERY_SPLITTER.split(queryString); 
    for (Map.Entry<String, String> entry : transform(entryStrings, ENTRY_SPLITTER)) { 
    result.put(entry.getKey(), entry.getValue()); 
    } 
    return result; 
} 

public static String toQueryString(Multimap<String, String> multimap) { 
    return QUERY_JOINER.join(transform(multimap.entries(), ENTRY_JOINER)); 
} 

private static class EntrySplitFunction 
    implements Function<String, Map.Entry<String, String>> { 
    private final Splitter keyValueSplitter; 

    private EntrySplitFunction(Splitter keyValueSplitter) { 
    this.keyValueSplitter = keyValueSplitter; 
    } 

    @Override public Map.Entry<String, String> apply(String input) { 
    Iterator<String> keyAndValue = keyValueSplitter.split(input).iterator(); 
    return Maps.immutableEntry(keyAndValue.next(), keyAndValue.next()); 
    } 
} 

private static class EntryJoinFunction 
    implements Function<Map.Entry<String, String>, String> { 
    private final Joiner keyValueJoiner; 

    private EntryJoinFunction(Joiner keyValueJoiner) { 
    this.keyValueJoiner = keyValueJoiner; 
    } 

    @Override public String apply(Map.Entry<String, String> input) { 
    return keyValueJoiner.join(input.getKey(), input.getValue()); 
    } 
} 

Avec cela, tout ce que vous auriez à faire pour mettre en œuvre votre méthode est la suivante:

public static String removeParameters(String queryString, String... parameters) { 
    Multimap<String, String> query = parseQueryString(queryString); 
    for (String parameter : parameters) { 
    query.removeAll(parameter); 
    } 
    return toQueryString(query); 
} 

Mieux encore, en supposant qu'il ya autre chose que vous faites avec la requête, vous auriez juste le Multimap déjà quand vous atteignez le point que vous avez besoin de faire cela et vous ne même pas la peine d'écrire une méthode spéciale pour cela.

+0

à propos de la dernière phrase: le cas d'utilisation est que la chaîne de requête doit être envoyée à un service externe qui a besoin apparemment quelques paramètres réservés supprimés. Je ne sais pas pourquoi, la question était pour un collègue. –

0

Vous pouvez utiliser Goyave

public static String toQueryString(final Map<String, Object> queryParameters) { 
     return "?" + Joiner.on('&').withKeyValueSeparator("=").join(queryParameters); 
    } 
+0

Le problème est: ceci échoue à la fois avec les paramètres dupliqués 'foo = bar1 & foo = bar2' et avec les paramètres vides' foo & bar' ou 'foo = & bar =', qui sont tous des constructions légales –

+0

Au lieu de cela, j'utiliserais probablement Spring ['' UriComponentsBuilder'] (http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html?is-external=true) –

+0

Les doublons fonctionneraient réellement si vous utilisez un 'Multimap ' et passez 'entries()' à la méthode 'join':' Joiner.on ("&"). withKeyValueSeperator ("="). join (params.entries()) " – whiskeysierra

Questions connexes