JSP 环境配置与使用

273 阅读15分钟

学习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

图片描述

用鼠标右键单击网页空白处,查看页面源代码,如下图所示。

图2.4

显示内容如下图所示。

图片描述 其中 <!-- --> 注释可以通过客户端(浏览器)查看到,而 JSP 注释和 Java 注释无法被客户端直接查看。

JSP 内置对象

我们曾经接触过如下代码:

<%
    String bookName ="《jsp环境配置与使用》";
    String author = "掘金" ;
    out.print("书名:"+bookName+"<br/>作者:"+author);
%>

在上述代码中,像 out 这样没有定义和实例化(new)就可以直接使用的对象,称为内置对象。除了 out 外,JSP 还提供了其他的一些内置对象,共有九个。

内 置 对 象类 型简 介
pageContextjavax.servlet.jsp.PageContextJSP 页面容器。
requestjavax.servlet.http.HttpServletRequest客户端向服务器端发送的请求信息。
responsejavax.servlet.http.HttpServletResponse服务器端向客户端的响应信息。
sessionjavax.servlet.http.HttpSession客户端与服务器端的一次会话。
applicationjavax.servlet.ServletContext可存放全局变量,实现用户间数据的共享。
configjavax.servlet.ServletConfig服务器配置信息,可以取得初始化参数。
outjavax.servlet.jsp.JspWriter向客户端输出内容。
pagejava.lang.Object当前 JSP 页面本身,类似于 Java 类中的 this 关键字。
exceptionjava.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

image.png

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 对象。

下面我们将通过一个简单的注册及显示的实验,演示上述部分方法的使用。

  1. 在我们之前的项目中创建一个 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>
  1. 在项目中创建 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]+"&nbsp");
              }
           }
        %>
    </body>
</html>
  1. 使用命令重启 Tomcat,在地址栏中新增 /JspProject/src/main/webapp/register.jsp 得到以下结果。

图片描述

  1. 尝试在 register.jsp 中填写信息,并在 show.jsp 成功接收到信息。

image.png

image.png

在程序 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 为例)。

  1. 将所有 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">
…
  1. 对于 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() 的使用。

接下来我们需要完成一个登录功能的实验(用户输入用户名和密码,如果验证正确,则跳转到欢迎页)。

  1. 在我们之前的 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>
  1. 重启 Tomcat 服务器,在弹出的页面地址栏添加 /JspProject/src/main/webapp/login.jsp,并输入用户名“zs”,密码“abc”。

image.png 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>
  1. 若登录成功则跳转成功页面,新建 success.jsp
<%@ page pageEncoding="UTF-8"%>
<html>
    <head>
        <title>登陆成功</title>
    </head>
    <body>
        登录成功!<br/>
        欢迎您:<br/>
        <%
            String name = request.getParameter("uname");
            out.print(name);
        %>
    </body>
</html>

运行结果:

图片描述

从“运行结果”可以发现以下两点:

  1. 如果用户名和密码验证成功,确实跳转到了欢迎页 success.jsp ,但数据却丢失了,用户名 name 的值为 null 。
  2. 重定向到 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),其他代码均不变,再次运行程序,可以发现以下两点:

① 可以获取到客户端发送的表单数据;

image.png ② 页面内容确实跳转到了 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) 来跳转页面后:

  1. 可以获取到客户端发送的表单数据。
  2. 页面内容确实跳转到了 success.jsp 中编写的内容,但地址栏仍然停留在 check.jsp ,即采用请求转发方式,地址栏不会发生改变。

关于请求转发(request.getRequestDispatcher("xx").forward(request, response))和重定向(response.sendRedirect("xx"))的区别,这些内容经常会在面试中被提到,特在此做一个总结,如下表所示。

请求转发(forward())重定向(redirect())
请求服务器次数1 次2 次
是否保留第一次请求时 request 范围中的属性保留不保留
地址栏里的请求 URL,是否改变不变改变为重定向之后的新目标 URL。相当于在地址栏里重新输入 URL 后再按回车键

关于“请求服务器次数”问题的详尽分析如下。

请求转发:

  1. 客户端(浏览器)向服务器的资源 A 发起一次请求 ①。
  2. 服务器的资源 A 接收到该请求后,将该请求转发到内部的其他资源 B ②。
  3. 资源 B 处理完请求后,最终给客户端做出响应 ③。

如图所示:

图片描述

重定向:

  1. 客户端(浏览器)向服务器的资源 A 发起一次请求 ①。
  2. 服务器的资源 A 接收到该请求后,给客户端做出响应,告诉客户端去重新访问资源 B 的地址 ②。
  3. 客户端收到资源 B 的地址后再次向服务器的资源 B 发出第二次请求 ③。
  4. 服务器资源 B 处理完该请求并做出响应 ④。

如图所示:

图片描述

在此可以将“请求转发”和“重定向”想象成以下情景。

请求转发:张三去银行的 A 窗口办理业务,A 窗口的业务员发现自己办不了该业务,就将张三的业务请求转发给其他同事办理,最后将办理完的业务返回给张三。也就是说,张三只是给银行的 A 窗口发送了一次请求,而该业务办理人员之间的换人工作,是由银行内部处理的,即张三只发出了一次请求,更换窗口业务员(跳转)是银行的行为。

重定向:张三去银行的 A 窗口办理业务,A 窗口的业务员发现自己办不了该业务,然后告诉张三应该重新去窗口 B 办理,张三收到该消息后,又重新向银行的窗口 B 再次请求办理业务,最终银行的窗口 B 处理完张三的请求,并将办理完的业务返回给张三。也就是说,张三分别向银行的窗口 A、窗口 B 各发送了一次请求(共 2 次请求),更换窗口业务员(跳转)是张三的行为。

。。。未完待续。。。