How to set default handler method in controller in Spring mvc? - java

I am working on a Spring mvc application in which I have to display a list of locations. I have a controller method for location. Following is my controller method code:
#RequestMapping("/location")
public class LocationController {
#RequestMapping(value = "/home")
public String showAllLocations(ModelMap modelMap) {
logger.info("showAllLocations() begins:");
try {
List<LocationModel> locationList = locationService
.getAllLocations("");
modelMap.addAttribute("locationlist", locationList);
} catch (Exception e) {
logger.debug("Error while getting locations: " + e.getMessage());
e.printStackTrace();
}
return "LocationHome";
}
}
It works fine when I user following URL:
http://www.example.com:8080/myapp/location/home
But when I use http://www.example.com:8080/myapp/location, it shows error.
How can I view location list without using 'home', by following URL:
http://www.example.com:8080/myapp/location

#RequestMapping(value = "/home")
public String doHome(ModelMap modelMap) {
...
}
#RequestMapping(value = "/**")
public String doDefault(ModelMap modelMap) {
...
}
Make sure you put more specific request handler before less specific one.

#RequestMapping(value = "/", method = { RequestMethod.GET, RequestMethod.POST })
This can map you to a default handler.

You have the request mapping for the LocationController here ,
#RequestMapping("/location")
public class LocationController {..}
So all the URL to be intercepted by this controller should have the pattern /location followed by the method request mapping as here ,
#RequestMapping(value = "/home")
public String showAllLocations(ModelMap modelMap) {..}
If you need to intercept the request for http://www.example.com:8080/myapp/location . Just remove the url mapping from the controller and assign it to the method.

Related

Spring -MVC use session attribute in controller

I have a method where I require the argument name and I have it set as a session attribute as it will be fixed through out the session. However, I have trouble adding it to the function. Any help is appreciated.
LoginController class that sets the session attribute
#Controller
#SessionAttributes({"name", "date"})
public class LoginController {
#Autowired
LoginService service;
/*
* Map /login to this method
* localhost:8080/spring-mvc/login
* spring-mvc -> dispatcher (todo-servlet.xml)
* dispatcher detects login url
* dispatcher use view resolver to find .jsp file based on String. In this case, login
* view resolver locates login.jsp and shows the content to user via http
*/
#RequestMapping(value = "/test")
// Mark this method as an actual repsonse back to user
#ResponseBody
public String test() {
return "Hello, world!";
}
#RequestMapping(value ="/")
public String returnLogin() {
return "redirect:/loginPage";
}
// Only handles get request from the login page
#RequestMapping(value = "/login", method= RequestMethod.GET)
public String loginPage() {
// search through the view resolver for login.jsp
return "login";
}
// Only handles post request from the login page
#RequestMapping(value = "/login", method= RequestMethod.POST)
// #RequestParm to be used for user input
// Model is used to supply attributes to views
// ModelMap has the same functionality has model except it has an addition function where it allows a collection of attributes
public String handleLogin(#RequestParam String name, #RequestParam String password, ModelMap model) {
if (service.validateUser(name, password)) {
// Send name to .jsp
// use addAttrible( nameAtJSP, nameInRequestParam ) to check for null
model.addAttribute("name", name);
model.addAttribute("passWelcome", password);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
String date = sdf.format(new Date());
model.addAttribute("date", date);
}
else {
model.put("errorMessage","Invalid credentials");
return loginPage();
}
return "welcome";
}
My controller class. I've commented the part that I need to add the session attribute.
#Controller
public class ToDoController {
#Autowired
private ToDoService service;
#RequestMapping(value = "/list-todo", method= RequestMethod.GET)
public String showToDo(ModelMap model, String name, String date) {
model.addAttribute("toDos", service.retrieveTodos("in28Minutes"));
model.addAttribute("name", name);
model.addAttribute("date", date);
// Only returns to the jsp
return "list-todos";
}
#RequestMapping(value = "/add-todo", method= RequestMethod.GET)
public String addToDo() {
return "addToDo";
}
#RequestMapping(value = "/add-todo", method= RequestMethod.POST)
public String addToDo(ModelMap model,#RequestParam String description) {
// SESSION ATTRIBUTE NAME
model.addAttribute("name");
service.addTodo((String) model.get("name"), description, new Date(), false);
model.clear();
return "redirect:/list-todo";
}
#SessionAttributes doesn't do what you are trying to achieve.
From javadoc of #SessionAttributes:
NOTE: Session attributes as indicated using this annotation correspond
to a specific handler's model attributes, getting transparently stored
in a conversational session. Those attributes will be removed once the
handler indicates completion of its conversational session. Therefore,
use this facility for such conversational attributes which are
supposed to be stored in the session temporarily during the course of
a specific handler's conversation.
For permanent session attributes, e.g. a user authentication object,
use the traditional session.setAttribute method instead.
So, what you need to do is:
public String handleLogin(#RequestParam String name,
#RequestParam String password,
ModelMap model,
HttpSession httpSession) {
// your code here
httpSession.setAttribute("name", name);
// your code here
}
And then you can retrieve this session attribute in your ToDoController as httpSession.getAttribute("name");

How to access the session variable in one controller to the other controller in SpringMVC?

I had one login controller in that I define one session variable, now I want to access that session variable in all my remaining controllers in my application?
this is my login controller code snippet
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
HttpSession session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
This is my ProfileController code snippet
#Controller
public class ProfileController {
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
HttpSession session=req.getSession();
String loggedInUser=(String)session.getAttribute("username");
System.out.println("UserName is "+ loggedInUser);
Now I want to access this session variable(username) in my another profile controller. I tried like this but I got null pointer expection in ProfileController.
I found the solution to my requirement.
actually, my requirement is to access the session value from the login controller to profile controller.
So What I did is instead of accessing the session variable in profile controller, just I am calling a method in login controller that will return my required value.
#Controller
public class LoginController {
private HttpSession session=null;
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
}catch(Exception e)
{
}
}
public String getUserName()
{
return session.getAttribute("username");
}
}
ProfileController
#Controller
public class ProfileController {
#Autowired
private LoginController loginControllerObj;
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
String loggedInUser=loginControllerObj.getUserName();
System.out.println("UserName is "+ loggedInUser);
As per my understanding, in my question. I got null pointer exception in Profile controller this is because of if we want to access the session then we need to call the request.getSession()
the method that will return if any session is associated with the request then it will return that one if not then it creates a new session.the same concept in my profile controller also applied.
Instead of accessing the existing session in will create the new session because of both are two different requests.
For this reason, I follow the above code get rid of my requirement.
if it is about current logged in username then you just pass Principal parameter to controller method.
#RequestMapping(value="/login", method = RequestMethod.GET)
public String methodName(ModelMap model, Principal principal ) {
String name = principal.getName(); //get logged in username
model.addAttribute("username", name);
return "page";
}

Spring boot: how to match all routes?

I'm developing a simple web application on Spring boot 1.5.3 and I need all the routes to send static index.html file. Now, I have this:
#Controller
public class IndexController {
#RequestMapping("/*")
public String index(final HttpServletRequest request) {
final String url = request.getRequestURI();
if (url.startsWith("/static")) {
return String.format("forward:/%s", url);
}
return "forward:/static/index.html";
}
}
My application contains only static assets and REST API. But the problem is that the controller shown above only matches the first-level url like /index, /department etc. I want to match all url levels like /index/some/other/staff etc. How can I do that?
PS. I've tried to use the template /** in #RequestMapping, but my application has broken with the StackOverflow error.
UPDATE
If add one more level to url, then all will work as expected:
#Controller
public class IndexController {
#RequestMapping("/test/**")
public String index(final HttpServletRequest request) {
final String url = request.getRequestURI();
if (url.startsWith("/static")) {
return String.format("forward:/%s", url);
}
return "forward:/static/index.html";
}
}
All requests to /test, /test/some/other/staff will return index.html, but I need to start with /.
Above answer didn't really work for me. As per official Spring doc it should be done like this:
#RequestMapping(value = "{*path}", method = RequestMethod.GET)
#ResponseBody
public String handleAll(#PathVariable(value = "path") String path) {
log.debug("Requested path is: {}", path);
return "forward:/static/index.html";
}
You can try this:
#Controller
public class IndexController {
#RequestMapping(value = "/**/{path:[^\\.]*}")
public String index(final HttpServletRequest request) {
final String url = request.getRequestURI();
if (url.startsWith("/static")) {
return String.format("forward:/%s", url);
}
return "forward:/static/index.html";
}
}

Adding custom Spring Security filter on controller method using annotation?

I have written a custom strong authorization server and libraries for integration called PowerAuth 2.0.
Currently, the developer who tries to secure the API call with it can use it as such:
#Controller
#RequestMapping(value = "/session")
public class AuthenticationController {
#Autowired
private PowerAuthAuthenticationProvider authenticationProvider;
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody String login(
#RequestHeader(value = "X-PowerAuth-Authorization", required = true) String signatureHeader,
HttpServletRequest servletRequest) throws Exception {
PowerAuthApiAuthentication apiAuthentication = authenticationProvider.validateRequestSignature(
servletRequest,
"/session/login",
signatureHeader
);
if (apiAuthentication != null && apiAuthentication.getUserId() != null) {
return "OK";
} else {
return "NOT OK";
}
}
}
I would like to simplify the work for the developer though, so that the code can look like this:
#Controller
#RequestMapping(value = "/session")
public class AuthenticationController {
#RequestMapping(value = "/login", method = RequestMethod.POST)
#PowerAuth(value = "/session/login")
public #ResponseBody String login(PowerAuthApiAuthentication apiAuthentication) throws Exception {
if (apiAuthentication != null && apiAuthentication.getUserId() != null) {
return "OK";
} else {
return "NOT OK";
}
}
}
Principle (probably?):
Remove the need for autowired authentication provider
Replace the signature verification call with a custom request filter
Bind the request filter to a custom annotation with parameters
Inject the resulting authentication object in a method parameter
Since I am not strong in Spring, could you please provide me a guidance on how to do this?

How to access a PathVariable of a controller specified at class level in Spring?

Can I do something like this with Spring MVC ?
#RequestMapping(value = "/{root}")
public abstract class MyBaseController {
#PathVariable(value = "root")
protected ThreadLocal<String> root;
}
#Controller
public class MyController extends MyBaseController {
#RequestMapping(value = "/sayHello")
#ResponseBody
public String hello() {
return "Hello to " + this.root.get();
}
}
When I request to http://..../roberto/sayHello, I get this as response:
Hello to roberto
You can have a path variable in the controller URL-prefix template like this:
#RestController
#RequestMapping("/stackoverflow/questions/{id}/actions")
public class StackOverflowController {
#GetMapping("print-id")
public String printId(#PathVariable String id) {
return id;
}
}
so that when a HTTP client issues a request like this
GET /stackoverflow/questions/q123456/actions/print-id HTTP/1.1
the {id} placeholder is resolved as q123456.
you can code like this:
#RequestMapping("/home/{root}/")
public class MyController{
#RequestMapping("hello")
public String sayHello(#PathVariable(value = "root") String root, HttpServletResponse resp) throws IOException {
String msg= "Hello to " + root;
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
out.println(msg);
out.flush();
out.close();
return null;
}
}
and the result like this:
and,you can use ModelAndView return msg value to the jsp or other html page.
According to the docs:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html
the PathVariable annotation is itself annotated with #Target(value=PARAMETER) so it shouldn't be possible to be used the way you're saying as it's only applicable to method parameters.

Categories