Thursday, September 6, 2012

HTML5 and CSS for Mobile-aware Liquid Layouts

This is inspired by a talk, given by Rupert Breheny at the Frontend Conference (Zurich). The idea: simple CSS can help layouts adapt to changes in the viewport thus eliminating the need to have different sites for desktop, mobile, and tablet. The goal is to have the content shrink when viewport width gets smaller and re-arrange it from a horizontally aligned (like the three column layout of this example) to a vertically aligned one and avoid horizontal scroll bars.

The code:

The HTML
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>The HTML5 With Mobile in Mind</title>
    <meta name="description" content="The HTML5 With Mobile in Mind">
    <link rel="stylesheet" href="html5mob.css">
</head>
<body>
<div>
This is an example of a markup with mobile in mind.
It is a three-column layout that acts in a resolution-independent manner.
</div>
<h2>Three columns</h2>
<div class="column">
    Column 1<br>
    <p>
        ...
    </p>
</div>
<div class="column">
    Column 2<br>
    <p>
        ...
    </p>
</div>
<div class="column last">
    Column 3<br>
    <p>
        ...
    </p>
</div>
</body>
</html>

The CSS: its the media line that will make sure a different CSS kicks in for smaller viewports.
html {
    background: #7fffd4;
}

body {
    background: #fffff0;
    max-width: 640px;
    margin: 0 auto;
}

.column {
    background: #6495ed;
    width: 32%;
    margin-right: 2%;
    float: left;
}

.column.last {
    margin-right: 0;
}

h1, h2 {
    clear: both;
}

@media screen and (max-width: 480px) {
    body {
        background: #fa8072;
    }
    .column {
        float: none;
        width: 100%;
        margin: 0;
    }
}
Some screenshots:

  • when displayed by a narrow browser:

  • when displayed by a wider browser: 



Saturday, September 1, 2012

Spring MVC 3 : file uploads and POST requests

HTTP POST is the method to use when the aim of the HTTP request is to change the state of the server (thus HTTP POST is an omnipotent type of a request). We use POSTs to send bytes to the server in the form of an in-lined within the request simple form data but also to transmit larger chunks of bytes, normally stored as files on our local device.
Spring MVC (3.1+) makes it easy for us to handle POSTs within our controllers and in particular to organize our controller logic into separate sections depending on whether our server-side code handles simple POST or actual file uploads. 

  • Simple POST vs File Upload
Pre-HTML5/ES5 file upload was possible only when initiated via a FORM element. Those, now older browsers, featured a less-sophisticated version of the famous XMLHttpRequest object, which allowed simple POST requests but no file upload-like functionality. File upload in such older browsers was possible only through the FORM tag. It was that FORM tag that allowed for a functionality like the ability to fire-up a file chooser dialog and transmit the file to the server as part of a POST request.

ES5, the new hotness, came with an updated (and now a W3C standard) spec for the XMLHttpRequest object that gives us the option to carry out file uploads in new ways.

Whatever the way to initiate file uploads and simple POSTs, the server will differentiate between the two based on an HTTP header, the Content-Type header:

Simple POST:
...
Accept: */*
Accept-Encoding:gzip, deflate
Accept-Language: en-us,en;q=0.5
Connection:keep-alive
Content-Length: 21
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: JSESSIONID=4A9CEA0165FB443EABBD45BBC36E4482
Hostlocalhost:8080
...

POST file upload:
...
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-us,en;q=0.5
Connection: keep-alive
Cookie: JSESSIONID=4A9CEA0165FB443EABBD45BBC36E4482
Host: localhost:8080
Content-Length: 48
Content-Type: multipart/form-data; boundary=----------------------265001916915724
...

  • Spring MVC 3 (tested 3.1.2) and POSTs on a controller level
Annotations and content negotiation will help us have different methods with almost idential RequestMapping definitions (except the consumes parameter) in order to handle the two scenarios:

@RequestMapping(method = RequestMethod.POST, value = "/url", consumes = "!multipart/form-data")
public void post(HttpServletRequest httpRequest) {
...
}

and

@RequestMapping(method = RequestMethod.POST, value = "/url", consumes = "multipart/form-data")
@ResponseStatus(HttpStatus.CREATED)
public void upload(@RequestParam("file") MultipartFile file) {
 if (!file.isEmpty()) {
 ...
 }
}

  • Spring MVC 3 (tested 3.1.2) configuration
Spring has some good documentation on the subject:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-multipart

What is important is the following bit of Spring config to be present:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
 ...
</bean>

<bean id="messageAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
 ...
</bean>

So, if you used DefaultAnnotationHandlerMapping,  now we need to change that to RequestMappingHandlerMapping and AnnotationMethodHandlerAdapter now becomes RequestMappingHandlerAdapter. You need to define both the HandlerMapping and the HandlerAdapter to the RequestMapping* versions.