404 Request Resource not found - spring

I am using Spring Framework with restful web services, and I am trying to create an API with restful service and use a get method. I have created a method and I'm trying to have it return a string, but instead I get a 404 error - requested resources not found. Please see my code below:
#RestController
#RequestMapping("/test")
public class AreaController {
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
}
I am using: localhosr:8080/MyProject/wangdu

This error occurs because you forgot to add
#RequestMapping(value = "/{name}", method = RequestMethod.GET) before your find method:
#RestController
#RequestMapping("/test")
public class AreaController {
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return "list";
}
}

Please make sure about this:
The value that the find method is returning is a String with the value "list" and the find method declaration is waiting for a RestResponse object
For example if I have a RestResponse object like this:
public class RestResponse {
private String value;
public RestResponse(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
}
Then try to return the value in this way:
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return new RestResponse("list");
}
Verify that the method has #RequestMapping annotation with the value that your expect from the url
#RequestMapping(method = RequestMethod.GET, value = "/{name}")
By default the proper way to call the rest resource is by the #RequestMapping value that you set at the #RestController level (#RequestMapping("/test")), in this case could be: http://localhost:8080/test/myValue
If you need to use a different context path then you can change it on the application.properties (for spring boot)
server.contextPath=/MyProject/wangdu
In that case you can call the api like this:
http://localhost:8080/MyProject/wangdu/test/myValue
Here is the complete code for this alternative:
#RestController
#RequestMapping("/test")
public class AreaController {
#RequestMapping(method = RequestMethod.GET, value = "/{name}")
public RestResponse find(#PathVariable String name, ModelMap model) {
model.addAttribute("movie", name);
return new RestResponse("list");
}

Related

What should I do in springboot if I use a post request with only one parameter?

No use of map and bean, what is a good solution?
How to get the orderId better
#RequestMapping(value = "/submitTail", method = RequestMethod.POST)
#ResponseBody
public Object generateTailOrder(String orderId) {
}
Use PathVariable if you can add orderId somewhere in URL. Take care of API standards.
Example: /orders/{orderId}/submitTrail
By doing this your API will be more informative and should not be invoked without orderId.
#RequestMapping(value = "/submitTail/{orderId}", method =
RequestMethod.GET)
public Object generateTailOrder(#PathVariable String orderId) {
}
OR
#GetMapping(value = "/submitTail/{orderId}")
public Object generateTailOrder(#PathVariable String orderId) {
}

spring boot : RequestMapping

I have following three REST API methods :
#RequestMapping(value = "/{name1}", method = RequestMethod.GET)
public Object retrieve(#PathVariable String name1) throws UnsupportedEncodingException {
return configService.getConfig("frontend", name1);
}
#RequestMapping(value = "/{name1}/{name2}", method = RequestMethod.GET)
public Object retrieve(#PathVariable String name1, #PathVariable String name2) throws UnsupportedEncodingException {
return configService.getConfig("frontend", name1, name2);
}
#RequestMapping(value = "/{name1}/{name2}/{name3}", method = RequestMethod.GET)
public Object retrieve(#PathVariable String name1, #PathVariable String name2, #PathVariable String name3) {
return configService.getConfig("frontend", name1, name2,name3);
}
getConfig method is configured to accept multiple parameters like:
public Object getConfig(String... names) {
My Question is : is it possible to achieve the above RequestMapping using only one method/RequestMapping ?
Thanks.
Simple approach
You can use /** in your mapping to grab any URL and then extract all parameters from the mapping path. Spring has a constant which allows you to fetch the path from the HTTP request. You just have to remove the unnecessary part of the mapping and split the rest to get the list of parameters.
import org.springframework.web.servlet.HandlerMapping;
#RestController
#RequestMapping("/somePath")
public class SomeController {
#RequestMapping(value = "/**", method = RequestMethod.GET)
public Object retrieve(HttpServletRequest request) {
String path = request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
String[] names = path.substring("/somePath/".length()).split("/");
return configService.getConfig("frontend", names);
}
}
Better approach
However, path variables should be rather used for identifying resources in your application and not as a parameters to a given resource. In that case, it is advised to stick with simple request parameters.
http://yourapp.com/somePath?name=value1&name=value2
You mapping handler would look much more simple:
#RequestMapping(method = RequestMethod.GET)
public Object retrieve(#RequestParam("name") String[] names) {
return configService.getConfig("frontend", names);
}
You should probably use #RequestParam instead and method POST in order to achieve what you want.
#RequestMapping(name = "/hi", method = RequestMethod.POST)
#ResponseBody
public String test(#RequestParam("test") String[] test){
return "result";
}
And then you post like that:
So your array of Strings will contain both values
Also in REST a path corresponds to a resource, so you should ask yourself "what is the resource i am exposing ?". It would probably be something like /config/frontend and then you specify your options through request params and/or HTTP verbs
You can retrieve the complete path with request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE) and then parse it to get all the values.
This should work:
#SpringBootApplication
#Controller
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#RequestMapping(value ={"/{name1}","/{name1}/{name2}","/{name1}/{name2}/{name3}"})
public #ResponseBody String testMethod(
#PathVariable Map<String,String> pathvariables)
{
return test(pathvariables.values().toArray(new String[0]));
}
private String test (String... args) {
return Arrays.toString(args);
}
}

Spring REST Service Controller not being validate by #PathVariable and #Valid

#Controller
#EnableWebMvc
#Validated
public class ChildController extends ParentController<InterfaceController> implements InterfaceController{
#Override
#RequestMapping(value = "/map/{name}", produces = "application/json; charset=UTF-8", method = RequestMethod.GET)
#ResponseStatus( HttpStatus.OK)
#ResponseBody
public List<Friends> getAllFriendsByName(
#Valid
#Size(max = 2, min = 1, message = "name should have between 1 and 10 characters")
#PathVariable("name") String name,
#RequestParam(value="pageSize", required=false) String pageSize,
#RequestParam(value="pageNumber", required=false) String pageNumber,
HttpServletRequest request) throws BasicException {
//Some logic over here;
return results;
}
#ExceptionHandler(value = { ConstraintViolationException.class })
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleResourceNotFoundException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
StringBuilder strBuilder = new StringBuilder();
for (ConstraintViolation<?> violation : violations ) {
strBuilder.append(violation.getMessage() + "\n");
}
return strBuilder.toString();
}
Hi, I am trying to do pretty basic validation for a spring request parameter but it just doesn't seem to call the Exception handler, could someone point me into the right direction
P.S. I keep getting NoHandlerFoundException
Spring doesn't support #PathVariable to be validated using #Valid. However, you can do custom validation in your handler method or if you insist on using #Valid then write a custom editor, convert your path variable value to an object, use JSR 303 bean validation and then use #Valid on that object. That might actually work.
Edit:
Here's a third approach. You can actually trick spring to treat your path variable as a model attribute and then validate it.
1. Write a custom validator for your path variable
2. Construct a #ModelAttribute for your path variable and then use #Validator (yes not #Valid as it doesn't let you specify a validator) on that model attribute.
#Component
public class NameValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return String.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
String name = (String) target;
if(!StringUtils.isValidName(name)) {
errors.reject("name.invalid.format");
}
}
}
#RequestMapping(value = "/path/{name}", method = RequestMethod.GET)
public List<Friend> getAllFriendsByName(#ModelAttribute("name") #Validated(NameValidator.class) String name) {
// your code
return friends;
}
#ModelAttribute("name")
private String nameAsModelAttribute(#PathVariable String name) {
return name;
}

Tomcat Show HTTP Status 400 Error Page During Validation

I'm learning to make Bean Validation works in Spring MVC with Thymeleaf as default view. Every valid data can be saved properly. But when I tried an invalid data passed, Tomcat just showed HTTP Status 400 Error page. In Tomcat console showed something like validation but just became logging text in Tomcat console. Here is the controller that saves data (item).
#Controller
#RequestMapping("/item")
#SessionAttributes("item")
public class ItemController {
#Autowired
private ItemService itemService;
#Autowired
private ColorService colorService;
#ModelAttribute("allColors")
public List<Color> populateColors() {
return colorService.findAll();
}
#ModelAttribute("allItems")
public List<Item> populateItems() {
return itemService.findAll();
}
#RequestMapping(value = {"/image/{id}", "image/{id}"})
#ResponseBody
public byte[] showImage(#PathVariable("id") String id) {
return itemService.getItem(id).getImage();
}
#RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
public String showAllItems() {
return "itemList";
}
#RequestMapping(value = {"add", "/add"}, method = RequestMethod.GET)
public String showItemAddForm(Model model) {
model.addAttribute("item", new Item());
return "itemAddForm";
}
#RequestMapping(value = {"add", "/add"}, method = RequestMethod.POST)
public String processAddItem(
#ModelAttribute("item") #Valid Item item,
RedirectAttributes model,
BindingResult errors,
SessionStatus session) {
if (errors.hasErrors()) {
return "itemAddForm";
}
itemService.saveItem(item);
session.setComplete();
model.addFlashAttribute("message", "Item has been added");
return "redirect:/item";
}
}
Is any wrong with the controller? How should I to make Bean Validation works with Spring and Thymeleaf?

set #RequestMapping value to return spring controller

I have problem with mapping in spring 3 mvc. General I must "send" value (#RequestMapping(value = "/*") to my return statement. How it resolve? I was thinking about this:
#RequestMapping(value = "/*", method = RequestMethod.GET)
public String homeForm( Model model, HttpServletResponse response) throws IOException {
logger.info("Welcome ");
String url=response.getWriter().toString();
return url;
}
Is it good solutions, maybe someone has any advices?
Thaks
If you want to return the string that comes after the slash, you could do something like this:
#RequestMapping(value = "/{foo}", method = RequestMethod.GET)
public #ResponseBody String homeForm(#PathVariable("foo") String foo) {
return foo;
}

Resources