Zdravím,
nejschůdnější mi připadá ta cesta s mapování "/*". Pak musíte využít
pravidel mapování - mapování přípon použít nemůžete, protože se aplikují až
po mapování prefixu, takže při použití /* na ně nikdy nedojde řada. Můžete
využít standardní mapování dle nejdelšího prefixu (např.
pro /protocol-servlet). Pro ostatní případy (např. JSP) byste pak musel
použít NamedDispatcher – nebudete tedy mapovat podle cesty, ale rozeberete
si URL a podle toho zjistíte, který servlet (podle jména) se má zavolat.

S pozdravem

Filip Jirsák


2011/4/19 Petr Novak <[email protected]>

>  Zdravím všechny,
>
> mám tu jeden takový problémek se servlet URL mapping a už ani googlík mi
> nepomáhá.
>
> Mám webovou aplikaci, používám Tomcat 7.x a Servlet 3.x, ale potencionálně
> se nechcina Tomcat vázat, takže bych uvítal spíše řešení využívající jen
> standardních konfigurací  JEE descriptorů, než zásahy do Tomcatích
> konfiguráků.
>
> Struktura aplikace je asi relativně standardní:
>
> /images
> /jsp
> /WEB-INF/web.xml
> ...
>
>
> Problém spočívá v nastavení URL mappingu,  potřebuji dosáhnout
> následujícího chování:
>
> http://server/mycontext      - na tuto adresu se spusti mnou nastavený
> servlet, musí to být konkrétně tato adresa a není možné ani žádné
> přesměrování přes klienta (on ignoruje veškeré 302 a jiné HTTP kódy). Prostě
> s klientem nic neudělám, má to zadrátované v sobě a není pod mou kontrolou.
> Navíc, jak ukazuje následující příklad, chování je takové, že pokud je
> request z Web-browseru, tak se jde na standardní GUI aplikace, jinak se jde
> na obsluhu příslušného protokolu, kterým komunikuje ten zadrátovaný klient.
>
> A ted co už jsem zkusil:
>
> Varianta 1)
>
> @WebServlet(urlPatterns = { "/*" })
> public class FrontController extends HttpServlet{
>  protected void service(HttpServletRequest req, HttpServletResponse resp){
>   if(fromBrowser()){
>      req.getRequestDispatcher("/jsp/my-page.jsp").forward(req,resp);
>   }else{
>    req.getRequestDispatcher("/protocol-servlet").forward(req,resp);
>   }
>  }
> }
>
> Na tento mapping "/*" mi to funguje skoro dokonale, bohužel jakýkoliv
> forward na straně serveru na JSP stránku způsobí zacyklení, protože tento
> pattern samozřejmě pokrývá i adresy   /mycontext/*.jsp
>
> Zkusil jsem i
>
> urlPatterns = { "/" }  //bez hvězdičky
>
> Ale pak Tomcat  při Requestu  na  http://server/mycontext  odpoví s
> response 302 aby klient udělal redisrect na http://server/mycontext/  -
> tedy přidá lomítko.   HTTP-302 však ten zadrátovaný klient, který jde jen na
> adresu server/mycontext  neumí provést. A jediné, co se dá v tom klientu
> konfigurovat je  host-name serveru, kam se pripojuje, tedy nemohu ovlivnit
> /path, ta je natvrdo.
>
>
> Varianta 2)
> Další varianta byla použít <welcome-file>  s mapováním na servlet:
>
> @WebServlet(urlPatterns = {* "/controller"* })
> public class FrontController extends HttpServlet{
>
> a ve web.xml
>
>   <welcome-file-list>
>     <welcome-file>*controller*</welcome-file>
>   </welcome-file-list>
>
>
> Toto funguje dokonale, až na jednu drobnost   - pokud vznesu request na
> http://localhost/mycontext   tak tomcat pošle nejdřív HTTP-302
> redirect,aby klient přešel na adresu http://localhost/mycontext/  tedy
> přidá to lomítko na konci. Lomítko by mi nevadilo, ale ten 302 redirect přes
> klienta je problém, protože to funguje jen v Browseru, ale ten zadrátovaný
> klient ho neprovede a vyhodí error protokolu.  Někde jsem četl, že snad je
> to takto podle servlet specifikace (že se to takto má chovat, pokud ten
> název souboru nemá příponu), ale specifikaci jsem ještě podrobně nečetl,
> jestli to tak musí být a nebo to je jen vychytávka Tomcatu.
>
> Varianta 3)
>
> Pak jsem ještě zkoušel pozměněnou varinatu 1), dočetl jsem se, že z pohledu
> URL mappingu by měl nejdřív server brát specifické patterny a až pak ty
> obecné a tak jsem narazil na doporučení do web.xml namapovat natvrdo JSP
> příponu, tím by se na ni měl spustit standardní procesing a nepouštět ten
> můj obecný FrontController servlet.
>
>   <servlet-mapping>
>     <servlet-name>jsp</servlet-name>
>     <url-pattern>*.jsp</url-pattern>
>   </servlet-mapping>
>
> Problém je, že JSP servlet nemám ve web.xml   definován a tak to nefunguje
> (tomcat odmítl nastartovat tuto webaplikaci).  konkrétní servlet tam ale
> nemohu dát, protože ten je na každém serveru asi jiný, takže dávat tam
> tomcatí JSP servlet natvrdo je asi nesmysl. Nebo jsem něco přehlédl a
> existuje ve standardní JSP specifikaci nějaký konkrétní servlet, který se
> tam dá dát a řeší kompilaci a spuštění JSP ?  Vím že bych tam mohl
> předkompilovat JSP a vyjmenovat tam všechny servlety vygenerované z JSP, ale
> to je trochu špatně udržovatelné řešení.
>
> Asi jsem tam měl nějaký překlep, protože teď, když to zkouším znovu, tak už
> to nekřičí, že jsp neexistuje, ale každopádně to nefunguje - zdá se, že
> *.jsp mu připadá mnohem obecnější než /* což nechápu, prostě se to JSP
> nespustí a cyklí to úplně stejně jako ve varinatě 1)-
>
> Napadlo mě ještě udělat
>
> <url-pattern>/jsp/*.jsp</url-pattern>
>
> že by to bylo přesnější a mohl by tak před /* preferovat to /jsp/*.jsp  ale
> toto není validní URL mapping podle specifikace - nelze kombinovat přípony s
> cestami.
>
>
> Varianta 4)
> Použít ServletFilter jako FrontController.
>
> @WebFilter(filterName = "FrontControllerFilter", urlPatterns = { "/*" })
> public class FrontControllerFilter implements Filter {
>   @Override
>   public void doFilter(ServletRequest request, ServletResponse response, 
> FilterChain chain) throws IOException, ServletException {
>     final HttpServletRequest req = (HttpServletRequest) request;
>     final HttpServletResponse resp = (HttpServletResponse) response;
>
>     if (req.getAttribute("forwarded") != null) {
>       chain.doFilter(req, resp);
>     }
>
>     RequestDispatcher disp = null;
>     if (!fromBrowser()) {
>       disp = req.getRequestDispatcher("/protocol-servlet");
>     } else { // from browser
>       disp = req.getRequestDispatcher("/jsp/my-page.jsp");
>     }
>     req.setAttribute("forwarded", true);
>     disp.forward(req, resp);
>   }
> }
>
> Problém je, že tento filter se nespustí, pokud nenadefinuji ještě nějaký
> defaultní servlet, takže nakonec jsem musel zadefinovat stejný servlet jako
> ve variantě 1)
>
> @WebServlet(urlPatterns = { "/*" })
> public class FrontController extends HttpServlet{
> ....
> }
>
>
> Pak se filter spustí, ale je k ničemu, protože ten servlet následně
> obsluhuje veškeré požadavky a tak jsem na stejném jako ve variantě 1), tedy
> nekonečný cyklus.
>
> Varianta 5)
> Dát před Tomcat třeba Apache HTTP server a udělat Alias na tu URL adresu,
> jak potřebuji.   Ale to je server navíc, už to komplikuje nasazení,
> preferoval jsem jednoduchý WAR, který dám kamkoliv a bude vyřešeno.
>
> Varianta 6)  rozdělit to na 2 samostatné web-moduly  - protokol bude řešen
> jinde než gui aplikace, ale to je zase komplikace z pohledu údržby (i když
> chápu, že v případě enterprise řešení je to lepší, aspoň se to může lépe
> škálovat, řešit jinak přechody na nové verze, apod.), ale v mém případě jde
> spíše o jednoduché řešení, primární je totiž ten protokol a to GUI je jen
> sada několika stránek pro administraci nastavení aplikace, takže oddělený
> modul je zbytečná komplikace.
>
> Tak zatím se zdá, že žádné jednoduché řešení není a tak se chci zeptat, zda
> jste někdo neřešil podobný problém nebo nemáte nějaký další nápad, co
> zkusit.
>
> Díky předem za další nápady
>
> Petr
>
>

Odpovedet emailem