2.2 Java Servlet 会话管理 使用隐藏域

2.2 隐藏域

使用隐藏域来保持状态类似于URL重写技术,但不是将值附加到URL上,而是放到HTML表单的隐藏域中。当表单提交时,隐藏域的值也同时提交到服务器端。隐藏域技术只在网页有表单时有效。隐藏域技术相对于 URL重写的优势在于:没有字符数限制,同时无须额外的编码。但隐藏域技术同URL重写一样,不适合跨越多个界面。

Demo

完整代码

User类

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
package session.management.hiddenfields;
public class User
{
//编号
String id;
//姓名
String name;
//所在地
String city;
//姓名
String sex;
//getter setter方法
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getCity()
{
return city;
}
public void setCity(String city)
{
this.city = city;
}
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
}

这里的User类用来存放我们要操作的数据.

UserServlet类

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
package session.management.hiddenfields;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(
name = "UserServlet",
// 这些URL都用当前这个Servlet来处理
urlPatterns =
{"/showUsers", "/editUser", "/updateUser", "/addUser"}
)
public class UserServlet extends HttpServlet
{
// 数据
ArrayList<User> userList;
private static final long serialVersionUID = 2L;
private User findUserById(String id)
{
for (User person : userList) {
if (person.getId().equals(id)) {
return person;
}
}
return null;
}
// 初始化数据
@Override
public void init() throws ServletException
{
userList = new ArrayList<User>();
User p1 = new User();
User p2 = new User();
p1.setId("1");
p1.setName("小明");
p1.setCity("南京");
p1.setSex("男");
userList.add(p1);
p2.setId("2");
p2.setName("小王");
p2.setCity("南京");
p2.setSex("男");
userList.add(p2);
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// 用utf-8来发送数据
response.setCharacterEncoding("UTF-8");
// 让浏览器用utf-8解析
response.setHeader("Content-type", "text/html;charset=UTF-8");
// 获取调用带Servlet的请求所用的链接
String url = request.getRequestURI();
if (url.endsWith("/showUsers")) {
// 显示用户列表
showUserList(response);
} else if (url.endsWith("/editUser")) {
// 发送修改表单
sendEditForm(request, response);
} else if (url.endsWith("/addUser")) {
sendAddForm(request, response);
}
}
private void sendAddForm(HttpServletRequest request,
HttpServletResponse response)
{
String html = "<html><head><title>添加User</title><meta charset='utf-8'></head><body><h2>添加User</h2>\r\n"
+ "<form method='post' action='addUser'><table><tbody>"
+ "<tr><td style='text-align:right'>编号:</td><td><input type='text' name='id' value='"
+ (userList.size() + 1)
+ "' readonly='readonly' title='编号由系统指定,无法修改'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>姓名:</td><td><input type='text' name='name'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>城市:</td><td><input type='text' name='city'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>性别:</td><td><input type='text' name='sex'></td></tr>\r\n"
+ "<tr><td colspan='2' style='text-align:right'><input type='submit' value='add'></td></tr>\r\n"
+ "<tr><td colspan='2'><a href='showUsers'>返回用户列表</a></td></tr>"
+ "</tbody></table></form></body></html>";
responseHTML(response, html);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// 设置请求体的编码,用utf-8来解析表单数据
request.setCharacterEncoding("UTF-8");
// 用utf-8编码来发送数据
response.setCharacterEncoding("UTF-8");
// 让浏览器用utf-8解析数据
response.setHeader("Content-type", "text/html;charset=UTF-8");
String url = request.getRequestURI();
if (url.endsWith("/updateUser")) {
updateUser(request, response);
} else if (url.endsWith("/addUser")) {
addUser(request, response);
}
}
private void addUser(HttpServletRequest request,
HttpServletResponse response)
{
String id = request.getParameter("id");
// 创建一个新用户
User user = findUserById(id);
if (user == null) {
// 创建一个新用户
user = new User();
user.setId(id);
user.setName(request.getParameter("name"));
user.setCity(request.getParameter("city"));
user.setSex(request.getParameter("sex"));
userList.add(user);
}
//请求重定向 显示主界面
try {
response.sendRedirect("showUsers");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void updateUser(HttpServletRequest request,
HttpServletResponse response)
{
String id = request.getParameter("id");
User person = findUserById(id);
if (person != null) {
person.setName(request.getParameter("name"));
person.setSex(request.getParameter("sex"));
person.setCity(request.getParameter("city"));
}
//请求重定向 显示主界面
try {
response.sendRedirect("showUsers");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void sendEditForm(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
// 获取URL中的id参数
String id = request.getParameter("id");
PrintWriter writer;
writer = response.getWriter();
User person = findUserById(id);
if (person != null) {
setEditFormByID(response, person);
} else {
writer.println("<h2>查无此人</h2>");
}
}
private void setEditFormByID(HttpServletResponse response, User person)
{
String htmlFirst = "<html>\r\n" + "<head>\r\n"
+ "<title>更新User</title>\r\n" + "</head>\r\n"
+ "<meta charset=\"utf-8\">\r\n" + "<body>\r\n"
+ "<h2>更新User</h2>\r\n"
+ "<form method='post' action='updateUser'>\r\n" + "<table>";
String htmlTrs = "<tr><td style='text-align:right'>姓名:</td><td><input name='name' value='"
+ person.getName() + "'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>城市:</td><td><input name='city' value='"
+ person.getCity() + "'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>性别:</td><td><input name='sex' value='"
+ person.getSex() + "'></td></tr>\r\n"
+ "<tr><td colspan='2' style='text-align:right'><input type='submit' value='Update'></td></tr>\r\n"
+ "<tr><td colspan='2'><a href='showUsers'>返回用户列表</a></td></tr>";
String htmlAfter = "</table>\r\n"
+ "<input type=\"hidden\" name=\"id\" value=\"" + person.getId()
+ "\">\r\n" + "</form>\r\n" + "</body>\r\n" + "</html>";
String html = htmlFirst + htmlTrs + htmlAfter;
responseHTML(response, html);
}
private void showUserList(HttpServletResponse response)
{
// 拼接HTML代码
String HTML = createShowPersonHTML();
// 响应
responseHTML(response, HTML);
}
private String createShowPersonHTML()
{
// 拼凑html代码
String htmlBefore = "<html>\r\n" + "<head>\r\n"
+ "<title>Person</title>\r\n" + "</head>\r\n" + "<body>\r\n"
+ "<h2>Users:</h2>\r\n" + "<table border=\"1\">\r\n"
+ "<tr><th>编号</th><th>姓名</th><th>城市</th><th>性别</th><th>操作</th></tr>";
String tr;
String htmlAfter = "<tr><td colspan=\"5\" style=\"text-align:right\"><a href=\"addUser\">添加用户</a></td></tr></table>\r\n"
+ "</body>\r\n" + "</html>";
StringBuffer sb = new StringBuffer(htmlBefore);
for (int i = 0, lenght = userList.size(); i < lenght; i++) {
// 从列表中取出一个对象
User person = userList.get(i);
tr = "<tr>\r\n" + "<td>" + person.getId() + "</td>\r\n" + "<td>"
+ person.getName() + "</td>\r\n" + "<td>" + person.getCity()
+ "</td>\r\n" + "<td>" + person.getSex() + "</td>\r\n"
+ "<td>\r\n" + "<a href=\"editUser?id=" + person.getId()
+ "\">编辑</a>\r\n" + "</td>\r\n" + "</tr>";
sb.append(tr);
}
sb.append(htmlAfter);
return sb.toString();
}
private void responseHTML(HttpServletResponse response, String HTML)
{
PrintWriter writer;
try {
writer = response.getWriter();
writer.write(HTML);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

代码详解

URL映射

1
2
3
4
5
6
@WebServlet(
name = "PersonServlet",
// 这些URL都用当前这个Servlet来处理
urlPatterns =
{"/showUsers", "/editUser", "/updateUser"}
)

这里为这个Servlet映射了三个URL,分别用于展示数据http://localhost:8080/SessionManagement/showUsers,修改数据,展示更新后的数据。

初始化数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 数据
ArrayList<User> userList;
private static final long serialVersionUID = 2L;
// 初始化数据
@Override
public void init() throws ServletException
{
userList = new ArrayList<User>();
User p1 = new User();
User p2 = new User();
p1.setId("1");
p1.setName("小明");
p1.setCity("南京");
p1.setSex("男");
userList.add(p1);
p2.setId("2");
p2.setName("小王");
p2.setCity("南京");
p2.setSex("男");
userList.add(p2);
}

这里首先声明了一个装有User对象的容器,当用户第一次请求页面时,Tomcat调用init()方法,init()方法,创建并初始化两个User对象,并把它们放到userList中。

工具方法

根据用户id获取该用户对象的引用
1
2
3
4
5
6
7
8
9
private User findUserById(String id)
{
for (User person : userList) {
if (person.getId().equals(id)) {
return person;
}
}
return null;
}

这个方法可以根据用户的id,从userList中查找User,如果没有将返回null.

输出HTML字符串到响应对象中
1
2
3
4
5
6
7
8
9
10
11
private void responseHTML(HttpServletResponse response, String HTML)
{
PrintWriter writer;
try {
writer = response.getWriter();
writer.write(HTML);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

显示所有用户数据

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
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// 用utf-8来发送数据
response.setCharacterEncoding("UTF-8");
// 让浏览器用utf-8解析
response.setHeader("Content-type", "text/html;charset=UTF-8");
// 获取调用带Servlet的请求所用的链接
String url = request.getRequestURI();
if (url.endsWith("/showUsers")) {
// 显示用户列表
showUserList(response);
} else if (url.endsWith("/editUser")) {
// 发送修改用户表单
sendEditForm(request, response);
} else if (url.endsWith("/addUser")) {
//发送添加用户表单
sendAddForm(request, response);
}
}
private void showUserList(HttpServletResponse response)
{
// 拼接HTML代码
String HTML = createShowPersonHTML();
// 响应
responseHTML(response, HTML);
}
private String createShowPersonHTML()
{
// 拼凑html代码
String htmlBefore = "<html>\r\n" + "<head>\r\n"
+ "<title>Person</title>\r\n" + "</head>\r\n" + "<body>\r\n"
+ "<h2>Users:</h2>\r\n" + "<table border=\"1\">\r\n"
+ "<tr><th>编号</th><th>姓名</th><th>城市</th><th>性别</th><th>操作</th></tr>";
String tr;
String htmlAfter = "<tr><td colspan=\"5\" style=\"text-align:right\"><a href=\"addUser\">添加用户</a></td></tr></table>\r\n"
+ "</body>\r\n" + "</html>";

StringBuffer sb = new StringBuffer(htmlBefore);
for (int i = 0, lenght = userList.size(); i < lenght; i++) {
// 从列表中取出一个对象
User person = userList.get(i);
tr = "<tr>\r\n" + "<td>" + person.getId() + "</td>\r\n" + "<td>"
+ person.getName() + "</td>\r\n" + "<td>" + person.getCity()
+ "</td>\r\n" + "<td>" + person.getSex() + "</td>\r\n"
+ "<td>\r\n" + "<a href=\"editUser?id=" + person.getId()
+ "\">编辑</a>\r\n" + "</td>\r\n" + "</tr>";
sb.append(tr);
}
sb.append(htmlAfter);
return sb.toString();
}

显示效果如下:
这里有一张图片
其中超链接HTML代码如下:

1
2
3
<a href="editUser?id=1">编辑</a>
<a href="editUser?id=2">编辑</a>
<a href="addUser">添加用户</a>

这是前面介绍的URL重写技术,因为前面路径省略,浏览器会发给父路径http://localhost:8080/SessionManagement/,最终得到URL为:http://localhost:8080/SessionManagement/editUser?id=1,点击这个URL可以可以进入修改页面。

修改用户数据

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
private void sendEditForm(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
// 获取URL中的id参数
String id = request.getParameter("id");
PrintWriter writer;
writer = response.getWriter();
User person = findUserById(id);
if (person != null) {
setEditFormByID(response, person);
} else {
writer.println("<h2>查无此人</h2>");
}
}
private void setEditFormByID(HttpServletResponse response, User person)
{
String htmlFirst = "<html>\r\n" + "<head>\r\n"
+ "<title>更新User</title>\r\n" + "</head>\r\n"
+ "<meta charset=\"utf-8\">\r\n" + "<body>\r\n"
+ "<h2>更新User</h2>\r\n"
+ "<form method='post' action='updateUser'>\r\n" + "<table>";
String htmlTrs = "<tr><td style='text-align:right'>姓名:</td><td><input name='name' value='"
+ person.getName() + "'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>城市:</td><td><input name='city' value='"
+ person.getCity() + "'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>性别:</td><td><input name='sex' value='"
+ person.getSex() + "'></td></tr>\r\n"
+ "<tr><td colspan='2' style='text-align:right'><input type='submit' value='Update'></td></tr>\r\n"
+ "<tr><td colspan='2'><a href='showUsers'>返回用户列表</a></td></tr>";
String htmlAfter = "</table>\r\n"
+ "<input type=\"hidden\" name=\"id\" value=\"" + person.getId()
+ "\">\r\n" + "</form>\r\n" + "</body>\r\n" + "</html>";
String html = htmlFirst + htmlTrs + htmlAfter;
responseHTML(response, html);
}

假设用户点击的是第一个超链接,也就是通过http://localhost:8080/SessionManagement/editUser?id=1这个URL访问。
此时,Tomcat将调用doGet方法,doGet方法调用sendEditForm方法,该根据Id找出一个User对象,然后doGet调用setEditFormByID这个方法,把User对象中的数据填入表单,封装成HTML
,发送给浏览器显示,用户在浏览器中修改表单中的数据即可完成修改,然后点击update按钮进行更新。如下图所示:
这里有一张图片
在服务器发送HTML的时候在表单之中偷偷塞了一个如下的隐藏域:

1
<input type="hidden" name="id" value="1">

这个隐藏域存放用户的id信息,这样当用户提交表单的时候,服务器就可根据这id信息,知道要修改的是哪个User对象的数据。
还是有就是表达的两个属性:

1
<form method="post" action="updateUser">

这表明提交方法为post方法,提交给/updateUser这个URL。提交后Tomcat将调用/updateUser这个URL对应的Servlet的doPost()方法。

服务器端更新数据

假设用户在表单中修改好了数据,然后点击update按键提交,调用的方法如下:

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
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
// 设置请求体的编码,用utf-8来解析表单数据
request.setCharacterEncoding("UTF-8");
// 用utf-8编码来发送数据
response.setCharacterEncoding("UTF-8");

// 让浏览器用utf-8解析数据
response.setHeader("Content-type", "text/html;charset=UTF-8");
String url = request.getRequestURI();
if (url.endsWith("/updateUser")) {
updateUser(request, response);
} else if (url.endsWith("/addUser")) {
addUser(request, response);
}
}
private void updateUser(HttpServletRequest request,
HttpServletResponse response)
{
String id = request.getParameter("id");
User person = findUserById(id);
if (person != null) {
person.setName(request.getParameter("name"));
person.setSex(request.getParameter("sex"));
person.setCity(request.getParameter("city"));
}
//请求重定向 显示主界面
try {
response.sendRedirect("showUsers");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

因为表单提交方式为post,所以Tomcat调用doPost()方法来做出响应。doPost()中做了写编码相关的设置,然后调用updateUser方法,updateUser这个方法,先获取id参数。然后根据id参数找到要修改的User对象。使用文本框中修改过的值更新这个对象的内容。这样就完成了更新数据的操作,最后请求重定向到showUsers这个URL上,也就是显示主界面
显示效果如下:
这里有一张图片

添加用户

在主界面中点击最下方的超链接<a href="addUser">添加用户</a>可以添加一个用户,浏览器请求http://localhost:8080/SessionManagement/addUser这个URL响应,这是一个get请求.Tomcat调用doGet方法响应,doGet方法根据请求的URL,调用sendAddForm方法,这个方法发给浏览器一个表单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void sendAddForm(HttpServletRequest request,
HttpServletResponse response)
{
String html = "<html><head><title>添加User</title><meta charset='utf-8'></head><body><h2>添加User</h2>\r\n"
+ "<form method='post' action='addUser'><table><tbody>"
+ "<tr><td style='text-align:right'>编号:</td><td><input type='text' name='id' value='"
+ (userList.size() + 1)
+ "' readonly='readonly' title='编号由系统指定,无法修改'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>姓名:</td><td><input type='text' name='name'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>城市:</td><td><input type='text' name='city'></td></tr>\r\n"
+ "<tr><td style='text-align:right'>性别:</td><td><input type='text' name='sex'></td></tr>\r\n"
+ "<tr><td colspan='2' style='text-align:right'><input type='submit' value='add'></td></tr>\r\n"
+ "<tr><td colspan='2'><a href='showUsers'>返回用户列表</a></td></tr>"
+ "</tbody></table></form></body></html>";
responseHTML(response, html);
}

需要注意的是id信息,我这里放在隐藏域中:

1
<input type="hidden" name="id" value="3">

需要注意的是表单的属性:

1
<form method='post' action='addUser'>

这表明表单将会发送给addUser这个URL,虽然还是调用的这个URL,但是这次是post请求,而不是get请求。
填写表单如下:
这里有一张图片
所以Tomcat会调用doPost方法来响应。doPost根据请求中的URL,调用addUser方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void addUser(HttpServletRequest request,
HttpServletResponse response)
{
String id = request.getParameter("id");
// 创建一个新用户
User user = findUserById(id);
if (user == null) {
// 创建一个新用户
user = new User();
user.setId(id);
user.setName(request.getParameter("name"));
user.setCity(request.getParameter("city"));
user.setSex(request.getParameter("sex"));
userList.add(user);
}
// 请求重定向 显示主界面
try {
response.sendRedirect("showUsers");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

这个方法,把表单中提交的数据转换成User对象,然后添加到userList中保存。最后重定向到showUser这个URL去显示添加的效果,如下所示:
这里有一张图片

小结

这个demo就到这里了,本来我还想搞个删除的功能,但是懒得搞了,先这样。