Quelle est la manière idiomatique de composer une URL ou un URI en Java?

115

Comment créer une URL ou un URI en Java? Y a-t-il un moyen idiomatique ou des bibliothèques qui le font facilement?

Je dois autoriser le démarrage à partir d'une chaîne de requête, analyser / modifier diverses parties d'URL (schéma, hôte, chemin, chaîne de requête) et prendre en charge l'ajout et le codage automatique des paramètres de requête.

jon077
la source
7
Faire voter la question longtemps après sa clôture, car il n'est pas clair s'il existe une solution populaire non obsolète à ce problème. J'ai trouvé cela en recherchant sur Google 'java URL parameter class'.
user1445967
4
Mon intention était de trouver un constructeur d'URL pour Java, et cette question m'est utile au moins.
whirlwin

Réponses:

76

À partir du composant HTTP Apache HttpClient 4.1.3, du tutoriel officiel :

public class HttpClientTest {
public static void main(String[] args) throws URISyntaxException {
    List<NameValuePair> qparams = new ArrayList<NameValuePair>();
    qparams.add(new BasicNameValuePair("q", "httpclient"));
    qparams.add(new BasicNameValuePair("btnG", "Google Search"));
    qparams.add(new BasicNameValuePair("aq", "f"));
    qparams.add(new BasicNameValuePair("oq", null));
    URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",
                                 URLEncodedUtils.format(qparams, "UTF-8"), null);
    HttpGet httpget = new HttpGet(uri);
    System.out.println(httpget.getURI());
    //http://www.google.com/search?q=httpclient&btnG=Google+Search&aq=f&oq=
}
}

Edit: à partir de la v4.2, il URIUtils.createURI()est obsolète au profit de URIBuilder:

URI uri = new URIBuilder()
        .setScheme("http")
        .setHost("www.google.com")
        .setPath("/search")
        .setParameter("q", "httpclient")
        .setParameter("btnG", "Google Search")
        .setParameter("aq", "f")
        .setParameter("oq", "")
        .build();
HttpGet httpget = new HttpGet(uri);
System.out.println(httpget.getURI());
Chikei
la source
20
Cela fonctionne, mais à partir de la v4.2, URIUtils.createURI () a été abandonné au profit de URIBuilder. Du côté positif, cet URIBuilder semble avoir une méthode addParameter () donc la construction de chaînes de requête devrait au moins être plus simple maintenant.
stian
6
URIBuilder builder = new URIBuilder() .setScheme("http") .setHost("www.google.com") .setParameters(qparams);comme @stian l'a dit
vanduc1102
Println ci-dessus imprime ce qui suit; google.com
...
61

En tant qu'auteur, je ne suis probablement pas la meilleure personne pour juger si mon constructeur d'URL / URI est bon , mais le voici néanmoins: https://github.com/mikaelhg/urlbuilder

Je voulais la solution complète la plus simple possible sans aucune dépendance en dehors du JDK, j'ai donc dû rouler la mienne.

Mikael Gueck
la source
6
Il a l'air super Mikael, avez-vous pensé à le publier sur maven central? Je sais que c'est petit mais cela facilite son utilisation. Je ne trouve d'ailleurs pas de classe similaire dans JAX-RS. Le manque de dépendances est définitivement un plus.
Barry Pitman
Cela a l'air bien, mais comme c'est un constructeur et donc mutable, pourquoi y a-t-il des paramètres uniquement pour les paramètres, mais pas pour l'hôte, le port, le protocole et le chemin? Et, eh bien, pas de getters pour ceux-là aussi. UPD: Oh, ce n'est pas mutable - setParameter crée un clone. Eh bien, setHost / setPort / ... pourrait toujours fonctionner de la même manière. Ou, peut-être, une version mutable serait bien d'avoir aussi.
mvmn
3
«Solution complète la plus simple possible sans dépendances» - On dirait que vous savez ce qui est important! Votre réponse devrait être acceptée à mon humble avis. Inclure tout HttpClient (avec toutes ses mises à jour de version et même la dépréciation de l'API même dont cette question concerne) juste pour créer une URL est ce qui rend les applications criblées de bogues les plus lourdes.
Stijn de Witt
2
Enfin sur Maven Central, et il ne m'a fallu que quatre ans pour le faire.
Mikael Gueck
@mikaelhg Merci! J'ai besoin exactement en ce moment!
Fabian Damken
29

L'utilisation de HTTPClient a bien fonctionné.

protected static String createUrl(List<NameValuePair> pairs) throws URIException{

  HttpMethod method = new GetMethod("http://example.org");
  method.setQueryString(pairs.toArray(new NameValuePair[]{}));

  return method.getURI().getEscapedURI();

}
jon077
la source
6
Cette fonctionnalité est désormais obsolète. Est-ce que quelqu'un sait comment utiliser le nouveau package de composants HTTP pour faire de même parce que cela me déroute.
Link19
3
La nouvelle version 4x ne le prend plus en charge.
Joscha
13

Il existe de nombreuses bibliothèques qui peuvent vous aider à construire des URI (ne réinventez pas la roue). En voici trois pour commencer:


Java EE 7

import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();

org.apache.httpcomponents: httpclient: 4.5.2

import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();

org.springframework: spring-web: 4.2.5.RELEASE

import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();

Voir aussi: GIST> Tests URI Builder

Nick Grealy
la source
2
EE 7 est la bonne réponse. Tout ce que vous avez à faire est d'extraire toute la suite de bibliothèques EE, de choisir une implémentation JAX-RS, de résoudre les conflits de version de jax-rs, et en récompense, vous aurez une classe UriBuilder pratique qui fonctionne très bien. Sarcasme mis à part, c'est la bonne réponse. :)
tekHedd
1
À partir du printemps 5, consultez UriBuilder( docs.spring.io/spring-framework/docs/current/javadoc-api/org/… ) et UriBuilderFactory( docs.spring.io/spring-framework/docs/current/javadoc-api/org /… )
Brice Roncace le
10

Utilisez OkHttp

Nous sommes en 2020 et il existe une bibliothèque très populaire appelée OkHttp qui a été étoilée 35K fois sur GitHub. Avec cette bibliothèque, vous pouvez créer une URL comme ci-dessous:

import okhttp3.HttpUrl;

URL url = new HttpUrl.Builder()
    .scheme("http")
    .host("example.com")
    .port(4567)
    .addPathSegment("foldername/1234")
    .addQueryParameter("abc", "xyz")
    .build().url();
Tyler Long
la source
J'ai corrigé une faute de frappe, c'est addPathSegment(pas addPathSegments).
PapaFreud
1

Après avoir été critiqué pour avoir suggéré la classe URL. Je vais suivre les conseils du commentateur et suggérer la classe URI à la place. Je vous suggère de regarder de près les constructeurs pour un URI car la classe est très immuable une fois créée.
Je pense que ce constructeur vous permet de définir tout ce dont vous pourriez avoir besoin dans l'URI.

URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)
          Constructs a hierarchical URI from the given components.
Mike Pone
la source
8
Mais il ne fournit pas de fonctionnalité pour réellement construire et encoder une chaîne de requête à partir d'un ensemble de paires de valeurs de nom.
Link19
4
Comme l'a dit l'enfant prodige à Alan Partridge - on ne peut pas avoir de dégradations d'immuabilité, c'est ou ce n'est pas ;-) youtube.com/watch?v=_lvFns5Lubc
Stewart
Le constructeur d'URI fait des choses désagréables sur le chemin. Voir blog.palominolabs.com/2013/10/03/… pour les détails.
mpierce
1
Laissez cette réponse servir d'exemple de la façon de NE PAS faire cela alors.
Mike Pone
1
Requête de chaîne ... Merci à Sun / Oracle pour la granularité. Nous allons simplement remplacer tous les espaces par des symboles plus, encoder en uri tous les paramètres et les lier tous ensemble avec des symboles esperluette nous-mêmes, puis ... frapper la tête sur la table à plusieurs reprises
Stijn de Witt