Spring MVC : Request Mapping with matching sub paths - spring-mvc

I have 2 methods in a class with request mapping as below:
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String register(#ModelAttribute RegistrationForm registrationForm, Model model, HttpServletRequest request) {
}
and
#RequestMapping(value = "/two/register", method = RequestMethod.GET)
public String registerTwo(#ModelAttribute TwoRegistrationForm twoRegistrationForm, Model model, HttpServletRequest request) {
}
Is it possible that a call to /two/register will trigger /register because the subpaths match?
Have tried to debug this flow on local and everything works ok. However, when deployed onto a server and integrated to Site Minder - the above behaviour is observed.
Site Minder is configured to say -
if user hits /app -> forward to /app/register and
if user hits /app/two -> forward to /app/mgr/register

Related

Spring log request payload

I want to log every incoming request data and payload(body). How to configure that in Spring Boot? And how to hide sensitive data like password in logs?
Is it possible to log the original 'raw' request body (e.g. JSON)?
You could use AOP (Aspect Oriented programming) and intercept all the requests and log the info you need. Also you can filter which kind of requests need to log. An example with Spring-Boot could be this code
If you want to skip some methods from the logging in the aspect you can add this:
Create an annotation
#Retention(RetentionPolicy.RUNTIME)
public #interface NoLogging {}
#Aspect
#Component
public class LogsAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(EventAspect.class);
#Before("execution(* com.your.controller..*Controller.*(..)) && !#annotation(NoLogging)")
public void beforeController(JoinPoint joinPoint){
String packageName = joinPoint.getSignature().getDeclaringTypeName();
String params = getArguments(joinPoint);
String methodName = joinPoint.getSignature().getName();
//Log here your message as you prefer
}
}
And in any method from your Controllers, if you want to avoid the logging by aspects add the annotation
#RequestMapping(value = "/login", method = RequestMethod.GET)
#NoLogging
public ModelAndView loginUser(){
//actions
}
IMO, to log any incoming request should place at webserver level instead of application level.
For example, you could turn on/off access_log at Nginx.

URL with hash in Spring Mvc

everyone.
I'm using Spring MVC 4. My App sends activation url to user's email.
Activation url:
www.example.com:8080/myapp/user/activate/$2a$10$Ax2WL93zU3mqjtdxuYlYvuWWyQsPBhkhIfzYHJYk4rdNlAY8qCyC6
But, my App can't find path.
My controller:
#RequestMapping(value = "/user/activate/{hash})
public void activateUser(#PathVariable("hash") String hash) {
userService.activate(hash);
}
What am I doing wrong?
Update:
I've found out that if hash contains dot (".") then throws 404 error.
I've change my url:
www.example.com:8080/myapp/user/activate?code=$2a$10$Ax2WL93zU3mqjtdxuYlYvuWWyQsPBhkhIfzYHJYk4rdNlAY8qCyC6
and my controller:
#RequestMapping(value = "/user/activate)
public void activateUser(#RequestParam("code") String hash) {
userService.activate(hash);
}
It works perfectly.
you are not returning anything from the controller, hence receiving a 404
If you have dot (.) in your path variable value, then you must declare it explicitly in the RequestMapping, as shown below -
#RequestMapping(value = "/download/{attachmentUri:.+}", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<InputStreamResource> downloadAttachment(#PathVariable("attachmentUri") String attachmentUri,
HttpServletResponse response,
WebRequest webRequest) {
}

Spring 3 -- how to do a GET request from a forward

I'm trying to forward a request to another Spring controller that takes a GET request, but it's telling me POST is not supported. Here is the relevant portion from my first controller method, which does take a POST request, since I'm using it for a login function.
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#ModelAttribute("administrator") Administrator administrator,
Model model) {
// code that's not germane to this problem
return "forward:waitingBulletins";
}
Here is the method I'm trying to forward to.
#RequestMapping(value = "/waitingBulletins", method = RequestMethod.GET)
public String getWaitingBulletins(Model model) {
// the actual code follows
}
Here is the error message in my browser.
HTTP Status 405 - Request method 'POST' not supported
--------------------------------------------------------------------------------
type Status report
message Request method 'POST' not supported
description The specified HTTP method is not allowed for the requested resource (Request method 'POST' not supported).
forward maintains the original request intact, so you are forwarding a POST request and missing a handler for it.
By the looks of it, what you're really trying to implement is the POST-redirect-GET pattern, which uses redirect instead of forward.
You only need to change your POST handler to:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#ModelAttribute("administrator") Administrator administrator,
Model model) {
// code that's not germane to this problem
return "redirect:waitingBulletins";
}
to make it work.

Spring-MVC 3.1: Forwarding A Request From One Controller Function To Another

I'm using Spring 3.1. I have a controller function that takes in a command object ( a data holder ) submitted via a FORM and does some processing :
#RequestMapping(value = "/results", method = RequestMethod.POST)
public String toResultsScreen(#ModelAttribute("ssdh") SearchScreenDataHolder ssdh,
BindingResult bindingResult,
ModelMap model,
HttpSession session) {
if (bindingResult.hasErrors()) {
logger.debug("Error returning to /search screen");
return "search";
}
netView = "results";
// do stuff
return nextView;
} // end function
Some user would like to programmatically make GET links to obtain information from our site and I would like to set up another handler that would handle that request. It would create a new installation of that the command object ( ssdh ) and populate it with the parameters sent via the GET request. Then it would pass it on to the handler above. Something like this:
#RequestMapping(value = "/pubresult")
public String toPublicResultsScreen(ModelMap model,
HttpSession session,
#RequestParam (required=true) String LNAME,
#RequestParam (required=false)String FNAME){
Search search = new Search(usertype);
// Capture the search parameters sent by HTTP
ssdh.setLast_name(LNAME);
ssdh.setFirst_name(FNAME);
// To Do: "forward this data holder, ssdh to the controller function quoted first
return nextView;
} // end function
My question is how can I forward my command/data holder object to the first controller function such that I don't have to alter the code to the first controller function in any way?
You can use RedirectAttributes object which was introduced in Spring MVC 3.1 and populate it with data you want to keep for redirection. It called PRG (POST/Redirect/GET) pattern.
#RequestMapping(value="/saveUserDetails.action", method=RequestMethod.POST)
public String greetingsAction(#Validated User user,RedirectAttributes redirectAttributes){
//setting attributes
redirectAttributes.addFlashAttribute("firstName", user.getFirstName());
redirectAttributes.addFlashAttribute("lastName", user.getLastName())
return "redirect:success.html";
}
I wrote some technical article regarding how to use it. I believe it will give you more details:
http://www.tikalk.com/java/redirectattributes-new-feature-spring-mvc-31
You should be able to set the ssdh in a ModelAttribute and simply forward it back, this way, the RequestDispatcher should be able to map it back to the /results handler:
#RequestMapping(value = "/pubresult")
public String toPublicResultsScreen(ModelMap model,
HttpSession session,
#RequestParam (required=true) String LNAME,
#RequestParam (required=false)String FNAME, Model model){
Search search = new Search(usertype);
// Capture the search parameters sent by HTTP
ssdh.setLast_name(LNAME);
ssdh.setFirst_name(FNAME);
model.addAttribute("ssdh", ssdh);
return "forward:/results";
}
Use
org.springframework.web.servlet.view.RedirectView
class from spring package to redirect to different page in spring MVC controller. The Baeldung blog page has more details
Sample code:
#RequestMapping(value = "/", method = RequestMethod.GET)
public RedirectView mainMethod() {
return new RedirectView("/login");
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView mainLogin() {
ModelAndView model = new ModelAndView("login");
return model;
}

how to get controller method name in Spring Interceptor preHandle method

In my application based on spring mvc and spring security I am using #Controller annotation to configure controller.
I have configured Spring Handler Interceptor and in preHandle() method , I want to get method name which is going to be call by interceptor.
I want to get custom annotation defined on controller method in preHandle() method of HandlerInterceptor so that I can manage by logging activity for that particular method.
Please have a look at my application requirement and code
#Controller
public class ConsoleUserManagementController{
#RequestMapping(value = CONSOLE_NAMESPACE + "/account/changePassword.do", method = RequestMethod.GET)
#doLog(true)
public ModelAndView showChangePasswordPage() {
String returnView = USERMANAGEMENT_NAMESPACE + "/account/ChangePassword";
ModelAndView mavChangePassword = new ModelAndView(returnView);
LogUtils.logInfo("Getting Change Password service prerequisit attributes");
mavChangePassword.getModelMap().put("passwordModel", new PasswordModel());
return mavChangePassword;
}
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// here I want the controller method name(i.e showChangePasswordPage()
// for /account/changePassword.do url ) to be called and that method annotation
// (i.e doLog() ) so that by viewing annotation , I can manage whether for that
// particular controller method, whether to enable logging or not.
}
I am using SPRING 3.0 in my application
Don't know about the Handler interceptor, but you could try to use Aspects and create a general interceptor for all your controller methods.
Using aspects, it would be easy to access your joinpoint method name.
You can inject the request object inside your aspect or use:
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
To retrieve it from your advice method.
For instance:
#Around("execution (* com.yourpackages.controllers.*.*(..)) && #annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object doSomething(ProceedingJoinPoint pjp){
pjp.getSignature().getDeclaringType().getName();
}

Resources