Web-第十二天 el&jstl表达式学习
JSP模式&EL&JSTL
今日内容介绍
案例:重写商品信息展示
今日内容学习目标
阐述MVC设计模式思想
绘制三层体系架构执行流程图
会使用EL从指定作用域获得数据
会使用JSTL的forEach遍历数据
会使用JSTL的if语句进行数据过滤
第1章 案例:商品信息展示
1.1 需求
重写商品信息展示
1.2 相关知识点
1.2.1 EL表达式的概述
在JSP开发中,为了获取Servlet域对象中存储的数据,经常需要书写很多Java代码,这样的做法会使JSP页面混乱,难以维护,为此,在JSP2.0规范中提供了EL表达式。EL是Expression Language的缩写,它是一种简单的数据访问语言。本节将针对EL表达式进行详细的讲解。
1.2.1.1 什么是EL
EL(Expression Language) 目的:为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
1.2.1.2 EL的语法
由于EL可以简化JSP页面的书写,因此,在JSP的学习中,掌握EL是相当重要的。要使用EL表达式,首先要学习它的语法。EL表达式的语法非常简单,都是以“${”符号开始,以“}”符号结束的,具体格式如下:
${表达式}
1.2.1.3 EL的使用:内置对象
分类 | 内置对象名称 | 描述 |
作用域 | pageScope | page作用域 |
requestScope | request作用域 | |
sessionScope | session作用域 | |
applicationScope | application作用域 | |
请求参数 | param | 获得一个参数 |
paramValues | 获得一组参数 | |
请求头 | header | 获得一个请求头 |
headerValues | 获得一组请求头 | |
JSP上下文对象 | pageContext | |
全局初始化参数 | initParam | |
cookie | cookie |
获得指定作用域的数据
<%--初始化数据--%>
<%
pageContext.setAttribute("name", "pValue");
request.setAttribute("name", "rValue");
session.setAttribute("name", "sValue");
application.setAttribute("name", "aValue");
%>
<%--使用JSP脚本获得--%>
<%=pageContext.getAttribute("name") %> <!-- 如果没找到 返回null -->
<%=request.getAttribute("name") %>
<%=session.getAttribute("name") %>
<%=application.getAttribute("name") %>
<%--获得指定作用域的数据--%>
${ pageScope.name } <!-- 返回的是"" -->
${ requestScope.name }
${ sessionScope.name }
${ applicationScope.name }
<%--依次获得数据--%>
${ name } <%-- 底层使用 pageContext.findAttribute("name") ,依次从page、request、session、application获得数据,如果都没有返回null --%>
请求参数
//请求路径:/day18/a_el.jsp?username=jack&hobby=xxx&hobby=yyy
<%--
param.xxx 对应 request.getParameter("xxx");
paramValue.xxx 对应 request.getParameterValues("xxx");
--%>
${param.username} <br/>
${param.hobby}<br/> <%--获得第一个参数--%>
${paramValues.hobby} <br/> <%--获得一组数据,使用数组 --%>
${paramValues.hobby[1]} <br/> <%--如果是数组,可以使用下标获得 --%>
请求头
<%--
header.xxx 对应 request.getHeader("xxx");
headerValues.xxx 对应 request.getHeaders("xxx");
--%>
${header.accept} <br/>
\${header.accept-Encoding} <br/> <%--非法的,有异常,“-”被解析成减号。使用"/"进行单个el表达式转义 --%>
${header['accept-Encoding']} <br/>
${headerValues['accept-Encoding'][0]} <br/>
pageContext
<%--
pageContext 对应 pageContext对象
--%>
jsp: <%= ((HttpServletRequest)pageContext.getRequest()).getContextPath() %> <br/>
el : ${pageContext.request.contextPath} <br/>
全局初始化参数
<%--
web.xml配置
<context-param>
<param-name>person</param-name>
<param-value>白跃</param-value>
</context-param>
initParam 对应 servletContext.getInitParameter("person");
--%>
${initParam.person}
cookie
<%--
cookie 没有对应api。底层使用request.getCookies()获得所有cookie,然后遍历并存放到Map中(Map<name,obj>)
--%>
${cookie} <br/> <%--使用Map存所有cookie , Map<名称,对象> --%>
${cookie.company} <%--map.key 获得对应value --%>
${cookie.company.name} <%--通过javabean属性获得属性,获得cookie的名称,对应方法getName()--%>
${cookie.company.value} <%--获得cookie的值值,对应方法getValue() --%>
.和[]的区别.
1)[]用于有下标的数据(数组,list集合) .用于有属性的数据(map,对象)
2)如果属性名中包含有特殊的字符.必须使用[]
1.2.1.4 EL的使用:获得数据
自定义数据,必须存放在作用域
<%
String str = "悟空教程";
%>
${str} <%--无法获得,str不在域中 --%>
获得字符串
<%
String s = "Java帮帮";
//将输出存放到作用域
pageContext.setAttribute("sss", s);
%>
${sss} <br/>
${pageScope.sss} <br/>
获得数组
<%
String[] arr = {"A","B","C"};
pageContext.setAttribute("arr", arr,PageContext.REQUEST_SCOPE);
%>
${arr} <br/>
${arr[1]} <br/>
获得List数据
<%
//模拟数据
List<String> list = new ArrayList<String>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
pageContext.setAttribute("list", list);
%>
${list} <br/> <%-- 输出格式:[ , , ] --%>
${list[2]} <br/>
获得Map<String,String>数据
<%
//模拟数据
Map<String,String> map = new HashMap<String,String>();
map.put("li", "小李");
map.put("guo", "小郭");
map.put("wang", "老王");
pageContext.setAttribute("map", map);
%>
${map} <br/> <%-- 输出结果: { k=v ,...} --%>
${map.li} <br/> <%-- 通过key获得数据--%>
获得Map<String,JavaBean>数据
<%
Map<String,User> map2 = new HashMap<String,User>();
map2.put("u1", new User("u001","jack",18));
map2.put("u2", new User("u002","rose",21));
map2.put("3", new User("u003","tom",25));
pageContext.setAttribute("map2", map2);
%>
${map2} <br/>
${map2.u2} <br/> <%--通过key获得数据 --%>
${map2.u2.userName} <%--通过javabean 属性获得数据 --%>
${map2['3'].userName} <%--可以通过字符串'3'获得数据,注意:Map.key类型为Integer,将不能获得数据 --%>
1.2.1.5 EL的使用:运算符
模拟数据
<%
pageContext.setAttribute("n1", "10");
pageContext.setAttribute("n2", "20");
pageContext.setAttribute("n3", "30");
pageContext.setAttribute("n4", "40");
%>
算术运算符
${ n1 + n2 + n3 }
${1+1} <br/>
${"1"+1} <br/> <%--将字符串转换成数字,然后进行计算 --%>
${'1'+1} <br/> <%--el没有字符 --%>
\${'a'+1} <br/> <%-- 将a转换数字,异常 --%>
${a + 1} <br/> <%--a将从作用域获得数据,如果没有 --%>
关系运算符
${ n1 < n2 } - ${ n1 lt n2 } <!-- less than --><br/>
${ n1 > n2 } - ${ n1 gt n2 } <!-- great than --><br/>
${ n1 <= n2 } - ${ n1 le n2 } <!-- less equal --><br/>
${ n1 >= n2 } - ${ n1 ge n2 } <!-- great equal --><br/>
${ n1 == n2 } - ${ n1 eq n2 } <!-- equal --><br/>
逻辑运算符
${ n1<n2 && n3 < n4 } - ${ n1<n2 and n3 < n4 }<br/>
${ n1<n2 || n3 < n4 } - ${ n1<n2 or n3 < n4 }<br/>
${ !(n1 < n2) } - ${ not(n1<n2) }
三元运算符
${ n1 < n2 ? "正确":"错误" }
empty运算符
<%--
1.对象是否为null
2.字符串是否为""
3.集合是否为0
--%>
${ user == null } - ${ empty user }
${ user != null } - ${ not empty user }
1.2.2 JSTL
1.2.2.1 什么是JSTL
从JSP1.1规范开始,JSP就支持使用自定义标签,使用自定义标签大大降低了JSP页面的复杂度,同时增强了代码的重用性。为此,许多Web应用厂商都定制了自身应用的标签库,然而同一功能的标签由不同的Web应用厂商制定可能是不同的,这就导致市面上出现了很多功能相同的标签,令网页制作者无从选择,为了解决这个问题,Sun公司制定了一套标准标签库(JavaServer Pages Standard Tag Library),简称JSTL。
JSTL虽然被称为标准标签库,而实际上这个标签库是由5个不同功能的标签库共同组成的。在JSTL1.1规范中,为这5个标签库分别指定了不同的URI以及建议使用的前缀,如表1-7所示。
表1-1 JSTL包含的标签库
标签库 | 标签库的URI | 前缀 |
Core | http://java.sun.com/jsp/jstl/core | c |
I18N | http://java.sun.com/jsp/jstl/fmt | fmt |
SQL | http://java.sun.com/jsp/jstl/sql | sql |
XML | http://java.sun.com/jsp/jstl/xml | x |
Functions | http://java.sun.com/jsp/jstl/functions | fn |
1.2.2.2 JSTL的安装和测试
通过7.3.1小节的学习,了解了JSTL的基本知识,要想在JSP页面中使用JSTL,首先需要安装JSTL。接下来,分步骤演示JSTL的安装和测试,具体如下:
1.下载JSTL包
从Apache的网站下载JSTL的JAR包。进入“http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/”网址下载JSTL的安装包jakarta-taglibs-standard-1.1.2.zip,然后将下载好的JSTL安装包进行解压,此时,在lib目录下可以看到两个JAR文件,分别为jstl.jar和standard.jar。其中,jstl.jar文件包含JSTL规范中定义的接口和相关类,standard.jar文件包含用于实现JSTL的.class文件以及JSTL中5个标签库描述符文件(TLD)。
2.安装JSTL
将jstl.jar和standard.jar这两个文件复制到day18项目的lib目录下,如图1-16所示。
图1-1 导入jstl.jar和standard.jar文件
从图1-8可以看出,jstl.jar和standard.jar这两个文件已经被导入到day18项目的lib文件夹中,这个过程就相当于在day18项目中安装JSTL,安装完JSTL后,就可以在JSP文件中使用JSTL标签库。
3.测试JSTL
JSTL安装完成后,就需要测试JSTL安装是否成功。由于在测试的时候使用的是<c:out>标签,因此,需要使用taglib指令导入Core标签库,具体代码如下:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
在上述代码中,taglib指令的uri属性用于指定引入标签库描述符文件的URI,prefix属性用于指定引入标签库描述符文件的前缀,在JSP文件中使用这个标签库中的某个标签时,都需要使用这个前缀。
接下来编写一个简单的JSP文件test.jsp,使用taglib指令引入Core标签库,在该文件中使用<c:out>标签,如文件1-12所示。
文件1-1 test.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<c:out value="Hello World!"></c:out>
</body>
</html>
启动Tomcat服务器,打开浏览器,在地址栏中输入地址“http://localhost:8080/chapter07/test.jsp”访问test.jsp页面,此时,浏览器窗口中显示的结果如图1-17所示。
图1-2 test.jsp
从图1-17可以看出,使用浏览器访问test.jsp页面时,输出了“Hello World!”,由此可见,JSTL标签库安装成功了。
1.2.2.3 Core标签库:if标签
在程序开发中,经常需要使用if语句进行条件判断,如果要在JSP页面中进行条件判断,就需要使用Core标签库提供的<c:if>标签,该标签专门用于完成JSP页面中的条件判断,它有两种语法格式,具体如下:
语法1:没有标签体的情况,将结果存放到指定的作用域(不常用)
<c:if test="testCondition" var="result"
[scope="{page|request|session|application}"]/>
语法2:有标签体的情况,在标签体中指定要输出的内容
<c:if test="testCondition" >
body content
</c:if>
在上述语法格式中,可以看到<c:if>标签有三个属性,接下来将针对这三个属性进行讲解,具体如下:
test属性用于设置逻辑表达式;
var属性用于指定逻辑表达式中变量的名字;
scope属性用于指定var变量的作用范围,默认值为page。如果属性test的计算结果为true,那么标签体将被执行,否则标签体不会被执行。
通过前面的讲解,我们对<c:if>标签有了一个简单的认识,接下来通过一个具体的案例来演示如何在JSP页面中使用<c:if>标签。
在WebContent目录下创建一个名为c_if.jsp的文件,代码如文件1-15所示。
文件1-2 c_if.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<c:set value="1" var="visitCount" property="visitCount" />
<c:if test="${visitCount==1 }">
This is you first visit. Welcome to the site!
</c:if>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_if.jsp”访问c_if.jsp页面,此时,浏览器窗口中显示的结果如图1-18所示。
图1-3 c_if.jsp
从图1-18可以看出,浏览器窗口中显示了<c:if>标签体中的内容。这是因为在文件1-15中使用了<c:if>标签,当执行到<c:if>标签时会通过test属性来判断表达式${visitCount==1}是否为true,如果为true就输出标签体中的内容,否则输出空字符串。由于使用了<c:set>标签将visitCount的值设置为1,因此,表达式${visitCount==1}的结果为true,便会输出<c:if>标签体中的内容。
1.2.2.4 Core标签库:forEach标签
在JSP页面中,经常需要对集合对象进行循环迭代操作,为此,Core标签库提供了一个<c:forEach>标签,该标签专门用于迭代集合对象中的元素,如Set、List、Map、数组等,并且能重复执行标签体中的内容,它有两种语法格式,具体如下:
语法1:迭代包含多个对象的集合
<c:forEach [var="varName"] items="collection" [varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]>
body content
</c:forEach>
语法2:迭代指定范围内的集合
<c:forEach [var="varName"] [varStatus="varStatusName"] begin="begin"
end="end" [step="step"]>
body content
</c:forEach>
在上述语法格式中,可以看到<c:forEach>标签有多个属性。接下来针对这些属性进行讲解,具体如下:
var属性用于指将当前迭代到的元素保存到page域中的名称;
items属性用于指定将要迭代的集合对象;
varStatus用于指定当前迭代状态信息的对象保存到page域中的名称;
begin属性用于指定从集合中第几个元素开始进行迭代,begin的索引值从0开始,如果没有指定items属性,就从begin指定的值开始迭代,直到迭代结束为止;
step属性用于指定迭代的步长,即迭代因子的增量。
<c:forEach>标签在程序开发中经常会被用到,因此熟练掌握<c:forEach>标签是很有必要的,接下来,通过几个具体的案例来学习<c:forEach>标签的使用。
分别使用<c:foreach>标签迭代数组和Map集合,首先需要在数组和Map集合中添加几个元素,然后将数组赋值给<c:forEach>标签的items属性,而Map集合对象同样赋值给<c:forEach>标签的items属性,之后使用getKey()和getValue()方法就可以获取到Map集合中的键和值,如文件1-17所示。
文件1-3 c_foreach1.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
<%
String[] fruits = { "apple", "orange", "grape", "banana" };
%>
String数组中的元素:
<br />
<c:forEach var="name" items="<%=fruits%>">
${name}<br />
</c:forEach>
<%
Map userMap = new HashMap();
userMap.put("Tom", "123");
userMap.put("Make", "123");
userMap.put("Lina", "123");
%>
<hr />
HashMap集合中的元素:
<br />
<c:forEach var="entry" items="<%=userMap%>">
${entry.key} ${entry.value}<br />
</c:forEach>
</body>
</html>
启动Tomcat服务器,在浏览器在地址栏中输入地址“http://localhost:8080/chapter07/c_foreach1.jsp”访问c_ foreach1.jsp页面,此时,浏览器窗口中的显示结果如图1-19所示。
图1-4 c_foreach1.jsp
从图1-19可以看出,在String数组中存入的元素apple、orange、grape和banana全部被打印出来了,因此可以说明使用<c:forEach>标签可以迭代数组中的元素。Map集合中存入的用户名和密码全部被打印出来了。在使用<c:forEach>标签时,只需将userMap集合对象赋值给items属性,之后通过entry变量就可以获取到集合中的键和值。
<c:forEach>标签的begin、end和step属性分别用于指定循环的起始索引、结束索引和步长。使用这些属性可以迭代集合对象中某一范围内的元素。
在项目的WebContent目录下,创建一个名为c_foreach2.jsp的文件,该文件中使用了<c:forEach>标签的begin、end和step属性,代码如文件1-14所示。
文件1-4 c_foreach2.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body>
colorsList集合(指定迭代范围和步长)<br />
<%
List colorsList=new ArrayList();
colorsList.add("red");
colorsList.add("yellow");
colorsList.add("blue");
colorsList.add("green");
colorsList.add("black");
%>
<c:forEach var="color" items="<%=colorsList%>" begin="1"
end="3" step="2">
${color}
</c:forEach>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_foreach2.jsp”访问c_ foreach2.jsp页面,此时,浏览器窗口中的显示结果如图1-20所示。
图1-5 c_ foreach2.jsp
从图1-20可以看出,浏览器窗口中显示了colorsList集合中的yellow和green两个元素,只显示这两个元素的原因是,在使用<c:forEach>标签迭代List集合时,指定了迭代的起始索引为1,当迭代集合时首先会输出yellow元素,由于在<c:forEach>标签中指定了步长为2,并且指定了迭代的结束索引为3,因此,还会输出集合中的green元素,其他的元素不会再输出。
<c:forEach>标签的varStatus属性用于设置一个javax.servlet.jsp.jstl.core.LoopTagStatus类型的变量,这个变量包含了从集合中取出元素的状态信息。使用<c:forEach>标签的varStatus属性可以获取以下信息:
count:表示元素在集合中的序号,从1开始计数;
index:表示当前元素在集合中的索引,从0开始计数;
first:表示当前是否为集合中的第一个元素;
last:表示当前是否为集合中的最后一个元素;
通过上面的讲解,读者对<c:forEach>标签的varStatus属性已经有了基本的了解,接下来通过一个具体的案例来演示如何使用<c:forEach>标签的varStatus属性获取集合中元素的状态信息
在项目的WebContent目录下创建一个名为c_foreach3.jsp的文件,代码如文件1-15所示。
文件1-5 c_foreach3.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head></head>
<body style="text-align: center;">
<%
List userList = new ArrayList();
userList.add("Tom");
userList.add("Make");
userList.add("Lina");
%>
<table border="1">
<tr>
<td>序号</td>
<td>索引</td>
<td>是否为第一个元素</td>
<td>是否为最后一个元素</td>
<td>元素的值</td>
</tr>
<c:forEach var="name" items="<%=userList%>" varStatus="status">
<tr>
<td>${status.count}</td>
<td>${status.index}</td>
<td>${status.first}</td>
<td>${status.last}</td>
<td>${name}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
启动Tomcat服务器,在浏览器地址栏中输入地址“http://localhost:8080/chapter07/c_foreach3.jsp”访问c_ foreach3.jsp页面,此时,浏览器窗口中的显示结果如图1-21所示。
图1-6 c_ foreach3.jsp
从图1-21可以看出,使用<c:forEach>标签迭代集合中的元素时,可以通过varStatus属性获取集合中元素的序号和索引,而且还可以判断集合中的元素是否为第一个元素以及最后一个元素。因此可以说明使用该属性可以很方便的获取集合中元素的状态信息。
1.2.3 MVC设计模式
MVC设计模式: Model-View-Controller简写。
MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的设计方法。它把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
控制器Controller:对请求进行处理,负责请求转发;
视图View:界面设计人员进行图形界面设计;
模型Model:编写程序应用的功能(实现算法等等)、数据库管理;
MVC可对程序的后期维护和扩展提供了方便,并且使程序某些部分的重用提供了方便。而且MVC也使程序简化,更加直观。
注意,MVC不是Java的特有的,几乎现在所有B/S结构的软件都采用了MVC设计模式。
1.2.4 JSP开发模式
当SUN公司推出JSP后,同时也提供相应的开发模式,JavaWeb经历了JSP Model1 第一代,JSPModel1第二代,JSP Model 2 三个时期。
1.2.4.1 JSP Model1 第一代
JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都耦合在一起,对后期的维护和扩展极为不利。
(高内聚低耦合:)
1.2.4.2 JSP Model1 第二代
JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。
1.2.4.3 JSP Model 2
Model2使用到的技术有:Servlet、JSP、JavaBean。Model2 是MVC设计模式在Java语言的具体体现。
JSP:视图层,用来与用户打交道。负责接收用来的数据,以及显示数据给用户;
Servlet:控制层,负责找到合适的模型对象来处理业务逻辑,转发到合适的视图;
JavaBean:模型层,完成具体的业务工作,例如:转账等。
1.2.5 三层架构
JSP模式是理论基础,但实际开发中,我们常将服务器端程序,根据逻辑进行分层。一般比较常见的是分三层,我们称为:经典三层体系架构。三层分别是:表示层、业务逻辑层、数据访问层。
表示层:又称为 web层,与浏览器进行数据交互的。
业务逻辑层:又称为service层,专门用于处理业务数据的。
数据访问层:又称为dao层,与数据库进行数据交换的。将数据库的一条记录与JavaBean进行对应。
三层架构包命名:
简单版
cn.com.javahelp 公司域名倒写
cn.com.javahelp.dao dao层实现
cn.com.javahelp.service service层实现
cn.com.javahelp.web.servlet web层实现
cn.com.javahelp.domain JavaBean
cn.com.javahelp.utils 工具
完整版
cn.com.javahelp 公司域名倒写
cn.com.javahelp.xxx 项目名称
cn.com.javahelp.xxx.yyy 子模块
cn.com.javahelp.xxx.yyy.dao 子模块dao层接口
cn.com.javahelp.xxx.yyy.dao.impl 子模块dao层实现类
cn.com.javahelp.xxx.yyy.service 子模块service层接口
cn.com.javahelp.xxx.yyy.service.impl 子模块service层实现类
cn.com.javahelp.xxx.yyy.domain 子模块JavaBean (子模块yyy可省略)
cn.com.javahelp.xxx.yyy.web.servlet 子模块web层,servlet
cn.com.javahelp.xxx.yyy.web.filter 子模块web层,filter
cn.com.javahelp.xxx.utils 工具
cn.com.javahelp.xxx.exception 自定义异常
cn.com.javahelp.xxx.constant 常量
1.3 案例实现
重写“day17 查询商品详情”案例,此处只需要修改jsp页面的显示。
修改JSP页面
<%--导入核心标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%-- 列表 start --%>
<c:forEach items="${requestScope.allProduct}" var="p">
<div>
<a href="product_info.htm">
<img src="${p.pimage}" width="170" height="170" style="display: inline-block;">
</a>
<p><a href="product_info.html" style='color:green'>${p.pname}</a></p>
<p><font color="#FF0000">商城价:¥${p.shop_price}</font></p>
</div>
</c:forEach>
<%-- 列表 end --%>
第2章 总结
长按指纹,识别二维码,一键关注Java,大数据
长按指纹,识别二维码,一键关注Python
长按指纹,识别二维码,一键关注产品经理