Relib HTTP - TroyHisted/relib GitHub Wiki

HTTP Request mapping and routing module.

Features

  • Annotation based URL mapping
  • Request parameter to bean conversion
  • Supports POJOs and JavaBeans

Example

import javax.servlet.annotation.WebServlet;

import org.relib.http.HandleRequest;
import org.relib.http.Controller;
import org.relib.http.HttpMethod;
import org.relib.http.RequestBean;
import org.relib.http.View;

@WebServlet("/root/*")
public class RootController extends Controller {

	/**
	 * Load the root page.
	 * 
	 * @return view of the root page
	 */
	@HandleRequest(value = "/root", method = HttpMethod.GET)
	public View home() {
		return View.of("/WEB-INF/view/root.jsp").put("person", new Person());
	}

	/**
	 * Handles saving the root page.
	 * 
	 * @param person the person to save
	 * @return view of the root page containing the updated info or any errors
	 */
	@HandleRequest(value = "/root", method = HttpMethod.POST)
	public View post(@RequestBean Person person) {
		person.save();
		return View.of("/WEB-INF/view/root.jsp").put("person", person);
	}
}

URL mapping

This module is built on top of Servlet technology. As such, a Servlet is required either through web.xml configuration or the more recent WebServlet annotation. Using a wildcard mapping (e.g. /root/*) is recommended to ensure nested paths will resolve to the Servlet.

@WebServlet("/root/*")

Mapped methods are invoked through the handleRequest(req, resp) method of the RequestHandler class. The various servlet doGet/doPost/etc... methods must all delegate to handleRequest. The preferred way to accomplish this is to have the servlet extend the Controller class which has the delegation already implemented.

import org.relib.http.Controller;

public class RootController extends Controller

HandleRequest

Methods are mapped using the @HandleRequest annotation. The handler may designate the path (relative to the servlet mapping) using the value attribute. If not specified the path will default to "/".

@HandleRequest("/home")

Additionally, the handler may specify any combination of the optional method, accept and contentType values. Method specifies the HttpMethod (GET/POST/etc..). Accept specifies the format of data returned by the method (the source of the http request will accept a response in the specified format). Content-Type specifies the format of the data coming into the method (the contents of the request are in the specified format).

@HandleRequest(method=HttpMethod.PUT, accept=MediaType.JSON, contentType=MediaType.JSON)

To determine if a request should be processed by a particular HandleRequest, first the method is checked, then contentType, accept, and finally the path. This order determines the priority of ambiguous mappings.

Request parsing

The arguments of any HandleRequest method are built dynamically based on the argument type and special parameter annotations.

By default, HttpServletRequest and HttpServletResponse are always available. If you wish to access them from your method simply include them in the method signature.

@HandleRequest
public void doSomething(HttpServletRequest req, HttpServletResponse resp) {
	req.getParameter("fieldName");
}

Other arguments may be pre-populated by using the PathParam, RequestParam, or BeanParam annotations.

PathParam

The @PathParam annotation will populate the argument based on the value from the URL path. To use this, the HandleRequest path must include a portion of that path that is to be treated as a wild card. While not required, the general convention is to wrap the wild card in curly braces.

@HandleRequest("/zip/{zipCode}")
public void handleZip(@PathParam("{zipCode}") String zip) {
	// Given a request for domain.com/zip/55555 the zip will be populated with "55555"
}

RequestParam

The @RequestParam annotation will populate the argument based on the value from a request parameter.

@HandleRequest("/customer")
public void loadCustomer(@RequestParam("customerId") Integer id) {
	// Given a request for domain.com/customer?customerId=123 the id will be populated with 123
}

RequestBean

The @RequestBean annotation will populate the argument by building an object of the argument type and populating it from the request arguments using BeanUtils.

@HandleRequest("/order")
public void savePerson(@RequestBean Person person) {
	// Given a request for domain.com/user?name=bob&age=40 the person will be created with a name "bob" and age 40
}

If the parameters for the object have a common prefix you may specify that prefix in the @RequestBean value to have it ignored when mapping to your object.

@HandleRequest("/transfer")
public void savePerson(@RequestBean("buyer") Person buyer, @RequestBean("seller") Person seller) {
	// Given a request for domain.com/transfer?buyerName=jim&buyerAge=29&sellerName=bob&sellerAge=40
	// The buyer will be populated with a name "jim" and age 29. 
	// The seller will be populated with a name "bob" and age 40. 
}

Returning a View

The return type and accept property of the controller method, annotated with @HandleRequest, is used to control the response behavior.

Forwarding to a JSP

Return an instance of org.relib.http.View using the viewPath to specify the location of the jsp file to use.

@HandleRequest(value = "/root", method = HttpMethod.GET)
public View home() {
    return View.of("/WEB-INF/view/root.jsp").put("person", new Person());
}

The View may be constructed using the new keyword or by using the static of method.

View homePage = new View("/WEB-INF/view/home.jsp");
View aboutPage = View.of("/WEB-INF/view/about.jsp");

Objects may be added to the view using the put method. This method returns the view to support method chaining.

View.of("/page.jsp").put("foo", 1).put("bar", 2);

Return void to generate no response.

If you wish to control the response, potentially to return a file instead of a jsp, set the return type of your controller method to void.

@HandleRequest(value = "/download", method = HttpMethod.GET)
public void home(HttpServletResponse response) {
    // Code that writes a file directly to the response.
}

Return JSON

Set the accept property of the @HandleRequest annotation to MediaType.JSON and have the method return the object that is to be converted. Internally this uses Json.toJson to handle the object conversion.

@HandleRequest(value = "/person", method = HttpMethod.GET, accept = MediaType.JSON)
public Person home() {
    return new Person();
}