Thursday, 21 July 2011

Using Spring’s HttpEntity Class to Parse the HttpRequest

Spring provides an HttpEntity class for dealing with HTTP request and response objects. This blog uses the HttpEntity class to pull the HTTP request apart and return it as a page. The first thing to do is to quickly write some HTML that’ll POST a request to the server giving us something to parse and return. For that, I’ve used the following form:

<form:form method="POST" action="requestentity">
 <input type="submit" name="action" value="<spring:message code="label.request.entity"/>"  />
 <input type="hidden" id="age" name="age" value="45" />
 <input type="hidden" id="gender" name="gender" value="female" />
</form:form>

The simple form above posts a request to requestentity, which we’re going to capture with our controller handler method.

  @RequestMapping("/requestentity")
 
public String handleRequestEntity(HttpEntity<String> requestEntity, Model model) {

   
addBodyToModel(requestEntity, model);
    addHeadersToModel
(requestEntity, model);
   
return "request.entity.page";
 
}

 
private void addBodyToModel(HttpEntity<String> requestEntity, Model model) {

   
String requestBody = requestEntity.getBody();
    model.addAttribute
("body", requestBody);
 
}

 
private void addHeadersToModel(HttpEntity<String> requestEntity, Model model) {

   
HttpHeaders headers = requestEntity.getHeaders();
    List<HeaderBean> headerList =
new ArrayList<HeaderBean>();
    addHeadersToList
(headerList, headers);
    model.addAttribute
("headerList", headerList);
 
}

 
private void addHeadersToList(List<HeaderBean> headerList, HttpHeaders headers) {

   
Set<String> keys = headers.keySet();
   
for (String key : keys) {
     
headerList.add(HeaderBean.createInstance(key, headers.getFirst(key)));
   
}
  }

public class HeaderBean {

 
private final String key;

 
private final String value;

 
private HeaderBean(String key, String value) {

   
this.key = key;
   
this.value = value;
 
}

 
public static HeaderBean createInstance(String key, String value) {

   
return new HeaderBean(key, value);
 
}

 
public final String getKey() {

   
return key;
 
}

 
public final String getValue() {

   
return value;
 
}

 
@Override
 
public String toString() {

   
return ToStringHelper.toString(this);
 
}
}

The controller method above takes the HttpEntity and pulls out the request body as a String and the request headers, which are stored in a list of HeaderBean objects. These are then added into the model before the handler method returns the name of the next view: “request.entity.page”. This is then displayed by the browser as shown below:


The JSP code that displays the above screen snippet uses a bunch of the usual tags, following the usual paradigms previously mentioned in this blog.

<%-- Spring framework - form tags  --%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%-- Other Spring tags --%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%--  This is the JSTL tag --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<div class="portlet">
 <div class="portlet-header">
  <h2><spring:message code="label.http.headers.title"/></h2>
 </div>
 <div class="portlet">
  <div class="portlet-header">
   <h2><spring:message code="label.viewResults"/></h2>
  </div>
  <div class="portlet-body">
   <div class="columns two-columns">
    <div class="column bold">
     <spring:message code="column.header.key"/>
    </div>
    <div class="column bold">
     <spring:message code="column.header.value"/>
    </div>
    <c:forEach items="${headerList}" var="headerBean">
     <div class="column">
      <c:out value="${headerBean.key}" />
     </div>
     <div class="column">
      <c:out value="${headerBean.value}" />
     </div>
    </c:forEach>
   </div> 
  </div>
 </div> 
</div>
<div class="portlet">
 <div class="portlet-header">
  <h2><spring:message code="label.body.title"/></h2>
 </div>
 <div class="portlet-body">
  <c:out value="${body}" />
  <br />
  <hr />
 </div>
</div>

I’ve obviously fixed up my tiles-definition to resolve the view, but there’s nothing remarkable about that.

No comments: