001/* 002 * Copyright 2002-2020 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.config.annotation; 018 019import java.util.ArrayList; 020import java.util.LinkedHashMap; 021import java.util.List; 022import java.util.Map; 023 024import org.springframework.context.ApplicationContext; 025import org.springframework.http.HttpStatus; 026import org.springframework.lang.Nullable; 027import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; 028 029/** 030 * Assists with the registration of simple automated controllers pre-configured 031 * with status code and/or a view. 032 * 033 * @author Rossen Stoyanchev 034 * @author Keith Donald 035 * @since 3.1 036 */ 037public class ViewControllerRegistry { 038 039 @Nullable 040 private ApplicationContext applicationContext; 041 042 private final List<ViewControllerRegistration> registrations = new ArrayList<>(4); 043 044 private final List<RedirectViewControllerRegistration> redirectRegistrations = new ArrayList<>(10); 045 046 private int order = 1; 047 048 049 /** 050 * Class constructor with {@link ApplicationContext}. 051 * @since 4.3.12 052 */ 053 public ViewControllerRegistry(@Nullable ApplicationContext applicationContext) { 054 this.applicationContext = applicationContext; 055 } 056 057 058 /** 059 * Map a view controller to the given URL path (or pattern) in order to render 060 * a response with a pre-configured status code and view. 061 * <p>Patterns like {@code "/admin/**"} or {@code "/articles/{articlename:\\w+}"} 062 * are allowed. See {@link org.springframework.util.AntPathMatcher} for more details on the 063 * syntax. 064 * <p><strong>Note:</strong> If an {@code @RequestMapping} method is mapped 065 * to a URL for any HTTP method then a view controller cannot handle the 066 * same URL. For this reason it is recommended to avoid splitting URL 067 * handling across an annotated controller and a view controller. 068 */ 069 public ViewControllerRegistration addViewController(String urlPath) { 070 ViewControllerRegistration registration = new ViewControllerRegistration(urlPath); 071 registration.setApplicationContext(this.applicationContext); 072 this.registrations.add(registration); 073 return registration; 074 } 075 076 /** 077 * Map a view controller to the given URL path (or pattern) in order to redirect 078 * to another URL. By default the redirect URL is expected to be relative to 079 * the current ServletContext, i.e. as relative to the web application root. 080 * @since 4.1 081 */ 082 public RedirectViewControllerRegistration addRedirectViewController(String urlPath, String redirectUrl) { 083 RedirectViewControllerRegistration registration = new RedirectViewControllerRegistration(urlPath, redirectUrl); 084 registration.setApplicationContext(this.applicationContext); 085 this.redirectRegistrations.add(registration); 086 return registration; 087 } 088 089 /** 090 * Map a simple controller to the given URL path (or pattern) in order to 091 * set the response status to the given code without rendering a body. 092 * @since 4.1 093 */ 094 public void addStatusController(String urlPath, HttpStatus statusCode) { 095 ViewControllerRegistration registration = new ViewControllerRegistration(urlPath); 096 registration.setApplicationContext(this.applicationContext); 097 registration.setStatusCode(statusCode); 098 registration.getViewController().setStatusOnly(true); 099 this.registrations.add(registration); 100 } 101 102 /** 103 * Specify the order to use for the {@code HandlerMapping} used to map view 104 * controllers relative to other handler mappings configured in Spring MVC. 105 * <p>By default this is set to 1, i.e. right after annotated controllers, 106 * which are ordered at 0. 107 */ 108 public void setOrder(int order) { 109 this.order = order; 110 } 111 112 113 /** 114 * Return the {@code HandlerMapping} that contains the registered view 115 * controller mappings, or {@code null} for no registrations. 116 * @since 4.3.12 117 */ 118 @Nullable 119 protected SimpleUrlHandlerMapping buildHandlerMapping() { 120 if (this.registrations.isEmpty() && this.redirectRegistrations.isEmpty()) { 121 return null; 122 } 123 124 Map<String, Object> urlMap = new LinkedHashMap<>(); 125 for (ViewControllerRegistration registration : this.registrations) { 126 urlMap.put(registration.getUrlPath(), registration.getViewController()); 127 } 128 for (RedirectViewControllerRegistration registration : this.redirectRegistrations) { 129 urlMap.put(registration.getUrlPath(), registration.getViewController()); 130 } 131 132 return new SimpleUrlHandlerMapping(urlMap, this.order); 133 } 134 135}