spring RESTful service work fine, but throws an exception - java

I am creating a spring RESTful service, and it is working. My client send an object into a put request and my service receive this object perfectly, but after this, my client receive this exception: "org.springframework.web.client.HttpClientErrorException: 404 Not Found"
This is my client code:
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Greeting greeting = new Greeting(21l, FileUtils.toByteArray("src/main/resources/test.png"));
String url = "http://localhost:8080/DolphinRestServer/bulletin/put";
restTemplate.put(url,greeting);
And this is my server code:
#Service
#RequestMapping("/bulletin")
public class BulletinService {
#RequestMapping(method = RequestMethod.PUT, value = "/put")
public void put(#RequestBody Greeting greeting){
System.out.println("it's work fine and my greeting is here --------->"+greeting);
}
}
When tested, i get those messages:
-server side:
-Client side:

Your put method has a void return type. Additionally, it does not take the HttpServletResponse as a parameter. According to the Spring MVC documentation, when such a situation arises, Spring MVC uses the URL as the view name and attempts to render it. In your case, Spring MVC is attempting to find and load a view called /bulletin/put, which it can't find and hence the 404 message.

As you can see it is making another request at 20:40:34:085 DolphinRestServer/bulletin/bulletin/put in the server side giving an error page not found.
And it is because you are calling BulletinService twice.
You defined as a bean and it has an annotation. Make sure you are only loading/scanning this package once..
Remove #service annotation on BulletinService

Related

Trouble sending multipart request

I'm creating a new endpoint to upload and process excel and csv files.
I'm trying to create an endpoint using springs Multipart upload, but I cannot reach the endpoint from Postman or using curl in command line.
I have a RestController
#RestController
#RequestMapping("/v1/finance/ratecard")
public class RateCardController
and I am able to access other endpoints in this controller without a problem.
I added new endpoint to this controller.
#PostMapping(value = "/uploadFile")
#ResponseStatus(HttpStatus.OK)
public void uploadExcelFile(#RequestPart("file") MultipartFile file, #RequestPart("meta-data") UploadRateCardRequest uploadRateCardRequest) {
//Unrelated logic here
}
And I'm trying to send POST request using postman, I haven't touched Content-Type header, it's generated by Postman, but I have had no success reaching it. I always get 404 error. Postman Config
I have tried adding consumes = "multipart/mixed" and "multipart/form-data" to #PostMapping annotation, but those changes had no effect.
What am I doing wrong? Am I missing some obvious request parameter in Postman, or is my controller set up wrong?
I had problems in uploadExcelFile method, one of dependencies I was using could not detect valid beans for an autowired interface. That was causing this issue.
Nothing was wrong with Controller set up or postman config pictured in the post.

Invoke Spring Controller from Spring Integration flow

Hi I have a little problem. I want to invoke spring controller manually but I have an exception. Firstly, let me show you some integration flow and controller:
#Bean
public IntegrationFlow flow() {
return IntegrationFlows.from(
Amqp.inboundAdapter(rabbitMqConfig.connectionFactory(), queue)
.acknowledgeMode(AcknowledgeMode.MANUAL)
.errorChannel("errorChannel")
.concurrentConsumers(2)
.maxConcurrentConsumers(3))
.transform(Transformers.fromJson(Event.class))
.transform(new EventToRequestTransformer())
.handle(Request.class, (request, headers) -> controller.trigger(request))
.<ResponseEntity, HttpStatus>transform(ResponseEntity::getStatusCode)
.routeToRecipients(some routing)
.get();
}
#Controller
public class SomeController {
#RequestMapping(value = "/trigger", method = RequestMethod.POST)
public ResponseEntity<Response> trigger(#RequestBody Request request)
{
//some logic
}
}
When I'm running my app and sending an event I am getting exception on line:
.handle(Request.class, (request, headers) -> controller.trigger(request))
Exception:
nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet
Could someone please tell me what is wrong and how to fix that? I thought I can just invoke controller method like it was coming from simple POJO.
You are mixing concerns and try to call Web tier from the service layer.
If the logic is like that, then design of the app is wrong.
You should extract some service from the controller logic and call it from the Web, as well as from there on the Integration level.
According your stack trace it looks like you try to get access to the request scope object. Well, and that is exactly what happens to #Controller beans, I guess.

How to access endpoints in a controller in Spring?

I have a controller class this way with endpoints. I know that we can access RESTful endpoints in a web application through a tool like 'postman' using the URL. But I am not sure how to access these endpoints. This is not a web application.
This is a java application deployed as a JAR on server using embedded tomcat.
How can I access these endpoints?
#Controller
public class TopicStatsController {
#Autowired
private QueueDepths depths;
#RequestMapping("/topicDepth")
#ResponseBody
public Long topicDepth() throws Exception {
return depths.topicDepth();
}
#RequestMapping("/subscribersDepth")
#ResponseBody
public List<Long> subscribersDepth() throws Exception {
return depths.subscribersDepth();
}
}
You can access the endpoints using RestTemplate.
RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl
= "/topicDepth";
ResponseEntity<String> response
= restTemplate.getForEntity(fooResourceUrl + "/1", Long.class);
Your remote must be having an IP address and a port number.
You can use it to hit a GET or POST request.
On localhost - http://localhost:8080/myapp-oracle/api/v1/user
On remote - http://172.16.254.1:8080/myapp-oracle/api/v1/user
Note: You also need to change the http protocol depending upon the server.

POST method in Spring Boot REST service (external Tomcat) return 404 error

I created a REST web service using Spring Boot.
The project is configured to use an external Tomcat.
When using Tomcat 8 it connects successfully and get good responses when i call my GET methods.
However, the POST methods return 404 errors.
#RestController
#RequestMapping("/hashkey")
#EnableAutoConfiguration
public class StringHashingController {
#RequestMapping(method=RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody HashedStringsList hashMe(#RequestParam(value="caller", required=true) String callerId, #RequestBody StringHashingRequestBodyParams hashParam) {
HashedStringsList pList = new HashedStringsList();
//...
return pList;
}
}
I have no problem calling the same post method locally in the IDE (Intellij) through running 'Spring Boot Configuration'.
Is there anything I need to configure in Tomcat or in my code?
Thanks!

Spring Boot in standalone Tomcat ignores exceptions set in DeferredResults

I'm running a Spring Boot 1.2.1 application in standalone Tomcat.
I have two controller mappings, which both for simplicity always throw an exception. The first one is for a GET request and it returns a String for the view name:
#RequestMapping(value = {
"/index"
}, method = RequestMethod.GET)
public String init() throws MyRequestProcessingException {
if (true) {
throw new MyRequestProcessingException(
"Something went wrong processing request");
}
return "init";
}
This is the exception definition:
#ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
public class MyRequestProcessingException extends Exception {
public MyRequestProcessingException(String message) {
super(message);
}
}
In embedded Tomcat as well as in standalone Tomcat, trying to access /index always results in a 500 with some JSON error data being returned to the client.
My controller has another method which accepts a POST and returns a DeferredResult:
#RequestMapping(value = "html/start", method = RequestMethod.POST, consumes = APPLICATION_FORM_URLENCODED)
public DeferredResult<String> start(final HttpServletResponse response,
#Valid #ModelAttribute final InitialisationStartAttributes model,
final SessionData sessionExisting) throws MyRequestProcessingException {
final DeferredResult<String> finalResult = new DeferredResult<>(5000);
// Just return an error, so we can test
if (true) {
finalResult.setErrorResult(new MyRequestProcessingException(
"Something went wrong processing request"));
}
return finalResult;
}
In embedded Tomcat, a POST to /html/start returns a 500 with some JSON data in the response body, just like the other request method. However, when I try to reproduce this behaviour using a standalone Tomcat instance, I always get a 200 response with no response body.
I'm using Tomcat 8 in embedded and Tomcat 7.0.52 standalone, but I've also tried with standalone Tomcat 8 and it doesn't make a difference.
My application is deployed in the root application context by modifying /etc/tomcat/Catalina/localhost/ROOT.xml.
EDIT: I've done a bit more testing, and it does seem that DeferredResult is the culprit. I have yet to override handleErrorResult() to see what happens. I'm a bit surprised though, because I don't recall seeing anything in the documentation about the difference between returning a DeferredResult in embedded vs standalone Tomcat.
If you throw an exception in a #RequestMapping and don't handle it anywhere, then the response status is not set before you hit the ErrorPageFilter. If you want to map status to error path in your customizer, you need to handle the error and get the status set in the filter chain somewhere (e.g. with an #ExceptionHandler or by using an Exception with a #ResponseStatus). Another way to get your custom error page to render would be to map exceptions instead of (or as well as) the HttpStatus, using new ErrorPage(Exception.class, "/html/error").
This behaviour was due to a bug in Spring Boot's ErrorPageFilter; see bug report on GitHub. It was fixed in Spring Boot 1.2.3.

Categories