el&jstl
第一章 Servlet3.0 注解开发
1.1 Servlet3.0
Tomcat版本 | Servlet版本 | JavaEE版本 | JDK版本 |
---|---|---|---|
9.0.x | 4.0 | 8.0 | 8 |
8.5.x | 3.1 | 8.0 | 7 |
8.0.x | 3.1 | 7.0 | 7 |
7.0.x | 3.0 | 6.0 | 6 (1.6) |
6.0.x | 2.5 | 5.0 | 5 (1.5) |
Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化 Web 应用的开发和部署。其中有几项特性的引入让开发者感到非常兴奋,同时也获得了 Java 社区的一片赞誉之声:
- 异步处理支持:有了该特性,Servlet 线程不再需要一直阻塞,直到业务处理完毕才能再输出响应,最后才结束该 Servlet 线程。在接收到请求之后,Servlet 线程可以将耗时的操作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度。
- 新增的注解支持:该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。
- 可插性支持:开发者可以通过插件的方式很方便的扩充已有 Web 应用的功能,而不需要修改原有的应用。
1.2 注解配置servlet演示
创建servlet,在@WebServlet
注解中添加urlPatterns= "/hello"
,作为请求路径
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//name = "HelloServlet":servlet名称,相当于web.xml中的<servlet-name>
//urlPatterns = "/hello":servlet的访问路径,相当于<url-pattern>
@WebServlet(name = "HelloServlet",urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("get 请求执行");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("post 请求执行");
}
}
配置tomcat服务器启动测试,浏览器地址栏输入:http://localhost:8080/day03/hello
第二章 域对象&请求转发&重定向
2.1 Request作为域对象存取数据
- Request作为域对象的API:
方法 | 返回值 | 描述 |
---|---|---|
setAttribute(String name, Object obj) | void | 向Request域中保存数据 |
getAttribute(String name) | Object | 从Request域中获取数据 |
removeAttribute(String name) | void | 从Request域中移除数据 |
- Request作为域对象作用范围:
- Request对象其实就是从客户端浏览器向服务器发送的一次请求信息的封装。那么实质上向Request中所保存的数据有效期也是一次请求范围。
- 所谓一次请求范围:指从客户端浏览器向服务器发送一次请求,服务器针对这次请求对浏览器作出响应。当服务器作出响应之后,请求对象就销毁了,保存在其中的数据就无效了。
2.2 请求转发和重定向完成页面的跳转
2.2.1 请求转发
- 上图所示的请求转发的过程如下:
-
浏览器向Servlet1发出访问请求;
-
Servlet1调用forward()方法,在服务器端将请求转发给Servlet2;
-
最终由Servlet2做出响应。
- 请求转发的写法:
- 通过ServletRequest对象获得RequestDispatcher对象
方法 | 返回值 | 描述 |
---|---|---|
getRequestDispatcher(String path) | RequestDispatcher | 获得RequestDispatcher对象 |
- 再根据RequestDispatcher中的方法进行请求转发
方法 | 返回值 | 描述 |
---|---|---|
forward(ServletRequest request, ServletResponse response) | void | 进行请求转发 |
- 请求转发的代码实现:
/**
* 页面跳转前的Servlet
*/
@WebServlet(name = "ServletDemo1", urlPatterns = "/demo1")
public class ServletDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 向request域保存数据:
request.setAttribute("name", "张三");
// 请求转发的方式:
/*
RequestDispatcher dispatcher = request.getRequestDispatcher("/demo2");
dispatcher.forward(request, response);
*/
request.getRequestDispatcher("/demo2").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
/**
* 页面跳转后的Servlet
*/
@WebServlet(name = "ServletDemo2",urlPatterns = "/demo2")
public class ServletDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从request域获取数据:
Object name = request.getAttribute("name");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("<h1>跳转后的页面</h1>");
response.getWriter().print(name);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
2.2.2 重定向
- 上图所示的间接转发请求的过程如下:
- 浏览器向Servlet1发出访问请求;
- Servlet1调用sendRedirect()方法,将浏览器重定向到Servlet2;
- 浏览器向servlet2发出请求;
- 最终由Servlet2做出响应。
- 重定向的写法:
通过HttpServletResponse对象中的以下方法实现重定向
方法 | 返回值 | 描述 |
---|---|---|
sendRedirect(String location) | void | 重定向 |
- 重定向的代码实现:
/**
* 页面跳转前的Servlet
*/
@WebServlet(name = "ServletDemo1", urlPatterns = "/demo1")
public class ServletDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 向request域保存数据:
request.setAttribute("name", "张三");
// 重定向的方式:
response.sendRedirect("/day03/demo2");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
/**
* 页面跳转后的Servlet
*/
@WebServlet(name = "ServletDemo2",urlPatterns = "/demo2")
public class ServletDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从request域获取数据:
Object name = request.getAttribute("name");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("<h1>跳转后的页面</h1>");
response.getWriter().print(name);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
2.3 请求转发和重定向的区别
请求转发和重定向原理
区别总结
- 请求转发是一次请求一次响应,而重定向是两次请求两次响应。
- 请求转发地址栏不会变化的,重定向地址栏发生变化。
- 请求转发路径不带工程名,重定向需要带工程名路径。
- 请求转发只能在本网站内部,重定向可以定向到任何网站。
注意:
如果需要使用request进行值传递,需要通过请求转发完成。
如果页面需要跳转到其他网站上必须使用重定向。
第三章 jsp的基本入门
3.1 jsp简介
3.1.1 jsp的概念
JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。为了与传统HTML有所区别,JSP文件的扩展名为.jsp。
3.1.2 体验jsp
- 创建JSP文件,复制以下代码到jsp文件中,启动tomcat,在地址栏输入jsp文件名称进行访问。
<html>
<head>
<title>测试jsp</title>
</head>
<body>
<%
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:dd");
String curTime = dateFormat.format(date);
request.setAttribute("curTime",curTime);
%>
当前系统时间:<span style="color: red"><%=request.getAttribute("curTime") %></span>
</body>
</html>
在地址栏输入jsp文件名称访问即可。
3.2 jsp的执行原理
通过上述的体验jsp之后,我们发现jsp真的非常厉害,既可以编写java代码也可以直接编写html代码,相对servlet更加方便,那么jsp为什么可以直接使用reqeust 与直接编写html代码呢
依据上图的流程,这时用everything软件搜索本机上的_1_jsp.java
文件, 可以找到如下内容的文件:找到了生成的java文件,其中一部分内容如下图:
我们可以看到当前的jsp文件被翻译成了一个类,这个类继承HttpJspBase
类,那么这个HttpJspBase
类又是什么?
注意jsp的翻译有服务器完成,HttpJspBase
类一定也是tomcat服务器的内容,顺着org.apache.jasper.runtime.HttpJspBase
这个类全名,我们找到这个类的源码:
通过观察源码,我们发现JSP其实底层就是一个servlet。通过观察源码,我们发现我们刚刚编写的所有代码都在该Servlet里面的service方法内部。
总结:
-
jsp之所以可以编写html代码,其实本质上也是类似我们使用Servlet直接输出的。
-
jsp之所以直接使用 直接使用request对象,是因为我们自己编写的代码全部都落入到了service方法内部,在service方法内部一开始就已经声明了request等对象了。
3.3 jsp的基本语法
3.3.1 jsp注释
JSP注释格式
<%-- jsp注释 --%>
JSP注释的使用
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注释</title>
</head>
<body>
<!---这个是html注释-->
<%-- 这个是jsp的注释--%>
</body>
</html>
访问页面测试:没有任何内容显示,那么也就说html与jsp注释都生效, 但是点击查看源码的时候我们发现我们只能查看到html的注释,jsp的注释根本就看不到。
总结
1. jsp的注释不会显示在源码上,更加安全。
2. 如果在jstl标签体内使用html的注释将会失效,所以在jsp页面中推荐使用jsp的注释。
3.3.2 jsp书写java代码的三种方式
在之前的演示中,我的jsp已经可以向页面输出一个html内容,但是这个还不够,jsp应该还要有像servlet一样可以通过代码,动态生成网页的功能。servlet是使用java代码生成动态网页的,因此,接下来,我们要学习如何在jsp页面使用java代码。
3.3.2.1 方式一:脚本片段
脚本片段格式:
格式:
<% Java代码片段 %>
jsp代码演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书写java代码的三种方式</title>
</head>
<body>
<%-- 脚本片段 --%>
<% int x = 10; %>
</body>
</html>
翻译成java文件:
- 在脚本片段中写的
<% int x = 10; %>
Java代码,会翻译到java文件中的_jspService方法中。
脚本片段作用
- 在jsp翻译后的_jspService方法中,可以嵌入java代码
脚本片段使用注意事项
- 脚本片段可以分开书写,最终是组合在一起的,示例:
jsp代码演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书写java代码的三种方式</title>
</head>
<body>
<%-- 脚本片段 --%>
<% for(int j = 0 ; j < 5 ;j++){%>
Hello World!!!<br>
<%}%>
</body>
</html>
3.3.2.2 方式二:脚本声明
脚本片段虽然可以嵌入java代码,但是如果,我们要给当前的jsp中定义一些方法或者成员变量,就需要一个新的技术——脚本声明。
脚本声明格式
<%! 书写Java代码 %>
jsp代码演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书写java代码的三种方式</title>
</head>
<body>
<%! int i = 0 ;%>
</body>
</html>
翻译成java文件:
- 脚本声明书写的
<%! int i = 0 ;%>
java代码,会翻译在类的成员位置上。
脚本声明作用
- 在类的成员位置上声明方法和变量
脚本声明使用注意事项
- 声明方法的时候,不要声明与jsp翻译的java文件中默认的一些方法或者变量同名的方法或者变量。
3.3.2.3 方式三:脚本表达式
虽然脚本声明和脚本片段已经可以书写Java代码了,但是如果我们要使用java代码向页面输出一些内容,还是需要使用原来的response对象,比较繁琐,因此,我们需要一个更加简便的方式,可以代替response向页面输出内容——这个就是脚本表达式。
脚本表达式格式
<%= 表达式 %>
jsp代码演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>书写java代码的三种方式</title>
</head>
<body>
<%-- 脚本表达式 --%>
<%= "公司名称" %>
</body>
</html>
翻译成java文件:在_jspService方法中,找到了我们书写的内容
- 脚本表达式书写的
<%= "传智播客" %>
java代码,会翻译到java文件中的_jspService方法内,被out.print输出到页面。
out对象的类型是JspWriter,通过查阅JAVAEE文档发现其父类是java.io.Writer,是一个Writer 字符流。
脚本表达式作用
- 代替response向页面输出内容
脚本表达式使用注意事项
- 使用表达式向页面输出内容的时候,不要同时使用response对象向页面输出内容,会出现页面内容输出顺序和代码顺序不一致。
第四章 EL表达式
4.1 EL表达式的基本概述
EL(Express Lanuage)表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL 出现的目的是要替代jsp页面中输出脚本的编写。
4.2 EL表达式的格式和作用
EL表达式的格式:
${EL表达式内容}
EL表达式的作用:
- 从域对象中查找指定的数据。
- 内置对象使用
- 执行运算符
4.3 EL表达式的基本使用
4.3.1 EL表达式作用一:从域中取出数据
- EL从四个域中获得某个值:
${key}
- 同样是依次从pageContext域,request域,session域,application域中 获取属性,在某个域中获取后将不在向后寻找
- 其中,若只想获得request域中的值:
${requestScope.key}
- 其中,若只想获得session域中的值:
${sessionScope.key}
- 其中,若只想获得application域中的值:
${applicatioScope.key}
1. 通过EL表达式,获得普通数据
格式:
${key}
代码演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 存储普通数据 --%>
<%
//向request域中存储数据
request.setAttribute("name","zhangsan");
//向session域中存储数据
request.getSession().setAttribute("name","lisi");
//向servletContext域中存储数据
getServletContext().setAttribute("name","wangwu");
%>
<h1>取出request域中的数据</h1>
${requestScope.name}
<h1>取出session域中的数据</h1>
${sessionScope.name}
<h1>取出servletContext域中的数据</h1>
${applicationScope.name}
<h1>按照域的从小到大依次搜索域数据</h1>
${name}
</body>
</html>
2. EL获得javaBean对象的值
格式:
${对象.成员变量}
代码演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 存储User实体数据 --%>
<%
User user = new User("tom",18);
request.setAttribute("user",user);
%>
<h1>取出User的数据</h1>
${user.username}==${user.age}
</body>
</html>
public class User {
private String username;
private int age;
//省略构造方法、get、set方法
}
3. EL获得List<String>的值
格式:
${List集合对象[角标]}
代码演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 存储List<String>数据 --%>
<%
List<String> strList = new ArrayList<String>();
strList.add("aaa");
strList.add("bbb");
strList.add("ccc");
request.setAttribute("strList",strList);
%>
<h1>取出strList的数据</h1>
${strList[0]}==${strList[1]}
</body>
</html>
4. EL获得List<User>的值
格式:
${List集合对象[角标].成员变量}
代码演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 存储List<User>数据 --%>
<%
List<User> userList = new ArrayList<User>();
User user2 = new User("lucy",20);
userList.add(user);
userList.add(user2);
request.setAttribute("userList",userList);
%>
<h1>取出userList的数据</h1>
${userList[0].username}==${userList[0].age}<br/>
${userList[1].username}==${userList[1].age}<br/>
</body>
</html>
5. EL获得Map<String,User>的值
格式:
${Map集合对象.key.成员变量}
或
${Map集合对象[key].成员变量}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 存储Map<String,User> --%>
<%
Map<String,User> userMap = new HashMap<>();
userMap.put("user1",user);
userMap.put("user2",user2);
request.setAttribute("userMap",userMap);
%>
<h1>取出userMap的数据</h1>
${userMap.user1.username}==${userMap.user1.age}<br/>
${userMap.user2.username}==${userMap.user2.age}<br/>
${userMap['user1'].username}==${userMap['user1'].age}<br/>
${userMap['user2'].username}==${userMap['user2'].age}<br/>
</body>
</html>
4.3.2 EL的内置对象
pageContext - WEB开发中的pageContext.
作用:可以获取JSP中域中的数据(pageScope,requestScope,sessionScope,applicationScope)
- 例如,在Servlet中,想获得web应用的名称:
request.getContextPath();
- 那么,在jsp页面上,想获得web应用的名称:
${pageContext.request.contextPath}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>获得web应用的名称</title>
</head>
<body>
<h1>获得web应用的名称</h1>
${pageContext.request.contextPath}
</body>
</html>
4.3.3 EL执行运算符
- 算数运算符 + - * / %
- 逻辑运算符 && || !
- 比较运算符 > < >= <=
- Null运算符 empty
- 三元运算符
代码演示:
<%--再当前jsp导入ArrayList--%>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>el表达式可以执行运算符<</title>
</head>
<body>
${3==3}<br>
${3>=4}<br>
${3<5}<br>
${3!=3}<br>
${3+4}<br>
${3==3&&3<4}<br>
${3==5||3>4}<br>
<%
request.setAttribute("str",null);
request.setAttribute("list",new ArrayList<>());
%>
${empty str}<br>
${empty list}<br>
${str == null? "数据为空":str}<br>
</body>
</html>
第五章 JSTL的核心标签库使用
5.1 jstl标签的基本概述
JSTL(JSP Standard Tag Library),JSP标准标签库,可以嵌入在jsp页面中使用标签的形式完成业务逻辑等功能。jstl出现的目的同el一样也是要提到jsp页面中的脚本代码。JSTL标准标准标签库有5个子库,但随着发展,目前常使用的是他的核心库
标签库 | 标签库的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 |
5.2 jstl标签的安装
导入jar包
javax.servlet.jsp.jstl.jar
jstl-impl.jar
使用taglib指令在jsp页面导入要使用的jstl标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
在jsp书写"<c:",看到如下提示,说明安装成功:
5.3 常用的jstl标签
jstl的核心标签内容有很多,现在目前还常用的标签只有if、foreach标签。
5.3.1 <c:if>标签
if标签作用
起到java代码的判断的作用
if标签属性介绍
-
test:判断是否执行标签内的内容(true——执行标签中的内容,false,不执行)。
-
var:用来保存test属性的结果(使用var属性给他取个名字),这个结果可以保存到指定的容器中。
-
scope:指定保存数据的容器。
if标签演示
<%@ 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 test="${num>5}">
num大于5
</c:if>
<c:if test="${num<=5}">
num小于等于5
</c:if>
<%--将if判断的结果存储到指定的域中--%>
<c:if test="${num==100}" var="res" scope="request"></c:if>
<h1>取出结果</h1>
${res}
</body>
</html>
5.3.2 forEach标签
forEach标签作用
起到java代码的for循环作用
forEach标签属性介绍
- var:在不循环对象的时候,保存的是控制循环的变量;在循环对象的时候,保存的是被循环对象中的元素
- items:指定要循环的对象
- varStatus:保存了当前循环过程中的信息(循环的开始、结束、步长、次数等)
- begin:设置循环的开始
- end:设置循环的结束
- step:设置步长——间隔几次循环,执行一次循环体中的内容
foreach演示
<%@ 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>
<h1>模拟增强for循环</h1>
<c:forEach items="${userList}" var="user">
${user.username}==${user.age}
</c:forEach>
<h1>模拟普通for循环</h1>
<c:forEach begin="0" end="${num}" var="i" step="10">
${i}<br>
</c:forEach>
</body>
</html>
第六章 三层架构和MVC模式
6.1 JSP开发模式
当SUN公司推出JSP后,同时也提供相应的开发模式,JavaWeb经历了JSP Model1 第一代,JSPModel1第二代,JSP Model 2 三个时期。
JSP Model1 第一代
JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都在一起,对后期的维护和扩展极为不利。
JSP Model1 第二代
JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。
JSP Model 2
Model2使用到的技术有:Servlet、JSP、JavaBean。Model2 是MVC设计模式在Java语言的具体体现。
-
JSP:视图层,用来与用户打交道。负责接收用来的数据,以及显示数据给用户;
-
Servlet:控制层,负责找到合适的模型对象来处理业务逻辑,转发到合适的视图;
-
JavaBean:模型层,完成具体的业务工作,例如:转账等。
6.1.3 三层架构
JSP模式是理论基础,但实际开发中,我们常将服务器端程序,根据逻辑进行分层。一般比较常见的是分三层,我们称为:经典三层体系架构。三层分别是:表示层、业务逻辑层、数据访问层。
- 表示层:又称为 web层,与浏览器进行数据交互的。
- 业务逻辑层:又称为service层,专门用于处理业务数据的。
- 数据访问层:又称为dao层,与数据库进行数据交换的。将数据库的一条记录与JavaBean进行对应。