001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.mvc; 018 019import java.util.Map; 020import java.util.concurrent.ConcurrentHashMap; 021import javax.servlet.http.HttpServletRequest; 022 023import org.springframework.util.StringUtils; 024import org.springframework.web.servlet.HandlerMapping; 025 026/** 027 * Simple {@code Controller} implementation that transforms the virtual 028 * path of a URL into a view name and returns that view. 029 * 030 * <p>Can optionally prepend a {@link #setPrefix prefix} and/or append a 031 * {@link #setSuffix suffix} to build the viewname from the URL filename. 032 * 033 * <p>Find some examples below: 034 * <ol> 035 * <li>{@code "/index" -> "index"}</li> 036 * <li>{@code "/index.html" -> "index"}</li> 037 * <li>{@code "/index.html"} + prefix {@code "pre_"} and suffix {@code "_suf" -> "pre_index_suf"}</li> 038 * <li>{@code "/products/view.html" -> "products/view"}</li> 039 * </ol> 040 * 041 * <p>Thanks to David Barri for suggesting prefix/suffix support! 042 * 043 * @author Alef Arendsen 044 * @author Juergen Hoeller 045 * @author Rob Harrop 046 * @see #setPrefix 047 * @see #setSuffix 048 */ 049public class UrlFilenameViewController extends AbstractUrlViewController { 050 051 private String prefix = ""; 052 053 private String suffix = ""; 054 055 /** Request URL path String --> view name String */ 056 private final Map<String, String> viewNameCache = new ConcurrentHashMap<String, String>(256); 057 058 059 /** 060 * Set the prefix to prepend to the request URL filename 061 * to build a view name. 062 */ 063 public void setPrefix(String prefix) { 064 this.prefix = (prefix != null ? prefix : ""); 065 } 066 067 /** 068 * Return the prefix to prepend to the request URL filename. 069 */ 070 protected String getPrefix() { 071 return this.prefix; 072 } 073 074 /** 075 * Set the suffix to append to the request URL filename 076 * to build a view name. 077 */ 078 public void setSuffix(String suffix) { 079 this.suffix = (suffix != null ? suffix : ""); 080 } 081 082 /** 083 * Return the suffix to append to the request URL filename. 084 */ 085 protected String getSuffix() { 086 return this.suffix; 087 } 088 089 090 /** 091 * Returns view name based on the URL filename, 092 * with prefix/suffix applied when appropriate. 093 * @see #extractViewNameFromUrlPath 094 * @see #setPrefix 095 * @see #setSuffix 096 */ 097 @Override 098 protected String getViewNameForRequest(HttpServletRequest request) { 099 String uri = extractOperableUrl(request); 100 return getViewNameForUrlPath(uri); 101 } 102 103 /** 104 * Extract a URL path from the given request, 105 * suitable for view name extraction. 106 * @param request current HTTP request 107 * @return the URL to use for view name extraction 108 */ 109 protected String extractOperableUrl(HttpServletRequest request) { 110 String urlPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); 111 if (!StringUtils.hasText(urlPath)) { 112 urlPath = getUrlPathHelper().getLookupPathForRequest(request); 113 } 114 return urlPath; 115 } 116 117 /** 118 * Returns view name based on the URL filename, 119 * with prefix/suffix applied when appropriate. 120 * @param uri the request URI; for example {@code "/index.html"} 121 * @return the extracted URI filename; for example {@code "index"} 122 * @see #extractViewNameFromUrlPath 123 * @see #postProcessViewName 124 */ 125 protected String getViewNameForUrlPath(String uri) { 126 String viewName = this.viewNameCache.get(uri); 127 if (viewName == null) { 128 viewName = extractViewNameFromUrlPath(uri); 129 viewName = postProcessViewName(viewName); 130 this.viewNameCache.put(uri, viewName); 131 } 132 return viewName; 133 } 134 135 /** 136 * Extract the URL filename from the given request URI. 137 * @param uri the request URI; for example {@code "/index.html"} 138 * @return the extracted URI filename; for example {@code "index"} 139 */ 140 protected String extractViewNameFromUrlPath(String uri) { 141 int start = (uri.charAt(0) == '/' ? 1 : 0); 142 int lastIndex = uri.lastIndexOf('.'); 143 int end = (lastIndex < 0 ? uri.length() : lastIndex); 144 return uri.substring(start, end); 145 } 146 147 /** 148 * Build the full view name based on the given view name 149 * as indicated by the URL path. 150 * <p>The default implementation simply applies prefix and suffix. 151 * This can be overridden, for example, to manipulate upper case 152 * / lower case, etc. 153 * @param viewName the original view name, as indicated by the URL path 154 * @return the full view name to use 155 * @see #getPrefix() 156 * @see #getSuffix() 157 */ 158 protected String postProcessViewName(String viewName) { 159 return getPrefix() + viewName + getSuffix(); 160 } 161 162}