Couldn't find HttpResponse or HttpServletResponse in Spring 4 - download

Just I am working on web project, In that i need to download a sql file while clicking the link. I tried to find the HttpResponse or HttpServletResponse in controller. Could any one help me to resolve this issue,
#RequestMapping(value = "/downloadFile.htm", method = RequestMethod.GET)
public void toDownloadFile(#RequestParam("fileName") String fileName,
HttpServletResponse response) {
File file = new File(fileName);
if (file != null) {
try {
response.setContentType("application/sql");
// response.setContentLength((new
// Long(file.getLength()).intValue()));
response.setHeader("content-Disposition",
"attachment; filename=" + fileName);
FileCopyUtils.copy(fileName, response.getOutputStream());
} catch (IOException ex) {
LOGGER.error("Exception in toDownloadFile :" + ex);
}
}
}
But in Spring 3 its available, I hope they removed or renamed the HttpServletResponse in Spring 4. Because HttpServeltRequest has been moved to org.springframework.web.context.request.WebRequest. Any one looked into this? Thanks in advance!!!

HttpServeltRequest and HttpServletResponse are javax interfaces not spring.
Are your project dependencies set up correctly?
javax.servlet.http.HttpServletResponse
org.springframework.web.context.request.WebRequest has been around for a while and is documented as...
Generic interface for a web request. Mainly intended for generic web request interceptors, giving them access to general request metadata, not for actual handling of the request.

Related

java.lang.IllegalStateException: getWriter() has already been called for this response, Even thought its called only once

I am using spring-boot. I want to send a CSV as the attachment of response for which I am using opencsv to write bean to response. Even though response.getWriter() is called only once, I am getting this exception.
While searching for solution, I came to know that we cannot use response.getWriter() and response.getOutputStream() together. But this is not the case here.
I am only calling getWriter and exactly once.
I also checked if it was due to opencsv library by writing a plain string to it e.g. "name, test". But still the same error. So it's not due to opencsv either.
private Pair<Boolean, String> writeCSVToResponse(List<QuestionDownloadResponse> qdrList, HttpServletResponse response) {
String fileName = new SimpleDateFormat("'CSV'yyyyMMddHHmmss'.csv'").format(new Date());
response.reset();
response.setContentType("application/csv");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"");
response.setCharacterEncoding("UTF-8");
//Find answer, for now we will return any if exists
try {
Writer writer = response.getWriter();
// Create Mapping Strategy to arrange the
// column name in order
final CustomCSVMappingStrategy<QuestionDownloadResponse> mappingStrategy = new CustomCSVMappingStrategy<>();
mappingStrategy.setType(QuestionDownloadResponse.class);
StatefulBeanToCsv<QuestionDownloadResponse> sbc = new StatefulBeanToCsvBuilder<QuestionDownloadResponse>(writer)
.withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withMappingStrategy(mappingStrategy)
.build();
sbc.write(qdrList);
} catch (IOException e) {
CMSQuestionServiceImpl.logger.error("Error in CSV IO operations", e);
return Pair.of(false, "Failed to Open file");
} catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
CMSQuestionServiceImpl.logger.error("Error in CSV Write operation", e);
return Pair.of(false,"Failed to write in csv");
}
}
Why is this exception coming, even when response.getWriter is called exactly once. How to solve this issue.
I found the issue. The problem was that I was sending a String (a message) in response in the controller, but in service, I am sending an attachment. So getWriter() was being called first time in service by me, and the second time by spring to write the response message of type String. Solution: I set the return type of method in the controller to void ex::
#GetMapping(value = "/downloadCSV")
public void downloadCSV(#RequestBody(required = false) List<Integer> items, HttpServletResponse response){
The only problem is if something goes wrong in service, you cannot send an error message and there are other alternatives to overcome it.
I had the same error: in spring-boot
This error occures when we use a RestExceptionHandler which tries to modify the response by using response.getOutputStream(), remember, the response.getWriter() is already called (even once in our code).
So when we call response.getWriter() , and we have some exception, the RestExceptionHandler executes the response.getOutputStream() which causes java.lang.IllegalStateException: getWriter() has already been called for this response.
What I suggest to do is to add try-catch to the response.getWriter() and when you catch any exception we have to reset the response by using response.reset() like that:
try {
writer.write(beans);
} catch (Exception e) {
response.reset();
throw e;
}
After throwing the exception the RestExceptionHandler will do it's job.

Media Type not acceptable exception when using SseEmitter

Following this tutorial, I am trying to set up a Sse Emitter. When I open the html page I get a
Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
On client side (javascript) it sais it cannot connect to the server. I have tried various other tutorials, but I am clueless on why my code isnt working.
I set up a clean test project containing only and exactly the tutorial code.
I Was in the middle of doing something else when I got the same issue.
The code below fixed it.
Simply put Mismatch Media type.
#GetMapping(value = "/api/push/notification",headers = "Accept=*/*", consumes = MediaType.ALL_VALUE, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public String doNotify(#RequestParam("authToken") String token, #RequestParam("clientId") String clientId, HttpServletResponse response) throws InterruptedException, IOException {
response.addHeader("charset","UTF-8");
final SseEmitter emitter = new SseEmitter(30000l);
service.addEmitter(clientId,emitter);
service.sendConnectedNotification(clientId);
emitter.onCompletion(() -> service.removeEmitter(clientId));
emitter.onTimeout(() -> service.removeEmitter(clientId));
return "Connected OK";
}
any my event handler
#Async
public void doNotify(String clientId, Object data) {
SseEmitter emitter= emitters.get(clientId);
if(emitter!=null) {
try {
emitter .send(SseEmitter.event() .reconnectTime(30000)
.data(data,MediaType.APPLICATION_JSON)
.id(UUID.randomUUID().toString())
.name("Notification")
.comment("Client connection notification")
);
} catch (Exception e) {
emitters.remove(clientId);
}
}
}

spring boot HttpServletResponse not setting file name

I have a rest service like this:
import org.apache.tomcat.util.http.fileupload.IOUtils;
#RequestMapping(value = "/xxx", method = GET)
public void getExcel(HttpServletResponse resp) {
resp.setHeader("Content-Disposition", "attachment; filename=\"NAME.xlsx\"");
resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
try (ServletOutputStream outputStream = resp.getOutputStream()) {
IOUtils.copy(A-VALID-FILE-INPUT-STREAM, outputStream);
resp.flushBuffer();
} catch (IOException e) {
throw new AppException(e);
}
}
the problem is that every time I call this service the default save name is 'response', I have tried returning HttpEntity<byte[]>, create objects like HttpHeaders() but nothing changes.
Any help is appreciated
If you are using postman take a look at https://github.com/postmanlabs/postman-app-support/issues/2082
Seems that you will need to wait until this issue will be addressed by postman team.

How to know the handler spring controller class and the handler method for the specified HttpServletRequest object

I need to somehow access the handler method with the reflection in the web filter and get the requestPattern value without passing the control to the dispatcher servlet. How can I do this?
I only have for that HttpServletRequest object and somehow I can also #Autowire there ApplicationContext object.
Thanks.
I have started to look how the DispatcherServlet itself decides which handler method it will give the control and implemented with such a way.
Here is the code:
//Initialization in filter constructor
....
final HandlerMapping handlerMappings = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMapping.class, true, false).get("requestMappingHandlerMapping");
....
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
.....
Method mappingMethod = null;
try {
mappingMethod = ((HandlerMethod)handlerMappings.getHandler(request).getHandler()).getMethod();
RequestMapping requestMapping = mappingMethod.getAnnotation(RequestMapping.class);
final String requestPattern = requestMapping.value();
}
catch(Exception ex){
logger.error("Error getting the mapping bean for the request URL " + request.getRequestURI(), ex);
return;
}
....
}
On top of the proposal of #Arsen I would suggest to do like this:
try {
handlerMappings.getHandler(request);
String requestPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
} catch (Exception ex) {
logger.error("Error getting the mapping bean for the request URL " + request.getRequestURI(), ex);
return;
}
The getHandler() instruction is enoght to trig the spring lookup of the correct controller that will also set the HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE attribute, this is usually available in controllers but not in filters.
Be aware that these solutions will waste some resources, cause spring will do the lookup again after that.

spring boot serving image/jpeg gives gibberish

I'm trying to serve images from mongodb GridFS. My Controller.
#RequestMapping(value = "{id}", method = RequestMethod.GET)
public void getPhoto (#PathVariable String id, HttpServletResponse response, HttpServletRequest request) {
log.info("#getPhoto > ip of request: " + request.getRemoteAddr() + ", id: " + id);
final InputStream inputStream = resourceService.getMediaResourceById(id);
try {
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
} catch (IOException | NullPointerException e) {
log.error("#getPhoto > error with request for objectId: " + id, e);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
}
The result:
This only happens using Spring Boot. as a test when using Spring and running the exact same code i'm getting:
Writing directly to a response is discouraged in controller methods for various reasons. You are essentially responsible for almost everything yourself. The preferred way is to return something that gets converted as needed.
You already use ResponseEntity<byte[]> now. But your source is a stream and you have to create an unnecessary byte array. You can use Resource instead that wraps all sorts of input streams, be it from files or already opened input streams.
InputStreamResource inputStream = new InputStreamResource(resourceService.getMediaResourceById(id));
return new ResponseEntity<>(inputStream, HttpStatus.OK);
or as of Spring 4.1
return ResponseEntity.ok(inputStream);
Please note that produces = MediaType.IMAGE_JPEG_VALUE doesn't actually set a content type. It's used for content negotiation.

Resources