Webová aplikace: parametry na cestě - Ameriko už tě vidím

Obrázek uživatele benzin@jabber.cz
Vložil benzin@jabber.cz, Pá, 2007-05-11 08:34 :: | | |

Jistě jste již řeěili takovou drobnost, jako jak předat servletu jednoduchý parameter. Například číslo stránky v diskusi, nebo identifikátor editovaného záznamu. Nejspíš jste tento vyřešili pomocí parameterů předávaných metodou GET. Takže jít na další stránku v diskusi jste zapsali jako odkaz na diskuse.html?pa­ge=2. Jedná se o standardní (standardně tohle slovo nepoužívám, protože se mi standardně plete se standartou.) řešení.

Takže problém jste vyřeěili. Jenže co když pak odešleme formulář s příspěvkem? No protože již parameter page, nepředáváme, tak uživatel automaticky přejde z právě zobrazené stránky na stránku první. Někdy je toto chování vhodné, ale často by bylo lepší ho změnit. Jedna z možností je přidat do všech formulářů jako skrytý prvek všechny potřebné parametry, které se předávají metodou GET.

Právě ono druhé řešení jsem se snažil realizovat s pomocí Spring MVC. Nejedná se ale o elegantní řešení, už jen proto, že se po odeslání formuláře metodou POST, ztratí ona informace z URL adresy. Je sice předána, ale v URL adrese chybí, což se mi nejeví jako šťastné. Následně pak narazíte na problém s tím, že parametery předané metodou POST, které nejsou v rámci Commandu vám shodí controller. Takže je nutné z gruntu přepsat SimpleFormCon­troller (ne že bych to už neudělal, ale chtělo by to další zásah).

Našel jsem však lepší řešení (bacha, teď jsem objevil ameriku) co tak dát parametry přímo do cesty? Cesta se vždycky přenáší ve formulářích celá, navíc, pracujete-li s odkazy relativně, tak se přenášejí parametry i v odkazech. Skvělé pak je, že právě Spring nám umožňuje navázat controller i na adersu typu: /diskuse/**/proh­lizeni.htm, takže v případě, že uživatl bude požadovat adresu /diskuse/page­/2/prohlizeni­.htm zavolá se stejný controller, jako v případě že požadujeme jenom /diskuse/proh­lizeni.htm.

Takže jsem naprogramoval dvě metody. První je k získání mapy parametrů z cesty. Druhá je pak vhodná pro získání cesty k rootu aplikace. Třeba kvůli cestě ke stylům, obrázkům a tak.

/** Methode which read from context path parameter value. On example you
 * have parameter storage=idOfStorage normally you write it as parameter
 * /foo/page.html?storage=idOfStorage, but withi this you can write this
 * parameter to context path as /foo/storage/idOfStorage/page.html.
 * <p>This function give pair from end and first from pair set as name of
 * parameter and second set as value of parameter on example:
 * /foo/param1/value1/param2/valu2/param3/value3/page.html
 * will be read as three parameter param1 = value1, param2 = value2 etc.
 * But when you have on example this: /foo/foo/param1/value1/page.html
 * it is reade as two parameter: foo = foo, param1 = value1. And on end
 * if you have /foo/param1/value1/foo/page.html, then will be read as
 * two paramteres: foo = param1, value1 = foo, what is terible mistake.</p>
 * @param request HTTP request
 * @return map which binding parameter with value.
 */
public static Map<String, String> paramsFromPath(final HttpServletRequest
                                                 request) {
  Map<String, String> result = new LinkedHashMap<String, String>();
  String path = request.getServletPath();
  ArrayList<String> list = new ArrayList<String>();
  int j = 1;
  int in = path.indexOf("/", 1);
  while (in != -1) {
    list.add(path.substring(j, in));
    j = in + 1;
    in = path.indexOf("/", in + 1);
  }
  for (int i = list.size() - 1; i > 0; i -= 2) {
    result.put(list.get(i - 1), list.get(i));
  }
  return result;
}
/** Methode which return relative address path to root of application.
 * on example: When path is /foo/foo/page.htm this methode return ../../
 * It's good when you have templet with images, or css then will be good
 * set path with relative path
 * @param request request which give information about path
 * @return relative path to root
 */
public static String relativePathToRoot(final HttpServletRequest request) {
  StringBuffer result = new StringBuffer();
  String path = request.getServletPath();
  for (int i = 0; -1 != path.indexOf("/", i + 1);
       i = path.indexOf("/", i + 1)) {
    result.append("../");
  }
  return result.toString();
}

P.S.: Tahle metoda má i svá úskalí. Takto předávané parametry jsou totiž velmi odolné a jen tak se jich nezbavíte. Zatímco při předávání parametru běžným způsobem, bylo nutné specifikovat který odkaz tento parametr přenáší, tak tato metoda přenáší automaticky všechny, které se už do cesty dostaly. Jediný způsob jak se parametrů zbavit, je vrátit se zpět ke kořenu.