学习Java第一天,打卡一下。
第一个了解动态网页和静态网页
这里的“动态”是相对于“静态”而言的。
静态网页:页面的内容一旦生成,就不再发生变化,因此无法和用户进行交互。
动态网页:页面的内容生成以后,可以随着时间、客户操作的不同而发生改变。例如经常使用的百度、淘宝、京东等网站,使用的就是动态网页。
以百度搜索为例,当搜索 “JSP” 时,页面会显示与 “JSP” 相关的内容。如下图所示:
值得注意的是,不要将“动态网页”和“页面内容是否有动感”混为一谈。动态网页需要使用服务器端脚本语言,如 JSP、PHP、ASP 等,有动感,单纯前端就能完成,比如css动画。
C/S 和 B/S 架构
C/S 架构:Client/Server,客户端/服务器端模式。将软件系统分为客户端和服务器端两层,用户在本机安装客户端,通过网络连接服务器端,例如微信、QQ、魔兽世界等。
现以 QQ 为例(如下图所示),分析 C/S 架构的不足。
如果腾讯对 QQ 进行了升级,那么全球所有安装了 QQ 的客户端都要进行升级。也就是说:凡是采用了 C/S 架构的软件,每次对软件进行改动后,都必须对所有的客户端进行升级;任何一台客户端出现了问题,所有客户端都必须进行维护。
那么,有没有一种架构,既可以降低维护量,又能更广泛地使用系统呢?答案就是 B/S 架构。 B/S 结构:Browser/Server,浏览器/服务器模式。这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用。客户机上只要安装一个浏览器就可访问服务器端。
比如使用 B/S 架构实现的网页版百度(如下图所示),用户并不需要安装百度客户端,就能通过浏览器访问百度,类似的还有网页版的淘宝、京东等。即使开发人员对百度进行修改,也不会影响到任何一个用户。也就是说,采用 B/S 架构的软件系统,用户只要能联网,就可以通过浏览器来访问,无须对系统的升级进行维护。而开发维护人员,只需要对服务器端的代码进行修改即可。
需要注意的是,B/S 架构是 C/S 架构的升级和改善,而不是 C/S 架构的替代品。C/S 架构也有很多自己独有的优势,比如采用 C/S 架构的软件系统有着本地响应快、界面更美观友好、减轻服务器负荷等优势。
tomcat配置
如何配置tomcat以及用tomcat写第一个javaweb项目。 - 掘金 (juejin.cn)
小结
-
JSP 执行流程。
(1)客户端向 Tomcat 服务器发送一个请求。
(2)Tomcat 服务器接收并处理请求后,返回给客户端一个响应。
-
Tomcat 服务器在处理请求期间,执行了如下流程。
① 第一次请求 JSP 页面时的流程。
a.将接收到的 index.js 翻译成与之对应的 Java 文件。
b.再将翻译后的 Java 文件,编译成与之对应的 CLASS 文件。
c.执行 CLASS 文件。
② 第二次请求 JSP 页面时的流程
a.执行 CLASS 文件。
-
HTTP 协议的相关知识。HTTP 协议有请求和响应。该协议有以下特点:
(1)支持 C/S 模式(浏览器就是一种客户端)。
(2)简单快速:客户端向服务器端发送请求时,只需要传递请求路径和请求方式。
(3)灵活:可以传递任意类型的数据;数据类型由 Content-Type 指定。
(4)无状态:HTTP 是无状态协议,即对事务的处理没有记忆能力(如果后续处理需要前面处理过的数据,则必须重新传输)。
jsp基本语法
<%…%> 主要用来定义局部变量、编写简单的 Java 语句。
<%!…%> 主要用来定义全局变量、定义方法。
<%=… %> 用来输出 = 后面的表达式的值,功能类似于 out.print() ,此外 out.print() 和 <%=…> 不仅能输出变量,还可解析 <br/> 等 HTML 代码。
第一个实验:
将项目中的 index.jsp 修改成以下内容。
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>First Web Project</title>
</head>
<body>
<% String bookName ="《JSP 环境配置与使用》"; String author = "掘金" ;
out.print("书名:"+bookName+"<br />作者:"+author); %>
</body>
</html>
输出:书名《JSP 环境配置与使用》
作者:掘金
第二个实验:
在 index.jsp 相同路径下新建 index2.jsp 文件,在文件中写入以下代码:
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>First Web Project</title>
</head>
<body>
<%! public String bookName ; public String author ; public void initInfo() {
bookName ="《jsp环境配置和使用》"; author = "掘金" ;
} %>
<%
initInfo(); out.print("书名:"+bookName+"<br />作者:"+author); %>
</body>
</html>
实验3:
<%=… %> 用来输出 = 后面的表达式的值,功能类似于 out.print() 。
在 index.jsp 相同路径下新建 index3.jsp 文件,在文件中写入以下代码:
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>First Web Project</title>
</head>
<body>
<% String bookName ="《jsp环境配置和使用》"; String author =
"掘金k" ; %> <%="书名:"+bookName+"<br />作者:"+author%>
<!--等价于out.print("书名:"+bookName+"<br/>作者:"+author); -->
</body>
</html>
JSP 的指令
demoJsp1.jsp,在文件中写入下列代码:
<%@ page language="java" import="java.util.Date" contentType="text/html; charset=UTF-8"
pageEncoding= "UTF-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<%
Date date = new Date();
out.print(date);
%>
</body>
</html>
以上代码在 page 指令中,通过 import 导入了 java.util.Date,并指定了编码方式为 UTF-8。page 指令除了 import 和 contentType 等属性以外,还拥有以下属性。
| 属 性 | 说 明 |
|---|---|
| language | 指定 JSP 页面使用的脚本语言,默认是 “java”,一般不用修改 |
| import | 与 Java 中 import 的用法一致,可以执行导包操作 |
| pageEncoding | 指定 JSP 文件本身的编码方式 |
| contentType | 指定服务器发送给客户端的内容的编码方式,通常与 pageEncoding 保持一致 |
JSP 的注释
基本的 JSP 包含了 HTML 和 Java 两种代码。因此,JSP 中的注释既可以是 HTML 的注释,又可以是 Java 的注释,此外还拥有 JSP 自己独有的注释,如下表所示。
| 注 释 方 式 | 说 明 |
|---|---|
<!-- --> | HTML 注释。可以用来注释 HTML 代码,但要注意此种注释能通过客户端(浏览器)查看到,因此是不安全的。 |
<%-- --%> | JSP 注释。如果想让注释不被浏览器所查看到,就可以使用 JSP 注释。 |
<% //单行注释 %>、<% /*多行注释 */ %> | Java 注释。<% %> 中放置的是 Java 代码,所以可以在 <% %> 中使用 // 和 /* */ 来对其中的 Java 代码进行注释。 |
在项目中新建 demoJsp2.jsp 文件写入以下代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding= "UTF-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<!-- HTML 注释,此种注释能通过客户端(浏览器)查看到 -->
<%-- JSP 注释,此种注释不能通过客户端(浏览器)查看到 --%>
<%
//Java 单行注释,此种注释不能通过客户端(浏览器)查看到
/*
Java 多行注释,此种注释不能通过客户端(浏览器)查看到
*/
%>
</body>
</html>
使用命令重新启动 Tomcat
用鼠标右键单击网页空白处,查看页面源代码,如下图所示。
显示内容如下图所示。
其中
<!-- --> 注释可以通过客户端(浏览器)查看到,而 JSP 注释和 Java 注释无法被客户端直接查看。
JSP 内置对象
我们曾经接触过如下代码:
<%
String bookName ="《jsp环境配置与使用》";
String author = "掘金" ;
out.print("书名:"+bookName+"<br/>作者:"+author);
%>
在上述代码中,像 out 这样没有定义和实例化(new)就可以直接使用的对象,称为内置对象。除了 out 外,JSP 还提供了其他的一些内置对象,共有九个。
| 内 置 对 象 | 类 型 | 简 介 |
|---|---|---|
| pageContext | javax.servlet.jsp.PageContext | JSP 页面容器。 |
| request | javax.servlet.http.HttpServletRequest | 客户端向服务器端发送的请求信息。 |
| response | javax.servlet.http.HttpServletResponse | 服务器端向客户端的响应信息。 |
| session | javax.servlet.http.HttpSession | 客户端与服务器端的一次会话。 |
| application | javax.servlet.ServletContext | 可存放全局变量,实现用户间数据的共享。 |
| config | javax.servlet.ServletConfig | 服务器配置信息,可以取得初始化参数。 |
| out | javax.servlet.jsp.JspWriter | 向客户端输出内容。 |
| page | java.lang.Object | 当前 JSP 页面本身,类似于 Java 类中的 this 关键字。 |
| exception | java.lang.Throwable | 当一个页面在运行过程中发生异常时,就会产生这个对象。 |
JSP 内置对象:out
out 用于向客户端(注意这里的客户端是指浏览器,而非控制台)输出数据,最常用的是 out.print();。需要注意的是 out.println() 或者 out.print("\n") 均不能实现在客户端的换行功能,因为浏览器中只能识别 br 等 HTML 换行符,而不能识别 \n 转义符。
将我们的 index.jsp 改成以下代码。
<html>
<head>
<title>First Web Project</title>
</head>
<body>
<%
out.println("hello");
out.print("world\n");
out.print("hello world");
%>
</body>
</html>
使用命令启动 Tomcat。
在打开的页面地址中添加 /JspProject/src/main/webapp/index.jsp
JSP 内置对象:request
request 对象主要用于存储“客户端发送给服务器端的请求信息”,如下图所示。因此可以通过 request 对象来获取用户发送的相关数据。接下来将通过案例来演示 request 的使用。
| 方 法 | 简 介 |
|---|---|
| public String getParameter(String name) | 获取客户端发送给服务器端的参数值。(由 name 指定的唯一参数值,如单选框、密码框等前端 form 表单的值)。 |
| public String[] getParameterValues(String name) | 获取客户端发送给服务器端的参数值。(由 name 指定的多个参数值,如复选框的值)。 |
| public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException | 指定请求的编码,用于解决乱码问题。 |
| public RequestDispatcher getRequestDispatcher(String path) | 返回 RequestDispatcher 对象,该对象的 forward() 方法用于转发请求。 |
| public HttpSession getSession() | 返回和请求相关 Session。 |
| public ServletContext getServletContext() | 获取 web 应用的 ServletContext 对象。 |
下面我们将通过一个简单的注册及显示的实验,演示上述部分方法的使用。
- 在我们之前的项目中创建一个
register.jsp,并输入以下代码。
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>用户注册</title>
</head>
<body>
<form action="show.jsp" method="post" >
用户名:<input type="text" name="uname" /><br/>
密码:<input type="password" name="upwd" /><br/>
兴趣:<br/>
足球<input type="checkbox" name="hobby" value="足球"/>
篮球<input type="checkbox" name="hobby" value="篮球"/>
羽毛球<input type="checkbox" name="hobby" value="羽毛球"/><br/>
<input type="submit" value="注册" />
</form>
</body>
</html>
- 在项目中创建
show.jsp并写入以下代码。
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>用户注册</title>
</head>
<body>
<%
// 将请求的编码与页面保持一致,设置为UTF-8
request.setCharacterEncoding("UTF-8");
// 获取表单中name值为uname元素的value值
String name = request.getParameter("uname");
// 获取表单中name值为upwd元素的value值
String pwd = request.getParameter("upwd");
// 获取表单中,已选name值为hobby元素的value数组值
String[] hobbies = request.getParameterValues("hobby");
%>
您注册的信息如下:<br/>
用户名:<%=name %> <br/>
密码:<%=pwd %> <br/>
爱好:
<%
if(hobbies != null)
{
for(int i=0 ; i<hobbies.length ;i++)
{
out.print(hobbies[i]+" ");
}
}
%>
</body>
</html>
- 使用命令重启 Tomcat,在地址栏中新增
/JspProject/src/main/webapp/register.jsp得到以下结果。
- 尝试在 register.jsp 中填写信息,并在 show.jsp 成功接收到信息。
在程序 show.jsp 中,通过 request.setCharacterEncoding("UTF-8") 将 post 方式的编码设置为 UTF-8,并通过 request.getParameter() 和 request.getParameterValues() 方法获取到了从表单传来的数据。
需要注意的是,客户端的数据不一定必须从表单传递过来,也可以通过 URL 地址进行传递,格式如下。
页面地址?参数名1=参数内容1&参数名2=参数内容2&…
即通过“?”将页面地址和参数分离,然后按照 “ 参数名=参数内容 ” 的格式来传递数据,并且多个参数之间用“&”分隔。例如,上例中可以不运行注册页 register.jsp ,而直接在浏览器中你的 url 后面加上,/JspProject/src/main/webapp/show.jsp?uname=李四&upwd=123&hobby=足球&hobby= 篮球,也能正常运行程序,并得到运行结果,如图所示。
仔细观察以下表单提交和 URL 地址提交两种方式的地址栏。
① 表单提交方式的地址栏:/JspProject/show.jsp。
② URL 地址提交方式的地址栏:/JspProject/show.jsp?uname=李四&upwd=123&hobby=足球&hobby=篮球。
这两种地址不同的本质原因在于表单的提交方式,在 register.jsp 中有一行代码:
<form action="show.jsp" method="post" >
其中,method 就可以用来指定表单的提交方式,常用属性值有 get 和 post 两种。
当 method="post" 时,表示以 post 方式请求表单,请求后的地址为 / JspProject/show.jsp。
如果改为 method="get",再次提交表单,则地址栏显示: / show.jsp?uname=李四&upwd=123&hobby=足球&hobby=篮球。
说明:如果“ URL 地址传递”中的值是中文,而 JSP 页面编码是 UTF-8 时,则会显示乱码。原因是“ URL 地址传递”使用的是 get 方式传递数据,而 get 方式的默认编码是 ISO-8859-1 ,与 JSP 页面编码 UTF-8 不一致。解决方法就是将 get 方式提交的数据进行统一字符编码。
解决乱码
了解完 get 方式和 post 方式的区别后,再来看看两种方式是如何解决字符乱码问题的。
解决 Web 项目乱码问题的基本步骤如下(以将编码统一为 UTF-8 为例)。
- 将所有 JSP 文件的编码设置为 UTF-8 ,如下。
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
…
- 对于
get或post方式,实施不同的统一编码操作。
首先要知道 Tomcat 服务器,默认使用的编码方式是 ISO-8859-1。
如果以 get 方式提交表单(或 URL 地址传递的方式),则处理编码的方式有以下方法:
分别把每个变量的编码方式从 ISO-8859-1 转为 UTF-8。
代码如下:
// 将name的编码方式,从ISO-8859-1转为UTF-8
String name = request.getParameter("uname");
name = new String(name.getBytes("ISO-8859-1"), "UTF-8");
// 将pwd的编码方式,从ISO-8859-1转为UTF-8
String pwd = request.getParameter("upwd");
pwd = new String(pwd.getBytes("ISO-8859-1"), "UTF-8");
JSP 内置对象:response
通过前面的学习知道,客户端可以通过 request 向服务器端发送请求数据,那么反过来会怎样呢? 当服务器端接收到请求的数据后,如何向客户端响应呢?答案就是 response ,即服务器端可以通过 response 向客户端做出响应,如图所示。
response 也提供了一些方法来处理响应,如表所示。
| 方 法 | 简 介 |
|---|---|
| public void addCookie(Cookie cookie) | 服务器端向客户端增加 Cookie 对象 |
| public void sendRedirect(String location) throws IOException | 将客户端发来的请求,重新定位(跳转)到另一个 URL 上(习惯上称为“重定向”) |
| public void setContentType(String type) | 设置服务器端响应的 contentType 类型 |
首先来了解一下重定向方法 sendRedirect() 的使用。
接下来我们需要完成一个登录功能的实验(用户输入用户名和密码,如果验证正确,则跳转到欢迎页)。
- 在我们之前的
JspProject中的项目里新建一个login.jsp并在其中写入以下代码:
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>用户登陆</title>
</head>
<body>
<form action="check.jsp" method="post" >
用户名:<input type="text" name="uname" /><br/>
密码:<input type="password" name="upwd" /><br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
- 重启 Tomcat 服务器,在弹出的页面地址栏添加
/JspProject/src/main/webapp/login.jsp,并输入用户名“zs”,密码“abc”。
3. 新建验证页
check.jsp,并写入以下代码。
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>登陆验证</title>
</head>
<body>
<%
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("uname");
String pwd = request.getParameter("upwd");
// 假设用户名为“zs”且密码为“abc”时,登录验证成功
if(name.equals("zs") && pwd.equals("abc")){
// 若验证成功,则重定向到success.jsp页面
response.sendRedirect("success.jsp");
}
%>
</body>
</html>
- 若登录成功则跳转成功页面,新建
success.jsp。
<%@ page pageEncoding="UTF-8"%>
<html>
<head>
<title>登陆成功</title>
</head>
<body>
登录成功!<br/>
欢迎您:<br/>
<%
String name = request.getParameter("uname");
out.print(name);
%>
</body>
</html>
运行结果:
从“运行结果”可以发现以下两点:
- 如果用户名和密码验证成功,确实跳转到了欢迎页
success.jsp,但数据却丢失了,用户名name的值为 null 。 - 重定向到
success.jsp后,地址栏也变成了success.jsp页面的地址。
为了解决重定向后数据丢失的问题,先来回忆一下 Request 对象中的一个方法。
public RequestDispatcher getRequestDispatcher(String path)
前面讲过,此方法的返回值 RequestDispatcher 对象,有一个 forward()方法可以用于转发请求,也就是说,request 的 getRequestDispatcher()方法和 response 的 sendRedirect()方法有相同之处:都可以实现页面之间的跳转。
现将 check.jsp 中的 response.sendRedirect("success.jsp") 改为 request.getRequestDispatcher ("success.jsp").forward(request, response),其他代码均不变,再次运行程序,可以发现以下两点:
① 可以获取到客户端发送的表单数据;
② 页面内容确实跳转到了 success.jsp 中编写的内容,但地址栏仍然停留在 check.jsp,即采用请求转发方式,地址栏不会发生改变。
转发和重定向
为了解决重定向后数据丢失的问题,先来回忆一下 Request 对象中的一个方法。
public RequestDispatcher getRequestDispatcher(String path)
前面讲过,此方法的返回值 RequestDispatcher 对象,有一个 forward() 方法可以用于转发请求,也就是说,request 的 getRequestDispatcher() 方法和 response 的 sendRedirect() 方法有相同之处:都可以实现页面之间的跳转。
现将 check.jsp 中的 response.sendRedirect("success.jsp") 改为 request.getRequestDispatcher ("success.jsp").forward(request, response) ,其他代码均不变,再次运行程序,其 success.jsp 页面如图所示。
由上图可以发现,采用
request.getRequestDispatcher("success.jsp").forward(request, response) 来跳转页面后:
- 可以获取到客户端发送的表单数据。
- 页面内容确实跳转到了 success.jsp 中编写的内容,但地址栏仍然停留在 check.jsp ,即采用请求转发方式,地址栏不会发生改变。
关于请求转发(request.getRequestDispatcher("xx").forward(request, response))和重定向(response.sendRedirect("xx"))的区别,这些内容经常会在面试中被提到,特在此做一个总结,如下表所示。
| 请求转发(forward()) | 重定向(redirect()) | |
|---|---|---|
| 请求服务器次数 | 1 次 | 2 次 |
| 是否保留第一次请求时 request 范围中的属性 | 保留 | 不保留 |
| 地址栏里的请求 URL,是否改变 | 不变 | 改变为重定向之后的新目标 URL。相当于在地址栏里重新输入 URL 后再按回车键 |
关于“请求服务器次数”问题的详尽分析如下。
请求转发:
- 客户端(浏览器)向服务器的资源 A 发起一次请求 ①。
- 服务器的资源 A 接收到该请求后,将该请求转发到内部的其他资源 B ②。
- 资源 B 处理完请求后,最终给客户端做出响应 ③。
如图所示:
重定向:
- 客户端(浏览器)向服务器的资源 A 发起一次请求 ①。
- 服务器的资源 A 接收到该请求后,给客户端做出响应,告诉客户端去重新访问资源 B 的地址 ②。
- 客户端收到资源 B 的地址后再次向服务器的资源 B 发出第二次请求 ③。
- 服务器资源 B 处理完该请求并做出响应 ④。
如图所示:
在此可以将“请求转发”和“重定向”想象成以下情景。
请求转发:张三去银行的 A 窗口办理业务,A 窗口的业务员发现自己办不了该业务,就将张三的业务请求转发给其他同事办理,最后将办理完的业务返回给张三。也就是说,张三只是给银行的 A 窗口发送了一次请求,而该业务办理人员之间的换人工作,是由银行内部处理的,即张三只发出了一次请求,更换窗口业务员(跳转)是银行的行为。
重定向:张三去银行的 A 窗口办理业务,A 窗口的业务员发现自己办不了该业务,然后告诉张三应该重新去窗口 B 办理,张三收到该消息后,又重新向银行的窗口 B 再次请求办理业务,最终银行的窗口 B 处理完张三的请求,并将办理完的业务返回给张三。也就是说,张三分别向银行的窗口 A、窗口 B 各发送了一次请求(共 2 次请求),更换窗口业务员(跳转)是张三的行为。
。。。未完待续。。。