mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

  • Monday, 22 February, 2016

    Java EE 8 MVC: Working with form parameters

    In the previous two posts we saw how to work with query and path parameters in the upcoming Java EE MVC framework. This post focuses on form parameters.

    When you submit a web form using a post request, the form values are send as part of the request body. The media type (or content type) defines the format that is used to store the values inside the request body. Web forms usually use the media type application/x-www-form-urlencoded. Parameters that are send using this media type can be accessed using the @FormParam annotation.

    Using form parameters

    Assume we have the following simple HTML form, containing two text input fields and a select menu:

    <form action="submit" method="post">
      <label>ID:</label>
      <input type="text" name="id" />
      
      <label>Name:</label>
      <input type="text" name="name" />
      
      <label>Role:</label>
      <select name="role">
        <option value="admin">Admin</option>
        <option value="reporter">Reporter</option>
        <option value="accountant">Accountant</option>
      </select>
      
      <input type="submit" />
    </form>
    

    To process the form values we can use the following controller method:

    public enum Role {
      admin, reporter, accountant
    }
    
    @Controller
    @Path("form-params")
    public class FormParamsController {
    
      @POST
      @Path("submit")
      public String submitParams(
          @FormParam("id") long id,
          @FormParam("name") String name,
          @FormParam("role") Role role) {
    
        ...
      }
    }
    

    With @FormParam form parameters can automatically be mapped to method arguments. Form parameters use the same type conversion rules as query or path parameters (described here). This makes it easy to convert form parameters to primitives, enums or objects.

    Using @FormParam on fields and methods

    Like other parameter annotations @FormParam can be used to annotate fields and methods.

    For example:

    @Controller
    @Path("form-params-fields")
    public class FormParamsFieldController {
    
      @FormParam("id")
      private long id;
    
      @FormParam("role")
      private Role role;
    
      private String name;
    
      @FormParam("name")
      public void setNameField(String name) {
        this.name = name;
      }
    
      @POST
      public String submitParams() {
         // use id, role, name
      }
    }
    

    In this example the submitted form parameters are mapped to fields (id, role) and a setter (setNameField()). Inside submitParams() we can then simply access the fields to obtain the form parameters.

    Quick Summary

    Parameters submitted via HTML forms can be obtained with @FormParam. Like @QueryParam and @PathParam it is possible to annotate fields, methods and method parameters with @FormParam.

    You can find the source code for all examples on GitHub.

  • Sunday, 31 January, 2016

    Java EE 8 MVC: Working with Path Parameters

    In the previous post we saw how to work with query parameters in Java EE MVC. This post continues with a very similar topic: path parameters.

    Path parameters are a dynamic part of the request path and can be specified with the @Path annotation.

    For example:

    @Controller
    @Path("path-params")
    public class PathParamsController {
    
      @GET
      @Path("/date/{year}/{month}")
      public String pathParamDate(@PathParam("year") int year, @PathParam("month") int month) {
        ...
      }
    }
    

    Paths parameter are surrounded with curly brackets inside the @Path annotation. In this example two path parameters are defined: year and month.

    With @PathParam path parameters can be mapped to method parameters.

    We can call this method by sending a request to

    /path-params/date/2016/01
    

    In this case 2016 and 1 will be passed as year and month arguments.

    Type conversion

    Path parameters use the same type conversion rules as query parameters (explained in the previous blog post).

    For example, we can convert a path parameter to an enum value like this:

    public enum Role {
      admin, reporter, accountant
    }
    
    @Controller
    @Path("path-params")
    public class PathParamsController {
    
      @GET
      @Path("/roles/{role}")
      public String pathParamUsers(@PathParam("role") Role role) {
        ...
      }
    }
    

    If we now send a request to

    /path-params/roles/admin
    

    the string admin gets converted to the corresponding enum constant.

    Using @PathParam on fields and methods

    Like @QueryParam the usage of @PathParam is not limited to method parameters. It is also possible to annotate fields or setters with @PathParam.

    For example:

    @Controller
    @Path("path-params")
    public class PathParamsController {
    
      @PathParam("category")
      private String category;
    
      @GET
      @Path("/categories/{category}")
      public String findByCategory() {
        // work with category
      }
    }

    Using Path Parameters with Patterns

    It is possible to define a more specific pattern for a path variable. Therefore, a regular expression can be added after the name of the path variable.

    For example:

    @Controller
    @Path("path-params")
    public class PathParamsController {
    
      @GET
      @Path("/users/{id : \\d+}")
      public String findUserById(@PathParam("id") long id) {
        ...
      }
    
      @GET
      @Path("/users/{name : [a-zA-Z]+}")
      public String findUserByName(@PathParam("name") String name) {
        ...
      }  
    }
    

    Here we define two controller methods that listen on /users/{variable}:

    • findUserById() is only called if a numeric id is part of the request path
    • findUserByName() is used if the path parameter matches the regular expression [a-zA-Z]+.

    So if we send a request to

    /path-params/users/123
    

    findUserById() will be called and 123 is passed as id.

    Sending a request to

    /path-params/users/john
    

    calls findUserByName() and passes john as name.

    Quick Summary

    @PathParam can be used to extract path parameters defined with @Path. Like @QueryParam, @PathParam can be used on method arguments, instance fields and methods.

    When defining path parameters with @Path, a regular expression can be used to define a specific path pattern.

    You can find the source code for all shown examples on GitHub.

  • Thursday, 14 January, 2016

    Java EE 8 MVC: Working with query parameters

    In the previous post about the new Java EE MVC Framework we had a detailed look on Controllers. In this and the following posts we will see how to access various types of request data in MVC Controllers.

    Java EE MVC makes heavy use of JAX-RS and most of the things we will see in this and the next posts are JAX-RS features. So, if you are familiar with JAX-RS you probably will not learn much new in this post.

    Query parameters

    This post focuses on query parameters. If you read my Java EE MVC Getting started post you might already know the @QueryParam annotation. The most common use case of  @QueryParam is to map a query parameter to a controller method parameter.

    For example:

    @Controller
    @Path("query-params")
    public class QueryParamsController {
    
      @GET
      public String queryParams(@QueryParam("name") String name) {
        ...
      }
    }
    

    If we now send a HTTP GET request to

    /query-params?name=john
    

    the string "john" will be passed as name parameter to the method queryParams().

    Type conversion

    With @QueryParam query parameters can automatically be converted to various types.

    For example:

    public enum Role {
      admin, reporter, accountant
    }
    
    @Controller
    @Path("query-params")
    public class QueryParamsController {
    
      @GET
      public String queryParams(
          @QueryParam("id") long id,
          @QueryParam("name") String name,
          @QueryParam("role") Role role) {
    
        ...
      }
    }
    

    We can now send a request like this:

    /query-params?id=42&name=john&role=admin
    

    A query parameter can automatically converted to a type, if the target type matches one of the following rules:

    • It is a primitive type
    • The type has a constructor that accepts a single String argument
    • The type has a static factory method named valueOf() or fromString() with a single String argument
    • The type is List<T>, Set<T>; or SortedSet<T> where T matches one of the previous rules

    In the previous example, the query parameter id is automatically converted to long. If the id parameter is missing or a conversion to long is not possible, an exception will be thrown. It is also possible to use Long instead of long. In this case, we get null passed to the controller method if the id parameter is missing.

    Enums have a valueOf() method by default. So, the query parameter role can automatically be converted to the corresponding enum value.

    Using @QueryParam on fields and methods

    @QueryParam is not limited to method parameters. It is also possible to map query parameters to fields or methods, like the following example shows:

    @Controller
    @Path("query-params-fields")
    public class QueryParamsFieldController {
    
      @QueryParam("id")
      private Long id;
    
      @QueryParam("role")
      private Role role;
    
      private String name;
    
      @QueryParam("name")
      public void setName(String name) {
        this.name = name;
      }
      
      @GET
      public String queryParams() {
        // use id, role and name
      }
    }
    

    If we now send a HTTP GET request to

    /query-params-fields?name=john&id=42&role=reporter
    

    the parameters are set to the fields id, role and name (via setName()) before queryParams() is called.

    Do not forget that a new instance of the class is created for every request, so it is safe to have fields that contain request information.

    Quick Summary

    The @QueryParam annotation can be used to obtain query parameters. @QueryParam can be used on fields, methods and method parameters. Query parameters can be automatically converted to various types, as long as the target type is a primitive type, contains a String constructor or contains valueOf() or fromString() factory methods.

    You can find the source code for all the shown examples on GitHub.

    In the next post we will see how to work with path parameters.

  • Sunday, 4 October, 2015

    Java EE 8 MVC: A detailed look at Controllers

    Java EE MVC is a new action based MVC framework planned for Java EE 8 and specified in JSR-371. This is the second post of my Java EE 8 MVC tutorial. The first post covered the basics and shows how to get started with Ozark, the Java EE 8 MVC reference implementation.

    In this post we will have a more detailed look at MVC Controllers.

    MVC Controllers

    A controller is responsible for processing incoming requests. It invokes business logic, updates the model and returns the view that should be rendered. An MVC Controller is a JAX-RS resource method annotated with @Controller. If a class is annotated with @Controller, then all resource methods of this class are regarded as controllers.

    The following example shows a simple Controller that renders a product details page for a given product id:

    @Path("product")
    @Controller
    public class ProductController {
    
      @Inject
      private Models models;
    
      @Inject
      private ProductService productService;
    
      @GET
      public String getProductDetailPage(@QueryParam("id") long productId) {
        Product product = this.productService.getProduct(productId);
        models.put("product", product);
        return "/WEB-INF/jsp/productDetailPage.jsp";
      }
    }

    This Controller resolves a product id (passed as id request parameter) to a product using a ProductService. The obtained product is added to the model and a path to a view is returned. The view is then rendered with the information stored in the model.

    Like in JAX-RS, the @Path annotation is used to define the URL path. This Controller is accessible via a URL that looks like this:

    /<application-path>/product?id=42

    The following example shows a hybrid class with one MVC controller method and one traditional JAX-RS resource method:

    @Path("hybrid")
    public class HybridController {
    
      @GET
      @Path("jaxrs")
      public Response jaxrs() {
        return Response.status(200).build();
      }
    
      @Path("mvc")
      @GET
      @Controller
      public String mvc() {
        return "/WEB-INF/jsp/hello.jsp";
      }
    }

    Controller methods work very similar to JAX-RS resource methods. However, there are two small differences:

    • A return type of String on Controller methods is interpreted as a view path. With JAX-RS resource methods the returned String is interpreted as text content.
    • The default response media type for Controller methods is text/html. Like in JAX-RS the media type can be changed using the @Produces annotation.

    MVC Controller classes and hybrid classes with MVC Controller methods need to be CDI-managed beans. Like JAX-RS resource classes, MVC controller classes are instantiated per request. For every request, a new Controller class instance is created.

    Like in JAX-RS the supported HTTP verb is defined by annotations. If a controller method should listen for HTTP POST requests, it needs to be annotated with @POST instead of @Get.

    For example:

    @Controller
    @Path("http")
    public class PostController {
    
      @POST
      @Path("post")
      public String post() {
        return "/WEB-INF/jsp/hello.jsp";
      }
    }

    Controller return types

    Four different return types are supported on MVC controller methods:

    • String - The returned string value is interpreted as view path.
    • void - In this case the view need to be defined using the @View annotation
    • Viewable - An abstraction that includes information about a view, the model and the used view engine.
    • Response - A JAX-RS response. The entity type of the response needs to be String, void or Viewable.

    The following class defines four controller methods using different return types. All methods return the same response:

    @Controller
    @Path("return-types")
    public class ReturnTypesController {
    
      @GET
      @View("/WEB-INF/jsp/hello.jsp")
      @Path("return-void")
      public void returnVoid() {
      }
    
      @GET
      @Path("return-string")
      public String returnString() {
        return "/WEB-INF/jsp/hello.jsp";
      }
    
      @GET
      @Path("return-string")
      public Viewable returnViewable() {
        return new Viewable("/WEB-INF/jsp/hello.jsp");
      }
    
      @GET
      @Path("return-response")
      public Response returnResponse() {
        return Response.status(Response.Status.OK)
            .entity("/WEB-INF/jsp/hello.jsp")
            .build();
      }
    }

    Returning a JAX-RS Response is the most flexible way. This way the JAX-RS Response builder can be used to modify the HTTP status code, response headers and more.

    If void is used as return type, the view needs to be defined using the @View annotation. @View can be applied to methods (like in the previous example) and classes. If a class is annotated with @View, the view is applied to all controller methods in this class. A class level @View annotation can be overridden by a more specific view definition on method level, like shown in the following example:

    @Controller
    @Path("views")
    @View("/WEB-INF/jsp/foo.jsp")
    public class ViewController {
    
      @GET
      @Path("first")
      public void first() {
        // renders foo.jsp
      }
    
      @GET
      @Path("second")
      @View("/WEB-INF/jsp/bar.jsp")
      public void second() {
        // renders bar.jsp
      }
    
      @GET
      @Path("third")
      public String third() {
        // renders baz.jsp
        return "/WEB-INF/jsp/baz.jsp";
      }
    }

    Summary

    The @Controller annotation can be used on methods and classes. When used on classes, all methods of the class are considered as controllers. Controller methods invoke business logic and determine the view that should be rendered. Classes with Controller methods are CDI managed beans. For every request, a new class instance will be created. Traditional JAX-RS resource methods can be combined with MVC Controller methods in the same class.

    In the next posts about Java EE 8 MVC we will have a look at parameter binding and validation.

    You can find the example source code on GitHub.

  • Monday, 21 September, 2015

    Resource versioning with Spring MVC

    When serving static resources, it is common practice to append some kind of version information to the resource URL. This allows the browser to cache resources for an unlimited time. Whenever the content of the resource is changed, the version information in the URL is changed too. The updated URL forces the client browser to discard the cached resource and reload the latest resource version from the server.

    With Spring it only takes two simple steps to configure versioned resource URLs. In this post we will see how it works.

    Serving versioned URLs

    First we need to tell Spring that resources should be accessible via a versioned URL. This is done in the resource handler MVC configuration:

    @Configuration
    public class MvcApplication extends WebMvcConfigurerAdapter {
    
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
        VersionResourceResolver versionResourceResolver = new VersionResourceResolver()
            .addVersionStrategy(new ContentVersionStrategy(), "/**");
    
        registry.addResourceHandler("/javascript/*.js")
            .addResourceLocations("classpath:/static/")
            .setCachePeriod(60 * 60 * 24 * 365) /* one year */
            .resourceChain(true)
            .addResolver(versionResourceResolver);
      }
    
      ...
    }

    Here we create a resource handler for JavaScript files located in folder named static inside the classpath. The cache period for these JavaScript files is set to one year. The important part is the VersionResourceResolver which supports resource URLs with version information. A VersionStrategy is used to obtain the actual version for a resource.

    In this example we use a ContentVersionStrategy. This VersionStrategy implementation calculates an MD5 hash from the content of the resource and appends it to the file name.

    For example: Assume we have a JavaScript file test.js inside the classpath:/static/ directory. The MD5 hash for test.js is 69ea0cf3b5941340f06ea65583193168.

    We can now send a request to

    /javascript/test-69ea0cf3b5941340f06ea65583193168.js

    which will resolve to classpath:/static/test.js.

    Note that it is still possible to request the resource without the MD5 hash. So this request works too:

    /javascript/test.js

    An alternative VersionStrategy implementation is FixedVersionStrategy. FixedVersionStrategy uses a fixed version string that added as prefix to the resource path.

    For example:

    /v1.2.3/javascript/test.js

    Generating versioned URLs

    Now we need to make sure the application generates resource URLs that contain the MD5 hash.

    One approach for this is to use a ResourceUrlProvider. With a ResourceUrlProvider a resource URL (e.g. /javascript/test.js) can be converted to a versioned URL (e.g. /javascript/test-69ea0cf3b5941340f06ea65583193168.js). A ResourceUrlProvider bean with the id mvcResourceUrlProvider is automatically declared with the MVC configuration.

    In case you are using Thymeleaf as template engine, you can access the ResourceUrlProvider bean directly from templates using the @bean syntax.

    For example:

    <script type="application/javascript"
            th:src="${@mvcResourceUrlProvider.getForLookupPath('/javascript/test.js')}">
    </script>

    If you are using a template engine which does not give you direct access to Spring beans, you can add the ResourceUrlProvider bean to the model attributes. Using a ControllerAdvice, this might look like this:

    @ControllerAdvice
    public class ResourceUrlAdvice {
    
      @Inject
      ResourceUrlProvider resourceUrlProvider;
    
      @ModelAttribute("urls")
      public ResourceUrlProvider urls() {
        return this.resourceUrlProvider;
      }
    }

    Inside the view we can then access the ResourceUrlProvider using the urls model attribute:

    <script type="application/javascript" 
            th:src="${urls.getForLookupPath('/javascript/test.js')}">
    </script>

    This approach should work with all template engines that support method calls.

    An alternative approach to generate versioned URLs is the use of ResourceUrlEncodingFilter. This is a Servlet Filter that overrides the HttpServletResponse.encodeURL() method to generate versioned resource URLs.

    To make use of the ResourceUrlEncodingFilter we simply have to add an additional bean to our configuration class:

    @SpringBootApplication
    public class MvcApplication extends WebMvcConfigurerAdapter {
    
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // same as before ..
      }
    
      @Bean
      public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
        return new ResourceUrlEncodingFilter();
      }
    
      ...
    }

    If the template engine you are using calls the response encodeURL() method, the version information will be automatically added to the URL. This will work in JSPs, Thymeleaf, FreeMarker and Velocity.

    For example: With Thymeleaf we can use the standard @{..} syntax to create URLs:

    <script type="application/javascript" th:src="@{/javascript/test.js}"></script>

    This will result in:

    <script type="application/javascript" 
            src="/javascript/test-69ea0cf3b5941340f06ea65583193168.js">
    </script>

    Summary

    Adding version information to resource URLs is a common practice to maximize browser caching. With Spring we just have to define a VersionResourceResolver and a VersionStrategy to serve versioned URLs. The easiest way to generate versioned URLs inside template engines, is the use of an ResourceUrlEncodingFilter.

    If the standard VersionStrategy implementations do not match your requirements, you can create our own VersionStrategy implementation.

    You can find the full example source code on GitHub.