Из этого туториала Вы узнаете, как создать сетку jQuery с Struts2 без использования плагина. Я отфильтровал этот код из моего существующего проекта. Архитектура проекта основана на strts2, Spring и Hibernate интегрированной среде. Я уверен, что вы можете настроить этот код так, чтобы он подходил для вашей среды.
Шаг 01: Создание класса сущности для главного экрана « Провинция ».
Я использую JPA в качестве технологии персистентности и поддержки доступа к данным в спящем режиме, предоставляемой Spring ( HibernateDaoSupport ). Я не собираюсь объяснять эти вещи подробно. Моя главная задача — как создать класс действий struts 2, поддерживающий сетку jQuery. Вот мой класс сущности.
Province.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
|
/** * */ package com.shims.model.maintenance; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import com.shims.model.Audited; /** * @author Semika Siriwardana * */ @Entity @Table (name= 'PROVINCE' ) public class Province extends Audited implements Serializable { private static final long serialVersionUID = -6842726343310595087L; @Id @SequenceGenerator (name= 'province_seq' , sequenceName= 'province_seq' ) @GeneratedValue (strategy = GenerationType.AUTO, generator = 'province_seq' ) private Long id; @Column (name= 'description' , nullable = false ) private String name; @Column (name= 'status' , nullable = false ) private char status; /** * */ public Province() { super (); } /** * @param id */ public Province(Long id) { super (); this .id = id; } /** * @return the id */ public Long getId() { return id; } /** * @param id the id to set */ public void setId(Long id) { this .id = id; } /** * @return the name */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this .name = name; } /** * @return the status */ public char getStatus() { return status; } /** * @param status the status to set */ public void setStatus( char status) { this .status = status; } } |
Шаг 02: Создание файла JSP для сетки главного экрана ‘Province’ .
Имейте в виду, что сетка jQuery является плагином для jQuery. Поэтому вам нужно скачать соответствующий CSS-файл и JS-файл для сетевого модуля jQuery . Возможно, вам понадобится включить следующие ресурсы в заголовочную часть файла JSP.
1
2
3
4
5
6
|
<link type= 'text/css' rel= 'stylesheet' media= 'screen' href= '<%=request.getContextPath()%>/css/jquery/themes/redmond/jquery-ui-1.8.16.custom.css' > <link type= 'text/css' rel= 'stylesheet' media= 'screen' href= '<%=request.getContextPath()%>/css/ui.jqgrid.css' > <script src= '<%=request.getContextPath()%>/js/jquery-1.6.2.min.js' type= 'text/javascript' ></script> <script src= '<%=request.getContextPath()%>/js/grid.locale-en.js' type= 'text/javascript' ></script> <script src= '<%=request.getContextPath()%>/js/jquery.jqGrid.src.js' type= 'text/javascript' ></script> <script src= '<%=request.getContextPath()%>/js/jquery-ui-1.8.16.custom.min.js' type= 'text/javascript' ></script> |
Затем мы создадим необходимое содержимое DOM в файле JSP для визуализации сетки. Для этого вам понадобятся только простые элементы TABLE и DIV, размещенные в файле JSP с указанными идентификаторами, как показано ниже.
1
2
|
<table id= 'list' ></table> <div id= 'pager' ></div> |
Тег DIV ‘ pager ‘ необходим для отображения панели разбивки сетки jQuery.
Шаг 03: Создание файла JS для сетки главного экрана ‘Province’.
Сетка jQuery необходима для запуска с помощью JavaScript. Я собираюсь начать сетку со страницы при загрузке. Существует так много функций, как добавление новых записей, обновление записей, удаление записей, поиск, поддерживаемый сеткой jQuery. Я думаю, вы можете ознакомиться с этими вещами, если вы можете создать начальную сетку. Этот javascript содержит только код, инициирующий сетку.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
var SHIMS = {} var SHIMS.Province = { onRowSelect: function(id) { //Handle event }, onLoadComplete: function() { //Handle grid load complete event. }, onLoadError: function() { //Handle when data loading into grid failed. }, /** * Initialize grid */ initGrid: function(){ jQuery( '#list' ).jqGrid({ url:CONTEXT_ROOT + '/secure/maintenance/province!search.action' , id: 'gridtable' , caption: 'SHIMS:Province Maintenance' , datatype: 'json' , pager: '#pager' , colNames:[ 'Id' , 'Name' , 'Status' ], pagerButtons: true , navigator: true , jsonReader : { root: 'gridModel' , page: 'page' , total: 'total' , records: 'records' , repeatitems: false , id: '0' }, colModel:[ { name: 'id' , index: 'id' , width: 200 , sortable: true , editable: false , search: true },{ name: 'name' , index: 'name' , width: 280 , sortable: true , editable: true , search: true , formoptions:{elmprefix: '(*)' }, editrules :{required: true } },{ name: 'provinceStatus' , index: 'provinceStatus' , width: 200 , sortable: false , editable: true , search: false , editrules:{required: true }, edittype: 'select' , editoptions:{value: 'A:A;D:D' } }], rowNum: 30 , rowList:[ 10 , 20 , 30 ], width: 680 , rownumbers: true , viewrecords: true , sortname: 'id' , viewrecords: true , sortorder: 'desc' , onSelectRow:SHIMS.Province.onRowSelect, loadComplete:SHIMS.Province.onLoadComplete, loadError:SHIMS.Province.onLoadError, editurl:CONTEXT_ROOT + '/secure/maintenance/province!edit.action' }); }, /** * Invoke this method with page on load. */ onLoad: function() { this .initGrid(); } }; |
Я хотел бы выделить некоторые фрагменты кода из приведенного выше кода. Атрибут ‘ jsonReader ‘ объекта инициализации сетки был ключевым моментом, когда его было трудно найти, и он потратил много раз, чтобы заставить работу сетки.
root — это должен быть список объектов.
страница — номер текущей страницы.
итого — это общее количество страниц. Например, если у вас 1000 записей, а размер страницы равен 10, значение «total» будет равно 100.
records — общее количество записей или количество записей
Если вы создаете сетку с данными JSON, ответом указанного URL — адреса должен быть ответ JSON в этом формате. Пример ответа JSON показан ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
{ 'gridModel' :[ { 'id' : 15001 , 'name' : 'Western' , 'provinceStatus' : 'A' }, { 'id' : 14001 , 'name' : 'North' , 'provinceStatus' : 'A' }, { 'id' : 13001 , 'name' : 'North Central' , 'provinceStatus' : 'A' }, { 'id' : 12002 , 'name' : 'East' , 'provinceStatus' : 'A' }, { 'id' : 12001 , 'name' : 'Southern' , 'provinceStatus' : 'A' } ], 'page' : 1 , 'records' : 11 , 'rows' : 30 , 'sidx' : 'id' , 'sord' : 'desc' , 'total' : 2 } |
Выше поля должны быть объявлены в классе действия и обновлены соответствующим образом. Я приду к этому позже. Если вы намереваетесь использовать такие операции, как добавление записи, удаление записи, обновление записи, поиск и т. Д., Вы должны указать « editurl ».
В файле JSP, чуть выше тега close body, я поместил следующий скрипт для вызова кода инициализации сетки.
1
2
3
4
|
var CONTEXT_ROOT = '<%=request.getContextPath()%>' ; jQuery(document).ready(function(){ SHIMS.Province.onLoad(); }); |
Шаг 04: Создание класса действий Struts2 для сетки главного экрана ‘Province’.
Это самая важная часть этого урока.
ProvinceAction.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
/** * */ package com.shims.web.actions.maintenance.province; import java.util.List; import org.apache.log4j.Logger; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ModelDriven; import com.shims.dto.Page; import com.shims.dto.ProvinceDto; import com.shims.model.maintenance.Province; import com.shims.service.maintenance.api.ProvinceService; import com.shims.support.SHIMSSoringSupport; import com.shims.web.actions.common.BaseAction; import com.shims.web.common.WebConstants; /** * @author Semika Siriwardana * */ @Controller @Namespace (WebConstants.MAINTENANCE_NAMESPACE) @ParentPackage (WebConstants.MAINTENANCE_PACKAGE) @Results ({ @Result (name=ProvinceAction.SUCCESS, location= '/jsp/maintenance/province.jsp' ), @Result (name = 'json' , type = 'json' )}) public class ProvinceAction extends BaseAction<Province> implements ModelDriven<Province> { private static final long serialVersionUID = -3007855590220260696L; private static Logger logger = Logger.getLogger(ProvinceAction. class ); @Autowired private ProvinceService provinceService; private List<Province> gridModel = null ; private Province model = new Province(); private Integer rows = 0 ; private Integer page = 0 ; private String sord; private String sidx; private Integer total = 0 ; private Integer records = 0 ; @Override public String execute() { return SUCCESS; } /** * Search provinces * @return */ public String search() throws Exception { Page<Province> resultPage = provinceService.findByCriteria(model, getRequestedPage(page)); List<Province> provinceList = resultPage.getResultList(); setGridModel(provinceList); setRecords(resultPage.getRecords()); setTotal(resultPage.getTotals()); return JSON; } /** * @return the gridModel */ public List<Province> getGridModel() { return gridModel; } /** * @param gridModel the gridModel to set */ public void setGridModel(List<Province> gridModel) { this .gridModel = gridModel; } /** * @return the page */ public Integer getPage() { return page; } /** * @param page the page to set */ public void setPage(Integer page) { this .page = page; } /** * @return the rows */ public Integer getRows() { return rows; } /** * @param rows the rows to set */ public void setRows(Integer rows) { this .rows = rows; } /** * @return the sidx */ public String getSidx() { return sidx; } /** * @param sidx the sidx to set */ public void setSidx(String sidx) { this .sidx = sidx; } /** * @return the sord */ public String getSord() { return sord; } /** * @param sord the sord to set */ public void setSord(String sord) { this .sord = sord; } /** * @return the total */ public Integer getTotal() { return total; } /** * @param total the total to set */ public void setTotal(Integer total) { this .total = total; } /** * @return the records */ public Integer getRecords() { return records; } /** * @param records the records to set */ public void setRecords(Integer records) { this .records = records; } @Override public Province getModel() { return model; } } |
Метод getRequestedPage () — это обобщенный метод, реализованный в классе BaseAction, который возвращает экземпляр страницы для данного типа.
BaseAction.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
/** * */ package com.shims.web.actions.common; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.SessionAware; import com.opensymphony.xwork2.ActionSupport; import com.shims.dto.Page; import com.shims.dto.security.UserDto; import com.shims.web.common.WebConstants; import flexjson.JSONSerializer; /** * @author Semika Siriwardana * */ public abstract class BaseAction<T> extends ActionSupport implements ServletRequestAware, SessionAware { private static final long serialVersionUID = -8209196735097293008L; protected static final Integer PAGE_SIZE = 10 ; protected HttpServletRequest request; protected Map<String, Object> session; protected String JSON = 'json' ; public abstract String execute(); public HttpServletRequest getRequest() { return request; } @Override public void setServletRequest(HttpServletRequest request) { this .request = request; } protected void setRequestAttribute(String key, Object obj) { request.setAttribute(key, obj); } /** * Returns generic Page instance. * @param domain * @param employeeDto * @return */ protected Page<T> getRequestedPage(Integer page){ Page<T> requestedPage = new Page<T>(); requestedPage.setPage(page); requestedPage.setRows(PAGE_SIZE); return requestedPage; } /** * @return the session */ public Map<String, Object> getSession() { return session; } /** * @param session the session to set */ public void setSession(Map<String, Object> session) { this .session = session; } } |
Я уже объяснил « gridModel », « page », « total » и «records ». ‘ sord ‘ и ‘ sidx ‘, которые упоминаются как ‘порядок сортировки’ и ‘индекс сортировки’, передаются сеткой jQuery, когда мы сортируем данные в сетке с некоторым столбцом. Чтобы получить эти поля буксировки, мы должны объявить это в классе действия и предоставить методы setter и getter. Позже мы можем отсортировать наш список данных на основе этих параметров буксировки.
Шаг 05: Реализация сервисных методов.
С этого момента, большинство методов являются специфическими для моей текущей структуры проекта. Я объясню их, чтобы Вы могли понять, как я разработал соответствующие сервисы и методы DAO. Поскольку jQuery grid поддерживает разбиение на страницы, необходимо было иметь правильный способ обмена информацией о сетке от внешнего интерфейса к внутреннему, а затем к внутреннему интерфейсу. Для этой цели я реализовал универсальный класс Page.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
|
/** * */ package com.shims.dto; import java.util.ArrayList; import java.util.List; /** * @author semikas * */ public class Page<T> { /** * Query result list. */ private List<T> resultList = new ArrayList<T>(); /** * Requested page number. */ private Integer page = 1 ; /** * Number of rows displayed in a single page. */ private Integer rows = 10 ; /** * Total number of records return from the query. */ private Integer records; /** * Total number of pages. */ private Integer totals; /** * @return the resultDtoList */ public List<T> getResultList() { return resultList; } /** * @param resultDtoList the resultDtoList to set */ public void setResultList(List<T> resultList) { this .resultList = resultList; } /** * @return the page */ public Integer getPage() { return page; } /** * @param page the page to set */ public void setPage(Integer page) { this .page = page; } /** * @return the rows */ public Integer getRows() { return rows; } /** * @param rows the rows to set */ public void setRows(Integer rows) { this .rows = rows; } /** * @return the records */ public Integer getRecords() { return records; } /** * @param records the records to set */ public void setRecords(Integer records) { this .records = records; } /** * @return the totals */ public Integer getTotals() { return totals; } /** * @param totals the totals to set */ public void setTotals(Integer totals) { this .totals = totals; } } |
Кроме того, с некоторыми критериями поиска, мы можем получить данные и соответственно обновить таблицу.
Мой интерфейс службы и классы реализации следующие.
ProvinceService.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/** * */ package com.shims.service.maintenance.api; import java.util.List; import com.shims.dto.Page; import com.shims.exceptions.ServiceException; import com.shims.model.maintenance.Province; /** * @author Semika Siriwardana * */ public interface ProvinceService { /** * Returns list of provinces for a given search criteria. * @return * @throws ServiceException */ public Page<Province> findByCriteria(Province searchCriteria, Page<Province> page) throws ServiceException; } |
ProvinceServiceImpl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/** * */ package com.shims.service.maintenance.impl; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.shims.dto.Page; import com.shims.exceptions.ServiceException; import com.shims.model.maintenance.Province; import com.shims.persist.maintenance.api.ProvinceDao; import com.shims.service.maintenance.api.ProvinceService; /** * @author Semika Siriwardana * */ @Service public class ProvinceServiceImpl implements ProvinceService { @Autowired private ProvinceDao provinceDao; /** * {@inheritDoc} */ @Override public Page<Province> findByCriteria(Province searchCriteria, Page<Province> page) throws ServiceException { Page<Province> resultPage = provinceDao.findByCriteria(searchCriteria, page); return resultPage; } } |
Я использую экземпляр « страницы » для обмена информацией сетки между интерфейсом и сервером.
Далее я объясню другую важную часть этого урока.
Шаг 06: Реализация метода доступа к данным.
В методе DAO Мы должны фильтровать только записи запрошенной страницы пользователем, а также должны обновлять атрибуты экземпляра страницы , чтобы они отражались в сетке. Поскольку я использую спящий режим, я использовал «Критерии» для извлечения необходимых данных из базы данных. Вы реализуете это по-своему, но оно должно корректно обновлять информацию сетки.
ProvinceDao.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/** * */ package com.shims.persist.maintenance.api; import com.shims.dto.Page; import com.shims.exceptions.DataAccessException; import com.shims.model.maintenance.Province; import com.shims.persist.common.GenericDAO; /** * @author Semika Siriwardana * */ public interface ProvinceDao extends GenericDAO<Province, Long> { /** * Returns search results for a given search criteria. * @param searchCriteria * @param page * @return * @throws DataAccessException */ public Page<Province> findByCriteria(Province searchCriteria, Page<Province> page) throws DataAccessException; } |
ProvinceDaoImpl.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
/** * */ package com.shims.persist.maintenance.impl; import java.util.List; import org.hibernate.Criteria; import org.hibernate.SessionFactory; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import com.shims.dto.Page; import com.shims.exceptions.DataAccessException; import com.shims.model.maintenance.Province; import com.shims.persist.maintenance.api.ProvinceDao; /** * @author Semika Siriwardana * */ @Repository public class ProvinceDaoImpl extends AbstractMaintenanceDaoSupport<Province, Long> implements ProvinceDao { @Autowired public ProvinceDaoImpl(SessionFactory sessionFactory) { setSessionFactory(sessionFactory); } /** * {@inheritDoc} */ @SuppressWarnings ( 'unchecked' ) @Override public Page<Province> findByCriteria(ProvinceDto searchCriteria, Page<Province> page) throws SHIMSDataAccessException { Criteria criteria = getSession().createCriteria(Province. class ); if (searchCriteria.getName() != null && searchCriteria.getName().trim().length() != 0 ) { criteria.add(Restrictions.ilike( 'name' , searchCriteria.getName(), MatchMode.ANYWHERE)); } //get total number of records first criteria.setProjection(Projections.rowCount()); Integer rowCount = ((Integer)criteria.list().get( 0 )).intValue(); //reset projection to null criteria.setProjection( null ); Integer to = page.getPage() * page.getRows(); Integer from = to - page.getRows(); criteria.setFirstResult(from); criteria.setMaxResults(to); //calculate the total pages for the query Integer totNumOfPages =( int ) Math.ceil(( double )rowCount / ( double )page.getRows()); List<Province> privinces = (List<Province>)criteria.list(); //Update 'page' instance. page.setRecords(rowCount); //Total number of records page.setTotals(totNumOfPages); //Total number of pages page.setResultList(privinces); return page; } } |
Я думаю, это будет хорошим подспорьем для разработчиков, которые хотят использовать чистый jQuery со Struts2. Если вы найдете больше связанных с этой темой, пожалуйста, пост ниже.
Ссылка: Как использовать jQuery grid со стойками 2 без плагина? от нашего партнера JCG Семика локу калуге в блоге Code Box .