How to use a URL like a parameter - java

I want a simple servlet that can be used without parameters. Something like :
http://servername:8080/do/view/username/address
and use it like a parameter :
http://servername:8080/do?action=view&login=username&page=address
Both urls will have the same behaviour. I prefer don't use any framework, only servlets and filters.
How can I obtain the url name from the servlet? What's the best solution?
Response:
Based on the reply made by #BalusC i have created the following servlet that do all i want:
#WebServlet("/do/*")
public class ActionTestCasesServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
String pathInfo = request.getPathInfo();
String[] parts = pathInfo.substring(1).split("/");
RequestDispatcher destination = getServletContext()
.getRequestDispatcher("/" + parts[0] + ".jsp");
if (parts.length > 1) {
request.setAttribute("username", parts[1]);
}
if (parts.length > 2) {
request.setAttribute("page", parts[2]);
}
destination.forward(request, response);
}
}
This code call the "view.jsp" passing the attributes "username" and "page".

Just map the servlet on /do/* instead of /do.
#WebServlet("/do/*")
This way you can obtain the path information using HttpServletRequest#getPathInfo().
String pathInfo = request.getPathInfo(); // /view/username/address
You can use the usual String methods like String#split() to split it in fragments.
String[] parts = pathInfo.substring(1).split("/"); // view, username, address
See also:
Design Patterns web based applications - for the case you intend to homegrow MVC (note: I don't recommend this, it's fun if it's for learning/hobby purposes, but if it's for real job, rather pick an existing MVC framework so that you can ensure that every pitfall is covered)

You say you'd prefer not to use "any framework, only servlets and filters", but have you considered the tuckey.org UrlRewriteFilter? This is a single filter that you can register in web.xml and then declare rules such as
<rule>
<from>/do/(.+)/(.+)/(.+)</from>
<to>/do?action=$1&login=$2&page=$3</to>
</rule>
in an XML file. Then you just write your servlets to expect the query parameters as normal and let the filter deal with the "pretty" URLs.

Spring MVC do it very very good. But if you do not want to use third-party frameworks all you can is handle request.getRequestURI(), split this string and do what you want. For example you can use pattern /entity/action.

I think previous threads reply are the perfect solution. I played with web.xml file to see what I can do for and here is my results. I was able to change the web.xml to get a url similar to what you want "http://localhost:8080/do/myServlet.do". Here is web.xml file content which pertains to the servlet-name and url-pattern.
<servlet>
<servlet-name>do</servlet-name>
<servlet-class>ControlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>do</servlet-name>
<url-pattern>/myServlet.do</url-pattern>
</servlet-mapping>
</web-app>

Related

How to pass on parameters from pretty URL to JSP pages?

I trying to do two things at once and I don't seem to find answers that can do both.
I'm trying this:
I want URLs ending in /user/{parameter} to be mapped to a JSP page user.jsp where I can access the parameter.
I find ways to pass parameters from the web.xml file to the JSP using this method
<init-param>
<param-name>someParam</param-name>
<param-value>itsValue</param-value>
</init-param>
And I find ways to create URL filters and map them to Java Servlets.
What I need is a combination. Also, what I found on passing URL parameters to Servlets wasn't too detailed either, so a good reference on that would also be more than welcome!
I want URLs ending in /user/{parameter} to be mapped to a JSP page user.jsp where I can access the parameter.
Map a servlet on /user/* and use HttpServletRequest#getPathInfo() to extract the path info.
E.g.
#WebServlet("/user/*")
public class UserServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo(); // "/{parameter}"
// ...
request.getRequestDispatcher("/WEB-INF/user.jsp").forward(request, response);
}
}
That's basically all. Use the usual String methods like substring() and/or split() to break down the path info in usable parts.
Use a base-url servlet to parse the URL and perform a conditional servlet forwarding to the appropriate JSP.
request.getRequestDispatcher().forward(JSPurl)
Let us say you have a URL branch /sales/. Under this URL branch, you would allow the following URLs to to be serviced by /implemented/usersales.jsp :
/sales/liquour/users/{region}
/sales/liquour/soft/users/{region}
/sales/toiletries/users/{type}
and the following URLs to be serviced by /implemented/products.jsp
- /sales/groceries/products/{section}
- /sales/groceries/meat/products/{region}
- /sales/groceries/vegetables/beans/products/{region}
You would have a web.xml servlet mapping for servlet class org.myorg.SalesHandler to be mapped to /sales/.
In the service method override in org.myorg.SalesHandler servlet class,
analyse the URL pattern (using regexp or otherwise) and then conditionally forward the request using
request.getRequestDispatcher().forward(JSPurl)
JAX-RS
But why would you do that when we have jax-rs?
How to forward from a JAX-RS service to JSP?.
JAX-RS may seem daunting at first, but it is actually very simple and intuitive to implement.

Handling URLs in a Java Serlvet

I am fairly new to servlets and the way I am handling repsonses from the client is using if uri matches a certain path such as:
public class EntryServlet extends HttpServlet
{
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws IOException
{
String uri = request.getRequestURI ();
if (uri.matches ("/1")) {
do something....
} else if (uri.matches ("/2")) {
do something else.....
} else {
throw error message...
}
}
}
This works only if my web service have a few pages. But say i have 50 xml documents and I want to map exmaple.com/1 to a xml ...to example.com/50 to another xml. Now it would be bad design to have 50 if else statements to handle each of the resource. What is a better way to implement this? I am trying to do this purely in java with no third party apps/plugins/frameworks
Update:
I am working with only one servlet with a background thread. Essentially a client request to process a file and the background thread handles the processing and stores xml docs in a db. And I want have each of the xml docs to be a resource on the web service.
You gave the answer "I want to map", so lets use a Map
you have 2 options (that i see now)
1: you put the "/1" as a key and put a String as value that map's to your xyz.xml
2: you put the "/1" as a key and put an object that implements an "Executor" interface...
in both cases you lookup the value for the key and then use the value object to return something useful.
Put this in the init of your Servlet and fill it with your objects:
Map<String,String> myActions = new HashMap<String,String>();
myActions.put("/1","one.xml");
.....
Now you can do this:
String uri = request.getRequestURI ();
if (myActions.containsKey(uri)) {
String value = myActions.get(uri);
do something with value
} else {
throw error message...
}
you can easily change this to option 2 by using object that implement this:
public interface Action {
String execute(HttpServletRequest req, HttpServletResponse res) throws ServletException,
IOException;
}
The answer may depend on what you want to do with the information in the URI. When writing a REST style application, the URI is one of the primary ways that information is passed to your application. So if you may want to re-consider your aversion to additional packages since the REST APIs are very popular for good reason.
Sticking with plain Servlets, lets say we have 50 xml documents that we want to serve based on which id number is passed through the URL.
We could store a table in a database that indicates the correspondence between id number and document. Or we could store this data into a CSV file. Either way, for such a relatively small table, I would just load the whole table into memory when the Servlet starts up. You can place code in an init() method for loading data into your application.
Then we have something like this:
static HashMap<Integer, String> fileMap;
public void init() {
fileMap = new HashMap<> ();
fileMap.put(1,"thing1.xml");
fileMap.put(2,"thing2.xml");
fileMap.put(3,"Otherthingy.xml");
}
Now you can write much cleaner code in your doGet method.
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws IOException {
String uri = request.getRequestURI();
int slash = uri.indexOf("/");
if(slash+1 == uri.length())
//throw an error
String idString = request.getRequestURI().substring(slash+1);
int id = Integer.parseInt(idString);
//should put this in a try catch block and throw an error if it is not a number.
String requestedFile = fileMap.get(id);
if(requestedFile == null)
//throw some error.
// Do whatever you need to do with the file.
}
You should
Move each URI specific logic into a different servlet.
Use the servlet mapping concept from Java Servlet Specification and define the following in your web.xml
<!- Define the servlets here, ofcourse you should use meaningful names -->
<servlet>
<servlet-name>servlet-1</servlet-name>
<servlet-class>com.vikdor.webapps.ServletForURI1</servlet-class>
</servlet>
<servlet>
<servlet-name>servlet-2</servlet-name>
<servlet-class>com.vikdor.webapps.ServletForURI2</servlet-class>
</servlet>
....
<!- Map the servlet to the URL pattern -->
<servlet-mapping>
<servlet-name>servlet-1</servlet-name>
<url-pattern>/1/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet-2</servlet-name>
<url-pattern>/2/</url-pattern>
</servlet-mapping>
....
This will push the routing logic to web.xml and each servlet does a specific job.
Use a framework. That's what they're for. I'm partial to Spring MVC but for a basic use case like this anything modern should be fine. It might feel like a pain to first get it setup but once it's configured development is much faster and much more maintainable.
Edit: I just noticed the original question says not to use any frameworks/libraries. I still stick by this answer though as the majority of the time that's a bad idea. If you really have to then you can create Maps as suggested by a few other people but in the long run it's not maintainable so avoid it while you can.
You can specify in your web.xml uri patterns to route to specific servlet classes. Forgive my bad servlet names.
<servlet>
<servlet-name>processUserXml</servlet-name>
<servlet-class>com.example.server.ProcessUserXml</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>processUserXml</servlet-name>
<url-pattern>/processuser</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>processItemXml</servlet-name>
<servlet-class>com.example.server.ProcessItemXml</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>processItemXml</servlet-name>
<url-pattern>/processitem</url-pattern>
</servlet-mapping>
So instead of accepting uri requests from a single gateway and routing them through if statements (as you're doing now), when a user calls a specific uri, it'll get routed to the appropriate servlet class for you. So calling uri /processuser will route the call to the ProcessUserXml servlet class doGet method (or doPost, if it's defined and that's how the user made the HTTP call).

Spring and returning protected resources

I have a pretty standard Spring 3.0.7 web app
The structure is like this
WebContent/
resources/
myStaticConent/
WEB-INF/
views/
myProtectedContent/
I am using the <mvc:resources> configuration for the static content and my controllers get views using the InternalViewResolver from WEB-INF/views
Now I have a requirement to return non-JSP content ( JPGs,PNGs,HTML,etc ) from a protected directory in WEB-INF
So a user might enter a URL like http:myWebApp/myProtectedContent and hit my protected content controller.
#Controller
public class HelloWorldController {
#RequestMapping(value="/myProtectedContent")
public String index() {
return "myjpg.jpg";
}
}
Essentially I want to conditionally serve a file just like I would a view. Anyone know how this can be done ?
I looked at some of the other methods here, Streaming using Inputstream seems overkill for files that are essentially static. Can I register another "view" type ? I need this to appear l( from the web browser side ) like a standard http request response ( like the current view implementation).
I would really like to avoid inventing my own file handling methods unless there is some reason why using the file access methods are better then Springs "other" view resolvers like ResourceBundleResolver
So the requirement is
Conditionally respond to a http request with variable file type (jpg,png,html) from inside WEB-INF without wrapping in a jsp or having the file interpreted by the JSTL view. The names of the files are known and static. The controller will determine the file name based on its own business logic.
You can reproduce the behavior of the underlying implementation of <mvc:resources/> which is org.springframework.web.servlet.resource.ResourceHttpRequestHandler, which essentially streams out the content of the static files - You can like ResourceHttpRequestHandler, extend from org.springframework.web.servlet.support.WebContentGenerator which has extensive support for sending last-modified and caching related headers, and finally to stream the content also there is a utility that Spring provides:
org.springframework.util.FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
Updated:
#Controller
public class HelloWorldController implements ApplicationContextAware {
ApplicatonContext ctx = ...;
#RequestMapping(value="/myProtectedContent")
public void index(HttpServletRequest req, HttpServletResponse res) {
Resource resource = ctx.getResource("classpath:staticpath/myjpg.jpg");
FileCopyUtils.copy(resource.getInputStream(), response.getOutputStream());
}
}
Something you can do is to map a new servlet to the path you want to be protected and handle the request the way you want.
For example, in web.xml:
<servlet>
<servlet-name>protServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/protServlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>protServlet</servlet-name>
<url-pattern>/myProtectedContent</url-pattern>
</servlet-mapping>
This way, you map a new servlet (DispatcherServlet) for URLs that are protected content.
The load-on-startup value equals 2 is due if you already have a DispatcherServlet with this field value equals 1.

RequestDispatcher.forward loop

I am using
<url-pattern>/*</url-pattern>
to map all the requests to one sevlet,where i do all the authentication work.
but I want to skip some static content (like css files).so I tried fowrding them from
that sevlet to where the resource file is
if(isResourceFile){
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("static/" + fileName);
dispatcher.forward(request, response);
}
but this will start a infinite loop because this will again call the same sevlet
is there any way to work around this without mapping all the resource(css) files in web.xml?
The url-pattern of /* is better to be used exclusively by Filters, not Servlets. Put all your static files in a certain folder (maybe covered by the url-pattern of a more effective FileServlet?) and let the Filter check it.
E.g. (pseudo)
public void doFilter(request, response, chain) {
if (requestURI.startsWith("/static")) {
chain.doFilter(request, response); // Just continue. Do nothing.
} else {
request.getRequestDispatcher("/pages").forward(request, response); // Forward to page controller.
}
}
Hope this helps.
Assuming that you're looking to authenticate just JSP files, you could change the URL:
/*.jsp
I think it's a better idea to handle your authentication using a filter rather than a servlet. And in a production environment, you should use a front-end webserver for static content.
In case you cannot use a filter and you have to use a wildcard '*' in the mapping without a extension like '.jsp' then then this could work for you:
if(isResourceFile){
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/static/" + fileName);
dispatcher.forward(request, response);
return;
}
Adding the '/' in the beginning of the static directory will give it root context.

URL Pattern for servlet mapping in web.xml

I need a workaround with this URL mapping in web.xml to create URLs with a letter, followed by a "_" followed by any combination of alphanumeric characters.
I want to map a servlet to something like this:
/something_*
Instead of:
/something/*
Using different "somethings" for different JSP's. Example:
/search_Something-I-searched-for
I tried using:
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/something_*</url-pattern>
</servlet-mapping>
But this doesn't seem to work.
This answer tells me I can't do this within web.xml, so maybe there's some workaround.
I don't know if this information is important, but I'm using JBoss and Struts2 in my project.
Map a servlet to the containing directory. Inside that servlet, take apart the URL path and forward to the appropriate named servlet.
Why not try Spring MVC Framework. Spring can offer that url mapping you want.
#RequestMapping(value="/something_{name}", method=RequestMethod.GET)
public String demo(#PathVariable(value="name") String name, ModelMap map) {
String something = name;
// Do manipulation
return "something"; // Forward to something.jsp
}
Watch this Spring MVC Framework Tutorial

Categories