Hope you've had nice holiday.
Now we are familiar with Spring-MVC and JQuery enough. I think it's the time to mix our knowledge of High-Tech technologies. Here I'm going to continue the JQuery course in JQuery-plugin and also take a sample joining Spring MVC and JQuery-Plugin(JQGrid) using JSon.
Ok let's start...
First JQuery-Plugin
7. JQuery-Plugin
7.1 jqGrid
jqGrid is an Ajax-enabled JavaScript control that provides solutions for representing and manipulating tabular data on the web. Since the grid is a client-side solution loading data dynamically through Ajax callbacks, it can be integrated with any server-side technology, including PHP, ASP, Java Servlets, JSP, ColdFusion, and Perl.
jqGrid uses a jQuery Java Script Library and is written as plugin for that package. jqGrid's Home page can be found here.
Here you can take look of simple view of jqGrid
Simple jqGrid |
An instance of jqGrid is a javascript object, with properties, events and methods. Properties may be strings, numbers, arrays, boolean values or even other objects.
Calling Convention:
jQuery("#grid_id").jqGrid(properties );
- grid_id is the id of the <table> element defined separately in your html and used as the name of your grid.
- properties is an array of settings in name: value pairs format. Some of these settings are values, some are functions to be performed on an event. Some of these settings are optional while others must be present for jqGrid to work.
jQuery("#list").jqGrid({
url:'example.html',
datatype: 'xml',
mtype: 'GET',
colNames:['Inv No','Date', 'Amount','Tax','Total','Notes'],
colModel :[
{name:'invid', index:'invid', width:55},
{name:'invdate', index:'invdate', width:90},
{name:'amount', index:'amount', width:80, align:'right'},
{name:'tax', index:'tax', width:80, align:'right'},
{name:'total', index:'total', width:80, align:'right'},
{name:'note', index:'note', width:150, sortable:false} ],
pager: jQuery('#pager'),
rowNum:10,
rowList:[10,20,30],
sortname: 'id',
sortorder: "desc",
viewrecords: true,
imgpath: 'themes/basic/images',
caption: 'My first grid'
});
Events raised by the grid, which offer opportunities to perform additional actions, are described in Events in future post.
The grid also offers several methods for getting or setting properties or data: Methods will be described in future post.
A key property of the grid is the column model (colModel) that defines the contents of the grid: colModel Properties
Additional properties, events and methods of the basic grid, not described in this section, are used to create and manage the three special types of grids: multiselect grids, subGrids and treeGrids. I will handle them in future posts.
7.1.2 Properites
The available properties are listed here, in alphabetic order. Some have more details described.
Property | Type | Description | Default |
---|---|---|---|
altRows | boolean | Set a zebra-striped grid | true |
caption | string | Defines the Caption layer for the grid. This caption appear above the Header layer. If the string is empty the caption does not appear. | empty string |
cellEdit | boolean | Enables (disables) cell editing. | true |
cellsubmit | string | Determines where the contents of the cell are saved: 'remote' or 'clientArray'. | 'remote' |
cellurl | string | the url where the cell is to be saved. | null |
colModel | array | Array which describes the parameters of the columns. For a full description of all valid values see colModel API. | empty array |
colNames | array | Array which describes the column labels in the grid | empty array |
datastr | string | The string of data when datatype parameter is set to xmlstring or jsonstring | null |
datatype | string | Defines what type of information to expect to represent data in the grid. Valid options are xml - we expect xml data; xmlstring - we expect xml data as string; json - we expect JSON data; jsonstring - we expect JSON data as string; clientSide - we expect data defined at client side (array data) | xml |
editurl | string | Defines the url for inline and form editing. | null |
ExpandColumn | string | indicates which column (name from colModel) should be used to expand the tree grid. If not set the first one is used. Valid only when treeGrid option is set to true. | null |
forceFit | boolean | If set to true, and resizing the width of a column, the adjacent column (to the right) will resize so that the overall grid width is maintained (e.g., reducing the width of column 2 by 30px will increase the size of column 3 by 30px). In this case there is no horizontal scrolbar. Note: this option is not compatible with shrinkToFit option - i.e if shrinkToFit is set to false, forceFit is ignored. | false |
gridstate | string | Determines the current state of the grid (i.e. when used with hiddengrid, hidegrid and caption options). Can have either of two states: 'visible' or 'hidden' | visible |
hiddengrid | boolean | If set to true the grid initially is hidden. The data is not loaded (no request is sent) and only the caption layer is shown. When the show/hide button is clicked the first time to show grid, the request is sent to the server, the data is loaded, and grid is shown. From this point we have a regular grid. This option has effect only if the caption property is not empty and the hidegrid property (see below) is set to true. | false |
hidegrid | boolean | Enables or disables the show/hide grid button, which appears on the right side of the Caption layer. Takes effect only if the caption property is not an empty string. | true |
height | string | The height of the grid. Can be set as percentage or any valid measured value | 150px |
imgpath | string | Defines the path to the images that are used in the grid. Set this option without / at end | empty string |
jsonReader | array | Array which describes the structure of the expected json data. For a full description and default setting | |
loadonce | boolean | If this flag is set to true, the grid loads the data from the server only once (using the appropriate datatype). After the first request the datatype parameter is automatically changed to clientSide and all further manipulations are done on the client side. The functions of the pager (if present) are disabled. | false |
loadtext | string | The text which appear when requesting and sorting data | Loading... |
loadui | string | This option controls what to do when an ajax operation is in progress.
| |
mtype | string | Defines the type of request to make ("POST" or "GET") | GET |
multikey | string | This parameter have sense only multiselect option is set to true. Defines the key which will be pressed when we make multiselection. The possible values are: shiftKey - the user should press Shift Key altKey - the user should press Alt Key ctrlKey - the user should press Ctrl Key | empty string |
multiboxonly | boolean | This option works only when multiselect = true. When multiselect is set to true, clicking anywhere on a row selects that row; when multiboxonly is also set to true, the row is selected only when the checkbox is clicked (Yahoo style). | false |
multiselect | boolean | If this flag is set to true a multi selection of rows is enabled. A new column at left side is added. Can be used with any datatype option. | false |
prmnames | array | Customizes names of the fields sent to the server on a Post: default values for these fields are "page", "rows", "sidx", and "sord". For example, with this setting, you can change the sort order element from "sidx" to "mysort": prmNames: {sort: "mysort"} The string that will be posted to the server will then be myurl.html?page=1&rows=10&mysort=myindex&sord=asc rather than myurl.php?page=1&rows=10&sidx=myindex&sord=asc | none |
postData | array | This array is passed directly to the url. This is associative array and can be used this way: {name1:value1...}. | empty array |
resizeclass | string | Assigns a class to columns that are resizable so that we can show a resize handle only for ones that are resizable | grid_resize |
scroll | boolean | Creates dynamic scrolling grids. When enabled, the pager elements are disabled and we can use the vertical scrollbar to load data. This option currently should be used carefully on big data sets, since I have not developed an intelligent swapper, which means that all the data is loaded and a lot of memory will be used if the dataset is large. You must be sure to have a initial vertical scroll in grid, i.e. the height should not be set to auto. | false |
scrollrows | boolean | When enabled, selecting a row with setSelection scrolls the grid so that the selected row is visible. This is especially useful when we have a verticall scrolling grid and we use form editing with navigation buttons (next or previous row). On navigating to a hidden row, the grid scrolls so the selected row becomes visible. | false |
sortclass | string | the class to be applied to the currently sorted column, i.e. applied to the th element | grid_sort |
shrinkToFit | boolean | This option describes the type of calculation of the initial width of each column against with the width of the grid. If the value is true and the value in width option is set then: Every column width is scaled according to the defined option width. Example: if we define two columns with a width of 80 and 120 pixels, but want the grid to have a 300 pixels - then the columns are recalculated as follow: 1- column = 300(new width)/200(sum of all width)*80(column width) = 120 and 2 column = 300/200*120 = 180. The grid width is 300px. If the value is false and the value in width option is set then: The width of the grid is the width set in option. The column width are not recalculated and have the values defined in colModel. | true |
sortascimg, sortdescimg | string | Links to image url which are used when the user sort a column | sort_asc.gif, sort_desc.gif |
sortname | string | The initial sorting name when we use datatypes xml or json (data returned from server) | none (empty string) |
sortorder | string | The initial sorting order when we use datatypes xml or json (data returned from server) | asc |
toolbar | array | This option defines the toolbar of the grid. This is array with two values in which the first value enables the toolbar and the second defines the position relative to body Layer. Possible values "top" or "bottom" | [false,"top"] |
treeGrid | boolean | Enables (disables) the tree grid format. | false |
tree_root_level | numeric | Determines the level where the root element begins when treeGrid is enabled | 0 |
url | string | The url of the file that holds the request | null |
userData | array | This array contain custom information from the request. Can be used at any time. | empty array |
width | number | If this option is not set, the width of the grid is a sum of the widths of the columns defined in the colModel (in pixels). If this option is set, the initial width of each column is set according to the value of shrinkToFit option. | none |
xmlReader | array | Array which describes the structure of the expected xml data. | |
$.jgrid.default | array | This array is used to define a grid option common to all jqGrids in the application. Typically, this is called once to set the default for one or more grid parameters -- any parameter can be changed. Typical implementation; $.extend($.jgrid.defaults,{rowNum:10}) | empty array |
7.1.3 colModel
The colModel property defines the individual grid columns as an array of properties.
Syntax:
colModel: [
{name:'name1', index:'index1'...},
{...},
...
]
Property | Type | Description | Default |
---|---|---|---|
align | string | Defines the alignment of the cell in the Body layer, not in header cell. Possible values: left, center, right. | left |
datefmt | string | Governs format of sorttype:date and editrules {date:true} fields. Determines the expected date format for that column. Uses a PHP-like date formatting. Currently "/", "-", and "." are supported as date separators. Valid formats are:
| ISO Date (Y-m-d) |
editable | boolean | Defines if the field is editable. This option is used in inline and form modules. | false |
editoptions | array | Array of allowed options (attributes) for edittype option | empty array |
editrules | array | editrules: {edithidden:true(false), required:true(false), number:true(false), minValue:val, maxValue:val, email:true(false), date:true(false)}
For example, colModel: [ ... {...editrules:{required:false, number:true..}...} ... ] In this case, if no data is provided by the user (it is left blank) the alert message does not appear - i.e. this is considered to be valid input. | empty array |
edittype | string | Defines the edit type for inline and form editing Possible values: text, textarea, select, checkbox, password | text |
formatoptions | array | Format options can be defined for particular columns,overwriting the defaults from the language file. See formatter for more details. | none |
formatter | string | The predefined types or custom function name that controls the format of this field. See formatter for more details. | none |
hidedlg | boolean | If set to true this column will not appear in the modal dialog where users can choose which columns to show or hide. | false |
hidden | boolean | Defines if this column is hidden at initialization. | false |
index | string | Set the index name when sorting. Passed as sidx parameter. | the order of cell |
jsonmap | string | Defines the json mapping for the column in the incoming json string. | none |
key | boolean | In case if there is no id from server, this can be set as as id for the unique row id. Only one column can have this property. If there are more than one key the grid finds the first one and the second is ignored. | false |
label | string | When colNames array is empty, defines the heading for this column. If both the colNames array and this setting are empty, the heading for this column comes from the name property. | none |
name | string | Set the unique name in the grid for the column. This property is required. As well as other words used as property/event names, the reserved words (which cannot be used for names) include subgrid and cb. | |
resizable | boolean | Defines if the column can be resized | true |
search | boolean | When used in formedit, disables or enables searching on that column | true |
sortable | boolean | Defines is this can be sorted. | true |
sorttype | string | Used when datatype is clientSide. Defines the type of the column for appropriate sorting. Possible values:
| text |
width | number | Set the initial width of the column, in pixels | 150 |
xmlmap | string | Defines the xml mapping for the column in the incomming xml file. Use a CCS specification for this | none |
7.1.4 jsonReader
JSON data is handled in a fashion very similar to that of xml data. What is important is that the definition of the jsonReader matches the data being received
datatype: json, (or jsonstring)
The default definition of the jsonreader is as follows:
jsonReader : {
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: true,
cell: "cell",
id: "id",
userdata: "userdata",
subgrid: {root:"rows",
repeatitems: true,
cell:"cell"
}
}
If the parameter datatype is 'json', jqGrid expects the following default format for json data.
{
total: "xxx",
page: "yyy",
records: "zzz",
rows : [
{id:"1", cell:["cell11", "cell12", "cell13"]},
{id:"2", cell:["cell21", "cell22", "cell23"]},
...
]
}
Property | Description |
---|---|
total | total pages for the query |
page | current page of the query |
records | total number of records for the query |
rows | an array that contains the actual data |
id | the unique id of the row |
cell | an array that contains the data for a row |
In this case, the number of the elements in the cell array should equal the number of elements in
colModel.
7.1.5 formatter
Formatter can be used in either of two ways: Predefined and Custom.
7.1.5.1 Predefined formats
Default formatting functions are defined in the language files e.g., grid.locale-xx (where xx is your language). To modify these, open the language file and search for "$.jgrid.formatter". Here you will find all the settings that you may want to review or change before using the predifined formats. These settings can also be overridden for specific columns using the FormatOptions parameter, described below.
The second step is to set the desired formatting in colModel. This is done using the option formatter. For example
colModel :[
...
{name:'myname', ... formatter:'number', ...},
...
]
The predefined types are
- integer
- number
- currency
- date (uses formats compatable with php function date.)
- checkbox
- link
- showlink
- select (this is not a real select but a special case for editing modules. See note below)
The types are treated as normal strings and must be enclosed in single or double quotes. All predefined types are compatible with the editing modules. This means that the numbers, links, e-mails, etc., are converted so that they can be edited correctly.
Note: Type = 'Select'
The select type is not real select. This is used when we use some editing module and have edittype:'select'. Before this release we pass the value of the select in grid and not the key. For example:
colModel : [
{name:'myname', edittype:'select', editoptions:{value:"1:One;2:Two"}}
...
]
Now, with this setting
colModel : [
{name:'myname', edittype:'select', formatter:'select', editoptions:{value:"1:One;2:Two"}}
...
]
7.1.5.2 Custom formats
You can define your own formatter for a particular row. Usually this is a function. When set in the formatter option this should not be enclosed in quotes and not entered with () - show just the name of
the function. For example,
colModel:[
...
{name:'price', index:'price', width:60, align:"center", editable: true, formatter:currencyFmatter},
...
]
- cellValue: the cell value
- opts: a set of options containing
- rowId - the id of the row
- colModel - the colModel for this column
- rowData - the data for this row
- rowObject: the object of this row containing the its fields as object field.
For example:
function folder(cellValue, opts, rowObject) {
if (!rowObject.file) {
return "<div class='ui-state-default'><span class='ui-icon ui-icon-folder-collapsed'></span></div>";
}
return "<div></div>";
}
Formatter options can be defined for particular columns, overwriting the defaults from the language file. This is accomplished by using the formatoptions array in colModel. For example:
colModel : [
...
{name:"myname"... formatter:'currency', formatoptions:{decimalSeparator:",", thousandsSeparator: " ",
decimalPlaces: 2, prefix: "$ "}},
...
]
Type | Options |
---|---|
integer | {thousandsSeparator: " ", defaulValue: 0} |
number | {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaulValue: 0} |
currency | {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaulValue: 0} |
date | {srcformat: 'Y-m-d',newformat: 'd/m/Y'} |
showlink | {baseLinkUrl: '',showAction: 'show'} |
7.1.7 Navigating
If your grids are all so small that they can display all records at the same time, then you don't need to worry about navigation. But more likely, you will want to display the available records a few at a a time. And for that, you will need the Navigation Bar.
To use this feature we need to enable form editing.
7.1.7.1 HTML
The Navigation Bar, also known as the pager, is defined first in html -- normally, but not necessarily,
placed so it appears at the bottom of the grid. Note that it is a <div>, not a <table>.
<body>
<table id="list" class="scroll"></table>
<div id="pager" class="scroll" style="text-align:center;"></div>
</body>
The pager is then defined in the grid by a grid property:
pager: '#pager_id'
Calling Convention:
$("#grid_id").navGrid("#pager",{parameters})
- grid_id - the id of the already constructed jqGrid.
- pager - the id of the navigation bar
- parameters - an array of settings, defined below
Several properties of the grid govern the function and appearance of the Navigation bar:
Property | Type | Description | Default |
---|---|---|---|
firstimg | string | Link to image url for the first button | first.gif |
lastimg | string | Link to image url for the last button | last.gif |
nextimg | string | Link to image url for the next button | next.gif |
page | integer | The requested initial page number when we use datatypes xml or json (data returned from server) | 1 |
pager | DOM element or string | Sets the pager bar for the grid. Must be a valid html element. If the element has class “scroll”, then the width is equal to the grid. Usage: If parameter is a DOM element, jQuery("#mypager"); if using a string, "mypager", where mypager is the id of the pager. Note the missing "#" | true |
pgbuttons | boolean | Disables or enables pager buttons, if pager is present | true |
pginput | boolean | Disables or enables the input box for current page, if pager is present | true |
pgtext | string | Text that appear before the number of total pages | "/" |
previmg | string | Link to image url for the previous button | prev.gif |
recordtext | string | Displays the text associated with the display of total records; specified value must be in quotes. | "Rows" |
rowList | array | This parameter constructs a select box element in the pager in which the user can change the number of the visible rows. | empty array |
rowNum | integer | The initial number of rows that are be returned from the server | 20 |
viewrecords | boolean | Display the total records from the query in the pager bar | false |
7.1.7.5 Methods
The only methods we need are to invoke the pager itself and to add custom buttons, if necessary
Method | Parameters | Returns | Description |
---|---|---|---|
navGrid | pager_id, parameters | jQuery object | accepts the following settings to govern which buttons appear on the Navigation bar; any of them may be set to true or false. The default for all is true, but may be changed by, for example {refresh: true, edit: true, add: true, del: false, search: true} or {del: false} The position of these buttons is controlled by a position setting (the default is left): {add:false,del:false,edit:false,position:"right"} Parameters for these buttons can be sent by adding them after the main array: ...{add:false,edit:false,del:false}, {}, // edit parameters {}, // add parameters {reloadAfterSubmit:false} //delete parameters |
navButtonAdd | jQuery object | supports adding custom buttons. This method must be chained with the setting of the Standard Buttons. See details and examples in Custom Buttons |
7.1.7.6 Custom Buttons
Calling Convention:
jQuery("#grid_id").navGrid("#pager",{standard parameters}).navButtonAdd("#pager",{custom parameters});
{ caption:'NewButton',
buttonicon: "ui-icon-plus",
onClickButton:function(){
alert('custom button');
},
position "last",
title:'ToolTip'}
- caption: (string) the caption of the button, can be a empty string.
- buttonicon: (string) css class name of icon.
- onClickButton: (function) action to be performed when a button is clicked. Default null.
- position: ("first" or "last") the position where the button will be added (i.e., before or after the standard buttons).
- title: (string) a tooltip for the button.
jqGrid provide us more features and facilities but I think that's enough for today. Now Its is the time to take a sample using jqGrid and Spring MVC. As you remember I have post called Spring MVC - MultipartFile. I'm going to extend it. The file list grid was so simple
classic grid |
file list with jqGrid |
1. Pagination
public class Pagination {
public static final String ASC = "asc";
public static final String DESC = "desc";
int currentPage;
int rowSizePerPage;
String sortIndex;
String sortOrder;
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getRowSizePerPage() {
return rowSizePerPage;
}
public void setRowSizePerPage(int rowSizePerPage) {
this.rowSizePerPage = rowSizePerPage;
}
public String getSortIndex() {
return sortIndex;
}
public void setSortIndex(String sortIndex) {
this.sortIndex = sortIndex;
}
public String getSortOrder() {
return sortOrder;
}
public void setSortOrder(String sortOrder) {
this.sortOrder = sortOrder;
}
public Boolean isAscending() {
return sortOrder.equals(ASC);
}
public int getFirstResult() {
return (currentPage - 1) * rowSizePerPage;
}
}
public abstract class BaseController {
Pagination pagination;
Model model;
HttpServletRequest request;
HttpServletResponse response;
public Pagination getPagination() {
return pagination;
}
public void setPagination(Pagination pagination) {
this.pagination = pagination;
}
public Model getModel() {
return model;
}
public HttpServletRequest getRequest() {
return request;
}
public HttpServletResponse getResponse() {
return response;
}
public abstract void init();
@ModelAttribute("command")
public BaseController init(HttpServletRequest request, HttpServletResponse response, Model model) {
this.model = model;
this.request = request;
this.response = response;
ServletRequestDataBinder binder = new ServletRequestDataBinder(this, "command");
binder.bind(request);
init();
return this;
}
}
This class has some changes in these methods:
2.1 list
@RequestMapping("/list")
public String list() {
return "file.list";
}
2.2 fileList
@RequestMapping("/fileList")
public void fileList() throws IOException {
List<File> fileList = fileService.findAllFiles(getCurrentUser(), parentFolder, getPagination());
Integer fileListSize = fileService.findAllFilesSize(getCurrentUser(), parentFolder);
JsonConfig jc = new JsonConfig();
jc.setExcludes(new String[]{"fileData", "parentFolder", "owner"});
JSONArray ja = JSONArray.fromObject(fileList, jc);
getResponse().setCharacterEncoding("UTF8");
getResponse().getWriter().write(paginationHelper(getPagination(), fileListSize, ja));
}
public String paginationHelper(Pagination pagination, int totalRowSize, JSONArray jsonArray) {
int pageCount = 1;
if (pagination.getRowSizePerPage() > 0) {
pageCount = totalRowSize / pagination.getRowSizePerPage();
if (totalRowSize % pagination.getRowSizePerPage() != 0) {
pageCount++;
}
}
return "{\"page\":\"" + pagination.getCurrentPage() + "\", \"total\":\"" + pageCount + "\", \"records\":\"" + totalRowSize + "\", \"rows\":" + jsonArray.toString() + "}";
}
2.3 delete
@RequestMapping("/delete")
public void delete(@RequestParam(value = "id", required = true) String sIds) {
List<Long> ids = new ArrayList();
String[] sIdParts = sIds.split(",");
for (String sId : sIdParts) {
ids.add(Long.parseLong(sId));
}
fileService.deleteAll(ids);
}
2.4 getParentFolders
public String getParentFolders() {
String parentFolders = "";
File folder = parentFolder;
while (folder != null && folder.getName() != null) {
parentFolders = "/" + folder.getName() + parentFolders;
folder = folder.getParentFolder();
}
if(parentFolders.equals("")){
parentFolders = "/";
}
return parentFolders;
}
3. FileService Class
@Service
public class FileServiceImpl implements FileService {
@Autowired
FileDao fileDao;
public List<File> findAllFiles(User user, File parentFolder, Pagination pagination) {
return fileDao.findAllFiles(user, parentFolder, pagination);
}
public Integer findAllFilesSize(User user, File parentFolder) {
return fileDao.findAllFilesSize(user, parentFolder);
}
...
}
4. FileDao Class
@Repository
public class FileDaoImpl extends BaseDao implements FileDao {
public List<File> findAllFiles(final User user, final File parentFolder, final Pagination pagination) {
return getHibernateTemplate().execute(new HibernateCallback<List<File>>() {
public List<File> doInHibernate(Session session) throws HibernateException, SQLException {
return session.createCriteria(File.class).add(Restrictions.eq("owner", user)).
add((parentFolder != null && parentFolder.getId() != null) ? Restrictions.eq("parentFolder", parentFolder) : Restrictions.isNull("parentFolder")).
addOrder(Order.asc("file")).addOrder(pagination.isAscending() ? Order.asc(pagination.getSortIndex()) : Order.desc(pagination.getSortIndex())).
setFirstResult(pagination.getFirstResult()).setFetchSize(pagination.getRowSizePerPage()).list();
}
});
}
public Integer findAllFilesSize(final User user, final File parentFolder) {
return getHibernateTemplate().execute(new HibernateCallback<Integer>() {
public Integer doInHibernate(Session session) throws HibernateException, SQLException {
return (Integer) session.createCriteria(File.class).setProjection(Projections.count("id")).add(Restrictions.eq("owner", user)).add((parentFolder != null && parentFolder.getId() != null) ? Restrictions.eq("parentFolder", parentFolder) : Restrictions.isNull("parentFolder")).uniqueResult();
}
});
}
...
}
JSPs
These JSP files are changed:
1. /WEB-INF/layout/view.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<script type="text/javascript" src="<spring:url value="/resources/js/jquery-1.4.4.min.js"/>"></script>
<script type="text/javascript" src="<spring:url value="/resources/js/grid.locale-en.js"/>"></script>
<script type="text/javascript" src="<spring:url value="/resources/js/jquery.jqGrid.min.js"/>"></script>
<link rel="stylesheet" type="text/css" href="<spring:url value="/resources/css/jquery-ui-1.8.6.custom.css"/>"/>
<link rel="stylesheet" type="text/css" href="<spring:url value="/resources/css/ui.jqgrid.css"/>"/>
</head>
<body>
<div>
<security:authorize access="isAuthenticated()">
<a href="/j_spring_security_logout">logout</a> welcome <security:authentication property="name"/> <br/>
main menu:
<a href="<spring:url value="/user/list.html"/>">user list</a>
<a href="<spring:url value="/file/list.html"/>">file repository</a>
<br/>
<br/>
</security:authorize>
<tiles:insertAttribute name="body"/>
</div>
</body>
</html>
2. /WEB-INF/pages/file/file-list.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<spring:url value="/file/fileList.html" var="listUrl">
<c:if test="${not empty command.parentFolder.id}">
<spring:param name="parentFolder.id" value="${command.parentFolder.id}"/>
</c:if>
</spring:url>
<script type="text/javascript">
function folder(cellValue, opts, rowObject) {
if (!rowObject.file) {
return "<div class='ui-state-default'><span class='ui-icon ui-icon-folder-collapsed'></span></div>";
}
return "<div></div>";
}
function edit(cellValue, opts, rowObject) {
return "<input type='submit' value='edit' onclick='setFileId(" + rowObject.id + "); setFormAction(\"<spring:url value="/file/edit.html"/>\");'/>";
}
function view(cellValue, opts, rowObject) {
if (rowObject.file) {
return "<a href='<spring:url value="/file/download.html"/>?file.id=" + rowObject.id + "'>download</a>";
} else {
return "<a href='<spring:url value="/file/list.html"/>?parentFolder.id=" + rowObject.id + "'>view</a>";
}
}
function setFormAction(action) {
document.getElementById("fileForm").action = action;
}
function setFileId(id) {
document.getElementById("fileId").value = id;
}
$(function() {
$("#fileGrid").jqGrid({
url:'${listUrl}',
datatype:'json',
contentType:'contentType:"application/json; charset=utf-8"',
jsonReader:{repeatitems: false,id:"id"},
direction:'ltr',
width:'500',
colNames:['','name','view','edit'],
colModel:[{sortable:false, width:'20', formatter:folder},{name:'name',sortable:true},{align:'center', sortable:false,formatter:view},{align:'center', sortable:false,formatter:edit}],
rowNum:10,
rowList:[10,20,30],
pager:'#filePager',
sortname:'id',
viewrecords:true,
multiselect:true,
multiboxonly:true,
sortorder:'desc',
prmNames:{rows:'pagination.rowSizePerPage', page:'pagination.currentPage', sort:'pagination.sortIndex', order:'pagination.sortOrder'},
editurl:'<spring:url value="/file/delete.html"/>',
caption:'File List',
recordtext:'View {0} - {1} of {2}',
emptyrecords:'No Records',
loadtext:'Loading ...',
pgtext:'Page {0} Of {1}'
});
$("#fileGrid").jqGrid('navGrid', '#filePager', {search:false, edit:false, add:false, del:true}).navButtonAdd("#filePager", {
caption:'',
buttonicon: "ui-icon-plus",
onClickButton:function() {
setFormAction('<spring:url value="/file/add.html"/>');
$("#fileForm").submit();
},
position:"first", title:'add'});
});
</script>
<form:form id="fileForm">
<form:hidden path="file.id" id="fileId"/>
<form:hidden path="parentFolder.id" id="fileId"/>
<div style="color:red;">${deleteError}</div>
<br/>
<table class='ui-state-default'>
<tr>
<td>
<span class='ui-icon ui-icon-folder-open'></span>
</td>
<td>${command.parentFolders}</td>
</tr>
</table>
</table>
<c:if test="${not empty command.parentFolder.name}">
<spring:url value="/file/list.html" var="parentFolderUrl">
<c:if test="${not empty command.parentFolder.parentFolder}">
<spring:param name="parentFolder.id" value="${command.parentFolder.parentFolder.id}"/>
</c:if>
</spring:url>
<a style="font-weight:bold; font-size:20px"
href="${parentFolderUrl}">..</a>
</c:if>
<br/>
<br/>
<table id="fileGrid"></table>
<div id="filePager"></div>
</form:form>
Source Code
It's the time to download the source code and try it yourselves. The application database script is available in [app-root]/db/filerepository.sql. you can restore it in your mysql server. the connection datasource properties is in [app-root]/src/database.properites. and after you deploy the project in you application server (like tomcat) the home page will be: http://localhost:8080/home/view.html also file list page is: http://localhost:8080/file/list.html
the admin user specification is:
username: administrator
password: 123456
you can use it to log in for the first time.
all rights reserved by Mostafa Rastgar and Programmer Assistant weblog
No comments:
Post a Comment