1 /* 2 * Copyright 2002-2014 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.web.servlet.mvc.method.annotation; 18 19 import org.springframework.core.MethodParameter; 20 import org.springframework.util.PatternMatchUtils; 21 import org.springframework.web.context.request.NativeWebRequest; 22 import org.springframework.web.method.support.HandlerMethodReturnValueHandler; 23 import org.springframework.web.method.support.ModelAndViewContainer; 24 import org.springframework.web.servlet.RequestToViewNameTranslator; 25 26 /** 27 * Handles return values of types {@code void} and {@code String} interpreting 28 * them as view name reference. 29 * 30 * <p>A {@code null} return value, either due to a {@code void} return type or 31 * as the actual return value is left as-is allowing the configured 32 * {@link RequestToViewNameTranslator} to select a view name by convention. 33 * 34 * <p>A String return value can be interpreted in more than one ways depending 35 * on the presence of annotations like {@code @ModelAttribute} or 36 * {@code @ResponseBody}. Therefore this handler should be configured after 37 * the handlers that support these annotations. 38 * 39 * @author Rossen Stoyanchev 40 * @since 3.1 41 */ 42 public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler { 43 44 private String[] redirectPatterns; 45 46 47 /** 48 * Configure one more simple patterns (as described in 49 * {@link PatternMatchUtils#simpleMatch}) to use in order to recognize 50 * custom redirect prefixes in addition to "redirect:". 51 * <p>Note that simply configuring this property will not make a custom 52 * redirect prefix work. There must be a custom View that recognizes the 53 * prefix as well. 54 * @since 4.1 55 */ 56 public void setRedirectPatterns(String... redirectPatterns) { 57 this.redirectPatterns = redirectPatterns; 58 } 59 60 /** 61 * The configured redirect patterns, if any. 62 */ 63 public String[] getRedirectPatterns() { 64 return this.redirectPatterns; 65 } 66 67 68 @Override 69 public boolean supportsReturnType(MethodParameter returnType) { 70 Class<?> paramType = returnType.getParameterType(); 71 return (void.class.equals(paramType) || String.class.equals(paramType)); 72 } 73 74 @Override 75 public void handleReturnValue(Object returnValue, MethodParameter returnType, 76 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { 77 78 if (returnValue == null) { 79 return; 80 } 81 else if (returnValue instanceof String) { 82 String viewName = (String) returnValue; 83 mavContainer.setViewName(viewName); 84 if (isRedirectViewName(viewName)) { 85 mavContainer.setRedirectModelScenario(true); 86 } 87 } 88 else { 89 // should not happen 90 throw new UnsupportedOperationException("Unexpected return type: " + 91 returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); 92 } 93 } 94 95 /** 96 * Whether the given view name is a redirect view reference. 97 * The default implementation checks the configured redirect patterns and 98 * also if the view name starts with the "redirect:" prefix. 99 * @param viewName the view name to check, never {@code null} 100 * @return "true" if the given view name is recognized as a redirect view 101 * reference; "false" otherwise. 102 */ 103 protected boolean isRedirectViewName(String viewName) { 104 if (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)) { 105 return true; 106 } 107 return viewName.startsWith("redirect:"); 108 } 109 110 }