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 > >
