一、JSP概念
JSP全称是Java Server Pages,它和Servlet技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。其特点在于,写JSP就像在写HTML,但它相比html而言,html只能为用户提供静态数据,而JSP技术允许在页面中嵌套Java代码,为用户提供动态数据。
二JSP原理
1.web服务器调用执行jsp页面
浏览器向服务器发送请求,其都是在访问Servlet,所以当访问一个jsp页面时,其实也是在访问一个Servlet,服务器在执行jsp的时候,首先把jsp翻译成一个servlet,因此访问jsp就是在访问servlet。
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html >
<!-- Mirrored from www.zi-han.net/theme/hplus/login_v2.html by HTTrack Website Copier/3.x [XR&CO'2014], Wed, 20 Jan 2016 14:19:49 GMT -->
<head>
<base href="<%=basePath%>" target="_blank" rel="external nofollow" >
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>系统登录</title>
</head>
<body class="gray-bg">
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<div>
<h3 class="logo-name"></h3>
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="用户名" id="username">
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="密码" id="password">
</div>
<button type="button" class="btn btn-primary block full-width m-b" style="background-color: #00b7ee" οnclick="login()">登 录</button>
</div>
</div>
</body>
</html>
当我们访问login.jsp时,服务器首先将login.jsp翻译成login_jsp.class,在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到源码文件login_jsp.java,如下:
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class login_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
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 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 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 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');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html en\">\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("<!-- Mirrored from www.zi-han.net/theme/hplus/login_v2.html by "
+ "HTTrack Website Copier/3.x [XR&CO'2014], Wed, 20 Jan 2016 14:19:49 GMT -->\r\n");
out.write("<head>\r\n");
out.write("\t<base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" <meta charset=\"utf-8\">\r\n");
out.write(" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\r\n");
out.write("\r\n");
out.write(" <title>系统登录</title>\r\n");
out.write("\r\n");
out.write("</head>\r\n");
out.write("\r\n");
out.write("<body class=\"gray-bg\">\r\n");
out.write(" <div class=\"middle-box text-center loginscreen animated fadeInDown\">\r\n");
out.write(" <div>\r\n");
out.write(" <div>\r\n");
out.write("\r\n");
out.write(" <h3 class=\"logo-name\"></h3>\r\n");
out.write("\r\n");
out.write(" </div>\r\n");
out.write(" <div class=\"form-group\">\r\n");
out.write(" <input type=\"text\" class=\"form-control\" placeholder=\"用户名\" id=\"username\">\r\n");
out.write(" </div>\r\n");
out.write(" <div class=\"form-group\">\r\n");
out.write(" <input type=\"password\" class=\"form-control\" placeholder=\"密码\" id=\"password\">\r\n");
out.write(" </div>\r\n");
out.write(" <button type=\"button\" class=\"btn btn-primary block full-width m-b\" "
+ "style=\"background-color: #00b7ee\" οnclick=\"login()\">登 录</button>\r\n");
out.write(" </div>\r\n");
out.write(" </div>\r\n");
out.write("</body>\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("</html>\r\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);
}
}
}
这里可以看到,login_jsp这个类继承于org.apache.jasper.runtime.HttpJspBase,查看Tomcat服务器源代码(apache-tomcat-8.5.23-src\java\org\apache\jasper\runtime目录),HttpJspBase源码如下:
import java.io.IOException;
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;
/**
* This is the super class of all JSP-generated servlets.
*
* @author Anil K. Vijendran
*/
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
private static final long serialVersionUID = 1L;
protected HttpJspBase() {
}
@Override
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
@Override
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
@Override
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
@Override
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
@Override
public void jspInit() {
}
public void _jspInit() {
}
@Override
public void jspDestroy() {
}
protected void _jspDestroy() {
}
@Override
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}
HttpJspBase继承自HttpServlet,而login_jsp又继承自HttpJspBase,所以当访问login.jsp时,其实就是访问Servlet
2.jsp中的html发送到客户端
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="http://localhost:8080/JavaWeb_Jsp_Study_20140603/" target="_blank" rel="external nofollow" >
<title>First Jsp</title>
</head>
<body>
Hello Jsp
</body>
</html>
html在_jspService方法中输出给浏览器:
out.write('\r');
out.write('\n');
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
out.write("\r\n");
out.write("\r\n");
out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <base href=\"");
out.print(basePath);
out.write("\">\r\n");
out.write(" \r\n");
out.write(" <title>First Jsp</title>\r\n");
out.write("\t\r\n");
out.write(" </head>\r\n");
out.write(" \r\n");
out.write(" <body>\r\n");
out.write(" ");
out.print("Hello Jsp");
out.write("\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
在jsp中编写的java代码和html代码都会被翻译到_jspService方法中去,在jsp中编写的java代码会原封不动地翻译成java代码,如<%out.print("Hello Jsp");%>直接翻译成out.print("Hello Jsp");,而HTML代码则会翻译成使用out.write("<html标签>\r\n");的形式输出到浏览器。在jsp页面中编写的html排版标签都是以out.write("<html标签>\r\n");的形式输出到浏览器,浏览器拿到html代码后才能够解析执行html代码。
查看_jspService方法可以看到,Web服务器在调用jsp时,会给Jsp提供如下的8个java对象。
PageContext pageContext;
HttpSession session;
ServletContext application;
ServletConfig config;
JspWriter out;
Object page = this;
HttpServletRequest request,
HttpServletResponse response
这8个java对象在Jsp页面中是可以直接使用的,如下所示:
<%
session.setAttribute("name", "session对象");//使用session对象,设置session对象的属性
out.print(session.getAttribute("name")+"<br/>");//获取session对象的属性
pageContext.setAttribute("name", "pageContext对象");//使用pageContext对象,设置pageContext对象的属性
out.print(pageContext.getAttribute("name")+"<br/>");//获取pageContext对象的属性
application.setAttribute("name", "application对象");//使用application对象,设置application对象的属性
out.print(application.getAttribute("name")+"<br/>");//获取application对象的属性
out.print("Hello Jsp"+"<br/>");//使用out对象
out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");//使用page对象
out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");//使用config对象
out.print(response.getContentType()+"<br/>");//使用response对象
out.print(request.getContextPath()+"<br/>");//使用request对象
%>
运行结果:
三、基础语法
1.JSP模板元素
JSP页面中的HTML内容称之为JSP模板元素。
JSP模板元素定义了网页的基本骨架,即定义了页面的结构和外观。
2.JSP表达式
JSP脚本表达式(expression)用于将程序数据输出到客户端。
语法:<%= 变量或表达式%>
举例:
<%= new java.util.Date() %>
3.JSP脚本片段
JSP脚本片段(scriptlet)用于在jsp页面中编写多行Java代码。
语法:
<%
多行java代码
%>
在<% %>中可以定义变量、编写语句、不能定义方法。
举例:
<%
int sum=0;//声明变量
/*编写语句*/
for (int i=1;i<=100;i++){
sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
注意:
- JSP脚本片段中只能出现Java代码,不能出现其他模板元素,JSP引擎在翻译JSP页面中,会将JSP脚本片段中的Java代码放到_jspService方法中。
- JSP脚本片段中的Java代码必须严格遵循Java语法,例如,每执行语句后面必须用分号结束。
- 在一个JSP页面中可以有多个脚本片段,在两个或多个脚本之间可以嵌入文本、HTML标记和其他JSP元素。
例如:
<%
int x = 10;
out.println(x);
%>
<p>这是JSP页面文本</p>
<%
int y = 20;
out.println(y);
%>
4.JSP声明
JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而Jsp声明中的java代码被翻译到_jspService方法的外面。语法:
<%!
java代码
%>
所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法 。
多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。
JSP声明案例:
举例:
<%!
static {
System.out.println("loading Servlet!");
}
private int globalVar = 0;
public void jspInit(){
System.out.println("initializing jsp!");
}
%>
<%!
public void jspDestroy(){
System.out.println("destroying jsp!");
}
%>
5.JSP注释
在JSP中,注释有两大类:
显式注释:直接使用HTML风格的注释:<!- - 注释内容- ->
隐式注释:直接使用JAVA的注释://、
JSP自己的注释:<%- - 注释内容- -%>
<!--这个注释可以看见-->
<%
//JAVA中的单行注释
/*
JAVA中的多行注释
*/
%>
<%--JSP自己的注释--%>