Passing HttpServletResponse in Spring Boot controller method - java

Came across spring boot code snippet which has HttpServletResponse passed has an argument in the controller method
public void someApiMethod(#RequestBody MyRequest req, HttpServletResponse response) {
//some code
response.setStatus(HttpStatus.NO_CONTENT.value());
}
The same could have been achieved using ResponseEntity and I feel there is no need of passing HttpServletResponse here.Kindly advise on which is the best approach and why, considering this code is written for rest API ?

Better solution is to use #ResponseStatus for there is no real reason to add non-API arguments, such as HttpServletResponse or ResponseEntity in controller methods. Only path variables, request params, request body & headers should be the set of controller parameters for majority of cases. Plus it is more readable, maintainable, and still is usable by Swagger etc.
#ResponseStatus(code = HttpStatus.NO_CONTENT)
public void someApiMethod(#RequestBody MyRequest req) {
//some code
}

Spring boot (and in particular Spring MVC which is a part of spring boot in this case) provides an abstraction over low-level HttpResponse which is a part of the servlet specification.
In a nutshell, this abstraction saves you from thinking in terms of Http Protocol and allows concentrating on a business logic which is a good thing.
So if you can avoid HttpServletResponse - do it by all means (and this is what you'll usually do in your applications).
You can create objects (and spring will convert them for you if its REST), you can return ResponseEntity which is "status" + "body" - spring will do all the conversions.
So consider these techniques first.
Now, sometimes you have to manipulate the response at the low level, well in this case you have to work with HttpServletResponse object.
Example of this if you want to return a binary data that cannot be easily converted. For instance, if you want to prepare a zip file and send it back as a result of HTTP request, you'll have to get a more fine-grain low-level control, in this case, it's better to start off with HttpServletResponse param passed into controller method.

It depends on your particular use case.
If you can implement your use case without directly accessing the HttpServletResponse object, do so by any means. It is the cleaner approach.
You might have a scenario in which you need to access the HttpServletResponse. Such an example would be when you need to stream content back to the client, so you need direct access to the response output stream. In recent versions of Spring this can also be achieved via StreamingResponseBody, which avoids the need to directly access the response outout stream.

I believe it is a better approach to return a ResponseEntity and use that as per your suspicious.
ResponseEntity is easier to handle and a more "elegant" solution, more consistent with Spring design.

Related

RestTemplate: exchange() vs postForEntity() vs execute()

I am working on Rest API using Spring boot and I had to access an application's endpoint. I used RestTemplate for it. I was able to do it using 2 methods,
postForEntity():
responseEntity =
restTemplate.postForEntity(uri, httpEntity, ResponseClass.class);
exchange():
responseEntity =
restTemplate.exchange(uri, HttpMethod.POST, httpEntity, ResponseClass.class);
I would like to know the usage and differences of these two methods.
I also see another method execute(). Please shed some light on it. How and when to use it.
The RestTemplate is a very versatile object.
Let's start with execute, since it's the most generic method:
execute(String url, HttpMethod method, #Nullable RequestCallback requestCallback,
#Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables)
Note the uriVariables can be passed as a Map too.
execute is designed to be applicable in the highest variety of scenarios possible:
The first and second parameters allow any valid combination of URL and method.
The request can be modified in a myriad of different ways by passing a custom RequestCallback (a #FunctionalInterface with just one method doWithRequest(ClientHttpRequest request)) before sending it.
The response returned from the remote resource can be deserialized in any way necessary by passing a custom ResponseExtractor.
Compare this with exchange:
exchange(String url, HttpMethod method, #Nullable HttpEntity<?> requestEntity,
Class<T> responseType, Object... uriVariables)
There are two major differences here:
You can now pass an HttpEntity directly, whereas before it needed to be set manually using the RequestCallback.
Deserialization mechanics are provided out of the box by passing the desired response type Class.
As you can see, this is much more convenient for everyday use.
Methods like getForEntity and postForEntity are even shorter, easier to understand versions of this:
getForEntity(String url, Class<T> responseType, Object... uriVariables)
postForEntity(String url, #Nullable Object request, Class<T> responseType,
Object... uriVariables)
Notice postForEntity now allows you to POST any Object directly without a wrapper. There is no performance benefit or detriment to using these instead of execute, as they call execute themselves under the hood - it's simply a matter of convenience.
RestTemplate is a synchronous client to perform HTTP requests. It offers templates for common scenarios for each HTTP method, in addition to the generalized exchange(...) and execute(...) methods that support less frequent cases.
The Spring Integration documentation summarizes the usage of each method:
postForEntity
Create a new resource via POST and return the representation from the response.
exchange
More generalized, and less opinionated version, of the above methods that provides extra flexibility when needed. It accepts RequestEntity, including HTTP method, URL, headers, and body as input, and returns a ResponseEntity.
These methods allow the use of ParameterizedTypeReference instead of Class to specify a response type with generics.
execute
The most generalized way to perform a request, with full control over request preparation and response extraction via callback interfaces.
In the end, both postForEntity(...), exchange(...) and execute(...) methods will invoke the protected doExecute(...) method, which will perform the actual HTTP request. You can check the source code for details
Execute(..)
The most raw form of method, to make REST call.
Exchange(..)
A wrapper over Execute method.
PostForEntity(..)
A wrapper method, which further eases the use for making REST calls.
You specify the request type in the method name itself(getForEntity, postForEntity), so,
need not mention request type in the parameter.
The method name in itself becomes self explanatory.
In Exchange & postForEntity, response has to be in Json formats.
This Json is further converted to Model class by json-mapper libraries.
While, in Execute, we accept response in any format, as we pass the deserializer in Response Executor argument.
If you look at the implementation of both postForEntity and exchange method you will see that both use the execute methods in the back. Using the exchange method will give you more freedom for calling different http methods.

How to get HttpServletRequest and HttpServletResponse in FreeMarker?

I just took over a freemarker project.
The controller classes extend the abstract class squirrel.web.SquProcessor, and use squirrel.web.PageData to transfer values.
But now, I want to use the HttpServletRequest and HttpServletResponse in the controller classes.
How to get them?
FreeMarker is unaware of servlets or HTTP (barring the included FreemarkerServlet that was added to ease migrating from JSP). You see in templates what the controller class has exposed to FreeMarker. Exposing highly technical things like servlet request/response object is not very clean; ideally the template should only get application-domain objects and some helpers to generate URL-s and such.

How to define RequestMapping prioritization

I have a situation where I need the following RequestMapping:
#RequestMapping(value={"/{section}"})
...method implementation here...
#RequestMapping(value={"/support"})
...method implementation here...
There is an obvious conflict. My hope was that Spring would resolve this automatically and map /support to the second method, and everything else to the first, but it instead maps /support to the first method.
How can I tell Spring to allow an explicit RequestMapping to override a RequestMapping with a PathVariable in the same place?
Edit 2: It seems that it would work if the /support mapping came before the /{section} mapping. Unfortunately we have dozens of controllers containing numerous methods with RequestMapping. How can I make sure that the controller with the /{section} mapping is initialized last? Or would a pre-interceptor be the way to go?
Edit 1: This is simplified, I know that having those two RequestMapping alone wouldn't make much sense)
Using Spring you can extend the org.springframework.web.HttpRequestHandler to support your scenario.
Implement the method:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
Use it to analyze the incoming request, determine if the request url is part of your special subset of request url's and forward to the appropriate location.
Ex:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/** You will want to check your array of values and have this data cached **/
if (urlPath.contains("/sectionName")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("sections" + "/" + urlPath);
requestDispatcher.forward(request, response);
}
}
And setup your sections such as:
#RequestMapping(value={"/sections/{sectionName}"})
This will not interfere with any of your pre-existing controller mappings.
If 2 these methods are defined in 2 different controllers your problem is that you have 2 controllers mapped to same URL. You do not control the order of controllers initialization right now, so the order is random.
I think you need /support mapping to be initialized before /{section}.
To achieve this try to define that controller "section" depends on controller "support". If this will not help try to put both methods together to one controller and put method mapped to "support" before "section"
I this does not work here is other suggestion. What "section" is? If it can accept limited number of values it should be defined as enum. I believe that in this case everything will work as required if support and section methods are in one controller or in separate controllers.
Good luck.
This not seems to be a problem, this is a valid mapping. If you have a look to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
In the section 16.3.2 Mapping Requests With #RequestMapping exists two methods doing exactly the same that you are trying.
To be sure that your classes are being compiled try to add a #RequestMapping("/someprefix") at class level to see if the URL is being exposed as you want.
I verify your example locally using the version 3.1.0.RELEASE and no issue were present.
As a workaround (and also to provide a well-understand REST URI add some context to your second mapping:
#RequestMapping(value={"client/support"}) // i.e: if you are working with clients
public ModelAndView getsupport(#PathVariable Long supportId){
// do your code here something here
}
Of course that this is valid if this is the unique controller present in the system, otherwise you must use RequestMapping at class level as I suggested above.
I hope this helps.
I am not seeing this behavior with Spring 3.1.2, it could potentially have been a bug with an older Spring version. Here is a gist which runs through without any issues for me - https://gist.github.com/3802254

Accessing HttpServletRequest object in a normal Java class from Spring

I have a normal Java class in a Spring MVC 3.06 web application.
In this class I would like to inject or get hold of the HttpServletRequest object in a method.
I know I can pass this around, but I was wondering how can I get hold of the request without passing it in to the method. Perhaps using annotations or similar?
Also, what are the "real" concerns with getting hold of the request this way, except some peoples opinions of it being ugly coding. I mean, is it unstable to access it this way?
Preferably non application server dependent way.
I have seen
(HttpServletRequest) RequestContextHolder.getRequestContext().getExternalContext().getNativeRequest()
but this doesn't seem to work for Spring MVC 3.06 . RequestContextHolder doesn't have the method getRequestContext().
Use
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
I'm not sure where you got RequestContextHolder.getRequestContext(), that's completely wrong.
is it unstable to access it this way?
No, it's stable enough, assuming you're always running the code as part of an HttpServlet request thread. The main issue is that yes, it's ugly, and it makes your code hard to test. That is reason enough not to use it.
If you must use it, then decouple it from your code, e.g.
public void doSomething() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
doSomething(request);
}
void doSomething(HttpServletRequest request) {
// put your business logic here, and test this method
}
#Context HttpServletRequest httpServletRequest =null;
use this

#Autowired HttpServletResponse

I'm looking for a way to autowire HttpServletResponse. It doesn't work with spring out of the box, but I've found this description. This works but is sort of annoying, in that spring obviously has a mechanism to make objects request scoped (i.e. HttpServletRequest) and this seems to be a hack bolted on top.
Is there a way to hook into the same mechanism that spring uses for HttpServletRequest? And, any idea why spring team decided to only make HttpServletRequest autowire capable (and excluded HttpServletResponse)?
Perhaps there is some workaround, but it's not that obvious, because it's not the way it's meant to be. Spring MVC is meant to have singleton #Controller beans that provide #RequestMapping methods which take the request and response as arguments.
If you need the response in another place (the service layer) - don't do it. The response should not go beyond the web (controller) layer.
To inject the response, you need:
- to store the response in a ThreadLocal
- to make a factory bean that returns the current response
About the example code you showed - I'm not sure if you are not going to need the factory bean to return a proxy (implementing HttpServletResponse), which in turn to return the current response. And it gets rather complicated.
But ultimately - you should not do that. If you need to intercept multiple controller invocations, use an mvc-interceptor. If you really need to use an aspect, you can get the response if it is passed as argument to the intercepted method.
Can you simply include the request in the method handle?
#RequestMapping(method=Method.GET, value="myUrl")
public String doGet(HttpServletResponse response){//spring will put the response in for you
...
}

Categories

Resources