Java Servlet: pass a request back to default processing - java

I want a Servlet to handle requests to files depending on prefix and extension, e.g.
prefix_*.xml
Since mapping on beginning AND end of request path is not possible, I have mapped all *.xml requests to my Servlet.
The question now is: how can I drop out of my servlet for XML files not starting with "prefix_", so that the request is handled like a "normal" request to an xml file?
This is probably quite simple but I do not seem to be able to find this out... :-/
Thanks a lot in advance

another solution (maybe fits for you) is if you are using/plan to use an Apache in front of that web container instance you could use the rewrite module of apache. Rewriting the url to something more easy to handle for the Webapp container.
Hope this helps.
David.

I would strongly suggest using a proper MVC framework for this. As you've discovered, the flexibility of the standard servlet API is very limited when it comes to request dispatching.
Ideally, you would be able to use your existing servlet code in combination with an MVC framework, with the framework doing the diapcthing based on path pattern, and your servlets doing the business logic. Luckily, Spring MVC allows you to do just that, using the ServletForwardingController. It'd be a very lightweight spring config.
So you'd have something like this in your web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>foo.MyServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<url-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*</url-pattern>
</url-mapping>
You would then have a WEB-INF/spring-servlet.xml file like this:
<beans>
<bean name="/prefix*.xml" class="org.springframework.web.servlet.mvc.ServletForwardingController">
<property name="servletName" value="myServlet"/>
</bean>
</beans>
And that would be pretty much it. All requests for /prefix*.xml would go to myServlet, and all others would fall through to the container.

Not shure, but once you catch all *.xml requests you can inspect the request again in your code via HttpServletRequest.getRequestURI()
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri =req.getRequestURI();
int i = uri.lastIndexOf('/');
int j = uri.lastIndexOf('.', i);
if (uri.substring(i+1, j).startsWith("prefix_")) {
// your code
}
}
(code not tested, only an idea ...)

Related

Spring MVC Can't configure Dispatcher Servlet right

I'm having trouble configuring the Dispatcher for Spring. What I am trying to achieve is:
Build REST WebService to receive requests
Have HTML + Ajax pages consuming the data (Therefore, I don't have Views in my Spring project)
So far I have only 2 HTML pages: Login (using j_security_check) and Main page. Both very simple. I also have a simple controller:
MainController.java
#RestController //Or #Controller and #ResponseBody, no difference, right?
public class MainController {
#RequestMapping("rest/main/data")
public String getData () {
return "{data: \"DATA HUEHUE\"}"; // Yes, I'm brazilian
}
}
And I have tried the following configuration for web.xml and dispatcher-servlet.xml:
web.xml:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
dispatcher-servlet.xml
<context:component-scan base-package="com.example.controller"/>
This doesn't work. I get the message INFO: Mapped URL path [/rest/main/data] onto handler 'mainController' but when I try to access I get No mapping found for HTTP request with URI [/myapp/rest/main/data] in DispatcherServlet with name 'dispatcher'
I also have tried:
On web.xml: <url-pattern>/</url-pattern>
On dispatcher-servlet: The same
What happened: The controller DID work but the application also tried to map my login.html and couldnt find a match so I got 404 ;-;
I'm aware of that "standard" configuration using a prefix and a sufix, but since I dont have views here I dont think that's the right approach.
I'm kinda new at Spring (as you may have noticed), so please be gentle on the answers.
Any ideas?
Thanks in advance :)
My project tree:
-project
--src
---main
----webapp
-----WEB-INF
------web.xml
------weblogic.xml
------dispatcher-servlet.xml
-----www
------main.html
-----login.html
(Login is outside www)
With the first approach if you modify the controller code to have /rest/main/data It will work.
#RestController //Or #Controller and #ResponseBody, no difference, right?
public class MainController {
#RequestMapping("/rest/main/data")
public String getData () {
return "{data: \"DATA HUEHUE\"}"; // Yes, I'm brazilian
}
}
What is happening in happening in the second approach is that since you have Spring Security configured you need to be authenticated first but for that it finds the Login.html and can not find it. This may be because of incorrect configuration.

In a servlet mapping in Spring MVC how do I map the root of a url pattern directory?

<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
If I hit /test/page the above will work. However, hitting /test or /test/ will not work. I'm using Spring MVC, and my request mapping is as follows:
#RequestMapping(value = {"","/"})
EDIT:
I'm in the process of verifying with an independent project, but this appears to be a bug with Spring's UrlPathHelper. The following method returns an incorrect path when there is both a context and a servlet path, and you hit the servlet without a trailing slash.
public String getPathWithinApplication(HttpServletRequest request) {
String contextPath = getContextPath(request);
String requestUri = getRequestUri(request);
if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
// Normal case: URI contains context path.
String path = requestUri.substring(contextPath.length());
return (StringUtils.hasText(path) ? path : "/");
}
else {
// Special case: rather unusual.
return requestUri;
}
}
Just as an example let's say I have a context of "admin" and the following servlet-mapping:
<servlet-mapping>
<servlet-name>usersServlet</servlet-name>
<url-pattern>/users/*</url-pattern>
</servlet-mapping>
Now I have a request mapping in one of my controllers like this:
#RequestMapping(value = {"","/"})
If I hit /admin/users it will not work. However, if I hit /admin/users/ it will work. Now if I change my request mapping to the following then they will both work:
#RequestMapping(value = {"/users","/"})
However, now the URL /admin/users/users will also work (which is not what I would want).
Yevgeniy is correct, but if your DispatcherServlet is taking over for the default servlet, you have to add this to your web.xml:
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
my setup usually looks like this:
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
controller, where i assume you want to handle /test and /test/ equally:
#Controller
public class MyController {
#RequestMapping("/test")
public String test() {
return "redirect:/welcome";
}
#RequestMapping("/test/")
public String test() {
return "redirect:/welcome";
}
#RequestMapping("/welcome")
public void test(ModelMap model) {
// do your stuff
}
}
setup like this would cause DispatcherServlet to handle requests for *.css and *.js files, which is not desired in most cases. i think this is the problem Bhavik describes. For those resources you can you the ResourceController like this:
<mvc:resources mapping="/css/**" location="/resources/css/" />
<mvc:resources mapping="/js/**" location="/resources/js/" />
files from /resources/css and /resources/js will be served without forcing you to write a extra controller.
First of all, the difference between mapping dispatcher servlet to "/" and to "/*".
There is a difference!
When mapping to "/*", all URL requests (including something like this "/WEB-INF/jsp/.../index.jsp") are mapped to dispatcher servlet.
Secondly, when using Spring + Tiles, and returning some JSP in your tiles definition, it is treated as an internal forward request, and handled by the same servlet as the original request.
In my example, I invoke root URL "/", which is properly caught by home() method, and then forwarded to "index.jsp" by Tiles, which is again being handled by Dispatcher Servlet.
Obviously, dispatcher servlet cannot handle "index.jsp", because there is no controller for it.
Yeah, it is ugly, but looks like this is the way it works.
So, the only solution I've found so far: to change "/*" back to "/" in web.xml. This way JSPs are rendered properly by Tomcat's jsp servlet, I guess, and not dispatcher servlet.
Unfortunately, this fix will break the ROOT URL dispatching by Spring, so you need to leave the idea of using ROOT URL + Tiles for now.
Please note that adding explicit servlet mapping ".jsp -> Tomcat jsp in web.xml doesn't help, when using "/*", and it sucks.
Still the problem is not resolved.
Also this is the problem in Spring MVC 3.0
A way without touch the web.xml file is by set the map to the default welcome file path.
#RequestMapping("/index.html")
In my case, every url was working except of the root "/" url.
The problem was that i didn't deleted the index.htm file inside of my projects' webapp root folder.

Spring Framework Page Direction

Background: I'm relatively new to Java/Spring and inherited a project built on them. We're moving to AWS Elastic Beanstalk which changed the location of the main page for JSON requests from:
www.mywebsite.com/myApp/myAppJsonService
to:
www.mywebsite.com/myAppJsonService
That worked fine- all the functions that come out the JSON requests (most of them) are working perfectly. I have another page that takes a teacher's uploaded quiz via HTML form submit and parses the data. The form used to point to:
www.mywebsite.com/myApp/controllers/importQuiz
so I changed it to:
www.mywebsite.com/controllers/importQuiz
The web.xml file has:
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context/Controllers.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringDispatcher</servlet-name>
<url-pattern>/controllers/*</url-pattern>
</servlet-mapping>
And the corresponding Controllers.xml code:
<bean id="importExamController" class="com.myapp.controllers.ImportExamController">
<property name="commandClass" value="com.myapp.objects.spring.FileUploadBean"/>
<property name="myappManager" ref="myappManager"/>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/importExam">importExamController</prop>
<prop key="/heartbeat">heartBeatController</prop>
</props>
</property>
</bean>
The way I read it, regardless of the preceding "myapp" in the URL, it should find "/controllers/" in the URL, look to the Controllers.xml file and find the "/importExam" and direct it to the "importExamController". That's not happening. Clearly, there is a fault in my logic, and I can't seem to find it. Any help would be very much appreciated.
EDIT:
Doing some digging through the logs, I found:
INFO: WSSERVLET14: JAX-WS servlet initializing
Aug 27, 2011 7:21:06 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate doGet
SEVERE: caught throwable
ClientAbortException: java.net.SocketException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:373)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:327)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:396)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:385)
and it goes on for a while. To me it looks like that is confirming the idea that the data is trying to be sent to something that is incorrectly mapped. Let me know if this might mean something else or if it's just irrelevant.
First off, why in the world would you want controllers in your URL? Secondly, you have the right idea of how it should work, and you're probably correct about something not being configured correctly.
You should really read up on the enhanced MVC functionality in Spring 3.0+. With annotations and the mvc namespace, your code would look like (e.g.):
#Controller
#RequestMapping("importExam")
public class ExamController {
private final examService;
#Autowired
public ExamController(ExamService examService) {
this.examService = examService;
}
#RequestMapping(method=RequestMethod.GET)
public String getExams(ModelMap model) {
model.addAttribute("exams", examService.getExams());
return "exams";
}
}
And your controller is just:
<mvc:annotation-config/>
to load the controller and bind the request mappings to urls. This allows for wildcards too. The above controller would wire all URL request for /importExam to this controller, and process the default GET method at the base context. You could add nested methods with additional request mappings which would reside beneath the /importExam context.

dynamic URLs in java web application (like in rails)

I'm a Ruby on Rails developer programming a web application in Java. I am trying to achieve something similar to what is achieved in Rails. In Rails it is possible to call a link using localhost:8000\Users\1 when Users is a Model and 1 is the id of a specific user. I would like to get the same kind of thing in Java.
I am working in an MVC type design where my JSP pages are the view and my Servlets are the controllers. I created a servlet called Users which renders the users.jsp page now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Any idea how I can achieve this?
I'm doing this in a University project and am not allowed to use any frameworks. I also would rather something i could code rather than install.
now i can get to that page using the URL localhost:8000\projectName\Users, i would like to route localhost:8000\projectName\Users\1 to the page user.jsp while the appropriate Servlet will handle sending into the page the correct user (with id=1).
Simple. Map the servlet on an URL pattern of /Users/* instead of /Users. You can then grab the path info (the part after /Users in the URL, which is thus /1 in your example) as follows:
String pathInfo = request.getPathInfo();
// ...
You can just forward to users.jsp the usual way.
Long id = Long.valueOf(pathInfo.substring(1));
User user = userService.find(id);
request.setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/users.jsp").forward(request, response);
I would try this via a servlet and servlet mappings like that in web.xml
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/Users/*</url-pattern>
</servlet-mapping>
Than in your UserServlet try to get the full URL and parse it to your needs. Example:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String url = reg.getRequestURL();
//... get last part after slash and parse it to your id
}
See http://download.oracle.com/javaee/1.3/api/javax/servlet/http/HttpServletRequest.html for further documentation on the request and how its parameters can be retrieved
UrlRewriteFilter is like mod_rewrite but for Tomcat. You can use it to make your URLs SEO-friendly. You can also use Apache+mod_rewrite+Tomcat.

Can I have custom servlet URL in java?

I want that when user hits following URL:
http://host:8080/AppName/ServletName/Param1/Param2
It should go to a servlet named ServletName and Param1 and Param2 become request parameters. I have seen these kind of urls in ruby projects. Is it possible in Java?
If you are using Spring MVC you can map a #Controller and access the params as #PathVariable in a #RequestMapping.
#Controller
public class MyController {
#RequestMapping("/{param1}/{param2})
public Response get(#PathVariable("param1") String param1, #PathVariable("param2") String param2) {
//method body
}
}
Yes, you can do something like that with a servlet. You need to set the servlet mapping in web.xml like this:
<servlet-mapping>
<servlet-name>ServletName</servlet-name>
<url-pattern>/ServletName/*</url-pattern>
</servlet-mapping>
to get all requests and in the servlet you need to parse the result of HttpServletRequest.getPathInfo().
HttpServletRequest.getContextpath() seems interesting, even though i have never used it myself.
Sure you can, it's called REST, and you can get an intro here: http://download.oracle.com/javaee/6/tutorial/doc/giepu.html
You can also map servlets to wildcarded paths, so you could just map your servlet to /ServletName/* and get the /Param1/Param2 part from request.getPathInfo().
You can also achieve this with URL rewriting. There is also a servlet container equivalent available that works with a ServletFilter called UrlRewriteFilter.
I personally use Tapestry5 which natively encodes parameters this way.
I haven't done this,even haven't seen but try this
first map the url in the web.xml like this
<servlet>
<servlet-name>ServletName</servlet-name>
<servlet-class>ServletName</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletName</servlet-name>
<url-pattern>/ServletName/Param1/Param2</url-pattern>
</servlet-mapping>
and then get the url to a string using
String url=request.getRequestURI();
then you can split and get param1 and param2.

Categories

Resources