001/*
002 * Copyright 2002-2017 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.view;
018
019import javax.servlet.ServletContext;
020import javax.servlet.http.HttpServletRequest;
021
022import org.springframework.context.MessageSource;
023import org.springframework.lang.Nullable;
024import org.springframework.web.servlet.support.JstlUtils;
025import org.springframework.web.servlet.support.RequestContext;
026
027/**
028 * Specialization of {@link InternalResourceView} for JSTL pages,
029 * i.e. JSP pages that use the JSP Standard Tag Library.
030 *
031 * <p>Exposes JSTL-specific request attributes specifying locale
032 * and resource bundle for JSTL's formatting and message tags,
033 * using Spring's locale and {@link org.springframework.context.MessageSource}.
034 *
035 * <p>Typical usage with {@link InternalResourceViewResolver} would look as follows,
036 * from the perspective of the DispatcherServlet context definition:
037 *
038 * <pre class="code">
039 * &lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
040 *   &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
041 *   &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
042 *   &lt;property name="suffix" value=".jsp"/&gt;
043 * &lt;/bean&gt;
044 *
045 * &lt;bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"&gt;
046 *   &lt;property name="basename" value="messages"/&gt;
047 * &lt;/bean&gt;</pre>
048 *
049 * Every view name returned from a handler will be translated to a JSP
050 * resource (for example: "myView" -> "/WEB-INF/jsp/myView.jsp"), using
051 * this view class to enable explicit JSTL support.
052 *
053 * <p>The specified MessageSource loads messages from "messages.properties" etc
054 * files in the class path. This will automatically be exposed to views as
055 * JSTL localization context, which the JSTL fmt tags (message etc) will use.
056 * Consider using Spring's ReloadableResourceBundleMessageSource instead of
057 * the standard ResourceBundleMessageSource for more sophistication.
058 * Of course, any other Spring components can share the same MessageSource.
059 *
060 * <p>This is a separate class mainly to avoid JSTL dependencies in
061 * {@link InternalResourceView} itself. JSTL has not been part of standard
062 * J2EE up until J2EE 1.4, so we can't assume the JSTL API jar to be
063 * available on the class path.
064 *
065 * <p>Hint: Set the {@link #setExposeContextBeansAsAttributes} flag to "true"
066 * in order to make all Spring beans in the application context accessible
067 * within JSTL expressions (e.g. in a {@code c:out} value expression).
068 * This will also make all such beans accessible in plain {@code ${...}}
069 * expressions in a JSP 2.0 page.
070 *
071 * @author Juergen Hoeller
072 * @since 27.02.2003
073 * @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext
074 * @see InternalResourceViewResolver
075 * @see org.springframework.context.support.ResourceBundleMessageSource
076 * @see org.springframework.context.support.ReloadableResourceBundleMessageSource
077 */
078public class JstlView extends InternalResourceView {
079
080        @Nullable
081        private MessageSource messageSource;
082
083
084        /**
085         * Constructor for use as a bean.
086         * @see #setUrl
087         */
088        public JstlView() {
089        }
090
091        /**
092         * Create a new JstlView with the given URL.
093         * @param url the URL to forward to
094         */
095        public JstlView(String url) {
096                super(url);
097        }
098
099        /**
100         * Create a new JstlView with the given URL.
101         * @param url the URL to forward to
102         * @param messageSource the MessageSource to expose to JSTL tags
103         * (will be wrapped with a JSTL-aware MessageSource that is aware of JSTL's
104         * {@code javax.servlet.jsp.jstl.fmt.localizationContext} context-param)
105         * @see JstlUtils#getJstlAwareMessageSource
106         */
107        public JstlView(String url, MessageSource messageSource) {
108                this(url);
109                this.messageSource = messageSource;
110        }
111
112
113        /**
114         * Wraps the MessageSource with a JSTL-aware MessageSource that is aware
115         * of JSTL's {@code javax.servlet.jsp.jstl.fmt.localizationContext}
116         * context-param.
117         * @see JstlUtils#getJstlAwareMessageSource
118         */
119        @Override
120        protected void initServletContext(ServletContext servletContext) {
121                if (this.messageSource != null) {
122                        this.messageSource = JstlUtils.getJstlAwareMessageSource(servletContext, this.messageSource);
123                }
124                super.initServletContext(servletContext);
125        }
126
127        /**
128         * Exposes a JSTL LocalizationContext for Spring's locale and MessageSource.
129         * @see JstlUtils#exposeLocalizationContext
130         */
131        @Override
132        protected void exposeHelpers(HttpServletRequest request) throws Exception {
133                if (this.messageSource != null) {
134                        JstlUtils.exposeLocalizationContext(request, this.messageSource);
135                }
136                else {
137                        JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));
138                }
139        }
140
141}