hecache is always returning the same result - spring

I'm developing a web service system. I'm using Spring framework and hecache.
the problem is that when i do my first request to the URL I get the correct result but when I do a second request with another parameter it still returning the same result as the first request. When the cache expires it returns the correct result the first time.
This is my Spring Service method
#Cacheable(value="getUserInformation", key="#progid")
public Object getUserInformation(String login, String progid, HttpServletRequest request){
System.out.println( login.concat(progid) );
try {
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).
withCatalogName("siv_pck_general_functions").
withFunctionName("fn_get_user_information");
SqlParameterSource out = new MapSqlParameterSource().addValue("p_loginname", login).addValue("p_programid", progid);
map.put("Result", simpleJdbcCall.executeFunction(List.class, out) );
logger.info( LogUtils.getTypeMessage(request.getRemoteAddr(), request.getRequestURI(), LogUtils.INFO ));
} catch (Exception e) {
map.put("Result","Error");
}
return map;
}
This is my ecache configuration
<cache name="getUserInformation"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap" />
</cache>
This is my Web Service mapping
#RequestMapping( value="/getUserInformation/{loginName}/{programId}/{token}", method = RequestMethod.GET, produces="application/json;charset=UTF-8" )
public Object getUserInformation( #PathVariable String loginName, #PathVariable String programId, #PathVariable String token,HttpServletRequest request){
httpServletRequest = request;
String result = validateToken(token);
if ( "OK".equals(result) ){
map.put("Result", service.getUserInformation(loginName, programId, request) );
}else{
map.put("Result",result);
}
return map;
}

Related

Reuse existing token rather than requesting it on every request in spring boot + Retrofit app

I have a spring boot application that uses Retrofit to make requests to a secured server.
My endpoints:
public interface ServiceAPI {
#GET("/v1/isrcResource/{isrc}/summary")
Call<ResourceSummary> getResourceSummaryByIsrc(#Path("isrc") String isrc);
}
public interface TokenServiceAPI {
#FormUrlEncoded
#POST("/bbcb6b2f-8c7c-4e24-86e4-6c36fed00b78/oauth2/v2.0/token")
Call<Token> obtainToken(#Field("client_id") String clientId,
#Field("scope") String scope,
#Field("client_secret") String clientSecret,
#Field("grant_type") String grantType);
}
Configuration class:
#Bean
Retrofit tokenAPIFactory(#Value("${some.token.url}") String tokenUrl) {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(tokenUrl)
.addConverterFactory(JacksonConverterFactory.create());
return builder.build();
}
#Bean
Retrofit serviceAPIFactory(#Value("${some.service.url}") String serviceUrl, TokenServiceAPI tokenAPI) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new ServiceInterceptor(clientId, scope, clientSecret, grantType, apiKey, tokenAPI))
.build();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(repertoireUrl)
.client(okHttpClient)
.addConverterFactory(JacksonConverterFactory.create());
return builder.build();
}
Interceptor to add the Authorization header to every request
public class ServiceInterceptor implements Interceptor {
public ServiceInterceptor(String clientId,
String scope,
String clientSecret,
String grantType,
String apiKey,
TokenServiceAPI tokenAPI) {
this.clientId = clientId;
this.scope = scope;
this.clientSecret = clientSecret;
this.grantType = grantType;
this.apiKey = apiKey;
this.tokenAPI = tokenAPI;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader(AUTHORIZATION_HEADER, getToken())
.addHeader(API_KEY_HEADER, this.apiKey)
.build();
return chain.proceed(newRequest);
}
private String getToken() throws IOException {
retrofit2.Response<Token> tokenResponse = repertoireTokenAPI.obtainToken(clientId, scope, clientSecret, grantType).execute();
String accessToken = "Bearer " + tokenAPI.body().getAccessToken();
return accessToken;
}
}
This is working as expected, the problem is that the token is being requested for every request rather than using the existing valid one. How can one store the token somewhere and re-use it? I was wondering if Retrofit had a built-in solution.
a possible option with caching:
add caffeiene
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
add #Cacheable("your-token-cache-name") on the method returning the token, looks like getToken above
add max cache size and expiration configuration in application.yml
e.g. 500 entries and 10 minutes for configuration below
spring.cache.cache-names=your-token-cache-name
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
example from: https://www.javadevjournal.com/spring-boot/spring-boot-with-caffeine-cache/

#CacheEvict is not working in SpringBoot

#Cacheable(value = "apis", key = "#request")
public Object queryCenterAPI(QCRequest request,HttpHeaders headers) throws JSONException, ParseException {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new ToolsResponseHandler());
Response res=new Response();
HashMap<String,String> map=new HashMap<String,String>();
logger.info("No Caching^^^^^^^^^^");
Gson gson = new Gson();
String requestJson = gson.toJson(request);
HttpEntity<String> requestEntity = new HttpEntity<String>(requestJson, headers);
System.out.println("Request Body "+requestEntity);
Object response = null;
try {
response = restTemplate.postForObject(QCUtils.queryURL, requestEntity, Object.class);
logger.info("1st response>"+response);
response = response.toString().replaceAll("\\\\", "");
System.out.println("Final response "+response);
}catch (HttpClientErrorException httpEx) {
logger.info("Error:"+httpEx);
}
return response;
}
#CacheEvict(value = "apis", key = "#request")
public void resetOnRequest(QCRequest request) {
// Intentionally blank
System.out.println("Evict in Progrsss......");
}
Caching is working fine but I am unable to use #CacheEvict annotation.I guess cacheEvict method is called immediately after Cacheable method.
The resetOnRequest() method is not called after Cachable method(queryCenterAPI).
Cache evict method should be called from a different class otherwise it will not work, same for method with #Cacheable annotation.
Another different way instead the #CacheEvict annotation, would be using the CacheManager > https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/cache/CacheManager.html
For single value;
public void evictSingleCacheValue(String cacheName, String cacheKey) {
cacheManager.getCache(cacheName).evict(cacheKey);
}
For all values;
public void evictAllCacheValues(String cacheName) {
cacheManager.getCache(cacheName).clear();
}
Using ehcache works for me andAdding the below Xml file and Config file is enough to do caching and cache evict.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir" />
<cache name="apis"
eternal="false"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="200" timeToLiveSeconds="900"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
</cache>
public class AppConfig {
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
#Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
}
We only need to configure in xml file and give the time after which cache eviction take place.
I think you will need to switch to the "aspectj" mode in order for the #CacheEvict to work fine.
From Spring documentation:
The default advice mode for processing caching annotations is "proxy"
which allows for interception of calls through the proxy only; local
calls within the same class cannot get intercepted that way. For a
more advanced mode of interception, consider switching to "aspectj"
mode in combination with compile-time or load-time weaving.
Second option would be to try to move the #CacheEvict method into another class.

Multiple scenarios #RequestMapping produces JSON/XML together with Accept or ResponseEntity

I am working with Spring 4.0.7
About Spring MVC, for research purposes, I have the following:
#RequestMapping(value="/getjsonperson",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody Person getJSONPerson(){
logger.info("getJSONPerson - getjsonperson");
return PersonFactory.createPerson();
}
#RequestMapping(value="/getperson.json", method=RequestMethod.GET)
public #ResponseBody Person getPersonJSON(){
logger.info("getPerson - getpersonJSON");
return PersonFactory.createPerson();
}
Each one works fine, observe both for JSON, with and without extension:
/getjsonperson
/getperson.json
Same for XML
#RequestMapping(value="/getxmlperson",
method=RequestMethod.GET,
produces=MediaType.APPLICATION_XML_VALUE
)
public #ResponseBody Person getXMLPerson(){
logger.info("getXMLPerson - getxmlperson");
return PersonFactory.createPerson();
}
#RequestMapping(value="/getperson.xml", method=RequestMethod.GET)
#ResponseBody
public Person getPersonXML(){
logger.info("getPerson - getpersonXML");
return PersonFactory.createPerson();
}
Each one works fine, observe both for XML, with and without extension:
/getxmlperson
/getperson.xml
Now about Restful I have the following:
#RequestMapping(value="/person/{id}/",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Person> getPersonCustomizedRestrict(#PathVariable Integer id){
Person person = personMapRepository.findPerson(id);
return new ResponseEntity<>(person, HttpStatus.FOUND);//302
}
Observe the MediaType, it is mixed, for JSON and XML
Through RestTemplate I can indicate the Accept value
if(type.equals("JSON")){
logger.info("JSON");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
else if(type.equals("XML")){
logger.info("XML");
headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
}
….
ResponseEntity<Person> response =
restTemplate.exchange("http://localhost:8080/spring-utility/person/{id}/customizedrestrict",
HttpMethod.GET,
new HttpEntity<Person>(headers),
Person.class,
id
);
Until here, therefore I am able to use one URL/URI to get some data in either XML or JSON formats. It works fine
My problem is with Spring MVC … just consider
#RequestMapping(value="/{id}/person",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public #ResponseBody Person getPerson(#PathVariable Integer id){
return personMapRepository.findPerson(id);
}
I can call or activate that handler method (#RequestMapping) through:
jQuery working with Ajax, I am able to indicate the Accept value (JSON for example)
Poster, through the Headers button, I can set the Accept
Question One:
But for a common link? how I can set the Accept value? is possible?
I thought in other way to around this problem.
http://localhost:8080/spring-utility/person/getpersonformat?format=json
http://localhost:8080/spring-utility/person/getpersonformat?format=xml
Observe:
?format
Therefore
#RequestMapping(value="/getpersonformat",
method=RequestMethod.GET,
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
public #ResponseBody Person getPerson(#RequestParam String format){
return personMapRepository.findPerson(id);
}
Question Two:
What code for the method shown above must be added to customize the return type format?
I mean, JSON or XML, Is possible?
I thought in the following:
#RequestMapping(value="/getpersonformataltern",
method=RequestMethod.GET
produces={MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE}
)
public ResponseEntity<Person> getPersonFormat(#RequestParam String format){
logger.info("getPersonFormat - format: {}", format);
HttpHeaders httpHeaders = new HttpHeaders();
if(format.equals("json")){
logger.info("Ok JSON");
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
}
else{
logger.info("Ok XML");
httpHeaders.setContentType(MediaType.APPLICATION_XML);
}
return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
}
But:
If I execute the URL:
http://localhost:8080/spring-utility/person/getpersonformataltern?format=json
I get
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<id>1</id>
<firstName>Manuel</firstName>
<lastName>Jordan</lastName>
…
</person>
Yes in XML!
Note: I can confirm the Console prints Ok JSON
If I execute the URL:
http://localhost:8080/spring-utility/person/getpersonformataltern?format=xml
I get
This XML file does not appear to have any style information associated with it.
The document tree is shown below.
<person>
<id>1</id>
<firstName>Manuel</firstName>
<lastName>Jordan</lastName>
…
</person>
Question Three
What code for the method shown above must be added to fix the JSON output?
I don't know what is wrong or is missing..
There are three questions.
Thank You
Alpha
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Map<String,MediaType> mediaTypes = new LinkedHashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
mediaTypes.put("xml", MediaType.APPLICATION_XML);
configurer.mediaTypes(mediaTypes);
configurer.defaultContentType(MediaType.TEXT_HTML);
}
Using Accept header is really easy to get the format json or xml from the REST service.
This is my Controller, take a look produces section.
#RequestMapping(value = "properties", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
public UIProperty getProperties() {
return uiProperty;
}
In order to consume the REST service we can use the code below where header can be MediaType.APPLICATION_JSON_VALUE or MediaType.APPLICATION_XML_VALUE
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", header);
HttpEntity entity = new HttpEntity(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/properties", HttpMethod.GET, entity,String.class);
return response.getBody();
Edit 01:
In order to work with application/xml, add this dependency
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
All your problems are that you are mixing content type negotiation with parameter passing. They are things at different levels. More specific, for your question 2, you constructed the response header with the media type your want to return. The actual content negotiation is based on the accept media type in your request header, not response header. At the point the execution reaches the implementation of the method getPersonFormat, I am not sure whether the content negotiation has been done or not. Depends on the implementation. If not and you want to make the thing work, you can overwrite the request header accept type with what you want to return.
return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
I've preferred using the params filter for parameter-centric content-type.. I believe that should work in conjunction with the produces attribute.
#GetMapping(value="/person/{id}/",
params="format=json",
produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> getPerson(#PathVariable Integer id){
Person person = personMapRepository.findPerson(id);
return ResponseEntity.ok(person);
}
#GetMapping(value="/person/{id}/",
params="format=xml",
produces=MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Person> getPersonXML(#PathVariable Integer id){
return GetPerson(id); // delegate
}

400 Bad Request when uploading byte[] with Spring RestTemplate to SpringMVC rest endpoint

I am trying to upload a byte[] that contains an image to my Spring rest service (running in Spring Boot, btw) as a MultipartFile with my client running Spring RestTemplate and am getting HttpClientErrorException: 400 Bad Request.
My endpoint:
#RequestMapping(value="/scale/{percent}", method= RequestMethod.POST)
public ResponseEntity scaleImage(#PathVariable("percent") float percent,
#RequestParam("file") MultipartFile file) {
try {
if (!file.isEmpty()) {
byte [] result = transformService.scaleImage(percent, file.getBytes());
return getResponseEntityFromBytes(result);
} else {
return generateBadRequestError();
}
} catch (Exception e) {
if (e instanceof InvalidOperationParameterException) {
// TODO - populate message with bad parameters
LOGGER.log(Level.FINE, "Invalid Parameters: ");
return generateBadRequestError();
} else {
LOGGER.log(Level.SEVERE, "Exception caught: " + e.getMessage(), e);
return generateServerError(e.getMessage());
}
}
}
My Spring RestTemplate client:
public void scaleImage(byte[] image, float percent) throws Exception {
String url = "http://localhost:8080/scale/" + percent;
this.testNumberThreads=10;
this.testNumberThreads=10;
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<>();
mvm.add("file", image);
TransformedResponse r = doPost(url, mvm);
}
private TransformedResponse doPost(String url, MultiValueMap<String, Object> mvm) {
RestTemplate restTemplate = new RestTemplate();
TransformedResponse xr = null;
try {
xr = restTemplate.postForObject(url, mvm, TransformedResponse.class);
} catch (RestClientException e) {
e.printStackTrace();
}
return xr;
}
...
public class TransformedResponse {
byte[] image;
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}
Here is the exception I'm seeing in the client (nothing hitting server yet):
org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:546)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:330)
at com.me.image.xform.LoadTest.doPost(LoadTest.java:110)
at com.me.image.xform.LoadTest.loadTestScalePercent(LoadTest.java:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
Why won't this request post correctly?
I found my problem. I needed to add an AbstractResource (in this case a ByteArrayResource) to my MultiValueMap instead of the raw byte array. Here's the code that fixed it:
public void scaleImage(byte[] image, float percent) throws Exception {
String url = "http://localhost:8080/scale/" + percent;
final byte[] rawBytes = image.clone();
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<>();
ByteArrayResource bar = new ByteArrayResource(rawBytes) {
#Override
public String getFilename() {
return "Test-"+rawBytes.length + ".jpg";
}
};
mvm.add("file", bar);
TransformedResponse r = doPost(url, mvm);
}
First of all, when using Spring, make sure that you have proper MultiPartFile resolver defined in your servlet context:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="52428800"/>
<property name="maxInMemorySize" value="52428800"/>
</bean>
If you're using maven, this resolver is located in spring-web artifact:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${your.spring.version}</version>
</dependency>
Then, create form and make sure you're using proper enctype:
<form method="post" action="upload.form" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>
Finally, handle file upload in your controller
#RequestMapping(value="/path", method= RequestMethod.POST)
public StringscaleImage(#RequestParam("file") MultipartFile file) {
//....
}
Remember that asynch file upload is supported only with HTML5, with others you'd need to use some workarounds (like flash or iframes).
If you're still facing 400 Error, add to your logging service this logger (or similar, depending on logging framework):
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<param name="threshold" value="TRACE"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c] %m%n"/>
</layout>
</appender>
<logger name="org.springframework.web.method.HandlerMethod">
<level value="TRACE"/>
</logger>
<root>
<priority value="info"/>
<appender-ref ref="console"/>
</root>
It should output exception thrown during request handling
Instead of trying to pass the MultipartFile in as a request parameter, try the following:
#RequestMapping(value="/scale/{percent}", method= RequestMethod.POST)
public ResponseEntity scaleImage(#PathVariable("percent") float percent,
MultipartHttpServletRequest request) {
Iterator<String> fileNames = request.getFileNames();
MultipartFile uploadedFile = request.getFile(fileNames.next());
String fileName = uploadedFile.getName();
This is the only way I could actually get my multipart file to be accepted.
If you are still getting an empty file from this process, it must be something to do with how you are POST'ing the data.

How to avoid redirect loop in spring web mvc

public class ValidateSession extends HandlerInterceptorAdapter {
//before the actual handler will be executed
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
if(session.getAttribute("user")==null){
/*ModelAndView mav = new ModelAndView("/login/index");
throw new ModelAndViewDefiningException(mav);*/
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/login/index.mars");
throw new ModelAndViewDefiningException(mav);
}
return true;
}
}
In my case if session is expired then user can't access my application, but i am stuck with redirection loop. although i have tried many possible ways but not luck :(
Don't associate the ValidateSession handler with the login/index.mars request. Use mvc interceptor. Exclusions possible since 3.2, I think.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/yourpath/*"/>
<exclude-mapping path="/login/index.mars"/>
<bean class="org...ValidateSession " />
</mvc:interceptor>
</mvc:interceptors>
I know this is an old post but thought it may be of help since none of the above worked for me.
In the class implementing HandlerInterceptor:
response.sendRedirect("login?logout=true");
then in controller:
#RequestMapping(value = "login", method = RequestMethod.GET)
public String login(ModelMap modelmap, HttpServletRequest request, HttpSession httpSession, #RequestParam(required = false) String logout, #RequestParam(required = false) String reason, #RequestParam(required = false) String message) {
if (reason != null && MvcStatics.ERROR_MAP.get(reason) != null) {
ArrayList<String> errors = new ArrayList<>();
errors.add(MvcStatics.ERROR_MAP.get(reason));
modelmap.addAttribute("errors", errors);
}
if (logout != null && logout.equalsIgnoreCase("true")) {
httpSession.removeAttribute("loggedIn");
httpSession.removeAttribute("user");
httpSession.removeAttribute("token");
modelmap.addAttribute("message", "You have successfully been logged out.");
}}
i experienced the same issue. just remove the "redirect:" appended before "/login/index.mars"
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/login/index.mars");
//to this and you redirect ll works fine
mav.setViewName("/login/index.mars");
throw new ModelAndViewDefiningException(mav);

Resources