1.背景(why study)
1.2 jsp小历史
sun公司早期推出了servlet技术,用于动态页面的html输出。但是,由于直接使用响应流输出的html格式内容,不方便修改和调整html代码。为了解决这一麻烦问题,衍生出了JSP技术,通过嵌入标签的方式写入java代码。总之:使用此技术的目的是为了将数据与页面结合起来,数据不断变化,页面跟着不断变化,简称为动态页面。编译流程为JSP——Servlet——class.
1.3 login.jsp编译成login_jsp.java文件
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 = org.apache.jasper.runtime.JspSourceImports { javax.servlet.jsp.JspFactory.getDefaultFactory();
1.4 查看源码可见servlet的生命周期方法
public void _jspInit() { } public void _jspDestroy() { } public void _jspService(final HttpServletRequest request, final HttpServletResponse response)
1.5 查看service方法,对比jsp代码和servlet代码
从代码可以看出JSP内置对象的初始化操作,切记servlet没有9大内置对象(一部分有对应对象,一部分没有 page、pageContext、exection)。简略描述下PageContext:页面上下文,可以拿到页面上的所有东西包括对象
1.5.1 嵌入java代码前后比对final javax.servlet.jsp.PageContext pageContext; HttpSession session = null; final ServletConfig config; final ServletContext application; final Object page = this; javax.servlet.jsp.JspWriter out = null; javax.servlet.jsp.PageContext _jspx_page_context = null; javax.servlet.jsp.JspWriter _jspx_out = null; try { pageContext = _jspxFactory.getPageContext(this, request, response, response.setContentType("text/html;charset=UTF-8"); null, true, 8192, true); config = pageContext.getServletConfig(); _jspx_page_context = pageContext; application = pageContext.getServletContext(); _jspx_out = out; session = pageContext.getSession(); out = pageContext.getOut();
1.5.2 发现html代码用输出语句进行输出,java代码则直接执行。
<head> <% request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); <link rel="stylesheet" type="text/css" href="MyCss.css"/> %> </head> out.write("<head>\n"); out.write(" "); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); out.write("\n"); out.write(" <link rel=\"stylesheet\" type=\"text/css\" href=\"MyCss.css\"/>\n"); out.write("</head>\n");
1.5.3 发现碰到java代码后直接执行,输出数据,打印
<script>
var error=<%=request.getAttribute("error")%>;
if(error==0){ alert("账号密码错误,请重新输入!");
}
out.write("<script>\n");
out.write(" var error=");
out.print(request.getAttribute("error"));
out.write(";\n");
out.write(" alert(\"账号密码错误,请重新输入!\");\n");
out.write(" if(error==0){\n");
out.write(" }\n");
2.内容(what study)
2.1.页面组成结构
(1)HTML
(2)JSP标记(指令、动作、自定义)<%@> <jsp: >
指令标记:
原理:翻译阶段提供全局信息,所有指令元素在整个JSP页面都有效。指令标记通知JSP引擎如何处理JSP页面。
1.include指令标记
原理:直接插入一段代码,属于静态的,先合并成一个jsp文件后才进行编译。由于属于同一个页面,所以一些语法规则要遵守。(不能对出import外的其他属性赋值多次,将会报错)
方法:<%@ include file="文件URL" %>
2.page指令标记
原理:只能应用本页面的指令,可以用来定义JSP页面的全局属性并设置属性值,page指令可以修改多个属性,与写入顺序无关,只是习惯把这类指令写在开头而已。(除import属性以外,其他属性只能出现一次)
例如属性有:
定义脚本语言:<%page language="java">
导入包:<%page import="java.util.*">
继承<%page extends="package.class">
指定页面输出内容的格式 <%page contentType="text/html"; charset=gb2312">
抛出异常的时候自动跳转页面 <%page errorPage="URL">
是否定义本jsp页面为错误页面 <%page isErrorPage="true"> (可以使用内置的execption对象)
3.taglib指令标记
原理:为了简化jsp页面的开发,将一些公共部分的逻辑代码抽取出来放到一个.tag文件中
方法:<% taglib tagdir="标记资源位置" prefix="前缀">
动作标记:
原理:在执行阶段为页面提供插件或动态引入资源,就是说实际上会编译成两个servlet,只是把另一个servlet的返回结果拿到而已,所以说动作标记不要遵守jsp的页面规定,因为是两个页面,两次编译。
1.jsp:include
原理:include动作在执行阶段才处理被插入的文件,可动态传递参数,处理灵活,但是运行速度慢。
方法:<jsp:include page="URL" flush=true|false>
<jsp:param name="name" value="value"/>
</jsp :include>
可传递参数,参数可以通过request.getParameter()获取
2.jsp:forward
原理:在原页面跳转到另外一个页面,但是地址不会改变。
方法:<jsp:forward page="URL">
同样也可以传递参数,此处不再描述。
3.jsp:plugin(省略)
4.jsp:useBean原理:javaBean是一种可以重复使用的软件组件,是用java语言编写的一种类。JSP引擎根据useBean中id属性指定的名字,在一个同步块中,查找内置对象pageContext中是否包含该id指定的名字和scope指定的作用域的对象。如果存在则分配。根据scope范围的不同,useBean的可共享域也不同。
方法:<jsp:useBean id="bean实例名字" class="bean完整类名">
<scope="page|request|session|application"> page:作用域只在当前页面
...以此类推
</jsp:useBean>
5.jsp:setProperty
原理:设置useBean的属性值,功能上可以类似于springmvc的属性自动映射
方法:<jsp:setProperty name="bean的名字" property="bean的属性" value="xx">
直接赋值
<jsp:setProperty param="请求的参数名字">
写上参数名字,进行值的映射
<jsp:setProperty param="*">
所有复合的参数名字,全部都映射
(3)java代码片段<% %>
实际上就是java代码片段,从源代码可以看出来全部一股脑都在servlet的service方法里面,那么理所当然的所有定义的变量或者程序段都位于方法里面,所以是局部变量,它跟成员变量不同,所以每个用户的变量都是新的变量。
方法:
利用java代码可以重复渲染某些数组的数据。
<% for(int i=0;i<10;i++){ %>
html代码、、、
<% } %>
(4)声明变量、方法、对象<%! %>
原理:由于遵循单例原则,多用户同时访问同一个页面的时候都是同一个单例,所以理所当然的共享成员变量。
方法:<%! int i=6;%> 记得要加分号
<%! Circle a=new Circle();%>
(5)表达式 <%= %>
原理:直接使用PrintWriter.print()输出表达式的值,这个表达式其实就是java表达式,这个表达式理所当然的可以访问JSP的各种内部对象。
方法:<%= MyDate.toLocalString()%>
(6)注释(HTML、JSP、脚本语言)
HTML:<!-- -->
JSP <%-- --%>
脚本语言:java 编译自动忽略
//
/* */
3.总结(after study)
优点:
1.jsp引擎实行单例模式,减少内存开销。
2.动作指令和指示指令(include),可以按照场景去使用,需要提前得到结果的肯定是先用动作指令,将一些重复代码提炼出来则用指示指令。
3.jsp:usebean,也就是pojo了,可以根据作用域去实例化,有sping容器管理bean的概念和技术。
4.声明变量,可以做一些需要所有用户共享变量的功能
5.taglib自定义标签,可以将一些重复可提炼的工具逻辑程序段提取出来,使用自定义标签代替
缺点:
1.java代码和html代码混合,混乱不堪,解决办法有使用jstl标签技术和EL表达式
2.动态页面的通病,没有彻底与前后端分离(是否分离看业务需要)