Servlet/PortletResponse supported as a resolvable dependency now (in particular for web controllers)

This feature required support for response exposure on Servlet/PortletRequestAttributes, instead of just in the Servlet/PortletWebRequest subclasses.

Issue: SPR-11795
This commit is contained in:
Juergen Hoeller
2014-05-16 18:06:29 +02:00
parent 5faacd5a3d
commit ea88bc2c81
11 changed files with 138 additions and 67 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.web.context.request;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.util.Assert;
@@ -48,6 +49,8 @@ public class ServletRequestAttributes extends AbstractRequestAttributes {
private final HttpServletRequest request;
private HttpServletResponse response;
private volatile HttpSession session;
private final Map<String, Object> sessionAttributesToUpdate = new ConcurrentHashMap<String, Object>(1);
@@ -62,6 +65,16 @@ public class ServletRequestAttributes extends AbstractRequestAttributes {
this.request = request;
}
/**
* Create a new ServletRequestAttributes instance for the given request.
* @param request current HTTP request
* @param response current HTTP response (for optional exposure)
*/
public ServletRequestAttributes(HttpServletRequest request, HttpServletResponse response) {
this(request);
this.response = response;
}
/**
* Exposes the native {@link HttpServletRequest} that we're wrapping.
@@ -70,6 +83,13 @@ public class ServletRequestAttributes extends AbstractRequestAttributes {
return this.request;
}
/**
* Exposes the native {@link HttpServletResponse} that we're wrapping (if any).
*/
public final HttpServletResponse getResponse() {
return this.response;
}
/**
* Exposes the {@link HttpSession} that we're wrapping.
* @param allowCreate whether to allow creation of a new session if none exists yet

View File

@@ -52,8 +52,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private static final String METHOD_HEAD = "HEAD";
private HttpServletResponse response;
private boolean notModified = false;
@@ -71,18 +69,10 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
* @param response current HTTP response (for automatic last-modified handling)
*/
public ServletWebRequest(HttpServletRequest request, HttpServletResponse response) {
this(request);
this.response = response;
super(request, response);
}
/**
* Exposes the native {@link HttpServletRequest} that we're wrapping (if any).
*/
public final HttpServletResponse getResponse() {
return this.response;
}
@Override
public Object getNativeRequest() {
return getRequest();
@@ -181,8 +171,9 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
@Override
@SuppressWarnings("deprecation")
public boolean checkNotModified(long lastModifiedTimestamp) {
HttpServletResponse response = getResponse();
if (lastModifiedTimestamp >= 0 && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
(response == null || !response.containsHeader(HEADER_LAST_MODIFIED))) {
long ifModifiedSince = -1;
try {
ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
@@ -202,12 +193,12 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
}
}
this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
if (this.response != null) {
if (response != null) {
if (this.notModified && supportsNotModifiedStatus()) {
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
this.response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
}
}
}
@@ -216,16 +207,17 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
@Override
public boolean checkNotModified(String etag) {
HttpServletResponse response = getResponse();
if (StringUtils.hasLength(etag) && !this.notModified &&
(this.response == null || !this.response.containsHeader(HEADER_ETAG))) {
(response == null || !response.containsHeader(HEADER_ETAG))) {
String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH);
this.notModified = etag.equals(ifNoneMatch);
if (this.response != null) {
if (response != null) {
if (this.notModified && supportsNotModifiedStatus()) {
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
else {
this.response.setHeader(HEADER_ETAG, etag);
response.setHeader(HEADER_ETAG, etag);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import javax.faces.context.FacesContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.ObjectFactory;
@@ -154,6 +155,7 @@ public abstract class WebApplicationContextUtils {
}
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
@@ -300,6 +302,29 @@ public abstract class WebApplicationContextUtils {
}
/**
* Factory that exposes the current response object on demand.
*/
@SuppressWarnings("serial")
private static class ResponseObjectFactory implements ObjectFactory<ServletResponse>, Serializable {
@Override
public ServletResponse getObject() {
ServletResponse response = currentRequestAttributes().getResponse();
if (response == null) {
throw new IllegalStateException("Current servlet response not available - " +
"consider using RequestContextFilter instead of RequestContextListener");
}
return response;
}
@Override
public String toString() {
return "Current HttpServletResponse";
}
}
/**
* Factory that exposes the current session object on demand.
*/
@@ -326,7 +351,8 @@ public abstract class WebApplicationContextUtils {
@Override
public WebRequest getObject() {
return new ServletWebRequest(currentRequestAttributes().getRequest());
ServletRequestAttributes requestAttr = currentRequestAttributes();
return new ServletWebRequest(requestAttr.getRequest(), requestAttr.getResponse());
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
package org.springframework.web.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -92,7 +91,7 @@ public class RequestContextFilter extends OncePerRequestFilter {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
initContextHolders(request, attributes);
try {