Is there a right way to build a URL?

2020-02-17 06:51发布

In much of the code I work with there is horrible stuff like:

String url = "../Somewhere/SomeServlet?method=AMethod&id="+object.getSomething()+ "&aParam="+object.getSomethingElse());

or - even worse:

String url = "Somewhere/Here/Something.jsp?path="+aFile.toString().replace("\\","/")+ "&aParam="+object.getSomethingElse());

Is there a right way to:

  1. Create a new URL (or is it a URI).
  2. Add correctly escaped parameters to it.
  3. Add well-formed file paths in those params.
  4. Resolve it to a String.

Essentially - it is too easy to just build the string than it is to do it properly. Is there a way to do it properly that is as easy as just building the string?

Added

For clarity - and after a little thought - I suppose I am looking for something like:

String s = new MyThing()
    .setPlace("Somewhere/Something.jsp")
    .addParameter(aName,aValue)
    .addParameter(aName,aFile)
    .toString();

so that it will deal with all of the unpleasantness of escaping and adding "?"/"&" and changing "\" to "/" instead of using "\" for files etc.

If I have to write one myself (i.e. if Apache is not an option) are there real Java techniques for correctly escaping the various parts. I mean things like escaping " " in parameters as "." while escaping " " in other places a "%20".

标签: java url uri
5条回答
ゆ 、 Hurt°
2楼-- · 2020-02-17 07:02

You can use Apache URIBuilder

Sample code: Full Apache Example

URIBuilder builder = new URIBuilder()
    .setScheme("http")
    .setHost("apache.org")
    .setPath("/shindig")
    .addParameter("hello world", "foo&bar")
    .setFragment("foo");
builder.toString();

Output: http://apache.org/shindig?hello+world=foo%26bar#foo

查看更多
戒情不戒烟
3楼-- · 2020-02-17 07:07

I have written this up, you can change it where you want extra functionality. It doesn't use any external resources, let me know if I have looked over something!

It's basically a wrapper for the URI class that allows you to more easily add subdirectories and parameters to the URI. You can set default values if you're not interested in some things.

Edit: I have added an option to use a relative URI (per your question).

public class Test {
    public static void main(String[] args) throws URISyntaxException,
            MalformedURLException {
        URLBuilder urlb = new URLBuilder("www.example.com");
        urlb.setConnectionType("http");
        urlb.addSubfolder("somesub");
        urlb.addSubfolder("anothersub");
        urlb.addParameter("param lol", "unknown");
        urlb.addParameter("paramY", "known");
        String url = urlb.getURL();
        System.out.println(url);


        urlb = new URLBuilder();
        urlb.addSubfolder("servlet");
        urlb.addSubfolder("jsp");
        urlb.addSubfolder("somesub");
        urlb.addSubfolder("anothersub");
        urlb.addParameter("param lol", "unknown");
        urlb.addParameter("paramY", "known");
        String relUrl = urlb.getRelativeURL();
        System.out.println(relUrl);
    }
}

class URLBuilder {
    private StringBuilder folders, params;
    private String connType, host;

    void setConnectionType(String conn) {
        connType = conn;
    }

    URLBuilder(){
        folders = new StringBuilder();
        params = new StringBuilder();
    }

    URLBuilder(String host) {
        this();
        this.host = host;
    }

    void addSubfolder(String folder) {
        folders.append("/");
        folders.append(folder);
    }

    void addParameter(String parameter, String value) {
        if(params.toString().length() > 0){params.append("&");}
        params.append(parameter);
        params.append("=");
        params.append(value);
    }

    String getURL() throws URISyntaxException, MalformedURLException {
        URI uri = new URI(connType, host, folders.toString(),
                params.toString(), null);
        return uri.toURL().toString();
    }

    String getRelativeURL() throws URISyntaxException, MalformedURLException{
        URI uri = new URI(null, null, folders.toString(), params.toString(), null);
        return uri.toString();
    }
}

Output:

Absolute

http://www.example.com/somesub/anothersub?param%20lol=unknown&paramY=known

Relative

/servlet/jsp/somesub/anothersub?param%20lol=unknown&paramY=known

查看更多
Ridiculous、
4楼-- · 2020-02-17 07:08

Recomendations

private final String BASE_URL = Properties.getProperty("base-url");

private Map propertiesMap; // = new HashMap<String,String>();

and in the code to build the URL.

public String buildURL(){
    StringBuilder builder = new StringBuilder();
    builder.append(BASE_URL);
    //for each property, append it

    return builder.toString();

}
查看更多
闹够了就滚
5楼-- · 2020-02-17 07:13

You can also use spring UriComponentsBuilder

UriComponentsBuilder
    .fromUriString(baseUrl)
    .queryParam("name", name)
    .queryParam("surname", surname)
    .build().toUriString();
查看更多
等我变得足够好
6楼-- · 2020-02-17 07:22

I like @Jeroen's suggestion but it didn't quite do all I wanted so, using his idea of gathering the parts together and then using a URI to grow the final result I put together this solution which seems to do what I want:

public class URLBuilder {
  // The scheme - http
  private String scheme = null;
  // The user - user
  private String user = null;
  // The host - example.com
  private String host = null;
  // The port - 8080
  private int port = -1;
  // The paths - /Path/To/Somewhere/index.jsp
  private final ArrayList<String> paths = new ArrayList<String>();
  // The parameters - ?a=b&c=d
  private final ArrayList<Pair<String, String>> queries = new ArrayList<Pair<String, String>>();
  // The fragment - #n
  private String fragment = null;

  public URLBuilder addQuery(String name, String value) {
    queries.add(new Pair(name, value));
    return this;
  }

  public URLBuilder addQuery(String name, long value) {
    addQuery(name, String.valueOf(value));
    return this;
  }

  public URLBuilder addQuery(String name, File file) {
    addQuery(name, file.toURI().getPath());
    return this;
  }

  public URLBuilder addPath(String path) {
    paths.add(path);
    return this;
  }

  @Override
  public String toString() {
    // Build the path.
    StringBuilder path = new StringBuilder();
    for (String p : paths) {
      path.append("/").append(p);
    }
    // Build the query.
    StringBuilder query = new StringBuilder();
    String sep = "";
    for (Pair<String, String> p : queries) {
      query.append(sep).append(p.p).append("=").append(p.q);
      sep = "&";
    }
    String url = null;
    try {
      URI uri = new URI(
              scheme,
              user,
              host,
              port,
              path.length() > 0 ? path.toString() : null,
              query.length() > 0 ? query.toString() : null,
              fragment);
      url = uri.toString();
    } catch (URISyntaxException ex) {
      Logger.getLogger(URLBuilder.class.getName()).log(Level.SEVERE, null, ex);
    }

    return url;
  }

  /**
   * @param host the host to set
   * @return this
   */
  public URLBuilder setHost(String host) {
    this.host = host;
    return this;
  }

  /**
   * @param scheme the scheme to set
   * @return this
   */
  public URLBuilder setScheme(String scheme) {
    this.scheme = scheme;
    return this;
  }

  /**
   * @param user the user to set
   * @return this
   */
  public URLBuilder setUser(String user) {
    this.user = user;
    return this;
  }

  /**
   * @param port the port to set
   * @return this
   */
  public URLBuilder setPort(int port) {
    this.port = port;
    return this;
  }

  /**
   * @param fragment the fragment to set
   * @return this
   */
  public URLBuilder setFragment(String fragment) {
    this.fragment = fragment;
    return this;
  }

  public static void main(String args[]) {
    try {
      URLBuilder url = new URLBuilder();
      System.out.println(url.toString());
      url.setFragment("fragment");
      System.out.println(url.toString());
      url.setHost("host.com");
      System.out.println(url.toString());
      url.addPath("APath");
      System.out.println(url.toString());
      url.addPath("AnotherPath");
      System.out.println(url.toString());
      url.addQuery("query1", "param1");
      System.out.println(url.toString());
      url.addQuery("query 2", "param 2");
      System.out.println(url.toString());
      url.addQuery("file", new File("Hello World.txt"));
      System.out.println(url.toString());
    } catch (Throwable t) {
      t.printStackTrace(System.err);
    }
  }

}
查看更多
登录 后发表回答