Servlet-Cookie/Session
Cookie、Session
简介
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器。客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
Cookie(复数形态:Cookies),是指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。
- Cookie是由服务端生成的,发送给客户端(通常是浏览器)的。Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie:
- 内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。
- 硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。
作用
Cookie的根本作用就是在客户端存储用户访问网站的一些信息。典型的应用有:- 记住密码,下次自动登录。
- 购物车功能。
- 记录用户浏览数据,进行商品(广告)推荐。
缺陷
- Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
- 由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
- Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。
总结一下:
- Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
- Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式
Cookie和Session的区别
- 存放位置不同
Cookie保存在客户端,Session保存在服务端。 - 存取方式的不同
Cookie中只能保管ASCII字符串,假如需求存取Unicode字符或者二进制数据,需求先进行编码。Cookie中也不能直接存取Java对象。若要存储略微复杂的信息,运用Cookie是比拟艰难的。
而Session中能够存取任何类型的数据,包括而不限于String、Integer、List、Map等。Session中也能够直接保管Java Bean乃至任何Java类,对象等,运用起来十分便当。能够把Session看做是一个Java容器类。
- 安全性(隐私策略)的不同
Cookie存储在浏览器中,对客户端是可见的,客户端的一些程序可能会窥探、复制以至修正Cookie中的内容。而Session存储在服务器上,对客户端是透明的,不存在敏感信息泄露的风险。 假如选用Cookie,比较好的方法是,敏感的信息如账号密码等尽量不要写到Cookie中。最好是像Google、Baidu那样将Cookie信息加密,提交到服务器后再进行解密,保证Cookie中的信息只要本人能读得懂。而假如选择Session就省事多了,反正是放在服务器上,Session里任何隐私都能够有效的保护。 - 有效期上的不同
只需要设置Cookie的过期时间属性为一个很大很大的数字,Cookie就可以在浏览器保存很长时间。 由于Session依赖于名为JSESSIONID的Cookie,而Cookie JSESSIONID的过期时间默许为–1,只需关闭了浏览器(一次会话结束),该Session就会失效。 - 对服务器造成的压力不同
Session是保管在服务器端的,每个用户都会产生一个Session。假如并发访问的用户十分多,会产生十分多的Session,耗费大量的内存。而Cookie保管在客户端,不占用服务器资源。假如并发阅读的用户十分多,Cookie是很好的选择。 - 跨域支持上的不同
Cookie支持跨域名访问,例如将domain属性设置为“.baidu.com”,则以“.baidu.com”为后缀的一切域名均能够访问该Cookie。跨域名Cookie如今被普遍用在网络中。而Session则不会支持跨域名访问。Session仅在他所在的域名内有效。
HttpSession 会话机制 –>Servlet的会话机制的实现
创建于服务器端,保存于服务器,维护于服务器端,每创建一个新的Session,服务器端都会分配一个唯一的ID,并且把这个ID保存到客户端的Cookie中,保存形式是以JSESSIONID来保存的。
- 通过HttpServletRequest.getSession 进行获得HttpSession对象,通过setAttribute()给会话赋值,可以通过invalidate()将其失效。
- 每一个HttpSession有一个唯一的标识SessionID,只要同一次打开的浏览器通过request获取到session都是同一个。浏览器不同SessionID 也不同
- WEB容器默认的是用Cookie机制保存SessionID到客户端,并将此Cookie设置为关闭浏览器失效,Cookie名称为:JSESSIONID
- 每次请求通过读取Cookie中的SessionID获取相对应的Session会话
- HttpSession的数据保存在服务器端,所以不要保存数据量耗资源很大的数据资源,必要时可以将属性移除或者设置为失效
HttpSession可以通过setMaxInactiveInterval()设置失效时间(秒)或者在web.xml中配置
1
2
3
4<session-config>
<!--单位:分钟-->
<session-timeout>30</session-timeout>
</session-config>HttpSession默认使用Cookie进行保存SessionID,当客户端禁用了Cookie之后,可以通过URL重写的方式进行实现。
- 可以通过response.encodeURL(url) 进行实现
- API对encodeURL的结束为,当浏览器支持Cookie时,url不做任何处理;当浏览器不支持Cookie的时候,将会重写URL将SessionID拼接到访问地址后。
Cookie的使用:
添加Cookie:
1
2
3Cookie cookie = new Cookie("user", "suntao");
cookie.setMaxAge(7*24*60*60); // 一星期有效
response.addCookie(cookie);获取Cookie
1
2
3
4
5
6// 因为取得的是整个网页作用域的Cookie的值,所以得到的是个数组
Cookie[] cookies = request.getCookies();
for(int i = 0 ; i < cookies.length ; i++){
String name = cookies[i].getName() ;
String value = cookies[i].getValue() ;
}
cookie的存活期:默认为-1
会话Cookie:把Cookie保存到浏览器上,当存活期为负数
持久Cookie:把Cookie保存到文件中,当存活期为正数
设置存活期:c.setMaxAge();
Cookie中的特殊字符和中文
由于Cookie是在Http协议头部传送的, Http协议头必须是 ISO8859-1 编码,并且不能使用特殊字符和中文。
- 利用 Escape 编码进行解决,是HTTP协议标准。
- 数据加入Cookie之前进行编码即可。
- Java 提供了编码API
1
URLEncoder.encode("您好Cookie", "UTF-8")
利用Java Servlet API 下发Cookie
- 下发Cookie,response 对象上有下发Cookies API:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class AddCookieServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 请求路径 /add-cookie
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 利用response下发一个Cookie到浏览器
//1. 创建一个Cookie
Cookie cookie = new Cookie("message", URLEncoder.encode("Hello World!","UTF-8"));
Cookie cookie2 = new Cookie("test", URLEncoder.encode("您好Cookie", "UTF-8"));
//2. 下发Cookie
response.addCookie(cookie);
response.addCookie(cookie2);
response.setContentType("text/html; charset=UTF-8");
response.getWriter().print("OK");
}
}
什么时候需要使用Session
通常,使用Session存储:
- 用户的身份的唯一标识,例如:用户的id;
- 使用频率较高的数据,例如:用户名;
- 不便于使用其它解决方案去存储或者传递的数据。
JSP-Java-2
标准标签库 和 EL表达式
关于标签库 和 EL表达式:
- 网页中的Java代码不方便维护,经常出现 空指针异常,不友好。
- SUN提供了自定义标签技术,用于替代Java代码。每个厂商都设计了自己标签。 标签无法通用。自定义标签语法复杂,实现繁琐成本高。
- Apache组织设计了“标准标签库 JSTL” 实现了绝大部分企业需要用的标签功能。 目前企业基本上都使用标准标签库解决问题。
使用标准标签库 和 EL表达式
EL 表达式
EL 表达式有标准标签库一起诞生, 与JSTL配合使用
- 自动化工作:可以在pageContext,request,session,application中子弹寻找 “attribute”
- 自动调用 get方法
- 自动处理空值
HelloWorld: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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<%
//代表在Servlet中向 request 对象添加的数据
request.setAttribute("message", "Hello World!");
Emp emp = new Emp(1, "Tom", 1, null, 1, 1000,100);
request.setAttribute("emp", emp);
request.setAttribute("text", null);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EL EL表达式演示</title>
</head>
<body>
<h1>EL表达式演示</h1>
<h2>Java 代码输出数据</h2>
<%
//定义变量,利用getAttribute寻获数据
String message =
(String)request.getAttribute("message");
Emp one = (Emp) request.getAttribute("emp");
String text=(String)request.getAttribute("text");
%>
<p>利用java表达式输出数据: <%=message%>
<%=one.getEname()%> <%=text%> </p>
<h2>EL表达式输出信息</h2>
<p>自动寻获 ${message},
自动调用get方法 ${emp.ename}
自动处理空 ${text} </p>
</body>
</html>
EL 语法
好处是: 简洁! 写的少,做的多
可以访问对象的 getXxx() 方法
1
obj.name 就是访问了 obj.getName()
可以访问数组、List集合的元素
1
2arr[下标]
list[下标]可以访问map
1
2map.key 得到 value
map['key'] 得到value以上方式的符合使用,无需类型转换
1
2list[1].ename
map.east.ename
案例: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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<%
int[] arr1 = {5,1,5,6};
String[] arr2 = {"Tom","Jerry"};
Emp[] arr3 = {new Emp(1, "光头强", 1, null, 1,100,10),
new Emp(1,"李大嘴",1,null,1,100,10)};
List<String> list1 = new ArrayList<String>();
list1.add("沉鱼落雁");
list1.add("明眸善睐");
List<Emp> list2 = new ArrayList<Emp>();
list2.add(new Emp(3,"擎天柱",1,null,1,10,1));
list2.add(new Emp(4,"大黄蜂",1,null,1,20,5));
Map<String, Emp> map=new HashMap<String, Emp>();
map.put("east", new Emp(6,"黄老邪",1,null,1,50,1));
map.put("north", new Emp(7,"洪七公",1,null,1,40,2));
request.setAttribute("arr1", arr1);
request.setAttribute("arr2", arr2);
request.setAttribute("arr3", arr3);
request.setAttribute("list1", list1);
request.setAttribute("list2", list2);
request.setAttribute("map", map);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>EL EL表达式演示2</title>
</head>
<body>
<h1>EL表达式演示2</h1>
<p>arr1: ${arr1[0]} ${arr1[1]} </p>
<p>arr2: ${arr2[0]} ${arr2[1]} </p>
<p>arr3: ${arr3[0].ename} ${arr3[0].empno}</p>
<p>list1: ${list1[0]}</p>
<p>list2: ${list2[0].ename}</p>
<p>map: ${map.east.ename} ${map['east'].ename}</p>
</body>
</html>
JSTL
使用步骤:
导包
1
2
3
4
5<dependency>
<artifactId>jstl</artifactId>
<groupId>jstl</groupId>
<version>1.2</version>
</dependency>在JSP 导入标签库
1
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
使用JSP标签
1
2<c:out value="${message}"></c:out>
out 标签用于输出信息, 自动替换特殊符合,相对输出安全
HelloWorld案例: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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<!-- 导入 core 核心标签库,使用前缀是c -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
request.setAttribute("message", "<Hello World!>");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL 演示</title>
</head>
<body>
<h1>JSTL演示</h1>
<!-- out 将信息输出到网页中 -->
<p><c:out value="${message}"></c:out></p>
<p>${message}</p>
<!-- JSTL 标签和 EL 表达式都是在服务器上处理的 -->
</body>
</html>
JSTL 有哪些常用标签:
JSTL标签的设计目的:用于取代浏览器的中的用于显示信息的Java代码
- out标签,用于输出数据,相对于EL表达式输出,out标签进行了特殊字符替换
for 循环标签: 1 计次循环, 2 集合遍历
1
2
3
4
5
6
7
8<c:forEach begin="1" end="5" step="2" var="i">
<p>${i}</p>
</c:forEach>
<ul>
<c:forEach items="${list}" var="emp" >
<li>${emp.empno}, ${emp.ename}</li>
</c:forEach>
</ul>if标签 单路分支标签
1
2
3<c:if test="${active>=100}">
<span style="color:red">赚钱了</span>
</c:if>多路分支标签
- choose
- when
- otherwise
1 | <c:choose> |
- import 包含标
1
<c:import url="footer.jsp"></c:import>
重要:JSP、JSP中的脚本、JSP中的指令(包含)、EL、JSTL、等都是在服务器端执行的。 执行结束以后将生成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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<!-- 导入 core 核心标签库,使用前缀是c -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL 演示</title>
</head>
<body>
<h1>JSTL演示</h1>
<h2>forEach 标签</h2>
<!-- begin: 开始, end:结束 step: 步子 var:变量名
如下案例:从1开始循环, 每次增加2, 到5结束循环-->
<c:forEach begin="1" end="5" step="2" var="i">
<p>${i}</p>
</c:forEach>
<h2>集合的遍历</h2>
<%
//在实际开发中,如下数据应该在Servlet中生成
List<String> names = new ArrayList<String>();
names.add("佟湘玉");
names.add("白展堂");
names.add("莫小贝");
names.add("李大嘴");
request.setAttribute("names", names);
List<Emp> list=new ArrayList<Emp>();
list.add(new Emp(1, "霸波奔", 1, null, 1, 100,10));
list.add(new Emp(2, "奔波霸", 1, null, 1, 200,10));
request.setAttribute("list", list);
%>
<!-- forEach 遍历集合 -->
<ul>
<c:forEach items="${names}" var="name">
<li>${name}</li>
</c:forEach>
</ul>
<h2>遍历对象集合</h2>
<ul>
<c:forEach items="${list}" var="emp" >
<li>${emp.empno}, ${emp.ename}</li>
</c:forEach>
</ul>
<h2>if 标签</h2>
<!-- if 标签只能实现单路分支 -->
<%
request.setAttribute("active", 100);
%>
<c:if test="${active>=100}">
<span style="color:red">赚钱了</span>
</c:if>
<h2>多路分支标签</h2>
<!-- 多路分支包含其他情形,相当于else
choose 选择 when:当,当xxx的时候,otherwise其他情况 -->
<c:choose>
<c:when test="${active>=200}">
<span style="color:red">赚大了</span>
</c:when>
<c:when test="${active>=100}">
<span style="color:red">赚钱了</span>
</c:when>
<c:otherwise>
<span style="color:green">赔本了</span>
</c:otherwise>
</c:choose>
<h2>包含标签</h2>
<!-- 其功能与 jsp:include 一样 -->
<c:import url="footer.jsp"></c:import>
</body>
</html>
利用JSTL和EL重构 list-emp2.jsp:
导入标签库:
1
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
更新头部组件包含
1
2
3
4
5<!-- Main Header 包含子页面 -->
<c:import url="/WEB-INF/include/header.jsp"/>
<!-- Left side 包含子页面 -->
<c:import url="/WEB-INF/include/left-side.jsp"/>更新集合遍历输出表格
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<c:forEach items="${list}" var="emp">
<tr>
<td>${emp.empno}</td>
<td><c:out value="${emp.ename}"/></td>
<td>${emp.mgr}</td>
<td>${emp.hiredate}</td>
<td>${emp.deptno}</td>
<td>${emp.salary}</td>
<td>${emp.comm}</td>
<!-- onclick中出现"return false" 则会阻止事件
-点击事件的响应 -->
<td><a onclick="return confirm('真的删除?吗?')"
href="delete?empno=${emp.empno}"
class="btn btn-danger btn-xs"
><i class="fa fa-fw fa-remove"></i></a>
<a href="edit-emp?empno=${emp.empno}"
class="btn btn-success btn-xs"><i
class="fa fa-fw fa-edit"></i></a></td>
</tr>
</c:forEach>更新尾部组件包含
1
2
3
4
5<!-- Main Footer 包含 -->
<c:import url="/WEB-INF/include/footer.jsp"/>
<!-- Control Sidebar 包含 -->
<c:import url="/WEB-INF/include/sidebar.jsp"/>
利用JSTL和EL重构 add-emp.jsp:
导入JSTL
1
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
替换头部包含标签
1
2
3
4<!-- Main Header 包含子页面 -->
<c:import url="/WEB-INF/include/header.jsp"/>
<!-- Left side 包含子页面 -->
<c:import url="/WEB-INF/include/left-side.jsp"/>替换Java代码
1
2
3
4
5
6
7
8
9<select class="form-control" id="mgr" name="mgr">
<c:forEach items="${mgrs}" var="mgr">
<!-- 客户端选中员工名,发送到服务器是对应的员工号
value属性是发送到服务器上的值 -->
<option value="${mgr.empno}">
<c:out value="${mgr.ename}"/>
</option>
</c:forEach>
</select>替换尾部包含
1
2
3
4<!-- Main Footer 包含 -->
<c:import url="/WEB-INF/include/footer.jsp"/>
<!-- Control Sidebar 包含 -->
<c:import url="/WEB-INF/include/sidebar.jsp"/>
利用JSTL和EL重构 edit-emp.jsp:
导入JSTL
1
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
替换头部包含标签
1
2
3
4<!-- Main Header 包含子页面 -->
<c:import url="/WEB-INF/include/header.jsp"/>
<!-- Left side 包含子页面 -->
<c:import url="/WEB-INF/include/left-side.jsp"/>替换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<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">添加新员工信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal"
method="post" action="update-emp">
<div class="box-body">
<div class="form-group">
<label for="empno"
class="col-sm-2 control-label">员工号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="empno" name="empno" placeholder="员工号"
value="${emp.empno}"
readonly="readonly" >
</div>
</div>
<div class="form-group">
<label for="ename"
class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="ename" name="ename" placeholder="姓名"
value="<c:out value="${emp.ename}"/>">
</div>
</div>
<div class="form-group">
<label for="mgr"
class="col-sm-2 control-label">领导</label>
<div class="col-sm-10">
<select class="form-control" id="mgr" name="mgr">
<c:forEach items="${mgrs}" var="mgr">
<!-- 客户端选中员工名,发送到服务器是对应的员工号
value属性是发送到服务器上的值 -->
<c:choose>
<c:when test="${emp.mgr == mgr.empno}">
<option value="${mgr.empno}"
selected="selected">
<c:out value="${mgr.ename}"/>
</option>
</c:when>
<c:otherwise>
<option value="${mgr.empno}">
<c:out value="${mgr.ename}"/>
</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="hiredate"
class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-10">
<input type="date" class="form-control"
id="hiredate" name="hiredate"
placeholder="入职日期"
value="${emp.hiredate}">
</div>
</div>
<div class="form-group">
<label for="deptno"
class="col-sm-2 control-label">部门编号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="deptno" name="deptno"
placeholder="部门编号"
value="${emp.deptno}">
</div>
</div>
<div class="form-group">
<label for="salary"
class="col-sm-2 control-label">薪资</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="salary" name="salary"
placeholder="薪资"
value="${emp.salary}">
</div>
</div>
<div class="form-group">
<label for="comm"
class="col-sm-2 control-label">提成</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="comm" name="comm"
placeholder="提成"
value="${emp.comm}">
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-info pull-right">保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->替换尾部包含
1
2
3
4<!-- Main Footer 包含 -->
<c:import url="/WEB-INF/include/footer.jsp"/>
<!-- Control Sidebar 包含 -->
<c:import url="/WEB-INF/include/sidebar.jsp"/>
显示老板名字问题
重构 ListEmpServlet
1
2
3
4
5
6
7//创建集合,缓存全部的员工号和员工名
Map<Integer, String> names = new HashMap<>();
for (Emp emp : list) {
names.put(emp.getEmpno(), emp.getEname());
}
//打桩测试 ...
request.setAttribute("names", names);重构 list-emp2.jsp
1
<td><c:out value="${names[emp.mgr]}"/></td>
测试
路径问题
Web编程时候有3套路径体系
- 浏览器视角的Web路径
- Java Web 用于程序的路径体系
- 本地操作系统文件路径体系
- ContextPath路径: Java web应用程序部署在Web服务器时候的部署文件夹。
- 浏览器视角的路径与Java WEB路径相差了一个ContextPath路径
- 将Java Web路径映射到浏览器视角的Web路径有多种解决方案:
- 使用相对路径
- 书写简单,当页面移动显示位置时候会css等资源加载失败出现404错误
- 利用 <c:url> 标签解决
- <c:url> 标签就是解决将Java WEB路径转化为 浏览器视角绝对路径而设计的标签
- 这个标签使用比较繁琐
- 利用EL表达式在路径前面添加ContextPath,这种方式简洁方便。
- 在Servlet中将 contextPath保存到request中叫 root
- 在页面中将所有 html 标签路径修改为 ${root}/…
案例, 将全部emp功能移动到 /emp 中, 目的是为了后续增加权限管理功能
- 更新全部功能的URL
修改 员工列表功能:
修改web.xml
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>ListEmpServlet</display-name>
<servlet-name>ListEmpServlet</servlet-name>
<servlet-class>day05.ListEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListEmpServlet</servlet-name>
<url-pattern>/emp/list</url-pattern>
</servlet-mapping>此时查看网页/emp/list会看到很多 404 错误,导致很多css、js文件没有加载,因为路径上增加了一层emp造成了浏览器视角路径错误,找不到对应资源了。
更新 ListEmpServlet, 将contextPath添加到request中,命名为root
1
2
3
4//将context路径保存request中, 用于将
//Java WEB目录映射到 浏览器视角WEB目录
String contextPath = request.getContextPath();
request.setAttribute("root", contextPath);更新 list-emp2.jsp 将全部html标签中的路径更新为 ${root}/
1
2
3
4
5
6
7
8
9
10
11
12
13
14<link rel="stylesheet" href="${root}/bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="${root}/bower_components/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="${root}/bower_components/Ionicons/css/ionicons.min.css">
<link rel="stylesheet" href="${root}/dist/css/AdminLTE.min.css">
<link rel="stylesheet" href="${root}/dist/css/skins/skin-blue.min.css">
...
<!-- jQuery 3 -->
<script src="${root}/bower_components/jquery/dist/jquery.min.js"></script>
<!-- Bootstrap 3.3.7 -->
<script src="${root}/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- AdminLTE App -->
<script src="${root}/dist/js/adminlte.min.js"></script>更新 header.jsp
1
2
3
4
5<img src="${root}/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">
...
<img src="${root}/dist/img/user2-160x160.jpg" class="user-image" alt="User Image">
...
<img src="${root}/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">更新 left-side.jsp
1
<img src="${root}/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">
测试 /emp/list
JSP-case-2
实现“领导”列表
更新添加界面,实现“领导”列表。
步骤:
更新 EmpDao 添加方法查询所有的领导:
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/**
* 获取员工中的全部领导
*/
public List<Emp> findMgrs(){
String sql = "select empno, ename, mgr, hiredate, deptno, salary, comm from t_emp where mgr=0 or mgr=1";
try(Connection conn=DBUtil.getConnection()){
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
List<Emp> list=new ArrayList<>();
while(rs.next()) {
//必须是没有编译错误,并且选定的代码块能够抽取为方法!
Emp emp = row2Emp(rs);
list.add(emp);
}
return list;
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private Emp row2Emp(ResultSet rs) throws SQLException {
int empno = rs.getInt("empno");
String ename = rs.getString("ename");
int mgr = rs.getInt("mgr");
Date hiredate=rs.getDate("hiredate");
int deptno = rs.getInt("deptno");
double salary = rs.getDouble("salary");
double comm = rs.getDouble("comm");
Emp emp = new Emp(empno, ename, mgr, hiredate, deptno, salary, comm);
return emp;
}测试
1
2
3
4
5
6
7
8@Test
public void testFindMgrs() {
EmpDao dao = new EmpDao();
List<Emp> list = dao.findMgrs();
for (Emp emp : list) {
System.out.println(emp);
}
}添加 AddEmpServlet
1
2
3
4
5
6
7
8
9
10
11
12
13public class AddEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* URL /add-emp
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
EmpDao dao = new EmpDao();
List<Emp> mgrs = dao.findMgrs();
request.setAttribute("mgrs", mgrs);
request.getRequestDispatcher("/WEB-INF/jsp/add-emp.jsp")
.forward(request, response);
}
}配置
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>AddEmpServlet</display-name>
<servlet-name>AddEmpServlet</servlet-name>
<servlet-class>day07.AddEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddEmpServlet</servlet-name>
<url-pattern>/add-emp</url-pattern>
</servlet-mapping>将 add-emp.jsp 移动到 /WEB-INF/jsp/add-emp.jsp 并且更新:
在 add-emp.jsp 添加导入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import="java.util.*,entity.*"
<div class="form-group">
<label for="mgr"
class="col-sm-2 control-label">领导</label>
<div class="col-sm-10">
<%
List<Emp> mgrs=(List<Emp>)request.getAttribute("mgrs");
%>
<select class="form-control" id="mgr" name="mgr">
<%for(Emp mgr:mgrs){%>
<!-- 客户端选中员工名,发送到服务器是对应的员工号
value属性是发送到服务器上的值 -->
<option value="<%=mgr.getEmpno()%>">
<%=mgr.getEname()%>
</option>
<%}%>
</select>
</div>
</div>重构 list-emp2.jsp
1
<h3 class="box-title">员工信息 <a href="add-emp" class="btn btn-success">添加</a></h3>
测试
实现修改员工信息功能
实现步骤:
EmpDao中添加查找和更新的方法
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/**
* 根据ID获取一个员工信息
*/
public Emp findByEmpno(int empno) {
String sql = "select empno, ename, mgr, hiredate, deptno, salary, comm from t_emp where empno=?";
try(Connection conn = DBUtil.getConnection()){
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1, empno);
ResultSet rs = ps.executeQuery();
Emp emp=null;
while(rs.next()) {
emp = row2Emp(rs); //重用 row2Emp 方法
}
return emp; //找到结果返回emp对象,
//找不到返回null表示"空"结果。
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 根据ID更新员工信息
*/
public int updateEmp(Emp emp) {
String sql = "update t_emp set ename=?, mgr=?, hiredate=?, deptno=?,salary=?, comm=? where empno=?";
try(Connection conn = DBUtil.getConnection()){
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1, emp.getEname());
ps.setInt(2, emp.getMgr());
ps.setDate(3, emp.getHiredate());
ps.setInt(4, emp.getDeptno());
ps.setDouble(5, emp.getSalary());
ps.setDouble(6, emp.getComm());
ps.setInt(7, emp.getEmpno());
int n = ps.executeUpdate();
return n;
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}测试:
1
2
3
4
5
6
7
8
9@Test
public void testFindUpdate() {
EmpDao dao = new EmpDao();
Emp emp = dao.findByEmpno(2);
System.out.println(emp);
emp.setEname("杰瑞");
int n = dao.updateEmp(emp);
System.out.println(n);
}添加 EditEmpServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class EditEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 处理 get 请求 URL /edit-emp
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String no = request.getParameter("empno");
int empno = Integer.parseInt(no);
EmpDao dao = new EmpDao();
Emp emp = dao.findByEmpno(empno);
List<Emp> mgrs = dao.findMgrs();
request.setAttribute("mgrs", mgrs);
request.setAttribute("emp", emp);
request.getRequestDispatcher("/WEB-INF/jsp/edit-emp.jsp")
.forward(request, response);
}
}配置
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>EditEmpServlet</display-name>
<servlet-name>EditEmpServlet</servlet-name>
<servlet-class>day07.EditEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>EditEmpServlet</servlet-name>
<url-pattern>/edit-emp</url-pattern>
</servlet-mapping>编写 edit-emp.jsp
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<%
//获取EditEmpServlet共享的 emp 对象
Emp emp = (Emp) request.getAttribute("emp");
%>
<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">添加新员工信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal"
method="post" action="update-emp">
<div class="box-body">
<div class="form-group">
<label for="empno"
class="col-sm-2 control-label">员工号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="empno" name="empno" placeholder="员工号"
value="<%=emp.getEmpno()%>"
readonly="readonly" >
</div>
</div>
<div class="form-group">
<label for="ename"
class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="ename" name="ename" placeholder="姓名"
value="<%=emp.getEname()%>">
</div>
</div>
<div class="form-group">
<label for="mgr"
class="col-sm-2 control-label">领导</label>
<div class="col-sm-10">
<%
List<Emp> mgrs=(List<Emp>)request.getAttribute("mgrs");
%>
<select class="form-control" id="mgr" name="mgr">
<%for(Emp mgr:mgrs){%>
<!-- 客户端选中员工名,发送到服务器是对应的员工号
value属性是发送到服务器上的值 -->
<% if(mgr.getEmpno()==emp.getMgr()){%>
<option value="<%=mgr.getEmpno()%>"
selected="selected">
<%=mgr.getEname()%>
</option>
<% } else { %>
<option value="<%=mgr.getEmpno()%>" >
<%=mgr.getEname()%>
</option>
<% }%>
<%}%>
</select>
</div>
</div>
<div class="form-group">
<label for="hiredate"
class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-10">
<input type="date" class="form-control"
id="hiredate" name="hiredate"
placeholder="入职日期"
value="<%=emp.getHiredate()%>">
</div>
</div>
<div class="form-group">
<label for="deptno"
class="col-sm-2 control-label">部门编号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="deptno" name="deptno"
placeholder="部门编号"
value="<%=emp.getDeptno()%>">
</div>
</div>
<div class="form-group">
<label for="salary"
class="col-sm-2 control-label">薪资</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="salary" name="salary"
placeholder="薪资"
value="<%=emp.getSalary()%>">
</div>
</div>
<div class="form-group">
<label for="comm"
class="col-sm-2 control-label">提成</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="comm" name="comm"
placeholder="提成"
value="<%=emp.getComm()%>">
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-info pull-right">保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->测试,显示编辑界面
1
http://localhost:8080/Servlet07/edit-emp?empno=3
编写UpdateEmpServlet 处理表单Post请求
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
36public class UpdateEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* 处理 post 请求, URL: /update-emp
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String no = request.getParameter("empno");
String ename=request.getParameter("ename");
String mgrno=request.getParameter("mgr");
String hire=request.getParameter("hiredate");
String dept=request.getParameter("deptno");
String sly =request.getParameter("salary");
String com =request.getParameter("comm");
int empno = Integer.parseInt(no);
int mgr = Integer.parseInt(mgrno);
//java.sql.Date 提供了将字符串转换为日期的方法
Date hiredate = Date.valueOf(hire);
int deptno = Integer.parseInt(dept);
double salary = Double.parseDouble(sly);
double comm = Double.parseDouble(com);
Emp emp = new Emp(empno, ename, mgr, hiredate, deptno, salary, comm);
EmpDao dao = new EmpDao();
//更新数据
int n = dao.updateEmp(emp);
if(n==1) {
String path=request.getContextPath()+"/list-emp";
response.sendRedirect(path);
} else {
request.setAttribute("message", "更新失败!");
request.getRequestDispatcher("/WEB-INF/jsp/message.jsp")
.forward(request, response);
}
}
}更新 list-emp2.jsp 添加编辑员工信息按钮
1
2
3
4
5
6
7<td><a onclick="return confirm('真的删除?吗?')"
href="delete?empno=<%=emp.getEmpno()%>"
class="btn btn-danger btn-xs"
><i class="fa fa-fw fa-remove"></i></a>
<a href="edit-emp?empno=<%=emp.getEmpno()%>"
class="btn btn-success btn-xs"><i
class="fa fa-fw fa-edit"></i></a></td>测试
网页的包含
一个网页包含了另外一个网页组件, 最后合并为一个页面,称为包含
JSP提供两个包含方式
静态包含: 翻译期间会将两个JSP合并为一个Servlet,运行期间执行一个Servlet
1
<%@ include file="从页面文件地址"%>
动态包含: 翻译期间生成两个Servlet,运行期间一个Serlvet动态调用了另外一个Servlet
1
<jsp:include page="header.jsp"></jsp:include>
两个包含方式,结果差别不大,一般采用动态包含编程更加方便。
案例:
被包含页面 header.jsp
1
2
3
4
5
6
7<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div>
头部
</div>静态包含:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 静态包含 header.jsp, 两个网页在翻译期间合并为同一个 -->
<%@ include file="header.jsp" %>
<div>
内容
</div>
</body>
</html>动态包含:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 动态 header.jsp, 两个网页分别编译为Servlet -->
<jsp:include page="header.jsp"></jsp:include>
<div>
内容
</div>
</body>
</html>
将员工管理拆分为包含方式:
- 创建页面组件 /WEB-INF/include
- header.jsp
- footer.jsp
- left-side.jsp
- sidebar.jsp
- 重构页面 list-emp2.jsp
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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<!DOCTYPE html>
<!--
This is a starter template page. Use this page to start your new project from
scratch. This page gets rid of all links and provides the needed markup only.
-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AdminLTE 2 | Starter</title>
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<!-- Font Awesome -->
<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css">
<!-- Ionicons -->
<link rel="stylesheet" href="bower_components/Ionicons/css/ionicons.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. We have chosen the skin-blue for this starter
page. However, you can choose any other skin. Make sure you
apply the skin class to the body tag so the changes take effect. -->
<link rel="stylesheet" href="dist/css/skins/skin-blue.min.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<!--
BODY TAG OPTIONS:
=================
Apply one or more of the following classes to get the
desired effect
|---------------------------------------------------------|
| SKINS | skin-blue |
| | skin-black |
| | skin-purple |
| | skin-yellow |
| | skin-red |
| | skin-green |
|---------------------------------------------------------|
|LAYOUT OPTIONS | fixed |
| | layout-boxed |
| | layout-top-nav |
| | sidebar-collapse |
| | sidebar-mini |
|---------------------------------------------------------|
-->
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- Main Header 包含子页面 -->
<jsp:include page="/WEB-INF/include/header.jsp"></jsp:include>
<!-- Left side 包含子页面 -->
<jsp:include page="/WEB-INF/include/left-side.jsp"></jsp:include>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>
Page Header
<small>Optional description</small>
</h1>
<ol class="breadcrumb">
<li><a href="#"><i class="fa fa-dashboard"></i> Level</a></li>
<li class="active">Here</li>
</ol>
</section>
<!-- Main content -->
<section class="content container-fluid">
<!--------------------------
| Your Page Content Here |
-------------------------->
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">员工信息
<a href="add-emp" class="btn btn-success"><i class="fa fa-user-plus"></i> 添加</a></h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table class="table table-bordered">
<tr>
<th style="width: 10px">#</th>
<th>姓名</th>
<th>老板</th>
<th>入职日期</th>
<th>部门编号</th>
<th>薪资</th>
<th>提成</th>
<th></th>
</tr>
<%
List<Emp> list =
(List<Emp>)request.getAttribute("list");
%>
<%for(Emp emp:list){%>
<tr>
<td><%=emp.getEmpno()%></td>
<td><%=emp.getEname()%></td>
<td><%=emp.getMgr()%></td>
<td><%=emp.getHiredate()%></td>
<td><%=emp.getDeptno()%></td>
<td><%=emp.getSalary()%></td>
<td><%=emp.getComm()%></td>
<!-- onclick中出现"return false" 则会阻止事件
-点击事件的响应 -->
<td><a onclick="return confirm('真的删除?吗?')"
href="delete?empno=<%=emp.getEmpno()%>"
class="btn btn-danger btn-xs"
><i class="fa fa-fw fa-remove"></i></a>
<a href="edit-emp?empno=<%=emp.getEmpno()%>"
class="btn btn-success btn-xs"><i
class="fa fa-fw fa-edit"></i></a></td>
</tr>
<%}%>
</table>
</div>
<!-- /.box-body -->
<div class="box-footer clearfix">
<ul class="pagination pagination-sm no-margin pull-right">
<li><a href="#">«</a></li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">»</a></li>
</ul>
</div>
</div>
<!-- /.box -->
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!-- Main Footer 包含 -->
<jsp:include page="/WEB-INF/include/footer.jsp"></jsp:include>
<!-- Control Sidebar 包含 -->
<jsp:include page="/WEB-INF/include/sidebar.jsp"></jsp:include>
</div>
<!-- ./wrapper -->
<!-- REQUIRED JS SCRIPTS -->
<!-- jQuery 3 -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<!-- Bootstrap 3.3.7 -->
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- AdminLTE App -->
<script src="dist/js/adminlte.min.js"></script>
<!-- Optionally, you can add Slimscroll and FastClick plugins.
Both of these plugins are recommended to enhance the
user experience. -->
</body>
</html>
JSP-case-1
实现添加员工功能
步骤:
在员工列表页面list-emp2.jsp增加添加链接:
1
<h3 class="box-title">员工信息 <a href="add-emp.jsp" class="btn btn-success">添加</a></h3>
根据模板页面 starter.html 和 pages/forms/general.html创建 add-emp.jsp
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<!-- Horizontal Form -->
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">添加新员工信息</h3>
</div>
<!-- /.box-header -->
<!-- form start -->
<form class="form-horizontal"
method="post" action="save-emp">
<div class="box-body">
<div class="form-group">
<label for="ename"
class="col-sm-2 control-label">姓名</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="ename" name="ename" placeholder="姓名">
</div>
</div>
<div class="form-group">
<label for="mgr"
class="col-sm-2 control-label">领导编号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="mgr" name="mgr" placeholder="领导编号">
</div>
</div>
<div class="form-group">
<label for="hiredate"
class="col-sm-2 control-label">入职日期</label>
<div class="col-sm-10">
<input type="date" class="form-control"
id="hiredate" name="hiredate"
placeholder="入职日期">
</div>
</div>
<div class="form-group">
<label for="deptno"
class="col-sm-2 control-label">部门编号</label>
<div class="col-sm-10">
<input type="text" class="form-control"
id="deptno" name="deptno"
placeholder="部门编号">
</div>
</div>
<div class="form-group">
<label for="salary"
class="col-sm-2 control-label">薪资</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="salary" name="salary"
placeholder="薪资">
</div>
</div>
<div class="form-group">
<label for="comm"
class="col-sm-2 control-label">提成</label>
<div class="col-sm-10">
<input type="number" class="form-control"
id="comm" name="comm"
placeholder="提成">
</div>
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" class="btn btn-info pull-right">保存</button>
</div>
<!-- /.box-footer -->
</form>
</div>
<!-- /.box -->在EmpDao中添加 save(emp) 方法, 实现增加Emp对象的功能.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* 添加新用户功能
* 返回添加的行数
*/
public int save(Emp emp) {
//将emp对象中的数据保存到 数据库
String sql = "insert into t_emp (empno, ename, mgr, hiredate, deptno, salary, comm) values (null, ?,?,?,?,?,? )";
try(Connection conn=DBUtil.getConnection()){
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, emp.getEname());
ps.setInt(2, emp.getMgr());
ps.setDate(3, emp.getHiredate());
ps.setInt(4, emp.getDeptno());
ps.setDouble(5, emp.getSalary());
ps.setDouble(6, emp.getComm());
int n = ps.executeUpdate();
return n;
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}测试 save 方法
1
2
3
4
5
6
7
8
9
10
11public class TestCase {
@Test
public void testSaveEmp() {
Date date = new Date(System.currentTimeMillis());
Emp emp = new Emp(0, "范传奇", 1, date,
1, 1000, 20);
EmpDao dao = new EmpDao();
int n = dao.save(emp);
System.out.println(n);
}
}编写Servlet, 处理表单post请求:
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
47public class SaveEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 接收表单参数
//2. 将表单参数保存到数据
//3. 转发到 成功页面
request.setCharacterEncoding("UTF-8");
String ename=request.getParameter("ename");
String mgrId=request.getParameter("mgr");
String date =request.getParameter("hiredate");
String deptId=request.getParameter("deptno");
String salarys=request.getParameter("salary");
String comms = request.getParameter("comm");
System.out.println(ename);
System.out.println(mgrId);
System.out.println(date);
System.out.println(deptId);
System.out.println(salarys);
System.out.println(comms);
try {
//数据类型转换: 将字符串转换为目标数据类型
SimpleDateFormat fmt= new SimpleDateFormat("yyyy-MM-dd");
int mgr = Integer.parseInt(mgrId);
Date hiredate = new Date(fmt.parse(date).getTime());
int deptno = Integer.parseInt(deptId);
double salary = Double.parseDouble(salarys);
double comm = Double.parseDouble(comms);
//保存到数据库
Emp emp = new Emp(0, ename, mgr, hiredate, deptno, salary, comm);
EmpDao dao = new EmpDao();
int n = dao.save(emp);
if(n==1) {
//成功
request.setAttribute("message", "添加成功!");
request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
}else {
//失败
request.setAttribute("message", "添加失败!");
request.getRequestDispatcher("/WEB-INF/jsp/message.jsp").forward(request, response);
}
}catch(Exception e) {
e.printStackTrace();
}
}
}配置Servlet
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>SaveEmpServlet</display-name>
<servlet-name>SaveEmpServlet</servlet-name>
<servlet-class>day06.SaveEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SaveEmpServlet</servlet-name>
<url-pattern>/save-emp</url-pattern>
</servlet-mapping>利用starter.html 创建 /WEB-INF/jsp/message.jsp 用于显示成功消息
1
2
3<p class="well">
<%=request.getAttribute("message")%>
</p>测试
转发 与 重定向
- 转发: 一次请求
- 为了实现 Servlet与JSP协同工作, Sertvlet处理结束以后由JSP负责显示数据, SUN 设计 Servlet到JSP的转发功能.(尽管Servlet到Servlet, JSP到JSP可以转发, 但极少使用)
- 一般都在Servlet处理以后, 转发到JSP显示数据!!
- 重定向: 两次请求
- 是HTTP协议中设计的一个功能, 浏览器根据服务器的响应结果自动转向(跳转)到一个新的URL地址.
- 服务在响应中发送 302 状态码和Location头, 浏览器收到302就会转向到 Location头中设定的URL地址.
- 如果服务器端希望重新转向新的URL地址(发起新的GET请求)时候使用重定向.
重构SaveEmpServlet利用重定向显示添加的结果:1
2
3
4
5
6
7
8if(n==1) {
String url= request.getContextPath()+"/list-emp";
response.sendRedirect(url);
}else {
//失败
request.setAttribute("message", "添加失败!");
request.getRequestDispatcher("/WEB-INF/jsp/message.jsp") .forward(request, response);
}
实现删除功能:
步骤:
EmpDao中添加delete方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/**
* 按照员工号删除员工信息
*/
public int delete(int empno) {
String sql="delete from t_emp where empno=?";
try(Connection conn=DBUtil.getConnection()){
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, empno);
int n = ps.executeUpdate();
return n;
}catch(Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}测试:
1
2
3
4
5
6@Test
public void testDeleteEmp() {
EmpDao dao = new EmpDao();
int n = dao.delete(4);
System.out.println(n);
}修改list-emp2.jsp 添加删除链接:
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<table class="table table-bordered">
<tr>
<th style="width: 10px">#</th>
<th>姓名</th>
<th>老板</th>
<th>入职日期</th>
<th>部门编号</th>
<th>薪资</th>
<th>提成</th>
<th></th>
</tr>
<%
List<Emp> list =
(List<Emp>)request.getAttribute("list");
%>
<%for(Emp emp:list){%>
<tr>
<td><%=emp.getEmpno()%></td>
<td><%=emp.getEname()%></td>
<td><%=emp.getMgr()%></td>
<td><%=emp.getHiredate()%></td>
<td><%=emp.getDeptno()%></td>
<td><%=emp.getSalary()%></td>
<td><%=emp.getComm()%></td>
<!-- onclick中出现"return false" 则会阻止事件
-点击事件的响应 -->
<td><a onclick="return confirm('真的删除?吗?')"
href="delete?empno=<%=emp.getEmpno()%>"
class="btn btn-danger btn-xs"
><i class="fa fa-fw fa-remove"></i></a></td>
</tr>
<%}%>
</table>编写Servlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class DeleteEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String no = request.getParameter("empno");
//请自行打桩测试接收到的参数是否有效
int empno = Integer.parseInt(no);
//调用EmpDao删除数据
EmpDao dao = new EmpDao();
int n = dao.delete(empno);
if(n==1) {
//重定向到 员工列表页面, 显示结果
String path=request.getContextPath()+"/list-emp";
response.sendRedirect(path);
} else {
//转发到message.jsp显示错误消息
request.setAttribute("message", "删除失败");
request.getRequestDispatcher("/WEB-INF/jsp/message.jsp")
.forward(request, response);
}
}
}测试
JSP-Java
JSP
JSP: Java服务器页面1
2
3J-Java
S-Server
P-Page
- 历史上 微软公司首先提供了 ASP 技术, 很受欢迎
- SUN根据ASP的风格基于Servlet技术, 设计了JSP
- JSP就是Servlet
JSP编程好处:
- JSP 页面基于HTML页面, 传统的HTML开发工具可以写JSP
- 在运行时候 JSP 被翻译成 .java 文件(Servlet) 再编译为.class
- 执行时候执行class文件.
JSP自动部署, 不用写web.xml
JSP 的优势在于 使用HTML风格编码编写Servlet类! JSP非常适合显示网页符数据.
JSP Hello World!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个JSP</title>
</head>
<body>
<h1>第一个JSP</h1>
<!-- JSP 中可以嵌入 "Java 程序脚本" -->
<%
String str = "Hello World!";
%>
<!-- JSP 表达式, 用于计算表达式值 -->
<p><%=str%></p>
</body>
</html>
JSP运行原理
JSP运行过程:
- 第一次请求JSP时候
- 先将JSP翻译为一个 Servlet 源程序(.java)
- 再将Servlet源程序编译为.class文件
- 创建Servlet对象
- 执行Servlet对象的 service 方法, 处理请求与响应
- 第二次请求JSP时候
- 如果JSP被编辑过则重新走流程 1
- 如果JSP没有被编辑过, 则执行执行Servlet对象的 service 方法
JSP 中的Java
- Java 脚本 : 用于处理程序逻辑, 可以写任意语句, 流程控制等
1
2
3
4
5<%
//Java 脚本
long now = System.currentTimeMillis();
long year = now/1000/60/60/24/365 + 1970;
%>
Java 脚本中的语句会翻译到 service 方法中的语句
- Java 表达式: 用于计算并且输出表达式
1
2
3
4 <!-- JSP 表达式, 用于计算表达式值并且在网页上输出-->
<p><%=now/1000%60%></p>
<p><%=year%></p>
<p><%=add(times, 1)%></p>
- Java 声明: 用于为Servlet声明成员
1
2
3
4
5
6
7
8
9<!-- JSP 中的"声明", -->
<%!
//用于为当前类声明 属性/方法/静态成员等
//编译以后会成为 Servlet 中的成员
int times = 55;
int add(int a, int b){
return a+b;
}
%>
案例: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<%@ page language="java"
contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Java 程序</title>
</head>
<body>
<h1>JSP中的Java</h1>
<!-- JSP 中的"声明", -->
<%!
//用于为当前类声明 属性/方法/静态成员等
//编译以后会成为 Servlet 中的成员
int times = 55;
int add(int a, int b){
return a+b;
}
%>
<%
//Java 脚本
long now = System.currentTimeMillis();
long year = now/1000/60/60/24/365 + 1970;
%>
<!-- JSP 表达式, 用于计算表达式值并且在网页上输出-->
<p><%=now/1000%60%></p>
<p><%=year%></p>
<p><%=add(times, 1)%></p>
</body>
</html>
page 指令
使用 <%@ page %> 声明page 指令
- 必须写在JSP的第一行
- 属性:
- language=java 可以省略, 省略就是Java, 只能Java
- contentType=”text/html; charset=UTF-8” 就是 response.setContentType(…) 设置浏览器端的解析编码
- pageEncoding=”UTF-8” 页面编码, 是告诉Tomcat读取当前网页时候的编码
- import=”java.util.,java.sql.“ 导入组件
JSP内置对象
- 就是JSP中预先定义的引用, 引用了与JSP功能相关的对象.
- 可以随时使用引用调用对象的方法, 实现功能
- 一共有9个对象: 经常成为9大内置对象.
常用:
- request HttpServletResuest
- response HttpServletResponse
- out JspWriter 功能与 PrintWriter 一致
考点: JSP out对象的类型: JspWriter
比较常用:
- session HttpSession 类型, 用于存储与”用户会话”有关的数据.(以后讲)
- application ServletContext 类型, 用于存储与当前Servlet容器有关的数据(后续专门讲)
- pageContext PageContext, 页面”上下文Context”. PageContext是当前页面上下文, 是当前页面的大管家, 内部包含与JSP有关的全部资源.
1
2pageContext.getRequest() 返回的对象就是 request
pageContext.getResponse() 返回的对象就是 response对象
不常用:
- config : ServletConfig 用于读取 web.xml 的内容
- page : Object类型, 是当前JSP对象(Servlet对象)的引用, 就是this
- exception : Exception 类型, 当前网页是错误页面时候, 用于获取异常信息.
案例: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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,java.sql.*"
%>
<%
List<String> list=new ArrayList<String>();
//演示request对象的功能: 读取请求中的数据
String ua = request.getHeader("User-Agent");
//演示response对象功能: 处理响应信息
response.setHeader("message", "Hello World!");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>内置对象功能演示</h1>
<p>User-Agent:
<%
//在p标签里面显示ua信息
out.println(ua);
%>
</p>
<%
//pageContext 页面上下文, 包含当前页面全部相关信息
// pageContext.getOut() 返回对象就是 out 对象
// 其功能与out对象相同
JspWriter o = pageContext.getOut();
%>
<p>User-Agent: <% o.println(ua); %> </p>
</body>
</html>
利用request对象共享数据
request内部封装了一个集合, 用于在一个请求期间共享数据。
主要用于在Servlet与JSP之间共享数据。
其主要API方法:1
2
3request.setAttribute(key, value);
Object value = request.getAttribute(key);
request.removeAttribute(key);
案例: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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,java.sql.*"
%>
<%
//将数据存储到 request中
request.setAttribute("msg", "Hello World!");
request.setAttribute("price", 1234.0);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>利用request共享/传送数据</h1>
<%
//接收request传递/共享的数据
String s = (String)request.getAttribute("msg");
Double d = (Double)request.getAttribute("price");
//删除request中共享的数据
request.removeAttribute("msg");
request.removeAttribute("price");
%>
<p>msg:<%=s%> price:<%=d%></p>
</body>
</html>
转发
利用请求协作对象, 从Servlet转发到JSP。
SUN为了能够实现Servlet处理业务功能, 由JSP显示业务处理结果, 而设计了Servlet到JSP的转发功能。
案例: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
42public class DemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//测试 从Servlet转发到JSP
//1. 保存数据到 request 对象
request.setAttribute("msg", "Hello World!");
//2. 利用请求协作对象转发到一个JSP页面
RequestDispatcher rd=request.getRequestDispatcher("demo03.jsp");
rd.forward(request, response);
//注意!! 转发以后不能再处理网页内容,
//包括向response输出信息, 或者再次转发!!
}
}
<servlet>
<description></description>
<display-name>DemoServlet</display-name>
<servlet-name>DemoServlet</servlet-name>
<servlet-class>day05.DemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DemoServlet</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,java.sql.*"
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>从Servlet转发到JSP</h1>
<p><%=request.getAttribute("msg")%></p>
</body>
</html>
实现MVC版本的员工列表:
- DBUtil, Emp 等略
编写Servlet
1
2
3
4
5
6
7
8
9
10
11
12
13public class ListEmpServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//利用Dao获取数据
EmpDao dao = new EmpDao();
List<Emp> list = dao.findAll();
//利用request共享数据
request.setAttribute("list", list);
//转发到 list-emp.jsp, 显示员工列表
RequestDispatcher rd=request.getRequestDispatcher("list-emp.jsp");
rd.forward(request, response);
}
}配置
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>ListEmpServlet</display-name>
<servlet-name>ListEmpServlet</servlet-name>
<servlet-class>day05.ListEmpServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListEmpServlet</servlet-name>
<url-pattern>/list-emp</url-pattern>
</servlet-mapping>编写JSP
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<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*,entity.*"
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>员工列表</title>
</head>
<body>
<h1>员工列表</h1>
<table border="1">
<tr>
<td>编号</td>
<td>姓名</td>
<td>领导</td>
<td>入职日期</td>
<td>部门号</td>
<td>薪资</td>
<td>提成</td>
</tr>
<%
List<Emp> list =
(List<Emp>)request.getAttribute("list");
%>
<%for(Emp emp:list){ %>
<tr>
<td><%=emp.getEmpno()%></td>
<td><%=emp.getEname()%></td>
<td><%=emp.getMgr()%></td>
<td><%=emp.getHiredate()%></td>
<td><%=emp.getDeptno()%></td>
<td><%=emp.getSalary()%></td>
<td><%=emp.getComm()%></td>
</tr>
<%}%>
</table>
</body>
</html>
Web-Servlet-2
Request 接收表单参数
Request功能很多, 其主要作用就是处理浏览器请求. 用户通过表单提交的参数可以通过Request对象提供的API方法读取1
String name = request.getParamter("name");
案例:
编写表单 webapp/login.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录表单</title>
</head>
<body>
<h1>登录</h1>
<p>使用request对象接收表单参数</p>
<!-- 向 login url发起post请求 -->
<form action="login" method="post">
<div>
<label>用户</label>
<input type="text" name="user">
</div>
<div>
<label>密码</label>
<input type="password" name="pwd">
</div>
<input type="submit" value="登录">
</form>
</body>
</html>测试显示表单
编写Servlet
1
2
3
4
5
6
7
8
9
10
11
12
13public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//利用request的API获取表单参数
String name = request.getParameter("user");
String pwd = request.getParameter("pwd");
System.out.println(name+","+pwd);
response.setContentType("text/html; charset=utf-8");
PrintWriter out=response.getWriter();
out.print("OK");
}
}
参数编码问题
- 网络和IO 每次只能传输一个字节(8位)信息!
- 字符是16位无符号整数
- 利用网络传输字符时候, 需要将字符进行拆分才能传输
- 字符的拆分方案称为字符的编码!
Post请求时候, 在获取请求参数之前设置请求的编码可以解决编码问题.
案例:1
2
3
4
5
6
7
8
9
10
11
12
13
14public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {
//在读取参数之前设置request的编码,处理解码问题
request.setCharacterEncoding("UTF-8");
//利用request的API获取表单参数
String name = request.getParameter("user");
String pwd = request.getParameter("pwd");
System.out.println(name+","+pwd);
response.setContentType("text/html; charset=utf-8");
PrintWriter out=response.getWriter();
out.print("OK");
}
}
接收get请求参数
getParamter不仅可以接受post请求参数, 也可以接收get请求参数.
get编码问题可以在Tomcat配置文件server.xml中配置:1
<Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
案例:1
2
3
4
5
6
7
8
9
10
11
12
13public class GetDemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收浏览器通过 get 请求发送的参数
//如果浏览器没有提供对应的参数, 则接收到null
String id=request.getParameter("id");
String name=request.getParameter("name");
System.out.println(id+", "+name);
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("OK");
}
}
配置:1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>GetDemoServlet</display-name>
<servlet-name>GetDemoServlet</servlet-name>
<servlet-class>day03.GetDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetDemoServlet</servlet-name>
<url-pattern>/get-demo</url-pattern>
</servlet-mapping>
利用Servlet将数据库中的表显示到浏览器中
1. 创建表
创建员工表:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16create database web;
use web;
create table t_emp(
empno int auto_increment primary key,
ename varchar(100),
mgr int,
deptno int,
hiredate datetime,
salary double,
comm double
);
insert into t_emp (empno, ename, mgr, deptno, hiredate, salary, comm)
values (null, 'Tom', 0, null, now(), 1000, 200);
insert into t_emp (empno, ename, mgr, deptno, hiredate, salary, comm)
values (null, 'Jerry', 1, null, now(), 2000, 100);
2. 编写数据库连接配置文件 db.properties
1 | driver=com.mysql.jdbc.Driver |
3. 编写数据库连接工具
1 | public class DBUtil { |
4. 利用JUnit进行测试:
导入JUnit
1
2
3
4
5<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>编写测试案例:
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
30public class TestCase {
@Test
public void test() {
System.out.println("Hello World!");
}
@Test
public void testHello() {
System.out.println("Hello Kitty!");
}
@Test
public void testGetConnection() {
String sql = "select now() d";
Connection conn = null;
try {
conn = DBUtil.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
Date date=rs.getDate("d");
System.out.println(date);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
DBUtil.close(conn);
}
}
}
5. 编写Servlet 显示表内容
代码: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
51public class ListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得out对象
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("<title>登录表单</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>员工列表</h1>");
String sql="select empno, ename, mgr, hiredate, deptno, salary, comm from t_emp";
Connection conn = null;
try {
conn = DBUtil.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
//输出表格头
out.println("<table>");
out.println("<tr>");
out.println("<td>编号</td>");
out.println("<td>姓名</td>");
out.println("<td>入职日期</td>");
out.println("</tr>");
while(rs.next()) {
int empno = rs.getInt("empno");
String ename = rs.getString("ename");
Date date = rs.getDate("hiredate");
//System.out.println(empno+","+ename);
out.println("<tr>");
out.println("<td>"+empno+"</td>");
out.println("<td>"+ename+"</td>");
out.println("<td>"+date+"</td>");
out.println("</tr>");
}
out.println("</table>");
}catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(conn);
}
out.println("</body>");
out.println("</html>");
}
}
配置:1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>ListServlet</display-name>
<servlet-name>ListServlet</servlet-name>
<servlet-class>day03.ListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListServlet</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>
测试:1
http://localhost:8080/Servlet03/list
Web-Servlet-3
数据库连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
在需求数据连接数超过可连接总数时候可以控制最大连接数, 避免连接过载, 保护数据库连接资源。
这项技术能明显提高对数据库操作的性能, 同时限制数据库连接总数避免资源过载。
- 数据库连接池的管理策略
- 初始时候会创建一定数量的连接
- 在用户获取连接时候直接重用已有连接
- 在连接需求数量超过最大连接数时候, 控制连接总数
- 在连接池中的空闲连接较多时候, 会关闭连接多余的连接, 保持空闲连接数量
使用步骤
导入DBCP, MySQL JDBC, JUnit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>编写测试案例:
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
38public class TestCase {
@Test
public void testDBCP() throws Exception {
//BasicDataSource 就是Apache提供的数据库
//连接池组件, 使用步骤:
//1. 创建连接池对象
//2. 设置4个必须的连接池参数
// driverClass, url, username, password
//3. 设置可选的数据库连接管理策略参数
// 初始连接数: 先创建的连接数量
// 最大连接数: 最多创建的连接数量
// 空闲连接数: 连接用完以后保持连接数
// ...
BasicDataSource ds = new BasicDataSource();
//设置必须参数
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/web");
ds.setUsername("root");
ds.setPassword("root");
//设置可选参数
ds.setInitialSize(5); //Initial: 初始的
ds.setMaxActive(50); //最大连接数
ds.setMaxIdle(10); //最大空闲(Idle)连接数
//要合理设置可选参数.
//从数据库连接池中拿到数据库连接
Connection conn = ds.getConnection();
String sql = "select 'Hello World' as s";
Statement st = conn.createStatement();
ResultSet rs=st.executeQuery(sql);
while(rs.next()) {
String s = rs.getString("s");
System.out.println(s);
}
//执行close()方法, 将连接归还到连接池
conn.close();
}
}测试: 利用数据库连接池重构 DBUtil
编写配置文件 db.properties
1
2
3
4
5
6
7driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/web?characterEncoding=utf8&useUnicode=true&useSSL=false
username=root
password=
initial=5
max=50
idle=10编写DBUtil类
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
40public class DBUtil {
private static BasicDataSource ds;
static {
ds = new BasicDataSource();
//读取配置文件, 初始化连接池对象
Properties cfg = new Properties();
try {
InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
cfg.load(in);
in.close();
String driver=cfg.getProperty("driver");
String url=cfg.getProperty("url");
String username=cfg.getProperty("username");
String password=cfg.getProperty("password");
int initial=Integer.parseInt(cfg.getProperty("initial"));
int max = Integer.parseInt(cfg.getProperty("max"));
int idle = Integer.parseInt(cfg.getProperty("idle"));
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
ds.setInitialSize(initial);
ds.setMaxActive(max);
ds.setMaxIdle(idle);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void close(Connection conn) {
try {
if(conn!=null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}编写测试案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Test
public void testDBUitl() throws Exception {
//测试 DBUtil管理的连接池对象是否能够连接到数据库
//从连接池拿到连接
Connection conn = DBUtil.getConnection();
String sql = "select 'DBCP' as s";
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
String str = rs.getString("s");
System.out.println(str);
}
DBUtil.close(conn); //归还连接
}测试
DAO 数据访问对象
利用DAO将页面表现和数据访问进行分离
- 将数据访问和页面表现加以分离
- 数据访问逻辑集中管理,方便维护
- 页面表现集中管理方便维护
步骤
创建Emp类, 用于封装数据:
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/**
* 创建员工类, 封装员工数据
* 业务实体(entity)类, 封装业务数据的类
* 生成 有参构造器, get set 方法, 生成toString
*/
public class Emp {
private int empno;
private String ename;
private int mgr;
private Date hiredate;
private int deptno;
private double salary;
private double comm;
public Emp() {
}
public Emp(int empno, String ename, int mgr, Date hiredate, int deptno, double salary, double comm) {
super();
this.empno = empno;
this.ename = ename;
this.mgr = mgr;
this.hiredate = hiredate;
this.deptno = deptno;
this.salary = salary;
this.comm = comm;
}
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getMgr() {
return mgr;
}
public void setMgr(int mgr) {
this.mgr = mgr;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getComm() {
return comm;
}
public void setComm(double comm) {
this.comm = comm;
}
@Override
public String toString() {
return "Emp [empno=" + empno + ", ename=" + ename + ", mgr=" + mgr + ", hiredate=" + hiredate + ", deptno=" + deptno + ", salary=" + salary + ", comm=" + comm + "]";
}
}创建EmpDAO封装数据访问逻辑
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/**
* 封装对 Emp 表的数据访问功能
*/
public class EmpDao {
/**
* 从数据库中查询全部的员工数据, 封装到List
* 返回, list中的每个元素是一个Emp对象
* @return 全部的员工数据
*/
public List<Emp> findAll(){
String sql = "select empno, ename, mgr, hiredate, deptno, salary, comm from t_emp";
Connection conn = null;
try {
conn = DBUtil.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
List<Emp> list = new ArrayList<>();
while(rs.next()) {
int empno = rs.getInt("empno");
String ename = rs.getString("ename");
int mgr = rs.getInt("mgr");
Date hiredate=rs.getDate("hiredate");
int deptno = rs.getInt("deptno");
double salary = rs.getDouble("salary");
double comm = rs.getDouble("comm");
Emp emp = new Emp(empno, ename, mgr, hiredate, deptno, salary, comm);
list.add(emp);
}
return list;//正常结果
} catch (Exception e) {
e.printStackTrace();
//错误情况!
throw new RuntimeException(e); //错误结果
} finally {
DBUtil.close(conn);
}
}
}测试:
1
2
3
4
5
6
7
8@Test
public void testEmpDao() {
EmpDao dao = new EmpDao();
List<Emp> list = dao.findAll();
for (Emp emp : list) {
System.out.println(emp);
}
}
利用EmpDao显示员工列表
编写Servlet
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
43public class ListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
//获取全部需要显示的数据
EmpDao dao = new EmpDao();
List<Emp> list = dao.findAll();
//输出页面显示数据
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset=\"UTF-8\">");
out.println("</head>");
out.println("<body>");
out.println("<h1>员工列表</h1>");
//遍历 list 集合拼接表格
out.println("<table border='1'>");
out.println("<tr>");
out.println("<td>编号</td>");
out.println("<td>姓名</td>");
out.println("<td>领导</td>");
out.println("<td>入职日期</td>");
out.println("<td>部门号</td>");
out.println("<td>薪资</td>");
out.println("<td>提成</td>");
out.println("</tr>");
for(Emp emp : list) {
out.println("<tr>");
out.println("<td>"+emp.getEmpno()+"</td>");
out.println("<td>"+emp.getEname()+"</td>");
out.println("<td>"+emp.getMgr()+"</td>");
out.println("<td>"+emp.getHiredate()+"</td>");
out.println("<td>"+emp.getDeptno()+"</td>");
out.println("<td>"+emp.getSalary()+"</td>");
out.println("<td>"+emp.getComm()+"</td>");
out.println("</tr>");
}
out.println("</table>");
out.println("</body>");
out.println("</html>");
}
}配置 web.xml
1
2
3
4
5
6
7
8
9
10<servlet>
<description></description>
<display-name>ListServlet</display-name>
<servlet-name>ListServlet</servlet-name>
<servlet-class>day04.ListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListServlet</servlet-name>
<url-pattern>/list</url-pattern>
</servlet-mapping>部署测试:
1
http://localhost:8080/Servlet04/list
Web-Servlet
Servlet
Servlet: 是指在在服务器上执行的程序片段.
- Servlet是JavaEE规范的一部分
- 用来解决Web服务器端编程问题
- Servlet组件工作在Java Web服务器中
安装配置Tomcat服务器
- 下载Tomcat http://tomcat.apache.org
- 安装: 释放tomcat压缩包即可
- 在Eclipse中配置Tomcat
参考: http://doc.tedu.cn/tomcat/index.html
Servlet Hello World
实现步骤
- 创建 Maven Web 项目
- 创建maven war项目(Eclipse必须能够连接到Mavne仓库)
- 在项目上 使用 右键创建 “部署描述文件 web.xml”
- 导入Tomcat 目标服务器运行环境
- 就是导入 Servlet 接口
创建一个类 DemoServlet
- 向response发送 Hello World
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class DemoServlet implements Servlet{
public void destroy() {
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) throws ServletException {
}
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
//将 Hello World 写到response中
response.getWriter().print("Hello World!");
}
}
- 向response发送 Hello World
配置web.xml
- 将请求路径 /hello 映射到 DemoServlet 上
1
2
3
4
5
6
7
8
9
10<!-- 登记 Servlet -->
<servlet>
<servlet-name>demo</servlet-name>
<servlet-class>day01.DemoServlet</servlet-class>
</servlet>
<!-- 将Servlet 映射到 URL 连接 -->
<servlet-mapping>
<servlet-name>demo</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 将请求路径 /hello 映射到 DemoServlet 上
将web程序部署到 Tomcat 中
- 部署就是复制, 将web.xml DemoServlet 等复制到Tomcat服务器中.
- 使用浏览器请求 /hello, 在浏览器中看到 Hello World!
1
http://localhost:8080/Servlet01/hello
请求与响应
HttpServletRequest
HttpServletRequest 简称 request 对象, 其父类型是 ServletRequest
- request 对象在Tomcat收到用户请求时候创建, 其内部封装的全部的用户浏览器请求信息.
- ServletRequest类型定义的方法少, 转换为HttpServletRequest方法更多, 使用更加方便.
- request对象提供了API方法, 利用这些方法可以读取用户浏览器请求的请求信息.
案例:
创建Servlet类:
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
41public class RequestDemoServlet implements Servlet{
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
//由于getMethod方法是HttpServletRequest对象的方法
//所以需要将ServletRequest对象强制转型才能调用
HttpServletRequest req = (HttpServletRequest)request;
//获取请求行中的请求方式(GET/POST)
String method=req.getMethod();
//获取请求行中的 URI
String uri = req.getRequestURI();
//获取请求行中的HTTP版本
String http = req.getProtocol();
System.out.println(method+" "+uri+" "+http);
//获取请求头中的信息
String host=req.getHeader("Host");
String ua=req.getHeader("User-Agent");
System.out.println(host);
System.out.println(ua);
//获取全部的请求头信息:
//Enumeration 与 Iterator 功能相同
Enumeration<String> em=req.getHeaderNames();
//em.hasMoreElements() 与 it.hasNext() 相同
//em.nextElement(); 与 it.next() 相同
while(em.hasMoreElements()) {
String name=em.nextElement();
System.out.println(name+":"+req.getHeader(name));
}
response.setContentType("text/html");
response.getWriter().println("OK");
}
public void destroy() {
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) throws ServletException {
}配置web.xml
1
2
3
4
5
6
7
8<servlet>
<servlet-name>req</servlet-name>
<servlet-class>day02.RequestDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>req</servlet-name>
<url-pattern>/request-demo</url-pattern>
</servlet-mapping>
HttpServletResponse
HttpServletResponse 简称Response 其父类型是 ServletResponse
- Response用于处理服务器到客户端的响应, 其内部有一个缓冲, 用来保存响应信息.
- ServletResponse 是父类型, 提供的方法没有 HttpServletResponse 多, 使用没有HttpServletResponse方便. 所以 HttpServletResponse 使用更多.
- request提供的API用来处理向客户端发送的响应信息
案例:
编写Servlet类
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
34public class ResponseDemoServlet implements Servlet{
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
//为了调用子类型的方法, 先进行类型转换
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse res=(HttpServletResponse)response;
//利用response对象, 处理对用户浏览器的响应
//设置响应状态码, 默认状态码就是200
res.setStatus(200); //400 500 302 等
//设置响应头, 设置UTF-8支持中文
res.setContentType("text/html; charset=utf-8");
String str = "<html><body><h1>今天天气不错!</h1></body></html>";
byte[] bytes = str.getBytes("utf-8");
//设置消息正文长度
res.setContentLength(bytes.length);
//添加一个自定义的响应头
res.setHeader("msg", "Hello World!");
//发送消息正文
res.getOutputStream().write(bytes);
//将response中的信息刷出, 反馈到浏览器
//如果不调用这个方法, Tomcat会自动调用!
res.flushBuffer();
}
public void destroy() {
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) throws ServletException {
}
}配置 web.xml
1
2
3
4
5
6
7
8<servlet>
<servlet-name>res</servlet-name>
<servlet-class>day02.ResponseDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>res</servlet-name>
<url-pattern>/response-demo</url-pattern>
</servlet-mapping>测试: 检查浏览器中收到的响应头信息, 是否包含自定义响应头
Response提供了更加简便的API, 可以替代如上的API:- 采用默认的状态码200
- 先设置 Content-Type 头, 包含chaeset编码
- 在创建 PrintWriter对象, printWriter对象会自动处理文本的编码,并且会自动的设置Content-Length
案例:
编写Servlet类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class ResponseDemo2Servlet implements Servlet{
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//1 响应状态码 200 时候可以不设置, 默认就是200
//2 设置ContentType响应头, 通知浏览器正文内容和编码
res.setContentType("text/html;charset=utf-8");
//3 获取 PrintWriter 对象, 字符流, 封装字符
// 的编码功能. 按照ContentType设置编码utf-8
PrintWriter out = res.getWriter();
//4 设置消息正文内容
out.print("<html><body><h1>简单版本</h1></body></html>");
//PrintWriter 会自动处理文字编码,设置ContentLength
}
public void destroy() {
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) throws ServletException {
}配置web.xml
1
2
3
4
5
6
7
8<servlet>
<servlet-name>res2</servlet-name>
<servlet-class>day02.ResponseDemo2Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>res2</servlet-name>
<url-pattern>/response2-demo</url-pattern>
</servlet-mapping>
HttpServlet
- 实现Servlet接口创建Servlet非常繁琐, Servlet API 为了简化编程提供了更加简洁的API: HttpServlet.
- HttpServlet实现了Servlet接口, 继承HttpServlet 就间接实现Servlet接口.
- HttpServlet已经完整实现Servlet接口, 只需要简单重写 doGet或者doPost就可以方便的实现Servlet.
- HttpServlet根据用户请求类型, 调用对应的doGet或者doPost方法.
案例:
创建Servlet类
1
2
3
4
5
6
7
8
9public class HttpDemoServlet extends HttpServlet{
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
PrintWriter out=resp.getWriter();
out.print("<html><body><h1>");
out.print("第一个HttpServlet");
out.print("</h1></body></html>");
}
}配置web.xml
1
2
3
4
5
6
7
8<servlet>
<servlet-name>httpdemo</servlet-name>
<servlet-class>day02.HttpDemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>httpdemo</servlet-name>
<url-pattern>/http-demo</url-pattern>
</servlet-mapping>测试: 可以看出来 继承HttpServlet可以大大简化Servlet编码
利用Eclipse开发工具提供的Servlet向导可以快速创建Servlet, 这个功能了解即可.
概念梳理
URL/URI: 语法规则一致:1
协议://服务器/路径/资源名
URL 统一资源定位: 从你计算机开始能够唯一寻获的资源位置, 目标资源一定存在.
http://cdn.tmooc.cn/bsfile//imgad///4E6DEFE23ED047B2B4AB7AD8B963E9B0.pngURI 统一资源识别: 是一个名字, 其对应的位置未必有资源. 目标资源不一定存在, 只是用来作为唯一标识名!!
请求行 GET /demo HTTP/1.1 URI
Java WEB 目录结构
- Java EE 规定了web容器中的WEB应用目录结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18webapps Tomcat WEB应用程序部署目录
|- examples Webapp WEB应用
| |- WEB-INF
| | |- lib
| | | |- mysql-jdbc.jar 第三方的jar包
| | |- classes
| | | |- xxx.class 编写的类文件
| | |- web.xml 部署描述文件
| |- index.html
wtpwebapps Eclipse创建了应用程序测试目录, 也是部署目录
|- Servlet02 Webapp WEB应用
| |- WEB-INF
| | |- lib
| | | |- mysql-jdbc.jar 第三方的jar包
| | |- classes
| | | |- xxx.class 编写的类文件
| | |- web.xml 部署描述文件
| |- index.html
WEB-INF 文件夹是用户不能直接看到的文件夹.
- Eclipse 会自动在项目中创建目录结构, 在部署时候将目录结构复制到Tomcat中.
Maven 仓库检查步骤
- 用浏览器检查是否能够看到仓库
- 检查 https://mirrors.huaweicloud.com/repository/maven/
- 如果能够看到信息, 说明能够访问仓库, 相反说明网络故障.
修改Eclipse中的Maven settings.xml 文件
1
2
3
4
5<mirror>
<id>huaweicloud</id>
<mirrorOf>*</mirrorOf>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</mirror>重启Eclipse 检查 Maven Repositories 是否连接到了Maven
- 在项目上执行 Maven -> Update Project (Force Update)
- 如果有必须的话, 可以先删除 .m2 文件夹再更新Maven
Java-JDBC
JDBC
- Java 数据库连接: 将Java程序连接到数据的桥梁.
- Sun(Java) 设计了JDBC API底层封装了Socket, 简化数据库的访问.
- JDBC为数据库提供了统一访问接口.
- 使用JDBC
- 利用maven导入数据库驱动
- 创建Maven项目
- 找到 JDBC驱动程序的 坐标
- 将JDBC坐标添加到 pom.xml
- 注册数据库驱动: 告诉JDBC如何找到数据库驱动的实现类
- 最新的数据库驱动,会自动注册(有些驱动程序不支持).
- 建议手动注册:
- Class.forName(“数据库驱动程序类名”)
- Class.forName(“com.mysql.jdbc.Driver”)
建立与数据库之间的连接
1
2
3
4
5String usr="root";
String pwd="";
// jdbc:mysql://数据库IP:3306/数据库名
String url="jdbc:mysql://localhost:3306/db6";
Connection conn=DriverManger.getConnection(url, usr, pwd);创建Statement(语句)对象: 用于执行SQL(操作数据库)
- DDL create drop 等 一般使用 execute
- DML insert delete update 一般使用 executeUpdate 执行
- DQL select 一般使用 executeQuery
1
2
3
4String sql = "create table t_user(id int, name varchar(50))";
Statement st = conn.createStatement();
st.execute(sql);
st.close();
关闭连接
1
conn.close();
建表案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public static void main(String[] args)
throws Exception{
//注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//建立连接
String usr="root";
String pwd="root";
String url="jdbc:mysql://localhost:3306/db6";
Connection conn =
DriverManager.getConnection(url,usr,pwd);
//测试:
System.out.println(conn);
//创建Statement对象,执行SQL
Statement st = conn.createStatement();
String sql = "create table t_user ("
+ "id int, "
+ "name varchar(100))";
//执行sql语句
st.execute(sql);
st.close();
//关闭连接
conn.close();
}插入数据案例:
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
29public static void main(String[] args)
throws Exception {
/**
* 利用JDBC执行插入语句
*/
String sql="insert into t_user "
+ "(id, name) "
+ "values (2, '范传奇')";
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据库
String url="jdbc:mysql://localhost:3306/db6?characterEncoding=utf8&useUnicode=true&useSSL=false";
String username="root";
String password="root";
Connection conn = DriverManager.getConnection(
url, username, password);
//创建 Statement对象
Statement st = conn.createStatement();
//executeUpdate 返回数据库中更新行数!
int n = st.executeUpdate(sql);
//处理SQL结果
if(n==1) {
System.out.println("插入成功!");
}
//关闭资源和连接
st.close();
conn.close();
}MySQL JDBC 连接常用参数, 写在连接url上:
characterEncoding 字符编码, 可以设置为utf8
useUnicode 是否使用unicode字符编码, 设置为true
关闭ssl加密, useSSL 设置为false
1
jdbc:mysql://localhost:3306/db6? characterEncoding=utf8&useUnicode=true&useSSL=false
- 删除案例
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
28public static void main(String[] args)
throws Exception {
/**
* 利用JDBC执行删除语句
*/
String sql="delete from t_user where id=1";
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据库
String url="jdbc:mysql://localhost:3306/db6";
String username="root";
String password="root";
Connection conn = DriverManager.getConnection(
url, username, password);
//创建 Statement对象
Statement st = conn.createStatement();
//executeUpdate 返回数据库中更新行数!
int n = st.executeUpdate(sql);
//处理SQL结果
if(n>=1) {
System.out.println("删除成功!");
}else {
System.out.println("删除失败!");
}
//关闭资源和连接
st.close();
conn.close();
}