不得不说,JSP 现在已经是一门十分老旧的技术了,学习编程时,不仅要学习优秀的前言技术,还要对基础有一定的把握,所以学习 JSP 时,我们只做了解,不用刨根问底花费大量的时间,得不偿失。
我们主要从以下几个方面学习 JSP 技术:
学习 JSP 到什么程度呢?我们只需要能够使用 JSP 相关技术能够实现简单数据的增删改查即可。
JSP,Java Server Pages,指的是 Java 服务端页面,是一种动态的网页技术,其中既可以定义 HTML,CSS,JavaScript 静态内容,也可以使用 Java 代码定义动态内容。通俗的说,JSP = HTML + Java 。下面就是一个最简单的 JSP 代码:
title
HelloWorld
<%
System.out.println("HelloWorld!");
%>
上面的例子中,html 里面的内容会在浏览器渲染,而 Java 代码的输出语句会打印在 idea 控制台。
那么 JSP 到底是用来做什么的?我们如何实现不同用户登录网页显示不同的信息呢?例如,在页面上显示登录的用户名:
在 Servlet 中,我们使用 write 对象向浏览器写数据,html 标签可以作为字符串传入 write() 方法中。但是,当向页面写出大量数据时,代码显得十分的混乱不堪,并且后期后期维护成本极大。而 JSP 就结局了这个问题,在 JSP 代码中可以直接使用 html 标签,动态数据也可以使用 Java 代码展示,大大的简化了开发,避免了在 Servlet 中直接输出 html 标签。
在 idea 中创建一个 Maven Web 项目,项目结构如下:
在 pom.xml 添加 Servlet 的依赖坐标和 TomCat 插件坐标,如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.chengzigroupId>
<artifactId>jsp-demoartifactId>
<packaging>warpackaging>
<version>1.0-SNAPSHOTversion>
<name>jsp-demo Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
plugin>
plugins>
<finalName>jsp-demofinalName>
build>
project>
在 pom.xml 中添加 JSP 的依赖坐标,如下:
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
在项目的 webapps 文件目录下创建 jsp 页面,如图:
通过上面的操作创建一个名为 hello.jsp 的页面。
在 hello.jsp 中书写 HTML 标签和 Java 代码,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
HelloWorld
<%
System.out.println("helloWorld!");
%>
启动 Tomcat 服务器,在浏览器访问 http://localhost:8080/jsp-demo/hello.jsp
,结果如下:
之前,我们在 jsp 中不仅编写了 html 标签,还编写了 Java 代码,为什么呢?其实,JSP 本质上就是一个 Servlet。要弄明白这个问题,我们就要研究 jsp 的执行流程。
在上面的例子中,浏览器第一次访问 heelo.jsp 页面时,Tomcat 会将 hello.jsp 装换为名为 hello_jsp.java 的一个Servlet, 然后 这个 Servlet 会被 TomCat 编译为字节码文件 hello_jsp.class 。TomCat 会执行该字节码文件向外提供服务。
此时在项目磁盘目录下找到 target\tomcat\work\Tomcat\localhost\jsp-demo\org\apache\jsp
,在这个文件目录下就可以看到装换后的 Servlet 和编译后的 .class
文件。如图:
打开 hello_jsp.java 文件查看源码,如图:
可以发现转换后的 hello_jsp 类继承自 HttpJspBase ,其实 HttpJspBase 类是继承自 HttpServlet 的,我们可以查看 TomCat 源码,所以 hello_jsp 类间接继承了 HttpServlet ,也就是说,JSP 容器将 JSP 文件装换成了一个 Servlet。
在 hello_jsp 类中还有一个 _jspService() 方法,该方法和 Servlet 中的 service 方法类似,在每次访问警示牌 jsp 时自动执行。如图:
在 _jspService() 方法中可以看到完浏览器中写的标签和 Java 代码,如下:
不难看出,在 <%...%>
中的 Java 代码被放到了 _jspService() 方法中,这段 Java 代码被称为 JSP 脚本。
JSP 脚本用于在 JSP 页面内定义 Java 代码,之前案例中使用到的 Java 代码就是定义在 JSP 脚本中的,JSP 脚本一共分为 3 类:
<%…%> 内容会直接放到 _jspService() 方法中
<%=…%> 内容或被放到 out.print() 中,作为该的方法的参数
<%!..%> 内容会被放到 _jspService() 方法之外,被类直接包括
代码演示:
第一步:在 hello.jsp 中编写代码:
<%
System.out.println("hello");
int i = 3;
%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现 i 变量被定义在 _jspService() 方法中,如图:
第二步:在 hello.jsp 中编写代码:
<%="hello"%>
<%=i%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现 i 变量成为了 out.print() 方法的参数,并且这两个数据被发送到了浏览器展示给用户,如图:
第三步:在 hello.jsp 中编写代码:
<%!
void show(){}
String name = "zhangsan";
%>
通过浏览器访问该资源,查看转换后的 hello_jsp.java 源代码,不难发现该部分被放到了类的成员部分,如图:
使用 JSP 在浏览器以表格的形式展示学生信息的数据,这里的数据应该使用 MyBatis 在数据库中查找,但是这里只是简单的演示 JSP 的使用,所以我们省略了对数据库的操作,直接将数据封装到 Student 对象中并存放在集合中。
首先我们在 org.chengzi.pojo 包下创建一个实体类 Student 。在 Java 文件目录右击 new / Java class ,创建包和类。如下:
public class Student {
private int id;
private String name;
private String gender;
private int scoreEnglish;
private int scoreMath;
//省略了getter和setter方法以及重写的Object类的toString方法
}
在项目 webapps 目录下创建 student.jsp,在此文件中写 html 标签和 Java 代码,我们可以先将数据写死,方便展示在浏览器。如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
序号
姓名
性別
英语成绩
数学成绩
操作
1
张三
男
100
100
修改 删除
2
李四
男
100
100
修改 删除
3
王五
女
100
100
修改 删除
在浏览器访问该资源,效果如下:
准备需要动态展示到浏览器的数据,这里省略了从数据库查询数据,我们直接将数据封装在 Student 对象中,并将所有对象放在集合中。例如:
<%
// 查询数据库
List brands = new ArrayList();
brands.add(new Student(1,小张,女,85,89));
brands.add(new Student(2,小樊,女,98,87));
brands.add(new Student(3,小李,男,100,99));
%>
上面我们使用固定的数据发送到浏览器展示,为了动态的展示数据,我们要使用 Java 代码来动态的获取数据,而在 JSP 页面中,Java 代码要写在 JSP 脚本中,如下:
<%@ page import="org.chengzi.pojo.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 查询数据库
List students = new ArrayList();
students.add(new Student(1, "小张", "男", 80, 85));
students.add(new Student(2, "小李", "女", 98, 87));
students.add(new Student(3, "小樊", "女", 98, 100));
%>
Title
序号
姓名
性別
英语成绩
数学成绩
操作
<%
for (int i = 0; i < students.size(); i++) {
//获取集合中的 每一个 Brand 对象
Student student = students.get(i);
%>
<%=student.getId()%>
<%=student.getName()%>
<%=student.getGender()%>
<%=student.getScoreEnglish()%>
<%=student.getScoreMath()%>
修改 删除
<%
}
%>
此时,数据就会被动态的展示到浏览器页面,不难看出,其实 JSP 脚本标签就是在分割 Java 代码,在标签内是 Java 代码,在标签外则是 html 语句,如图:
不难看出,JSP 开发还是有很多的缺点的,首先,既然在 jsp 文件中既可以写 html 标签,有可以写 Java 代码,导致了书写麻烦和阅读麻烦的问题。并且其运行要依赖各种环境,例如 jre,jsp 容器,JavaEE 等等,导致其程序变得十分复杂。
JSP 会自动生成 .java 文件和 .class 文件占用了磁盘空间,而运行 .class 文件占用内存。在程序出错以后,我们一般要找到自动生成的 .java 文件进行调试,导致了调试困难的问题。
另外,把 Java 代码和 html 代码混在一个文件中是非常不利于团队开发的,如果页面出现问题,首先前端开发工程师修改静态页面,然后由后端开发来将该页面修改为 JSP 页面,这不是我们想看到的合作开发方式。
由于 JSP 存在着很多的确定,并且随着软件技术的发展,JSP 已经逐渐退出历史的舞台了,后面我们会学习新的技术 AJAX 来替代前面的方式,有了这个技术以后,前端工程师只负责前端页面的开发,而后端工程师只负责后端代码的开发,职责单一高效。
当然,我们并不是说后端开发就不用学习前端的知识,即使你是专注于后端开发,前端的知识你同样要了解,任何一个说后端不用了解前端知识的说法都是不负责任大额。
下面我们看一下服务器页面技术的发展过程,聊聊为什么 JSP 既然已经被淘汰,为什么我们还要学习呢?
第一阶段:
使用 Servlet 技术实现逻辑代码的编写,也对页面进行拼接。
第二阶段:
随着技术的发展,出现了 JSP,JSP 确实使用比 Servlet 方便了很多,但是随着时间的发展,JSP 的很多确定都暴露出来了。
第三阶段:
使用 Servlet 进行逻辑开发,使用 JSP 进行数据的展示。
第四阶段:
使用 Servlet 进行后端逻辑代码的开发,使用 HTML 进行数据的展示,html 是静态页面,为了展示动态数据,出现了新的技术 AJAX。
现在我们学习 JSP 时,大概有两个原因,一是一些公司的老项目仍然使用了 JSP,所以为了项目的维护,我们不得不学习,另外,学习技术是一个循序渐进的过程,我们必须一步一步的学习,虽然 JSP 老旧过时,但是其中的编程思想使我们学习编程过程中应该了解的。
前面说到,使用 Servlet 进行逻辑开发,使用 JSP 来获取数据,遍历展现数据,这样的方式解决了 JSP 页面中 Java 代码混乱的问题,接下来看一看如何使用 EL 表达式和 JSTL 标签库来替代 JSP 页面中的 Java 代码。
EL ,Expression Language,称为表达式语言,用于简化 JSP 页面内的 Java 代码。EL 表达式的主要作用是获取数据,期数就是从域对象中获取数据,然后将数据展示在页面上。
EL 表达式的语法比较简单,使用${expression}
,例如 ${student} 就是获取域对象中存储的 key 为 student 的数据。
定义一个 Servlet,在 Servlet 中封装数据并存储到 request 域对象中并转发到 el-demo.jsp 页面。
@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//准备数据
List<Student> students = new ArrayList<Student>();
students.add(new Student(1,"张三","男",100,100));
students.add(new Student(2,"李四","女",98,98));
//存储到request域对象中(使用request转发,将request作为域对象)
request.setAttribute("students",students);
//发送到 el-demo.jsp 页面
request.getRequestDispatcher("/el-demo.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
在 el-demo.jsp 中通过 EL 表达式来获取数据,EL 表示式后面不需要加分号。例如:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
Title
${students}
如果 JSP 中没有接收到 Servlet 共享的数据,如图:
解决方法:在 JSP 代码中添加:
isELIgnored="false"
添加位置在:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
上面我们在 Servlet 中使用转发将 request 作为域对象进行数据共享,那么什么是域对象?域对象有哪些呢?
在 JavaWeb 中,一共有四大域对象,分别是:
如图所示:
EL 表达式获取数据,会一次从四个域中寻找,知道找到为止。
例如,例如 EL 表达式 ${students} 会先从 page 域对象中获取数据,如果没有找到,再去 request 域对象中获取数据,一次寻找,直到找到数据。
前端开发工程师每天都在和标签打交道,他们对标签是更加敏感的,所以出现了 JSTL 标准标签库,使用标签替代了 JSP 页面中的 Java 代码,提高了代码的可读性。如下:
男
女
JSTL,Jsp Standarded Tag Library,JSP 标准标签库,其中提供了丰富的标签用于取代 JSP 页面中的 Java 代码,例如:
标签 | 描述 |
---|---|
|
用于在JSP中显示数据,就像<%= … > |
|
用于保存数据 |
|
用于删除数据 |
|
用来处理产生错误的异常状况,并且将错误信息储存起来 |
|
与我们在一般程序中用的if一样 |
|
本身只当做 和 的父标签 |
|
的子标签,用来判断条件是否成立 |
|
的子标签,接在 标签后,当 标签判断为false时被执行 |
|
检索一个绝对或相对 URL,然后将其内容暴露给页面 |
|
基础迭代标签,接受多种集合类型 |
|
根据指定的分隔符来分隔内容并迭代输出 |
|
用来给包含或重定向的页面传递参数 |
|
重定向至一个新的URL. |
|
使用可选的查询参数来创造一个URL |
使用 JSTL 之前要先导入依赖和引入标签库,例如在 pom.xml 中添加依赖坐标:
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
在 JSP 页面中引入 JSTL 标签库:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
下面举例练习几个常用的标签。
标签相当于 Java 中的if判断语句,示例:定义一个 Servlet,在 Servlet 中向 request 域对象中添加键为 status,值为 1 的数据。
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//存储数据到request域对象中
request.setAttribute("status",1);
//发送到 jstl.jsp页面
request.getRequestDispatcher("/jstl.jsp").forward(request,response);
}
定义 jstl.jsp 页面,使用
标签进行判断:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--
c:if:来完成逻辑判断,替换java if else
--%>
启用
禁用
标签相当于 Java 中的 for 循环,Java 中有普通 for 循环和增强 for 循环,其实在 JSTL 中的循环标签也有两种用法:
第一种用法类似于 Java 中的普通 for 循环,其中主要使用到的属性有:
示例:
${i}
第二种用法类似于 Java 中的增强 for 循环,主要使用的属性有:
示例:
${student.id}
${student.brandName}
${student.companyName}
${student.description}
上面例子中,首先从域对象中获取了 students 数据,该数据是一个集合,遍历结合,并给集合中每一个对象起名为 student ,在循环中使用了 EL 表达式获取每一个 Student 对象的属性值。
你问我青春还剩几年?我的回答是,趁现在,正当时。身边朋友都在问我怎样学好一门编程语言,怎样学好Java?怎样通过 Java 找到一份满意的工作?推荐学习此专栏:Java编程基础教程系列(零基础小白搬砖逆袭)
下期见。