Review
In the previous section, we have laid down the functional specs of the application. In this section, we will discuss the project's structure, write the Java classes, and organize them in layers.
Project Structure
Our application is a Maven project and therefore follows Maven structure. As we create the classes, we've organized them in logical layers: domain, repository, service, and controller.
Here's a preview of our project's structure:
The Layers
Domain
This layer contains two domain classes,
User and
Role. They represent our database tables,
user and
role respectively. Because we're developing a JPA-based repository, both classes must be annotated with JPA annotations.
Data Transfer Object (DTO)
This layer contains three DTO classes:
- UserDto is a POJO for mapping User objects to and from the presentation layer
- StatusResponse is a POJO for sending boolean responses to the presentation layer
- JqgridResponse is a container for UserDto objects for sending records to the jqGrid table. It contains information regarding the number of rows, current page, and total pages.
What is the principle behind JqgridResponse's structure?
By default, the
jqGrid plugin can process data in various formats: XML, JSON, Arrays, and etc. For this tutorial, we will use JSON because it's lightweight and simple. If we're going to use JSON, our JSON format must match our jqGrid's jsonReader property. Consequently, our DTO object must match as well.
Below is a sample jqGrid jsonReader property declaration:
Below is a sample JSON string that's acceptable to jqGrid (Notice the fields match the jsonReader fields and JqgridResponse's fields):
{"page":"1","total":"2","records":"2","rows":[{"id":1,"firstName":"John","lastName":"Smith","username":"john","role":1},{"id":2,"firstName":"Jane","lastName":"Adams","username":"jane","role":2}]}
Controller
This layer contains two controllers,
MediatorController and
UserController.
- MediatorController is responsible for redirecting requests from the root path to the Users page
- UserController is responsible for handling user related requests
The
UserController in all cases, except for the
getUsersPage() method, returns a JSON string as indicated in the
@RequestMapping annotation:
produces="application/json"
The methods
create(),
update(),
delete(), and
get() are pretty much straightforward. However, the
records() and
getFilteredRecords() methods are somewhat more involved.
The
records() method basically returns a list of
UserDto objects as JSON strings. If the
search prooperty is true, it will call the
getFilteredRecords() method. Otherwise, it will retrieve all records.
The
getFilteredRecords() is quite interesting. The basic algorithm is as follows:
- Convert a JSON String filter to a JqgridFilter object
- Use JqgridObjectMapper.map() method to do the conversion
(After the conversion, a list of Rule objects are produced)
- Loop these list.
- If any of the fields match "username", "firstName", "lastName", and "role", store its value
(This means we can only search within these fields.)
- Do a repository search based on non-empty field parameters
- Return the results to the presentation layer
Introducing Jsonquery
Question: What if I want to have a dynamic search on all fields? For example, instead of doing a "like" comparison, I want to do a "greater than" or "less than" and combine various operators, i.e. "and", "or".
Answer: This is not possible with the way I coded that here. And even if I could, it would be a big mess of if-else conditions. Luckily, there's a library that would simplify that for us: jsonquery
Jsonquery is a framework that translates SQL-like JSON queries to type-safe JPQL queries through Querydsl which means each query is type-safe, fluent, and SQL-like. Currently, the framework is designed for JPA-based backends.
To see the actual project, please visit https://github.com/markdevcode/jsonquery
To see the samples, please visit https://github.com/markdevcode/jsonquery-samples
However there are caveats: - It's not yet available from the Maven repository (it's on its way)
- You must build and deploy the project from Github
- You must use JPA and QueryDSL
Repository
This layer contains a single interface,
UserRepository. This is our data access object (DAO). With the help of Spring Data JPA, Spring will automatically provide the actual implementation.
What is Spring Data JPA?
Spring JPA is part of the umbrella Spring Data project that makes it easy to easily implement JPA based repositories.
Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.
Source: http://www.springsource.org/spring-data/jpa
Service
This layer contains a single service,
UserService. Its main purpose is to handle the CRUD operations for the
User object. Notice all operations are eventually delegated to the
UserRepository.
Utilities
- JqgridFilter is a Java representation of a jqGrid filter
- JqgridObjectMapper is used to convert a jqGrid filter to a JqgridFilter object
- UserMapper is used to map User objects to UserDto objects
- TraceInterceptor is an AOP-based utility class to help us debug our application. This is a subclass of CustomizableTraceInterceptor (see Spring Data JPA FAQ)
Next
In the next section, we will discuss the presentation layer and write the HTML and JavaScript files.
Click here to proceed.
Subscribe by reader
Subscribe by email
Share