0%

一.Session
1.1 概述
1.2 快速入门
HttpSession也是一个对象

说明 API
存储数据 void setAttribute(String name,Object value)
获取数据 Object getAttribute(String name)
删除数据 void removeAttribute(String name)
步骤分析

将数据存储到session中

说明 API
通过request对象,获取session对象 HttpSession session = req.getSession();
操作session的API,存储数据 session.setAttribute(“username”,”AAABBBCCCC”);
从session中获取数据
说明 API
通过request对象,获取session对象 HttpSession session = req.getSession();
操作session的API,获取数据 session.getAttribute(“username”);

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
@WebServlet("/SetSession")
public class SetSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象,获取session对象
HttpSession session = req.getSession();
//操作session的API,存储数据
session.setAttribute("username","AAABBBCCCC");
}
}


@WebServlet("/GetSession")
public class GetSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象,获取session对象
HttpSession session = req.getSession();
//操作session的API,获取数据
String username = (String) session.getAttribute("username");
System.out.println("GetSession:"+username);
}
}

1.3 工作原理
Session基于Cookie技术实现
HttpSession session = req.getSession();
如果用户是第一次访问:表示创建Session对象,生成编号
如果用户是第N次访问,根据浏览器携带编号找session对象

1.4 Session细节
1.4.1 客户端关闭,服务器不关闭,两次获取的Session数据是否相同
默认情况下,浏览器关闭再打开,两次获取的Session不同(基于cookie实现,浏览器关闭,cookie销毁)
设置cookie的存活时间(JESSIONID),代替服务器,覆盖JESSIONID,指定持久化时间

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
@WebServlet("/SessionDemo01")
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
//指定JESSIONID时间
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session对象
HttpSession session = req.getSession();
//向session中存数据
session.setAttribute("username","zZZ");
//获取SESSION 的唯一编号
String id = session.getId();
//设置cookie时长
Cookie cookie = new Cookie("JESSIONID", id);
//设置存活时间
cookie.setMaxAge(60*2);
//当前项目下共享
cookie.setPath(req.getContextPath());
//response响应cookie
resp.addCookie(cookie);
}
}

1.4.2 客户端不关闭,服务器关闭,两次获取的Session数据是否相同
当服务器正常关闭,重启后,两次获取的session数据一样
Tomcat实现了以下功能
钝化(序列化):当服务器正常关闭时,session中当数据,会序列化到磁盘
活化(反序列化):当服务器开启后,从磁盘中读取文件,反序列化到内存中
1.4.3 生命周期
何时创建

用户第一次调用req.getAttribute()时,创建
何时销毁

服务器非正常关闭
非活跃状态30分钟后销毁(tomcat/conf/web.xml官方已配置)
session.invalidate();立即销毁
作用范围

一次会话中,多次请求之间
注意:每一个浏览器和服务器之间都是独立的会话
1.4.4 URL重写
Session基于Cookie技术实现;浏览器Cookie可以禁用,一旦禁用,Session会出现问题
开发中,一般不考虑禁用Cookie用户

如果真要处理,可以使用URL重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@WebServlet("/SessionDemo02")
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session对象
HttpSession session = req.getSession();
//向session中存数据
session.setAttribute("username", "SIODJOISDJSO");

//定义URL
String url = "/Day37_war_exploded/GetSession";
//重写URL,拼接JESSIONID
url = resp.encodeURL(url);

resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("<a href'" + url + "'>Direct to get Session</a>");
}
}

1.5 Session特点
session存储数据在服务器
session存储类型任意(Object)
session存储大小和数据没有限制(相对于内存)
session存储数据相对安全
cookie和session的选择

cookie将数据保存在浏览器端,数据相对不安全,建议敏感数据不要放在cookie中,且数据大小有限制
成本低,对服务器要求不高
浏览器为了解决该不足,前端使用了localStroage

session将数据保存在服务器端,数据相对安全,数据大小比cookie中灵活
成本较高,对服务器压力大

二. 三大域对象总结
request,session,ServletContext

2.1 API
设置数据 void setAttribute(String name,Object o)
获取数据 Object getAttribute(String name)
删除数据 void removeAttribute(String name)
2.2 生命周期
2.2.1 ServleetContext域对象
何时创建 服务器正常启动,项目加载时创建
何时销毁 服务器关闭或项目卸载时,卸载
作用范围 整个web项目(共享数据)
2.2.2 HttpSession域对象
何时创建 用户第一次调用req.getSession() 方法时创建
用户访问携带的JESSIONID与服务器不匹配时创建
何时销毁 服务器非正常关闭时
未活跃时间30 min
session.invalidate();立即销毁
作用范围 一次会话中,多次请求间(共享数据)
2.2.3 HttpServletRequest域对象
何时创建 用户发送请求时创建
何时销毁 服务器做出响应后销毁
作用范围 一次请求中,多次转发间(共享数据)
2.3 小结
能用小的不用大的:request<session<servletContext

常用场景

request 一次查询的结果 (servlet转发jsp)
session 存放当前会话的私有数据
(验证码、购物车、等)
servletContext:若需要所有的Servlet都能访问到,才使用这个域对象

三.综合案例
3.1 商品购物车
3.1.1 需求分析
addCatrSetvlet

1.获取请求参数name(product)
2.返回:product 商品已加入购物车
3.从session中获取购物车
4.如果购物车为空,创建cart = new HashMap()
5.判断,此商品是否存在于购物车
6.不存在,添加商品数量1
7.存在,在原商品基础上+1
8.将购物车重写到session中

cart.jsp

1.从session中获取购物车对象
2.判断是否为空
3.如果空,显示购物车空
4.如果不为空,遍历展示商品和数量

3.1.2 代码实现
goods.jsp
addCartServlet
cart.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<head>
<title>Goods</title>
</head>

<body>

<h3>商品列表</h3>

<a href="/Day37_war_exploded/AddCartServlet?name=TV">TV,add to cart</a><br>
<a href="/Day37_war_exploded/AddCartServlet?name=PC">PC,add to cart</a><br>
<a href="/Day37_war_exploded/AddCartServlet?name=Phone">Phone,add to cart</a><br>
</body>
</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
@WebServlet("/AddCartServlet")
public class AddCartServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");

//获取请求参数
String product = req.getParameter("name");
resp.getWriter().write(product + ", has add to Cart");

//从session中获取购物车
Map<String, Integer> cart = (Map<String, Integer>) req.getSession().getAttribute("cart");

//判断购物车是否为空
if (cart == null) {
cart = new HashMap<>();
}

//判断购物车中是否包含本次商品
if (cart.containsKey(product)) {
//存在,product++
Integer oldCount = cart.get(product);//之前的数量
cart.put(product, ++oldCount);//数量加一
} else {
//不存在 ,加入购物车
cart.put(product, 1);
}

//重新将购物车写入到session中
req.getSession().setAttribute("cart", cart);

//继续浏览
resp.getWriter().write("<br><a href='/Day37_war_exploded/goods.jsp'>Continue View</a><br>");
//查看购物车
resp.getWriter().write("<br><a href='/Day37_war_exploded/cart.jsp'>Check Shopping Cart</a>");

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<table border="1" width="200px" align="center">
<tr>
<th>Product</th>
<th>Quantity</th>
</tr>
<%
//从session中获取购物车
Map<String, Integer> cart = (Map<String, Integer>) request.getSession().getAttribute("cart");
//判断是否为空
if (cart == null) {
out.write("No Product here<br>");
} else {
for (String product : cart.keySet()) {
out.write("<tr><td>" + product + "</td> <td>" + cart.get(product) + "</td><tr/>");
}
}
%>
<a href='/Day37_war_exploded/goods.jsp'>Continue View</a>
</table>

3.2 用户登陆(验证码)
3.2.1 需求分析
3.2.2 代码实现

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
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
//课下作业实现非空判断
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
//获取用户输入验证码
String checkcode = req.getParameter("checkcode");
//获取session验证码
String codeSession = (String) req.getSession().getAttribute("code_session");
//校验匹配
if (!checkcode.equalsIgnoreCase(codeSession)) {
//验证码不匹配提示
req.setAttribute("Error", "Check Code Wrong");
//转发到login.jsp
req.getRequestDispatcher("/login.jsp").forward(req, resp);
//代码不再向下执行
return;
}
//获取用户输入到用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");

//判断用户名密码
if (!("jack".equals(username) && "123".equals(password))) {
//用户名密码不匹配提示
req.setAttribute("Error", "Username or Password Wrong");
//转发到login.jsp
req.getRequestDispatcher("/login.jsp").forward(req, resp);
//代码不再向下执行
return;
}

//将用户名存入session
req.getSession().setAttribute("username", username);
//重定向到Succes.jsp
resp.sendRedirect(req.getContextPath() + "/success.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
<form action="/war_exploded/LoginServlet" method="post">
Name: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
Checkcode: <input type="text" name="checkcode"><img src="/Day37_war_exploded/CheckCodeServlet" id="image1"
alt=""><br>
<input type="submit" value="Login">
<span style="color: red">
<%
String error = (String) request.getAttribute("Error");
if (error != null) {
out.write(error);
}
%>

</span>
</form>
<script>
document.getElementById("image1").onclick = function () {
this.src = '/Day37_war_exploded/CheckCodeServlet?' + new Date().getTime();
}
</script>
</body>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Success</title>
</head>
<body>
<%
//获取用户信息
String username = (String) request.getSession().getAttribute("username");
if (username != null){
out.write("Welcome ,"+username);
}
%>
</body>
</html>

总结
概述
在一次会话的多次请求之间共享数据,将数据保存到服务器端
实现原理
基于Cookie技术
jsessionid=xxxx
常用方法
获取session
request.getSession()
使用session
setAttribute()
getAttribute()
remomveAttribute()
生命周期
何时创建
用户第一次执行getSession()方法时,创建
用户携带的jssionid与服务器不匹配时,创建
何时销毁
服务器非正常关闭时
session.invalidate()
session默认销毁时间30分钟

tomcat目录/conf/web.xm
作用范围
一次会话中,多次请求之间
特点

  1. session在服务器端存储数据
  2. session存储数据格式可以是任意类型
  3. session存储数据没有大小限制(相对于内存)
  4. session存储数据相对安全
    三个域对象
    ServletContext
    创建
    销毁
    作用域
    HttpSession
    创建
    销毁
    作用域
    HttpServletRequest
    创建
    销毁
    作用域
    综合案例
    商品购物车
    用户登录(验证码)

一.会话概述
1.1 什么是会话
http协议是一个无状态协议,同一会话的多次请求相互独立,会话负责存储浏览器和服务器多次请求之间的数据

1.2 会话技术
客户端会话技术:Cookie
服务端会话技术:Session

二.Cookie
2.1 概述
作用:在一次会话的多个请求之间共享数据,将数据保存到客户端

2.2 快速入门
2.2.1 设置数据到Cookie中
创建cookie对象,设置数据
Cookie cookie = new Cookie(String name,String value);
通过response,响应(返回)cookie
response.addCookie(cookie);
2.2.2 从cookie中获取数据
通过request对象,接收cookie数组
Cookie[] cookies = request.getCookies()
遍历数组
for(Cookie cookie:cookies){
}

浏览器具有自动存储cookie的能力,也有请求携带cookie的能力

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
@WebServlet("/SetServlet")
public class SetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("name","jack");
resp.addCookie(cookie);
}
}

@WebServlet("/GetServlet")
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象,接收cookie数组
Cookie[] cookies = req.getCookies();
if (cookies != null) {
//遍历数组
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println(name+"="+value);
}
}
}
}

2.3 工作原理
基于HTTP协议:请求头cookie和响应头set-cookie

2.4 Cookie细节
2.4.1 服务器如何发送多个Cookie
创建多个cookie对象
Cookie cookie1 = new Cookie(“name”,”rose”);
Cookie cookie2 = new Cookie(“age”,”18”);

通过response响应多个cookie
response.addCookie(cookie1);
response.addCookie(cookie2);

1
2
3
4
5
6
7
8
9
10
11
12
13
@WebServlet("/MultipleCookie")
public class MultipleCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("name", "rose");
Cookie age = new Cookie("age", "18");
resp.addCookie(cookie);
resp.addCookie(age);
}

}
2.4.2 Cookie在浏览器的保存时间
默认情况下,浏览器关闭(会话结束),cookie销毁(浏览器内存中存储)
设置Cookie的存活时间
cookie.setMaxAge(int second);
正数:指定存活时间,持久化浏览器的磁盘中,到期后自动销毁
负数:默认浏览器关闭,cookie销毁
零:立即销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@WebServlet("/MaxAgeCookie")
public class MaxAgeCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("product", "MI");
//设置Cookie的存活时间,默认值-1,关闭自动销毁
// cookie.setMaxAge(-1);
//设定30s,自动销毁
// cookie.setMaxAge(30);
//立即销毁
cookie.setMaxAge(0);
//resp响应Cookie
resp.addCookie(cookie);
}
}

2.4.3 Cookie是否支持中文存储
Tomcat 8版本开始支持中文

但是不支持部分特殊字符,如:分号,空格,逗号等,会触发Rfc6265 CookieProcessor规范错误

建议使用通用方法存储字符
URLEncoder 编码
URLDecoder 解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

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
@WebServlet("/EncodeCookie")
public class EncodeCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String product = ("华为 30X,");
product= URLEncoder.encode("UTF-8");
Cookie cookie = new Cookie("Brand", "苹果");
Cookie cookie1 = new Cookie("product", product);
resp.addCookie(cookie);
}}

@WebServlet("/GetServlet")
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象,接收cookie数组
Cookie[] cookies = req.getCookies();
if (cookies != null) {
//遍历数组
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
//解码
value = URLDecoder.decode("UTF-8");
System.out.println(name + "=" + value);
}
}
}}

2.4.4 Cookie共享数据的范围
2.4.4.1 同一个Tomcat服务器中,部署多个web项目,能否共享Cookie
默认情况下不可以
默认Cookie的携带路径,是当前设置cookie的servlet父路径

设置Cookie:http://localhost:8080/Day36_war_exploded/EncodeCookie
默认携带路径:http://localhost:8080/Day36_war_exploded/

指定Cookie携带路径
cookie.setPath(String Path);
例:cookie.setPath(“/“);

/ 相当于http://localhost:8080/

此cookie携带路径

http://localhost:8080/

访问:

http://localhost:8080/Day36_war_exploded/
http://localhost:8080/Day35_war_exploded/

携带路径不同,可以存储同名的cookie

在当前项目下共享cookie方法
cookie.setPath(“/项目名”);

2.4.4.2 不同Tomcat服务器之间的Cookie能否共享
默认情况下不可以
多个服务器之间的数据共享cookie,需要在同一个一级域名下
cookie.setDomain(“.xx.com”)
2.5 Cookie特点
Cookie存储的数据都在客户端
Cookie存储的数据只能是字符串
Cookie单个大学不能超过4kb
同一个域名下Cookie的数量不能超过50个
Cookie路径不同,可以重名出现
Cookie存储数据不太安全
三.综合案例
3.1 用户上次访问记录
需求:访问一个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

public class CookieUtils {
//根据指定名称,查找cookie对象
public static Cookie findByName(String name, Cookie[] cookies) {
//非空判断
if (cookies != null && cookies.length > 0) {
//遍历
for (Cookie cookie : cookies) {
//判断是否有指定名称的cookie
if (name.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
}
@WebServlet("/LastTimeServlet")
public class LastTimeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
//接收cookie数组,取出指定名称cookie对象
Cookie cookie = CookieUtils.findByName("last_time", req.getCookies());
//判断
if (cookie == null) {
//不存在
resp.getWriter().write("Welcome");
} else {
//存在
String value = cookie.getValue();
resp.getWriter().write("Welcome Back,Last Visit Time:" + value);
}
//创建cookie对象,记录本次访问时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd-HH:mm:ss");
String currentTime = simpleDateFormat.format(new Date());
cookie = new Cookie("last_time", currentTime);
//设置cookie存活1年
cookie.setMaxAge(60*60*24*365);
//resp响应cookie
resp.addCookie(cookie);
}
}

3.2 JSP初体验
Java服务端页面
简单来说:一个特殊的页面,即可定义html标签,又可定义Java代码
作用:简化书写,展示动态页面
本质:Servlet
脚本:JSP通过脚本方式来定义Java代码
<% Java代码 %> 就相当于Servlet中service方法

内置对象:在JSP页面中不需要获取和创建,可以直接使用对象
request
response
out
在JSP中响应内容,使用out
tomcat优先解析response缓冲区内容,再解析out缓冲区内容

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 contentType="text/html;charset=UTF-8" language="java" %>
<html>

<head>
<title>Demo</title>
</head>

<body>

<h3>I am Title</h3>
<table border="1" width="300" align="center">
<tr>
<td>I am static resource</td>


</tr>

</table>
<%
// response.getWriter().write("I am JSP");
System.out.println("I am jsp");
out.write("Out");
%>
</body>
</html>

3.3 商品浏览记录

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
<body>

<h3>List</h3>

<a href="/Day36_war_exploded/GoodsInfoServlet?name=MI">MI</a><br>
<a href="/Day36_war_exploded/GoodsInfoServlet?name=HW">HW</a><br>
<a href="/Day36_war_exploded/GoodsInfoServlet?name=Apple">Apple</a><br>
<a href="/Day36_war_exploded/GoodsInfoServlet?name=TCL">TCL</a><br>
</body>

<body>
<%
//Java Code
//获取指定名称的Cookie对象
Cookie cookie = CookieUtils.findByName("goods_name", request.getCookies());
//判断是否存在浏览记录
if (cookie == null) {
out.write("No History");
} else {
//格式:MI-Apple..
String value = cookie.getValue();
for (String product : value.split("-")) {
out.write(product + "<br/>");
}
}
%>
</body>
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
@WebServlet("/GoodsInfoServlet")
public class GoodsInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求的解码方式
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取请求参数name
String product = req.getParameter("name");
//展示当前商品详情
resp.getWriter().write("It's " + product);
//获取指定名称的Cookie对象
Cookie cookie = CookieUtils.findByName("goods_name", req.getCookies());

if (cookie == null) {
//如果不存在,将当前商品设置到cookie中
cookie = new Cookie("goods_name", product);
} else {
//如果存在,将浏览记录取出
String value = cookie.getValue();
//判断当前商品是否在此Cookie中
List<String> list = Arrays.asList(value.split("-"));
//如果不包含,追加,如果包含,不操作
if (!list.contains(product)) {
value=value+"-"+product;
}
//将value重置到Cookie中
cookie = new Cookie("goods_name", value);
}
//通过response响应到浏览器
cookie.setMaxAge(10);
resp.addCookie(cookie);

//制作a标签,实现继续浏览商品功能
resp.getWriter().write("<br/><a href='/Day36_war_exploded/goods.html'>Continue View</a><br/>");
//制作a标签,实现查看浏览记录功能
resp.getWriter().write("<a href='/Day36_war_exploded/history.jsp'>History</a><br/>");
}
}

一.ServletContext
1.1 概述
ServletContext是一个容器(域对象)可以存储键值对数据(String key,Object value),保存在ServletContext中的 数据不仅可以提供给所有的servlet使用,而且可以在整个项目范围内使用。

它的主要作用有3个:
作为域对象
可以获取当前应用下任何路径下的任何资源
获取初始化参数
获取文件MIME类型

1.2 域对象
说明 API
往servletcontext容器中存入数据,name为数据名称,object为数据的值 void setAttribute(String name,Object object)
从ServletContext中获取数据,根据指定的数据名称 Object getAttribute(String name)
从ServletContext中移除数据,根据指定的数据名称 void removeAttribute(String name)
生命周期
何时创建:项目加载时创建
何时销毁:项目卸载时销毁
作用范围:整个项目(多个Servlet都可以使用它)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@WebServlet(“/OneServlet”)
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //向ServletContext域存储数据
    ServletContext sc1 = req.getServletContext();
    ServletContext sc2 = getServletContext();
    sc1.setAttribute("user","jack");
    resp.getWriter().write("Set Message");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebServlet(“/TwoServlet”)
public class TwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //从ServletContext域存储数据
    String user = (String) req.getServletContext().getAttribute("user");
    resp.getWriter().write("Get Message:"+user);
}

}
1.3 获取资源在服务器的真实地址
可以实现Web项目的移植性,动态获取文件真实路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebServlet(“/RealPath”)
public class RealPath extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取web.xml文件真实路径
    String realPath = req.getServletContext().getRealPath("/WEB-INF/web.xml");
    resp.getWriter().write(realPath);
}

}
1.4 获取全局的配置函数
读取web.xml配置文件中标签,实现参数和代码的解耦(多个Servlet可以获取)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@WebServlet(“/ContextPath”)
public class ContextPath extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取全局参数
    String value = req.getServletContext().getInitParameter("encode");
    System.out.println(value);
    resp.getWriter().write(value);
}

}
1
2
3
4
5

encode UTF-8 1.5 获取文件MIME类型 互联网通信中的一种数据类型 格式:大类型/小类型 例如:text/html image/jpeg

1
Get MIME
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@WebServlet(“/MIMEServlet”)
public class MIMEServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取请求参数
    String filename = req.getParameter("filename");
    //获取指定文件的mime类型
    String mimeType = req.getServletContext().getMimeType(filename);
    resp.getWriter().write(filename+"="+mimeType);
}

}
1.6 案例:统计网站的访问次数
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
@WebServlet(value = “/CountServlet”,loadOnStartup = 4)//服务器启动时,创建此servlet对象
public class CountServlet extends HttpServlet {
@Override
public void init() throws ServletException {
getServletContext().setAttribute(“count”,0);
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //设置response响应编码
    resp.setContentType("text/html;charset=utf-8");
    resp.getWriter().write("<h1>Welcome</h1>");

    //用户每次访问,从域中取出,++再存入
    Integer count = (Integer) req.getServletContext().getAttribute("count");
    count++;
    getServletContext().setAttribute("count", count);

    resp.getWriter().write("<div>You are the "+count+" visitor</div>");
}

}
二.Response
2.1 概述
response对象表示web服务器给浏览器返回的响应信息

作用:开发人员可以使用response对象方法,设置要返回给浏览器的响应信息

Response体系结构

ServletResponse

HttpServletResponse

org.apache.catalina.connector.ResponseFacade 实现类(由Tomcat提供)
2.2 设置Http响应消息
2.2.1 响应行
格式
协议/版本号 状态码
例如
HTTP/1.1 200
API
说明 API
设置状态码 void setStatus()
2.2.2 响应头
格式
响应头名称:响应头的值
例如
Location:http://www.oracle.com
API
说明 API
设置指定头名称和对应的值 void setHeader(String name,String vale);
2.2.3 响应体
API(输出流对象)
说明 API
字符输出流 PrintWriter getWriter()
字节输出流 ServletOutputStream getOutputStream()
注意:在同一个Servlet中,不能同时存在两种流,互斥

2.3 响应重定向
2.3.1 重定向特点
地址栏会发生改变
重定向是二次请求
重定向是客户端(浏览器)行为,可以跳转到服务器外部资源
不能使用request域共享数据
2.3.2 方式一
说明 API
设置状态码 response.setStatus(302)
设置响应头Location response.setHeader(“Location”,”重定向网络地址”);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebServlet(“/AServlet”)
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("AServlet Run");
   resp.setStatus(302);
   resp.setHeader("Location","/Day35_war_exploded/BServlet");
}

}
1
2
3
4
5
6
7
8
9
10
11
12
@WebServlet(“/BServlet”)
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("Bservlet Run");
}

}
2.3.3 方式二
说明 API
response专门处理重定向的方法 response.sendRedirect(“重定向网络地址”)
1
2
3
4
5
6
7
8
9
10
11
12
13
@WebServlet(“/AServlet”)
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("AServlet Run");
    resp.sendRedirect("http://www.baidu.com");
}

}
2.3.4 转发与重定向区别
哪个对象
API
转发(request对象的方法) request.getRequestDispatcher(“/bServlet”).forward(request,response);
重定向(response对象的方法) response.sendRedirect(“/Day35_war_exploded/bServlet”);
几次请求
转发 重定向
地址栏 没有改变 发生了改变
浏览器 发了一次请求 发了两次请求
服务器 只有一对请求和响应对象 有两对请求和响应对象
发生的位置 服务器 浏览器
小结
写法 说明
转发 (“/servlet资源路径”) 服务器内部行为
重定向 (“/虚拟路径(项目名)/servlet资源路径”) 浏览器外部行为
使用场景

使用场景 说明
如果需要传递数据(request域) 使用转发
如果不需要传递数据(request域) 使用重定向
2.4 响应定时刷新
说明 API
通过response设置响应头Refresh response.setHeader(“Refresh”,”间隔时间(秒);跳转页面”)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebServlet(“/RefreshServlet”)
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setHeader("Refresh","3;http://www.baidu.com");
    resp.setContentType("text/html;charset=utf-8");
    resp.getWriter().write("Success,Redirect After 3 seconds");
}

}
2.5 响应中文
步骤:

说明 API
统一服务器编码:指定服务器响应编码方式 resp.setContentType(“text/html;charset=utf-8”);
通过response获取字符输出流 PrintWriter pw = response.getWriter();
通过字符输出流输出文本 pw.write()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebServlet(“/EncodeServlet”)
public class EncodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //可以解决客户端中文乱码,但是编码不统一

// resp.setCharacterEncoding(“GBK”);
resp.setContentType(“text/html;charset=utf-8”);
// PrintWriter pw = resp.getWriter();
// pw.write(“中文”);

    //链式编程
    resp.getWriter().write("中文");
}

}
综合案例
3.1 点击切换验证码
在页面展示登陆验证码,点击可以更换新验证码
作用:防止表单的恶意提交
本质:图片
1
2
3
4
5
6
7
8

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
@WebServlet(“/CheckCodeServlet”)
public class CheckCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 创建画布
int width = 120;
int height = 40;
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获得画笔
Graphics g = bufferedImage.getGraphics();
// 填充背景颜色
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 绘制边框
g.setColor(Color.red);
g.drawRect(0, 0, width - 1, height - 1);
// 生成随机字符
// 准备数据
String data = “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890”;
// 准备随机对象
Random r = new Random();
// 声明一个变量 保存验证码
String code = “”;
// 书写4个随机字符
for (int i = 0; i < 4; i++) {
// 设置字体
g.setFont(new Font(“宋体”, Font.BOLD, 28));
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

        String str = data.charAt(r.nextInt(data.length())) + "";
        g.drawString(str, 10 + i * 28, 30);

        //  将新的字符 保存到验证码中
        code = code + str;
    }
    //  绘制干扰线
    for (int i = 0; i < 6; i++) {
        //  设置随机颜色
        g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));

        g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
    }

    //  将验证码 打印到控制台
    System.out.println(code);

    //  将验证码放到session中
    req.getSession().setAttribute("code_session", code);

    //  将画布显示在浏览器中
    ImageIO.write(bufferedImage, "jpg", resp.getOutputStream());
}

}
3.2 文件下载
用户点击页面的链接,浏览器开始下载文件。
3.2.1 使用链接下载文件
1
Download_XML

缺点
浏览器可识别的媒体类型,是直接打开而不是下载
不能判断用户是否登录(vip),进行限制

3.2.2 使用Servlet下载文件
二个响应头二个字节流

说明 API
被下载文件的字节输入流 FileInputStream
response字节输出流 response字节输出流
告知客户端下载文件的MIME类型 Content-Type:MIME类型
告知浏览器以附件的方式保存 Content-Disposition:attachment;filename=文件名
1
Download_XML

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
@WebServlet(“/DownloadServlet”)
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取文件名
    String filename = req.getParameter("filename");
    //获取文件真实路径,封装字节输入流
    ServletContext servletContext = req.getServletContext();
    String realPath = servletContext.getRealPath("/download/" + filename);
    FileInputStream in = new FileInputStream(realPath);

    //告诉浏览器下载文件MIME类型 Content-Type
    String mimeType = servletContext.getMimeType(filename);
    resp.setContentType(mimeType);

    //告知浏览器以附件的方式保存 Content-Disposition:attachment;filename=文件名
    //解决中文乱码和浏览器兼容性
    String userAgent = req.getHeader("user-agent");
    //调用工具处理
    filename=DownLoadUtils.getName(userAgent,filename);
    resp.setHeader("content-disposition", "attachment;filename=" + filename);

// resp.setHeader(“Content-Disposition”, “attachment;filename=” + filename);
//获取response的字节输出流
ServletOutputStream out = resp.getOutputStream();
//IO流Copy
// byte[] bys = new byte[1024];
// int len = 0;
// while ((len = in.read(bys)) != -1) {
// out.write(bys, 0, len);
// }
IoUtil.copy(in,out);
//释放资源
out.close();//可以交给Tomcat关闭
in.close();
}
}
中文乱码问题
如果该下载文件名是中文的话,会出现乱码…
谷歌和绝大多数的浏览器是通过 url编码
URLEncode() 编码
URLDecode() 解码
火狐浏览器 base64编码
如下工具包解决乱码问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class DownLoadUtils {

public static String getName(String agent, String filename) throws UnsupportedEncodingException {
    if (agent.contains("Firefox")) {
        // 火狐浏览器
        BASE64Encoder base64Encoder = new BASE64Encoder();
        filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
    } else {
        // 其它浏览器
        filename = URLEncoder.encode(filename, "utf-8");
    }
    return filename;
}

}
3.2.2.1 hutool工具包
官网:https://www.hutool.cn/

hutool-all-5.2.3.jar
总结
一 ServletContext
概述
代表当前web项目对象
主要作用
共享数据(域对象)

获取资源文件在服务器上真实路径

获取全局的配置参数

web.xml中配置
获取文件MIME类型

互联网传输数据时,识别文件的类型
案例:统计网站的访问次数
二 Response
概述
开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息
Response设置响应消息
设置响应行

void setStatus(int sc)
设置响应头

void setHeader(String name, String value)
设置响应体

ServletOutputStream getOutputStream() 字节输出流
PrintWriter getWriter() 字符输出流
响应重定向
转发与重定向的区别

转发

地址栏: 没有改变
浏览器: 发了一次请求
服务器: 只有一对请求和响应对象
发生的位置: 服务器
重定向

地址栏: 发生了改变
浏览器: 发了两次请求
服务器: 有两对请求和响应对象
发生的位置: 浏览器
响应定时刷新
响应中文
response.setContentType(“text/html;charset=utf-8”);
三 综合案例
点击切换验证码
随机数欺骗浏览器
文件下载
解决了中文编码
hutool工具包

一.Request概述
用户通过浏览器访问服务器时,Tomcat将HTTP请求中所有信息封装在Request对象中
作用:开发人员可以通过Request对象方法,来获取浏览器发送的所有信息

Request体系结构

ServletRequest

HttpServletRequest

org.apache.catalina.connector.RequestFacade(由tomcat厂商提供实现类)
二.Request获取Http请求信息
2.1 获取请求行信息
例如:
GET /Day34_Request_war_exploded/RequestDemo01 HTTP/1.1
相关API:
说明
API
获取请求方式 String getMethod()
获取项目虚拟路径名 String getContextPath()
获取URI
(统一资源标识符) String getRequestURI()
获取URL
(统一资源定位符) StringBuffer getRequestURL()
获取协议和版本号 String getProtocol()
获取客户端IP String getRemoteAddr()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@WebServlet("/RequestDemo01")
public class RequestDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println(req);
//1.获取请求方式
System.out.println("Request Method "+req.getMethod());
//2.获取项目路径
System.out.println("Project Path "+req.getContextPath());
//3.获取URI
System.out.println("URI "+req.getRequestURI());
//4.获取URL
System.out.println("URI "+req.getRequestURL());
//5.协议和版本
System.out.println("Protocol & Version "+ req.getProtocol());
//6.客户端IP
System.out.println("IP "+ req.getRemoteAddr());}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

//输出
Request Method: GET
Project Path: /Day34_Request_war_exploded
URI: /Day34_Request_war_exploded/RequestDemo01
URL: http://127.0.0.1:8080/Day34_Request_war_exploded/RequestDemo01
Protocol & Version: HTTP/1.1
IP: 127.0.0.1
2.2 获取请求头信息
例如:

Host:locaohost:8080

相关API

说明
API
获取请求头名称对应的值 String getHeader(String name)
获取所有请求头的名称 Enumeration getHeaderNames()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebServlet("/RequestDemo02")
public class RequestDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有请求头名称
Enumeration<String> headerNames = req.getHeaderNames();
//遍历
while (headerNames.hasMoreElements()){
//取出元素名(请求头名称)
String name = headerNames.nextElement();
//根据名称获取值
String value = req.getHeader(name);
System.out.println(value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

案例:模拟视频防盗链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@WebServlet("/RefereRequest")
public class RefereRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//0.设置编码,让中文不乱码
resp.setContentType("text/html;charset=UTF-8");
//1.获取请求来源(如果是浏览器地址栏直接访问,referer是Null)
String referer = req.getHeader("referer");
//2.判断是否自己网站发起的请求
if(referer != null && referer.startsWith("http://127.0.0.1:8080")){
resp.getWriter().write("Play Video");
}else {
resp.getWriter().write("Permission Denied");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

案例:浏览器兼容性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@WebServlet("/UserAgentRequest")
public class UserAgentRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//0.设置语言编码
resp.setContentType("text/html;charset=UTF-8");
//1.获取浏览器版本信息
String useragent = req.getHeader("user-agent");
//2.判断浏览器版本
System.out.println(useragent);
if (useragent.contains("Chrome")){
System.out.println("Chrome");
}else if (useragent.contains("Firefox")){
System.out.println("Firefox");
}else {
System.out.println("Others");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

2.3 获取请求参数(请求体)
不论是get还是post请求方式,都可以使用下列方式来获取请求参数
参数:
username=jack&password=123
说明
API
获取指定参数名的值 String getParameter(String name);
获取指定参数名的值数组 String[] getParameterValues(String name);
获取所有参数名和对应值数组 Map<String,String[]> getParameterMap()
中文乱码
get:在Tomcat 8 及以上版本,内部URL编码(UTF-8)
post:编码解码不一致,造成乱码现象
客户端(浏览器)编码UTF-8
服务器默认解码:ISO-8859-1
指定解码:void setCharacterEncoding(String env)
注意:指定解码必须在行首

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

@WebServlet("/RequestDemo03")
public class RequestDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Get manually
// String username = req.getParameter("username");
// System.out.println(username);
// String password = req.getParameter("password");
// System.out.println(password);
// String[] hobbies = req.getParameterValues("hobby");
// System.out.println(Arrays.toString(hobbies));
//Automatic acquisition
Map<String, String[]> parameterMap = req.getParameterMap();
parameterMap.forEach((k, v) -> {
System.out.println(k + "" + Arrays.toString(v));
});
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
//使用方法一样,可以直接调用get方法
this.doGet(req, resp);
}
}

2.4 BeanUtils
Apache提供的工具类,简化参数封装,即将前端数据直接封装到想要的JavaBean中

导入Jar包

使用工具类封装数据(要求:map集合的key,必须为JavaBean属性名)

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
public class User {
private String username;
private String password;
private String[] hobby;

// 此处省略getter setter toString

@WebServlet("/RequestDemo04")
public class RequestDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Get manually
String username = req.getParameter("username");
System.out.println(username);
String password = req.getParameter("password");
System.out.println(password);
String[] hobbies = req.getParameterValues("hobby");
//Automatic acquisition
Map<String, String[]> parameterMap = req.getParameterMap();
parameterMap.forEach((k, v) -> {
System.out.println(k + "" + Arrays.toString(v));
});
//将前端表单数据赋值到user对象中,保存到数据库
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setHobby(hobbies);
System.out.println(user);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
//使用方法一样,可以直接调用get方法
this.doGet(req, resp);

//使用BeanUtils快速封装数据到User对象中
//map集合的key,必须为JavaBean属性名
Map<String, String[]> parameterMap = req.getParameterMap();
//
User user = new User();
try {
BeanUtils.populate(user, parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(user);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<h3>Bean Utils:</h3>
<form action="/Day34_Request_war_exploded/RequestDemo04" method="post">
Name:
<input type="text" name="username"><br>
Password:
<input type="password" name="password"><br>
Hobby:
<input type="checkbox" name="hobby" value="smoke">smoke
<input type="checkbox" name="hobby" value="drink">drink
<input type="checkbox" name="hobby" value="perm">perm<br>
<input type="submit" value="Post Submit Method">
</form>

2.4.1 变量名是否等于属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//成员变量名username
private String username;


//属性Username,是方法的命名
public String getUsername() {
return username;
}

//属性是getter/setter方法截取之后的产物
//通常情况下,使用IDEA自动生成getter&setter时,变量名 equals 属性
getUsername-Username-username

//不一样的情况
//成员变量名
private String user;
//属性名
public String getUsername() {
return user;
}

三.Request其他功能
3.1 请求转发
一种在服务器内部的资源跳转方式
说明
API
通过request对象,获得转发器对象 RequestDispatcher getRequestDispatcher(String path);
通过转发器对象,实现转发功能 void forward(ServletRequest request,ServletResponse response);
请求转发的特点:
浏览器:只发了一次请求
地址栏:没有改变
只能转发到服务器内部资源

链式编程
request.getRequestDispatcher(“/bServlet”).forward(reqeust,response)
3.2 域对象(共享数据)
域对象:一个有作用访问的对象,可以在范围内共享数据

request域:代表一次请求范围,一般用于一次请求中转发的多个资源中共享数据

说明
API
设置数据 void setAttribute(String name,Object o);
获取数据 Object getAttribute(String name)
删除数据 void removeAttribute(String name)
生命周期

创建时间 用户发送请求时,发送request
销毁时间 服务器返回响应时,销毁request
作用范围 一次请求,包含多次转发

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

@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//转发到BServlet
//1.获取转发器对象 path=@WebServlet("/BServlet")
// RequestDispatcher requestDispatcher = req.getRequestDispatcher("/BServlet");
//2.实现转发功能
// requestDispatcher.forward(req,resp);
//AServlet存一个数据
req.setAttribute("name","This is A Object");

//链式编程
req.getRequestDispatcher("/BServlet").forward(req,resp);
}
}

@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("B");
String name = (String) req.getAttribute("name");
resp.getWriter().write(name);
}
}

3.3 获取ServletContext对象
应用上下文对象,表示一个web项目
通过request,可以获取ServletContext对象
public ServletContext getServletContext();

1
2
3
4
5
6
7
8
9
10
11
@WebServlet("/RequestDemo05")
public class RequestDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取当前web项目对象
ServletContext servletContext = req.getServletContext();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}

四.用户登陆案例
实现用户的登录功能
登录成功跳转到SuccessServlet展示:登录成功!xxx,欢迎您
登录失败跳转到FailServlet展示:登录失败,用户名或密码错误

创建web项目,导入BeanUtils(工具类)
编写index.html
User实体类
创建LoginServlet,SuccessServlet,FailedServlet

1
2
3
4
5
<form action="/Day34_Request_war_exploded/loginServlet" method="post">Login
Name:<input type="text" name="username"><br>
Password:<input type="password" name="password"><br>
<input type="submit" value="Login Submit">
</form>
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
public class User {
private String username;
private String password;
//此处getter & setter ,toString省略
}


@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.设置request解码方式
req.setCharacterEncoding("UTF-8");
//2.获取浏览器参数,map集合
Map<String, String[]> parameterMap = req.getParameterMap();
//3.使用BeanUtils工具类,封装到User中
User user = new User();
try {
BeanUtils.populate(user, parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

//4.判断(写一个file文件,存储真实到用户名密码,判断)
if ("jack".equals(user.getUsername()) && "123".equals(user.getPassword())){
req.setAttribute("user",user);
req.getRequestDispatcher("/successServlet").forward(req, resp);
}else{
req.getRequestDispatcher("/failedServlet").forward(req, resp);
}
}
}


@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.从request域获取user对象
User user = (User) req.getAttribute("user");
//2.提示
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write(user.getUsername()+"Successful");
}
}
@WebServlet("/failedServlet")
public class FailedServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("Login Failed,Wrong Username or Password");
}
}

附录:Servlet模版设置
IDEA-Settings-Editor-File and Code Templates-Other-Web>Jaava code templates>Servlet Annotated Class.java
更改为如下代码

1
2
3
4
5
6
7
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") @javax.servlet.annotation.WebServlet("/${Class_Name}")
public class ${Class_Name} extends javax.servlet.http.HttpServlet {
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
this.doPost(request,response); }
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {

} }

总结
一 Request概述
开发人员可以通过request对象方法,来获取浏览器发送的所有信息.
二 Request获取Http请求信息

getMethod()

请求方式

get
post
getContextPath()

项目名(虚拟路径)
getRemoteAddr()

客户端的ip地址

getHeader(String key)

Referer

防盗链
User-Agent

浏览器兼容器
getHeaderNames()

参数(体)
api

getParameter()
getParameterValues()
getParameterMap()
BeanUtils工具类

中文乱码

get:tomcat8及以上版本,解决了get方式乱码问题
post:request.setCharacterEncoding(“utf-8”);
三 Request其他功能
请求转发
一种在服务器内部的资源跳转方式

request.getRequestDispatcher(“/内部资源”).forward(request,response);

特点

转发是一次请求
浏览器地址栏不发生变化
只能跳转到服务器内部资源
域对象(共享数据)
api

void setAttribute(String name, Object o)
Object getAttribute(String name)
void removeAttribute(String name)
生命周期

何时创建

用户发送请求时
何时销毁

服务器做出响应后
作用范围

一次请求转发中
获取ServletContext
api

ServletContext getServletContext()

一.Servlet概述
Servlet 运行在服务端的Java小程序,是sun公司提供一套规范,用来处理客户端请求、响应给浏览器的动态资源。
但servlet的实质就是java代码,通过java的API动态的向客户端输出内容

servlet= server+applet 运行在服务器端的java程序。
Servlet是一个接口,一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口
二.Servlet快速入门
2.1 代码编写
创建web项目

编写普通java类,实现Servlet接口
写抽象方法(service方法)

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

public class QuickServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {}

@Override
public ServletConfig getServletConfig() {
return null;
}

//对外提供服务
/*
request:代表请求
response:代表响应
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//向浏览器写一句话
servletResponse.getWriter().write("QuickServlet");
}

//表示当前Servlet对象的描述信息
@Override
public String getServletInfo() {
return "快速入门";
}

@Override
public void destroy() {

}}

配置web.xml
配置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
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--
把QuickServlet交给tomcat管理
servlet-name:当前servlet的别名(使用类名即可)
servlet-class:全限定类名
-->
<servlet>
<servlet-name>QuickServlet</servlet-name>
<servlet-class>Project.QuickServlet</servlet-class>
</servlet>
<!--
给servlet社长一个网络访问地址(路径)
servlet-name:给指定别名的servlet配置映射
url-pattern:网络访问地址(注意:必须以"/"开头)
-->
<servlet-mapping>
<servlet-name>QuickServlet</servlet-name>
<url-pattern>/QuickServlet</url-pattern>
</servlet-mapping>
</web-app>

部署web项目
启动测试
2.2 执行原理
步骤:
Step 1: Browser通过 Domain 在网络中Request到该 Server(Tomcat)
Step 2: 找到该Server后,通过Project Name查找项目(Day32_Servlet_XML)
Step 3: 通过Source Name(QuickServlet)查找web.xml中同名的url-pattern标签
Step 4: 找到url-pattern同名标签后,查找其映射的servlet-name
Step 5: 通过servlet-name寻找servlet-class
Step 6: 通过反射机制创建QuickServlet
Step 7: 创建后,自动调用service方法,Response to Browser

三.Servlet相关API
3.1 生命周期相关
3.1.1 思想介绍
生命周期:指的是一个对象从创建到销毁到过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//servlet对象创建时,调用此方法
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("LifeServlet Created");
}

//用户访问servlet时,调用此方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("LifeServlet carried out");
}

//servlet对象销毁时,调用此方法
@Override
public void destroy() {
System.out.println("LifeServlet destroy");
}

创建

1)默认
用户第一次访问时,创建servlet,执行init方法
2)修改servlet创建时机

值 说明
正数 服务器启动时创建
(Tomcat默认1-3,建议4开始)
负数(默认值):-1 用户第一次访问时创建
运行

第二次开始,都调用执行service方法

销毁

服务器正常关闭时,销毁servlet,执行destroy方法

3.1.2 代码演示
LifeServlet

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
public class LifeServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("LifeServlet Created");
}

@Override
public ServletConfig getServletConfig() {
return null;
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("LifeServlet carried out");
}

@Override
public String getServletInfo() {
return null;
}

@Override
public void destroy() {
System.out.println("LifeServlet destroy");
}
}

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
<!--
servlet生命周期
-->
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>Project.Demo02.LifeServlet</servlet-class>
<load-on-startup>4</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/LifeServlet</url-pattern>
</servlet-mapping>

3.2 拓展:ServletConfig接口
Tomcat在Servlet对象创建时,执行init()方法,并创建一个ServletConfig配置对象

主要作用:读取web.xml配置文件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
public class EncodingServlet implements Servlet {
//定义全局变量
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
}

@Override
public ServletConfig getServletConfig() {
return servletConfig;
}

//用户访问,执行service方法
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
// String encode = "UTF-8";
// servletResponse.getWriter().write(encode);
String encode = getServletConfig().getInitParameter("encode");
servletResponse.getWriter().write(encode);
}
@Override
public String getServletInfo() {
return null;
}

@Override
public void destroy() {

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--servlet配置对象-->
<servlet>
<servlet-name>EncodingServlet</servlet-name>
<servlet-class>Project.Demo02.EncodingServlet</servlet-class>
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>EncodingServlet</servlet-name>
<url-pattern>/EncodingServlet</url-pattern>
</servlet-mapping>

四.Servlet体系结构
Servlet
顶级接口,提供了5个抽象方法

GenericServlet 抽象类,重写绝大多数的抽象方法,只需要开发者重写service方法

HttpServlet 抽象类,处理Http协议的交互信息(请求,响应),根据不同的请求方式作出不同的处理
4.1 GenericServlet
编写普通Java类继承GenericServlet抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ServletDemo01 extends GenericServlet {
@Override
public void init() throws ServletException {
System.out.println("ServletDemo01 Created");
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
super.getServletConfig();//调用父类的配置对象
servletResponse.getWriter().write("ServletDemo01 extends GenericServlet");
}

@Override
public void destroy() {
System.out.println("ServletDemo01 Destroyed");
}
}

配置web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--servlet继承GenericServlet-->
<servlet>
<servlet-name>ServletDemo01</servlet-name>
<servlet-class>Project.Demo03_inherit.ServletDemo01</servlet-class>
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo01</servlet-name>
<url-pattern>/ServletDemo01</url-pattern>
</servlet-mapping>

4.2 HttpServlet
编写前端HTML页面提交表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>


<body>
<h3>Login</h3>
<form action="http://localhost:8080/Day33_Servlet_war_exploded/ServletDemo02" method="get">
<input type="submit" value="Update Form">
</form>

</body>
</html>

编写普通java类,继承HttpServlet抽象类

1
2
3
4
5
6
7
8
9
10
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Get");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Post");
}
}

配置web.xml

1
2
3
4
5
6
7
8
9
<!--servlet继承HttpServlet-->
<servlet>
<servlet-name>ServletDemo02</servlet-name>
<servlet-class>Project.Demo03_inherit.ServletDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo02</servlet-name>
<url-pattern>/ServletDemo02</url-pattern>
</servlet-mapping>

4.3 Http错误
响应状态码405
方法没有重写,父类抛出405
例:
ServletDemo02 extends HttpServlet 没有重写get方法,而form使用get方法,则抛出父类405错误

1
2
3
4
5
6
7
8
9
10
//父类方法
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}

响应状态码500
Java代码写错了

五.Servlet路径
5.1 url-patterns
作用:讲一个请求的网络地址和servlet建立一个映射关系

5.1.1 Servlet映射多个路径

1
2
3
4
5
6
7
8
9
10
11

public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo3 Get Method Run");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo3 Post Method Run");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--    一个Servlet类可以映射多个网络访问地址        -->
<servlet>
<servlet-name>ServletDemo03</servlet-name>
<servlet-class>Project.Demo04_URL_Partten.ServletDemo03</servlet-class>
</servlet>
<!-- 映射地址一 -->
<servlet-mapping>
<servlet-name>ServletDemo03</servlet-name>
<url-pattern>/ServletDemo03</url-pattern>
</servlet-mapping>
<!-- 映射地址二 -->
<servlet-mapping>
<servlet-name>ServletDemo03</servlet-name>
<url-pattern>/Demo03</url-pattern>
</servlet-mapping>

5.1.2 url映射模式
配置url地址取值可以是:

精确匹配

1
2
3
4
5
6
7
8
9
10
11

public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo4 Get Method Run");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo4 Post Method Run");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<!--目录的匹配规则
只要浏览器符合规则:/aa/xxx
都访问ServletDemo04
-->
<servlet>
<servlet-name>ServletDemo04</servlet-name>
<servlet-class>com.test.Demo04_URL_Partten.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo04</servlet-name>
<url-pattern>/aa/*</url-pattern>
</servlet-mapping>

后缀匹配
*.xxx

例如:*.do

1
2
3
4
5
6
7
8
9
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo5 Get Method Run");
}@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("ServletDemo5 Post Method Run");
}
}
1
2
3
4
5
6
7
8
9
<!-- 只要浏览器符合后缀匹配规则,都可以访问到这个servlet-->
<servlet>
<servlet-name>ServletDemo05</servlet-name>
<servlet-class>com.test.Demo04_URL_Partten.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo05</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

5.2 相对/绝对路径
浏览器的地址栏
a标签的href属性
form表单的action属性
js的location.href属性
ajax请求地址

//访问地址:http://localhost:8080/projectname/static/Path.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
<html>
<head>
<meta charset="UTF-8">
<title>Path</title>
</head>
<body>

<h3>Text Interview Path</h3>

<h4>绝对路径</h4>

<!--
在开发时,强烈建议使用绝对路径
完整:protocol://domain:port/project/SourceName
推荐:/项目名/资源名
-->
<a href="http://localhost:8080/Day33_Servlet_war_exploded/QuickServlet">
带HTTP协议的绝对路径:QuickServlet
</a><br/>

<a href="/Day33_Servlet_war_exploded/QuickServlet">不带HTTP协议的绝对路径:QuickServlet</a>
<br/>

<h4>相对路径</h4>

<!--
相对路径语法:
./当前目录
../上级目录
-->
<a href="../QuickServlet">相对路径:QuickServlet</a>

</body>
</html>

六.Servlet3.0
通过注解配置Servlet,简化web.xml配置Servlet复杂性,提高开发效率,集合所有框架都使用注解

创建web项目
编写普通Java类继承HttpServlet抽象类
配置@WebServlet

1
2
3
4
5
6
7
8
9
@WebServlet("/QuickServlet")
public class QuickServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Quick Servlet 3.0 Get Method");
}@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Quick Servlet 3.0 Post Method");
}}

总结
一 Servlet概述
运行在服务器端的java程序
一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口
二 Servlet快速入门
① 创建web项目
② 创建普通的java类,实现servlet接口,重写抽象方法
③ 配置web.xml
④ 部署web项目
⑤ 启动测试
三 Servlet相关API
生命周期相关
创建

1)默认情况下,用户第一次访问时创建,执行init方法,只创建一次
2)修改创建时机,在tomcat启动时,创建servlet,执行init方法,只创建一次
运行(提供服务)

用户访问servlet资源时,执行service方法
销毁

服务器正常关闭,销毁servlet,执行destroy方法
ServletConfig接口
加载web.xml配置文件信息,实现参数和代码的解耦
四 Servlet体系结构
Servlet
GenericServlet

HttpServlet
五 Servlet路径
url-pattern
Servlet映射多个url

url映射模式

精确匹配
目录匹配
后缀匹配
相对/绝对路径
绝对路径…
六 Servlet3.0
@WebServlet(“/网络访问地址”)

一.Web知识概述
JavaWeb:将编写好的代码,发布到互联网,可以让所有用户访问

1.1 软件架构
•网络中有很多的计算机,它们直接的信息交流,我们称之为:交互
•在互联网交互的过程的有两个非常典型的交互方式——B/S 交互模型(架构)和 C/S 交互模型(架构)

C/S架构

Client/Server 客户端/服务器
访问服务器资源必须安装客户端软件
优点:用户体验好
缺点:开发(客户端,服务器),部署和维护繁琐

B/S架构

Browser/Server 浏览器/服务器
访问服务器资源不需要专门安装客户端软件,而是直接通过浏览器访问服务器资源.
优点:开发、部署,更新简单
缺点:用户体验差

C/S架构也是一种特殊的B/S架构

1.2 Web服务器作用
开发者通过web服务器可以把本地资源发布到互联网
用户就可以通过浏览器访问这些资源
1.3 资源的分类
资源:计算机中数据文件

静态资源
对于同一个页面,不同用户看到的内容是一样的。
例如:体育新闻、网站门户等,常见后缀: .html、.js、*.css

动态资源 用对于同一个页面,不同用户看到的内容可能不一样。
例如:购物车、我的订单等,常见后缀: .jsp、.aspx、*.php

1.4 常见的Web服务器
Tomcat: Apache组织开源免费的web服务器,支持JavaEE规范(Servlet/Jsp).
Jetty:Apache组织开源免费的小型web服务器,支持JavaEE规范.
JBoss: RedHat红帽公司的开源免费的web服务器,支持JavaEE规范.
Glass Fish:Sun公司开源免费的web服务器,支持JavaEE规范.
WebLogic: Oracle公司收费的web服务器,支持JavaEE规范.
WebSphere:IBM公司收费的web服务器,支持JavaEE规范.
JavaEE规范
在Java中所有的服务器厂商都要实现一组Oracle公司规定的接口,这些接口是称为JavaEE规范。不同厂商的JavaWeb服务器都实现了这些接口,在JavaEE中一共有13种规范。实现的规范越多,功能越强。
二.Tomcat服务器
2.1 Tomcat使用
2.1.1 下载
Tomcat 官网下载地址:https://tomcat.apache.org/download-80.cgi

2.1.2 安装
解压即用

2.1.3 目录结构
ls -F | grep “/

目录 说明
bin/ 启停命令
conf/ 配置文件
lib/ 运行时所依赖的jar包
logs/ 运行日志
temp/ 缓存
webapps/ 发布自己的网站目录
work/ 存放编译生产的.java与.class文件
cd webapps/

目录 说明
docs tomcat的帮助文档
examples web应用实例
host-manager 主机管理
manager 主机管理
ROOT 说默认站点根目录明
[root@localhost webapps]# cd ../conf/

目录 说明
Catalina
catalina.policy
catalina.properties
context.xml
logging.properties
logs
server.xml tomcat 主配置文件
tomcat-users.xml tomcat 管理用户配置文件
tomcat-users.xsd
web.xml
ls -l | grep ^- | awk ‘{print $9}’

文件 说明
BUILDING.txt
CONTRIBUTING.md
LICENSE
NOTICE
README.md
RELEASE-NOTES
RUNNING.txt
2.1.4 启动和关闭
cd apache-tomcat-8.5.54/bin
chmod +x *.sh
./startup.sh
./shutdown.sh

2.1.5 启动报错问题
Java环境变量

解决方法:
配置JAVA_HOME

8080端口被占用
启动时报错

解决方式一:kill pid
netstat -anpl | grep ‘8080’

解决方式二:修改Tomcat端口号
进入Tomcat安装目录/conf/server.xml 文件修改
cat server.xml| grep ‘Connector port’
Connector port=”8080”

如果要启动多个tomcat,需要修改三个端口
2.1.6 发布项目的三种方式
webapps部署
直接放置在 webapps 目录下
cp -r myapp tomcat/webapps
这种方案,一般在开发完毕后使用

server.xml部署不建议使用
在tomcat/conf/server.xml中找到标签,添加标签

1
2

 <Context path="myapp" docBase="apache-tomcat-8.5.54/webapps/myapp"/>

缺点:

I.配置文件修改完后,需要重启才生效
II.server.xml是tomcat核心配置文件,如果操作错误会导致tomcat启动失败

独立xml部署
在tomcat/conf/Catalina/localhost 目录下创建一个xml文件,添加标签

myapp.xml
文件名就是虚拟路径
localhost:8080/myapp/index.html

1
2

2.2 Web项目结构 前端项目

1
2
3
4
5
6
|– myapp(项目名称)
|– css 目录
|– js 目录
|– html目录
|– img 目录
|– index.html
Web项目

1
2
3
4
5
6
7
|– myapp(项目名称)
|– 静态资源目录(html,css,js,img)
|– WEB-INF 目录 (浏览器无法直接访问内部资源)
|– classes 目录(java字节码文件)
|– lib 目录 (当前项目所需要的第三方jar包)
|– web.xml 文件 (当前项目核心配置文件,servlet3.0可以省略)
|– index.html or index.jsp
2.3 IDEA中使用Tomcat
2.3.1 配置Tomcat
IDEA->Edit Configuration->在Application server添加Tomcat解压的路径即可

2.3.2 创建Web项目
IDEA->New Moudle->左侧选Java Enterprise->右侧选Moudle SDK选1.8,JAVAEE Version选JAVAEE 7,Application Server选tomcat,下拉列表勾选Web Application并勾选创建web.xml,下一步即可

2.3.3 发布Web页面
IDEA->选择Edit Configurations->进入Deployment指定context(新版本会默认生成)

2.3.4 页面资源热更新
IDEA->选择Edit Configurations->On ‘Update’ action 和On frame deactivation都选择Update resources

注意:WEB-INF动态资源是无法被浏览器直接访问的,会出现404错误

三.Http协议
3.1 Http协议概述
超文本传输协议(Hyper Text Transfer Protocol)是互联网上应用最为广泛的一种网络协议。
传输协议:在客户端和服务器端通信时,规范了传输数据的格式
HTTP协议特点:
I.基于TCP协议
II.默认端口80
III.基于请求/响应模型
IV.无状态协议(多次请求之间都是独立,不能交互数据)

HTTPS协议:
本质就是HTTP,对通信对数据进行加密
默认端口号443

3.2 Http请求
3.2.1 浏览器查看Http请求协议
get方式(查看Inspect-Network-Request Headers)
请求行 GET /Day32_Tomcat/web/index.html?username=jack&password=123 HTTP/1.1
请求头 Host: localhost:63343
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36 Edg/80.0.361.109
Sec-Fetch-Dest: document
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Referer: http://localhost:63343/Day32_Tomcat/web/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh,en-CN;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: Idea-b40ac89=cb70dd01-3e65-4870-9e53-e3ad801dd2b0;
If-Modified-Since: Mon, 13 Apr 2020 10:05:39 GMT
post方式(查看Inspect-Network-Request Headers)
请求头 POST /Day32_Tomcat/web/index.html?username=jack&password=123 HTTP/1.1
请求行 Host: localhost:63343
Connection: keep-alive
Content-Length: 26
Cache-Control: max-age=0
Origin: http://localhost:63343
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36 Edg/80.0.361.109
Sec-Fetch-Dest: document
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Referer: http://localhost:63343/Day32_Tomcat/web/index.html?username=jack&password=123
Accept-Encoding: gzip, deflate, br
Accept-Language: zh,en-CN;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: Idea-b40ac89=cb70dd01-3e65-4870-9e53-e3ad801dd2b0;
请求体
(位于Form Data) username=jack&password=123
3.2.2 HTTP请求消息格式
3.2.2.1 请求行
格式
请求方式 请求路径 协议/版本号
例如
POST /Day32_Tomcat/web/index.html?username=jack&password=123 HTTP/1.1
GET /Day32_Tomcat/web/index.html?username=jack&password=123 HTTP/1.1

请求方式区别
get
1.请求参数在地址栏显示(请求行)
2.请求参数大小有限制
3.数据不太安全

post
1.请求参数不在地址栏显示(请求体)
2.请求参数大小没有限制
3.数据相对安全
3.2.2.2 请求头
格式
请求头名称:请求头的值
例如
Host: localhost:8080
常见请求头:Accept开头的,都是浏览器告诉服务器的一些暗语

Host: 访问服务器的地址(域名+端口)

Host: localhost:8080

Connection: 长连接(http1.1协议)

Connection: keep-alive

Cache-Control: 设置缓存数据的存活时间,单位秒

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 客户端支持https加密协议

Upgrade-Insecure-Requests:1

Content-Type: 发送数据的媒体类型

Content-Type: application/x-www-form-urlencoded

Accept: 客户端告诉服务器,客户端支持的数据类型

Accept: text/html,/;

Accept-Charset: 客户端告诉服务器,客户端支持的字符集

Accept-Charset: UTF-8

Accept-Encoding: 客户告诉服务器,客户端支持的压缩格式

Accept-Encoding: gzip, deflate

Accept-Language: 客户端告诉服务器,客户端系统语言环境 简体中文

Accept-Language: zh-CN,zh;q=0.9

Cookie:

Referer: http://baidu.com 上一次请求的地址

User-Agent: 客户端系统和浏览器版本
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) Chrome/63.0 Safari/537.36
浏览器兼容性

3.2.2.3 请求体(正文)
格式
参数名=参数值&参数名=参数值

例如
username=jack&password=123

注意
get方式没有请求体,post有请求体

3.3 Http响应
3.3.1 浏览器查看Http响应协议(查看Inspect-Network-Response Headers,响应体查看Network的Response栏)
响应行 HTTP/1.1 200 OK
响应头 HTTP/1.1 200 OK
content-type: text/html
server: IntelliJ IDEA 2020.1
date: Mon, 13 Apr 2020 10:25:17 GMT
X-Frame-Options: SameOrigin
X-Content-Type-Options: nosniff
x-xss-protection: 1; mode=block
accept-ranges: bytes
cache-control: private, must-revalidate
last-modified: Mon, 13 Apr 2020 10:12:12 GMT
content-length: 317
access-control-allow-origin: http://localhost:63343
vary: origin
access-control-allow-credentials: true
响应体

Login

Login

Name:
Password
3.3.2 HTTP响应消息格式 3.3.2.1 响应行 格式 协议/版本号 状态码

例如
tomcat8:HTTP/1.1 200
tomcat7:HTTP/1.1 200 OK

• 常见状态码

状态码 说明
200 成功
302 重定向
304 从缓存中读取数据
404 请求资源未找到
405 请求的方法未找到
500 服务器内部错误
3.3.2.2 响应头
格式
响应头名称:响应头的值

例如
last-modified: Mon, 13 Apr 2020 10:12:12 GMT

常见响应头:Content开头都是服务器告诉客户端一些暗语

Location:通常与状态码302一起使用,实现重定向操作

Location:http://www.baidu.com

Content-Type:服务器告诉客户端,返回响应体的数据类型和编码方式

Content-Type:text/html;charset=utf-8

Content-Disposition:服务器告诉客户端,以什么样方式打开响应体

in-line(默认):浏览器直接打开相应内容,展示给用户
attachment;filename=文件名:浏览器以附件的方式保存文件 【文件下载】

Refresh::在指定间隔时间后,跳转到某个页面

Refresh:5;http://www.baidu.com

Last-Modified:通常与状态码304一起使用,实现缓存机制

last-modified: Mon, 13 Apr 2020 10:12:12 GMT

3.3.2.3 响应体
服务器返回的数据,由浏览器解析后展示给用户
用户看到页面所有的内容,都是在响应体中返回的
总结
web知识概述
架构分类
C/S

客户端专门安装软件
B/S

浏览器作为客户端
web服务器作用
将本地资源发布到互联网,用户可以通过浏览器访问
资源分类
静态

.html .css .js .jpg
动态

.jsp
常见服务器
Tomcat
tomcat服务器
下载
apache-tomcat-8.5.31-windows-x64.zip
安装
解压缩即可
目录结构
bin

startup.bat

启动
shutdown.bat

关闭
conf

server.xml

配置恩建
lib

logs

temp

webapps

存放自己编写web项目,对外发布
work

启停
startup.bat
shutdown.bat
启动有问题
JAVA_HOME环境变量

端口占用

找到占用端口软件,关闭掉,在启动tomcat
修改tomcat在启动
tomcat发布项目方式
webapps目录

热部署
conf/server.xml

不推荐
conf/catalina/localhost

热部署
web项目目录结构
WEB-INF

classes

lib

web.xml

web3.0之后可选
静态资源

index.html或index.jsp

idea中使用tomcat
配置tomcat

创建web项目

启动

重启tomcat
重新部署项目
http协议
概述
在客户端和服务器端通信时,规范了传输数据的格式
构成
请求格式

请求方式

get
post
URL

协议

请求的描述信息

Referer
User-Agent

数据内容

get方式没有,post才有
响应格式

协议

状态码

200
302
304
404
405
500

响应的描述信息

Location
Content-Type
Content-Disposition
refresh
Last-Modified

数据内容

一.JSON
1.1 JSON概述
Javascript对象表现形式(JavaScript Object Notation)

JavaScript对象表现形式

1
2
let user = {“username”:”ObjName”,”age”:”10”,”gender”:”male/female”};
let product = {“Brander”:”Apple”,”Price”:”8999”};

取代厚重XML,比起XML更小更快更易解析

Json,XML作用:作为数据的载体,在网络中传输

1.2 JSON基础语法

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
对象类型
{name:value,name:value}

数组类型

[
{name:value,name:value},
{name:value,name:value},
{name:value,name:value}
]

复杂对象:

{
name:value,
array:[{name:value},{},{}],
user:{name:value}
}


<script>
//1.描述用户对象
let user = {"username": "Trump", "Gender": "male", "Age": "103"}
alert(typeof user);//object
alert(user.username + user.Gender + user.Age);

//2.描述用户数组
let users = [
{"username": "John", "Gender": "male", "Age": "103"},
{"username": "Jack", "Gender": "Female", "Age": "23"},
{"username": "Bobe", "Gender": "male", "Age": "13"}
]

for (let user of users) {
console.log(user.username + "," + user.Gender + "," + user.Age);
}

//3.描述复杂对象
let Emperor = {
"Age": 20,
"Wife": [
{"username": "Queen", "Gender": "Female", "Age": "23"},
{"username": "Concubine", "Gender": "Female", "Age": "18"}
],
"Father_Emperor": {"username": "Lord"}
}
console.log(Emperor);
console.log(Emperor.Age);
let wifes = Emperor.Wife;
for(let wife of wifes){
console.log(wife.username + "," + wife.Gender + "," + wife.Age);
}

let fatherEmperor = Emperor.Father_Emperor;
console.log(fatherEmperor.username);
</script>

1.3 JSON格式转换
JSON对象与字符串的相关函数
语法:
语法 作用
JSON.stringify(object) 把JSON对象转换为字符串
JSON.parse 把字符串转换为JSON对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<script>
let user = {"username": "Trump"}
alert(typeof user);//object

let userstr = '{"username": "Trump"}'
alert(typeof userstr);//string

//1. JSON.parse 把字符串转换为JSON对象
let user_parse = JSON.parse(userstr);
console.log(typeof user_parse);//object

//2. JSON.stringify(object) 把JSON对象转换为字符串
let user_stringify = JSON.stringify(user);
console.log(typeof user_stringify);//string
</script>
</body>

二.AJAX
2.1 AJAX概述
AJAX是浏览器提供的一套方法,在无需重新加载整个网页的情况下,能够更新部分网页技术,从而提高用户浏览器网站应用的体验
应用场景

搜索框提示
表单数据验证
无刷新分页

2.2 JS原生AJAX
代码实现
•创建Ajax对象
let xhr = new XMLHttpRequest();
•告诉Ajax请求方式和请求地址
xhr.open(请求方式,请求地址)

•发送请求
xhr.send();

•获取服务器返回的数据
xhr.onload=function(){
xhr.responseText;
}

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
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
span{
color: red;
}
</style>
</head>
<body>
<input type="text" id="username" placeholder="Input Username"><span id="userwarn"></span>

<script>
document.getElementById('username').onblur = function () {
console.log(this.value);
//创建Ajax对象
let xhr = new XMLHttpRequest();

//告诉Ajax请求方式和请求地址
xhr.open('get', 'http://localhost:8080/check?username=' + this.value);

//发送请求
xhr.send();

//获取服务器返回的数据
xhr.onload = function () {
console.log(xhr.responseText); //返回的字符串
document.getElementById('userwarn').innerText=xhr.responseText;
}
}
</script>
</body>

2.3 jQuery的Ajax插件
2.3.1 ajax函数
语法:
$.ajax(json对象格式);
参数:
url:请求地址
type:请求方式(get:不安全且大小有限制,post大小无限制且相对安全)
data:请求参数
success:请求成功时,执行回调函数
error:请求失败时,执行的回调函数
dataType:预期服务器返回的数据类型:text,json

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
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../js/jquery-3.2.1.js"></script>
<style>
span{
color: red;
}
</style>
</head>
<body>
<input type="text" id="username" placeholder="Input Username"><span id="userwarn"></span>

<script>
//给文本绑定失去焦点事件
$('#username').blur(function () {
//使用ajax发送请求
$.ajax({
url: "http://localhost:8080/check",
type: "post",
data: "username=" + $(this).val(),
success: function (resp) {
//实现局部刷新
$('#userwarn').text(resp);
},
error: function () {
alert('Server Busy ,Please Retry');
},
//dataType: "json"//相当于把字符串转为JSON对象
})
})
</script>
</body>

2.3.2 get函数
语法:
$.get(url,callback)
参数:
url:请求地址
success:请求地址成功时的回调函数

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
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../js/jquery-3.2.1.js"></script>
<style>
span{
color: red;
}
</style>
</head>
<body>
<input type="text" id="username" placeholder="Input Username"><span id="userwarn"></span>

<script>
//给文本绑定失去焦点事件
$('#username').blur(function () {
//使用get发送函数
let url = 'http://localhost:8080/check?username' + $(this).val();
$.get(url, function (resp) {
//局部刷新
$('#userwarn').text(resp);
})
})
</script>
</body>

2.3.3 post函数
语法:
$.post(url,data,success)
参数:
url:请求地址
data:请求参数
success:请求地址成功时的回调函数

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
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../js/jquery-3.2.1.js"></script>
<style>
span{
color: red;
}
</style>
</head>
<body>
<input type="text" id="username" placeholder="Input Username"><span id="userwarn"></span>

<script>
//给文本绑定失去焦点事件
$('#username').blur(function () {
//使用post发送函数
let url = 'http://localhost:8080/check';
let data = 'username=' + $(this).val();
$.post(url, data, function (resp) {
//局部刷新
$('userwarn').text(resp);
})
})
</script>
</body>

2.4 同步和异步概述
使用ajax发送的是异步请求
**同步和异步请求指的是:客户端和服务器的交互行为
同步:客户端发送请求后,必须等待服务器端响应。在等待的期间客户端不能做其他操作
异步:客户端发送请求后,不需要等待服务器端的响应。在服务器处理的过程中,客户端可以进行其他操作

感知同步和异步区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="../js/jquery-3.2.1.js"></script>
</head>
<body>
<button id="btn">Send Ajax</button>

<script>
//给按钮绑定事件
$('#btn').click(function () {
// 使用ajax函数发送请求,ajax默认的是异步提交,可以改为同步(了解)
$.ajax({
url: 'http://localhost:8080/sleep',
type: 'get',
success: function (resp) {
alert(resp)
},
async: false // 同步提交
})
})
</script>
</body>

三.搜索案例

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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Search Case</title>
<script type="text/javascript" src="../js/jquery-3.2.1.js"></script>
<style type="text/css">
.content {
width: 643px;
margin: 200px auto;
text-align: center;
}

input[type='text'] {
width: 530px;
height: 40px;
font-size: 14px;
}

input[type='button'] {
width: 100px;
height: 46px;
background: #38f;
border: 0;
color: #fff;
font-size: 15px
}

.show {
position: absolute;
width: 535px;
height: 100px;
border: 1px solid #999;
border-top: 0;
}
</style>
</head>
<body>
<div class="content">
<img src="../img/logo.png" alt=""><br/><br/>
<input type="text" id="search" name="keyword">
<input type="button" value="Search">
<div class="show" style="display: none"></div>
</div>

<script>
//1.搜索框绑定键盘弹起事件
$('#search').keyup(function () {
//显示div
$('.show').show();

//2.获取用户输入的值
console.log($(this).val());
//判断用户输入的值,JS提供了trim()方法,JQ使用需要转换
if (this.value.trim().length == 0) {
return $('.show').hide();//拦截代码,不再向下执行
}

//3.使用post函数发送请求
let url = 'http://localhost:8080/search';
let data = 'keyword=' + $(this).val();
$.post(url, data, function (resp) {
//清空上次搜索的内容
$('.show').empty();
//4.局部更新
console.log(resp);
for (let ele of resp) {
$('.show').append(`<div style="cursor: pointer;
text-align: left;
padding-left: 5px"
onmouseover="highlight(this)"
onmouseout="restores(this)"
onclick="set(this)">${ele}</div>`)
}
})
})

function highlight(obj) {
$(obj).css('background-color', '#f0f0f0');
}

function restores(obj) {
$(obj).css('background-color', 'white');
}

function set(obj) {
//设置选中文字色
$('#search').val($(obj).text()).css('color','brown');
//跳转网址
location.href = "http://www.baidu.com";
// $('.show').css('display', "none");
$('.show').hide();
}
</script>
</body>
</html>

一.jQuery概述
1.1 简介
jQuery是一个优秀的javascript的轻量级框架之一,封装了dom操作、事件、页面动画、异步操 作等功能。
特别值得一提的是基于jQuery的插件非常丰富,大多数2015年之前的前端业务场景都有其封装好的工具框架。

注意:如果公司使用的老版本插件,升级jQuery之后,可能会让插件失效

库名 说明
jQuery-x.js 开发版本:有良好的锁紧格式和注释,方便开发者阅读
jQuery-x.min.js 生产版本:代码进行压缩,体积小方便网络传输
1.2 自定义JS框架
框架(Framework)是完成某种功能的半成品,抽取重复繁琐代码,提高简介强大的方法实现。

感知jQuery的强大

1
2
3
4
5
// 抽取获取id的方法 function jQuery(id) {
return document.getElementById(id); }
// 简化名称方案 function $(id) {
return document.getElementById(id); }

1
2
3
4
5
6
7
8
9
10
11
12

Title
AAAAAAAAAA

小结:jQuery本质上就是js的一个类库文件,使用它时,就能简化代码

二.jQuery基础语法
2.1 HTML引入jQuery
1
2
3
4
5
6
7
8
9
10
11
12

HTML Intro Jqurey
AAAAAAAAAA
2.2 jQuery与JS区别 jQuery虽然本质也是JS,但是如果使用jQuery的属性和方法那么必须包装对象是jQuery对象而不是js对象。 通过js方式获取的是js对象,通过jQuery方式获取的是jQuery对象,两者关系和区别如下:

jQuery与JS的相互转换
js—>jq
$(js对象)或者jQuery(js对象)
jq—>js
js对象[] 或者 jq对象.get(索引)
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

Mutual conversion
AAAAA

页面加载事件 js window.onload=function(){}

jq
$(function(){})

区别
js:只能定义因此,如果定义多次,后加载会进行覆盖
jq:可以定义多次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

window onload
三.jQuery选择器
3.1 基本选择器
标签(元素)选择器
语法:
$(“html标签名”) 根据标签匹配元素 格式 标签
id选择器
语法:
$(“#id的属性值”) 根据id值匹配元素 id属性是标签的唯一标志 #id
类选择器
语法:
$(“.class的属性值”) 根据class的值匹配元素 class属性是给标签归类添加样式 格式 .class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

古力娜扎 迪丽热巴 黑寡妇

钢铁侠
超人

3.2 层级关系选择器 后代选择器 语法: $(“A B”) 选择A元素内部的所有B元素 并集选择器 语法: $(“选择器1,选择器2….”) 获取多个选择器选中的所有元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
儿子:雍正

孙子:乾隆

牛顿

3.3 属性选择器
属性选择器
语法:$(“A[属性名=’值’]”) 包含指定属性等于指定值的选择器
复合属性选择器
语法:$(“A[属性名=’值’][]…”) 包含多个属性条件的选择器
1
2
3
4
5
6
7
8
9
10
11
12



3.4 过滤选择器 首元素选择器 语法: :first 获得选择的元素中的第一个元素 尾元素选择器 语法: :last 获得选择的元素中的最后一个元素 偶数选择器 语法: :even 偶数,从 0 开始计数 奇数选择器 语法: :odd 奇数,从 0 开始计数 指定索引选择器 语法: :eq(index) 指定索引元素 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
  • 大娃(红娃)
  • 二娃(橙娃)
  • 三娃(黄娃)
  • 四娃(绿娃)
  • 五娃(青娃)
  • 六娃(蓝娃)
  • 七娃(紫娃)

3.5 对象遍历
语法
jq对象.each(function(index,element){
})

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

  • 北京
  • 上海
  • 天津
四.jQuery的DOM操作 4.1 jQuery操作内容 text():获取/设置元素的标签体纯文本内容 相当于js: innerText属性 html():获取/设置元素的标签体超文本内容 相当于js: innerHTML属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

天王盖地虎

4.2 jQuery操作属性 val():获取/设置元素的value属性值 相当于:js对象.value attr():获取/设置元素的属性 removeAttr() 删除属性 相当于:js对象.setAttribute() / js对象.getAttribute() prop():获取/设置元素的属性 removeAttr() 删除属性 jq在1.6版本之后,提供另一组API prop 通常处理属性值为布尔类型操作 例如:checked selected等 做条件判断用prop,做属性封装做attr

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

姓名
爱好
<input id="hobby" type="checkbox" name="hobby" value="perm" checked="checked">烫头<br/>
<input id="hobby_undefined" type="checkbox" name="hobby" value="perm" >烫头<br/>


<input type="reset" value="清空按钮"/>
<input type="submit" value="提交按钮"/><br/>
4.3 jQuery操作样式 直接修改jq对象样式属性 语法: jq对象.css() css(样式名) 获取 css(样式名,样式值) 设置 优点:支持css语法 举例:font-size

添加/删除jq对象样式
语法:
jq对象.addClass()
jq对象.removeClass()

切换jq对象样式
语法:
jq对象.toggleClass() 无添加,有删除

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

Title
六.综合案例 6.1 隔行换色 1 2 3 4 6.2 商品全选 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
6.3 QQ表情
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

Title QQ表情选择

一.BOM对象
1.1 BOM简介
浏览器对象模型(Browser Object Model)
作用:把浏览器抽象成一个对象模型,可以使用JS模拟一些浏览器功能
1.2 Window对象
三种弹框
警告框:提示信息
alert()
确认框:确认信息
confirm()
输入框:输入信息
prompt()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
//警告框:提示信息
alert("Hello")
//确认框:确认信息
let result = confirm("Sure to Delete?Y/N")
if (result == true) {
console.log("Y");
} else {
console.log("N");
}
//输入框:输入信息
let age = prompt("Please Input Your Age");
if (age != null) {
console.log("Please Input Age",`${age}`)
}else {
console.log("Canceled");
}
</script>

二种定时器

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
<body>
<!--
JS两个定时器
1)一次性定时器
创建:let 定时器对象 = setTimeout(`函数()`,毫秒)
关闭:clearTimeout(定时器对象)
2)循环型定时器
创建: let 定时器对象 = setInterval(函数,毫秒)
关闭:clearInterval()
-->
<button id="btn1">Cancel Print Time</button>
<button id="btn2">Cancel Print Number</button>

<script>


//1.定时1s在控制台打印当前时间
function fun1() {
console.log(new Date().toLocaleString());
}

let timeout = setTimeout(`fun1()`, 1000);

//2.点击按钮取消打印时间
document.getElementById("btn1").onclick = function () {
clearTimeout(timeout);
}

//3.每隔2秒在控制台打印递增自然数
let num = 1;

function fun2() {
console.log(num++);
}

let interval = setInterval(fun2, 2000);

//4.点击按钮取消打印自然数
document.getElementById('btn2').onclick = function () {
clearInterval(interval);
}

</script>
</body>

1.3 Location对象

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
<body>
<!--
location地址
1)获取当前窗口地址
location.href
2)刷新当前页面
location.reload
3)跳转页面
location.href='new location'
-->

<button onclick="addr()">获取当前浏览器地址</button>
<button onclick="refresh()">刷新当前页面</button>
<button onclick="jump()">跳转页面(重点)</button>

<script>
function addr() {
console.log(location.href);
}
function refresh() {
console.log(location.reload());
}
function jump() {
console.log(location.href = 'https://www.baidu.com/');;
}
</script>

</body>

二.DOM对象
2.1 DOM简介
DOM(Document Object Model) 页面文档对象模型
JS把页面抽象成为一个对象,允许我们使用js来操作页面

2.2 DOM获取元素
第一种:es6之前的获取方式
1)获取一个:
document.getElementById(id属性值)
2)获取多个:
document.getElementByTagName(标签名属性值) 根据标签名获取,返回数组对象
document.getElementByClassName(class属性值) 根据class属性获取,返回数组对象
document.getElementByName(name属性值) 根据name属性获取,返回数组对象
第二种:es6可根据CSS选择器获取
1)获取一个:
document.querySelector(id选择器)
2)获取多个:
document.querySelectorAll(css选择器)
标签
class
属性
后代
并集
父子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
//1.获取id="name"对象
console.log(document.getElementById('name'));
console.log(document.querySelector('name'));
//2.获取class="radio"的标签数组
console.log(document.getElementsByClassName('radio'));
console.log(document.querySelectorAll('radio'));
//3.获取所有option标签对象数组
console.log(document.getElementsByTagName('option'));
console.log(document.querySelectorAll('option'));

//4.获取name="hobby"的input标签对象数组
console.log(document.getElementsByName('hobby'));
console.log(document.querySelectorAll('input[name="hobby"]'));//CSS的属性选择器

//5.获取文件上传选择框
console.log(document.querySelectorAll('form input[type="file"]'));
</script>

2.3 DOM操作内容
获取或修改元素(标签)的纯文本内容
语法:
element.innerText
获取或者修改元素的html内容
element.innerHTML;
获取或者修改包含自身的html内容
element.outerHTML;
总结:

innerText 获取的是纯文本 innerHTML获取的是所有html内容
innerText 设置到页面中的是纯文本 innerHTML设置到页面中的html会展示出外观效果
innerHTML不包含自身 outerHTML包含自身的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


<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#myDiv {
border: 1px solid red;
}
</style>
</head>

<body>

<div id="myDiv">AAA</div>
<script>
let myDIV = document.getElementById('myDiv');
//1.innetText操作div内容
//1.1获取纯文本
console.log(myDIV.innerText);
//1.2 获取纯文本,无法更改标签等属性
myDIV.innerText = "BBBBB";//覆盖
myDIV.innerText += "BBBBB";//追加


//2.innerHTML操作div内容
//2.1 获取超文本内容
console.log(myDIV.innerHTML);
//2.2 设置超文本,可以更改标签等属性
myDIV.innerHTML = '<h1>CCCCCC</h1>'//覆盖
myDIV.innerHTML += '<h1>CCCCCC</h1>'//追加

//3.outerHTML操作div
myDIV.outerHTML='<p>DDDDDDDD</p>'//不仅可以修改纯文本,还能修改标签

</script>
</body>

2.4 DOM操作属性
获取文本框的值,单选框或复选框的选中状态
语法:
element.properties 获取或者修改元素对象的原生属性
给元素设置自定义属性
语法:
element.setAttribute(属性名,属性值) 给元素设置一个属性值,可以设置原生和自定义
获取元素的自定义属性值
语法:
element.getAttribute(属性名) 获取元素的一个属性值,可以获取原生和自定义
移除元素的自定义属性
语法:
element.removeAttribute(属性名)

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
<body>

<form action="#" method="post">
Name: <input type="text" name="username" id="username" value="AAAAA"/><br/>


Hobby:
<input type="checkbox" name="hobby" value="smoke">X
<input type="checkbox" name="hobby" value="drink">Y
<input type="checkbox" name="hobby" value="perm">Z<br/>

<input type="reset" value="清空按钮">
<input type="submit" value="提交按钮"><br/>

</form>

<script>
//1.获取文本框预定义的属性值
let username = document.getElementById('username');
console.log(username);
console.log(username.type);
console.log(username.name);
console.log(username.value);
//2.给文本框设置自定义属性
username.setAttribute('customize', 'customize properties');
//3.获取文本框自定义属性
console.log(username.getAttribute('customize'));
//4.移除文本框自定义属性
username.removeAttribute('customize');
username.removeAttribute('value');
</script>

</body>

2.5 DOM操作样式
设置一个css样式
语法:
element.style.样式名=’样式值’ 获取或者修改一个css样式
特点:
驼峰格式样式属性名
css格式:font-size
js格式:fontSize

批量设置css样式
语法:
element.style.cssText 获取后者修改 标签的style属性的文本值
特点:有耦合性,无提示较麻烦

通过class设置样式
语法:
element.className=’class选择器名’ 获取或者修改标签的class属性的文本值

切换class样式
语法:
element.classList es6特别提供的操作元素class的接口
常用方法有四个:
add() 添加一个class样式
remove() 移除一个class样式
contains() 判断是否包含某一个样式
toggle() 切换一个class样式 有则删除,无则添加

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


<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#p1 {
background-color: red;
}


.mp {
color: green;
font-size: 30px;
font-family: "Cascadia Code";
}

.mpp {
background-color: lightgray;
}

</style>

</head>
<body>

<p id="p1">Set One CSS Style</p>
<p id="p2">Set CSS Style</p>
<p id="p3">Set CSS Style By Class</p>

<script>
let p1 = document.getElementById('p1');
let p2 = document.getElementById('p2');
let p3 = document.getElementById('p3');


//1.设置一个css样式
p1.style.backgroundColor = 'black';
p1.style.color = 'white';

//2.批量设置css样式
p2.style.cssText = 'border:1px solid red;font-size:20px';

//3.通过class设置样式
p3.className = 'mp mpp';//注意不要添加'.'符号,可以添加多个组

</script>
</body>

2.6 DOM操作元素
创建一个标签对象
语法:
innerHTML 获取或者设置标签的html内容
父标签添加子标签
语法:
document.createElement(标签名称) 创建一个标签对象
parentNode.appendChild(newNode) 给父标签添加一个子标签
移除元素
outerHTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>

<ul id="name">
<li>A</li>
<li>B</li>
</ul>
<script>
//添加一个心列表
//方式一
document.getElementById("name").innerHTML += '<li>C</li>';
//方式二
//1.1 创建li标签
let li = document.createElement('li');
li.innerText = 'All';
console.log(li);
//1.2 父标签添加子标签
document.getElementById('name').appendChild(li);
</script>

</body>

三.正则表达式
作用:根据定义好的规则,过滤文本内容

在js中使用正则表达式
创建方式
1)let reg1 = new RegExp(‘正则表达式字符串’);
2)let reg1 = /正则表达式/;
验证方法
1)正则对象.test(字符串)
符号正则规则就返回true,否则false
2)字符串对象.match(正则对象)
返回字符串中符号正则规则的内容

正则表达式修饰符
i忽略大小写 g全局匹配 m 多行匹配

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
<body>

<script>
//1.创建正则对象
let reg1 = new RegExp('\\d+');
console.log(reg1.test('abc'));
console.log(reg1.test('123'));


let reg2 = /\d+/;
console.log(reg2.test('abc'));
console.log(reg2.test('123'));

//验证方法
console.log("a1".match(reg2));//表示获取字符串符号正则规则的部分

//正则表达式修饰符
//i忽略大小写 g全局匹配 m 多行匹配
let regi = /[]amn]/i;//不区分大小写匹配amn ignore忽略大小写
let resi = 'ABC'.match(regi);//从ABC中匹配regi模式字符串
console.log(resi);
let regg = /\d/g;//全局查找数组 global 全局
let resg = "1 plus 2 equels 3".match(regg);
console.log(resg);
let regm = /^\d/m;//多行匹配开头的数字(^限定开始 $限定结束) ,multipart
let resm = "abc1 plus 2 equals 3\n6abcmnk".match(regm);
console.log(resm);

</script>
</body>

四.综合案例
4.1 表单校验

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
//1.两次密码输入一致
//2.获取密码框和确认密码框的js对象
let
pwd1 = document.getElementById('pwd1');
let pwd2 = document.getElementById('pwd2');

//1.2 校验密码是否一致的方法
function checkPwd() {
let boo = pwd1.value == pwd2.value;
if (boo == true) {
document.getElementById('pwdwarn').style.display = 'none';
} else {
document.getElementById('pwdwarn').style.display = 'inline';
}
return boo;
}

//1.3 给确认密码框绑定失去焦点时间
pwd2.onblur = checkPwd;//不能加括号()

//2.邮箱格式正确
//2.1 定义邮箱正则表达式

//2.2 获取邮箱的js对象
let email = document.getElementById('email');
let emailReg = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;

//2.3 定义校验函数(方法)
function checkEmail() {
let boo = emailReg.test(email.value);
if (boo == true) {
document.getElementById('emailwarn').style.display = 'none';
} else {
document.getElementById('emailwarn').style.display = 'inline';
}
return boo;
}

//2.4 给邮箱绑定失去焦点事件
email.onblur = checkEmail;

//3.手机号格式正确

let phone = document.getElementById('phone');
let phoneReg = /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/;

function checkPhone() {
let boo = phoneReg.test(phone.value);
if (boo == true) {
document.getElementById('phonewarn').style.display = 'none';
} else {
document.getElementById('phonewarn').style.display = 'inline';
}
return boo;
}

phone.onblur = checkPhone;

//表单提交时进行校验 一定触发onsubmit()事件
document.getElementById('myForm').onsubmit = function () {
if (checkPwd() && checkEmail() && checkPhone()) {
alert('Successful')
return true;
} else {
alert('Something Wrong')
}
}

点我展开html和css
4.2 商品全选

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
<body>
<button id="btn1">1.全选</button>
<button id="btn2">2.反选</button>
<button id="btn3">3.全部取消</button>
<br>
<input type="checkbox">Computer
<input type="checkbox">Phone
<input type="checkbox">Car
<input type="checkbox">House
<input type="checkbox" checked="true">NoteBook

<script>
let boxs = document.querySelectorAll('input[type="checkbox"]');


document.getElementById('btn1').onclick = function () {
for (let box of boxs) {
box.checked=true;
}
}
document.getElementById('btn2').onclick = function () {
for (let box of boxs) {
box.checked=!box.checked;
}
}

document.getElementById('btn3').onclick = function () {
for (let box of boxs) {
box.checked=false;
}
}

</script>
</body>

4.3 省市联动

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
var data = new Array();
data['A'] = ['A1', 'A2', 'A3'];
data['B'] = ['B1', 'B2', 'B3'];
data['C'] = ['C1', 'C2', 'C3'];

let provinceID = document.getElementById("provinceId");
let cityID = document.getElementById("cityId");

//1.页面加载成功后,初始化省份数据
window.onload = function () {
for (let index in data) {
console.log(index);
provinceId.innerHTML +=`<option value="${index}">${index}</option>`;
}
}
//2.给省份下拉框绑定onchange事件
provinceId.onchange = function () {
console.log(this.value);//当前用户选中的value值,它就是二维数组的索引
console.log(data[this.value]);
//3.城市列表
cityId.innerHTML = '<option value="">----请-选-择-市----</option>';
console.log(this.value);
console.log(data[this.value]);
let citys = data[this.value];
for (let city of citys) {
cityId.innerHTML += `<option value="${city}">${city}</option>`;
}
}

4.4 隔行换色

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
let oldColor;
//获取所有数组对象
let trs = document.querySelectorAll('table tr');//注意:这里使用的是后代选择器,这里是js的一个小坑

for (let i = 0; i < trs.length; i++) {
if (i % 2 == 0) {//偶数索引,奇数行
trs[i].style.backgroundColor = 'lightgray';
} else {//奇数索引,偶数行
trs[i].style.backgroundColor = 'skyblue';
}
trs[i].onmouseover = function () {//鼠标移入某一行
//获取当前行的颜色
oldColor=trs[i].style.backgroundColor;
trs[i].style.backgroundColor = 'brown';
}
trs[i].onmouseout = function () {//鼠标移出某一行
trs[i].style.backgroundColor=oldColor;
}
}
let tds = document.querySelectorAll('table td');
for (let i = 0; i < tds.length; i++) {
tds[i].onmouseover=function(){
tds[i].style.backgroundColor='Green';
}
tds[i].onmouseout = function () {//鼠标移出某一行
tds[i].style.backgroundColor=oldColor;
}
}

4.5 拓展:为什么不用var
ES6之前作用域为全局,容易导致变量有值被新值替代,局部变量使用let可以自动销毁,推荐let

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


// for循环举例:var声明变量全局作用域、let声明变量是局部作用域
for (var i = 0; i < 5; i++) {
document.write('<h3>我是var修饰遍历的内容</h3>')
}
console.log(i);

for (let j = 0; j < 5; j++) {
document.write('<h3>我是let修饰遍历的内容</h3>')
}
// console.log(j);


{
var a = 10;
let b = 5;
}
console.log(a); // 可以取到
console.log(b); // 不能取到

总结:
BOM对象
简介
浏览器对象模型
Window对象
三种弹框

alert()
confim()
prompt()
二种定时器

setTimeout(函数,毫秒)

clearTimeout(定时器)
setInterval(函数,毫秒)

clearInterval(定时器)
Location对象
reload()

href

跳转页面
DOM对象
简介
文档对象模型
获取元素
ES5

getElementById(id属性值)
ES6

querySelector(CSS选择器)
querySelectorAll(CSS选择器)
操作内容
innerText
innerHTML
操作属性
js对象.属性名

原生属性
操作样式
js对象.style.样式名(驼峰格式)
js对象.style.cssText
js对象.className
操作元素
添加元素

js对象.innerHTML +=追加内容

document.createjs对象(标签)

parentNode.appendChild(newNode)
正则表达式
创建
let rege = new RegExp(“正则表达式”);
let regex = /正则表达式/;
验证方法
正则对象.test(字符串)
综合案例
表单校验
发挥大家的想象力
商品全选
省市联动
隔行换色

一.JavaScript基础语法
1.1 JS运算符
算术运算符

      • / % ++ –

赋值运算符
= += -= *= /=

比较运算符

1
> < ==(===) !=(!==)

逻辑运算符
&& || !

三元(目)运算符
条件表达式?为真:为假

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22


<script>
//算数运算符
//在JS中数值可以与字符串进行数学运算,底层实现了隐式转换
let a =10;//num
let b = '4';//String
console.log(a+b);//104 字符串拼接
console.log(a-b);//6
console.log(a*b);//40
console.log(a/b);//2.5 保留小数位


//比较运算符
let c='10';
console.log(a == c);//比较的是内容
console.log(a === c);//比较的是类型+内容

//!= 比较的是内容
//!== 比较的是类型+内容

</script>

1.2 JS流程控制
条件判断
•if判断
if(条件表达式){
代码块
}else if(条件表达式){
代码块
}else{
代码块
}
•switch判断
switch(条件表达式){
case 满足条件1 :
代码块 break;
case 满足条件2 :
代码块 break;
case 满足条件3 :
代码块 break;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
/*
条件表达式
1)布尔型
2)数值型:非0为真
3)字符串:非空串为真
4)变量:null 或 undefined 都为假
*/
let flag = true;
flag = 15;
flag = "Hello";
flag = null;
if(flag){
console.log("Right");
}else{
console.log("Wrong");
}
</script>

循环语句
•普通for循环
for (let i = 0; i < ; i++) {
//需要执行的代码
}

•增强for循环
for(let obj of array){
//需要执行的代码
}

•索引for循环
for(let index in array){
//需要执行的代码
}

•while循环
while(条件表达式){
//需要执行的代码
}

•do…while循环
do{
//需要执行的代码
}while(条件表达式)

•break和continue
break:跳出整个循环
continue:跳出本次循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
let arr=['a','b','c'];


//普通for循环
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}

//增强for循环
for(let element of arr){
console.log(element);
}
//索引for循环
for (let index in arr) {
console.log(index);
console.log(arr[index]);
}

</script>

二.JS函数
功能:js函数用于执行特定功能的代码块,为了方便立即也可以称为JS方法

2.1 普通函数
语法:
function 函数名(参数列表){
函数体;
[return 返回值;] //中括号表示内容可以省略
}

js不支持方法重载,重名的方法会被覆盖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<script>
//两数求和
function sum(a, b) {
//console.log(a + b); //无返回值
return a + b;
}
// sum(1,10);

//三数求和
//NaN:not a number 这不是一个数
//js是弱类型语言,不支持方法重载,重名的方法会覆盖
//js函数定义的参数个数,可以与实际调用的参数个数不同
function sum(a, b, c) {
return a + b + c;
}

let result = sum(1, 5);
console.log(result);

console.log(sum(1, 2, 3));
function new_sum(a, b, c) {
//js函数题内置arguments[]数组对象,获取实际调用者的参数值
console.log(arguments[3]);//可以获取额外传入的第4个参数,但是不允许这样使用
}

new_sum(1, 2, 3, 4, 5);

//可变参数,本质就是一个数组
function sum(...args) {
console.log(args);
}

let resut = sum(5, 6, 7, 8);
// console.log(resut);

2.2 匿名函数
通常与事件结合使用
语法:
function (参数列表){
函数体;
[return 返回值;]//中括号表示内容可以省略
}

1
2
3
4
5
6
7
8
9
10
<body>
<button id="btn">Button</button>

<script>
document.getElementById("btn").onclick = function () {
alert("匿名函数触发事件");
};
</script>

</body>

2.3 案例:轮插图
分析:
展示图片的
通过js代码修改img标签的src数学

每隔3秒,切换一次,使用定时器

通过定时器,触发一个方法,修改img标签src属性的图片地址

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
<body>
<!--
setInterval(函数,间隔时间) 每隔固定间隔时间(毫秒)执行一次函数
document.querySelector(css选择器) 根据css选择器获取匹配到的一个标签
-->

<div>
<img id="myImg" src="" alt="" width="500px">
</div>


<script>
//通过DOM获取img标签的js对象
let img = document.getElementById("myImg");
console.log(img);
console.log(img.src);//获取img标签的src属性值



//图片编号
let num = 1;

//定义一个修改图片的方法
function change() {
img.src = '../img/' + num + '1.jpg';
if (num == 4) {
num = 0;
}else {
num++;
}
}

//每间隔3秒,触发此方法
setInterval('change()', 3000);


//每间隔1秒,向控制台输出一句话
//''相当于script标签
// setInterval('console.log("Hello");', 1000);

</script>

三.JS事件
3.1 常用事件
点击事件
•onclick:单击事件
•ondblclick:双击事件

焦点事件
•onblur:失去焦点
•onfocus:元素获得焦点

加载事件
•onload:页面加载完后立即发送

鼠标事件
•onmousedown:鼠标按钮被按下
•onmouseup:鼠标按钮被松开
•onmousemove:鼠标被移动
•onmouseover:鼠标移到某元素之上
•onmouseout:鼠标从某元素一开

键盘事件
•onkeydown:某个键盘按键被按下
•onkeyup:某个键盘按键被松开
•onkeypress:某个键盘按键被按下并松开

改变事件
•onchange:域的内容被改变

表单事件
•onsubmit:提交按钮被点击

3.2 事件绑定
将事件与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
<body>

<input type="button" value="普通函数" onclick="show()"><br>
<input type="button" value="匿名函数" id="myBtn">

<script>
//单击事件
//普通函数 此方案有耦合性
function show() {
alert("普通函数触发事件");
}


//匿名函数
//通过DOM技术获取按钮标签的js对象
// var myBtn = document.getElementById("myBtn");
// myBtn.onclick = function () {
// alert("匿名函数触发事件");
// }

document.getElementById("myBtn").onclick = function () {
alert("匿名函数触发事件");
};

</script>
</body>

3.3 案例:页面交互
需求:给页面表单空间绑定对应事件

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
<body>
<!--
常用事件
1)onload:页面加载完后立即发送
2)onfocus:元素获得焦点
3)onblur:失去焦点
4)onchange:域的内容被改变
5)onclick:单击事件
-->
Name: <input type="text" id="userName"><br/>
Score:

<select name="edu" id="edu">
<option value="0">A</option>
<option value="1">B</option>
<option value="2">C</option>
</select>

<br/>
<!--button相当于<input type="button" value="button">-->
<button id="btn">Button</button>

<script>


// js代码的执行自上而下(顺序结构)
//1.onload页面加载完成
window.onload = function () {
console.log("Page Load Done");//放在哪里都是最后执行
}
console.log("外部内容");

//2.onfocus
//this 当前对象
document.getElementById('userName').onfocus = function () {
// document.getElementById('userName').value = 'Focus';
this.value = 'Focus';
}

//3.onblur
document.getElementById('userName').onblur = function () {
this.value = 'lose Focus';
}

//4.onchange
document.getElementById("edu").onchange = function () {
alert(this.value);
}

//5.onclick
document.getElementById('btn').onclick = function () {
alert('onclick Event');
}

</script>
</body>

四.JS常用内置对象
4.1 String对象

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
<body>
<!--
1.构造字符串对象可以使用单引号,双引号,反引号
2.字符串常用方法
substring()
toLowerCase()
toUpperCase()
split()
trim()
-->

<script type="text/javascript">
//1.构造字符串对象可以使用单引号,双引号,反引号
//单引号
let str1="String";
console.log(str1);
//双引号
let str2="String";
console.log(str2);
//反引号
let str3=`String`;
console.log(str3);


//反引号案例
let num=100;
let str4=`Need ${num} to do Something`;
console.log(str4);

//字符串常用方法
// substring
let str = '我爱我的祖国'; console.log(str.substring(4, 6));

</script>
</body>

4.2 Array对象

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
<body>
<!--
数组:
1.创建数组
*let array=[ele1,ele2,ele3];
let array=new array(ele1,ele2,ele3);
特点:数组元素的类型任意

2.数组常用方法
concat() 连接两个或更多数组,并返回结果
push() 向数组末尾添加一个或多个元素,并返回一个新的长度
pop()删除并返回数组的最后一个元素
join()把数组所有元素放入一个字符串,元素通过指定的分隔符分隔。
与字符串.split()切割为数组方法相反
sort()对数组进行升序排序
reverse()对数组进行降序排序

-->

<script>
//1.创建数组
let arr1 = ['a', 'b', 'c'];
console.log(arr1);


let arr2 = new Array('AAA', 5, new Date());
console.log(arr2);
//2.数组合并
let concatArr = arr1.concat(arr2);
console.log(concatArr);
//3.添加元素,尾部添加
concatArr.push("New");
console.log(concatArr);
//4.删除元素,尾部删除
concatArr.pop('New');
console.log(concatArr);
//5.数组元素拼接为字符串
console.log(concatArr.join('-'));
//6.排序数组元素
let arr3 = [2, 4, 5, 1, 3, 7];
console.log(arr3.sort());
console.log(arr3.reverse());
//指定sort()排序规则
console.log(arr3.sort(function (a, b) {
return b - a;
}));

</script>
</body>

4.3 Date对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<!--
日期
let date = new Date();
-->

<script>
let date = new Date();


console.log(date);
console.log(date.toLocaleString());//转换为本地日期格式的字符串
console.log(date.getFullYear());//年
console.log(date.getMonth() + 1);//月
console.log(date.getDate());//日
console.log(date.getDay());//星期
console.log(date.getTime());//1970至今的毫秒值

</script>
</body>

4.4 Math对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<!--
数学运算
1)四舍五入 round()
2)向下取整 floor()
3)向上取整 ceil()
4)产生随机数 random() 返回[0,1)至今的随机数。左闭右开
-->

<script>
let a = 1234.567;
//round
console.log(Math.round(a));
console.log(Math.floor(a));
console.log(Math.ceil(a));
console.log(Math.random());
console.log(Math.floor(Math.random() * 100+1));
</script>

</body>

4.5 全局函数
不需要通过任何对象,可以至今调用的就称为全局函数

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
<body>
<!--
全局函数
1)字符串转为数字
parseInt()解析一个字符串并返回一个整数
parseFloat()解析一个字符串并返回一个浮点数
特点:从一个字符开始转换,遇到非数值字符停止转换
NaN:not a number, NaN != NaN
isNaN() 判断一个字符串,如果不是数值返回true,否则返回false,即纯数值返回false

2)对字符串编码和解码
HTTP 不识别中文,需要转码
encodeURI()把字符串编码为uri
decodeURI()把uri解码为字符串

3)把字符串当作js表达式来执行
eval() 计算JavaScript字符串,识别为JS脚本片段


-->

<script>
//1.字符串转为数字
let a = '123.932';
console.log(parseInt(a));//123
console.log(parseFloat(a));//123.932


let b = '123.9a32';
console.log(parseInt(b));//123
console.log(parseFloat(b));//123.9

let c = 'a123.9a32';
console.log(parseInt(c));//NaN
console.log(parseFloat(c));//NaN

console.log(NaN == NaN);//false

console.log(isNaN(a));//false
console.log(isNaN(c));//true

// 2.对字符串编码和解码
let name = "一二三";
var message = encodeURI(name);
console.log(message);
console.log(decodeURI(message));

//3.把字符串当作js表达式来执行
eval('alert(1)');

</script>
</body>

总结:
js基础语法
运算符
算数运算符

数值可以与字符串进行数学运算,底层进行了转换
比较运算符

=== 恒等 先比较类型后比较内容
!== 恒不等 先比较类型后比较内容
流程控制语句
顺序

代码自上而下,逐行执行
分支

条件语句

和java一样

if…else if…else
switch…case..default
循环

和java一样的

while
do…while
for…i
和java不一样的

for…in

数组的索引index
for…of

数组的元素
js函数(方法)
普通函数
在js中,没有方法重载
匿名函数
案例:轮播图
setInterval(函数,间隔时间)
document.getElementById(id属性值)
js事件
作用
JS可以监听用户的行为,并调用函数来完成用户交互功能
常用事件
页面加载完毕事件

window.onload
获取焦点

onfocus
失去焦点

onblur
值改变时

onchange
单击时

onclick
事件绑定
普通函数

匿名函数

解耦合….
案例:页面交互
js常用内置对象
String 对象
构造

双引号

单引号

反引号

我爱我的祖国 ${变量占位符}
常用方法

截取

substring()
分割为数组

split()
转换大小写

toLowerCase()
toUpperCase()
去掉前后空格

trim()
Array 对象
构造

[ele1,ele2,ele3];
new Array(ele1,ele2,ele3);
特点:

数组的长度和类型任意,可以把它当做java的集合
常用方法

连接数组

concat()
拼接为字符串

join()
添加/移出元素

push()
pop()
排序

sort()
Date 对象
Math 对象
round 四舍五入
floor 向下取整
ceil 向上取整
random 返回[0,1)随机小数
全局函数
字符串转为数字

parseInt()

转整数
parseFloat()

转小数
isNaN()

非数字
url编码

encodURI()

编码
decodeURI()

解码
执行字符串

eval()