My system is Spring MVC based and I checked that Spring automatically sets PRAGMA: no-cache. The system is available to the users through SSL. When the users try to download something using the INTERNET EXPLORER 7 or 8 an error like "Internet Explorer cannot download file from server" appears (more details: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q316431&).
I tried to configure the WebContentInterceptor like the code bellow but does not work:
<mvc:interceptors>
<bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="2100" />
<property name="useExpiresHeader" value="false" />
<property name="useCacheControlHeader" value="false" />
<property name="useCacheControlNoStore" value="false" />
</bean>
</mvc:interceptors>
What can I do avoid Spring send the Pragma: no-cache and related to Cache Control?
Regards!
You can write your own custom interceptor and set the header values to the response object. Interceptors are nothing but filters so override the filter and use the
prehandle and posthandle to set the request and response headers respectively.
Let me know if you want specific examples doing that.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<beans:bean id="customInterceptor"
class="org.example.interceptors.CustomInterceptor">
</beans:bean>
</mvc:interceptor>
</mvc:interceptors>
public class CustomInterceptor implements HandlerInterceptor{
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView modelAndView) throws Exception {
response.setHeader(...);}
}
The simplest approach is probably just to stop the header from being written with a servlet filter. This way no Spring configuration has to be modified and you pick up the correct cache functionality for free.
public class PragmaFilter implements Filter {
private static String PRAGMA_HEADER = "Pragma";
#Override
public void init(FilterConfig filterConfig) throws ServletException { }
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, new NoPragmaHttpServletResponseWrapper(response));
}
#Override
public void destroy() { }
private final class NoPragmaHttpServletResponseWrapper extends HttpServletResponseWrapper {
private NoPragmaHttpServletResponseWrapper(ServletResponse response) {
super((HttpServletResponse) response);
}
#Override
public void addHeader(String name, String value) {
if (PRAGMA_HEADER.equals(name)) {
return;
}
super.addHeader(name, value);
}
#Override
public void setHeader(String name, String value) {
if (PRAGMA_HEADER.equals(name)) {
return;
}
super.setHeader(name, value);
}
}
}
Try to set cache seconds to an negative value.
If this does not help you will need to override:
protected final void preventCaching(HttpServletResponse response)
or
protected final void applyCacheSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate)
Both methods are implements in WebContentGenerator
<mvc:interceptors>
<bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="2100" />
<property name="useExpiresHeader" value="false" />
<property name="useCacheControlHeader" value="false" />
<property name="useCacheControlNoStore" value="false" />
<property name="cacheMappings">
<props>
<prop key="/**/**">-1</prop><!-- removes pragma no-cache -->
</props>
</property>
</bean>
</mvc:interceptors>
Related
I use Spring i18n library.
- ReloadableResourceBundleMessageSource
- SessionLocaleResolver
- LocaleChangeInterceptor
There are no errors.
If I use a strong refresh function in chrome, all interceptor methods are executed twice more.
And The Issue only occurs when the pages is used messages.properties.
preHandle ==> Controller ==> postHandle ==> AfterCompletion is executed, and all methods are executed twice more.
I've looked at the lifecycle of the interceptor, but I don't understand why the interceptor runs twice more without reason.
1. servlet-context.xml
<beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<beans:property name="basenames" value="/WEB-INF/messages/messages, /WEB-INF/messages/messages_ko_KR" />
</beans:bean>
<beans:bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<beans:property name="defaultLocale" value="ko_KR" />
</beans:bean>
<interceptors>
<beans:bean id="localeChangeInterceptor" class="com.test.util.locale.LocaleChangeInterceptor" />
</interceptors>
2. LocaleChangeInterceptor is implemented by me and is implemented as simple as the code below.
public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String language = request.getParameter("language");
System.out.println("1. preHandle(): " + language);
if(language != null) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(language));
}
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("2. postHandle()");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("3. afterCompletion()");
}
}
Console
1. preHandle(): null
main.jsp
2. postHandle()
3. afterCompletion()
1. preHandle(): null
2. postHandle()
3. afterCompletion()
1. preHandle(): null
2. postHandle()
3. afterCompletion()
I don't know whether it is a problem or a natural result of Interceptor's lifecycle.
Resolved.
It was resolved by first creating an Interceptor bean,
then by calling the registered bean by reference from the .
It seems to be an issue because I didn't know well about Spring interceptor registration. I need to find out more.
<beans:bean id="localeChangeInterceptor" class="com.test.util.locale.LocaleChangeInterceptor" />
<interceptors>
<interceptor>
<mapping path="/**" />
<exclude-mapping path="/resources/**" />
<beans:ref bean="localeChangeInterceptor" />
</interceptor>
</interceptors>
All. Attached herewith all the files. If I give the same name for both bean property name and reference, it returns the object. But it returns null, in case both are different. Please help. Thank you so much.
The AuthenticateAction.java file has got the detailed comments inside it.....
below are my files list:
WIRAdminBaseAction.java ---> my base action
AuthenticateAction.java ---> my java file that calls the bean here
applicationContext_MNC.xml
The below way of calling works...... This is not encouraged, as we
should not use applicationContext always
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletRequest().getSession().getServletConte xt());
ICacheDelegate cacheAction = (ICacheDelegate)applicationContext.getBean("BMOCacheDelegate");
The below way of calling does NOT work .... returns null value....
Please help... I assume that, since I have extended the
WIRAdminBaseAction, i should be able to call the getCacheDelegate
directly and it should return my cacheDelegate object ... Again,
Please note.....if I change my applicationContext_MNC.xml as below,
the below way of calling works fine. But, i don't want to change my
applicationContext_MNC.xml as below, due to some necessity.
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
<bean id="cacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
Is it that the name and bean should have the same value.... ??? No
Need to be.....Am i right ? Please advise.
getCacheDelegate().getActorAction(1); // this way of calling doesn't work and returns null value. please help.
MY CODE Follows below.
AuthenticateAction.java
package com.symcor.wiradmin.web.action;
import java.net.UnknownHostException;
import java.sql.SQLException;
import org.bouncycastle.crypto.CryptoException;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.web.context.support.WebApplica tionContextUtils;
import com.symcor.wiradmin.delegate.ICacheDelegate;
public class AuthenticateAction extends WIRAdminBaseAction {
private static final long serialVersionUID = 1L;
public String authenticate() throws UnknownHostException, CryptoException,
DataAccessException, SQLException{
/** This way of calling works...... This is not encouraged, as we should not use applicationContext always **/
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContex t(getServletRequest().getSession().getServletConte xt());
ICacheDelegate cacheAction = (ICacheDelegate) applicationContext.getBean("BMOCacheDelegate");
/** The below way of calling does NOT work .... returns null value.... Please help...
* I assume that, since I have extended the WIRAdminBaseAction, i should be able to call the getCacheDelegate directly
* and it should return my cacheDelegate object ...
* Again, Please note.....if I change my applicationContext_MNC.xml as below, the below way of calling works fine...
* but, i don't want to change my applicationContext_MNC.xml as below, due to some necessity.
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
<bean id="cacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
... is it that the name and bean should have the same value.... ??? No Need to be.....Am i right ? Please advise.
*
* **/
getCacheDelegate().getActorAction(1); // this way of calling doesn't work and returns null value. please help.
return "success";
}
}
WIRAdminBaseAction.java
package com.symcor.wiradmin.web.action;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.config.entities.Parameteri zable;
import com.symcor.wiradmin.delegate.ICacheDelegate;
public class WIRAdminBaseAction extends ActionSupport implements Preparable, ParameterAware, Parameterizable, SessionAware,RequestAware {
private HttpServletRequest request;
private static final long serialVersionUID = 1L;
private HttpServletResponse response;
private ICacheDelegate cacheDelegate;
private Map session;
private Map<String, String> params;
private Map parameters;
public void prepare() throws Exception {
}
public String execute() throws Exception {
return SUCCESS;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getServletRequest() {
return this.request;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public HttpServletResponse getServletResponse() {
return this.response;
}
public ICacheDelegate getCacheDelegate() {
return cacheDelegate;
}
public void setCacheDelegate(ICacheDelegate cacheDelegate) {
this.cacheDelegate = cacheDelegate;
}
public void addParam(final String key, final String value) {
this.params.put(key, value);
}
public Map getParams() {
return params;
}
public void setParams(final Map<String, String> params) {
this.params = params;
}
public Map getSession() {
return this.session;
}
public void setSession(final Map session) {
this.session = session;
}
public void setParameters(final Map param) {
this.parameters = param;
}
}
applicationContext_MNC.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- database configuration from property file -->
<bean id="BMOAdminDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" lazy-init="default" autowire="default" dependency-check="default">
<property name="driverClass" value="${jdbc.driver}" ></property>
<property name="jdbcUrl" value="${admin.jdbc.url}" ></property>
<property name="user" value="${admin.jdbc.user}" ></property>
<property name="password" value="${admin.jdbc.password}" ></property>
<property name="initialPoolSize" value="3" ></property>
<property name="minPoolSize" value="3" ></property>
<property name="maxPoolSize" value="25" ></property>
<property name="acquireIncrement" value="1" ></property>
<property name="acquireRetryDelay" value="1000" ></property>
<property name="debugUnreturnedConnectionStackTraces" value="true" ></property>
<property name="maxIdleTime" value="300" ></property>
<property name="unreturnedConnectionTimeout" value="300000" ></property>
<property name="preferredTestQuery" value="SELECT COUNT(*) FROM LOCALE_CODE" ></property>
<property name="checkoutTimeout" value="300000" ></property>
<property name="idleConnectionTestPeriod" value="600000" ></property>
</bean>
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="BMOCacheDelegate" />
</property>
</bean>
<bean id="BMOCacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
<bean id="BMOStatusDBDAO" class="com.symcor.wiradmin.dao.StatusDBDAO">
<property name="dataSource">
<ref bean="BMOAdminDataSource" />
</property>
</bean>
<!-- this bean is set to map the constants which needs to be configured as per
the environment to the java constants file -->
<bean id="envConstantsConfigbean" class="com.symcor.wiradmin.util.constants.Environm entConstantsSetter">
<property name="loginUrl" value="${login.url}"/>
<property name="logoutIR" value="${logout.from.image.retrieval}"/>
<property name="adminModuleUrl" value="${admin.url}"/>
<property name="adminUrlSym" value="${admin.url.sym}"/>
<property name="envProperty" value="${env.property}"/>
</bean>
</beans>
In the springmvc, when i send this url to spring interceptor, it does not work.
http://localhost/RRAdmin/cgr/cagri.jpg
But when use this url, interceptor works.
http://localhost/RRAdmin/cgr&cagri.jpg
You will see interceptor mapping below
<mvc:interceptor>
<mvc:mapping path="/**.jpg" />
<mvc:mapping path="/**.png" />
<bean class="com.RRAdmin.interceptor.ImageInterceptor" />
</mvc:interceptor>
And you'll see my prehandle method below
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String uri = request.getRequestURI();
File image = new File(uri);
if(image.exists()) sendFile(image, response.getOutputStream());
return false;
}
Thank you.
I think that you have to add a new mapping path like this:
<mvc:mapping path="/**/*.jpg" />
<mvc:mapping path="/**/**.png" />
Hope it helps.
I have Spring SimpleFormController which currently works for POST requests.
I want to change the form submission to GET. So I changed the html form method="post" to method="get".
After the change, I want processFormSubmission method to be invoked.
However its not.
Can you please tell what I am doing wrong here?
import org.springframework.web.servlet.mvc.SimpleFormController;
public class VehicleDescController extends SimpleFormController
{
protected ModelAndView processFormSubmission(
final HttpServletRequest request, final HttpServletResponse response,
final Object command, final BindException errors) throws Exception
{
....
}
}
<bean name="/vehicleDesc.html"
class="com.xxx.VehicleDescController">
<property name="commandName" value="lotSeller"/>
<property name="commandClass" value="com.xxx.LotSeller"/>
<property name="formView" value="xxxTheBasics"/>
<property name="viewName" value="xxxVehicleDesc"/>
<property name="imageUploadViewName" value="imageUpload"/>
<property name="vixErrorView" value="xxxVIXError"/>
<property name="assignmentEntryService" ref="xxxService"/>
<property name="referenceDataService" ref="referenceDataService"/>
<property name="xxxReferenceDataService" ref="xxxReferenceDataService"/>
<property name="messageSource" ref="messageSource"/>
<property name="xxxService" ref="xxxService"/>
<property name="validator" ref="xxxEntryValidator"/>
</bean>
A simple:
#Override
protected boolean isFormSubmission(HttpServletRequest request) {
return true;
}
Will tell it to always follow the submit workflow of the controller. Obviously if there are both "Submits" and also "normal" GETs that come into this URL, you will have to examine the request and figure out the difference!
How can I add my own logout handler to LogoutFilter in spring-security ?
Thanks!
The following solution works for me and may be helpful:
Extend the SimpleUrlLogoutSuccessHandler or implement the LogoutHandler:
public class LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
// Just for setting the default target URL
public LogoutSuccessHandler(String defaultTargetURL) {
this.setDefaultTargetUrl(defaultTargetURL);
}
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// do whatever you want
super.onLogoutSuccess(request, response, authentication);
}
}
Add to your Spring Security Configuration:
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler" />
<bean id="logoutSuccessHandler" class="your.package.name.LogoutSuccessHandler" >
<constructor-arg value="/putInYourDefaultTargetURLhere" />
</bean>
See the answer in this post in the Spring Security Forum:
XML Definition:
<beans:bean id="logoutFilter" class="org.springframework.security.ui.logout.LogoutFilter">
<custom-filter position="LOGOUT_FILTER"/>
<beans:constructor-arg index="0" value="/logout.jsp"/>
<beans:constructor-arg index="1">
<beans:list>
<beans:ref bean="securityContextLogoutHandler"/>
<beans:ref bean="myLogoutHandler"/>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="securityContextLogoutHandler" class="org.springframework.security.ui.logout.SecurityContextLogoutHandler"/>
<beans:bean id="myLogoutHandler" class="com.whatever.CustomLogoutHandler">
<beans:property name="userCache" ref="userCache"/>
</beans:bean>
LogoutHandler class:
public class CustomLogoutHandler implements LogoutHandler {
private UserCache userCache;
public void logout(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) {
// ....
}
#Required
public void setUserCache(final UserCache userCache) {
this.userCache = userCache;
}
}
You can use java-config solutions like this.
#Configuration
#EnableWebSecurity
public class SpringSecurity2Config extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//you can set other security config by call http.XXX()
http
.logout()
.addLogoutHandler(new CustomLogoutHandler())
.logoutUrl("/logout")
.logoutSuccessHandler(...)
.permitAll();
}
static class CustomLogoutHandler implements LogoutHandler {
#Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//...
}
}
}
You should use success-handler-ref attribute of <logout> element:
<security:logout invalidate-session="true"
success-handler-ref="myLogoutHandler"
logout-url="/logout" />
As alternative solution you can configure your own filter on the logout URL.