7.9.2. Customer Controller Class

Controller classes start with the @Controller annotation. The @RequestMapping annotation preceding the method is necessary for directing the actions of the controller, for specifying the path that will be used to call the action.

  • The path is specified in the value attribute

  • The method attribute specifies the HTTP request method (PUT, GET, POST, DELETE)

  • The index method will be the input point of our controller. It is responsible for displaying the JSP page (view) that contains the layout for displaying the grid, the tool bar and the navigation bar.

Data for display are loaded asynchronously by the jqGrid component. The path is /customer/getdata, to which the getData method is connected.

getData Method

The getData method contains the additional @ResponseBody annotation for indicating that our method returns the object for serialization into a specific format. The annotation @RequestMapping contains the attribute produces = MediaType.APPLICATION_JSON, directing that the returned object be serialized into the JSON format.

It is in the getData method that we work with the JqGridCustomer class described earlier. The @RequestParam annotation enables the value of the parameter to be retrieved from the HTTP request. This class method works with GET requests.

  • The value attribute in the @RequestParam annotation defines the name of the parameter to be retrieved from the HTTP request.

  • The Required attribute can designate the HTTP request parameter as mandatory.

  • The defaultValue attribute supplies the value that is to be used if the HTTP parameter is not specified.

Customer Action Methods

The addCustomer method is used to add a new customer. It is connected with the /customer/create path and, unlike the previous method, it works with the POST request. The method returns {success: true} if the customer is added successfully. If an error occurs, it returns an object with the error message. The addCustomer method works with the CustomerManager business layer method.

The editCustomer method is connected with the /customer/edit path. The deleteCustomer method is connected with the /customer/delete path. Both methods operate on existing customer records.

  1. package ru.ibase.fbjavaex.controllers;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.ui.ModelMap;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RequestMethod;
  8. import org.springframework.web.bind.annotation.ResponseBody;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import javax.ws.rs.core.MediaType;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import ru.ibase.fbjavaex.managers.CustomerManager;
  13. import ru.ibase.fbjavaex.jqgrid.JqGridCustomer;
  14. import ru.ibase.fbjavaex.jqgrid.JqGridData;
  15. /**
  16. * Customer Controller
  17. *
  18. * @author Simonov Denis
  19. */
  20. @Controller
  21. public class CustomerController {
  22. @Autowired(required = true)
  23. private JqGridCustomer customerGrid;
  24. @Autowired(required = true)
  25. private CustomerManager customerManager;
  26. /**
  27. * Default action
  28. * Returns the JSP name of the page (view) to display
  29. *
  30. * @param map
  31. * @return name of JSP template
  32. */
  33. @RequestMapping(value = "/customer/", method = RequestMethod.GET)
  34. public String index(ModelMap map) {
  35. return "customer";
  36. }
  37. /**
  38. * Returns JSON data for jqGrid
  39. *
  40. * @param rows number of entries per page
  41. * @param page page number
  42. * @param sIdx sorting field
  43. * @param sOrd sorting order
  44. * @param search should the search be performed
  45. * @param searchField search field
  46. * @param searchString value for searching
  47. * @param searchOper search operation
  48. * @return JSON data for jqGrid
  49. */
  50. @RequestMapping(value = "/customer/getdata",
  51. method = RequestMethod.GET,
  52. produces = MediaType.APPLICATION_JSON)
  53. @ResponseBody
  54. public JqGridData getData(
  55. // number of entries per page
  56. @RequestParam(value = "rows", required = false,
  57. defaultValue = "20") int rows,
  58. // page number
  59. @RequestParam(value = "page", required = false,
  60. defaultValue = "1") int page,
  61. // sorting field
  62. @RequestParam(value = "sidx", required = false,
  63. defaultValue = "") String sIdx,
  64. // sorting order
  65. @RequestParam(value = "sord", required = false,
  66. defaultValue = "asc") String sOrd,
  67. // should the search be performed
  68. @RequestParam(value = "_search", required = false,
  69. defaultValue = "false") Boolean search,
  70. // search field
  71. @RequestParam(value = "searchField", required = false,
  72. defaultValue = "") String searchField,
  73. // value for searching
  74. @RequestParam(value = "searchString", required = false,
  75. defaultValue = "") String searchString,
  76. // search operation
  77. @RequestParam(value = "searchOper", required = false,
  78. defaultValue = "") String searchOper,
  79. // filters
  80. @RequestParam(value="filters", required=false,
  81. defaultValue="") String filters) {
  82. customerGrid.setLimit(rows);
  83. customerGrid.setPageNo(page);
  84. customerGrid.setOrderBy(sIdx, sOrd);
  85. if (search) {
  86. customerGrid.setSearchCondition(searchField, searchString, searchOper);
  87. }
  88. return customerGrid.getJqGridData();
  89. }
  90. @RequestMapping(value = "/customer/create",
  91. method = RequestMethod.POST,
  92. produces = MediaType.APPLICATION_JSON)
  93. @ResponseBody
  94. public Map<String, Object> addCustomer(
  95. @RequestParam(value = "NAME", required = true,
  96. defaultValue = "") String name,
  97. @RequestParam(value = "ADDRESS", required = false,
  98. defaultValue = "") String address,
  99. @RequestParam(value = "ZIPCODE", required = false,
  100. defaultValue = "") String zipcode,
  101. @RequestParam(value = "PHONE", required = false,
  102. defaultValue = "") String phone) {
  103. Map<String, Object> map = new HashMap<>();
  104. try {
  105. customerManager.create(name, address, zipcode, phone);
  106. map.put("success", true);
  107. } catch (Exception ex) {
  108. map.put("error", ex.getMessage());
  109. }
  110. return map;
  111. }
  112. @RequestMapping(value = "/customer/edit",
  113. method = RequestMethod.POST,
  114. produces = MediaType.APPLICATION_JSON)
  115. @ResponseBody
  116. public Map<String, Object> editCustomer(
  117. @RequestParam(value = "CUSTOMER_ID", required = true,
  118. defaultValue = "0") int customerId,
  119. @RequestParam(value = "NAME", required = true,
  120. defaultValue = "") String name,
  121. @RequestParam(value = "ADDRESS", required = false,
  122. defaultValue = "") String address,
  123. @RequestParam(value = "ZIPCODE", required = false,
  124. defaultValue = "") String zipcode,
  125. @RequestParam(value = "PHONE", required = false,
  126. defaultValue = "") String phone) {
  127. Map<String, Object> map = new HashMap<>();
  128. try {
  129. customerManager.edit(customerId, name, address, zipcode, phone);
  130. map.put("success", true);
  131. } catch (Exception ex) {
  132. map.put("error", ex.getMessage());
  133. }
  134. return map;
  135. }
  136. @RequestMapping(value = "/customer/delete",
  137. method = RequestMethod.POST,
  138. produces = MediaType.APPLICATION_JSON)
  139. @ResponseBody
  140. public Map<String, Object> deleteCustomer(
  141. @RequestParam(value = "CUSTOMER_ID", required = true,
  142. defaultValue = "0") int customerId) {
  143. Map<String, Object> map = new HashMap<>();
  144. try {
  145. customerManager.delete(customerId);
  146. map.put("success", true);
  147. } catch (Exception ex) {
  148. map.put("error", ex.getMessage());
  149. }
  150. return map;
  151. }
  152. }

Customer Display

The JSP page for displaying the customer module contains nothing special: the layout with the main parts of the page, the table for displaying the grid and the block for displaying the navigation bar. JSP templates are fairly unsophisticated. If you wish, you can replace them with other template systems that support inheritance.

The ../jspf/head.jspf file contains common scripts and styles for all website pages and the ../jspf/menu.jspf file contains the website’s main menu. Their code is not reproduced here: it is quite simple and you can examine it in the project’s source if you are curious.

  1. <%@page contentType="text/html" pageEncoding="UTF-8"%>
  2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  3. <c:set var="cp" value="${pageContext.request.servletContext.contextPath}"
  4. scope="request" />
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  9. <title>An example of a Spring MVC application using Firebird
  10. and jOOQ</title>
  11. <!-- Scripts and styles -->
  12. <%@ include file="../jspf/head.jspf" %>
  13. <script src="${cp}/resources/js/jqGridCustomer.js"></script>
  14. </head>
  15. <body>
  16. <!-- Navigation menu -->
  17. <%@ include file="../jspf/menu.jspf" %>
  18. <div class="container body-content">
  19. <h2>Customers</h2>
  20. <table id="jqGridCustomer"></table>
  21. <div id="jqPagerCustomer"></div>
  22. <hr/>
  23. <footer>
  24. <p>&copy; 2016 - An example of a Spring MVC application
  25. using Firebird and jOOQ</p>
  26. </footer>
  27. </div>
  28. <script type="text/javascript">
  29. $(document).ready(function () {
  30. JqGridCustomer({
  31. baseAddress: '${cp}'
  32. });
  33. });
  34. </script>
  35. </body>
  36. </html>

The basic logic on the client side is concentrated in the /resources/js/jqGridCustomer.js JavaScript module.

  1. var JqGridCustomer = (function ($) {
  2. return function (options) {
  3. var jqGridCustomer = {
  4. dbGrid: null,
  5. options: $.extend({
  6. baseAddress: null,
  7. showEditorPanel: true
  8. }, options),
  9. // return model description
  10. getColModel: function () {
  11. return [
  12. {
  13. label: 'Id',
  14. name: 'CUSTOMER_ID', // field name
  15. key: true,
  16. hidden: true
  17. },
  18. {
  19. label: 'Name',
  20. name: 'NAME',
  21. width: 240,
  22. sortable: true,
  23. editable: true,
  24. edittype: "text", // input field type in the editor
  25. search: true,
  26. searchoptions: {
  27. // allowed search operators
  28. sopt: ['eq', 'bw', 'cn']
  29. },
  30. // size and maximum length for the input field
  31. editoptions: {size: 30, maxlength: 60},
  32. editrules: {required: true}
  33. },
  34. {
  35. label: 'Address',
  36. name: 'ADDRESS',
  37. width: 300,
  38. sortable: false, // prohibit sorting
  39. editable: true,
  40. search: false, // prohibit search
  41. edittype: "textarea", // Memo field
  42. editoptions: {maxlength: 250, cols: 30, rows: 4}
  43. },
  44. {
  45. label: 'Zip Code',
  46. name: 'ZIPCODE',
  47. width: 30,
  48. sortable: false,
  49. editable: true,
  50. search: false,
  51. edittype: "text",
  52. editoptions: {size: 30, maxlength: 10}
  53. },
  54. {
  55. label: 'Phone',
  56. name: 'PHONE',
  57. width: 80,
  58. sortable: false,
  59. editable: true,
  60. search: false,
  61. edittype: "text",
  62. editoptions: {size: 30, maxlength: 14}
  63. }
  64. ];
  65. },
  66. // grid initialization
  67. initGrid: function () {
  68. // url to retrieve data
  69. var url = jqGridCustomer.options.baseAddress
  70. + '/customer/getdata';
  71. jqGridCustomer.dbGrid = $("#jqGridCustomer").jqGrid({
  72. url: url,
  73. datatype: "json", // data format
  74. mtype: "GET", // request type
  75. colModel: jqGridCustomer.getColModel(),
  76. rowNum: 500, // number of rows displayed
  77. loadonce: false, // load only once
  78. sortname: 'NAME', // Sorting by NAME by default
  79. sortorder: "asc",
  80. width: window.innerWidth - 80,
  81. height: 500,
  82. viewrecords: true, // display the number of records
  83. guiStyle: "bootstrap",
  84. iconSet: "fontAwesome",
  85. caption: "Customers",
  86. // navigation item
  87. pager: 'jqPagerCustomer'
  88. });
  89. },
  90. // editing options
  91. getEditOptions: function () {
  92. return {
  93. url: jqGridCustomer.options.baseAddress + '/customer/edit',
  94. reloadAfterSubmit: true,
  95. closeOnEscape: true,
  96. closeAfterEdit: true,
  97. drag: true,
  98. width: 400,
  99. afterSubmit: jqGridCustomer.afterSubmit,
  100. editData: {
  101. // In addition to the values from the form, pass the key field
  102. CUSTOMER_ID: function () {
  103. // get the current row
  104. var selectedRow = jqGridCustomer.dbGrid.getGridParam("selrow");
  105. // get the value of the field CUSTOMER_ID
  106. var value = jqGridCustomer.dbGrid.getCell(selectedRow,
  107. 'CUSTOMER_ID');
  108. return value;
  109. }
  110. }
  111. };
  112. },
  113. // Add options
  114. getAddOptions: function () {
  115. return {
  116. url: jqGridCustomer.options.baseAddress + '/customer/create',
  117. reloadAfterSubmit: true,
  118. closeOnEscape: true,
  119. closeAfterAdd: true,
  120. drag: true,
  121. width: 400,
  122. afterSubmit: jqGridCustomer.afterSubmit
  123. };
  124. },
  125. // Edit options
  126. getDeleteOptions: function () {
  127. return {
  128. url: jqGridCustomer.options.baseAddress + '/customer/delete',
  129. reloadAfterSubmit: true,
  130. closeOnEscape: true,
  131. closeAfterDelete: true,
  132. drag: true,
  133. msg: "Delete the selected customer?",
  134. afterSubmit: jqGridCustomer.afterSubmit,
  135. delData: {
  136. // pass the key field
  137. CUSTOMER_ID: function () {
  138. var selectedRow = jqGridCustomer.dbGrid.getGridParam("selrow");
  139. var value = jqGridCustomer.dbGrid.getCell(selectedRow,
  140. 'CUSTOMER_ID');
  141. return value;
  142. }
  143. }
  144. };
  145. },
  146. // initializing the navigation bar with editing dialogs
  147. initPagerWithEditors: function () {
  148. jqGridCustomer.dbGrid.jqGrid('navGrid', '#jqPagerCustomer',
  149. {
  150. // buttons
  151. search: true,
  152. add: true,
  153. edit: true,
  154. del: true,
  155. view: true,
  156. refresh: true,
  157. // button captions
  158. searchtext: "Search",
  159. addtext: "Add",
  160. edittext: "Edit",
  161. deltext: "Delete",
  162. viewtext: "View",
  163. viewtitle: "Selected record",
  164. refreshtext: "Refresh"
  165. },
  166. jqGridCustomer.getEditOptions(),
  167. jqGridCustomer.getAddOptions(),
  168. jqGridCustomer.getDeleteOptions()
  169. );
  170. },
  171. // initialize the navigation bar without editing dialogs
  172. initPagerWithoutEditors: function () {
  173. jqGridCustomer.dbGrid.jqGrid('navGrid', '#jqPagerCustomer',
  174. {
  175. // buttons
  176. search: true,
  177. add: false,
  178. edit: false,
  179. del: false,
  180. view: false,
  181. refresh: true,
  182. // button captions
  183. searchtext: "Search",
  184. viewtext: "View",
  185. viewtitle: "Selected record",
  186. refreshtext: "Refresh"
  187. }
  188. );
  189. },
  190. // initialize the navigation bar
  191. initPager: function () {
  192. if (jqGridCustomer.options.showEditorPanel) {
  193. jqGridCustomer.initPagerWithEditors();
  194. } else {
  195. jqGridCustomer.initPagerWithoutEditors();
  196. }
  197. },
  198. // initialize
  199. init: function () {
  200. jqGridCustomer.initGrid();
  201. jqGridCustomer.initPager();
  202. },
  203. // processor of the results of processing forms (operations)
  204. afterSubmit: function (response, postdata) {
  205. var responseData = response.responseJSON;
  206. // check the result for error messages
  207. if (responseData.hasOwnProperty("error")) {
  208. if (responseData.error.length) {
  209. return [false, responseData.error];
  210. }
  211. } else {
  212. // if an error was not returned, refresh the grid
  213. $(this).jqGrid(
  214. 'setGridParam',
  215. {
  216. datatype: 'json'
  217. }
  218. ).trigger('reloadGrid');
  219. }
  220. return [true, "", 0];
  221. }
  222. };
  223. jqGridCustomer.init();
  224. return jqGridCustomer;
  225. };
  226. })(jQuery);

Visual Elements

The jqGrid grid

is created in the initGrid method and is bound to the html element with the jqGridCustomer identifier. The grid column desciptions are returned by the getColModel method.

Each column in jqGrid has a number of properties available. The source code contains comments explaining column properties. You can read more details about configuring the model of jqGrid columns in the ColModel API section of the documentation for the jqGrid project.

The navigation bar

can be created either with edit buttons or without them, using the initPagerWithEditors and initPagerWithoutEditors methods, respectively. The bar constructor binds it to the element with the jqPagerCustomer identifier. The options for creating the navigation bar are described in the Navigator section of the jqGrid documentation.

Functions and Settings for Options

The getEditOptions, getAddOptions, getDeleteOptions functions return the options for the edit, add and delete dialog boxes, respectively.

The url property defines the URL to which the data will be submitted after the OK button in clicked in the dialog box.

The afterSubmit property marks the event that occurs after the data have been sent to the server and a response has been received back.

The afterSubmit method checks whether the controller returns an error. The grid is updated if no error is returned; otherwise, the error is shown to the user.

The editData property allows you to specify the values of additional fields that are not shown in the edit dialog box. Edit dialog boxes do not show the values of hidden fields and it is rather tedious if you want to display automatically generated keys.