本章要点

  • Spring5整合MyBatis3的配置
  • Spring5整合MyBatis3的优势

前面章节详细介绍了Spring MVC的常用功能和MyBatis的基本用法。在实际的项目开发中,我们需要将SpringMyBatis进行整合,SpringMyBatis整合后可以完成如下功能:

  1. 可以使用Spring依赖注入功能以减少代码的耦合,
  2. 可以使用Spring MVC处理请求并作出响应,
  3. 可以使用MyBatis更加简捷地完成数据库操作。

本章将重点介绍SpringMyBatis的整合过程。

13.4.3 事务管理

与所有的Java EE应用类似,本系统的事务管理负责管理业务逻辑组件里的业务逻辑方法,只有对业务逻辑方法添加事务管理才有实际意义,对于单个DAO方法(基本的CRUD方法)增加事务管理是没有太大实际意义的
下面是本应用中事务管理的配置代码:

1
2
3
4
5
6
7
<!-- JDBC事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<!-- 启用支持annotation注解方式事务管理 -->
<tx:annotation-driven
transaction-manager="transactionManager" />

借助于Spring Scheam所提供的tx命名空间的帮助,系统可以非常方便地为业务逻辑组件配置事务管理。其中,tx命名空间下的<tx:annotation-driven/>元素用于支持事务注解, transaction-manager属性用于指定使用哪个事务管理器。之后就可以在Java类中使用@Transactional注解给SpringBean添加事务管理了。

13.4.2 实现业务逻辑组件

业务逻辑组件负责实现系统所需的业务方法,系统有多少个业务方法,业务逻辑组件就提供多少个对应方法,业务逻辑方法完全由业务逻辑组件负责实现。
业务逻辑组件只负责业务逻辑上的变化,而持久层上的变化则交给DAO层负责,因此业务逻辑组件必须依赖于DAO组件。
为了简化分页功能,设计了一个分页的JSP标签,只需要在页面使用分页标签,就可以完成所有页面的分页功能。下面是分页标签的源代码:

PageModel.java

1
2
3
4
5
6
7
8
9
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
package org.fkit.hrm.util.tag;
import org.fkit.hrm.util.common.HrmConstants;
/**
* 分页实体
*/
public class PageModel{
/** 分页总数据条数 */
private int recordCount;
/** 当前页面 */
private int pageIndex;
/** 每页分多少条数据 */
private int pageSize = HrmConstants.PAGE_DEFAULT_SIZE = 4;
/** 总页数 */
private int totalSize;
public int getRecordCount()
{
this.recordCount = this.recordCount <= 0 ? 0 : this.recordCount;
return recordCount;
}
public void setRecordCount(int recordCount)
{
this.recordCount = recordCount;
}
public int getPageIndex()
{
this.pageIndex = this.pageIndex <= 0 ? 1 : this.pageIndex;
/** 判断当前页面是否超过了总页数:如果超过了默认给最后一页作为当前页 */
this.pageIndex = this.pageIndex >= this.getTotalSize()
? this.getTotalSize()
: this.pageIndex;
return pageIndex;
}
public void setPageIndex(int pageIndex)
{
this.pageIndex = pageIndex;
}
public int getPageSize()
{
this.pageSize = this.pageSize <= HrmConstants.PAGE_DEFAULT_SIZE
? HrmConstants.PAGE_DEFAULT_SIZE
: this.pageSize;
return pageSize;
}
public void setPageSize(int pageSize)
{
this.pageSize = pageSize;
}
public int getTotalSize()
{
if(this.getRecordCount() <= 0)
{
totalSize = 0;
} else
{
totalSize = (this.getRecordCount() - 1) / this.getPageSize() + 1;
}
return totalSize;
}
public int getFirstLimitParam()
{
return (this.getPageIndex() - 1) * this.getPageSize();
}
}

PagerTag.java

1
2
3
4
5
6
7
8
9
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
88
89
90
91
92
93
94
95
96
97
98
99
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package org.fkit.hrm.util.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* 分页标签
*/
public class PagerTag
extends SimpleTagSupport
{
/** 定义请求URL中的占位符常量 */
private static final String TAG = "{0}";
/** 当前页码 */
private int pageIndex;
/** 每页显示的数量 */
private int pageSize;
/** 总记录条数 */
private int recordCount;
/** 请求URL page.action?pageIndex={0} */
private String submitUrl;
/** 样式 */
private String style = "sabrosus";
/** 定义总页数 */
private int totalPage = 0;
/** 在页面上引用自定义标签就会触发一个标签处理类 */
@Override
public void doTag() throws JspException,IOException
{
/** 定义它拼接是终的结果 */
StringBuilder res = new StringBuilder();
/** 定义它拼接中间的页码 */
StringBuilder str = new StringBuilder();
/** 判断总记录条数 */
if(recordCount > 0)
{ // 1499 / 15 = 100
/** 需要显示分页标签,计算出总页数 需要分多少页 */
totalPage = (this.recordCount - 1) / this.pageSize + 1;
/** 判断上一页或下一页需不需要加a标签 */
if(this.pageIndex == 1)
{ // 首页
str.append("<span class='disabled'>上一页</span>");
/** 计算中间的页码 */
this.calcPage(str);
/** 下一页需不需要a标签 */
if(this.pageIndex == totalPage)
{
/** 只有一页 */
str.append("<span class='disabled'>下一页</span>");
} else
{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex + 1));
str.append("<a href='" + tempUrl + "'>下一页</a>");
}
} else if(this.pageIndex == totalPage)
{ // 尾页
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex - 1));
str.append("<a href='" + tempUrl + "'>上一页</a>");
/** 计算中间的页码 */
this.calcPage(str);
str.append("<span class='disabled'>下一页</span>");
} else
{ // 中间
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex - 1));
str.append("<a href='" + tempUrl + "'>上一页</a>");
/** 计算中间的页码 */
this.calcPage(str);
tempUrl = this.submitUrl.replace(TAG, String.valueOf(pageIndex + 1));
str.append("<a href='" + tempUrl + "'>下一页</a>");
}
/** 拼接其它的信息 */
res.append("<table width='100%' align='center' style='font-size:13px;' class='" + style
+ "'>");
res.append(
"<tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>"
+ str.toString());
res.append(
"&nbsp;跳转到&nbsp;&nbsp;<input style='text-align: center;BORDER-RIGHT: #aaaadd 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #aaaadd 1px solid; PADDING-LEFT: 5px; PADDING-BOTTOM: 2px; MARGIN: 2px; BORDER-LEFT: #aaaadd 1px solid; COLOR: #000099; PADDING-TOP: 2px; BORDER-BOTTOM: #aaaadd 1px solid; TEXT-DECORATION: none' type='text' size='2' id='pager_jump_page_size'/>");
res.append(
"&nbsp;<input type='button' style='text-align: center;BORDER-RIGHT: #dedfde 1px solid; PADDING-RIGHT: 6px; BACKGROUND-POSITION: 50% bottom; BORDER-TOP: #dedfde 1px solid; PADDING-LEFT: 6px; PADDING-BOTTOM: 2px; BORDER-LEFT: #dedfde 1px solid; COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; BORDER-BOTTOM: #dedfde 1px solid; TEXT-DECORATION: none' value='确定' id='pager_jump_btn'/>");
res.append("</td></tr>");
res.append(
"<tr align='center'><td style='font-size:13px;'><tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>");
/** 开始条数 */
int startNum = (this.pageIndex - 1) * this.pageSize + 1;
/** 结束条数 */
int endNum = (this.pageIndex == this.totalPage)
? this.recordCount
: this.pageIndex * this.pageSize;
res.append("总共<font color='red'>" + this.recordCount + "</font>条记录,当前显示" + startNum
+ "-" + endNum + "条记录。");
res.append("</td></tr>");
res.append("</table>");
res.append("<script type='text/javascript'>");
res.append(" document.getElementById('pager_jump_btn').onclick = function(){");
res.append(
" var page_size = document.getElementById('pager_jump_page_size').value;");
res.append(" if (!/^[1-9]\\d*$/.test(page_size) || page_size < 1 || page_size > "
+ this.totalPage + "){");
res.append(" alert('请输入[1-" + this.totalPage + "]之间的页码!');");
res.append(" }else{");
res.append(" var submit_url = '" + this.submitUrl + "';");
res.append(" window.location = submit_url.replace('" + TAG + "', page_size);");
res.append(" }");
res.append("}");
res.append("</script>");
} else
{
res.append(
"<table align='center' style='font-size:13px;'><tr><td style='COLOR: #0061de; MARGIN-RIGHT: 3px; PADDING-TOP: 2px; TEXT-DECORATION: none'>总共<font color='red'>0</font>条记录,当前显示0-0条记录。</td></tr></table>");
}
this.getJspContext().getOut().print(res.toString());
}
/** 计算中间页码的方法 */
private void calcPage(StringBuilder str)
{
/** 判断总页数 */
if(this.totalPage <= 11)
{
/** 一次性显示全部的页码 */
for(int i = 1;i <= this.totalPage;i++)
{
if(this.pageIndex == i)
{
/** 当前页码 */
str.append("<span class='current'>" + i + "</span>");
} else
{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='" + tempUrl + "'>" + i + "</a>");
}
}
} else
{
/** 靠近首页 */
if(this.pageIndex <= 8)
{
for(int i = 1;i <= 10;i++)
{
if(this.pageIndex == i)
{
/** 当前页码 */
str.append("<span class='current'>" + i + "</span>");
} else
{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='" + tempUrl + "'>" + i + "</a>");
}
}
str.append("...");
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(this.totalPage));
str.append("<a href='" + tempUrl + "'>" + this.totalPage + "</a>");
}
/** 靠近尾页 */
else if(this.pageIndex + 8 >= this.totalPage)
{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(1));
str.append("<a href='" + tempUrl + "'>1</a>");
str.append("...");
for(int i = this.totalPage - 10;i <= this.totalPage;i++)
{
if(this.pageIndex == i)
{
/** 当前页码 */
str.append("<span class='current'>" + i + "</span>");
} else
{
tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='" + tempUrl + "'>" + i + "</a>");
}
}
}
/** 在中间 */
else
{
String tempUrl = this.submitUrl.replace(TAG, String.valueOf(1));
str.append("<a href='" + tempUrl + "'>1</a>");
str.append("...");
for(int i = this.pageIndex - 4;i <= this.pageIndex + 4;i++)
{
if(this.pageIndex == i)
{
/** 当前页码 */
str.append("<span class='current'>" + i + "</span>");
} else
{
tempUrl = this.submitUrl.replace(TAG, String.valueOf(i));
str.append("<a href='" + tempUrl + "'>" + i + "</a>");
}
}
str.append("...");
tempUrl = this.submitUrl.replace(TAG, String.valueOf(this.totalPage));
str.append("<a href='" + tempUrl + "'>" + this.totalPage + "</a>");
}
}
}
/** setter 方法 */
public void setPageIndex(int pageIndex)
{
this.pageIndex = pageIndex;
}
public void setPageSize(int pageSize)
{
this.pageSize = pageSize;
}
public void setRecordCount(int recordCount)
{
this.recordCount = recordCount;
}
public void setSubmitUrl(String submitUrl)
{
this.submitUrl = submitUrl;
}
public void setStyle(String style)
{
this.style = style;
}
}

要使用JSP的标签还需要在WEB-INF下增加一个tld标签文件。

page.tld

1
2
3
4
5
6
7
8
9
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
<?xml version="1.0" encoding="utf-8"?>
<taglib
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<!-- 描述 自定义标签版本的一种描述 -->
<description>Pager 1.0 core library</description>
<!-- 显示的名称 导包进行的一个展示 -->
<display-name>Pager core</display-name>
<!-- 版本号 -->
<tlib-version>1.0</tlib-version>
<!-- 短名 -->
<short-name>fkjava</short-name>
<!-- uri :导包 -->
<uri>/pager-tags</uri>
<!-- 定义一个标签 -->
<tag>
<!-- 标签名 -->
<name>pager</name>
<!-- 标签处理类 -->
<tag-class>org.fkit.hrm.util.tag.PagerTag</tag-class>
<!-- 设置标签为空 -->
<body-content>empty</body-content>
<!-- 定义标签的属性 -->
<attribute>
<!-- 属性名 表示分页的第几页 -->
<name>pageIndex</name>
<!-- 必须的 -->
<required>true</required>
<!-- run time expression value 为true支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- 定义标签的属性 -->
<attribute>
<!-- 属性名 表示分页标签 ,每页显示多少条数据 -->
<name>pageSize</name>
<!-- 必须的 -->
<required>true</required>
<!-- run time expression value 为true支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- 定义标签的属性 -->
<attribute>
<!-- 属性名 记录分页的总数 -->
<name>recordCount</name>
<!-- 必须的 -->
<required>true</required>
<!-- run time expression value 为true支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- 定义标签的属性 -->
<attribute>
<!-- 属性名 -->
<name>submitUrl</name>
<!-- 必须的 -->
<required>true</required>
<!-- run time expression value 为true支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- 定义标签的属性 -->
<attribute>
<!-- 属性名 -->
<name>style</name>
<!-- 必须的 -->
<required>false</required>
<!-- run time expression value 为true支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>

HrmService.java

下面是HrmService接口的源代码。

1
2
3
4
5
6
7
8
9
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
88
89
90
91
92
93
94
95
96
97
98
99
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package org.fkit.hrm.service;

import java.util.List;
import org.fkit.hrm.domain.Dept;
import org.fkit.hrm.domain.Document;
import org.fkit.hrm.domain.Employee;
import org.fkit.hrm.domain.Job;
import org.fkit.hrm.domain.Notice;
import org.fkit.hrm.domain.User;
import org.fkit.hrm.util.tag.PageModel;

/**
* 人事管理服务层接口
*/
public interface HrmService {

/**
* 用户登录
* @param loginname
* @param password
* @return User对象
* */
User login(String loginname,String password);

/**
* 根据id查询用户
* @param id
* @return 用户对象
* */
User findUserById(Integer id);

/**
* 获得所有用户
* @return User对象的List集合
* */
List<User> findUser(User user,PageModel pageModel);

/**
* 根据id删除用户
* @param id
* */
void removeUserById(Integer id);

/**
* 修改用户
* @param User 用户对象
* */
void modifyUser(User user);

/**
* 添加用户
* @param User 用户对象
* */
void addUser(User user);

/**
* 获得所有员工
* @param employee 查询条件
* @param pageModel 分页对象
* @return Dept对象的List集合
* */
List<Employee> findEmployee(Employee employee,PageModel pageModel);

/**
* 根据id删除员工
* @param id
* */
void removeEmployeeById(Integer id);

/**
* 根据id查询员工
* @param id
* @return 员工对象
* */
Employee findEmployeeById(Integer id);

/**
* 添加员工
* @param employee 员工对象
* */
void addEmployee(Employee employee);

/**
* 修改员工
* @param employee 员工对象
* */
void modifyEmployee(Employee employee);

/**
* 获得所有部门,分页查询
* @return Dept对象的List集合
* */
List<Dept> findDept(Dept dept,PageModel pageModel);

/**
* 获得所有部门
* @return Dept对象的List集合
* */
List<Dept> findAllDept();

/**
* 根据id删除部门
* @param id
* */
public void removeDeptById(Integer id);

/**
* 添加部门
* @param dept 部门对象
* */
void addDept(Dept dept);

/**
* 根据id查询部门
* @param id
* @return 部门对象
* */
Dept findDeptById(Integer id);

/**
* 修改部门
* @param dept 部门对象
* */
void modifyDept(Dept dept);

/**
* 获得所有职位
* @return Job对象的List集合
* */
List<Job> findAllJob();

List<Job> findJob(Job job,PageModel pageModel);

/**
* 根据id删除职位
* @param id
* */
public void removeJobById(Integer id);

/**
* 添加职位
* @param Job 部门对象
* */
void addJob(Job job);

/**
* 根据id查询职位
* @param id
* @return 职位对象
* */
Job findJobById(Integer id);

/**
* 修改职位
* @param dept 部门对象
* */
void modifyJob(Job job);


/**
* 获得所有公告
* @return Notice对象的List集合
* */
List<Notice> findNotice(Notice notice,PageModel pageModel);

/**
* 根据id查询公告
* @param id
* @return 公告对象
* */
Notice findNoticeById(Integer id);

/**
* 根据id删除公告
* @param id
* */
public void removeNoticeById(Integer id);

/**
* 添加公告
* @param Notice 公告对象
* */
void addNotice(Notice notice);

/**
* 修改公告
* @param Notice 公告对象
* */
void modifyNotice(Notice notice);

/**
* 获得所有文档
* @return Document对象的List集合
* */
List<Document> findDocument(Document document,PageModel pageModel);

/**
* 添加文档
* @param Document 文件对象
* */
void addDocument(Document document);

/**
* 根据id查询文档
* @param id
* @return 文档对象
* */
Document findDocumentById(Integer id);

/**
* 根据id删除文档
* @param id
* */
public void removeDocumentById(Integer id);

/**
* 修改文档
* @param Document 公告对象
* */
void modifyDocument(Document document);
}

HrmService接口中是本系统所有业务逻辑方法的定义,下面是这些业务逻辑方法的实现:

HrmServiceImpl.java

1
2
3
4
5
6
7
8
9
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
88
89
90
91
92
93
94
95
96
97
98
99
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
package org.fkit.hrm.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.fkit.hrm.dao.DeptDao;
import org.fkit.hrm.dao.DocumentDao;
import org.fkit.hrm.dao.EmployeeDao;
import org.fkit.hrm.dao.JobDao;
import org.fkit.hrm.dao.NoticeDao;
import org.fkit.hrm.dao.UserDao;
import org.fkit.hrm.domain.Dept;
import org.fkit.hrm.domain.Document;
import org.fkit.hrm.domain.Employee;
import org.fkit.hrm.domain.Job;
import org.fkit.hrm.domain.Notice;
import org.fkit.hrm.domain.User;
import org.fkit.hrm.service.HrmService;
import org.fkit.hrm.util.tag.PageModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* 人事管理系统服务层接口实现类
*/
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
@Service("hrmService")
public class HrmServiceImpl implements HrmService
{

/** 自动注入持久层Dao对象 */
@Autowired
private UserDao userDao;
@Autowired
private DeptDao deptDao;
@Autowired
private EmployeeDao employeeDao;
@Autowired
private JobDao jobDao;
@Autowired
private NoticeDao noticeDao;
@Autowired
private DocumentDao documentDao;

/***************** 用户服务接口实现 *************************************/
/**
* HrmServiceImpl接口login方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public User login(String loginname, String password)
{
// System.out.println("HrmServiceImpl login -- >>");
return userDao.selectByLoginnameAndPassword(loginname, password);
}

/**
* HrmServiceImpl接口findUser方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<User> findUser(User user, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("user", user);
int recordCount = userDao.count(params);
pageModel.setRecordCount(recordCount);
if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}
List<User> users = userDao.selectByPage(params);

return users;
}

/**
* HrmServiceImpl接口findUserById方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public User findUserById(Integer id)
{
return userDao.selectById(id);
}

/**
* HrmServiceImpl接口removeUserById方法实现
* @see { HrmService }
*/
@Override
public void removeUserById(Integer id)
{
userDao.deleteById(id);

}

/**
* HrmServiceImpl接口addUser方法实现
* @see { HrmService }
*/
@Override
public void modifyUser(User user)
{
userDao.update(user);

}

/**
* HrmServiceImpl接口modifyUser方法实现
* @see { HrmService }
*/
@Override
public void addUser(User user)
{
userDao.save(user);

}

/***************** 部门服务接口实现 *************************************/
@Transactional(readOnly = true)
@Override
public List<Dept> findAllDept()
{

return deptDao.selectAllDept();
}

/**
* HrmServiceImpl接口findDept方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<Dept> findDept(Dept dept, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("dept", dept);
int recordCount = deptDao.count(params);
pageModel.setRecordCount(recordCount);

if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}

List<Dept> depts = deptDao.selectByPage(params);

return depts;
}

/**
* HrmServiceImpl接口removeUserById方法实现
* @see { HrmService }
*/
@Override
public void removeDeptById(Integer id)
{
deptDao.deleteById(id);

}

/**
* HrmServiceImpl接口addDept方法实现
* @see { HrmService }
*/
@Override
public void addDept(Dept dept)
{
deptDao.save(dept);

}

/**
* HrmServiceImpl接口findDeptById方法实现
* @see { HrmService }
*/
@Override
public Dept findDeptById(Integer id)
{

return deptDao.selectById(id);
}

/**
* HrmServiceImpl接口modifyDept方法实现
* @see { HrmService }
*/
@Override
public void modifyDept(Dept dept)
{
deptDao.update(dept);

}
/***************** 员工服务接口实现 *************************************/
/**
* HrmService接口findEmployee方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<Employee> findEmployee(Employee employee, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("employee", employee);

int recordCount = employeeDao.count(params);
pageModel.setRecordCount(recordCount);

if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}
List<Employee> employees = employeeDao.selectByPage(params);
return employees;
}
/**
* HrmService接口removeEmployeeById方法实现
* @see { HrmService }
*/
@Override
public void removeEmployeeById(Integer id)
{
employeeDao.deleteById(id);

}
/**
* HrmService接口findEmployeeById方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public Employee findEmployeeById(Integer id)
{

return employeeDao.selectById(id);
}

/**
* HrmService接口addEmployee方法实现
* @see { HrmService }
*/
@Override
public void addEmployee(Employee employee)
{
employeeDao.save(employee);
}

/**
* HrmService接口modifyEmployee方法实现
* @see { HrmService }
*/
@Override
public void modifyEmployee(Employee employee)
{
employeeDao.update(employee);
}

/***************** 职位接口实现 *************************************/

/**
* HrmService接口findAllJob方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<Job> findAllJob()
{

return jobDao.selectAllJob();
}

/**
* HrmService接口findJob方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<Job> findJob(Job job, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("job", job);
int recordCount = jobDao.count(params);
pageModel.setRecordCount(recordCount);

if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}

List<Job> jobs = jobDao.selectByPage(params);

return jobs;
}

/**
* HrmService接口removeJobById方法实现
* @see { HrmService }
*/
@Override
public void removeJobById(Integer id)
{
jobDao.deleteById(id);

}

/**
* HrmService接口addJob方法实现
* @see { HrmService }
*/
@Override
public void addJob(Job job)
{
jobDao.save(job);

}

/**
* HrmService接口findJobById方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public Job findJobById(Integer id)
{

return jobDao.selectById(id);
}

/**
* HrmService接口modifyJob方法实现
* @see { HrmService }
*/
@Override
public void modifyJob(Job job)
{
jobDao.update(job);

}

/***************** 公告接口实现 *************************************/
@Transactional(readOnly = true)
@Override
public List<Notice> findNotice(Notice notice, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("notice", notice);
int recordCount = noticeDao.count(params);
pageModel.setRecordCount(recordCount);

if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}

List<Notice> notices = noticeDao.selectByPage(params);

return notices;
}

/**
* HrmService接口findNoticeById方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public Notice findNoticeById(Integer id)
{

return noticeDao.selectById(id);
}

/**
* HrmService接口removeNoticeById方法实现
* @see { HrmService }
*/
@Override
public void removeNoticeById(Integer id)
{
noticeDao.deleteById(id);

}

/**
* HrmService接口addNotice方法实现
* @see { HrmService }
*/
@Override
public void addNotice(Notice notice)
{
noticeDao.save(notice);

}
/**
* HrmService接口modifyNotice方法实现
* @see { HrmService }
*/
@Override
public void modifyNotice(Notice notice)
{
noticeDao.update(notice);

}
/***************** 文件接口实现 *************************************/
/**
* HrmService接口findDocument方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public List<Document> findDocument(Document document, PageModel pageModel)
{
/** 当前需要分页的总数据条数 */
Map<String, Object> params = new HashMap<>();
params.put("document", document);
int recordCount = documentDao.count(params);
pageModel.setRecordCount(recordCount);

if (recordCount > 0)
{
/** 开始分页查询数据:查询第几页的数据 */
params.put("pageModel", pageModel);
}

List<Document> documents = documentDao.selectByPage(params);

return documents;
}

/**
* HrmService接口addDocument方法实现
* @see { HrmService }
*/
@Override
public void addDocument(Document document)
{
documentDao.save(document);

}
/**
* HrmService接口removeDocumentById方法实现
* @see { HrmService }
*/
@Override
public void removeDocumentById(Integer id)
{
documentDao.deleteById(id);

}
/**
* HrmService接口modifyDocument方法实现
* @see { HrmService }
*/
@Override
public void modifyDocument(Document document)
{
documentDao.update(document);

}
/**
* HrmService接口findDocumentById方法实现
* @see { HrmService }
*/
@Transactional(readOnly = true)
@Override
public Document findDocumentById(Integer id)
{
return documentDao.selectById(id);
}
}

HrmServiceImpl类中实现了服务接口HrmService中定义的所有业务逻辑方法并且在HrmServiceImpl类上使用了两个注解

1
2
3
4
5
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT
)
@Service("hrmService")

Transactional注解说明

1
2
3
4
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT
)

表示该类需要Spring加入事务,

  • propagation = Propagation.REQUIRED表示:有事务就处于当前事务中,没有事务就创建一个事务
  • isolation = Isolation.DEFAULT表示:使用事务数据库的默认隔离级别

Service注解说明

@Service("hrmService")注解表示将该类配置成一个SpringBean,标识符是hrmService

Autowired注解说明

@Autowired。在HrmServiceImpl类中业务方法的实现依赖于DAO组件,在配置文件中使用的XML:<mybatis:scan base-package="org.fkit.hrm.dao"/>会将orgfkit.hrm.dao文件夹下的所有MyBatis文件配置成SpringBean,Beanid就是文件的类的名称。
@Autowired注解默认使用byType自动装配将6个持久层的DAO注入给HrmServiceImpl类对应依赖的DAO组件。

13.4 实现Service持久层

本系统只使用了一个业务逻辑组件:HrmService。该组件作为门面封装6个DAO组件,系统使用这个业务逻辑组件将这些DAO对象封装在一起.

13.4.1 业务逻辑组件的设计

业务逻辑组件是DAO组件的门面,所以也可以理解为业务逻辑组件需要依赖于DAO组件DAO组件与HrmService(业务逻辑组件)直接的关系如图13.3所示。

image-20220830095015442

HrmService接口中定义了大量的业务方法,这些方法的实现依赖于DAO组件。由于每个业务方法要涉及多个DAO操作,DAO操作是单条数据记录的操作,而业务逻辑方法的访问,则需要涉及多个DAO操作,因此每个业务逻辑方法可能需要涉及多条记录的访问
业务逻辑组件面向DAO接口编程,可以让业务逻辑组件从DAO组件的实现中分离。因此业务逻辑组件只关心业务逻辑的实现,无须关心数据访问逻辑的实现

10.7 本章小结

本章介绍了一个完整的前端开发+后端整合项目,内容覆盖系统数据库设计,系统分析、设计,系统DAO层设计,业务逻辑层设计等。本章的应用是对传统Java EE应用的改进,而不是一个简单的前端应用。本应用还利用Spring AOP机制解决了前端控制器的权限检查问题。
此外,本应用还整合了Spring 的邮件支持和任务调度功能。当用户竞价成功后,系统会向用户发送确认邮件;任务调度模块则周期性地检查系统中的拍卖物品,一旦发现某拍卖物品超过了拍卖的最后期限,系统会修改该物品的状态。
本应用的前端综合使用了jQueryBootstrap两个框架。其中Bootstrap负责生成用户界面,Bootstrap提供了大量CSS样式用于简化界面开发,也提供了大量UI控件来”组装”界面;而jQuery则提供了与服务器端的异步交互能力,jQuery既可以以异步方式向服务器提交请求,也可以以异步方式从服务器获取数据,此外,jQueryDOM支持则允许开发者动态加载、更新服务器的响应数据。

10.6.9 参与竞价

如果单击图10.22所示的物品的链接,将触发goPage()函数加载addBid.html,并将当前物品赋值给curBidItem变量,这样程序可以在竞拍页面上回显当前竞拍的物品。
addBid.html页面主要用于显示当前竞拍物品的详情,并提供一个表单控件供用户输入竞价的价格。下面是addBid.html页面的代码。

1
2
3
4
5
6
7
8
9
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
<script src="js/addBid.js"></script>
<div class="container">
<!-- 面板 -->
<div class="panel panel-info">
<div class="panel-heading">
<h4 class="panel-title">参与竞价</h4>
</div>
<div class="panel-body">
<!-- 水平表单 -->
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">物品名:</label>
<div class="col-sm-4">
<p class="form-control-static" id="nameSt"></p>
</div>
<label class="col-sm-2 control-label">物品描述:</label>
<div class="col-sm-4">
<p class="form-control-static" id="descSt"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">物品所有者:</label>
<div class="col-sm-4">
<p class="form-control-static" id="ownerSt"></p>
</div>
<label class="col-sm-2 control-label">物品种类:</label>
<div class="col-sm-4">
<p class="form-control-static" id="kindSt"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">物品起拍价:</label>
<div class="col-sm-4">
<p class="form-control-static" id="initPriceSt"></p>
</div>
<label class="col-sm-2 control-label">物品最高价:</label>
<div class="col-sm-4">
<p class="form-control-static" id="maxPriceSt"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">起卖时间:</label>
<div class="col-sm-4">
<p class="form-control-static" id="startSt"></p>
</div>
<label class="col-sm-2 control-label">结束时间:</label>
<div class="col-sm-4">
<p class="form-control-static" id="endSt"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">物品备注:</label>
<div class="col-sm-10">
<p class="form-control-static" id="remarkSt"></p>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<p class="well">如果你有兴趣参与该物品竞价,请输入价格后提交,<br>
请注意,你的价格应该大于物品的当前最高价</p>
</div>
</div>
<div class="form-group">
<label for='bidPrice' class="col-sm-2 control-label">竞拍价:</label>
<div class="col-sm-10">
<input type="number" class="form-control" id="bidPrice" name="bidPrice" min="0" required>
<input type="hidden" id="itemId" name="itemId">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" id="addItem" class="btn btn-success">竞价</button>
<button id="cancel" role="button" class="btn btn-danger">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>

该页面使用静态表单控件回显当前竞拍物品的信息,此外页面还提供了一个表单控件让用户输入竞拍价格,和一个隐藏域记录当前物品ID。而该页面加载的JS脚本将会读取curBidItem变量的信息,并将当前竞拍物品的信息回显在当前页面中。
单击某个物品名,将看到如图10.23所示的界面。
在图10.23所示的界面的下方,用户可以输入竞拍价格参与竞拍。如果单击”竞价”按钮,将会触发表单提交,但jQuery会接管表单的提交行为,改为使用异步方式提交表单。该页面的JS脚本代码如下。
程序清单:codes\10\auction\WebContent\js\addBid.js

1
2
3
4
5
6
7
8
9
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
$(function () {
// 发送请求
$.get("auction/getAllKind", {}, function (data) {
// 遍历数据展示到下拉列表中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function () {
// 把数据注入到下拉列表中
$("<option/>").html(this.kindName).val(this.id)
.appendTo("#kindSelect");
})
});
// 监听下拉列表
$("#kindSelect").change(function () {
// 如果下拉项是默认
if ($("#kindSelect").val() == 0) {
return;
}
// 获取当前选中的商品类别去加载下面拍卖的商品
$.post(
// 请求URL
"auction/getItemsByKind",
// 请求数据
{ kindId: this.value },
// 响应处理回到函数
function (data) {
// 先清空表格之前的数据
$("tbody").empty();
//如果响应不对
if (data == null || data.length < 1) {
// 设置对话框中的提示信息
$("#tip").html("<span style='color:red;'>该种类下暂时没有竞拍物品,请重新选择</span>");
// 显示对话框
$('#myModal').modal('show');
}
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
else {
// 遍历JSON
$.each(data, function () {
// 把数据注入到表格的行中去
var tr = document.createElement("tr");
tr.align = "center";
$("<td/>").html("<a href='#' onclick='goPage(\"addBid.html\");"
+ "curBidItem=" + JSON.stringify(this)
+ ";'>" + this.name + "</a>").appendTo(tr);
$("<td/>").html(long2Date(this.addTime)).appendTo(tr);
$("<td/>").html(long2Date(this.endTime)).appendTo(tr);
$("<td/>").html(this.maxPrice).appendTo(tr);
$("<td/>").html(this.owner).appendTo(tr);
$("tbody").append(tr);
})
}
});
})
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
});

该JS脚本的第一段代码读取curBidItem变量的数据,并将这些数据加载在页面中显示。

10.6.8 浏览拍卖物品

用户可以浏览当前正在拍卖的物品。在浏览正在拍卖的物品时,必须先选择想浏览的物品种类。系统通过一个列表框来显示系统中所有的物品种类,当用户单击某个物品种类时,该种类下的所有物品将显示在页面上。当用户单击”浏览拍卖物品”链接时,将进入浏览物品的模块。这时应该先获取当前物品种类,并将所有物品种类加载在页面中供用户选择。
下面是浏览拍卖物品的页面代码。
程序清单:codes\10\auction\WebContent\viewInBid.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<script src="js/viewInBid.js"></script>
<div class="container">
<!-- 面板 -->
<div class="panel panel-primary">
<!-- 面板头 -->
<div class="panel-heading">
<h3 class="panel-title">浏览拍卖物品</h3>
</div>
<!-- 面板主体 -->
<div class="panel-body">

<select class="btn btn-default" id="kindSelect">
<option value="0">==请选拍卖物品的种类==</option>
</select>
<hr>
<table class="table table-bordered">
<thead>
<tr align="center">
<th style="text-align: center;">物品名</th>
<th style="text-align: center;">起拍时间</th>
<th style="text-align: center;">结束时间</th>
<th style="text-align: center;">最高价格</th>
<th style="text-align: center;">所有者</th>
</tr>
</thead>
<!-- jQuery自动注入 -->
<tbody>
</tbody>
</table>
</div>
</div>
</div>

页面中的粗体字代码用于加载、显示当前系统的物品种类,当用户通过该下拉列表选择指定种类时,系统将会获取该种类下所有物品信息,并将它们加载、显示在下面的表格内。
下面是该页面所包含的JS脚本。
程序清单:codes\10\auction\WebContent\js\viewInBid.js

1
2
3
4
5
6
7
8
9
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
$(function () {
// 发送请求
$.get("auction/getAllKind", {}, function (data) {
// 遍历数据展示到下拉列表中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function () {
// 把数据注入到下拉列表中
$("<option/>").html(this.kindName).val(this.id)
.appendTo("#kindSelect");
})
});
// 监听下拉列表
$("#kindSelect").change(function () {
// 如果下拉项是默认
if ($("#kindSelect").val() == 0) {
return;
}
// 获取当前选中的商品类别去加载下面拍卖的商品
$.post(
// 请求URL
"auction/getItemsByKind",
// 请求数据
{ kindId: this.value },
// 响应处理回到函数
function (data) {
// 先清空表格之前的数据
$("tbody").empty();
//如果响应不对
if (data == null || data.length < 1) {
// 设置对话框中的提示信息
$("#tip").html("<span style='color:red;'>该种类下暂时没有竞拍物品,请重新选择</span>");
// 显示对话框
$('#myModal').modal('show');
}
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
else {
// 遍历JSON
$.each(data, function () {
// 把数据注入到表格的行中去
var tr = document.createElement("tr");
tr.align = "center";
$("<td/>").html("<a href='#' onclick='goPage(\"addBid.html\");"
+ "curBidItem=" + JSON.stringify(this)
+ ";'>" + this.name + "</a>").appendTo(tr);
$("<td/>").html(long2Date(this.addTime)).appendTo(tr);
$("<td/>").html(long2Date(this.endTime)).appendTo(tr);
$("<td/>").html(this.maxPrice).appendTo(tr);
$("<td/>").html(this.owner).appendTo(tr);
$("tbody").append(tr);
})
}
});
})
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
});

第一段代码调用jQueryget()方法向auction/getAllKind发送请求,该地址将会返回当前系统中所有种类信息。接下来回调函数把所有物品种类加载、显示在下拉列表中。
然后为页面上下拉列表的"change"绑定事件处理函数,当用户改变下拉列表的选项时,会触发该事件处理函数。粗体字代码向auction/getItemsByKind发送请求,该地址会根据物品种类来获取拍卖物品信息,系统会将返回的指定种类下的所有物品信息加载、显示在表格中。
通过上面的代码可以看出,单击”浏览拍卖物品”链接时并未获取任何物品信息,而只是将当前的所有物品种类加载到了kindSelect 列表框中。如果用户单击”浏览拍卖物品”链接,将看到如图10.21所示的界面。
如果用户单击的物品种类下没有对应的拍卖物品,系统将弹出提示框。如果用户单击的种类下有相应的拍卖物品,将看到如图10.22所示的界面。
如图10.22所示,物品列表中的物品名是一个超链接,单击该链接将显示对应物品的详细信息,并可对该物品竞价。

10.6.7 查看自己的竞价记录

如果当前用户已经登录,则还可以查看自己的所有竞价记录。用户单击”查看自己竞标“链接时,系统将会通过goPager()函数异步加载viewBid.html 页面,该页面只是一个简单的表格页面。该页面代码如下。
程序清单:codes\10\auction\WebContent\viewBid.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script src="js/viewBid.js"></script>
<div class="container">
<!-- 面板 -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">您参与的全部竞价</h3>
</div>
<div class="panel-body">
<table class="table table-bordered">
<thead>
<tr align="center">
<th style="text-align: center;">物品名</th>
<th style="text-align: center;">竞标价格</th>
<th style="text-align: center;">竞标时间</th>
<th style="text-align: center;">竞标人</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>

该页面所包含的JS将会异步获取用户所有的竞价记录,并将竞价记录动态显示在页面中。下面是该页面所包含的JS脚本代码。
程序清单:codes\10\auction\WebContent\js\viewBid.js

1
2
3
4
5
6
7
8
9
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
$(function() {
//
$.get(
// 请求URL
"auction/getBidByUser",
// 请求参数
{},
// 响应回到方法,data为响应对象
function(data) {
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function() {
// 如果响应对象由错误
if (data.error) {
// 在对话框中添加提示文本
$("#tip").html(
"<span style='color:red;'>" + data.error + "</span>");
// 显示对话框
$('#myModal').modal('show');
return;
}
// 如果收到正确的响应数据
// 创建一个tr元素
var tr = document.createElement("tr");
// 设置对齐方式
tr.align = "center";
// 在<td>元素中写入html,并添加叫tr元素里面的末尾
$("<td/>").html(this.item).appendTo(tr);
$("<td/>").html(this.price).appendTo(tr);
$("<td/>").html(long2Date(this.bidDate)).appendTo(tr);
$("<td/>").html(this.user).appendTo(tr);
// 在tbody元素里面的末尾追加tr元素
$("tbody").append(tr);
})
});
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
})

粗体字代码将会向auction/getBidByUser发送异步请求,该地址将以JSON格式返回所有的竞价记录。接下来jQuery将把所有竞价记录迭代并显示在页面上。
如果用户没有登录,则查看竞价记录时将被拦截器拦截,并弹出提示,告诉用户必须先登录系统。如果用户已经登录系统,则查看竞价记录时将看到如图10.20所示的界面。

10.6.6 查看竞得物品

当用户单击页面上方的”查看竞得的物品“链接时,如果用户还未登录系统,将弹出提示信息,告诉用户应先登录系统;如果用户已经登录了本系统,系统通过goPager()函数加载viewSucc.html页面。该页面只是一个简单的表格页面,用于显示用户所有赢取的物品。
该页面代码如下。
程序清单:codes\10\auction\WebContent\viewSucc.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- 该js会向服务器请求数据,并更新表格 -->
<script src="js/viewSucc.js"></script>
<div class="container">
<!-- 面板 -->
<div class="panel panel-primary">
<!-- 面板头 -->
<div class="panel-heading">
<h3 class="panel-title">您赢取的所有物品</h3>
</div>
<!-- 面板主体 -->
<div class="panel-body">
<!-- 表格,将会通过js更新 -->
<table class="table table-bordered">
<thead>
<tr align="center">
<th style="text-align: center;">物品名</th>
<th style="text-align: center;">物品种类</th>
<th style="text-align: center;">赢取价格</th>
<th style="text-align: center;">物品描述</th>
</tr>
</thead>
<!-- 由jQuery根据响应数据生成表格内容 -->
<tbody>
</tbody>
</table>
</div>
</div>
</div>

该表格只包含一个表格头,表格的内容将会由jQuery异步获取并加载。该页面所包含的viewSucc.js脚本的代码如下。
程序清单:codes\10\auction\WebContent\js\viewSucc.js

1
2
3
4
5
6
7
8
9
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
$(function() {
// 发送get请求
$.get(
// 请求的URL
"auction/getItemByWiner",
// 请求参数
{},
// 响应回调函数,data的到的响应
function(data) {
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function() {
// 如果响应错误
if (data.error) {
$("#tip").html(
"<span style='color:red;'>" + data.error + "</span>");
$('#myModal').modal('show');
return;
}
// 把数据注入到表格的行中去
var tr = document.createElement("tr");
tr.align = "center";
// 创建<td>元素,然后设置其内容,然后添加到tr元素内部的尾部中.
$("<td/>").html(this.name).appendTo(tr);
$("<td/>").html(this.kind).appendTo(tr);
$("<td/>").html(this.maxPrice).appendTo(tr);
$("<td/>").html(this.remark).appendTo(tr);
// 在tbody内的尾部添加tr标签
$("tbody").append(tr);
})
});
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
})

从上述代码可以看出,该页面向auction/getItemByWiner发送请求,该地址将会以JSON格式返回当前用户所竞得的全部物品。接下来jQuery会迭代并显示从服务器端返回的全部物品信息。
如果当前用户已经赢取了某些物品,则当用户单击”查看竞得物品”链接时,将看到如图10.19所示的界面。

10.6.5 管理物品种类

如果用户单击页面上方的”管理种类”链接,将进入管理物品种类模块。用户在这里会先看到系统包含的所有物品种类。用户单击”管理种类”链接时,系统会调用goPager函数导航到viewCategory.html页面,该页面用于查看当前系统的所有物品种类。
viewCategory.html页面代码如下。
程序清单:codes\10\auction\WebContent\viewCategory.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script src="js/viewCategory.js"></script>
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">当前的物品种类如下:</h3>
<a id="addCategory" ui-sref="addCategory"
style="margin-top: -24px" role="button"
class="btn btn-default btn-sm pull-right"
aria-label="添加"> <i class="glyphicon glyphicon-plus"></i>
</a>
</div>
<div class="panel-body">
<table class="table table-bordered table-striped">
<thead>
<tr align="center">
<th style="text-align: center;">种类名</th>
<th style="text-align: center;">种类描述</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>

从以上代码可以看出,该页面只是一个简单的.panel容器,该容器中包含一个表格,用于显示系统中所有的物品种类。
为了获取系统中所有的物品种类,系统会向auction/getAllKind发送请求,该请求是通过jQuery发送的异步请求。下面是该页面包含的JS脚本。
程序清单:codes\10\auction\WebContent\js\viewCategory.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 异步加载所有物品种类
$(function () {
$.get("auction/getAllKind",
{},
function (data) {
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function () {
// 把数据注入到表格的行中去
var tr = document.createElement("tr");
tr.align = "center";
$("<td/>").html(this.kindName).appendTo(tr);
$("<td/>").html(this.kindDesc).appendTo(tr);
$("tbody").append(tr);
})
});
// 绑定添加种类的方法
$("#addCategory").click(function () {
goPage("addCategory.html");
})
})

从粗体字代码可以看出,该JS脚本会向auction/getAllKind发送请求,该请求将会获取系统物品种类,服务器则以JSON格式返回所有物品种类。接下来jQuery会迭代所有种类信息,并将它们显示在页面上。
进入浏览物品种类的页面,可以看到如图10.17所示的界面。
如果用户单击该界面右上角的"+"按钮,将会触发goPager()函数加载addCategory.html页面,该页面是一个添加物品种类的表单页面。表单页面代码如下。
程序清单:codes\10\auction\WebContent\addCategory.html

1
2
3
4
5
6
7
8
9
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
<script src="js/addCategory.js"></script>
<div class="container">
<div class="panel panel-info">
<div class="panel-heading">
<h4 class="panel-title">添加种类</h4>
</div>
<div class="panel-body">
<form class="form-horizontal">
<div class="form-group">
<label for="name" class="col-sm-2 control-label">种类名:</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="name" name="name" minlength="2" required>
</div>
</div>
<div class="form-group">
<label for="desc" class="col-sm-2 control-label">描述:</label>
<div class="col-sm-10">
<textarea type="text" class="form-control"
id="desc" name="desc" minlength="20"
required rows="4"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" id="addCategory"
class="btn btn-success">添加</button>
<button id="cancel" role="button"
class="btn btn-danger">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>

该页面只是一个简单的表单页面,当在页面中提交表单时,系统将会使用jQuerypost()方法向服务器发送异步请求,该过程由JS脚本完成。下面是该JS脚本代码。
程序清单:codes\10\auction\WebContent\js\viewCategory.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 异步加载所有物品种类
$(function() {
$.get(
// 请求URL
"auction/getAllKind",
// 请求参数
{},
// 响应回调函数,data参数表示响应数据
function(data) {
// 遍历数据展示到表格中去
// 使用jQuery的方法来遍历JSON集合数据
$.each(data, function() {
// 把数据注入到表格的行中去
var tr = document.createElement("tr");
tr.align = "center";
$("<td/>").html(this.kindName).appendTo(tr);
$("<td/>").html(this.kindDesc).appendTo(tr);
$("tbody").append(tr);
})
});
// 绑定添加种类的方法
$("#addCategory").click(function() {
goPage("addCategory.html");
})
})

从粗体字代码可以看出,该JS脚本会向auction/getAllKind发送请求,该请求将会获取系统物品种类,服务器则以JSON格式返回所有物品种类。接下来jQuery会迭代所有种类信息,并将它们显示在页面上。
进入浏览物品种类的页面,可以看到如图10.17所示的界面。
如果用户单击该界面右上角的"+"按钮,将会触发goPager()函数加载addCategory.html页面,该页面是一个添加物品种类的表单页面。表单页面代码如下。
程序清单:codes\10\auction\WebContent\addCategory.html

1
2
3
4
5
6
7
8
9
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
<script src="js/addCategory.js"></script>
<div class="container">
<!-- 面板 -->
<div class="panel panel-info">
<!-- 面板头 -->
<div class="panel-heading">
<h4 class="panel-title">添加种类</h4>
</div>
<!-- 面板主体 -->
<div class="panel-body">
<!-- 水平表单 -->
<form class="form-horizontal">
<!-- 一行 -->
<div class="form-group">
<label for="name" class="col-sm-2 control-label">种类名:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name" name="name" minlength="2" required>
</div>
</div>
<div class="form-group">
<label for="desc" class="col-sm-2 control-label">描述:</label>
<div class="col-sm-10">
<textarea type="text" class="form-control" id="desc" name="desc" minlength="20" required
rows="4"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" id="addCategory" class="btn btn-success">添加</button>
<button id="cancel" role="button" class="btn btn-danger">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>

该页面只是一个简单的表单页面,当在页面中提交表单时,系统将会使用jQuerypost()方法向服务器发送异步请求,该过程由JS脚本完成。下面是该JS脚本代码。
程序清单:codes\10\auction\WebContent\js\addCategory.js

1
2
3
4
5
6
7
8
9
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
$(function () {
// 表单提交时
$(".form-horizontal").submit(function () {
// 发送post请求
$.post(
// 请求URL
"auction/addKind",
// 请求参数(自动转为查询字符串)
$(".form-horizontal").serializeArray(),
// 响应回调函数,data为响应内容
function (data) {
// 添加种类成功
if (data == "success") {
// 显示对话框
$('#myModal').modal('show');
// 在对话框中 提示成功
$("#tip").html("<span style='color:red;'>您添加种类成功了,请问要继续吗?</span>");
} else {
// 显示对话框
$('#myModal').modal('show');
// 在对话框中 提示失败
$("#tip").html("<span style='color:red;'>添加种类失败了</span>");
}
});
return false;
});
// 取消对话框中两个按钮上绑定的事件处理函数
$("#sure").unbind("click");
$("#cancelBn").unbind("click");
// 为对话框中的"确定"按钮绑定单击事件处理函数
$("#sure").click(function () {
// 重置添加物品种类中表单中的内容
$('.form-horizontal').get(0).reset();
})

$("#cancelBn").unbind();
// 为对话框中的"取消"按钮绑定单击事件处理函数
$("#cancelBn").click(function () {
// 点击取消时,显示
goPage("viewCategory.html");
})
// 添加物品种类的取消按钮
$("#cancel").click(function () {
goPage("viewCategory.html");
});
})

该代码中采用异步请求的方式提交整个表单数据,向auction/addKind 发送异步请求,该地址则负责处理添加种类的请求。
当用户添加种类成功后,系统将弹出提示框,告诉用户添加种类成功,如图10.18所示。
如果用户单击提示框中的”确定”按钮,系统将停留在添加种类的表单页面,让用户可以继续添加种类;如果用户单击”取消”按钮,系统将返回种类列表页面,这样可以在添加种类成功后,立即在页面上看到新增的物品种类。