总体来说jsp和el和jstl等都是java的标签编程,其工作原理都是一样的,使用到了反射等一些技术
jsp标签:
javabean
bean:
package senssic.demo.bean;
public class UserBean {
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 使用javabean -->
<!-- 可以使用里面的scop属性更改作用范围,默认为page范围 -->
<jsp:useBean id="user" class="senssic.demo.bean.UserBean"></jsp:useBean>
<!-- 设置属性 -->
<%
user.setUsername("senssic");
%>
<jsp:setProperty property="age" name="user" value="20"/>
<!-- 获得属性 -->
用户名:<jsp:getProperty property="username" name="user"/>
年龄:${user.age}
头信息:${header}
</body>
</html>
tomcat产生的java文件,一看就明白了标签原理了
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class javabean_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.AnnotationProcessor _jsp_annotationprocessor;
public Object getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());
}
public void _jspDestroy() {
}
public void _jspService(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException {
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
JspWriter _jspx_out = null;
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("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<!-- 使用javabean -->\r\n");
out.write("<!-- 可以使用里面的scop属性更改作用范围,默认为page范围 -->\r\n");
senssic.demo.bean.UserBean user = null;
synchronized (_jspx_page_context) {
user = (senssic.demo.bean.UserBean) _jspx_page_context.getAttribute("user", PageContext.PAGE_SCOPE);
if (user == null){
user = new senssic.demo.bean.UserBean();
_jspx_page_context.setAttribute("user", user, PageContext.PAGE_SCOPE);
}
}
out.write("\r\n");
out.write("<!-- 设置属性 -->\r\n");
user.setUsername("senssic");
out.write('\r');
out.write('\n');
org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(_jspx_page_context.findAttribute("user"), "age", "20", null, null, false);
out.write("\r\n");
out.write("<!-- 获得属性 -->\r\n");
out.write("用户名:");
out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString((((senssic.demo.bean.UserBean)_jspx_page_context.findAttribute("user")).getUsername())));
out.write("\r\n");
out.write("年龄:");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user.age}", java.lang.String.class, (PageContext)_jspx_page_context, null, false));
out.write("\r\n");
out.write("头信息:");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${header}", java.lang.String.class, (PageContext)_jspx_page_context, null, false));
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
其中定义jsp标签的dtd文件在:
jsp-api.jar:javax.servlet.jsp.resources.jspxml.dtd
EL表达式语言
el是通过java程序对el的表达式进行解析,然后通过反射和jsp标签一起共同发生作用
el的内置对象
"applicationScope", :表示从applicationScope属性范围内查找输出属性
"cookie", :取出cookie的数据
"header",:取得一个头信息数据
"headerValues",:取出一组头信息数据
"initParam",:取得配置的初始化参数
"pageContext",:表示javax.servlet.jsp.PageContext对象
"pageScope",表示冲page属性范围查找输出属性
"param",:接受传递到本页面的参数
"paramValues",:接受传递到本页面的一组参数
"requestScope", :表示从request属性范围内查找输出属性
"sessionScope":表示从session属性范围内查找输出属性
这些参数在jsp-api.jar:javax.servlet.jsp.el.ImplicitObjectElResolver
自定义el表达式语言:
直接使用el的扩展就可以自己编写了
先编写java处理代码:
package senssic.demo.el;
public class ElClass {
public static int max(int a, int b) {//必须是静态方法
return a > b ? a : b;
}
}
编写tld描述文件:
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
<!-- 当然你也可以使用 web-jsptaglibrary_2_0.dtd-->
<tlib-version>1.0</tlib-version>
<short-name>mytag</short-name>
<function>
<name>max</name>
<function-class>senssic.demo.el.ElClass</function-class>
<function-signature>
int max(int,int)
</function-signature>
<example>${mytag:max(20,30)}</example>
</function>
</taglib>
编写jsp文件并引用(当然也可以将tld文件引用写在web.xml里面)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="mytag" uri="/WEB-INF/taglib/mytag.tld" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>使用自定义el表达式</h1>
${mytag:max(20,30)}
</body>
</html>
当然这个el语言的功能太弱了,但自己定义的el是不能获取到request和servlet等对象的。因为el是内层原理是使用java分解((java.lang.String) org.apache.jasper.runtime.PageContextImpl
.proprietaryEvaluate("${header}", java.lang.String.class,
_jspx_page_context, null, false))在jsp的java源码中。如果真想使用到标签得到pagecontext等属性需要使用jsp标签编程
jsp自定义标签
无标签体
java源码:
package senssic.demo.tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
public class JspTag extends TagSupport {
// 继承tagsupport就可使用其中的pageContext来获取各个jsp内置对象属性(通过反射实现的)
// 各个属性可以控制标签的操作如:skip_body:跳过标签体等
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int doStartTag() throws JspException {
JspWriter jWriter = pageContext.getOut();
try {
if (pageContext.getAttribute(name) != null) {
jWriter.write(name + "的属性范围为page");
} else if (pageContext.getServletContext().getAttribute(name) != null) {
jWriter.write(name + "的属性范围为application");
} else if (pageContext.getRequest().getAttribute(name) != null) {
jWriter.write(name + "的属性范围为request");
} else if (pageContext.getSession().getAttribute(name) != null) {
jWriter.write(name + "的属性范围为session");
} else {
jWriter.write("不能找到对应的属性!");
}
} catch (Exception e) {
}
return SKIP_BODY;
}
}
tld描述文件
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>jsptag</short-name>
<tag>
<name>showscope</name>
<tag-class>senssic.demo.tag.JspTag</tag-class>
<!-- body-content将忽视tag的标签体 -->
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>true</required>
<!-- 支持表达式<%%> -->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
jsp文件:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="mytag" uri="jsptag"%><!--这个实在web.xml配置了,也可以直接使用uri指向-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
pageContext.setAttribute("pagescope", "pagename");
request.setAttribute("requsetscope", "requestname");
session.setAttribute("sessionscope", "sessionname");
application.setAttribute("application", "applicationname");
%>
<mytag:showscope name="pagescope"/>
<br>
<mytag:showscope name="something"/>
</body>
</html>
web.xml--如果使用web中配置的话
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<jsp-config>
<taglib>
<taglib-uri>jsptag</taglib-uri>
<taglib-location>/WEB-INF/taglib/jsptag.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
有标签体
java源文件:
package senssic.demo.tag;
import java.io.IOException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
public class JspBodyTag extends TagSupport {
private String value;
private String name;
private int i = 0;
private Cookie[] cookie;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int doStartTag() throws JspException {
HttpServletRequest hRequest = (HttpServletRequest) pageContext
.getRequest();
cookie = hRequest.getCookies();
if (!(cookie.length < 0)) {
pageContext.setAttribute(name, cookie[i].getName());
pageContext.setAttribute(value, cookie[i].getValue());
return EVAL_BODY_INCLUDE;
} else {
try {
pageContext.getOut().write("没有发现有cookie");
} catch (IOException e) {
e.printStackTrace();
}
return SKIP_BODY;
}
}
@Override
public int doAfterBody() throws JspException {
i++;
if (i < cookie.length) {
pageContext.setAttribute(name, cookie[i].getName());
pageContext.setAttribute(value, cookie[i].getValue());
return EVAL_BODY_AGAIN;
} else {
return SKIP_BODY;
}
}
}
tld描述语言
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">
<tlib-version>1.0</tlib-version>
<short-name>JspBodyTag</short-name>
<tag>
<name>cookieinfo</name>
<tag-class>senssic.demo.tag.JspBodyTag</tag-class>
<body-content>JSP</body-content><!--输出标签体内部的jsp-->
<attribute>
<description>return the cookie name corresponding value</description>
<name>value</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>return the cookie name</description>
<name>name</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
jsp文件:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="myjbt" uri="/WEB-INF/taglib/jspbodytag.tld"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<myjbt:cookieinfo name="name" value="value">
cookie名字:${name}<br>
cookie值:${value}<br>
</myjbt:cookieinfo>
</body>
</html>
注:也可以直接继承BodyTagSupport类来处理标签体(很重要),有兴趣的可以研究一下,比如更复杂的将name和value变成jsp中的变量使用需要使用(BodyIterateTagExtraInfo类支持)并需要在标签tld文件中中使用<tag><tei-class>xxx.xxx.xx</tei-class></tag>
当然也有简单的标签编程方法就是使用继承SimpleTagSupport类,这样我们设置好属性不用再每次反射调用,而是封装好了,直接使用父类的getJspBody().invoke(xxx);就能达到每次的输出。
当然还可以使用DynamicAttributes类来动态设置<attribute>的属性
jsp标准标签库jstl
原理都是一样的,封装了我们经常使用的标签下载地址: http://jstl.java.net/download.html,一般下载
- JSTL Implementation因为jstl api是不是开发版的需要我们自己实现。
- tld可以再web.xml <jsp-config></jsp-config>中配置也可以直接在jsp中引用