一、Jsp基础语法
1.1. JSP模板元素
JSP页面中的HTML内容称之为JSP模版元素。
JSP模版元素定义了网页的基本骨架,即定义了页面的结构和外观。
1.2. JSP脚本片段
JSP脚本片断用于在JSP页面中编写多行Java代码(在<%%>不能定义方法)。
语法:<%多行java代码%>
例如:
<%
int num = 0;
num = ++num;
out.println("num" + num);
%>
注意:
1、JSP脚本片断中只能出现java代码,不能出现其它模板元素, JSP引擎在翻译JSP页面中,会将JSP脚本片断中的Java代码将被原封不动地放到Servlet的_jspService方法中。
2、JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号(;)结束。
3、在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。
4、多个脚本片断中的代码可以相互访问
1.3. JSP表达式
JSP脚本表达式(expression)用于将程序数据输出到客户端,语法:<%=变量或表达式 %>
例如:
<%="123" %>
1.4. JSP声明
JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。语法:<%!java代码 %>
JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法。
例如
<%!
static{
System.out.println("静态代码块");
}
private String name = "xinzhi";
public void TestFun(){
System.out.println("成员方法");
}
%>
<%
TestFun();
out.println("name:" + name);
%>
1.5. JSP注释
在JSP中,注释有显式注释, 隐式注释,JSP自己的注释:
区别:
HTML的注释在浏览器中查看源文件的时候是可以看得到的,而JAVA注释和JSP注释在浏览器中查看源文件时是看不到注释的内容的。
二、Jsp原理
2.1. Jsp本质上是什么
浏览器向服务器发请求,不管访问的是什么资源,其实都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp编译成一个Servlet,所以我们访问jsp时,其实不是在访问jsp,而是在访问jsp翻译过后的那个Servlet。
所以jsp的本质其实就是个html模板,编译器会根据模板生成对应的servlet。
例如下面的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/"+path;
%>
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Insert Title here</title>
</head>
<body>
<%!
static {
System.out.println("静态代码块");
}
private String name = "IT老王";
public void TestFun(){
System.out.println("成员方法!");
}
%>
<%
TestFun();
out.println("name:" + name);
%>
</body>
</html>
当我们通过浏览器访问index.jsp时,服务器首先将index.jsp翻译成一个index_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到index_jsp.class的源代码文件index_jsp.java
package org.apache.jsp.web;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
static {
System.out.println("静态代码块");
}
private String name = "IT老王";
public void TestFun(){
System.out.println("成员方法!");
}
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
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('\n');
out.write('\n');
String path = request.getContextPath();
String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\n");
out.write(" <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">\n");
out.write(" <title>Insert Title here</title>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" ");
out.write('\n');
out.write(' ');
out.write(' ');
TestFun();
out.println("name:" + name);
out.write("\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
index_jsp这个类是继承org.apache.jasper.runtime.HttpJspBase这个类的,通过查看HttpJspBase源代码,可以知道HttpJspBase类是继承HttpServlet的,所以HttpJspBase类是一个Servlet,而index_jsp又是继承HttpJspBase类的,所以index_jsp类也是一个Servlet,所以当浏览器访问服务器上的index.jsp页面时,其实就是在访问index_jsp这个Servlet,index_jsp这个Servlet使用_jspService这个方法处理请求。
HttpJspBase源码如下:
packageorg.apache.jasper.runtime;
import java.io.IOException;//IO异常
import javax.servlet.ServletConfig;//小服务程序配置
import javax.servlet.ServletException;//小服务程序异常
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;//请求对象
import javax.servlet.http.HttpServletResponse;//响应对象
import javax.servlet.jsp.HttpJspPage;
import org.apache.jasper.compiler.Localizer;//定位器
/*
*HttpJspBase本身是个抽象类,继承了httpservlet实现了httpJspPage接口
*httpJspPage接口实现了servlet(),JspPage接口(两抽象方法jspDestroy,jspInit)而本身创建jspservice(request,response)方法,
用于JSP页面工作,同时继承了jsppage两个抽象方法又从继承的servlet接口中实现了destroy,getservletconfig,getservletinfo,init,service(五个),
所以httpJsppage共实现了七个父类接口的抽象方法(jsppage两个,servlet五个)
*/
*/
*/
*五个),本身创建一个jspservice方法用于jsp页面工作
*---------------------------------------------------------------------------------------------------------------
*HttpServlet类继承了servlet接口(5个方法)和servletconfig接口(三个方法)
*/
public abstractclass HttpJspBase extends HttpServlet implements HttpJspPage{
protected HttpJspBase(){
}
public final void init(ServletConfig config)
throws ServletException{
super.init(config);
jspInit();
_jspInit();
}
public String getServletInfo(){
returnLocalizer.getMessage("jsp.engine.info");
}
public final void destroy(){
jspDestroy();
_jspDestroy();
}
public final void service(HttpServletRequestrequest, HttpServletResponse response)
throws ServletException, IOException{
_jspService(request, response);
}
public void jspInit(){
}
public void _jspInit(){
}
public void jspDestroy(){
}
protected void _jspDestroy(){
}
public abstract void _jspService(HttpServletRequest paramHttpServletRequest, HttpServletResponseparamHttpServletResponse)
throws ServletException, IOException;
}
2.2. _jspService方法
问题1:Jsp页面中的html排版标签是如何被发送到客户端的?
浏览器接收到的这些数据,都是在_jspService方法中使用如下的代码输出给浏览器的。
问题2:Jsp页面中的java代码服务器是如何执行的?
在jsp中编写的java代码会被翻译到jspService方法中去,当执行jspService方法处理请求时,就会执行在jsp编写的java代码了,所以Jsp页面中的java代码服务器是通过调用_jspService方法处理请求时执行的。
2.3. jsp在服务器的执行流程
第一次执行:
1. 客户端通过电脑连接服务器,因为是请求是动态的,所以所有的请求交给WEB容器来处理。
2. 在容器中找到需要执行的*.jsp文件
3. 之后*.jsp文件通过转换变为 *.java文件
4. *.java文件经过编译后,形成 *.class文件
5. 最终服务器要执行形成的*.class文件
第二次执行:
-
因为已经存在了*.class文件,所以不在需要转换和编译的过程
修改后执行:
-
源文件已经被修改过了,所以需要重新转换,重新编译。
三、 JSP指令
3.1. JSP指令标识的语法格式
-
指令名:用于指定指令名称 在JSP中包含 page、 include、 taglib 这3种指令
-
属性: 用于指定指令属性名称 不同的指令包含不同的属性 在同一个指令中可以设置多个属性 各个属性之间用逗号或者空格隔开
-
属性值:用于指定属性的值
注意点:
指令标识<%@%>是一个完整的指令,不能够添加空格,但是便签中定义的属性与指令名之间是有空格的
3.2. Page指令
page指令是JSP页面中最常见的指令,用于定义整个JSP页面的相关属性
语法格式
<%@ page 属性1 = “属性1的值” 属性2 = “属性2的值” ......%>
page指令的相关属性
language属性
用于设置整个JSP页面的使用的语言,目前只支持JAVA语言,改属性默认值是java
<%@ page language="java" %>
import属性
设置JSP导入的包
<%@ page import="java.util.*" %>
contentType属性
这种JSP页面的编码格式,也就是指定文件编码
设置JSP页面的MIME类型和字符编码
<%@ page contentType="text/html;charset=UTF-8" %>
session属性
设置页面是否使用HTTP的session会话对象。Boolean类型,默认值是true
<%@ page session="false" %>
-
session是JSP的内置对象之一
autoFlush属性
设置JSP页面缓存满时,是否自动刷新缓存,默认值是:true,如果这种为false,则当页面缓存满时就会抛出异常
<%@ page autoFlush="false" %>
isErrorPage属性
可以把当前页面设置成错误处理页面来处理另外jsp页面的错误
<%@ page isErrorPage="true" %>
errorPage属性
指定当前jsp页面异常错误的另一个Jsp页面,指定的jsp页面的isErrorPage属性必须为true,属性值是一个url字符串
<%@ page errorPage="errorPage.jsp" %>
3.3. include指令
include指令用于引入其它JSP页面,如果使用include指令引入了其它JSP页面,那么JSP引擎将把这两个JSP翻译成一个servlet。所以include指令引入通常也称之为静态引入。
语法:<%@ include file="relativeURL"%>
file属性用于指定被引入文件的路径。路径以"/"开头,表示代表当前web应用。
注意细节:
-
被引入的文件必须遵循JSP语法。
-
被引入的文件可以使用任意的扩展名,即使其扩展名是html,JSP引擎也会按照处理jsp页面的方式处理它里面的内容,为了见明知意,JSP规范建议使用.jspf(JSP fragments(片段))作为静态引入文件的扩展名。
-
由于使用include指令将会涉及到2个JSP页面,并会把2个JSP翻译成一个servlet,所以这2个JSP页面的指令不能冲突(除了pageEncoding和导包除外)。
3.4.taglib指令
导入资源,通常用于导入标签库(prefix:前缀,可自定义)
eg:
<%@ taglib prefix="s" uri="/struts-tags"%>(导入struts标签库)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>(导入jstl标签库)
四、 JSP标签
4.1. Jsp标签分类
1)内置标签(动作标签): 不需要在jsp页面导入标签
2)jstl标签: 需要在jsp页面中导入标签
3)自定义标签 : 开发者自行定义,需要在jsp页面导入标签
JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。
常用内置标签有以下三个:
-
标签一< jsp:include >
< jsp:include >标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面
执行时的引入方式称之为动态引入。
语法:
<jsp:include page="header.jsp/header.html" flush="true"></jsp:include >
标签与include指令的区别:
< jsp:include>标签是动态引入, < jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。 而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。
-
标签二< jsp:forward>
< jsp:forward>标签用于把给另外一个资源(服务器跳转,地址不变)
-
标签三< jsp:param>
<%--使用jsp:forward标签进行请求转发--% >
<jsp:forward page="/index2.jsp" >
<jsp:param value="10086" name="num"/>
<jsp:param value="10010" name="num2"/>
</jsp:forward >
五、九大内置对象
5.1.request 对象
代表的是来自客户端的请求 , 客户端发送的请求封装在 request 对象中 , 通过它才能了解到用户的请求信息 , 然后作出响应 , 它是 HTTPServletRequest 的实例
作用域为 request ( 响应生成之前 )
5.2. response 对象
对象代表的是对客户端的响应 , 也就是说可以通过 response 对象来组织发送到客户端的数据 ; 但是由于组织方式比较底层 , 所以不建议初学者使用 , 需要向客户端发送文字时直接使用 ; 它是HttpServletResponse 的实例 ;
作用域为 page ( 页面执行期 )
常用方法
5.3. session 对象
指的是客户端与服务器的一次会话 , 从客户连接到服务器的一个 WebApplication 开始 , 直到客户端与服务器断开连接为止 ; 它是 HTTPSession 类的实例
作用域为 session ( 会话期 )
5.4. out 对象
out 对象是 JspWriter 类的实例,是向客户端输出内容常用的对象 ;
作用域为 page ( 页面执行期 )
5.5. page 对象
page 对象就是指向当前 JSP 页面本身 , 有点象类中的 this 指针 , 它是 Object 类的实例 ; page 对象代表了正在运行的由 JSP 文件产生的类对象 , 不建议初学者使用 ;
作用域为 page ( 页面执行期 )
常用方法:
5.6. application 对象
实现了用户间数据的共享 , 可存放全局变量 ; 它开始于服务器的启动 , 直到服务器的关闭 , 在此期间 , 此对象将一直存在 ; 这样在用户的前后连接或不同用户之间的连接中 , 可以对此对象的同一属性进行操作 ;在任何地方对此对象属性的操作 , 都将影响到其他用户对此的访问 ; 服务器的启动和关闭决定了application 对象的生命 ; 它是 ServletContext 类的实例 ;
作用域为 application
5.7. pageContext 对象
提供了对 JSP 页面内所有的对象及名字空间的访问 , 也就是说他可以访问到本页所在的 session , 也可以取本页面所在的 application 的某一属性值 , 他相当于页面中所有功能的集大成者 , 它的本类名也叫pageContext ;
作用域为 Pageconfig 对象
5.8. config 对象
config 对象是在一个 Servlet 初始化时 , JSP 引擎向它传递信息用的 , 此信息包括 Servlet 初始化时所要用到的参数 ( 通过属性名和属性值构成 ) 以及服务器的有关信息 ( 通过传递一个 ServletContext 对象 ) ;
作用域为 page
5.9. exception 对象
这是一个例外对象 , 当一个页面在运行过程中发生了例外 , 就产生这个对象 ; 如果一个JSP页面要应用此对象 , 就必须把 isErrorPage 设为true , 否则无法编译 ; 他实际上是 Throwable 的对象 ;
作用域为 page
5.10. 总结
六、JSP属性作用域
JSP中提供了四种属性范围(四大域对象),如下:
-
当前页(pageContext):一个属性只能在一个页面中取得,跳转到其他页面无法取得
-
一次服务器请求(request):一个页面中设置的属性,只要经过了请求重定向之后的页面可以继续取得。
-
一次会话(session):一个用户设置的内容,只要是与此用户相关的页面都可以访问(一个会话表示一个人,这个人设置的东西只要这个人不走,就依然有效),关了浏览器就不见了。
-
上下文中(application):在整个服务器上设置的属性,所有人都可以访问
七、静态资源的路径问题
在Jsp中调用图片、JS脚本等,针对取得的路径有两种调用方式:
1、放入Body中生成绝对路径(不建议)
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>image调用</title>
</head>
<body>
<h1>图片访问</h1>
<div>
<img alt="图片" src="<%=basePath/image/a.png%>">
</div>
</body>
</html>
2、在Head中指定,Body中使用相对路径(建议)
<%
String path = request.getContextPath();
String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>image调用</title>
<base href="<%=basePath%>">
</head>
<body>
<h1>图片访问</h1>
<div>
<img alt="图片" src="image/a.png">
</div>
</body>
</html>
八、错误页面和404页面
<error-page>
<error-code>404</error-code>
<location>/pages/404.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/pages/err.jsp</location>
</error-page>
<welcome-file-list>
<welcome-file>/pages/home.jsp</welcome-file>
</welcome-file-list>
图片居中的方式:
可以绝对定位、浮动等手段都可以,这里使用一下弹性容器flex
<div style="display: flex;justify-content: center;align-content: center;width: 100%;height: 100%">
<img src="images/404.png">
</div>