I'd like to use memcached to cache the response produced by my controllers. The controllers themselves are Grails controllers, but there's nothing really Grails-specific about the problem. If I could figure out how to solve this problem in a Spring MVC, Struts (or similar) application, I should easily be able to migrate the solution to Grails.
Ideally, I'd like to identify the controller methods that are eligible for caching using Java annotations. Is anyone aware of an existing solution for this problem? I should emphasise that I'm not interested in using any caching technology other than memcached.
Thanks,
Don
The Simple Spring Memcached library the previous poster linked to would actually accomplish what you need to do. It doesn't limit itself to just DAO methods. You could annotate a controller method to cache it's response just as easily as annotating a DAO method.
So, if you have a Controller named SimpleController and you wanted to cache the response of that controller, you could do the following
public class SimpleController implements Controller {
#ReadThroughSingleCache(namespace = "SimpleController", keyIndex = 0, expiration = 3600)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView("index")
}
This will cache the response of the controller in Memcached for an hour and any request that comes in that matches the same request will return the cached response.
Aaron, braveterry,
Thanks for suggesting my project: http://code.google.com/p/simple-spring-memcached/
Don, Aaron is correct that SSM is not limited to DAO methods, however there are a few caveats for his example:
I don't think HttpServletRequest's toString() method would produce a good key
You would need to make sure that ModelAndView is Serializable
That being said, there's no reason you can't delegate to another bean that has an appropriate signature
Here's some code as an example:
public class SimpleController implements Controller {
private BeanWithAnnotatedMethod bean; // Injected resource
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
Object keyObject = Helper.generateAppropriateKey(request);
String result = bean.annotatedMethod(keyObject);
return new ModelAndView(result)
}
Would something like this do the trick? http://code.google.com/p/simple-spring-memcached/
Related
Is there any way in spring boot to grab header from request in any point of application?
Some static stuff will be great.
Please, be aware that #RequestHeader does not work for me since I need this value on service layer.
You can inject HttpServletRequest object in your service layer like this :
#Autowired
HttpServletRequest request;
private void method() {
request.getHeader("headerName");
}
but remember, that bean HttpServletRequest has HTTP request scope. So, you can't inject that into asynchronous methods etc, because it will throw Runtime Exception.
hope it helps.
I was searching the same question before, i found out that you can use header parameters in the RestController methods with #RequestHeader as you said. So why not direct them into your service layer methods:
#Autowired
ServiceLayerObj serviceLayerObj;
...
#RequestMapping
public YourReturnObj someRestServiceMethod(
#RequestBody SomeObj body,
#RequestHeader(value = "username") String username
){
return serviceLayerObj.yourServiceLayerMethod(body,username);
}
I have :
#Controller
#RequestMapping(value="admin/*", method=RequestMethod.GET)
public class AdminController {
#Autowired
private HttpServletRequest request;
#Autowired
private HttpServletResponse response;
#RequestMapping
public ResponseEntity<String> test0() {
System.out.println("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
return null;
}
}
and the tag:
<mvc:annotation-driven />
in my config.xml
It should be enough I feel, but there is a problem with #Autowired:
No matching bean of type [javax.servlet.http.HttpServletResponse] found for dependency: expected at least 1 bean which qualifies ...
I have seen a couple of solutions mention setting up beans and such, but I am sure there has to be some better way. The annotation-scan should take care of this. It would suck if I have to set up beans in xml for several different annotations at different times. I just want the annotations to work when I use them!
I have seen:
Spring MVC - Response
Thanks!
As a workaround try:
#RequestMapping
public ResponseEntity<String> test0(
HttpServletRequest request,
HttpServletResponse response) {
System.out.println("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
return null;
}
Also try adding RequestContextListener but this should't be required in Spring MVC environment.
Autowiring doesn't work for the response, only the request. There are workarounds, but they're kind of hacky and lame. I ran into the same issue, here's my original question with a link to the workaround: #Autowired HttpServletResponse
It does not work as you want it, as fields, because a request and respose changes after each request (in lack of better explanation). You cannot reinject every time the new request/response in the fields. That is why you have to add them in the method where they will be injected every time new.
I have a Spring HandlerInterceptor intercepting the frontend URL's in my application (/app/*). I want to determine which action method in the Handler is about to be invoked from within the HandlerInterceptor. Is there a way to look that up, do I need to inject something into the interceptor that can look that up based on the requested path?
The Interceptor is like this:
public class PageCacheInterceptor implements HandlerInterceptor {...}
It is mapped like this:
<mvc:interceptors>
<bean class="com.example.web.interceptors.PageCacheInterceptor" />
</mvc:interceptors>
Background (because I know you'll ask!). I am adding simple page caching to my app and want to use an annotation like #Cacheable on each suitable method in the controller. The interceptor can then determine whether to cache a response based on the action that created it.
For example:
#RequestMapping(value = "", method = RequestMethod.GET)
#Cacheable(events={Events.NEW_ORDER,Events.NEW_STAT})
public String home(Model model) {...}
The events are the ones that cause the cache to be invalidated. For example /widget/list action would have it's cached response invalidated by a new widget being saved.
Edit: I've upgraded to the latest Spring 3.1 M2, as this blog post hinted at features I need, but it's not clear whether injecting these new classes or sub-classing them will be required. Has any one used them to retrieve the HandlerMethod in an interceptor?
Ok so the solution was actually really easy:
1) Upgrade to Spring 3.1
2) RTFM (properly)
For example a HandlerInterceptor can cast the handler from Object to HandlerMethod and get access to the target controller method, its annotations, etc
3) Cast the handler object to HandlerMethod in the Interceptor.
Then you can do this sort of thing:
HandlerMethod method = (HandlerMethod) handler;
Cacheable methodAnnotation = method.getMethodAnnotation(Cacheable.class);
if (methodAnnotation != null) {
System.out.println("cacheable request");
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre-handle");
HandlerMethod hm=(HandlerMethod)handler;
Method method=hm.getMethod(); if(method.getDeclaringClass().isAnnotationPresent(Controller.class)){
if(method.isAnnotationPresent(ApplicationAudit.class))
{
System.out.println(method.getAnnotation(ApplicationAudit.class).value());
request.setAttribute("STARTTIME",System.currentTimemillis());
}
}
return true;
}
This post has more details,hope this helps http://www.myjavarecipes.com/spring-profilingaudit-using-mvc-filters/
This is the code example from Spring 3.1 Spring Source Blog: From XML to #Configuration I'm trying to implement in my application (which was done in Spring 2.0 not by me so it's lot of learning).
#FeatureConfiguration
class MvcFeatures {
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
// ...
}
However, I can't understand the point of .argumentResolvers(new CustomArgumentResolver()) and their CustomArgumentResolver looks like bellow. What's the point of it?
public class CustomArgumentResolver implements WebArgumentResolver {
#Override
public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {
RequestAttribute attr = param.getParameterAnnotation(RequestAttribute.class);
if (attr != null) {
return request.getAttribute(attr.value(), WebRequest.SCOPE_REQUEST);
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
To add to #GaryF's answer, and to clarify some points, Spring 2.5 introduced annotated controllers, which replaced the old interface-style controllers of Spring 2.0. These new controllers have methods with no fixed parameters - the method declares the parameters that it needs to do its job, and nothing more.
For example, say a controller method needed one thing to do its job - a request parameter that contains the ID of an object from the database. In Spring 2.0, you would need to implement something like AbstractController.handleRequestInternal(), e.g
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Spring 2.5 made that easier:
#RequestMapping
public ModelAndView handle(String id) {
MyThing obj = getObjById(id);
//... do stuff and return ModelAndView
}
Here, we only declare parameters for the stuff we need.
So far so good, but this is where a custom WebArgumentResolver comes in. Say I want to remove the getObjById from my controller altogether, because maybe I think it clutters up the code, and maybe it's used across many other controller methods. Instead, I want to do this:
#RequestMapping
public ModelAndView handle(MyThing id) {
//... do stuff and return ModelAndView
}
It's even simpler, and has a bare minimum of boilerplate code. A custom WebArgumentResolver can be registered with the app-context which recognises parameters of type MyThing, and knows how to extract the information from the request. Spring invokes that resolver, and passes the result to the controller method.
Custom resolvers aren't commonly used, but can be very handy in the right situation.
The example in your question uses CustomArgumentResolver to resolve the example's custom RequestAttribute class. The resolver pulls out request attributes and binds them to RequestAttribute objects, so that they can be declared as controller method parameters.
WebArgumentResolvers are a way for you to specify how the parameters of MVC-mapped methods should be resolved. If you'd like to use a custom object as a parameter for an MVC-mapped method, Spring tries to figure out how make sense of it in it's own way. Typically this would happen through binding, where some http parameters you submit match up with the fields of the object and Spring matches them up and creates a new object for you.
If you ever have a situation where the submitted parameters don't match up quite so neatly with your method parameters, WebArgumentResolvers are there to fill in the gap: you provide custom logic so Spring doesn't have to figure it out.
In your example, param is one such parameter to be matched up. This piece of custom code first checks if the parameter has an #RequestAttribute annotation. If it does, then the custom code pulls the value from that object and looks it up as an attribute on the http request, returning it. It it does not have that annotation, then the method returns the UNRESOLVED value, which simply indicates that this WebArgumentResolver doesn't know anything about this particular parameter and Spring should try a different method (such as binding).
Here is my problem, I need to map a AJAX request using spring. Now, I know that I need these two guys:
HttpServletRequest, to get the message the client sent to me and parse it from JSON(most likely) to a Map and HttpServletResponse to put my message to the client.
What I do not know is the right(simple, concise) way to do that...
Here is a code sample from the springframework site:
/**
* Normal comments here
*
* ##org.springframework.web.servlet.handler.metadata.PathMap("/foo.cgi")
* ##org.springframework.web.servlet.handler.metadata.PathMap("/baz.cgi")
*/
public class FooController extends AbstractController {
private Cruncher cruncher;
public FooController(Cruncher cruncher) {
this.cruncher = cruncher;
}
protected ModelAndView handleRequestInternal (
HttpServletRequest request, HttpServletResponse response) throws Exception {
return new ModelAndView("test");
}
}
Which is nice. Except that, as far as I can see, I cannot map a URL for each method in that class as I would do with this kind of synchronous request:
#Controller
#RequestMapping("/test")
public class ControllerTest {
#RequestMapping(value = "/test.htm", method = RequestMethod.GET)
public void showSearchView(Model model) {...}
...
}
Can I do something that simple for AJAX requests?
Not sure where you found that first example on SpringSource! That is the old-bad(tm) way of doing it. I'm pretty sure AbstractController is even marked deprecated in Spring 3.
The second way works fine for mapping AJAX requests. If you really want to parse it all yourself, HttpServletRequest and HttpServletResponse are legal parameters for that handler method. However, Spring will happily do it for you: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
(If you're stuck on an older version of Spring there are also 3rd party libraries for adding JSON mapping to handlers.)
This is the answer I found. I modified the method shown in my post and added a HttpServletRequest to the method arguments.
public void showSearchView(Model model, HttpServletRequest req, HttpServletRequest resp) {
if(req==null||resp==null)throw new RuntimeException("OLOLOLOLOL xD");
}
That's it. If anyone have a better answer or comments, I'd be glad to hear.