Changing the postmapping in Spring gives me a 404 - java

Right now, I have I can send post requests to /message using Postman according to this
#RestController
#Api // For swagger document
public class MessageController {
private final MessageService messageService;
public MessageController(MessageService messageService) {
this.messageService = messageService;
}
#ApiOperation(value = "POST a message")
#PostMapping(value = "/message", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity createMessage(#Valid #RequestBody MessageVo messageVo,
#RequestParam(value = "callingApplication") String callingApplication) {
Map<String, String> response = new HashMap<>();
HttpHeaders responseHeaders = new HttpHeaders();
String id = messageService.createMessage(messageVo, callingApplication);
response.put("id", id);
return new ResponseEntity<>(response, responseHeaders, HttpStatus.CREATED);
}
}
If I change the #PostMapping(value = "/message") to #PostMapping(value = "/message2") for example, I am getting a 404 instead of a 200 (while also changing the URL to a 2 at the end). Is there somewhere else the mapping is defined?
Edit: I might add that I'm using "mvn clean package" to compile with Jooq as I'm also running a Postgres database locally. It might be that when I press the build button to compile on Intellij locally, it's not compiling the whole thing.

If #PostMapping(value = "/message2") then URL to hit in postman should be -
base_url/message2?callingApplication=abc
The 'callingApplication' is a mandatory query parameter.

Realized I had to compile with mvn clean package, not from ide

Related

Spring boot rest endpoint returning null with fetch request

I have already created Rest Endpoint in Java spring boot. It returns appropriate response when I request it via Postman. But when I use react fetch it does not show any response in browser if return is Json.
Spring boot controller:
#RestController
#RequestMapping(path = "/v1/test")
#AllArgsConstructor(onConstructor_ = {#Autowired})
public class TestController {
...
}
Below endpoint is returning appropriate response.
#GetMapping(value = "/helloWorld", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public String getHelloWorld() {
return "Hello, World1!";
}
But when I try to hit below endpoint it returns null when I make fetch request. But it returns appropriate response when I hit it via postman.
#GetMapping(value = "/testEndpoint", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public String returnTestResponse() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", "value2");
return "{\"a\":1, \"b\":\"foo\"}";
}
Also tried returning POJO object. But still no response.
#GetMapping(value = "/testModel", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public SearchResultsModel testModel() {
this.myService.getSearchResult();
}
React fetch call:
await fetch(ALL_ARTICLES_ENDPOINT, {
mode: 'no-cors',
method: 'GET',
redirect: 'follow',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
}).then(response => {
console.log(response);
})
.then(data => {
console.log('Success:', data);
}).catch((error) => {
console.error('Error:', error);
});
Postman have couple hidden headers which are being sent with all requests.
Check Hide auto-generated headers
What you are missing in react call is is Accept header with application/json value
EDIT:
Just saw that you are returning string as json. You need to wrap it in POJO object and return it in returnTestResponse class
SECOND EDIT:
This will work. Try to implement your POJO
#GetMapping(value = "/testEndpoint", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public YourObject returnTestResponse() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", "value2");
return new YourObject(map);
}
Issue was caused by adding mode: 'no-cors' option in fetch request. This option helped me to get rid of cors error but it means that in return I won't be able to see body and headers in chrome.
To resolve the issue I removed mode: 'no-cors' and added #CrossOrigin annotation on my spring boot controller.

How to create a URL pointing to a REST endpoint in your system at runtime with Spring Boot?

I'm using Spring Boot to build a REST API. In my situation, there are 2 controllers: ExportController and ImportController. Please check the example code here:
Export Controller:
#RestController
public class ExportController {
#GetMapping(value = "/export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> export(#RequestParam("id") String id) {
// Processing...
}
}
Import Controller:
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
// Processing...
// What should I do here?
String url = ...
}
}
Inside my ImportController, I want to generate a URL pointing to the /export endpoint, e.g. http://www.example.com/export?id=1234.
I don't configure anything about the host or port in the application.properties. I want to get them at runtime.
Could you please show me how to achieve it? I searched a lot on the Internet but couldn't find the answer. Thank you for your help.
If you can live with bringing spring-hateoas into your project then this will work:
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
String someId = "1234";
ControllerLinkBuilder linkBuilder = ControllerLinkBuilder.linkTo(methodOn(ExportController.class).export(someId));
URI uri = linkBuilder.toUri();
return ResponseEntity.ok(uri);
}
}
This yields http://localhost:8080/export?id=1234
#RestController
public class ImportController {
#PostMapping(value = "/import", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> importData(HttpServletRequest request) {
// Processing...
String url = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort() + "/export";
}
}
You can make use of ServletUriComponentsBuilder that comes with Spring framework since 3.1.RELEASE.
Given that you have access to current request, You can do something like below.
UriComponents uriComponents = ServletUriComponentsBuilder
.fromRequest(httpServletRequest)
.replacePath("/export")
.queryParam("id",1234)
.build();
String url = uriComponents.toUri();

Using RestTemplate in spring-boot returns with 404

I am trying to send a body in a post request in a springboot application using rest template. Here is the controller:(I removed #RequestBody because I used application/x-www-form-urlencoded header)
#RestController
#CrossOrigin
#RequestMapping("/api")
public class SentimentParserController {
#Autowired
private SentimentParserService sentimentParserService;
#RequestMapping(value = "/something", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
}
I want to send the sentimentRequestDTO object(lang, key, and text) as the body in a post request to get the mcResponse:
public mcResponse parseTheSentiments(String text, Languages lang, String key) throws Exception {
RestTemplate restTemplate = new RestTemplate();
String request = "http://localhost:8080";
mcSentimentRequestDTO mSentiments =new mcSentimentRequestDTO(key,"EN",text);
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/x-www-form-urlencoded");
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("key", key);
map.add("txt", text);
map.add("lang", Languages.ENGLISH.toString());
HttpEntity<MultiValueMap<String, String>> request1 = new HttpEntity<MultiValueMap<String, String>>(map, headers);
mcResponse response = restTemplate.postForObject(request, request1 , mcResponse.class );
return response;
}
However, I am getting the following error: 404 null.
Can you please help me? Thanks in advance
and here is the service class:
public ResponseEntity<mcResponse> getSentimentsMc(mcSentimentRequestDTO sentimentRequestDTO){
ResponseEntity<mcResponse> dto = null;
try {
dto = sentimentConverter.getTheSentiments(mcsParser.parseTheSentiments(sentimentRequestDTO.getText(),
Languages.ENGLISH, sentimentRequestDTO.getKey()));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return dto;
}
Looks like variable request should be
String request = "http://localhost:8080/something";
Also if controller class has prefix, this prefix also should be in request.
I mean if your class looks like this
#RestController
#RequestMapping("/myApi")
public class CertificateController {
....
#RequestMapping(value = "/something", method = RequestMethod.POST)
public ResponseEntity<mcResponse>getTheSentiments( mcSentimentRequestDTO sentimentRequestDTO){
return sentimentParserService.getSentimentsMc(sentimentRequestDTO);
}
Then request should be
String request = "http://localhost:8080/myApi/something";
It sounds like the controller isn't getting included in the spring context. If you just have an app annotated with #SpringBootApplication, then make sure that your controller is in a package that is the same as or lower than your annotated application.
To check the controller is being picked up you can add the following logging options to your application.properties
logging.level.org.springframework.beans=debug
logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping=trace
When your server starts up you should see something like the following in the log
1. To show the controller is in the spring-context
DefaultListableBeanFactory : Creating shared instance of singleton bean 'sentimentParserController'
2. To show the mapping for the /api/something url
RequestMappingHandlerMapping : Mapped 1 handler method(s) for class SentimentParserController: {public org.springframework.http.ResponseEntity SentimentParserController.getTheSentiments(mcSentimentRequestDTO)={[/api/something],methods=[POST]}}
If you see both of these, then what you say you're doing should work. Just make sure you are sending the request to /api/something and the server is running on port 8080.

SpringBoot – add Cache Control Headers in Rest methods

I have a basic SpringBoot 2.0.5.RELEASE app. Using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR
I have created this Rest method:
#GetMapping(path = "/users/notifications", consumes = "application/json", produces = "application/json")
public ResponseEntity<List<UserNotification>> userNotifications(
#RequestHeader(value = "Authorization") String authHeader) {
User user = authUserOnPath("/users/notifications", authHeader);
List<UserNotification> menuAlertNotifications = menuService
.getLast365DaysNotificationsByUser(user);
return ResponseEntity.ok(menuAlertNotifications)
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS));;
}
and I want to add a Cache Control Headers, but I don't know how...
I got a compilation error:
Multiple markers at this line
- The method cacheControl(CacheControl) is undefined for the type
ResponseEntity<List<UserNotification>>
- CacheControl
- cacheControl
I also add this property in application.properties
security.headers.cache=false
When you use ResponseEntity.ok(T body) the return type is ResponseEntity<T> as it is a shortcut method to add data to the body part of the ResponseEntity.
You need the builder object that is created via ResponseEntity.ok() with no param which returns a Builder object. You then add your data yourself on via the body method.
So your code should be like this
#GetMapping(path = "/users/notifications", consumes = "application/json", produces = "application/json")
public ResponseEntity<List<UserNotification>> userNotifications(
#RequestHeader(value = "Authorization") String authHeader) {
User user = authUserOnPath("/users/notifications", authHeader);
List<UserNotification> menuAlertNotifications = menuService
.getLast365DaysNotificationsByUser(user);
return ResponseEntity.ok().cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS)).body(menuAlertNotifications);
}

How to get JSON as Response in Spring MVC?

I am trying to return response as JSON. After searching I found solution to add headers = "Accept=application/json" in RequestMapping. But still it is not working .
It is throwing error HTTP Status 406 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers."
Here is my controller code :
#RestController
public class EmployeeController {
private EmployeeService employeeService;
#Autowired(required = true)
#Qualifier(value = "employeeService")
public void setEmployeeService(EmployeeService employeeService){
this.employeeService = employeeService;
}
#RequestMapping(value = "/test",method = RequestMethod.GET)
public String test(){
return "{\"name\":\"xyz\"}";
}
#RequestMapping(value = "/employees",method = RequestMethod.GET,headers = "Accept=application/json")
public List<Employee> listEmployees(){
List<Employee> employees = this.employeeService.getEmployees();
return employees;
}
}
Where am I doing wrong?
The simple way to generate JSON, XML response is #ResponseBody annotation.
#RequestMapping(value =" /jsonPostSingle", method = RequestMethod.GET)
#ResponseBody
public PostModel generateJSONPostsingle(#ModelAttribute("postModel") PostModel postModel) {
if(postModel.getPostId() == 1) {
postModel.setTitle("post title for id 1");
} else {
postModel.setTitle("default post title");
}
return postModel;
}
This way you will be able to map your request to model class using #ModelAttribute.
Follow the complete tutorial Spring MVC : JSON response using #ResponseBody
I understand that you're trying to send a response from GET request of /employees.
if you are using Spring 3.1, try to use
#RequestMapping(value = "/employees",method = RequestMethod.GET, produces = "application/json")
instead of adding headers = "Accept=application/json"
More info:
if you want to specify type of data that will send with a request, you can use consumes attribute
example:
#RequestMapping(value="/foo", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
this will consumes and response with JSON type only
check this link about spring update http://spring.io/blog/2011/06/13/spring-3-1-m2-spring-mvc-enhancements/
Hope it helps

Categories