前一张的结尾,我想你已经发现了现在这个应用就是个骗子,根本就不是一个todos的应用,连个列表都没有,这一章就着重解决这个问题,在解决之前,先要明白几个概念:
Jsp的四种作用域
作用域顾名思义,就是一个变量能够起作用的区域,具体到jsp中,扣除自定义变量之外,共存在四种作用域,分别为:
- pageContext 即页面级,只存在本页面中,刷新后就消失。
- request 请求级,存在一样请求/响应周期
- session 会话级,存在一个用户完整的会话周期,可以暂时简单的理解为从用户访问站点开始,到关闭浏览器为止。
- application 应用级,即从应用启动到应用停止,比如tomcat重启,服务器重启都在这个范围。
page和request的区别在于,有些请求是跨页面的,比如通过forward的转发的页面,关于forward转发的内容,后面的章节会详细介绍。
看了四种作用域的介绍,因为列表是随时打开随时看的,那么很容易就可以想到,将所有的todo项存在于application中是最适合的(此时不考虑持久化技术),那么问题来了,jsp的application内置对象该如何使用呢?
这点,其实这四个内置变量的使用方式都是一致的,通过getAttribute(name:String)来获取在职,通过setAttribute(name:String,val:Object)来设置值。
存储todos
继续上一章的程序,暂时还是采取最简单的方法,仅仅是一个字符串的列表,将它通过一个List存入application中,代码如下:
<%
request.setCharacterEncoding("utf-8");
List<String> todos=(List<String>) application.getAttribute("todos");
if(todos==null){
todos=new ArrayList<>();
application.setAttribute("todos",todos);
}
if(request.getParameter("todo")!=null){
todos.add(request.getParameter("todo"));
}
%>
这里首先从application中获取一个List
这里有一个java很重要的基础知识点,即值类型与引用类型,对于这点一定要非常清晰,否则会在编码中产生非常可怕的影响。
显示todos
现在todo项已经存在了一个list中,下面要做的就是输出它(整个代码块):
<%
request.setCharacterEncoding("utf-8");
List<String> todos=(List<String>) application.getAttribute("todos");
if(todos==null){
todos=new ArrayList<>();
application.setAttribute("todos",todos);
}
if(request.getParameter("todo")!=null){
todos.add(request.getParameter("todo"));
}
out.print("<ul>");
for (String item :todos) {
out.print("<li>"+item+"</li>");
}
out.print("</ul>");
%>
查看一下效果:
不考虑美观的话,功能算是实现了,但是,这样好么?
当然不好,尤其是输出html标签这一点,想一下,如果把ul改成table怎么办?并且标签的开闭,很容易出错,在想想如果在todo的项目中增加一些超链接之类的,那么对于这种在代码中嵌入html的方法,几乎是一场噩梦,所以一个方法是把在代码中嵌入html改为在html中嵌入代码,修改后的代码如下:
<%
request.setCharacterEncoding("utf-8");
List<String> todos=(List<String>) application.getAttribute("todos");
if(todos==null){
todos=new ArrayList<>();
application.setAttribute("todos",todos);
}
if(request.getParameter("todo")!=null){
todos.add(request.getParameter("todo"));
}
%>
<ul>
<%
for (String item :todos) {
%>
<li><%=item%></li>
<%
}
%>
</ul>
这个:(貌似也没清晰多少,但是这是一个简单的例子,如果html稍微复杂点就能看出优势来,退一步说,即使只考虑使用html的高亮功能,都值得用这种代码中嵌入html的方法,但这种方法的缺点也是相当明显的,那就是他即破坏了html的结构,又破坏了代码的结构,那么有没有其他一种更加优秀的方法呢,这时候就轮到jstl出厂了.
jstl
jstl实际上是一套封装好的taglib组件,使用jstl首先需要加载jstl的依赖项,我们可以再maven公共库中搜索jstl,将搜索结果假如pom.xml文件的dependencies节点内中:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
加载后点击Import Changes 带进度条走完即表示加载完成。
然后,我使用默认模板创建的应用为2.3版本,其实现在默认即为3.*版本,即删除<!DOCTYPE声明节点即可,若需要强制声明版本,可修改web-app属性为:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
我的web.xml:
<web-app>
<display-name>jTodos</display-name>
</web-app>
呃 好简单
然后在页面声明taglib前缀:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
然后修改输出代码为:
<%
request.setCharacterEncoding("utf-8");
List<String> todos=(List<String>) application.getAttribute("todos");
if(todos==null){
todos=new ArrayList<>();
application.setAttribute("todos",todos);
}
if(request.getParameter("todo")!=null){
todos.add(request.getParameter("todo"));
}
%>
<ul>
<c:forEach var="item" items="${todos}">
<li>${item}</li>
</c:forEach>
</ul>
是不是清爽多了?运行看一下页面,和之前的一样,现在看页面的逻辑基本比较清晰了,代码和html互不干扰,同时,我们还可以为这个list假设一个编号:
<ul>
<c:forEach var="item" varStatus="status" items="${todos}">
<li>${status.index+1}.${item}</li>
</c:forEach>
</ul>
Ok很完美,这块暂时先告一段落,当然,jstl还有好多用法,以后再慢慢探索。
感谢您的阅读