I have REST endpoint with multiple paths as following:
#RequestMapping(method = RequestMethod.POST, path = {"/xxx/yyy", "/zzz"})
#ResponseBody
public Mono<EpcPain> paymentOrder(#RequestHeader(name = "Timeout", defaultValue = "10000") int timeout,
#RequestHeader(name = "X-Request-Id", required = false) String xRequestId) {
...
}
How can I resolve if request path was xxx/yyy or zzz? I do not want to duplicate this endpoint nor pass some params. I am looking for some spring code magic.
org.springframework.web.context.request.RequestContextHolder may be used to get the path
import static org.springframework.web.servlet.HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE;
import static org.springframework.web.servlet.HandlerMapping.LOOKUP_PATH;
import static org.springframework.web.servlet.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE;
and
#RequestMapping(value = {"/getDetails","/getDetailsMore"}, method = RequestMethod.GET)
public String getCustomerDetails(TestFormBean bean) {
RequestAttributes reqAttributes = RequestContextHolder.currentRequestAttributes();
System.out.println(reqAttributes.getAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, 0));
System.out.println(reqAttributes.getAttribute(LOOKUP_PATH, 0));
System.out.println(reqAttributes.getAttribute(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, 0));
return "test";
}}
All three prints the path.
Here 0 - is request scope and 1 - is session scope.
Hope this helps.
You could add ServerHttpRequest as a method argument and then get the URI for the current request using getURI(). It should work for both Spring MVC and Spring WebFlux.
Have a look at the handler methods documentation for details.
Related
I am developing chat application using java springboot and Angular 7. I am using events in spring boot and angular. I am trying to generate events in spring boot for angular to listen the event. However, I am getting following error:
Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
Here is my controller code in springboot:
#CrossOrigin("*")
#RestController
#RequestMapping("/chat")
public class MessageController {
#Autowired
MessageService messageService;
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
private static final Logger logger = LoggerFactory.getLogger(MessageController.class);
#PostMapping(consumes = "application/json", produces = "application/json")
public GenericApiResponse<Map<String, Object>>message(#RequestBody MessageRequest req) {
logger.info("MessageController:: messagemethod [POST] /chat");
GenericApiResponse<Map<String, Object>> responseObj = new GenericApiResponse<>();
Object returnValue = new Object();
try {
returnValue = messageService.translateText(req);
} catch (Exception e) {
e.printStackTrace();
logger.error("EXCEPTION: "+e.getStackTrace().toString());
responseObj.setStatus(Constants.ERROR);
responseObj.setMessage("Internal Server Error");
}
Map<String, Object> resMap = new HashMap<>();
resMap.put("result", returnValue);
resMap.put("sender", req.getSender());
responseObj.setResponseObject(resMap);
responseObj.setStatus(Constants.SUCCESS);
MessageEvent messageEvent = new MessageEvent(this,"eventName", responseObj);
applicationEventPublisher.publishEvent(messageEvent);
return responseObj;
}
I am unable to figure out what is the issue and how to solve it. Please help me to solve this issue.
Thanks in advance :)
From first look at your code, I can observe following problems:
#ResponseBody is added but no response is returned i.e. method type is void.
produces = "application/json" doesn't make sense for a void method returning no response.
Hence, for a rest endpoint always return some response. You can fix it by putting following as return statement in the end in your method:
return ResponseEntity.ok("your message");
Also, #ResponseBody means that response is always serialized to json hence, no need to specify , produces = "application/json" explicitly.
Update:
Can you please also try replacing consumes = "application/json", produces = "application/json" with
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
And
ensure that request headers are set to application/json.
Also, ensrue jackson dependencies are in place.
Solution: EventSource in angular takes Content-Type : text/event-stream by default. So I created new method and added #RequestHeader(value = "Content-Type", defaultValue = "text/event-stream") as parameter.
Automatic conversion of Objects are neglected if you don't have getter method for the return type object. If you don't have getter method for GenericApiResponse object add one.
I am new to wiremock and trying to stub the invocation of the following springboot restful endpoint.
#PostMapping(path = "/template/pdf", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<String> bindData(
#ApiParam(value = "BindDataRequest payload", required = true)
#RequestParam String template, #RequestParam String templateDataAsJson) throws IOException {
//Some code
return ResponseEntity.ok("xyz");
}
**The following basic logic works:**
templatingService.stubFor(
post(urlEqualTo("/template/pdf"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_PDF_GEN).withStatus(200)));
But, i need a way of setting the 2 string request parameters before invoking .willReturn(.....)
I have tried :
templateBinderService.stubFor(
post(urlEqualTo("/template/pdf"))
.withRequestBody(WireMock.equalTo("jixhcjxhcjxhcxhchx"))
.withRequestBody(WireMock.equalTo("nhhhxhxhhhhhxhhhh"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_HTML2PDF_GEN).withStatus(200)));
But got:
org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found
//I have also tried:
templateBinderService.stubFor(
post(urlEqualTo("/template/test"))
.withRequestBody(containing("param1-value"))
.withRequestBody(containing("param2-value"))
.willReturn(aResponse().withBody("i-am-a-response").withStatus(200)));
//I have also tried:
templateBinderService.stubFor(
post(urlEqualTo("/template/test"))
.withRequestBody(equalToJson("{}"))
.willReturn(aResponse().withBody("i-am-a-response").withStatus(200)));
Please help with code snippet or reference.
Since both the parameters template and templateDataAsJson are annotated with #RequestParam, they should be passed accordingly in the wiremock stub as below.
templatingService.stubFor(
post(urlEqualTo("/template/pdf?template=value1&templateDataAsJson=value2"))
.willReturn(aResponse().withBody(JSON_INPUT_TO_PDF_GEN).withStatus(200)));
where value1 and value2 are the respective values for both parameters.
The authentication method has been integrated with every REST calls in the API. I have been trying to implement an authentication method via Spring AOP so that I can remove all the duplicate code from end-points and have one single advise to look for all public methods in Controllers.
Please check the below my code,
#Aspect
public class EndpointAccessAspect {
/**
* All the request mappings in controllers need to authenticate and validate end-point access
*/
#Before("execution(public * com.xxxx.webapi.controllers.MenuController.getCategory(HttpServletRequest)) && args(request)")
public void checkTokenAccess(HttpServletRequest request){
String re =(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println(" %%%%%%%%%%%%%%%%%%% checkTokenAccess %%%%%%%%%%%%%%%" + re);
}
public void checkEndPointPermission(){
System.out.println(" $$$$$$$$$$$$$$$$$$ checkEndPointPermission &&&&&&&&&&&&&");
}
}
However, I saw Intelij gives error near getCategory(HttpServletRequest)) && args(request) saying can not resolve symbol HttpServletRequest. I need the request to distingues each REST end-points. There are more variables than HttpServletRequest variable in the method but only that variable is needed.
The code is compiling when I test the functionality I noticed it doesn't reach to the advise. Can anybody help me to fix this?
I found this from Spring documentation
Spring doc
any join point (method execution only in Spring AOP) which takes a
single parameter, and where the argument passed at runtime is
Serializable
Does this mean I can not use methods that have multiple parameters?
Controller end-point
#RequestMapping(value = "{menuId}/categories/{categoryId}", method = RequestMethod.GET)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Successful retrieval of a category requested", response = ProductGroupModel.class),
#ApiResponse(code = 500, message = "Internal server error") })
public ProductGroupModel getCategory(
#ApiParam(name = "menuId", value = "Numeric value for menuId", required = true) #PathVariable(value = "menuId") final String menuId,
#ApiParam(name = "categoryId", value = "Numeric value for categoryId", required = true) #PathVariable(value = "categoryId") final String categoryId,
final HttpServletRequest request) {
The following syntax, resolved the above issue. Basically, I had to modify the code to deal with multiple parameters in the advise.
#Before("execution(public * com.xxxx.webapi.controllers.MenuController.getCategory( HttpServletRequest,..)) && args(request, ..)")
public void checkTokenAccess(HttpServletRequest request){
String re =(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println(" %%%%%%%%%%%%%%%%%%% checkTokenAccess %%%%%%%%%%%%%%%" + re);
}
Im facing a an issue while Im adding a method to the controller class with #RequestMapping(method = RequestMethod.POST) annotation. The issue is when I add this method and start application. Application unable to load resources (css,JS etc). On the browser I get:
Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
and on the Run logs I get this message:
org.springframework.web.servlet.PageNotFound handleHttpRequestMethodNotSupported
WARNING: Request method 'GET' not supported
When I remove this method from the controller class, all works fine. Dont know why is this happening. Im sure its nothing to do with Configuration or resources in Dispatcher Servlet mapping because without this method every thing works perfectly fine.
I need to use this method because of some business requirement, which otherwise is not possible.
Can any body help me in Identifying where the issue is.
#Controller
public class InvoiceController
{
#RequestMapping(value = "/index", method = RequestMethod.GET)
public ModelAndView adminPage() {
String username;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
username = auth.getName(); //get logged in username
username.toUpperCase();
// Logic to build menue based on the Role of the user.
HashMap hm = new HashMap();
OrderItems od = new OrderItems();
ModelAndView model = new ModelAndView();
model.addObject("usr", username);
//Set the object for Menue Links on the Page
model.addObject("mnue", hm);
model.setViewName("index");
model.addObject("odi",od);
return model;
}
#RequestMapping(method = RequestMethod.POST)
public String save(HttpServletRequest request,
HttpServletResponse response,
Model model)
{
System.out.println("Im here in Genaric Post Method");
return null;
}
}
Please also note that Im using Spring Security configurations. Is there anything to do with Security? Or there is some issue with Controller Class configuration.
Thanks in advance for your anticipation.
Regards,
D Kamran
Add endpoint url value to request mapping
#RequestMapping(value="/index", method = RequestMethod.POST)
This happens because Post method declared mapped to all paths as both Method and Controller class don't have that value
my service code :
#RequestMapping(value = "/projects/{projectId}/resources/web/{path}", method = RequestMethod.GET)
#ResponseBody
public void getWebFileContent(#PathVariable("projectId") String projectId,#PathVariable("path") String path, HttpServletRequest httpServletRequest) throws Exception {
}
And my request will be
/projects/pro1/resources/web/src/main/webapp
/projects/pro1/resources/web/src/main/test/com/pro1...
and is it possible to get "src/main/webapp/../....." into "path" variable
Spring provide three patterns in the url handler mappings
? - zero or one charecter
*- one charecter
** - one or more charecters
And below approach resolved my issue
#RequestMapping(value = "/projects/{projectId}/resources/web/**", method = RequestMethod.GET)
#ResponseBody
public void getWebFileContent(#PathVariable("projectId") String projectIdHttpServletRequest httpServletRequest) throws Exception {
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
// will get path = /projects/pro1/resources/web/src/main/webapp
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
// will get bestMatchPattern = /projects/pro1/resources/web/**
AntPathMatcher apm = new AntPathMatcher();
String exactPath = apm.extractPathWithinPattern(bestMatchPattern, path);
// will get exactPath = src/main/webapp
.....
}
Any other approaches are appreciated....