文章目录
JSP
什么是jsp?
JSP全名为Java Server Pages,中文名叫java服务器页面,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码;标签通常以<%开头以%>结束。JSP技术有点类似ASP技术,它是在传统的网页HTML(标准通用标记语言的子集)文件(.html)中使用JSP标签插入Java程序段,从而形成JSP文件,后缀名为(*.jsp)。它实现了html语法中的java扩展(以<%, %>形式)简单来说就是jsp代替Servlet程序回传html页面的数据
JSP的本质
JSP页面本质上是一个Servlet程序。当我们第一次访问jsp页面的时候,Tomcat服务器会帮我们把jsp页面翻译成一个java源文件(也就是在C:\Users\曾经觊觎\AppData\Local\JetBrains\IntelliJIdea2020.3\tomcat\6124c6cf-3535-4273-ab14-6f279e07cf0c这个路径可以在IDEA启动Tomcat后,控制台找到,顺着这个路径可以找到Tomcat的work目录(\work\Catalina\localhost\cjjy\org\apache\jsp\static_\jsp可以找到对应的文件),那是Tomcat服务器工作的目录)我们可以看到它会进行编译成为.class字节码程序(jsp最后也会转换成Java类)

所以里面存放着页面会转变成
Java程序,我们可以看到该文件继承了HttpJspBase类,而HttpJspBase这个类它又继承了HttpServlet类。也就是说浏览器向服务器发送请求,不管访问什么资源,其实就是在访问Servlet在
jsp页面中,只要是Java代码,就会原封不动的输出,如果是HTML代码,就会被转换为下面的格式,输出到前端out.write("<html>\n");
JSP基础语法
jsp头部的page配置指令
<!--jsp的page指令可以修改jsp页面中的一些重要属性或者行为--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
常用指令属性
| jsp指令属性 | 说明 |
|---|---|
| language 属性 | 表示jsp翻译后是什么语言文件,目前只支持java语言 |
| contentType 属性 | 内容类型,一般是指网页中存在的Content-Type |
| pageEncoding 属性 | 表示当前jsp文件本身的字符集 |
| import 属性 | 跟java源代码中一样。用于导包,导类 |
| autoFlush 属性 | 设置当out输出流缓冲区满了之后,是否自动刷新缓冲区。默认值是true |
| buffer 属性 | 设置out缓冲区大小,默认8kb |
| errorPage 属性 | 如果页面发生错误,自动跳转到这个错误页面的路径 |
| isErrorPage 属性 | 设置当前jsp页面是否是错误信息页面,默认是false |
| session 属性 | 设置访问当前jsp页面,是否会创建HttpSession对象,默认是true |
| extends 属性 | 设置jsp翻译出来的Java类默认继承谁 |
JSP中的常用脚本
声明脚本
<!--可以给jsp翻译出来的Java类定义属性和方法和静态代码块,内部类等。且<%!%>里声明的变量和方法都是作为类的属性和方法存在的-->
<%! %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%!
/*定义属性*/
public int i;
/*定义方法*/
public int test(){
return 1;
}
/*
定义内部类
这里static关键字可以修饰类,普通类是不允许声明为静态的,只有内部类才可以。 被static修饰的内部类可以直接作为一个普通类来使用
*/
public static class A{
private String name="zhangsan";
private int age=1;
}
%>
</body>
</html>
表达式脚本(常用)
表达式脚本语法格式
<!--语法格式:--> <!--变量或表达式值输出到页面(在jsp页面上输出数据)
<%= %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%!
private static Map<String, String> map;
%>
<%!
static {
map = new HashMap<>();
map.put("张三","01");
map.put("张四","02");
}
%>
<!--输出整型。这里注意噢,jsp里面的注释是<%----%>是这个,markdown语法不显示jsp注释的颜色,所以为了好看,下面我全部都换成了html的注释格式 --%>
<%=12%>
<!--输出浮点数-->
<%=13.14%>
<!--输出字符串-->
<%="张三"%>
<!--还可以输出对象-->
<%=map%>
<!--举例-->
<%= new java.util.Date()%>
</body>
</html>
表达式脚本特点
所有的表达式脚本代码都是在底层在
_jspService()方法中,由于表达式脚本都是在底层在_jspService()方法中,所以_jspService()方法中的对象都可以直接使用(下面会讲到)//以下输出页面前增加的代码(以下的这些对象我们可以直接在jsp页面直接使用) public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException { 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; }<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%=request.getParameter("username")%> </body> </html>
表达式脚本都会被翻译成为
out.print()输出到页面上表达式脚本中的表达式不能以分号结束
代码脚本
代码脚本的语法格式
<!--
1、可添加java代码片段(可以写一些jsp脚本片段)要求:这里面的代码必须保证Java语法的正确性(简单来说代码脚本的作用是:可以在jsp页面中。编写我们自己需要的功能)
2、<% %>里面不能声明方法 而在<% %>里声明的变量则是作为_jspService()这个方法的内部属性
-->
<%
java语句
%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--代码脚本 if语句--%>
<%
int i=12<<2;
if (i>48){
//因为翻译后java文件中_jspService()方法内代码脚本由于翻译到_jspService()方法中,所以在_jspService()方法中的现有对象都可以直接使用
out.print("ge~ge");
}else {
out.print("mei~mei");
}
%>
<%
for (int j = 0; j < 100; j++) {
out.println("j="+j);
out.write("<br/>");
}
%>
</body>
</html>
代码脚本的特点
代码脚本翻译之后都在
_jspService()方法中代码脚本由于翻译到
_jspService()方法中,所以在_jspService()方法中的现有对象都可以直接使用可以由多个代码脚本块组合完成一个完整的
java语句<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <% for (int j = 0; j < 100; j++) { out.println("j="+j); %> <% out.write("<br/>"); } %> </body> </html>//底层代码 for (int j = 0; j < 100; j++) { out.println("j="+j); out.write('\r'); out.write('\n'); }
代码脚本还可以和表达式脚本一起组合使用,在
jsp页面上输出数据<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <% for (int j = 0; j < 100; j++) { %> <%="i="+j%> <% out.write("<br/>"); } %> </body> </html>
JSP注释
jsp的三种注释
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--这是html注释,会被解析成源代码,在_jspService()方法里,以out.writer输出到客户端-->
<%!
//java注释会被解析到java源代码中
//:单行java注释
/* 多行java注释 */
%>
<%-- jsp注释,jsp的注释没办法在客户端显示 --%>
</body>
</html>
JSP九大内置对象
什么是内置对象?
jsp中的内置对象,是指Tomcat在翻译jsp页面成为Servlet源代码后,内部提供的九大对象,叫内置对象
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
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;
}
| 变量 | 具体类型 |
|---|---|
| request | 请求对象 |
| response | 响应对象 |
| pageContext | jsp的上下文对象 |
| session | 会话对象 |
| application | ServletContext对象 |
| config | ServletConfig对象 |
| out | jsp输出流对象 |
| page | 指向当前jsp的对象 |
| exception | 异常对象(必须在头部的page配置指令加上isErrorPage="true"才能出现 ) |
JSP四大域对象
四个域对象分别是:pageContext、request、session、application
| 域对象 | 所属类 | 数据存取范围 |
|---|---|---|
pageContext | PageContext类 | 当前jsp页面范围内有效 |
request | HttpServletRequest类 | 一次请求内有效 |
session | HttpSession类 | 一个会话范围内有效(打开浏览器,直到关闭浏览器) |
application | ServletContext类 | 整个Web工程范围内都有效 |
域对象就是可以像Map一样存取数据的对象。四个域对象功能一样。不同的是它们对数据的存取范围
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//作用域从底层到高层
pageContext.setAttribute("key","pageContext");//保存的数据只在一个页面有效
request.setAttribute("key","request");//保存的数据只在请求有效,请求转发会携带这个数据
session.setAttribute("key","session");//保存的数据只在一次会话有效,从打开浏览器到关闭浏览器
application.setAttribute("key","application");//保存的数据只在服务器中有效,从打开服务器到关闭服务器
%>
</body>
</html>
域对象也可以设置作用域范围
pageContext.setAttribute("name","张三",PageContext.APPLICATION_SCOPE);//使用PageContext可以指定作用域
作用域大小如下
public abstract class PageContext extends javax.servlet.jsp.JspContext {
public static final int PAGE_SCOPE = 1;
public static final int REQUEST_SCOPE = 2;
public static final int SESSION_SCOPE = 3;
public static final int APPLICATION_SCOPE = 4;
}
四个域在使用的时候,优先从小到大的顺序范围是pageContext》request》session》application
JSP中有关out输出和response.getWriter输出区别
out输出和response.getWriter输出的区别?
out和response.getWriter()的类不一样,一个是JspWriter,另一个是java.io.PrintWriter。response表示响应,我们经常用于设置返回给客户端的内容(输出);out也是给用户做输出使用的- 执行原理不同:在
jsp页面中所有的代码执行完成后会做以下两个操作,会执行out.flush()操作,JspWriter相当于一个带缓存功能的printWriter,它不是直接将数据输出到页面,而是把out缓冲区中的数据追加写入到response缓冲区末尾,然后会执行response的刷新操作。把全部数据写给客户端
由于底层源代码都是使用
out来进行输出,所以一般情况下,我们在jsp页面统一使用out来进行输出,避免打乱页面输出内容顺序
out输出
out.write()和print()区别?
- out.write():仅支持输出字符类型数据,字符、字符数组、字符串等,因为你如果输出的是整型数据类型的话,底层源代码会转化成字符串,也就是对应的
ASCII字符 - print():不管什么类型底层源代码都转换成字符串后调用
write输出(一般使用这个,可以将各种类型(包括Object)的数据通过默认编码转换成bytes字节形式,这些字节都通过write(int c)方法被输出)
out.print()和out.println()区别?
out.print()方法和out.println()方法在缓冲区溢出并且没有自动刷新时候会产生ioexception,而response.getWrite().print()和response.getWrite().println()不会有ioexception。out.println("")方法只能实现html代码换行,要实现页面布局换行得这样写out.println("< /br>");
JSP常用的标签
jsp静态包含(一般使用这个)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div class="header">头部</div>
<div class="main"></div>
<%--
<%@include file=""%>就是静态包含
file属性指定你要包含的jsp页面的路径
”/“:表示http://ip:port/工程路径/
静态包含的特点:
1、静态包含不会翻译被包含的jsp页面
2、静态包含其实是把包含的jsp页面的代码拷贝到包含位置执行输出
--%>
<%@include file="/static/jsp/footer.jsp"%>
</body>
</html>
jsp动态包含
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div class="header">头部信息</div>
<div class="main">主体内容</div>
<%--
<jsp:include page=""></jsp:include>就是动态包含
page属性指定你要包含的jsp页面的路径
”/“:表示http://ip:port/工程路径/
动态包含也可以像静态包含一样。把被包含的内容执行输出到包含位置
动态包含的特点:
1、动态包含会把包含的jsp页面也翻译成java代码
2、动态包含底层代码使用如下代码去调用被包含的jsp页面执行输出:
//main.jsp把自己的request,response,out对象都传递给了footer.jsp页面去使用,其实footer.jsp页面request,response,out对象其实都是引用传递过来的对象(公用out缓冲区)
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/static/jsp/footer.jsp", out, false);
--%>
<jsp:include page="/static/jsp/footer.jsp">
<%-- 还可以传递参数--%>
<jsp:param name="username" value="zhangsan"/>
<jsp:param name="password" value="root"/>
</jsp:include>
</body>
</html>
上面jsp运行后底层源代码
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" <div class=\"header\">头部信息</div>\r\n");
out.write(" <div class=\"main\">主体内容</div>\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "/static/jsp/footer.jsp", out, false);
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
JSP标签请求转发
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--请求转发标签--%>
<jsp:forward page="/static/jsp/log.jsp"></jsp:forward>
</body>
</html>
EL表达式
什么是EL表达式?
EL(Expression Language) 是为了使JSP写起来更加简单。表达式语言的灵感来自于
ECMAScript和XPath表达式语言,它提供了在JSP中简化表达式的方法,让Jsp的代码更加简化
EL表达式语法格式
${}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
request.setAttribute("key","values值");
%>
jsp表达式输出的是:<%=request.getAttribute("key")%><br/>
EL表达式输出的是:${key}
<!--
2者等价,都能输出结果。
EL表达式的格式是${},EL表达式在输出null值的时候,输出的是空串。jsp表达式脚本输出null值的时候,输出的是null字符串
-->
</body>
</html>
EL表达式搜索域数据的顺序
EL表达式主要是在jsp页面中输出数据。主要是输出域对象中的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
pageContext.setAttribute("key","pageContext");
request.setAttribute("key","request");
session.setAttribute("key","session");
application.setAttribute("key","application");
%>
${key}
<!--当四个域中都有相同的key的数据的时候,EL表达式会按照四个域的从小到大的顺序进行搜索,然后输出-->
</body>
</html>
因为EL表达式专门输出域数据,所以我们可以使用EL表达式输出Bean的普通属性,数组属性。List集合属性,map集合属性
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Person person = new Person();
person.setName("张三");
person.setWife(new String[]{"小红","小绿","小黄"});
ArrayList<String> strings = new ArrayList<>();
strings.add("北京别墅");
strings.add("南京别墅");
strings.add("海南景房");
person.setHouses(strings);
Map<String, String> map = new HashMap<>();
map.put("爱好1","打球");
map.put("爱好2","吸烟");
map.put("爱好3","喝酒");
map.put("爱好4","打豆豆");
person.setMap(map);
pageContext.setAttribute("person",person);
%><br/>
<!--使用EL表达式输出数据的时候,首先找的是属性所对应的get方法-->
<%--输出Person的数据--%>
${person}<br/>
${person.name}<br/>
<!--.运算和[]中括号运算符
.运算,可以输出Bean对象某个属性的值
[]中括号运算,可以输出有序集合中某个元素的值,还可以输出map集合中key里含有特殊字符(这里的特殊字符指的是“.”,“-”等)的key的值(在[]用单引号或者双引号)
Map<String, String> map = new HashMap<>();
map.put("hobby.hobby.hobby","打球");
${person['hobby.hobby.hobby']}
-->
${person.wife[1]}<br/>
${person.houses}<br/>
${person.map}<br/>
<%--输出map集合某个元素值--%>
${person.map.爱好3}
</body>
</html>
关于一些运算符看这篇文章大佬的文章
其实运算跟Java的差不多,除了除法是带浮点数的,还有一些运算符逻辑啥的额外一些表达方式,例如8>9,可以写成8 gt 9,两者都是等价的;EL表达式也支持三元运算
empty运算
empty运算可以判断一个数据是否为空,如果为空,则输出true,否则输出false
以下几种情况为空
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//值为null的时候为空
request.setAttribute("emptyNull",null);
//值为空串的时候为空
request.setAttribute("emptystr","");
//值为Object类型数组,长度为零的时候为空
request.setAttribute("emptyObj",new Object[]{});
//list集合,元素个数为零
ArrayList<String> objects = new ArrayList<>();
request.setAttribute("emptyArr",objects);
//map集合,元素个数为零
Map<Object, Object> map = new HashMap<>();
request.setAttribute("emptyMap",map);
%>
${empty emptyNull}<br/>
${empty emptystr}<br/>
${empty emptyObj}<br/>
${empty emptyArr}<br/>
${empty emptyMap}<br/>
</body>
</html>
EL表达式的11个隐含对象
EL表达式中11个隐含对象,都是自己定义的,可以直接使用
| 变量 | 类型 | 作用 |
|---|---|---|
| pageContext | PageContext | 它可以获取jsp中9大内置对象 |
| pageScope | Map<String,Object> | 它可以获取pageContext域中的数据 |
| requestScope | Map<String,Object> | 它可以获取Request域中的数据 |
| sessionScope | Map<String,Object> | 它可以获取session域中的数据 |
| applicationScope | Map<String,Object> | 它可以获取ServletContext域中的数据 |
| param | Map<String,String> | 它可以获取请求参数的值 |
| paramValues | Map<String,String[]> | 它可以获取请求参数的值,可以获取多个值的时候使用 |
| header | Map<String,String> | 它可以获取请求头的信息 |
| headerValues | Map<String,String> | 它可以获取请求头的信息,它可以获取多个值的情况 |
| cookie | Map<String,Cookie> | 它可以获取当前请求的cookie信息 |
| initParam | Map<String,String> | 它可以获取在web.xml中配置的< context-param>上下文参数 |
EL获取四个特定域中的属性
前面我们说了,如果四个域对象如果存取
key相同的时候,输出域数据则是小到大的顺序范围,没有办法指定,而EL表达式的这4个隐藏对象则可以指定
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
pageContext.setAttribute("key","pageContext值");
request.setAttribute("key","request值");
%>
${requestScope.key}<br/>
${pageScope.key}<br/>
<!--以此类推...applicationScope、sessionScope去获取所对应的域数据值,只要选对EL表达式的域对象去使用,输出的是对应的域对象数据的值-->
</body>
</html>
pageContext
它可以获取jsp中9大内置对象
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${pageContext.request}
${pageContext.servletConfig}
${pageContext.session}
...等获取9大对象
</body>
</html>
pageContext的使用
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--
request.getScheme():获取请求的协议(返回用于发出此请求的方案的名称,例如http、https或ftp。不同的方案有不同的规则来构造url)
request.getServerName():获取服务器ip
request.getServerPort():获取请求的服务器端口号
request.getContextPath():获取当前的工程路径
request.getMethod():获取请求的方法
request.getRemoteHost():获取客户端的ip地址
session.getId():获取会话的id编号
-->
协议:${pageContext.request.scheme}<br/>
服务器ip:${pageContext.request.serverName}<br/>
服务器端口号:${pageContext.request.serverPort}<br/>
获取工程路径:${pageContext.request.contextPath}<br/>
获取请求方法:${pageContext.request.method}<br/>
获取客户端ip地址:${pageContext.request.remoteHost}<br/>
获取会话的id编号:${pageContext.session.id}<br/>
<!--
输出结果:
协议:http
服务器ip:localhost
服务器端口号:8081
获取工程路径:/cjjy
获取请求方法:GET
获取客户端ip地址:0:0:0:0:0:0:0:1
获取会话的id编号:E7099B32B789CF034B57A3A0B8F0512C
-->
</body>
</html>
其他EL表达式隐含对象的使用
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.cjjy.test.Person" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Map" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--username=zhangsan&password=10086-->
${param.username}
<!--输出请求参数username的值-->
${paramValues.username[0]}
<!--获取请求头User-Agent信息-->
${header['User-Agent']}<br/>
${ header.Connection }<br/>
${headerValues.Accept[0]}<br/>
<!--获取cookie名称-->
${cookie.JSESSIONID.name}<br/>
<!--获取cookie的值-->
${cookie.JSESSIONID.value}<br/>
${initParam}<br/>
${initParam.username}<br/>
</body>
</html>
补充
JSP和一些标签库所需要的依赖
<dependencies>
<!-- Servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.2.1</version>
</dependency>
<!-- JSTL表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
因为CSDN上Markdown语法不支持JSP代码,所以没办法高亮,只有HTML代码才能高亮,将就着看吧

