How to control servlet execution by URLs? - java

If the urlPatterns controls basic URL rewrite, can I not use .htaccess to rewrite the URL? I'm looking at this code: http://www.objectdb.com/tutorial/jpa/eclipse/ee/servlet
...
#WebServlet(name = "GuestServlet", urlPatterns = {"/guest"})
public class GuestServlet extends HttpServlet {
...
This page works great when I access http://localhost:8080/Guestbook/guest, but what if I wanted to do http://localhost:8080/Guestbook/guest/edit?id=4, how would I set that up in this controller?
In PHP the logical steps would be http://localhost:8080/Guestbook/controller/function. In java it seems like I can only use doGet(), is this right?
I'm trying to envision how the overall URL structure affects the execution of controllers.

Use an URL pattern of /guest/* and use HttpServletRequest#getPathInfo() to extract the path information.
Here's a kickoff example (trivial checks omitted):
#WebServlet("/guest/*")
public class GuestServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String[] pathInfo = request.getPathInfo().split("/");
String action = pathInfo[1]; // edit
String id = pathInfo[2]; // 4
// ...
}
}
Invoking http://localhost:8080/Guestbook/guest/edit/4 will set action to edit and id to 4. You could from this step on make use of the strategy pattern to invoke specific business actions.
You could of course also go for an action based MVC framework which abstracts all the servlet boilerplate away, such as Spring MVC.
See also:
Design Patterns web based applications

resource http://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/annotation/WebServlet.html
basically you need to change
#WebServlet(name = "GuestServlet", urlPatterns = {"/guest"})
to
#WebServlet(name = "GuestServlet", urlPatterns = {"/guest", "/guest/edit"})
now your servlet should handle the "/guest/edit" URL pattern also

Related

Dynamic URL routes with java EE

I'm super new to java web application development. Working on basic Todos app. So far app is working fine. I wish to add dynamic url routes like updateTodos, deleteTodos to existing path.
Expected behavior as shown below
/todos
*render todos list*
/todos/update
*render updateTodos.jsp*
/todos/delete
*render deleteTodos.jsp*
Below is my code
#WebServlet(urlPatterns = "/todos")
public class UserTodos extends HttpServlet {
private TodoService todoService = new TodoService();
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if(request.isRequestedSessionIdValid()){
request.setAttribute("userName", request.getParameter("userName"));
request.setAttribute("allTodos", todoService.retrieveTodos());
request.getRequestDispatcher("WEB-INF/views/todos.jsp").forward(request, response);
}else{
response.sendRedirect("/login");
}
}
}
My understanding is so far that the annotation #WebServlet triggers the class file based on route defined. Can I achieve the above with a single class file?
Something like being done in JS web-framework Express-JS
If I sum-up my whole query is - Is it possible to multiple doGet and doPost methods in a single class file which will be executed based on user's URL accessed?
Update
I was able to achieve this, not sure whether this is correct implementation or not :/

capturing relevant user requests using filter/interceptors

I am capturing URLs requested for my website. I need to see what all pages were requested from my website.
To achieve this I created a basic filter, and started logging page requests from there.
Now, this filter catches all the requests specific to a page.
For e.g. abc.com/page1, abc.com/resources/myjs.js, etc.
My problem is that for each page request, subsequent resources(js,css) are requested too. I want to capture only the relevant requests.
Right now, I check for patterns like /resources to ignore such requests, but I am looking for a more clean approach.
Also, will interceptors be more useful here?
I have seen filter patterns as well. But those are not useful, since I would have to create patterns for my filter.
If you want to capture the urls accessed from your website, you can configure spring boot to generate access logs in following way until you don't want more advance information:
server.tomcat.accesslog.directory=/logs/ #absolute directory path for log files\
server.tomcat.accesslog.enabled=false #Enable access log.
server.tomcat.accesslog.pattern=any_pattern # log string format pattern for access logs.
To perform any operation based on any request pattern, you can go ahead with filters.
I'm using filters for such requirements in following way:
public class CustomFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String url = request.getRequestURI();
if (url.startsWith("/resources/")) {
//your business logic
}
filterChain.doFilter(request,response);
}
}

Is using a ControllerServlet good practice for Java EE 6?

I read about ControllerServlet usage in affablebean tutorial for Java EE 6, by Oracle.
It ends up with a servlet handling a lot of different URL requests, like this:
#WebServlet(name = "ControllerServlet",
loadOnStartup = 1,
urlPatterns = {
"/category",
"/addToCart",
"/viewCart",
"/updateCart",
"/checkout",
"/purchase",
"/chooseLanguage"})
public class ControllerServlet extends HttpServlet {
#EJB
private CategoryFacade categoryFacade;
#EJB
private OrderManager orderManager;
#Override
public void init() throws ServletException {
// store category list in servlet context
getServletContext().setAttribute("categories", categoryFacade.findAll());
}
/**
* Handles the HTTP <code>GET</code> method.
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userPath = request.getServletPath();
// if category page is requested
if (userPath.equals("/category")) {
// get categoryId from request
String categoryId = request.getQueryString();
if (categoryId != null) {
// get selected category
Category selectedCategory = categoryFacade.find(Short.parseShort(categoryId));
// place selected category in request scope
request.setAttribute("selectedCategory", selectedCategory);
// get all products for selected category
Collection<Product> categoryProducts = selectedCategory.getProductCollection();
// place category products in request scope
request.setAttribute("categoryProducts", categoryProducts);
}
// if cart page is requested
} else if (userPath.equals("/viewCart")) {
// TODO: Implement cart page request
userPath = "/cart";
// if checkout page is requested
} else if (userPath.equals("/checkout")) {
// TODO: Implement checkout page request
// if user switches language
} else if (userPath.equals("/chooseLanguage")) {
// TODO: Implement language request
}
// use RequestDispatcher to forward request internally
String url = "/WEB-INF/view" + userPath + ".jsp";
try {
System.out.println("Redirecting to : "+url);
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
}
I wonder if it is good practice for a Java EE project? I'm thinking about adopting Java EE as the framework for a project, which involves a small team of programmers. I think this ControllerServlet is encouraging them to put a lot of business logic inside. The class is expected to grow terribly long with a lot of if/else if... in future.
So what would be your recommendation about such a ControllerServlet to work in a big project?
You are correct in thinking that the controller servlet will quickly grow to be unmanageable if you are handling many different actions. You'll wind up with a huge set of if or case statements following the naive approach you sketched out.
A typical solution would be a front controller pattern that dispatches url mappings to other code that actually handles the requests. There are many relatively straight forward solutions to do this (someone mentioned the command pattern) and it's a key part of most web frameworks. I would probably not write my own front controller in 2016. What with the ease of standing up annotation based servlets, I would consider structuring a very simple application (like a microservice) around a single action per servlet; handling as many of the http methods as necessary: DELETE, PUT, GET...
However, you are also probably going to need additional features such as templating, reusable UI components, fancy url parameter handling, object to json mapping (and the reverse), sub resource mapping, content negotiation, authorization, etc. To the extent that you do, consider one of the numerous java EE technologies that you can apply to the problem (JAX-RS, JSF, JSR 371) and even more numerous implementations of each.
If you exposing an api I'd look at a JAX-RS implementation like jersey For a certain kind of application that might suffice: perhaps a single page web application communicating with the back end via ajax calls.You could serve your static content with nginx for apache. For full-blown frameworks you can choose a component based approach that implements the JSF standard or an action based one that implements the mvc1 (JSR 371) spec. You can read about the differences here: https://blogs.oracle.com/theaquarium/entry/why_another_mvc_framework_in
You mentioned choosing between JSF and spring mvc, The former is component based, the latter is action based. There is currently only one implementation of JSR 371, Ozark, the reference. If this distinction is important for your choice then you might be hampered by the lack of JSR 371 implementations. But it really does seem to me that the action based approach is the future.

passing data btw classes using request.setParameter, request.getParameter

I have 2 java classes and I want to transfer data between them.
I take user id as parameter in a previous jsp form, and in a java class, using setAttribute I create a atribute named st_id.
then in another java clas I want to retrieve this data, but I get null.pointer exception.
first java file;
public class Signin implements Action {
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
Student stu = new StDAO().getUser(request.getParameter("st_id").toString());
request.setAttribute("st_id", request.getParameter("st_id").toString());
...
second;
public class addCourseStu implements Action{
#Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
TakeCourseDAO pf = new TakeCourseDAO();
String s= (String) request.getAttribute("st_id");
So s is null, it's not my intention.
A request exists from the time the web browser sends it to the web server until the web server (via the servlet) has made its response.Every request for a servlet has its own accessibilty scope. From a servlet, you can:
add new attributes to the request's scope
obtain exisiting attributes from the request's scope
remove exisiting attributes from the request's scope
As you are getting null it is quite obvious that the attribute is not accessed within the scope.
You can try alternatives like Session scope or Application scopes which ever suits you
It is not entirely clear what you want to do but I gather that you want to maintain some state on the server between two requests right?
Look into sessions & cookies for this.
What you do here is weird as it seems you are setting an attribute on an incoming request in the first file.

Are the #MultipartConfig configuration elements in a Servlet useless in presence of a Filter?

I've alredy configured a servlet like this:
#WebServlet(name = "TestServlet", urlPatterns = {"/test"})
#MultipartConfig(location = "C://test",
fileSizeThreshold=1024*1024*10, // 10 MB
maxFileSize=1024*1024*50, // 50 MB
maxRequestSize=1024*1024*100) // 100 MB
public class TestServlet extends HttpServlet {
However I'm not sure if the fileSize and requestSize "security limits" become useless when a Filter processes the request before the servlet (I read somewhere that the filter request processing is not necessarily before the resources, I might be wrong on this).
The filter configuration is simple enough:
#WebFilter(filterName = "TestFilter",
description = "TheTestFilter",
urlPatterns = { "*.any" })
public class TestController implements Filter {
The filter implementation will contain stateless security credentials validation.
Thanks for the interest!
Regards.
Well, I guess it was a silly question. The trick here is how the ServletRequest object in the filter is being handled. As long as I don't do the mistake of trying to read the request body with getInputStream() or getReader(), the MultipartConfig options should work as expected. Somehow I remebered running into this few years ago by trying to get into the message body instead of transfering control to another web component.
Here's some documentation.

Categories

Resources