How to change "pathInfo" of HttpServletRequest - java

I am afraid to ask a strange question but I want to change "pathInfo" of HttpServletRequest at a handler method of a Controller. Please take look at below.
I know I can get "pathInfo" by using getPathInfo(). However. I don't know how to set up the pathInfo. Is it possible ? Any help will be appreciated
#RequestMapping(value = "show1" method = RequestMethod.GET)
public String show1(Model model, HttpServletRequest request) {
// I want to set up "PathInfo" but this kind of methods are not provided
//request.setPathInfo("/show2");
// I thought that BeanUtils.copy may be available.. but no ideas.
// I have to call show2() with the same request object
return show2(model, request);
}
// I am not allowed to edit this method
private String show2(Model model, HttpServletRequest request) {
// I hope to display "http://localhost:8080/contextroot/show2"
System.out.println(request.getRequestURL());
return "complete";
}

You can't set these values.
The only option is to create a wrapper for your request, something like this:
return show2(model, new HttpServletRequestWrapper(request) {
public StringBuffer getRequestURL() {
return new StringBuffer(
super.getRequestURL().toString().replaceFirst("/show1$", "/show2"));
}
});

Path Info is set by the browser (client) when it requests a certain URL.

Related

How to return completely empty response in Spring

I have a Spring MVC Rest controller with one of the URL mappings being :
myhost:8080/helloworldexample/testnullresponse
Now, is it possible to return nothing at all when I call this URL
Nothing means: no body, no response, no status code simply nothing at all, almost like the server listening to the request did not do anything.
I would appreciate any help on this. I have tried the following options but nothing worked:
return new ResponseEntity<Void>(null);
AND
#RequestMapping(value = "/helloworldexample/testnullresponse", produces = "application/json; charset=UTF-8", method = RequestMethod.GET)
public void nullResponse(HttpServletRequest request) {
}
Actually your controller's method could return void.
Here is an example
#RequestMapping(value = "/helloworldexample/testnullresponse", method = RequestMethod.HEAD)
public void nullResponse(HttpServletResponse response) {
...
}

Spring 3 - How to throw an exception when additional request parameters are passed

I have a controller mapping, where I pass 2 request params instead of 1. But when done like that Spring is not throwing any exception rather it is ignoring the additional request params.
For eg:
#RequestMapping(value="/test", method = RequestMethod.GET)
public ModelAndView eGiftActivation(#RequestParam("value") String value)
When I hit my app using /test.do?value=abcd it is working fine. But when I pass additional params like /test.do?value=abcd&extra=unwanted also it's working fine.
In this case I want Spring to restrict the second URL where additional params are passed.
How can I achieve this?
You could check it manually, like this:
#RequestMapping("/test")
public ModelAndView eGiftActivation(HttpServletRequest request) {
Map<String, String[]> params = request.getParameterMap();
if (params.size() != 1 || !params.containsKey("value")) {
throw new RuntimeException("Extra parameters are present"); // or do redirect
}
...
}
I don't think it's possible (For Spring to prevent the request to flow to any controller's method). The reason being that:
Your controller handles request based on the URI path like, /app/hello/{name} rather than the request parameters
Request parameters are there to give extra set of meta-info for the request rather than endpoint specification of request.
But, if you wanted to restrict the URI path as such, you can use regex and you can avoid. I'm afraid it's not feasible and even the requirement for that never arose.
Programmatical Way:
Having said that, you can take HttpServletRequest for parameters and loop through the parameters to check for extra ones:
#RequestMapping(value="/test", method = RequestMethod.GET)
public Object eGiftActivation(#RequestParam("value") String value, HttpServletRequest request){
//check the request.getParameterMap() and throw custom exception if you need and handle using Exception handler or throw invalid request
return new ResponseEntity<String>(HttpStatus.SC_BAD_REQUEST);
}
I prefer handling these kind of validations (if required, what ever may be the reason) inside the Filter generically so that the requests will not even reach the Controller methods.
Please find the required code to handle inside the Filter as below (logic is almost similar to Slava).
#Component
public class InvalidParamsRequestFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Map<String, String[]> params = request.getParameterMap();
if (request.getRequestURI().contains("/test") && (params.size() != 1 || !params.containsKey("value"))) {
//Here, Send back the Error Response OR Redirect to Error Page
} else {
filterChain.doFilter(request, response);
}
}
}

How to send response before actions in spring mvc

Say that my spring controller function receives a large amount of data.
I want to return 200 OK, given that the data is structured right, and after that I want to perform the processing, which might take a while.
To my understanding the only way to send response is by return command. But I don't want to end the function on response send.
Are there other ways to send response to client at the middle of the function?
Creating a new thread run is obvious but other languages (JS) let you handle it more elegantly.
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message> messages) {
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
return new ResponseEntity<String>(res, code);
// how do I add code here??
}
You can of course do processing after sending the response. The more general way would be to use the afterCompletion method of a HandlerInterceptor. By construction, it will be executed after the response have been sent to client, but it forces you to split you logic in 2 components the before part in controller, and the after part in the interceptor.
The alternative way is to forget Spring MVC machinery and manually commit the response in the controller:
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public void doSomething(#RequestBody List<Message> messages, HttpServletResponse response) {
int code = (messages!=null && !messages.isEmpty()) ? HttpServletResponse.SC_OK
: HttpServletResponse.SC_NOT_FOUND;
if (code != HttpServletResponse.SC_OK) {
response.sendError(code, res);
return;
}
java.io.PrintWriter wr = response.getWriter();
response.setStatus(code);
wr.print(res);
wr.flush();
wr.close();
// Now it it time to do the long processing
...
}
Note the void return code to notify Spring that the response have been committed in the controller.
As a side advantage, the processing still occurs in the same thread, so you have full access to session scoped attributes or any other thread local variables used by Spring MVC or Spring Security...
You can use #Async
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method =
RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message>
messages) {
do();
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
return new ResponseEntity<String>(res, code);
}
#Async
void do(){
//your code
}
this work in java 8
I guess you mau use the async mechanism of spring
Async methods have been introduced in servlet 3.0 and Spring offers some support to them
Basically... you make a request; the request is handled by the server and then, in background, a new thread manages the requesta data
Here a useful link (at least i hope :) ) http://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/
You should use the HandlerInterceptor. But the code get a little bit more complex than expected. So, here's a code suggestion to make it simpler by putting the whole solution in a single class:
#RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(#RequestBody List<Message> messages) {
HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
: HttpStatus.NOT_FOUND;
result.set(res); // Save the object to be used after response
return new ResponseEntity<String>(res, code);
}
private static final ThreadLocal<String> result = new ThreadLocal<String>();
#Bean
public HandlerInterceptor interceptor() {
return new HandlerInterceptor() {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object and clean for the next request
String res = result.get();
result.set(null);
// TODO Your code to be executed after response.
}
};
}

return string instead of model

I am using spring 3.2 and I have come with one requirement and can't figure out how to achieve it, first please look for below
We mostly use model in Spring MVC which is use for data binding
#ResponseBody annotation returns the string as http response
So my requirement is I want to use both together in single method base on condition, Here is my code
#RequestMapping(value="userAddEditSubmit.htm", method={RequestMethod.GET, RequestMethod.POST})
public String userAddEditSubmit(
#ModelAttribute("user") User user,
HttpServletRequest request, HttpServletResponse response, HttpSession session,
Model model
) throws Exception {
try {
//Here is my logic
return "redirect:" + url;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
So above is my method which returns specific jsp with model attribute, but now in one condition I have requirement to return String data instead of whole jsp in the same method, what can I do to achieve this? Any help will be highly appreciated.
You can simply return null from that method when your condition is met and write to the response yourself. Spring assumes that when a method returns null it has handled the response itself.

Changing content type in jax-rs REST service

Forgive me, but I may not be familiar with all the lingo necessary to ask this question properly.
I'm working on a fairly simple REST web service in Java using the org.apache.cxf.jaxrs.ext implementation of jax-rs. The method header is like this:
#GET
#Path("json/{fullAlias}")
#Produces({"application/json"})
public String json(#PathParam("fullAlias") String fullAlias, #Context MessageContext req)
where MessageContext is org.apache.cxf.jaxrs.ext.MessageContext.
There are two things I'm trying to accomplish that I can't seem to figure out:
Change the content-type if certain conditions are met (e.g. for an error)
Change the status code of the response
I've tried using changing the response by accessing it through the MessageContext:
HttpServletResponse response = req.getHttpServletResponse();
response.setContentType("text/plain")
response.setStatus("HttpServletResponse.SC_BAD_REQUEST);
But these changes have no bearing on the response sent; with or without the #Produces annotation, setting the content type inside the method doesn't affect the actual content type (With the annotation, it of course returns "application/json", without it defaults to "text/html").
I am returning a simple String as the body. I've entertained trying to return a javax.ws.rs.core.Response object to do what I want, but I don't know much about it.
How would I change the content type and/or the status codes from inside this method?
One approach is to throw a WebApplicationException, as described by Pace, which will work if you are looking to specifically handle an error condition. If you are looking to be able to change your content at any time for any reason, then you will want to take a look at returning a Response as the result of your service method rather than a String. Returning a Response gives you the greatest amount of control over how your service responds to the client request (it does require more code than returning a simple string).
Here is an example of how you would can make use of the Response object:
#GET
#Path("json/{fullAlias}")
public Response json(#PathParam("fullAlias") String fullAlias, #Context MessageContext req) {
...
if (success) {
ResponseBuilder rBuild = Response.ok(responseData, MediaType.APPLICATION_JSON);
return rBuild.build();
}
else {
ResponseBuilder rBuild = Response.status(Response.Status.BAD_REQUEST);
return rBuild.type(MediaType.TEXT_PLAIN)
.entity("error message")
.build();
}
}
I'm not sure if it's the best approach but I've done the following to solve your question #1.
public WebApplicationException createStatusException(String statusMessage) {
ResponseBuilder rb = Response.noContent();
rb = rb.type(MediaType.TEXT_PLAIN);
rb = rb.status(Status.BAD_REQUEST);
rb = rb.entity(statusMessage);
return new WebApplicationException(rb.build());
}
EDIT: I then threw the resulting WebApplicationException.
You can write your own Response Filter to change the content-type header.
#Provider
public class MimeAddingFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Content-Type", "image/png");
}
}
This filter will add the "image/png" content-type header. You can also change or remove headers in JAX-RS response filters.

Categories

Resources