Java web.xml page routing - java

So here is my problem, I am somewhat new to programming, and now I want to make "web.xml" in Java EE project, to rout every url that contains "/profile/" to a profile page, where depending on the id after "/profile/" it'll show current users data. I have the servlet mapped as below...
<servlet-mapping>
<servlet-name>RoutServlet</servlet-name>
<url-pattern>profile/*</url-pattern>
</servlet-mapping>
But what I am supposed to do in the servlet so I can get the id, and show current users data?
Please give me an advice, or nice resource where I can see how it's done.
Thank you in advance ! :)

That looks fine for the web.xml. In short, if you're using a JAX-RS implementation (e.g. Jersey), you should use the #Path annotation with #PathParam for the parameters, so something like:
#Path("/profile")
public class ProfileService {
#GET
#Path("/{id}")
public Profile getProfile(#PathParam("id") String id) {
//...
}
See the Oracle guide on RESTful Web services for some more background.

Firstly I would change tha mapping to the following:
<servlet-mapping>
<servlet-name>RoutServlet</servlet-name>
<url-pattern>/profile</url-pattern>
</servlet-mapping>
Secondly in RoutServlet you should have a the following code to get the userId
int userId = Integer.parseInt(req.getParameter("userId"));
And finally any URL's that sends a request to RoutServlet should look like this
http://someurl.com/profile?userId=//someId
This way you can let RoutServlet retrieve all the information of the User depending on what Id is in the GET request.
I would let RoutServlet put all the data it retrieves in an ArrayList<Object> profileData, redirect to a JSP and retrieve the data there using Expression Language, but I dont know what you use/prefer to display the data.

Related

SpringMVC - dispatcher servler's url pattern style

I am trying to build a restful style API, using springMVC.
When config the url-pattern for springMVC's DispatcherServlet, there seems to have 2 choice, and I need some advice.
Choice A:
config pattern as: <url-pattern>*.action</url-pattern>
and action use path like #RequestMapping("/role/add.action")
Choice B:
config pattern as: <url-pattern>/api/*</url-pattern>
and action use path like #RequestMapping("/api/role/add")
I prefer to use a style that has no suffix, but in that case I need do add a sub path.
But I am not sure which is more proper to use in a project that serve as a backend to provide restful API, with browser / IOS / Android as its client.
There might be a choice C, but I am not sure:
config pattern as: <url-pattern>/*</url-pattern>
and action use path like #RequestMapping("/role/add")
In this case built-in servlet will be override, e.g jsp won't work normally.
But I don't have any jsp, and also, static resource like html / js / css / image / document / music / video are all put on another port or server served by nginx, request to tomcat only provide ajax service via json data.
So in this case is it proper to use choice C, or it has some bad side-effects?
if your goal is restful api my choice is the second one since you identify the resource in the url; say you must manage a role resource you should have some mapping like these ones:
#RequestMapping("/api/role" method = RequestMethod.POST)
to insert a new role (may be the api does not allow this)
#RequestMapping("/api/role/{roleId}" method = RequestMethod.PUT)
to update an existing role
#RequestMapping("/api/role/{roleId}" method = RequestMethod.DELETE)
to delete a role
#RequestMapping("/api/role" method = RequestMethod.GET)
to retrieve roles (you may implement some filters via query string)
The same applies for other resources (User, etc) the naming schema is the same.
I vould avoid option C since I think it's best to have a dedicated mapping for the api if you app also ship a web interface that does not use the api
I will go with the Choice B for RESTful services, consider performing CRUD operations using REST. And you can map the url-pattern as ,
config pattern as: <url-pattern>/api/*</url-pattern>
So to perform add , you can just make sure that you post the JSON object from the page and have a url like /api/add
And in case of delete , you can simply follow the same . Consider you are going to delete a object from the list using its id . You can simply make it out as,
/api/delete/${id}
And handle it like ,
#RequestMapping(value="/{id}", method=RequestMethod.GET)

Mapping a RESTful URL to a static HTML page, in a Java web app

I have a Java web app that runs in JBoss. I'm adding a new web page for applying for a job, using AngularJS, and I'd like it respond to this (RESTful) URL: /job/<job id>/apply
Since I'm new to Angular, I'm trying to figure out how to route the user's request of a URL like:
GET /job/1/apply (where "1" is the job id)
to a static HTML page in my web app, like src/main/webapp/job/apply.html. My plan is to have an ng-app and ng-controller specified in the apply.html template, which will call back to the server to fetch JSON to render in the view.
So how do I configure routing in my Java-based web app, so that requesting /job/1/apply yields /job/apply.html, and my controller JS code that's loaded by apply.html has easy access to the URL parameter "1"?
I've come up with several potential ways of accomplishing this, but none of them seem very simple or straightforward:
Use Spring MVC, write an #Controller that listens to the RESTful URL, and forwards the request to apply.html. (I'm not even using Spring MVC in this web app... yet.)
Use Spring MVC and the <mvc:resources> or <mvc:view-controller> element, to map the requested URL to the HTML page.
Use a web filter to rewrite the incoming URL to /job/apply.html.
Give up on using a RESTful URL, make the job ID a query param instead, and rename my apply.html to just index.html (so it gets picked up automatically). E.g. the user requests /job/apply?jobId=1, which maps to webapp/job/apply/index.html.
The thing I'm most uncertain about is whether the job ID in the request URL will be available to my angular controller code, in order to fetch data from the backend about that job.
Redirect every request server-side to index.html when not requesting a file and use ng-route (http://docs.angularjs.org/api/ngRoute.$route) to load the correct template with something like
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/job/:jobid/apply', {
templateUrl: '/job/apply.html'
}).
otherwise({
redirectTo: '/'
});
}
]);
If you can make use of the "html5 mode" of ngLocation (http://docs.angularjs.org/guide/dev_guide.services.$location) that would be even cleaner for the end user.

How do I catch or raise exceptions inside a Viewable object in a restful service

I want to be able to return a specific jsp page from restful service given the page name as a PathParam. These pages will be added and removed by a different group of people after the application is deployed.
I believe using the Viewable object is a decent way to go (I'm open to a better/correct way.)
#GET
#Produces(MediaType.TEXT_HTML)
#Path("{page}")
public Response showJSP(#PathParam("page") String page) {
Viewable loadPage = null;
try {
loadPage = new Viewable("/" + page, null);
} catch (Exception e) {
return Response.status(404).build();
}
Response ret = Response.ok(loadPage).build();
// if (ret.getStatus() == 500){
// ret = Response.status(404).build();
// }
return ret;
}
The above is my experimental code and contains my attempts to handle the error.
This works fine as long as the page name is a valid jsp page. If I pass in an invalid page I get
500 Internal Server Error
java.io.IOException: The template name, /someWrongFileName, could not be resolved to a fully qualified template name.....
What I've figured out is this error is generated internal to the Viewable object so it's not throwing an exception and the Response of course is a valid page so checking for the 500 status doesn't work.
I can hack in several things that I'm pretty sure are wrong such as, I really do not want to toString the generated page and regex for the error text.
I would like to be able to detect that the page is invalid and simply return a 404.
Am I on the right path or is there a better way?
If I'm on the right path how do I detect the bad page name?
I've tried catching the error like you did but it seems pretty hard. I suppose the class was never intended to be used this way.
The Viewable interface lets you use JSPs as a means to visualize the representation of your application's resources. In general, the resource is represented by a POJO that you serialize to JSON, XML or pass to the Viewable constructor.
As far as I understand, what you're trying to do here is a little different. Your resources are the JSPs themselves and it seems you only want to make the pages available to clients, without passing any objects to the Viewable constructor.
The HTTP 404 error means that a resource can not be found. In your case (while treating the JSPs as resources), when the path to a JSP is incorrect, this is exactly what happens so I understand why you want to use the status code.
However, I think that the creators of the interface you're trying to use had a different opinion on the matter. They didn't see the JSPs as resources but as a tool to represent them. The construction of a view is seen here as a completely different thing. A matter internal to the server and something that should be hidden from the client. The client has to receive a response with an HTML string in it. How it happens should not matter at all. An HTTP 500 is totally understandable in such context.
If you only want to use GET requests to fetch the contents of your JSPs, you can just ignore the Viewable interface or even Jersey itself. If your web.xml is appropriately set, the pages should be accessible anyway. You don't have to pass a JSP name to an annotated method. Just use paths to the documents themselves. Custom 404s can be dealt with in web.xml as well.
Assume that you have a project called MyApp and deployed to the path <host>:<port>/MyApp
With the following structure of its Web pages directory.
-Web pages
|-META-INF
|-WEB-INF
|-error
|\-error404.jsp
|-package1
||-ResourceClass
||\-page1.jsp
|-pages
||-plainpage1.jsp
|\-plainpage2.jsp
\-index.jsp
Now, let's assume the web.xml looks like this:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/resources/ *</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/err/err404.jsp</location>
</error-page>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
You can use the Viewable interface to show a page for your actual resource. This is how the interface is supposed to be used. As a means to show a resource's html representation, not the resource itself.
package package1;
#Path("/")
public class ResourceClass {
#Path("/POJO/{id}")
#GET
public Response tryToGetBadView(#PathParam("id") String id) {
MyPOJOClass entity = null;
//fetch your POJO from database/file/whatever
return Response.ok().entity(new Viewable("page1",entity)).build();
}
}
You can get the appropriate view using a path like:
<host>:<port>/MyApp/resources/POJO/1
while also being able to get the plain JSPs without the help of Jersey Servlet Container. The files are there and they don't need any other representation than themselves. The path to your Jersey Servlet Container is specified as
<host>:<port>/resources/*
So you can omit the container and reach normal files from your Web Apps folder. Images, css and also JSPs.
Like this:
<host>:<port>/MyApp/pages/plainpage1.jsp
the same way you get
<host>:<port>/MyApp/index.jsp
and even a page that you'd normally use to construct a Viewable object (without the guarantee that it would work properly without passing a POJO)
<host>:<port>/MyApp/package1/ResourceClass/page1.jsp
For these "static" files, you'll get a 404 every time you pick a name of a non-existent page. The error page displayed will be the one specified in web.xml
This is how I'd do it. Using Jersey to serve plain JSPs seems like an overkill and brings unnecessary complication. If it's not what you meant, I suggest rethinking the design.
Notice that while Jersey is not used, the pages can still be accessed in a way you can consider RESTful.
If you really want to stick to your experimantal code, you can also try accessing the directories in your Web Pages folder using the IO API and checking manually whether the requested files exist. It'd be ugly but it might just work.
I found what I'm looking for in another post and modified my method below.
#GET
#Produces("text/html")
#Path("{page}")
public void showJSP(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
request.getRequestDispatcher(page + ".jsp").forward(request, response);
}
This gives me my 404 that I'm looking for and all of my services still work.
If this is the 'wrong' way to do this I'm still open for ideas but for now it works.

Making custom URL in Java EE web-application

I'm writing a simple little application, which is a booking system. In the system there are two roles: administrator and user. All requests are working through the only servlet. Index.jsp (loginpage for user and admin) works without its help. So I have the starting url looking like this:
localhost:8080/[AppName]/index.jsp
To ensure security, I wrote a filter that will not allow anonymous users going to any page, except index.jsp; admin go on user page, and user go on admin page. But the problem is that I can't map the filter properly, because all the URLs in my app look like:
localhost:8080/[AppName]/servlet?command=[commandName]
Because of this, such a mapping, like (of course, in the web.xml the filter has already described before this mapping):
<filter-mapping>
<filter-name>Security</filter-name>
<url-pattern>/servlet?command=[commandName]</url-pattern>
</filter-mapping>
does not work, and I don't like it at all, because in this case it is necessary to prescribe all the commands of an application.
In this regard, I have an idea to make the url when smbdy log on like these:
localhost:8080/[AppName]/user - for user
localhost:8080/[AppName]/admin - for admin
In the web-inf folder I have inner folder "pages", in which there are several inner folders: "error", "admin" and "user", which keep jsp pages for these roles and errors.
How to implement the proposed idea? I suspect that this is quite trivial, but I didn't found the answer, because I even have no idea, how to name my issue.
I think i get it now;
-First make initial servlet (index.jsp ain't servlet), once user access your page he is being redirected to it. For example localhost:8080/YouWebAppName/IndexServlet.
IndexServlet check whether session is set, if not it redirects to accessible index.jsp, if the session is set then it checks the role, if the role is set to user it redirects to localhost:8080/YourWebAppName/UserServlet, if the session is set to Admin it redirects to localhost:8080/YourWebAppName/AdminServlet.
In both Admin and User servlet you check in the first place if the session variable equals respectively user/admin.
If there are methods that you want to share in both servlets, make third servlet call it however you want and then UserServlet and AdminServlet should extend that servlet
I've recently had something similiar in my project, try like that:
<servlet-mapping>
<servlet-name>YourServletName</servlet-name>
<url-pattern>/YourServletName/*</url-pattern>
</servlet-mapping>
In the servlet code I've got method:
protected String getActionSegment(HttpServletRequest request) {
String action = request.getRequestURI().
replace(request.getContextPath() +
request.getServletPath(), "").
replace("/", "").
trim();
return action.length() > 0 ? action : "index";
}
That method returns the name of the action, if the Url is localhost:8080/MyWebApp/MyServlet, then by default it redirects to index.jsp (you can change that)
In the servlet execution method you simply define what it should do (and where to redirect) in each case for example:
if(action.equals("admin")) {
//do something
} else if (action.equals("user")) {
//do something else
}
Let me know if that's what you meant.
Btw you can also restrict access to jsp folder and only make it work if servlet redirects to the jsp.

What is a right way to use servlets?

I'm studying EJB3.
I have a session bean which provides services to create/update customer accounts.
This session bean offers services on the lines of:
public void addCustomer(Customer c);
public void updateCustomer(Customer c);
Ideally I'd like to have a single servlet: CustomerServlet and it would invoke the session beans that I have listed above.
Problem is that I have two JSPs: UpdateAccount.jsp and CreateAccount.jsp. Both of these JSPs have a form with a method POST and action "CustomerServlet".
How can I distinguish in a customer servlet which operation I should carry out: createAccount or updateAccount?
I guess the alternative is to have a separate servlet for each operation...
Thank you
I'm not really certain about the best practice for this but I have a couple of suggestions that might work:
If your form is being submitted using a submit button, you could distinguish the request on the basis of the value of the <button-name> parameter. So if your buttons had the values Update and Create and were named account-submit, by checking the value you get with request.getParameter('account-submit'), you'd be able to tell which button was clicked to generate this request. If you named them differently, you could also just check which of the two parameters was not null and you'd know which form submit you were handling.
Note that if you have only a single text field in your form and the user hits Enter instead of clicking the button, you'll get a null in your servlet! See my blog post about this behaviour.
Check the Referer header - I wouldn't really recommend this since you wouldn't always know the context of the deployed app, this value may not always be present and it can be easily spoofed.
Add another mapping for your servlet so that it's accessible at both http://myapp.example.com/context/create and http://myapp.example.com/context/update. You can then check the ServletPath (request.getServletPath()) to see what 'servlet' the request came in for. I'd probably go with this one since it seems the most robust to me but you might also want to add the other two checks just to make sure. In your web.xml, you'd want something like
<servlet>
<servlet-name>CreateUpdateServlet</servlet-name>
<servlet-class>my.package.CustomerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CreateUpdateServlet</servlet-name>
<url-pattern>/create</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CreateUpdateServlet</servlet-name>
<url-pattern>/update</url-pattern>
</servlet-mapping>
JSPs are Servlets, just in a different source code form, there is no reason to POST to a different Servlet, you can just POST back to the same JSP.
You don't need the servlet. JSPs (or Facelets) can talk directly to the beans via EL.

Categories

Resources