0

I have a search form with following fields

price, status, owner

When user fill all the fields, the request will be sent to the back-end to show a list of categories that have products with the specified price, status and owner. User is able to click on each category to see the list of its products.

To implement it, I have following method to retrieve the categories, and put the search fields (price,status,owner) into session to be available in next page of the search ( when a category is selected).

The value of the parameters might be so long, and I prefer to have them as GET to be easy to bookmark the results.

public String retrieveCategories(){
        //... here I retrieve categories which their products are matched 
        //with the search fields
        Map session = ActionContext.getContext().getSession();
        session.put("Items", this.items);
        return "SUCCESS";
   }

Once all categories are shown user is able to click on each to see their products. The name of category will be send to backend, so I will retrieve the values from session to search for products with the same specifications for the selected category.

public String retrieveProductsOfSelectedCategory(){
        Map session = ActionContext.getContext().getSession();
        this.items = (Items) session.get("Items");
        //... here I retrieve products of the selected category based on values retrieved
       // from session
   }

I am wondering if it is a good practice to implement it if not whats your suggestion?

AlexCartio1
  • 238
  • 3
  • 9
  • 29
  • 3
    What if they want to open two windows and do different searches in each? – developerwjk Mar 19 '14 at 23:59
  • It can be done without using session variable. How are you making the request, I mean is it an ajax request or are you reloading the page when you search and when you select category? – Anupam Mar 20 '14 at 06:22

3 Answers3

8

No, I wouldn't use the session to implement that. Using the session has several inconvenients:

  • it makes your app stateful, which makes it harder to cluster: each request from a given client will have to go to the same server, or sessions will have to be persistent or replicated. And the more you put in the session, the more it costs in terms of memory, storage and bandwidth
  • since you use a hard-coded session key to store your search criteria and items, you can't have several tabs open on the same search page: they would all share the same criteria and items.
  • cleaning up the session is complex: when to do it? If you apply this pattern on many use-cases, you will end up with lots of useless data in the session. The session should be sued for data whose lifetime is the whole session. Not for passing data fro a specific page to the next page.

The clean solution is not so hard. Simply use hidden fields or request parameters to pass data from page to page:

First page:

<input type="text" name="price" />
<input type="text" name="owner" />

Second page

Please choose a category:

<ul>
    <li><a href="/products?name=foo&price=12&category=first"></a></li>
    <li><a href="/products?name=foo&price=12&category=second"></a></li>
    <li><a href="/products?name=foo&price=12&category=third"></a></li>
</ul>

The action mapped to /products can then retrieve the name, price and category from the request parameters, and display the results. And nothing has been stored in the session.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • thanks for your answer, but I am wondering what would happen if the total length of the search is over 256, does that limit the application? as I know there is a specific limit of 256 characters for GET requests. therefoe a lengthy request might not be sent properly. – AlexCartio1 Mar 23 '14 at 22:59
  • The actual limit is much larger than 256. See http://stackoverflow.com/questions/2659952/maximum-length-of-http-get-request. But if you're really concerned, then use a POST instead of a GET. You'll need JavaScript to make your link send a POST request rather than a GET. But I guess neither price, nor owner, nor status, are more than a few characters long. – JB Nizet Mar 23 '14 at 23:04
  • but the problem is that, the value of the parameters might be so long, and I prefer to have them as GET to be easy to bookmark the results. Whats your suggestion? – AlexCartio1 Mar 24 '14 at 01:36
  • What can I say? You know that there is a limit. You suspect that the parameters might be longer than the limit. You can't do anything about the limit. And you don't want to use a method that doesn't have the limit. That's an unsolvable equation. How could a price, a status, an owner and a category ID be longer than 2K? – JB Nizet Mar 24 '14 at 06:56
  • because the category id might have more than just one category id – AlexCartio1 Mar 24 '14 at 22:07
  • You said: *Once all categories are shown user is able to click on each to see their products. The name of category will be send to backend*. So the user clicks on *one* category to see its product. You thus need to send *one* category ID in your GET request. – JB Nizet Mar 24 '14 at 22:12
  • you are right sorry for misleading information, as in the comments of the code it accept multiple category ids sorry for the misleading information. – AlexCartio1 Mar 24 '14 at 22:21
0

You should implement something like this. You can change the get methods and more but this is a pretty simple way to do it.

import java.util.*;

/**
 * Created by Czipperz on 3/28/2014.
 */
public class Search {
    public static class Item {
        private String price;
        private String status;
        private String owner;

        public Item(String price, String status, String owner) {
            this.price = price;
            this.status = status;
            this.owner = owner;
        }

        public String getPrice() {
            return price;
        }

        public String getStatus() {
            return status;
        }

        public String getOwner() {
            return owner;
        }
    }

    public static class Category {
        private String name;
        private List<Item> items;

        public Category(String name, List<Item> items) {
            this.name = name;
            this.items = items;
        }

        public String getName() {
            return name;
        }

        public List<Item> getItems() {
            return items;
        }
    }

    private List<Category> categories = new ArrayList<Category>();

    //Only compatable with Java 8
    public List<Item> getItems(Category selectedCategory, String price, String status, String owner) {
        //The result array
        ArrayList<Item> result = new ArrayList<Item>();
        //Starts the stream of items (see http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
        selectedCategory.getItems().stream()
                //Filters out all that don't have the price
                .filter((i) -> i.getPrice().equalsIgnoreCase(price))
                //Filters out those that don't have the status
                .filter((i) -> i.getStatus().equalsIgnoreCase(status))
                //Filters out those that don't have the owner.
                .filter((i) -> i.getOwner().equalsIgnoreCase(owner))
                //Has each added to the result List
                .forEach((i) -> result.add(i));
        //Returns the resulting list of correct items.
        return result;


        /*
        Java 7 Version:
         */
        /*
        for(Item i : items) {
            if(i.getPrice().equalsIgnoreCase(price)) {
                if(i.getStatus().equalsIgnoreCase(status)) {
                    if(i.getOwner().equalsIgnoreCase(owner)) {
                        result.add(i);
                    }
                }
            }
        }
         */
    }

    public List<Category> getCategories() {
        return categories;
    }

    public void addCategory(Category category) {
        this.categories.add(category);
    }
}
Czipperz
  • 3,268
  • 2
  • 18
  • 25
0

You suggested the you would like users to bookmark the page. You will need something more persistent for that. You could use local storage for that and revert to a cookie if local storage is unavailable.

B2K
  • 2,541
  • 1
  • 22
  • 34