Servlet/JSP学习笔记(二)
概述
如果单独使用Servlet生成HTML页面是可以的,但是这个过程实在是太痛苦,因为所有HTML代码都没有任何提示功能,中间如果出现错误也无法查看,需要自己慢慢查找,所以出现了一门技术模版引擎
JSP算是一种模版引擎,其它的还有:Freemarker、Thymleaf等等
JSP 入门
Java Server Page Java:服务端页面,
本质就是Servlet,
优点:HTML代码和Java代码混合书写
<%@ page import="java.util.Random" %><%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/6/20
Time: 11:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP01</title>
</head>
<body>
JSP本质:</br>
<%
//书写java语言,不能定义类
double rand = new Random().nextInt(1000);
out.write("<h3>"+rand+"</h3>");//类似于PrintWrite功能,不太推荐
%>
<hr>
<!--混合书写-->
<h3 style="color: plum;font-size: 32px"><%=rand%></h3>
</body>
</html>
Tomcat中的work文件夹存储的JSP的临时文件,
C:\Users\Administrator\.IntelliJIdea2019.3\system\tomcat
目录,
JSP被翻译成了Java文件,该文件继承了
org.apache.jasper.runtime.HttpJspBase
又继承HttpServlet
,所以我们说JSP就是一个Servlet
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Random;
public final class demo01_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
/* WEB容器翻译JSP的时候帮骂我已经创建好的内置对象的名称,固定,request和response的变量名称HttpJspBase声明*/
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");//响应的内容
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${pageContext.request.contextPath}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
out.write("/\">\r\n");
out.write(" <title>JSP的本质</title>\r\n");
out.write(" </head>\r\n");
out.write(" <body>\r\n");
out.write(" JSP的本质:<br/>\r\n");
out.write(" ");
//书写是Java语句,不能定义类<%%>
double rand = new Random().nextInt(1000);
out.write("<h3>"+rand+"</h3>");//类似于PrintWrite功能,不太推荐
out.write("\r\n");
out.write(" <hr/>\r\n");
out.write(" <!-- 混合书写 -->\r\n");
//<%=%>
out.write(" <h3 style=\"color:blue\">");
out.print(rand);
out.write("</h3>\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
}
}
实际开发中,如何使用Servlet和JSP?
- Servlet做控制使用(获取数据-客户端数据或者服务端数据)
- JSP做显示使用(获得Servlet给我们的数据,我来只是做显示使用)
一.JSP工作原理(内置九个对象)
访问JSP的时候,JSP会给我们提供哪些对象?九个内置对象
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
//父类中
HttpServletRequest request;
httpServletResponse response;
有存储功能:4个对象(Web域对象)
<%@ page import="java.util.Random" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>JSP的九个内置对象</title>
</head>
<body>
<%-- 有存储功能对象HttpServletRequest/HttpSession/ServletContext --%>
<%
application.setAttribute("bookName","application三国演义");//在当前应用的范围有效
session.setAttribute("bookName","session水浒传");//在当前会话范围有效
request.setAttribute("bookName","request红楼梦");//在一次请求转发范围有效
pageContext.setAttribute("bookName","pageContext西游记");//只能在当前页面中有效
%>
<hr/>
<h3><%=pageContext.getAttribute("bookName")%></h3>
<h3><%=request.getAttribute("bookName")%></h3>
<h3><%=session.getAttribute("bookName")%></h3>
<h3><%=application.getAttribute("bookName")%></h3>
<hr/>
</body>
</html>
- response:HttpServletResponse
- out : 输出对象
- config :读取配置信息web.xml中
- page : 当前页面的信息
- exception : 异常处理对象
二.服务端和客户端路径跳转设置
JSP就是Servlet,只是默认使用自动映射为自己文件名称(包含文件夹),JSP跳转JSP的时候路径的设置
1.个人不推荐使用相对路径
<a href="result02.jsp">同级别访问</a><br/>
<a href="../demo04.jsp">如果访问不同层,使用..进行控制</a><br/>
<a href="../WEB-INF/view.jsp">WEB-INF无法直接访问,必须使用请求转发才能访问</a><br/>
<hr/>
2./:最前面设置/代表从端口号位置开始访问
<!-- http://127.0.0.1:8001/result02.jsp 不可以访问:缺少发布的路径 -->
<a href="/result02.jsp">发布路径,无法访问</a><br/>
<hr/>
3.推荐方式:从项目根目录开始查找★★
<a href="/yf06/view/result02.jsp">从发布路径根上开始查找</a><br/>
<a href="/yf06/demo04.jsp">从发布路径根上开始查找</a><br/>
<hr/>
<h3>获取发布的路径:<%=request.getContextPath()%></h3>
<a href="<%=request.getContextPath()%>/view/result02.jsp">从发布路径根上开始查找</a><br/>
<a href="<%=request.getContextPath()%>/demo04.jsp">从发布路径根上开始查找</a><br/>
4.获取发布的路径:<%=request.getContextPath()%>
配合base
标签设置</
<h3>获取发布的路径:<%=request.getContextPath()%>配合base标签设置</h3>
<a href="view/result02.jsp">base标签,所有的访问的路径,都会自动追加base里面的值</a><br/>
<a href="demo04.jsp">设置路径不是以/开头</a><br/>
请求转发和重定向的标准写法
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
result03.jsp<br/>
<!-- request请求转换和response重定向的标准写法,Servlet中 -->
<%
//请求转换中使用/开头,代表就是发布的路径
//请求转发可以访问WEB-INF中的资源
request.getRequestDispatcher("/WEB-INF/view.jsp").forward(request,response);
//重定向无法访问WEB-INF中的资源,重定向的标准写法如下 request.getContextPath() 发布路径
response.sendRedirect(request.getContextPath()+"/demo04.jsp");
%>
</body>
</html>
请求转发可以访问WEB-INF中的资源
三.JSP动作和标签
关于JSP的动作:<%@ page 页面相关属性的设置%> <%@ include 引入资源页面%> <%@ taglib 引入标签资源%>
关于JSP的标签:当设置了JSP标签之后,在进行翻译的时候,会自动转换成响应Java代码,标签化更加符合模版。
A. 静态包含
先包含后运行,执行一次,如果涉及到Java代码,需要注意定义的变量重复问题
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>test01.jsp,我们静态包含需要使用相对路径或者绝对路径</h3>
<%
int x = 888;
%>
<%@include file="/view/result02.jsp"%>
</body>
</html>
result02.jsp代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
int x = 999;
%>
result02.jsp<br/>
</body>
</html>
注意:不能重复定义相同变量,否则jsp翻译时候会重复出错
B. 动态包含
先运行后包含,执行多次。一般不会出现变量重复定义问题
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>test01.jsp,我们静态包含需要使用相对路径或者绝对路径</h3>
<%
int x = 888;
%>
<!-- 翻译这个标签的时候,会执行预先设置好的代码 -->
<!-- 将result02.jsp的运行结果包含进来 -->
<jsp:include page="/view/result02.jsp"></jsp:include>
</body>
</html>
四.EL表达式${}
在实际开发过程中,如果公司当中使用了JSP的这种方式,一般情况下不会使用
<%=%>
这种输出数据的方式,会使用专门替换,使用Expression Language表达式
作用:
- 获取数据:
WEB域的数据pageContext/request/session/application
- 执行运算:
- 调用Java方法
- 运算符:
.
或者[]
演示:
A_servlet代码:
package com.os.servlet;
import com.os.model.Student;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/data01")
public class WEB域传递数据 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("演示EL表达式:默认查找规则");
request.setAttribute("bookName","HttpServletRequest-西游记");
HttpSession session = request.getSession();
session.setAttribute("bookName","HttpSession-红楼梦");
ServletContext application = request.getServletContext();
application.setAttribute("bookName","ServletContext-三国演义");
System.out.println("演示EL表达式:演示单个对象如何获取数据");
Student student = new Student();
student.setStudentId(100);
student.setStudentName("悟空");
student.setSex("1");
student.setAge(100);
request.setAttribute("student",student);
System.out.println("演示EL表达式:演示多个对象如何获取数据");
List<Student> studentList = new ArrayList<>();
Student s1 = new Student();
s1.setStudentId(666);
s1.setStudentName("林黛玉");
s1.setSex("2");
s1.setAge(18);
studentList.add(s1);
s1 = new Student();
s1.setStudentId(777);
s1.setStudentName("贾宝玉");
s1.setSex("1");
s1.setAge(18);
studentList.add(s1);
request.setAttribute("studentList",studentList);
//请求转发的标准写法
request.getRequestDispatcher("/WEB-INF/el01.jsp").forward(request,response);
}
}
B_jsp代码
获取web域的数据,演示的默认规则
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
pageContext.setAttribute("bookName","PageContext-三国演义");
%>
<!--
EL表达式获取WEB域中的KEY是相同的时候,默认的操作规则如下
pageContext>HttpServletRequest>HttpSession>ServletContext
找到对应的KEY,立即返回后续就不再查找!
-->
<h3>
演示默认获取数据的规则:${bookName}
</h3>
<hr>
<!--
request.getParameter("name") 等价于 param.name 或者param["name"]
request.getParameterValues("name") 等价于 paramValues.name
-->
<h2>EL表达式,提供内置11个对象,关于web域对象如下:</h2>
<h3>${pageScope.bookName}</h3>
<h3>${requestScope.bookName}</h3>
<h3>${sessionScope["bookName"]}</h3>
<h3>${applicationScope['bookName']}</h3>
<hr>
<h2>传统方式,直接内置对象获取对应的数据</h2>
<h3><%=pageContext.getAttribute("bookName")%></h3>
<h3><%=request.getAttribute("bookName")%></h3>
<h3><%=session.getAttribute("bookName")%></h3>
<h3><%=application.getAttribute("bookName")%></h3>
</body>
</html>
- 运算符的介绍
EL表达式11个隐式对象:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--
request.getParameter("name") 等价于 param.name 或者param["name"]
request.getParameterValues("name") 等价于 paramValues.name
-->
<h3>对象的获取方式</h3>
<h4>标准获取方式:${requestScope.student.studentName} 或者 ${requestScope["student"]["age"]}</h4>
<h4>当之后一个KEY的时候:${student.studentName},需要知道查找pageContext里面是否包含</h4>
<!--判断是否为空及取反-->
<h3>==${requestScope.author}==**${empty requestScope.author}**
##${not empty requestScope.author}##${!empty requestScope.author}##</h3>
<!--比较数值是否相等-->
<h3>${student.age==100}
或者${student.studentName=="悟空"}
或者${student.studentName=='悟空'}
或者${student.studentName eq '悟空'}</h3>
<h3>
<!--不等于:ne-->
${student.age!=100}
或者${student.studentName!="悟空"}
或者${student.studentName!='悟空'}
或者${student.studentName ne '悟空'}
</h3>
<h3>
<!--大于:gt-->
${student.age>200}
或者${student.age gt 200}
</h3>
<h3>
<!--大于等于:ge-->
${student.age>=200}
或者${student.age ge 200}
</h3>
<h3>
<!--小于:lt-->
${student.age<200}
或者${student.age lt 200}
</h3>
<h3>
<!--小于等于:le-->
${student.age<=200}
或者${student.age le 200}
</h3>
<!--也支持关系运算符-->
<!-- && and / || or / ! not -->
<h2>集合</h2>
<h3>学生有:${studentList.size()} 个</h3>
<h3>现在无法变量,我也不推荐<%Java代码的遍历方式%></h3>
<h3>${studentList[1].studentName}</h3>
</body>
</html>
如果遍历数据,需要我们使用第三库提供的标签
五.JSTL标签库
刚才我们已经使用过JSP自带标签<jsp:include>
作用就是当我发现该标签的时候,会执行预先定义好的代码。
我们不推荐使用<%%>
在JSP中属性代码,原因就是不好看,格式化有一些乱七八糟。
-
核心标签库(重点)
-
格式化标签库(掌握)
-
函数标签库(掌握)
-
SQL标签库(不需要了解) -
XML标签库(不需要了解)
核心标签库
- 表达式
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 引入JSLT核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>核心标签库</title>
</head>
<body>
<h3>输出标签+必须要跟EL标签配合使用</h3>
<h4>${applicationScope.bookName}</h4>
<h4>
<c:out value="齐天大圣"></c:out>
</h4>
<h4>
默认对HTML标签会转义:
<c:out value="${applicationScope.bookName}"></c:out>
</h4>
<h4>
对HTML标签解释:
<c:out value="${applicationScope.bookName}" escapeXml="false"></c:out>
</h4>
<c:set value="三国志" var="bookName" scope="application"></c:set>
<h4>${applicationScope.bookName}</h4>
<c:remove var="bookName" scope="application"></c:remove>
<h4>${bookName}</h4>
<h4><c:out value="${applicationScope.bookName}">JSTL获取的数据没有值,显示的内容</c:out></h4>
<h4>${empty applicationScope.bookName?"EL获取的数据没有值,显示的内容":applicationScope.bookName}</h4>
</body>
</html>
- 循环数据
<h3>循环</h3>
<table style="width: 500px">
<tr>
<th>序号</th>
<th>索引</th>
<th>奇偶行</th>
<th>1或最后</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
<%--
items="${requestScope.studentList}
List<Student> studentList = request.getAttribute("studentList")
for(int i=0;i<studnetList.size();i++){
Student student = studentList.get(i); --> var="student"
序号(i+1)
}
--%>
<c:forEach items="${requestScope.studentList}" var="student" varStatus="vs">
<tr style="background-color: ${vs.index%2==0?'yellow':'gray'}">
<td>${vs.count}</td>
<td>${vs.index}</td>
<td>${vs.index%2==0}</td>
<td>${vs.first} -- ${vs.last}</td>
<td>${student.studentName}</td>
<td>${student.sex=="1"?"男":"女"}</td>
<td>${student.age}岁</td>
<td>
<a href="${pageContext.request.contextPath}/update?id=${student.studentId}">更新</a>
<a href="<%=request.getContextPath()%>/update?id=${student.studentId}">更新</a>
<a href="<c:url value="update?id=${student.studentId}"></c:url>">编辑</a>
</td>
</tr>
</c:forEach>
</table>