Announcement Announcement Module
Collapse
No announcement yet.
Spring Tiles Clean/Friendly URLS Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring Tiles Clean/Friendly URLS

    Hi,

    I am implementing clean URL's in my application. I do not think I am doing it correctly because I am explicitly stating the URL pattern for each page, i.e.:
    Code:
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/contact-us</url-pattern>
        </servlet-mapping>
        
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/terms-of-service</url-pattern>
        </servlet-mapping>
        
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/privacy</url-pattern>
        </servlet-mapping>
        
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/advertise</url-pattern>
        </servlet-mapping>
    
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/forgot</url-pattern>
        </servlet-mapping>
        
    <!-- 
    	<servlet-mapping>
            <servlet-name>dispatcher</servlet-name> -->
            <!-- <url-pattern>/*</url-pattern> 
                    <url-pattern>/</url-pattern>
         </servlet-mapping> -->
    Everything was going fine until I created a form. I have one url mapped as:
    Code:
        <servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
            <url-pattern>/sign-up</url-pattern>
        </servlet-mapping>
    Sign-up contains my sign-up form. But when I post the form, it goes to /sign-up/form
    Therefore, just "/sign-up" does not work for "sign-up/form", the post cannot makes its way to the request mapping /sign-up/form"

    What is the best way to implement clean URL's using the Spring Dispatcher servlet?
    Could I just use this in some way:
    Code:
    	<servlet-mapping>
            <servlet-name>dispatcher</servlet-name>
                    <url-pattern>/*</url-pattern> 
                    OR <url-pattern>/</url-pattern>
                    OR SOMETHING ELSE
         </servlet-mapping>
    Can I just implement dispatcher servlet just once as directly above somehow and not explicitly declare each URL sequence?

    Again the issue I ran into is the explicit mapping of /sign-up is not mapping to /sign-up/form.
    If I do something like /sign-up/** or /sign-up/ it then does not map to /sign-up

    Please advise

  • #2
    Here is the dispatcher servlet mapping that should be used.
    Code:
    <servlet>
    		<servlet-name>springmvc</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
      
    	<servlet-mapping>
    		<servlet-name>springmvc</servlet-name>
    		<url-pattern>*.htm</url-pattern>
    	</servlet-mapping>
    I use Annotations to define my Controllers use the @RequestMapping("/path") or since I'm using tiles i can just put the name of the view @RequestMapping("viewName") annotation to tell spring which path this controller will handle.
    See more about it here http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-servlet read 15.2 - 15.5
    Code:
    @Controller
    @RequestMapping("index")
    public class HomePageController {
    here is the view in tiles.xml
    Code:
    <definition name="index" extends="defaultTemplate">
            <put-attribute name="body" value="/jsp/home.jsp"/>
        </definition>

    Comment


    • #3
      tiles config messed up in web.xml which servlet mapping to use / or /*

      Hi people,

      I am really confused about how to map my dispatcher servlet when it is coming to using Tiles. My tiles config is broken right now. I would like to know what is the best way to set up my tiles configurations. Essentially what I am looking for is an easy way to add clean URL's without explicitly stating each URL pattern in web.xml Please refer to first post in this thread for additional info, any help would be greatly appreciated!!
      Code:
      	<servlet-mapping>
              <servlet-name>dispatcher</servlet-name> 
              <url-pattern>/*</url-pattern> OR
                      <url-pattern>/</url-pattern> 
           </servlet-mapping>
      In the '/' case, I can get my homepage to show up, but with no images and css! I used to map all my URLS explicitly when using this mapping, like : /sign-up or /contact-us and the web-pages used to show up correctly. I ran into issues when I had a URL called /sign-up/form. I thought it was kinda silly that I was explicitly naming each URL pattern.
      The reason why I am doing this is my Controllers are using annotations and they intercept the request.
      I would like to use clean URLs.

      With
      Code:
      	<servlet-mapping>
              <servlet-name>dispatcher</servlet-name> 
              <url-pattern>/*</url-pattern> 
                      <!-- <url-pattern>/</url-pattern> -->
           </servlet-mapping>
      the /* does not render the hompage anymore.
      This is the error I get:
      Code:
      No mapping found for HTTP request with URI [/PF-0.0.1-SNAPSHOT/WEB-INF/tiles/templates/defaultTemplateHomepage.jsp] in DispatcherServlet with name 'dispatcher'
      Obviously I can see that in the URL, the WEB-INF directory is in the URL, which is a private directory and can't be accessed directly.

      I also understand that I don't have to use a tilesViewResolver. It would also be hard in my case because my tiles are all in custom directories:
      tiles/templates/about
      tiles/templates/contactUs
      tiles/templates/forgot

      in other words its not all clumped into tiles/templates which might then use the prefix/suffix of tilesViewResolver.

      Comment


      • #4
        I think that you are very confused about how Tiles is supposed to work. Here is their tutorial. I'd suggest reading up on this before getting too far ahead of yourself. http://tiles.apache.org/2.1/framewor...ial/index.html

        I also understand that I don't have to use a tilesViewResolver. It would also be hard in my case because my tiles are all in custom directories:
        tiles/templates/about
        tiles/templates/contactUs
        tiles/templates/forgot
        The paths of your jsp(s) are irrelevant to the tile definition name. That is what the TilesViewResolver is for. It takes the tiles view name and finds the path to the jsp(s).

        Code:
        <definition name="crap" extends="defaultTemplate">
                <put-attribute name="body" value="/jsp/home.jsp"/>
            </definition>
        Then when you create your controllers using annotations. I showed you how to do that in my previous reply but here it is again.

        Code:
        @Controller
        @RequestMapping("crap")
        public class HomePageController {
        
        @RequestMapping(method=RequestMethod.GET)
        	protected ModelAndView getModelView(Model model, HttpServletRequest request) throws Exception {
        		
        		return new ModelAndView("crap", "model", model);
        	}
        }
        So if i went to http://localhost:8080/myapp/crap.htm the the TilesViewResolver is going to trim the first '/' and the '.htm' and what is left is the 'crap'. Then it references the tiles definitions for one named 'crap' that definition could be pointing to one or a hundred jsp files. each with their own path in the file system.
        i.e.)
        Code:
        <definition name="defaultTemplate" template="/jsp/template/template.jsp">
                <put-attribute name="header" value="/jsp/common/header.jsp" />
                <put-attribute name="footer" value="/jsp/common/footer.jsp" />
            </definition>
            
            <definition name="crap" extends="defaultTemplate">
                <put-attribute name="body" value="/jsp/sort/of/common/home.jsp"/>
                <put-attribute name="nav" value="/jsp/kind/of/common/navigation.jsp"/>
                <put-attribute name="whatever" value="/jsp/not/so/common/whatever.jsp"/>
            </definition>
        To use Tiles with Spring you do have to use the TilesViewResolver unless there is some hacked way to do it.

        Define your tiles beans as shown.
        Code:
        <!-- Tiles Config and View Resolver -->
        	<bean id="tilesConfigurer"
                  class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
                <property name="definitions">
                    <list>
                        <value>/WEB-INF/tiles-defs.xml</value>
                    </list>
                </property>
            </bean>
        
            <bean id="tilesViewResolver"
                  class="org.springframework.web.servlet.view.UrlBasedViewResolver">
                <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" />
            </bean>
        As for your images and css not showing up that has nothing to do with Tiles. That has to do with the paths that you are referencing them with in your jsp files. Unless you putting your images in tiles definitions as attributes?

        Try something like this.
        Code:
        <img src="${pageContext.request.contextPath}/images/someImage.png alt="logo" />
        The ${pageContext.request.contextPath} will get the application path up to the web root directory.

        Comment


        • #5
          in response - my tiles confi

          hey jonsinfinity, thanks for the reply.

          I would just like to re-iterate that my tiles and spring mvc app was all working fine but when I started to fiddle with the /sign-up servlet mapping....(cuz I couldnt get /sign-up to map to /sign-up/form - you actually have to explicitly state it as a new path i.e. /sign-up/form) I just started thinking about a better way to config all of this...

          I think I need to explain myself better.
          I actually do have a tilesViewResolver as so:
          Code:
          	<bean id="tilesViewResolver" 
          	    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
          	  <property name="viewClass" 
          	      value="org.springframework.web.servlet.view.tiles2.TilesView"/>
          
          		 
          	    <!-- <property name="prefix" value="/WEB-INF/tiles/templates/homepage/"/>
                  <property name="suffix" value=".jsp"/>
          	  	-->     
          	</bean>
          BUT I am not using the prefix/suffix part of it.

          Then I started thinking, my overall configuration may not have been scalable (it was growing to over 30 unique url patterns!) since I was explicitly defining my URL patterns in web.xml as so:

          Code:
              <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name>
                  <url-pattern>/categories</url-pattern>
              </servlet-mapping>
              
              <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name>
                  <url-pattern>/about</url-pattern>
              </servlet-mapping>
              
              <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name>
                  <url-pattern>/welcome</url-pattern>
              </servlet-mapping>
          I liked the idea of doing this because these URL's were mapped to my controllers using annotations as so:

          Code:
          @Controller
          public class HomePageController {
          
          @Autowired IProfileService profileService;
          private static final Log log = LogFactory.getLog(HomePageController.class);
          	
          	@RequestMapping("/welcome")
          It was my Controllers that would then map to a tiles definition as such


          Code:
          ModelAndView view= new ModelAndView("homepage");
          and then there is a homepage tiles definition:

          Code:
              <definition name="defaultTemplateHomepage" template="/WEB-INF/tiles/templates/defaultTemplateHomepage.jsp">  
          		<put-attribute name="title"  value="Helping each other learn" type="string"/>
          		<put-attribute name="header" value="/WEB-INF/tiles/templates/main/header.jsp" />  
          		<put-attribute name="body" value="/WEB-INF/tiles/templates/main/body.jsp" />
          		<put-attribute name="rightNav" value="/WEB-INF/tiles/templates/main/right_nav_3ads_twitter.jsp" />
          		<put-attribute name="bottomBody" value="/WEB-INF/tiles/templates/main/bottom_body_banner.jsp" />
                  <put-attribute name="footer" value="/WEB-INF/tiles/templates/main/footer.jsp" />  
              </definition>  
               
          	<!-- Home -->
              <definition name="homepage" extends="defaultTemplateHomepage">  
              	<put-attribute name="body" value="/WEB-INF/tiles/templates/homepage/homepage.jsp"/>  
              </definition>
          Sooo.....what I am saying is I like the fact that my controllers are mapped to the actual natural url's, not jsp pages. I initially did this by using explicit natural URL definitions and commenting out the default
          Code:
          <servlet-mapping>
             <!--     <servlet-name>dispatcher</servlet-name> -->
          <!--        <url-pattern>/*</url-pattern> -->
                <!--          </servlet-mapping>-->
          I made it work...and now that its kinda all confusing...I read some post somewhere to do this to get these URLs to work cuz I was getting some errors. I used the URL pattern '/' vs. '/*':
          Code:
          <servlet-mapping>
                <servlet-name>dispatcher</servlet-name> 
                 <url-pattern>/</url-pattern>
                    </servlet-mapping>
          BUT is there a way I can keep natural urls i.e. /welcome (not tiles definitions, like homepage) in the controllers but not have to explicitly define a natural URL for each URL pattern, i.e.:

          Code:
              <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name>
                  <url-pattern>/about</url-pattern>
              </servlet-mapping>
          and just use this mapping:
          Code:
          <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name> 
                         <url-pattern>/*</url-pattern> OR
                  </servlet-mapping>
          for /welcome, /welcom/form, /sign-up, /register etc???

          Hope this makes what I am asking more clear, please advise!!!

          Comment


          • #6
            OK, that make your question more clear. I don't think that's possible with Spring Tiles.

            I did find this though and thought that it looked promising for you. http://tuckey.org/urlrewrite/

            I saw it used in this demo app. http://blog.springsource.com/2009/06...source-slices/

            Comment


            • #7
              are clean URLs like REST urls for Tiles???

              Ok I still have not figured this out...all the stuff I have posted prior in this thread is still relevant.

              Now I have commented out all my explicit path names like /about and /contact-us in web.xml and just used /*
              as so:
              Code:
                  <servlet-mapping>
                      <servlet-name>dispatcher</servlet-name>
                      <url-pattern>/*</url-pattern>
                  </servlet-mapping>
              but now nothing is rendering! Let's use /about as an example. So I go to mywebsite.com/about and it actually hits the controller, great, returns the tiles definition for about which is "about". I get an error though:
              Code:
              No mapping found for HTTP request with URI [mywebsite.com/WEB-INF/tiles/templates/defaultTemplate.jsp] in DispatcherServlet with name 'dispatcher'
              I see what is happening, "about" in my tiles definition is mapped to:
              Code:
                  <!-- about -->
                  <definition name="about" extends="defaultTemplate">  
                  	<put-attribute name="body" value="/WEB-INF/tiles/templates/about/about.jsp"/>
                  </definition>
              where defaultTemplate is mapped to:
              Code:
              	<definition name="defaultTemplate" template="/WEB-INF/tiles/templates/defaultTemplate.jsp">  
              		<put-attribute name="title"  value="Helping each other learn" type="string"/>
              		<put-attribute name="header" value="/WEB-INF/tiles/templates/main/header.jsp" />  
              		<put-attribute name="body" value="/WEB-INF/tiles/templates/main/body.jsp" />
              		<put-attribute name="rightNav" value="/WEB-INF/tiles/templates/main/right_nav_3ads_twitter.jsp" />
              		<put-attribute name="bottomBody" value="/WEB-INF/tiles/templates/main/bottom_body_banner.jsp" />
                      <put-attribute name="footer" value="/WEB-INF/tiles/templates/main/footer.jsp" />  
                  </definition>
              It is trying to access the url : /WEB-INF/tiles/templates/defaultTemplate.jsp which it cannot directly.
              How can I get around this?
              I still would like to use real URL's! Like mywebsite.com/about or mywebsite.com/sign-up etc.
              Please advise.

              Comment


              • #8
                What application server are you using? It sounds like the /* mapping in web.xml is being applied when tiles tries to include the template jsp from within the WEB-INF folder. IMO this is probably an error, but the specification is not overly clear on this matter (WEB-INF normally can only be accessed via a RequestDispatcher not directly so it is a special case, but there is nothing that says you cannot have a servlet mapping to /WEB-INF AFAIK, and since /* is everything that could potentially include /WEB-INF).

                Using /* as a mapping always seems to cause numerous issues (e.g. loading of static resources such as css and images from within the web application becomes difficult). There are numerous solutions to this (try googling), and they tend to have various pros and cons. One possible solutions is URL rewriting using something like tuckey. In this case I would probably try something along the lines of:

                1) Add a servlet mapping /friendly/* to the dispatcher
                2) Write my application so friendly urls are /contextroot/friendly/about
                3) Add the tuckey filter with an inbound rule to rewrite any incoming url that doesn't have an extension to prepend /friendly (e.g. if the request is /contextroot/about then rewrite to /contextroot/friendly/about)
                4) Add an outbound rewrite rule that changes urls generated by your application to drop the /friendly (e.g. from /contextroot/friendly/about to /contextroot/about).

                HTH,

                Chris

                Comment


                • #9
                  I really don't think that this is possible using spring alone. I messed around with this for a while after my last post and ran into the same problems that you are having. I also mentioned the tuckey url rewrite project. It uses servlet filters to reformat the urls coming in and out of the application. See example here. http://urlrewritefilter.googlecode.c...de.html#urlabs. I actually think this looks pretty cool and might start using it. The cool thing about this is that you can develop your application without worrying about what your urls look like in tiles or spring and just worry about what the end user sees.

                  Comment


                  • #10
                    Using Tuckey

                    Ok so I tried using Tuckey and I have been at it for the last 5 hours!!

                    I can't figure it out....
                    I set dispatcher servlet to :
                    Code:
                        <servlet-mapping>
                            <servlet-name>dispatcher</servlet-name>
                            <url-pattern>/abc/*</url-pattern>
                        </servlet-mapping>
                    and then I set up the tuckey rule like this:
                    Code:
                        <rule>
                        <from>^/(.*)/(.*)$</from>
                        <!-- <to type="redirect">/$2/pf/$3</to>-->
                        <to type="redirect">%{context-path}/abc/$2</to>
                        </rule>
                    I got this url now: pf/about and so I want to convert it to pf/pf/about

                    which also means that I have to update my request mappings in my controllers as such:
                    Code:
                    @RequestMapping("/abc/welcome")
                    I have tried many different combinations of the tuckey pattern. Basically I would like to take the "about" part of pf/about and tack it onto pf/abc/about.

                    That is why I am trying to use wildcard pattern cuz in my local machine....the url is:
                    http://localhost:8080/pf/welcome (original link)

                    But again I think it is trying to just direct without hitting up dispatcher servlet.

                    How would the pattern look like??

                    Comment


                    • #11
                      There is a Spring sample that uses tuckey to do url writing in exactly this way. See https://src.springframework.org/svn/...ebapp/WEB-INF/

                      Comment


                      • #12
                        You guys rock!!

                        Originally posted by cmelgar View Post
                        There is a Spring sample that uses tuckey to do url writing in exactly this way. See https://src.springframework.org/svn/...ebapp/WEB-INF/
                        That link did it for me! Finally !!

                        I got it working....but it was tricky....I hope I don't run into problems later....so far so good...tuckey is very powerful...
                        thanks!!!

                        Comment

                        Working...
                        X