4.2.2 实现
将资料 资料\1. JSP案例素材
中的 Brand.java
文件放置到项目的 com.itheima.pojo
包下
在项目的 webapp
中创建 brand.jsp
,并将 brand.html
页面中的内容拷贝过来。brand.jsp
内容如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr> <table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <tr align="center"> <td>1</td> <td>三只松鼠</td> <td>三只松鼠</td> <td>100</td> <td>三只松鼠,好吃不上火</td> <td>启用</td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> <tr align="center"> <td>2</td> <td>优衣库</td> <td>优衣库</td> <td>10</td> <td>优衣库,服适人生</td> <td>禁用</td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> <tr align="center"> <td>3</td> <td>小米</td> <td>小米科技有限公司</td> <td>1000</td> <td>为发烧而生</td> <td>启用</td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> </table> </body> </html>
现在页面中的数据都是假数据。
在 brand.jsp
中准备一些数据
<% // 查询数据库 List<Brand> brands = new ArrayList<Brand>(); brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1)); brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0)); brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1)); %>
==注意:==这里的类是需要导包的
将 brand.jsp
页面中的 table
标签中的数据改为动态的
<table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <% for (int i = 0; i < brands.size(); i++) { //获取集合中的 每一个 Brand 对象 Brand brand = brands.get(i); } %> <tr align="center"> <td>1</td> <td>三只松鼠</td> <td>三只松鼠</td> <td>100</td> <td>三只松鼠,好吃不上火</td> <td>启用</td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> </table>
上面的for循环需要将 tr
标签包裹起来,这样才能实现循环的效果,代码改进为
<table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <% for (int i = 0; i < brands.size(); i++) { //获取集合中的 每一个 Brand 对象 Brand brand = brands.get(i); %> <tr align="center"> <td>1</td> <td>三只松鼠</td> <td>三只松鼠</td> <td>100</td> <td>三只松鼠,好吃不上火</td> <td>启用</td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> <% } %> </table>
注意:<%%> 里面写的是 Java 代码,而外边写的是 HTML 标签
上面代码中的 td
标签中的数据都需要是动态的,所以还需要改进
<table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <% for (int i = 0; i < brands.size(); i++) { //获取集合中的 每一个 Brand 对象 Brand brand = brands.get(i); %> <tr align="center"> <td><%=brand.getId()%></td> <td><%=brand.getBrandName()%></td> <td><%=brand.getCompanyName()%></td> <td><%=brand.getOrdered()%></td> <td><%=brand.getDescription()%></td> <td><%=brand.getStatus() == 1 ? "启用":"禁用"%></td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> <% } %> </table>
4.2.3 成品代码
<%@ page import="com.itheima.pojo.Brand" %> <%@ page import="java.util.List" %> <%@ page import="java.util.ArrayList" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <% // 查询数据库 List<Brand> brands = new ArrayList<Brand>(); brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1)); brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0)); brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1)); %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr> <table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <% for (int i = 0; i < brands.size(); i++) { Brand brand = brands.get(i); %> <tr align="center"> <td><%=brand.getId()%></td> <td><%=brand.getBrandName()%></td> <td><%=brand.getCompanyName()%></td> <td><%=brand.getOrdered()%></td> <td><%=brand.getDescription()%></td> <td><%=brand.getStatus() == 1 ? "启用":"禁用"%></td> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> <% } %> </table> </body> </html>
4.2.4 测试
在浏览器地址栏输入 http://localhost:8080/jsp-demo/brand.jsp
,页面展示效果如下
4.3 JSP 缺点
通过上面的案例,我们可以看到 JSP 的很多缺点。
由于 JSP页面内,既可以定义 HTML 标签,又可以定义 Java代码,造成了以下问题:
书写麻烦:特别是复杂的页面
既要写 HTML 标签,还要写 Java 代码
阅读麻烦
上面案例的代码,相信你后期再看这段代码时还需要花费很长的时间去梳理
复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE…
占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
调试困难:出错后,需要找到自动生成的.java文件进行调试
不利于团队协作:前端人员不会 Java,后端人员不精 HTML
如果页面布局发生变化,前端工程师对静态页面进行修改,然后再交给后端工程师,由后端工程师再将该页面改为 JSP 页面
由于上述的问题, ==JSP 已逐渐退出历史舞台,==以后开发更多的是使用 HTML + Ajax 来替代。Ajax 是我们后续会重点学习的技术。有个这个技术后,前端工程师负责前端页面开发,而后端工程师只负责前端代码开发。下来对技术的发展进行简单的说明
第一阶段:使用 servlet
即实现逻辑代码编写,也对页面进行拼接。这种模式我们之前也接触过
第二阶段:随着技术的发展,出现了 JSP
,人们发现 JSP
使用起来比 Servlet
方便很多,但是还是要在 JSP
中嵌套 Java
代码,也不利于后期的维护
第三阶段:使用 Servlet
进行逻辑代码开发,而使用 JSP
进行数据展示
第四阶段:使用 servlet
进行后端逻辑代码开发,而使用 HTML
进行数据展示。而这里面就存在问题,HTML
是静态页面,怎么进行动态数据展示呢?这就是 ajax
的作用了。
那既然 JSP 已经逐渐的退出历史舞台,那我们为什么还要学习 JSP
呢?原因有两点:
- 一些公司可能有些老项目还在用
JSP
,所以要求我们必须动JSP
- 我们如果不经历这些复杂的过程,就不能体现后面阶段开发的简单
接下来我们来学习第三阶段,使用 EL表达式
和 JSTL
标签库替换 JSP
中的 Java
代码。
5,EL 表达式
5.1 概述
EL(全称Expression Language )表达式语言,用于简化 JSP 页面内的 Java 代码。
EL 表达式的主要作用是 获取数据。其实就是从域对象中获取数据,然后将数据展示在页面上。
而 EL 表达式的语法也比较简单,==
5.2 代码演示
定义servlet,在 servlet 中封装一些数据并存储到 request 域对象中并转发到 el-demo.jsp
页面。
@WebServlet("/demo1") public class ServletDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 准备数据 List<Brand> brands = new ArrayList<Brand>(); brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1)); brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0)); brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1)); //2. 存储到request域中 request.setAttribute("brands",brands); //3. 转发到 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); } }
注意: 此处需要用转发,因为转发才可以使用 request 对象作为域对象进行数据共享
在 el-demo.jsp
中通过 EL表达式 获取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${brands} </body> </html>
在浏览器的地址栏输入 http://localhost:8080/jsp-demo/demo1
,页面效果如下:
5.3 域对象
JavaWeb中有四大域对象,分别是:
- page:当前页面有效
- request:当前请求有效
- session:当前会话有效
- application:当前应用有效
el 表达式获取数据,会依次从这4个域中寻找,直到找到为止。而这四个域对象的作用范围如下图所示
例如: ${brands},el 表达式获取数据,会先从page域对象中获取数据,如果没有再到 requet 域对象中获取数据,如果再没有再到 session 域对象中获取,如果还没有才会到 application 中获取数据。
6,JSTL标签
6.1 概述
JSP标准标签库(Jsp Standarded Tag Library) ,使用标签取代JSP页面上的Java代码。如下代码就是JSTL标签
<c:if test="${flag == 1}"> 男 </c:if> <c:if test="${flag == 2}"> 女 </c:if>
上面代码看起来是不是比 JSP 中嵌套 Java 代码看起来舒服好了。而且前端工程师对标签是特别敏感的,他们看到这段代码是能看懂的。
JSTL 提供了很多标签,如下图
我们只对两个最常用的标签进行讲解, 标签和
标签。
JSTL 使用也是比较简单的,分为如下步骤:
导入坐标
<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>
在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用标签
6.2 if 标签
:相当于 if 判断
- 属性:test,用于定义条件表达式
<c:if test="${flag == 1}"> 男 </c:if> <c:if test="${flag == 2}"> 女 </c:if>
代码演示:
定义一个 servlet
,在该 servlet
中向 request 域对象中添加 键是 status
,值为 1
的数据
@WebServlet("/demo2") public class ServletDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1. 存储数据到request域中 request.setAttribute("status",1); //2. 转发到 jstl-if.jsp 数据request.getRequestDispatcher("/jstl-if.jsp").forward(request,response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
定义 jstl-if.jsp
页面,在该页面使用 标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <%-- c:if:来完成逻辑判断,替换java if else --%> <c:if test="${status ==1}"> 启用 </c:if> <c:if test="${status ==0}"> 禁用 </c:if> </body> </html>
注意: 在该页面已经要引入 JSTL核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
6.3 forEach 标签
:相当于 for 循环。java中有增强for循环和普通for循环,JSTL 中的
也有两种用法
6.3.1 用法一
类似于 Java 中的增强for循环。涉及到的 中的属性如下
items:被遍历的容器
var:遍历产生的临时变量
varStatus:遍历状态对象
如下代码,是从域对象中获取名为 brands 数据,该数据是一个集合;遍历遍历,并给该集合中的每一个元素起名为 brand
,是 Brand对象。在循环里面使用 EL表达式获取每一个Brand对象的属性值
<c:forEach items="${brands}" var="brand"> <tr align="center"> <td>${brand.id}</td> <td>${brand.brandName}</td> <td>${brand.companyName}</td> <td>${brand.description}</td> </tr> </c:forEach>
代码演示:
servlet
还是使用之前的名为 ServletDemo1
。
定义名为 jstl-foreach.jsp
页面,内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="button" value="新增"><br> <hr> <table border="1" cellspacing="0" width="800"> <tr> <th>序号</th> <th>品牌名称</th> <th>企业名称</th> <th>排序</th> <th>品牌介绍</th> <th>状态</th> <th>操作</th> </tr> <c:forEach items="${brands}" var="brand" varStatus="status"> <tr align="center"> <%--<td>${brand.id}</td>--%> <td>${status.count}</td> <td>${brand.brandName}</td> <td>${brand.companyName}</td> <td>${brand.ordered}</td> <td>${brand.description}</td> <c:if test="${brand.status == 1}"> <td>启用</td> </c:if> <c:if test="${brand.status != 1}"> <td>禁用</td> </c:if> <td><a href="#">修改</a> <a href="#">删除</a></td> </tr> </c:forEach> </table> </body> </html>
6.3.2 用法二
类似于 Java 中的普通for循环。涉及到的 中的属性如下
begin:开始数
end:结束数
step:步长
实例代码:
从0循环到10,变量名是 i
,每次自增1
<c:forEach begin="0" end="10" step="1" var="i"> ${i} </c:forEach>
7,MVC模式和三层架构
MVC 模式和三层架构是一些理论的知识,将来我们使用了它们进行代码开发会让我们代码维护性和扩展性更好。
7.1 MVC模式
MVC 是一种分层开发的模式,其中:
M:Model,业务模型,处理业务
V:View,视图,界面展示
C:Controller,控制器,处理请求,调用模型和视图
控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示。
MVC 好处:
职责单一,互不影响。每个角色做它自己的事,各司其职。
有利于分工协作。
有利于组件重用
7.2 三层架构
三层架构是将我们的项目分成了三个层面,分别是 表现层
、业务逻辑层
、数据访问层
。
- 数据访问层:对数据库的CRUD基本操作
- 业务逻辑层:对业务逻辑进行封装,组合数据访问层层中基本功能,形成复杂的业务逻辑功能。例如
注册业务功能
,我们会先调用数据访问层
的selectByName()
方法判断该用户名是否存在,如果不存在再调用数据访问层
的insert()
方法进行数据的添加操作 - 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
而整个流程是,浏览器发送请求,表现层的Servlet接收请求并调用业务逻辑层的方法进行业务逻辑处理,而业务逻辑层方法调用数据访问层方法进行数据的操作,依次返回到serlvet,然后servlet将数据交由 JSP 进行展示。
三层架构的每一层都有特有的包名称:
- 表现层:
com.itheima.controller
或者com.itheima.web
- 业务逻辑层:
com.itheima.service
- 数据访问层:
com.itheima.dao
或者com.itheima.mapper
后期我们还会学习一些框架,不同的框架是对不同层进行封装的