Spring REST #RequestMapping Extract Incorrectly If Value Contains ‘.’ - spring

Problem:
See following Spring REST example, if a request such as http://localhost:8080/site/google.com is submitted, Spring returns “google“. Look like Spring treats “.” as file extension, and extract half of the parameter value.
Spring must return “google.com“. How can do it?
SiteController.java
package com.example.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/site")
public class SiteController {
#RequestMapping(value = "/{domain}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("domain") String domain,
ModelMap model) {
model.addAttribute("domain", domain);
return "domain";
}
}

I believe you can use regex in the path variable of the #ResourceMapping. For instance, you could do
{domain:.[\\S]*}
You will probably have to fiddle with the regex some to get it right. The ':' separates the path variable name from the regex.

It is pretty simple just add ":.+" with your parameter like below:
here username is e-mail id
#RequestMapping(value = "checkuser/{username:.+}" , method=RequestMethod.GET)
#ResponseBody
boolean getUserName(#PathVariable("username") String userName){
boolean isUserAvailable = userDao.checkAvailable(userName);
return isUserAvailable;
}
I am passing value from URL like :
baseurl/checkuser/test#test.com

just make sure your url end of '/'and SiteController.java chage noting..
change http://xxx/site/google.com to http://xxx/site/google.com/

Related

#GetMapping method not calles

I am a beginner so please don't be mean.
I have got an html page index.html
And I want the method MainController::getListEmployee to be called.
In this method, I put a System.err to see if the method is called. And I see nothing.
Controller code
package com.cgi.listeemployes.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.cgi.listeemployes.model.User;
import com.cgi.listeemployes.repository.UserRepository;
#Controller // This means that this class is a Controller
#RequestMapping(path="/") // This means URL's start with /demo (after Application path)
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
#GetMapping(path="/index.html")
public #ResponseBody Iterable<User> getListEmployee() {
// This returns a JSON or XML with the users
System.err.println("getting ");
return userRepository.findAll();
}
#PostMapping(path="/add") // Map ONLY POST Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);
return "Saved";
}
#GetMapping(path="/all")
public #ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
thanks for your help
When you want to return a html, just return a string with the name of the html file, it could be "Index" (without the .html).
In your #GetMapping(path="/index.html"), you are returning an object instead a html.
If you want to load data from database and render it at your html, then add the attribute "Model model" in your parameters, like this:
#GetMapping(path="/index.html")
public String getListEmployee(Model model) {
List<User> users = userRepository.findAll();
model.addAttribute("yourUsers", users); // this gonna inject the list of users in your html
System.err.println("getting ");
return "Index"
}
Then in your html, you can get the users with ${yourUsers} and do whatever you want.
I saw your project, it is missing the template engine. Template engine is what gonna get the data of your backend and show in your front/html. I added the Thymeleaf template engine into your pom.xml, and it worked. Here is the thymeleaf dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
To work with thymeleaf, you have to put all your html into a new folder called "templates" in the "resources", same level of "static". You cannot use html in the static folder, this folder should have only css, javascripts and assets.

unable to render an array of strings using th:each atrribute in thymeleaf

pls I tried rendering an array of strings with thymeleaf and its showing blank. does any one know the reason for this? The code is shown below:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
//public String[] greetings= new String[] {"Hi","Hello","Watsup"};
#RequestMapping("/home")
public String getHomePage(Model model) {
model.addAttribute("msg",new String[]{"Hi","Hello","Watsup"});
//model.addAttribute("msg",new String[]{"Hi","Hello","Watsup"});
return "home";
}
//<h1 th:text=${welcomeMessage}>*Hello Peeps!*</h1>
}```
the html(thymeleaf) is shown below:
<h1 th:each="msg : ${greetings}" th:text=${msg}>Hello,homepage</h1>
You are setting the attribute on the model by the "msg" key. You need to access that instead of greetings.
<h1 th:each="message : ${msg}" th:text=${message}>Hello,homepage</h1>

Circular view path [greeting]

I am using spring-boot-starter-paren: 2.3.2.RELEASE.
Here is my code:
package com.example.sweater;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greeting(#RequestParam(name="name",
required=false,
defaultValue="World") String name,
Map<String, Object> model) {
model.put("name", name);
return "greeting";
}
}
Stacktrace: https://pastebin.com/wtS2ubus
Problem: javax.servlet.ServletException: Circular view path [greeting]: would dispatch back to the current handler URL [/greeting] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
How can I debug this?
The circular path exception happens due to default ViewResolvers in spring. If your #GetMapping on path = 'path' returns a value which is also defined as a view in your project (html or equivalent, i.e path.html) then this error occurs.
As stated in the below source:
By default, the Spring MVC framework applies the InternalResourceView class as the view resolver. As a result, if the #GetMapping value is the same as the view, the request will fail with the Circular View path will occur.
One possible solution would be to rename the view and change the return value in the controller method.
If we don't want to rename the view and change the return value in the controller method, then another solution is to choose another view processor for the project.
Source:https://www.baeldung.com/spring-circular-view-path-error
I had a similar issue it was resolved by changing #Controller to #RestController

How to specify specific request mapping url

sorry i am new to spring boot and trying to learn, i have this code that when i run it will open a json request of my catalog item if i enter any url that is localhost/catalog/(any userid). But i want to narrow it to 1 specific userid how can i do that? for example i dont want any url to work except localhost/catalog/friends or any other item from the list i mention.
Code:
package com.poc.moviecatalog.controller;
import com.poc.moviecatalog.models.CatalogItem;
import java.util.Collections;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/catalog")
public class MovieController {
#RequestMapping("/{userId}")
public List<CatalogItem> getCatalog(#PathVariable("userId") String userId) {
return Collections.singletonList(
new CatalogItem("friends", "test", 9)
);
}
}
I hope I've understood your question correctly, you don't want to provide a mapping for any user id, but want one specific endpoint /catalog/friends.
#RestController
#RequestMapping("/catalog")
public class FriendsController {
#GetMapping("/friends")
public List<Friends> getFriends() {
....
}
}
then the url would be: http:<HOST>:<PORT>/catalog/friends

How to make localhost app publish to CloudFoundry as is: getting Resource not Available on CF

I have a basic Spring web app (Spring MVC Project) that I want to run on CloudFoundry. I took the default HelloWorld project and added to it. I've installed the CloudFoundry STS extensions, got a server created, publisd my app to the CF site. The 'home' page displays both on my localhost server, and the CF servers. All good. But, when I click on the only link to take me back into the HomeController to a different method/view, I get a 'Resource not available' error on the CF server, though it works perfectly on my localhost (local PC) server.
On my local PC:
The url is: http://localhost:8080/myapp (correct)
The initial page (home.jsp) displays with one link: Property (correct)
Mousing over the link shows this in the status bar: http://localhost:8080/myapp/property (correct)
Clicking takes me to the method mapped to /property and shows the property page (property.jsp). (correct)
On CloudFoundry:
The url is : http://myapp.cloudfoundry.com/ (correct)
The initial page (home.jsp) displays same as on my localhost PC. (correct)
Mousing over link shows this in status bar: http://myapp.cloudfoundry.com/myapp/property (correct, I think).
Clicking gets 'esource not available.
When I go up into the location window and remove myapp from the url, it works.
Below is all the code, but I think it's just some of my own misunderstanding of the two environments, my local PC, and CloudFoundry. Hopefully, someone can educate me on what I'm not knowing here to get the apps to work in both environements--locally, and on CloudFoundry.
Here is the HTML for home.jsp, the initial page
<html>
<head></head>
<body>
Property
</body>
</html>
The HomeController is:
package com.myapp.app;
import java.util.Locale;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.myapp.services.PropertyServicesImpl;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final String VIEW_HOME = "home";
private static final String VIEW_PROPERTY = "property";
private static final String ACQUISITIONS = "acquisitions";
#Autowired private PropertyServicesImpl propertyServices;
/**
* Shows home view
*/
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
return new ModelAndView(VIEW_HOME);
}
/**
* Shows Property.jsp with jQuery tabs.
*/
#RequestMapping(value = "/property", method = RequestMethod.GET)
public ModelAndView property(Locale locale, Model model) {
return new ModelAndView(VIEW_PROPERTY);
}
}
rather than putting a fixed value in your view it would be best to get the context path for the request and then adding that to the path in your view.
Add the following imports in to your Home controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
Then in the RequestMapping method get the current request object and create a UrlPathHelper instance and get the base path for the requests context;
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
UrlPathHelper helper = new UrlPathHelper();
String baseURL = helper.getContextPath(request);
So, when run from vFabric locally, baseURL will be "/myapp" and when run from a Cloud Foundry instance it will be ""
All that is left is to add this to the model and use it in the view;
model.addAttribute("relPath", baseURL);
I tested this with the Spring MVC template project in STS and it worked just fine, my HomeController looked like this;
package com.vmware.mvctest;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.sun.tools.internal.ws.processor.model.Request;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! the client locale is "+ locale.toString());
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
UrlPathHelper helper = new UrlPathHelper();
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
String baseURL = helper.getContextPath(request);
model.addAttribute("serverTime", formattedDate );
model.addAttribute("relPath", baseURL);
return "home";
}
}
and my view looked like this;
<%# page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world! (${relPath})
</h1>
home
<P> The time on the server is ${serverTime}. </P>
</body>
</html>
the context path in CF is {app.name}.cloudfoundry.com and not {app.name}.cloudfoundry.com/{app.name}
Replace in your jsp the Property with Property.

Resources