This works, I am able to make a request in postman for this Service.
#RestController
#Path("sample")
public class SampleClass {
#GET
#Path(value = "/s1")
public Object get() {
//Something
}
}
The problem is when I try to use #RequestMapping instead of #Path, I get a
404 Not Found
Error.
#RestController
#RequestMapping("sample")
public class CommonService {
#GetMapping(value = "/s1", produces = MediaType.APPLICATION_JSON)
public Object get() {
//Something
}
}
What I am doing wrong here?
After a while, I found out that for the JAX-RS (#Path) I had configured in web.xml file a different route "something".
JAX-RS: localhost:8080**/something**/sample/s1
Spring Rest Services: localhost:8080/sample/s1
I was also missing a "/" in the Spring Rest Service.
#RequestMapping("**/**sample")
Full code bellow:
#RestController
#RequestMapping("/sample")
public class CommonService {
#GetMapping(value = "/s1", produces = MediaType.APPLICATION_JSON)
public Object get() {
//Something
}
}
Related
DepartmentController
#RestController
public class DepartmentController {
#Autowired
DepartmentControllerConsumer departmentService;
#GetMapping("/departments")
public ResponseEntity<List<DepartmentResponse>> getAllDepartments() {
ResponseEntity<List<DepartmentResponse>> departments = departmentService.getAllDepartmentsUsingClient();
return departments;
}
}
DepartmentControllerConsumer
import reactor.core.publisher.Flux;
#Service
public class DepartmentControllerConsumer {
public ResponseEntity<List<DepartmentResponse>> getAllDepartmentsUsingClient() {
List<DepartmentResponse>list=new ArrayList<>();
WebClient client =WebClient.create("http://localhost:8080/restservice/api/");
System.out.println(client);
Flux<DepartmentResponse> value = client.get().uri("departments").accept(MediaType.APPLICATION_JSON).retrieve()
.bodyToFlux(DepartmentResponse.class);
list=value.toStream().collect(Collectors.toList());
System.out.println(value.toStream().collect(Collectors.toList()));
return new ResponseEntity<List<DepartmentResponse>>(list, HttpStatus.OK);
}
}
The above was the controller and the service classes, Having one endpoint.While calling it from the post man am getting 404 even gave the correct URL path
Yes, if your controller class is not in the same package as source package, you may need to either put them in same package or make use of #ComponentScan to scan your package :)
How can I get the matched request path in an HTTP mapping method in a spring application? In the following example, I want matchedPath variable to have the value /api/products/{product_id}/comments which is a combination of #RequestMapping and #PostMapping value.
#RestController
#RequestMapping("/api")
public class Example {
#PostMapping("/products/{product_id}/comments")
public ResponseEntity doSomething(#PathVariable("product_id") String id) {
// String matchedPath = getPath();
return ResponseEntity.ok().build();
}
}
I found it is doable via one of HandlerMapping attributes BEST_MATCHING_PATTERN_ATTRIBUTE
import javax.servlet.http.HttpServletRequest;
#RestController
#RequestMapping("/api")
public class Example {
#PostMapping("/products/{product_id}/comments")
public ResponseEntity doSomething(HttpServletRequest req, #PathVariable("product_id") String id) {
String matchedPath = String.valueOf(req.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
return ResponseEntity.ok().build();
}
}
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/HandlerMapping.html
Was trying out RSocket Request/Response as specified in section 4 of https://www.baeldung.com/spring-boot-rsocket. So there is a RSocketServer autoconfigured and listening at port 7000. Unable to connect to the method annotated with #GetMapping when hitting the same from browser
#RestController
public class MarketDataRestController {
private final RSocketRequester rSocketRequester;
public MarketDataRestController(RSocketRequester rSocketRequester) {
this.rSocketRequester = rSocketRequester;
}
#GetMapping(value = "/current/{stock}")
public Publisher<MarketData> current(#PathVariable("stock") String stock) {
return rSocketRequester
.route("currentMarketData")
.data(new MarketDataRequest(stock))
.retrieveMono(MarketData.class);
}
}
Expecting to be able to connect to the current() of the class MarketDataRestController annotated with #GetMapping when requesting the same from browser, say e.g.: http://localhost:7000/current/APPLE.
Not sure how to connect to the same.
You can't use #RequestMapping with sockets, use #MessageMapping instead:
instead of #RequestMapping or #GetMapping annotations like in Spring MVC, we will use the #MessageMapping annotation:
#Controller
public class MarketDataRSocketController {
private final MarketDataRepository marketDataRepository;
public MarketDataRSocketController(MarketDataRepository marketDataRepository) {
this.marketDataRepository = marketDataRepository;
}
#MessageMapping("currentMarketData")
public Mono<MarketData> currentMarketData(MarketDataRequest marketDataRequest) {
return marketDataRepository.getOne(marketDataRequest.getStock());
}
I want to have a RestController-class with the base-mapping "/user" (so the different functions will have paths like "/user/add", "/user/remove" etc or use POST/GET etc)
This is the part that I don't understand and can't get to work:
#RestController
public class UserController {
#GetMapping("/user")
public Response login(Principal principal){
//some output
}
}
Expected behavior for this case would be that I can access my output under "/user". This works as expected.
Now if I modify it to the following (since all functions in this controller should have a path starting with "/user" this would be cleaner)
#RestController
#RequestMapping("/user")
public class UserController {
#GetMapping("/")
public Response login(Principal principal){
//some output
}
}
I get a 404-Error page and can't access "/user" anymore
All examples I have found use the same syntax (or sometimes #RequestMapping(path="/user") but that didn't work as well) and I don't know why it doesn't work.
Can someone tell me where my mistake is?
If you use this code:
#RestController
#RequestMapping("/user")
public class UserController {
#GetMapping("/")
public Response login(Principal principal){
//some output
}
}
Then your url should have "/" at the end like "http://localhost:8080/user/"
I would just throw away "/" symbol from #GetMapping("/") and left like this:
#RestController
#RequestMapping("/user")
public class UserController {
#GetMapping
public Response login(Principal principal){
//some output
}
}
And if you need map get or post you can use like this:
#RestController
#RequestMapping("/user")
public class UserController {
#GetMapping("/add")
public SampleObj getJson() {
return new SampleObj();
}
}
It should work.
Controller needs uses .htm extensions for all handlers, including JSON REST endpoints. How should I test for REST endpoints?
Problem:
I cannot disable suffix interpretation and I am getting 406 "Could not find acceptable representation"
Tried attempts:
I reviewed posts on stackoverflow related to 406, but could not find relevant one to the case where 'htm' suffix is used in tests. When you remove '.htm' suffix from both Controller and Test - the test is passing.
Here is controller with /changePassword.htm endpoint:
#Controller
public class MainController {
public static class ResultBean {
private final String result;
public String getResult() {
return result;
}
public ResultBean(String result) {
this.result = result;
}
}
#RequestMapping(value="/changePassword.htm", method= RequestMethod.POST, produces = { "application/json" })
public #ResponseBody ResultBean changePassword (
#RequestParam("username") String username, #RequestParam("password") String password) {
return new ResultBean("OK");
}
}
And here is the test with configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { HomeControllerTest.Config.class })
public class HomeControllerTest {
#InjectMocks
private MainController controller = new MainController();
private MockMvc mvc;
#Configuration
#EnableWebMvc
public static class Config extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreUnknownPathExtensions(true)
.ignoreAcceptHeader(false)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON);
}
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(controller)
.build();
}
#Test
public void shouldPassChangePasswordBean() throws Exception {
mvc.perform(post("/changePassword.htm")
.accept("*/*")
.param("username", "example")
.param("password", "abcdef")
)
.andExpect(status().isOk()); // Test produces 406 instead of 200
}
}
Any idea?
On newer version of Spring (4+ I think), mime type is determined from suffix first.
So If you use a .htm suffix, Spring will default to produce HTML even if you don't want to.
One way to bypass this is to use a filter that rewrite URL. For instance tuckey URL rewriter filter
With this, you can set some rules like:
/my/page/that/return/json.htm is rewriten to /my/page/that/return/json so that Spring can produce data according to the Accept header.
with Spring 5, try changing your URL of your web service to .json! that is the right fix. great details here http://stick2code.blogspot.com/2014/03/solved-orgspringframeworkwebhttpmediaty.html