Spring MVC Multiple Controllers with same #RequestMapping - java

I am trying to make a web app that allows user to login from landing page index.htm. this action is mapped with a LoginController that after successful login takes user back to same index.htm but as logged in user and greets user with welcome message.
index.htm also have another form named itemform, that allows user to add in item name as text. This action is controlled by itemController.
My problem is both my LoginController and itemController have same #RequestMapping and hence I get this error:
Error creating bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0' defined in ServletContext resource [/WEB-INF/tinga-servlet.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler [loginController] to URL path [/index.htm]: There is already handler [com.tinga.LoginController#bf5555] mapped.
Cannot map handler [loginController] to URL path [/index.htm]: There is already handler [com.tinga.LoginController#bf5555] mapped.
How should I go about tackling this problem?

#RequestMapping(value="/login.htm")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) {
// show login page if no parameters given
// process login if parameters are given
}
#RequestMapping(value="/index.htm")
public ModelAndView index(HttpServletRequest request, HttpServletResponse response) {
// show the index page
}
Finally, you'll need a servlet filter to intercept the requests and if you're not requesting the login.htm page, you'll have to check to make sure the user is logged in. If you, you allow the filterchain to proceed. If not, you issue a forward to /login.htm
public class LoginFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
boolean loggedIn = ...; // determine if the user is logged in.
boolean isLoginPage = ...; // use path to see if it's the login page
if (loggedIn || isLoginPage) {
chain.doFilter(request, response);
}
else {
request.getRequestDispatcher("/login.htm").forward(request, response);
}
}
}
And in the web.xml
Example from my deployment descriptor:
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
This is all from memory, but it should give you the general idea of how to go about this.

Request Mapping for all controllers should be unique in Spring MVC.

Maybe in your controllers with the same #RequestMapping you should define the Method (GET, POST...), like this way:
#RequestMapping(value="/index.htm", method = RequestMethod.GET)
#RequestMapping(value="/index.htm", method = RequestMethod.POST)
The controller with the GET method you use to render the form and bind the data (some object) to it. The controller with POST method you usually use to process the submission and validation of the form.

Add an hidden parameter in your forms to differentiate them, then differentiate them by adding the params attribute in the annotation of your post methods.
<form:hidden name="hiddenAction" value="login" />
<form:hidden name="hiddenAction" value="item" />
#RequestMapping(method = RequestMethod.POST, params = {"hiddenAction=login"})
#RequestMapping(method = RequestMethod.POST, params = {"hiddenAction=item"})

Related

what is the importance of value attribute in request mappping of post method and this value is co-related in the project in spring mvc?

i have a request mapping with post method but i do not know what i should put in value attribute.
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String guestUserRegistration(#RequestHeader(value = "referer", required = false) final String referer,
final RegisterForm form, final BindingResult bindingResult, final Model model,
final HttpServletRequest request, final HttpServletResponse response, final RedirectAttributes redirectModel)
throws CMSItemNotFoundException
{
logger.info("guest User post method::");
return processGuestUserRequest(referer, form, bindingResult, model, request, response, redirectModel);
}
How the the "register" word as value is linked in spring mvc?
The HTTP method parameter has no default – so if you don't specify a value, it's going to map to any HTTP request.
#RequestMapping – by Path
In your example, you are mapping a request by path i.e "/register".
Request Mapping Basics
In Spring MVC applications, the RequestDispatcher (i.e. Front Controller) servlet is responsible for routing incoming HTTP requests to handler methods of controllers. When configuring Spring MVC, you need to specify the mappings between the requests and handler methods.
Test Mapping
To execute this mapping you just need to call this endpoint from your registoer action button. All API endpoints are relative to the base URL.
For example, assuming the base URL of https://api.example.com/, the /registor endpoint refers to https://api.example.com/registor.
https://api.example.com/registor
\______________________/\____/
server URL endpoint path

Possible misunderstanding of the doFilter method

I am actually pretty new to the Java EE specifications since I am kind of young. I never learned this things at school and I am facing a weird behaviour with the doFilter method.
Consider the following filter :
#WebFilter(filterName = "URLFilter", value = "/test")
public class URLFilter implements Filter {
public void destroy() {}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) resp;
if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND)
response.sendRedirect("/");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {}
}
There is no servlet or page present in /test and in my browser, the status is obviously a 404 not found error when accessing the URL and so should be the value returned to me by the getStatus() method which isn't. (actually having a 200 status code)
Why is my filter not redirecting me to / as requested ? Do I misunderstand the use of Filters in general ?
UPDATE:
My question was about redirecting the client (using the sendRedirect()) when a page is not found. I did not understand the filter part because I didn't know that resp and req are actually filled with the new data when chain.doFilter() is called. (which I actually found strange since the doFilter is calling the next Filter chained by the COR pattern)
I've made a class inheriting the HttpServletResponseWrapper, implemented it, passed it to the Filter and it's working fine now.
Your filter is invoked before trying to access the actual resource (servlet, page, file, whatever) located at /test. So the response status can't be 404 yet at this time.
Then your filter invokes chain.doFilter(), thus telling the container to actually serve the resource at /test. Since there is no such resource, you get a 404.

Skip request filter for specific resource in jersey

Iam working on a jersey project and Iam using token authentication and am using ContainerRequestFilter for filtering all the request and checking whether it has a token with it, but the requests includes Login and registration request, but we need to skip these request.. How i can skip the filtering for login and registration requests? Is there any mechanism in jersey for achieving this?
thank you
As far as I know, there is no facility fo such a behavior using a raw deployment descriptor (web.xml).
However, if that was a custom filter, you can get it skip the excluded paths using a simple check on request url in your doFilter() method. But since you are using a third party filter, that won't be the way to go with but still can have this functionality achieved:
Change your third party filter (ContainerRequestFilter) mapping to another path rather than a wildcard one:
<filter-mapping>
<filter-name>containerRequestFilter</filter-name>
<url-pattern>/tokenizedpaths/*</url-pattern>
</filter-mapping>
Declare a new filter (you will see in a moment what it looks like), that will be mapped to a wildcard path to filter all requests and be delegated to dispatch requests to your containerRequestFilter only if the request path does not match the excluded path(s) (I've choosen register as a sample):
<filter>
<filter-name>filteringFilter</filter-name>
<filter-class>com.sample.FilteringServletFilter</filter-class>
<init-param>
<param-name>excludedPaths</param-name>
<param-value>/register</param-value>
</init-param>
</filter>
The FilteringServletFilter will look like somthing like the following:
public class FilteringServletFilter implements Filter {
private List<String> excludedPaths = new ArrayList<String>();
public void init(FilterConfig config) throws ServletException {
// You can declare a comma separated list to hold your excluded paths
this.excludedPaths = Arrays.asList(config.getInitParameter("excludedPaths").split(","));
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String path = ((HttpServletRequest) request).getRequestURI();
// If the url is one of excluded paths, then just continue with next filter
if (this.excludedPaths.contains(path)) {
chain.doFilter(request, response);
return;
}
// Otherwilse, forward the request to the needed filter
else {
request.getRequestDispatcher("/tokenizedpaths" + path).forward(request, response);
}
}
}

AppEngine domain redirect using web.xml

I want to intercept all incoming requests e.g.
http://subdomain.domain.org/path/to/resource
to
https://appengineid.appspot.com/path/to/resource
for any possible /path/to/resource
Is this possible with the app engine web.xml deployment descriptor?
When I search this topic all the documentation or questions/answers relate to transforming/translating the /path/to/resource part of a request rather than the subdomain.domain.tld part?
Thanks
QUESTION EDIT/UPDATE:
Both of the above URLs point to the exact same instance of an app engine application. I don't want to URL pattern match on the /path/to/resource because this would "match" requests to both URLs. I want to URL pattern match on the domain part of the URL, so that any requests to subdomain.domain.org are redirected to appengineid.appspot.com, and then, so that no cycle is encountered any requests to appengineid.appspot.com are ignored by the redirecting filter and are handled by the rest of the web deployment descriptor.
It seems to be that a Filter will solve your problem.
You create a new filter in your web.xml, like this:
<filter>
<filter-name>yourFilterName</filter-name>
<filter-class>com.acme.filter.YourNewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>yourFilterName</filter-name>
<url-pattern>/path/to/resource/*</url-pattern>
</filter-mapping>
Your filter class will be something like this:
public class YourNewFilter extends MyGenericFilter implements Filter {
public void doFilter(final ServletRequest request,
final ServletResponse response,
FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
ServletContext context= getServletContext();
req.getRequestURL().toString() // use this method to get the end of the URL
RequestDispatcher rd= context.getRequestDispatcher("https://appengineid.appspot.com/path/to/resource/" + end of the URL
);
rd.forward(request, response);
}
}
It is gonna intercept all requests in one domain and dispatch it to another.

handleNoSuchRequestHandlingMethod override not working

#Controller
public class CentralizedExceptionController extends DefaultHandlerExceptionResolver {
#Override
protected ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("working?!");
return new ModelAndView();
}
I have this in my code, but in case of a 404 its never called.
(I dont have an error-page defined in my web.xml, and i dont want to)
Take a look at this jira issue: https://jira.springsource.org/browse/SPR-8837?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=72648#comment-72648
If your Spring dispatcher servlet is configured to process all/most URLs, then you are probably getting the 404 error along with this DispatcherServlet log message from console:
No mapping found for HTTP request with URI [xxx]
This indicates that Spring's DispatcherServlet is processing the request but do not have an appropriate #RequestMapping to dispatch to.
A simple solution would be to limit requests processed by dispatcher servlet by reconfiguring web.xml's servlet-mapping > url-pattern to only URLs specified by your application's #RequestMappings. However, this is NOT very practical (so don't do this).
One way to overcome this would be to create a #RequestMapping that handles all "unhandled" request mappings - some kind of fallback request mapping.
#RequestMapping("**")
#ResponseBody
public String fallbackRequestMapping() {
return "do something useful...";
}
Note that this answer is similar in approach to Dani's answer but written with annotation based development in mind. Therefore, it is useful to understand the associated Spring issue.
plz check. Your controller class name should not be Controller.java.
You need to use #ExceptionHandler annotation to your method:
#ExceptionHandler(NoSuchRequestHandlingMethodException.class)
public ModelAndView handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
...
}

Categories

Resources