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.Table of Contents
Part 1: Introduction and Functional SpecsPart 2: Java classes
Part 3: HTML and jqGrid
Part 4: XML configuration
Part 5: Running the Application
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.domain; | |
import javax.persistence.CascadeType; | |
import javax.persistence.Column; | |
import javax.persistence.Entity; | |
import javax.persistence.GeneratedValue; | |
import javax.persistence.GenerationType; | |
import javax.persistence.Id; | |
import javax.persistence.OneToOne; | |
@Entity(name="user") | |
public class User { | |
@Id | |
@GeneratedValue(strategy = GenerationType.AUTO) | |
private Long id; | |
private String firstName; | |
private String lastName; | |
@Column(unique=true) | |
private String username; | |
private String password; | |
@OneToOne(mappedBy="user", cascade={CascadeType.ALL}) | |
private Role role; | |
public User() {} | |
public User(String username, String password, String firstName, String lastName, Role role) { | |
this.username = username; | |
this.password = password; | |
this.firstName = firstName; | |
this.lastName = lastName; | |
this.role = role; | |
} | |
public User(String username, String firstName, String lastName, Role role) { | |
this.username = username; | |
this.firstName = firstName; | |
this.lastName = lastName; | |
this.role = role; | |
} | |
public User(String username) { | |
this.username = username; | |
} | |
...getters/setters | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.domain; | |
import javax.persistence.Entity; | |
import javax.persistence.GeneratedValue; | |
import javax.persistence.GenerationType; | |
import javax.persistence.Id; | |
import javax.persistence.OneToOne; | |
@Entity(name="role") | |
public class Role { | |
@Id | |
@GeneratedValue(strategy = GenerationType.AUTO) | |
private Long id; | |
@OneToOne | |
private User user; | |
private Integer role; | |
public Role() {} | |
public Role(Integer role) { | |
this.role = role; | |
} | |
...getters/setters | |
} |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.response; | |
import java.io.Serializable; | |
public class UserDto implements Serializable { | |
private Long id; | |
private String firstName; | |
private String lastName; | |
private String username; | |
private Integer role; | |
...getters/setters | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.response; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* A POJO containing the status of an action and a {@link List} of messages. | |
* This is mainly used as a DTO for the presentation layer | |
*/ | |
public class StatusResponse { | |
private Boolean success; | |
private List<String> message; | |
public StatusResponse() { | |
this.message = new ArrayList<String>(); | |
} | |
public StatusResponse(Boolean success) { | |
super(); | |
this.success = success; | |
this.message = new ArrayList<String>(); | |
} | |
public StatusResponse(Boolean success, String message) { | |
super(); | |
this.success = success; | |
this.message = new ArrayList<String>(); | |
this.message.add(message); | |
} | |
public StatusResponse(Boolean success, List<String> message) { | |
super(); | |
this.success = success; | |
this.message = message; | |
} | |
...getters/setters | |
@Override | |
public String toString() { | |
StringBuilder sb = new StringBuilder(); | |
for (String mess: message) { | |
sb.append(mess +", "); | |
} | |
return "StatusResponse [success=" + success + ", message=" + sb.toString() | |
+ "]"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.response; | |
import java.io.Serializable; | |
import java.util.List; | |
/** | |
* A POJO representing a jQgrid's jsonReader property. | |
* @see <a href="http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data">JSON Data</a> | |
*/ | |
public class JqgridResponse<T extends Serializable> { | |
/** | |
* Current page | |
*/ | |
private String page; | |
/** | |
* Total pages | |
*/ | |
private String total; | |
/** | |
* Total number of records | |
*/ | |
private String records; | |
/** | |
* Contains the actual data | |
*/ | |
private List<T> rows; | |
public JqgridResponse() {} | |
public JqgridResponse(String page, String total, String records, | |
List<T> rows) { | |
super(); | |
this.page = page; | |
this.total = total; | |
this.records = records; | |
this.rows = rows; | |
} | |
...getters/setters | |
@Override | |
public String toString() { | |
return "JqgridResponse [page=" + page + ", total=" + total | |
+ ", records=" + records + "]"; | |
} | |
} |
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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jsonReader : { | |
root: "rows", | |
page: "page", | |
total: "total", | |
records: "records", | |
repeatitems: false, | |
cell: "cell", | |
id: "id" | |
} |
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.controller; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
@Controller | |
@RequestMapping("/") | |
public class MediatorController { | |
@RequestMapping | |
public String getHomePage() { | |
return "redirect:/users"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.controller; | |
import java.util.List; | |
import org.krams.domain.Role; | |
import org.krams.domain.User; | |
import org.krams.repository.UserRepository; | |
import org.krams.response.JqgridResponse; | |
import org.krams.response.StatusResponse; | |
import org.krams.response.UserDto; | |
import org.krams.service.UserService; | |
import org.krams.util.JqgridFilter; | |
import org.krams.util.JqgridObjectMapper; | |
import org.krams.util.UserMapper; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.data.domain.Page; | |
import org.springframework.data.domain.PageRequest; | |
import org.springframework.data.domain.Pageable; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.web.bind.annotation.RequestBody; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RequestMethod; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import org.springframework.web.bind.annotation.ResponseBody; | |
@Controller | |
@RequestMapping("/users") | |
public class UserController { | |
@Autowired | |
private UserRepository repository; | |
@Autowired | |
private UserService service; | |
@RequestMapping | |
public String getUsersPage() { | |
return "users"; | |
} | |
@RequestMapping(value="/records", produces="application/json") | |
public @ResponseBody JqgridResponse<UserDto> records( | |
@RequestParam("_search") Boolean search, | |
@RequestParam(value="filters", required=false) String filters, | |
@RequestParam(value="page", required=false) Integer page, | |
@RequestParam(value="rows", required=false) Integer rows, | |
@RequestParam(value="sidx", required=false) String sidx, | |
@RequestParam(value="sord", required=false) String sord) { | |
Pageable pageRequest = new PageRequest(page-1, rows); | |
if (search == true) { | |
return getFilteredRecords(filters, pageRequest); | |
} | |
Page<User> users = repository.findAll(pageRequest); | |
List<UserDto> userDtos = UserMapper.map(users); | |
JqgridResponse<UserDto> response = new JqgridResponse<UserDto>(); | |
response.setRows(userDtos); | |
response.setRecords(Long.valueOf(users.getTotalElements()).toString()); | |
response.setTotal(Integer.valueOf(users.getTotalPages()).toString()); | |
response.setPage(Integer.valueOf(users.getNumber()+1).toString()); | |
return response; | |
} | |
/** | |
* Helper method for returning filtered records | |
*/ | |
public JqgridResponse<UserDto> getFilteredRecords(String filters, Pageable pageRequest) { | |
String qUsername = null; | |
String qFirstName = null; | |
String qLastName = null; | |
Integer qRole = null; | |
JqgridFilter jqgridFilter = JqgridObjectMapper.map(filters); | |
for (JqgridFilter.Rule rule: jqgridFilter.getRules()) { | |
if (rule.getField().equals("username")) | |
qUsername = rule.getData(); | |
else if (rule.getField().equals("firstName")) | |
qFirstName = rule.getData(); | |
else if (rule.getField().equals("lastName")) | |
qLastName = rule.getData(); | |
else if (rule.getField().equals("role")) | |
qRole = Integer.valueOf(rule.getData()); | |
} | |
Page<User> users = null; | |
if (qUsername != null) | |
users = repository.findByUsernameLike("%"+qUsername+"%", pageRequest); | |
if (qFirstName != null && qLastName != null) | |
users = repository.findByFirstNameLikeAndLastNameLike("%"+qFirstName+"%", "%"+qLastName+"%", pageRequest); | |
if (qFirstName != null) | |
users = repository.findByFirstNameLike("%"+qFirstName+"%", pageRequest); | |
if (qLastName != null) | |
users = repository.findByLastNameLike("%"+qLastName+"%", pageRequest); | |
if (qRole != null) | |
users = repository.findByRole(qRole, pageRequest); | |
List<UserDto> userDtos = UserMapper.map(users); | |
JqgridResponse<UserDto> response = new JqgridResponse<UserDto>(); | |
response.setRows(userDtos); | |
response.setRecords(Long.valueOf(users.getTotalElements()).toString()); | |
response.setTotal(Integer.valueOf(users.getTotalPages()).toString()); | |
response.setPage(Integer.valueOf(users.getNumber()+1).toString()); | |
return response; | |
} | |
@RequestMapping(value="/get", produces="application/json") | |
public @ResponseBody UserDto get(@RequestBody UserDto user) { | |
return UserMapper.map(repository.findByUsername(user.getUsername())); | |
} | |
@RequestMapping(value="/create", produces="application/json", method=RequestMethod.POST) | |
public @ResponseBody StatusResponse create( | |
@RequestParam String username, | |
@RequestParam String password, | |
@RequestParam String firstName, | |
@RequestParam String lastName, | |
@RequestParam Integer role) { | |
User newUser = new User(username, password, firstName, lastName, new Role(role)); | |
Boolean result = service.create(newUser); | |
return new StatusResponse(result); | |
} | |
@RequestMapping(value="/update", produces="application/json", method=RequestMethod.POST) | |
public @ResponseBody StatusResponse update( | |
@RequestParam String username, | |
@RequestParam String firstName, | |
@RequestParam String lastName, | |
@RequestParam Integer role) { | |
User existingUser = new User(username, firstName, lastName, new Role(role)); | |
Boolean result = service.update(existingUser); | |
return new StatusResponse(result); | |
} | |
@RequestMapping(value="/delete", produces="application/json", method=RequestMethod.POST) | |
public @ResponseBody StatusResponse delete( | |
@RequestParam String username) { | |
User existingUser = new User(username); | |
Boolean result = service.delete(existingUser); | |
return new StatusResponse(result); | |
} | |
} |
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.repository; | |
import org.krams.domain.User; | |
import org.springframework.data.domain.Page; | |
import org.springframework.data.domain.Pageable; | |
import org.springframework.data.jpa.repository.JpaRepository; | |
import org.springframework.data.jpa.repository.Query; | |
import org.springframework.data.repository.query.Param; | |
public interface UserRepository extends JpaRepository<User, Long> { | |
User findByUsername(String username); | |
Page<User> findByUsernameLike(String username, Pageable pageable); | |
Page<User> findByFirstNameLike(String firstName, Pageable pageable); | |
Page<User> findByLastNameLike(String lastName, Pageable pageable); | |
Page<User> findByFirstNameLikeAndLastNameLike(String firstName, String lastName, Pageable pageable); | |
@Query("select u from user u where u.role.role = :role") | |
Page<User> findByRole(@Param("role") Integer role, Pageable pageable); | |
} |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.service; | |
import org.krams.domain.User; | |
import org.krams.repository.UserRepository; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Service; | |
import org.springframework.transaction.annotation.Transactional; | |
@Transactional | |
@Service | |
public class UserService { | |
@Autowired | |
private UserRepository repository; | |
public Boolean create(User user) { | |
user.getRole().setUser(user); | |
User saved = repository.save(user); | |
if (saved == null) | |
return false; | |
return true; | |
} | |
public Boolean update(User user) { | |
User existingUser = repository.findByUsername(user.getUsername()); | |
if (existingUser == null) | |
return false; | |
// Only firstName, lastName, and role fields are updatable | |
existingUser.setFirstName(user.getFirstName()); | |
existingUser.setLastName(user.getLastName()); | |
existingUser.getRole().setRole(user.getRole().getRole()); | |
User saved = repository.save(existingUser); | |
if (saved == null) | |
return false; | |
return true; | |
} | |
public Boolean delete(User user) { | |
User existingUser = repository.findByUsername(user.getUsername()); | |
if (existingUser == null) | |
return false; | |
repository.delete(existingUser); | |
User deletedUser = repository.findByUsername(user.getUsername()); | |
if (deletedUser != null) | |
return false; | |
return true; | |
} | |
} |
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.util; | |
import java.util.ArrayList; | |
/** | |
* A POJO that represents a jQgrid JSON requests {@link String}<br/> | |
* A sample filter follows the following format: | |
* <pre> | |
* {"groupOp":"AND","rules":[{"field":"firstName","op":"eq","data":"John"}]} | |
* </pre> | |
*/ | |
public class JqgridFilter { | |
private String source; | |
private String groupOp; | |
private ArrayList<Rule> rules; | |
public JqgridFilter() { | |
super(); | |
} | |
public JqgridFilter(String source) { | |
super(); | |
this.source = source; | |
} | |
...getters/setters | |
/** | |
* Inner class containing field rules | |
*/ | |
public static class Rule { | |
private String junction; | |
private String field; | |
private String op; | |
private String data; | |
public Rule() {} | |
public Rule(String junction, String field, String op, String data) { | |
super(); | |
this.junction = junction; | |
this.field = field; | |
this.op = op; | |
this.data = data; | |
} | |
...getters/setters | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.util; | |
import org.codehaus.jackson.map.ObjectMapper; | |
/** | |
* Maps a jQgrid JSON query to a {@link JqgridFilter} instance | |
*/ | |
public class JqgridObjectMapper { | |
public static JqgridFilter map(String jsonString) { | |
if (jsonString != null) { | |
ObjectMapper mapper = new ObjectMapper(); | |
try { | |
return mapper.readValue(jsonString, JqgridFilter.class); | |
} catch (Exception e) { | |
throw new RuntimeException (e); | |
} | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.util; | |
import java.util.ArrayList; | |
import java.util.List; | |
import org.krams.domain.User; | |
import org.krams.response.UserDto; | |
import org.springframework.data.domain.Page; | |
public class UserMapper { | |
public static UserDto map(User user) { | |
UserDto dto = new UserDto(); | |
dto.setId(user.getId()); | |
dto.setFirstName(user.getFirstName()); | |
dto.setLastName(user.getLastName()); | |
dto.setUsername(user.getUsername()); | |
dto.setRole(user.getRole().getRole()); | |
return dto; | |
} | |
public static List<UserDto> map(Page<User> users) { | |
List<UserDto> dtos = new ArrayList<UserDto>(); | |
for (User user: users) { | |
dtos.add(map(user)); | |
} | |
return dtos; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.krams.aop; | |
import org.aopalliance.intercept.MethodInvocation; | |
import org.apache.commons.logging.Log; | |
import org.apache.log4j.Logger; | |
import org.springframework.aop.interceptor.CustomizableTraceInterceptor; | |
/** | |
* Extends {@link CustomizableTraceInterceptor} to provide custom logging levels | |
*/ | |
public class TraceInterceptor extends CustomizableTraceInterceptor { | |
private static final long serialVersionUID = 287162721460370957L; | |
protected static Logger logger4J = Logger.getLogger("aop"); | |
@Override | |
protected void writeToLog(Log logger, String message, Throwable ex) { | |
if (ex != null) { | |
logger4J.debug(message, ex); | |
} else { | |
logger4J.debug(message); | |
} | |
} | |
@Override | |
protected boolean isInterceptorEnabled(MethodInvocation invocation, Log logger) { | |
return true; | |
} | |
} |
Next
In the next section, we will discuss the presentation layer and write the HTML and JavaScript files. Click here to proceed.
Share the joy:
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |


nice tutorial.
ReplyDeletei have a column with user_id , how to write a method for this column in repository class.
in my code
Page findByUserid(Integer user_id, Pageable pageable);
Error
Caused by: java.lang.IllegalArgumentException: No property user found for type class org.krams.domain.User
@Anonymous, I think it should be:
ReplyDeletePage findByUser_Id(Integer user_id, Pageable pageable);
Thanks it worked out for me.
DeleteThanks You
ReplyDeleteOne comment : Sort is missing ;)
Thanks for sharing it works for Me...:)
ReplyDeleteAwesome tutorial, thanks!
ReplyDeleteThis comment has been removed by the author.
ReplyDelete@krams :hi i would like to ask that send me entire project to my email id:sag38.keerthi@gmail.com
ReplyDeleteif u wont mind...
eagerly waiting for this code..
I don't understand why you need it to be sent by email? You can download the whole project from Github.
Delete@krams :hi i kram i need pagination in spring 3.x
ReplyDeleteif u know then farward me that project also
but i just kept project in hold because of that issue..so please send me that code to mail id
:sag38.keerthi@gmail.com
Why don't you use Spring Data? It has built-in pagination support. Are you asking something in the frontend layer? I suggest using one of the existing jQuery table plugins.
DeleteThis comment has been removed by the author.
ReplyDeleteHi @Krams: First i want to thank you as your tutorial and example are the best, the best as i have tried many as new to Spring and hibernate all other post by many famous people gave many error and it never execute properly, yours is the best, thanks again for sharing such great knowledge
ReplyDeleteQuestion:for some reason @RequestMapping(value="/update", produces="application/json", method=RequestMethod.POST) is giving me error under Produces , can you help me with this, how can i resolve it?
What specific error are you getting? Can you copy and paste it here using pastebin.com?
DeleteHi @Krams: Thank you for the tutorial. I am wondering why you use UserDto DTO in the tutorial. Can you just use domain object User alone instead?
ReplyDeletecan you pls provide the link from where we can download the project
ReplyDeletewhy you dont just extend your Entity as Serializable and use it in your Jqgrid response?
ReplyDeleteI have read your blog its very attractive and impressive. I like it your blog.
ReplyDeleteSpring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training
spring training in chennai spring hibernate training in chennai
Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
ReplyDeletecore java training in Electronic City
Hibernate Training in electronic city
spring training in electronic city
java j2ee training in electronic city
yeezy outlet
ReplyDeletepalm angels hoodie
jordan outlet
fear of god hoodie
bape clothing
off white clothing
jordans
kyrie 6
hermes outlet
yeezy