拿起笔来做刀枪 · 之三 再造一个jsp(java sign pages)
2014-07-28 14:49
302 查看
JSP的全称叫做: java server pages。
我们这里也打造一个jsp, 名称叫做 java sign pages。
区别在于 没有 server 这个字样。 我会尝试打造一个 类似于 freemarker的模板标记语言, 从而,让 我们所写的 viewer 和 server 分离。
虽然我们现在还毫无头绪,但是,可以回想一下jsp 和 servlet的关系:
事实上,jsp就是servlet未编译版本,任何jsp最终都被tomcat容器编译到work目录并以java类的形态执行。
你可以在 你的tomcat运行目录中看到端倪:
你的webroot下的jsp页面的最终形态是:
当然tomcat还提供一个编译前版本:
如果我们也这么照葫芦画瓢的来一份不就OK了?
你可以参考一下我的博文:
生成一个java类,调用
工具进行编译,然后用
进行加载,并使用。
先看一个简单的例子,试验一下我们的想法是否可行:
创建一个接口:
试验成功!
让我们整理下代码:
运行:
同时,可以看到,
我们在效果上实现了 tomcat 对jsp说干的事情:)
现在,让我们来进行第二步工作,定义我们的标记语言格式。
同样,我们参考jsp已经有的标记做一个子集,如下所示:
我们将支持:
这样的约束条件足够我们说明问题,并可以很容易的进行扩展:)
让我们先创建 一个接口:
然后编译jsp文件,动态的实现这个接口,
注意,假设我们在方法内定义了一个返回结果result,那么我们要将
由此,我们获得了一下代码实现:
最后,让我们整合以上的代码,完成我们的工作:
run的结果为:
jsp模板内容为:
请注意模板中的context对象,显而易见,我用它取代了jsp中的上下文:page、session、request、application
同时,我们保留了servlet中的 Printer类型实例: out
动态生成的java文件:
main方法输出结果:
结果符合预期,我们造出了一个新的 模板工具~~!
我们这里也打造一个jsp, 名称叫做 java sign pages。
区别在于 没有 server 这个字样。 我会尝试打造一个 类似于 freemarker的模板标记语言, 从而,让 我们所写的 viewer 和 server 分离。
虽然我们现在还毫无头绪,但是,可以回想一下jsp 和 servlet的关系:
事实上,jsp就是servlet未编译版本,任何jsp最终都被tomcat容器编译到work目录并以java类的形态执行。
你可以在 你的tomcat运行目录中看到端倪:
\work\Catalina\localhost\_\org\apache\jsp
你的webroot下的jsp页面的最终形态是:
index_jsp.class
当然tomcat还提供一个编译前版本:
index_jsp.java让我们看看他的内容:
package org.apache.jsp; 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 { private static java.util.Vector _jspx_dependants; public java.util.List getDependants() { return _jspx_dependants; } public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { JspFactory _jspxFactory = null; 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 { _jspxFactory = JspFactory.getDefaultFactory(); 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("<html>\n"); out.write("\t<head>\n"); out.write(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n"); out.write(" <title>multi-media searcher demo</title>\n"); out.write("\t\t<style type=\"text/css\">\n"); out.write("\t\t\tbody { background-color: #fff; padding: 0 20px; color:#000; font: 13px/18px Arial, sans-serif; }\n"); out.write("\t\t\ta { color: #360; }\n"); out.write("\t\t\th3 { padding-top: 20px; }\n"); out.write("\t\t\tol { margin:5px 0 15px 16px; padding:0; list-style-type:square; }\n"); out.write("\t\t</style> \n"); out.write("\t</head>\n"); out.write("\t\n"); out.write("\t<body>\n"); out.write("\t\t\n"); out.write("\t\t<h1>This is my first jsp page!</h1>\n"); out.write("\t\t\n"); out.write("\t</body>\n"); out.write("\t\n"); out.write("</html>"); } catch (Throwable t) { if (!(t instanceof SkipPageException)){ out = _jspx_out; if (out != null && out.getBufferSize() != 0) out.clearBuffer(); if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); } } finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context); } } }
如果我们也这么照葫芦画瓢的来一份不就OK了?
你可以参考一下我的博文:
从String中动态(内存中)编译和加载java类
我们采取这篇文章中提到的最简单的方式,生成一个java类,调用
import javax.tools.JavaCompiler; import javax.tools.ToolProvider;
工具进行编译,然后用
URLClassLoader
进行加载,并使用。
先看一个简单的例子,试验一下我们的想法是否可行:
创建一个接口:
package net.csdn.blog.deltatang; public interface Cat { public void say(); }动态定义实现类,并初始化,调用接口:
package net.csdn.blog.deltatang;输出为:
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler; import javax.tools.ToolProvider;
public class DynaCompTest {
public static void main(String[] args) throws Exception {
StringBuffer srcbuf = new StringBuffer();
srcbuf.append("package test;");
srcbuf.append("import net.csdn.blog.deltatang.Cat;");
srcbuf.append("");
srcbuf.append("public class CatImpl implements Cat {");
srcbuf.append("");
srcbuf.append(" static {");
srcbuf.append(" System.out.print(\"hello, \");");
srcbuf.append(" }");
srcbuf.append("");
srcbuf.append(" public CatImpl() {");
srcbuf.append(" System.out.println(\"world\");");
srcbuf.append(" }");
srcbuf.append("");
srcbuf.append(" public void say() {");
srcbuf.append(" System.out.println(\"I'm a cat!\");");
srcbuf.append(" }");
srcbuf.append("");
srcbuf.append("}");
String source = srcbuf.toString();
// Save source in .java file.
File root = new File("/java");
File sourceFile = new File(root, "test/CatImpl.java");
sourceFile.getParentFile().mkdirs();
new FileWriter(sourceFile).append(source).close();
// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader
.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("test.CatImpl", true, classLoader); // Should
// "hello".
Object instance = cls.newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test@hashcode".
Cat cat = (Cat)instance;
cat.say();
}
}
source code : ------------------------------- package test; import net.csdn.blog.deltatang.Cat; public class CatImpl implements Cat { static { System.out.print("hello, "); } public CatImpl() { System.out.println("world"); } public void say() { System.out.println("I'm a cat!"); } } --------------------------------------------- hello, world test.CatImpl@578fd6 I'm a cat!
试验成功!
让我们整理下代码:
package net.csdn.blog.deltatang.jsp4me;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler; import javax.tools.ToolProvider;
public class StringToObjectBuilder {
public String workdir = "/_web_workdir_tmp";
public StringToObjectBuilder(String workdir) {
super();
this.workdir = workdir;
}
public StringToObjectBuilder() {
super();
}
public Object build(String source, String classPath) {
String javaFilePath = classPath.replaceAll("\\.", "/") + ".java";
try {
File root = new File(workdir);
File sourceFile = new File(root, javaFilePath);
sourceFile.getParentFile().mkdirs();
new FileWriter(sourceFile).append(source).close();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
URL[] urls = new URL[]{root.toURI().toURL()};
URLClassLoader classLoader = URLClassLoader.newInstance(urls);
Class<?> cls = Class.forName(classPath, true, classLoader);
Object instance = cls.newInstance();
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
StringBuffer srcbuf = new StringBuffer();
srcbuf.append("package net.csdn.blog.deltatang.jsp4me;").append("\n");
srcbuf.append("import net.csdn.blog.deltatang.jsp4me.Cat;").append("\n");
srcbuf.append("").append("\n");
srcbuf.append("public class CatImpl implements Cat {").append("\n");
srcbuf.append(" public void say() {").append("\n");
srcbuf.append(" System.out.println(\"I'm a cat!\");").append("\n");
srcbuf.append(" }").append("\n");
srcbuf.append("}").append("\n");
String source = srcbuf.toString();
System.out.println("source code : -------------------------------");
System.out.println(source);
System.out.println("---------------------------------------------");
String classPath = "net.csdn.blog.deltatang.jsp4me.CatImpl";
StringToObjectBuilder builder = new StringToObjectBuilder();
Cat cat = (Cat)builder.build(source, classPath);
cat.say();
}
}
运行:
source code : ------------------------------- package net.csdn.blog.deltatang.jsp4me; import net.csdn.blog.deltatang.jsp4me.Cat; public class CatImpl implements Cat { public void say() { System.out.println("I'm a cat!"); } } --------------------------------------------- I'm a cat!
同时,可以看到,
我们在效果上实现了 tomcat 对jsp说干的事情:)
现在,让我们来进行第二步工作,定义我们的标记语言格式。
同样,我们参考jsp已经有的标记做一个子集,如下所示:
<%@ page import="java.util.*"%> <% List datalist = new ArrayList(); datalist.add("row1"); datalist.add("row2"); datalist.add("row3"); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP - NOT java SERVER pages but java SIGN pages</title> </head> <body> <h1>This is my JSP page. </h1> <h1>My JSP - NOT java SERVER pages but java SIGN pages</h1> <h2>out.println()</h2> <% for(int i = 0; i < datalist.size(); i++) { out.println(datalist.get(i) + "<br/>"); } %> <h2>special marker</h2> <% for(int i = 0; i < datalist.size(); i++) { %> <%= datalist.get(i) %><br/> <% } %> </body> </html>
我们将支持:
<%@ page import="java.util.*"%> <% 代码片段 %> <%= datalist.get(i) %> out.print("testline");
这样的约束条件足够我们说明问题,并可以很容易的进行扩展:)
让我们先创建 一个接口:
package net.csdn.blog.deltatang.jsp4me; import java.util.Map; public interface JspHandler { public String buildContent(Map<String, Object> context); }
然后编译jsp文件,动态的实现这个接口,
注意,假设我们在方法内定义了一个返回结果result,那么我们要将
<%@ page import="java.util.*"%>替换成java代码的: result += "import java.util.*;";
<%= datalist.get(i) %>替换成: result += datalist.get(i);
out.print("testline");替换成:result += "testline";
由此,我们获得了一下代码实现:
package net.csdn.blog.deltatang.jsp4me; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class JspToJavaLangBuilder { public String convert(String jspPath, String className) { StringBuilder source = new StringBuilder(); List<String> imports = new ArrayList<String>(); StringBuilder codes = new StringBuilder(); String content = getJspContent(jspPath); int clen = content.length(); int fromIndex = 0; int toIndex = -1; while(fromIndex < clen) { fromIndex = content.indexOf("<%", fromIndex); String code = ""; if(toIndex > 0) { toIndex += 2; if(fromIndex < 0) { code = content.substring(toIndex); } else { code = content.substring(toIndex, fromIndex); } } else { if(fromIndex < 0) { code = content; } else { code = content.substring(0, fromIndex); } } code = code.replaceAll("\\\"", "\\\\\""); String[] lines = code.split("\n"); for(String line : lines) { line = line.trim(); if(line.equals("")) { continue; } codes.append("source.append(\"").append(line).append("\");").append("\n"); } if(fromIndex < 0) break; fromIndex += 2; toIndex = content.indexOf("%>", fromIndex); String snippet = content.substring(fromIndex, toIndex); fromIndex = toIndex + 2; if(snippet.startsWith("@")) { imports.add(snippet); continue; } // snippet = snippet.replaceAll("\\\"", "\\\\\""); if(snippet.startsWith("=")) { code = snippet.substring(1); codes.append("source.append(").append(code).append(");").append("\n"); continue; } snippet = snippet.replaceAll("out.println", "source.append"); codes.append(snippet); } //class start source.append("package net.csdn.blog.deltatang.jsp4me;").append("\n"); //imports source.append("import net.csdn.blog.deltatang.jsp4me.JspHandler;").append("\n"); for(String s : imports) { int start = s.indexOf('"') + 1; int end = s.indexOf('"', start); String ipt = s.substring(start, end); source.append("import ").append(ipt).append(";"); } source.append("public class ").append(className).append(" implements JspHandler {").append("\n"); source.append(" public String buildContent(Map context) {").append("\n"); source.append(" StringBuilder source = new StringBuilder();").append("\n"); source.append(codes); source.append(" return source.toString();").append("\n"); source.append(" }").append("\n"); //class end source.append("}").append("\n"); return source.toString(); } private String getJspContent(String jspPath) { StringBuilder sb = new StringBuilder(); InputStream is = null; try { is = this.getClass().getResourceAsStream(jspPath); byte buf[] = new byte[1024]; int len = 0; while((len = is.read(buf)) > 0) { sb.append(new String(buf, 0, len)); } } catch (Exception e) { e.printStackTrace(); } finally { if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } public static void main(String[] args) { String jspPath = "./test.jsp"; String java = new JspToJavaLangBuilder().convert(jspPath, "Test"); System.out.println(java); } }
最后,让我们整合以上的代码,完成我们的工作:
package net.csdn.blog.deltatang.jsp4me; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class JspCompiler { public static JspHandler compile(String jspPath, String classPath) { String className = classPath.substring(classPath.lastIndexOf('.') + 1); String source = new JspToJavaLangBuilder().convert(jspPath, className); System.out.println(source); StringToObjectBuilder builder = new StringToObjectBuilder(); JspHandler handler = (JspHandler)builder.build(source, classPath); return handler; } public static void main(String[] args) { String jspPath = "./test.jsp"; String classPath = "net.csdn.blog.deltatang.jsp4me.TestJsp"; Map<String, Object> context = new HashMap<String, Object>(); List datalist = new ArrayList(); datalist.add("data----------1"); datalist.add("data----------2"); datalist.add("data----------3"); context.put("datalist", datalist); JspHandler handler = JspCompiler.compile(jspPath, classPath); System.out.println(handler.buildContent(context)); } }
run的结果为:
jsp模板内容为:
<%@ page import="java.util.*"%> <% List datalist = (List)context.get("datalist"); %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP - NOT java SERVER pages but java SIGN pages</title> </head> <body> <h1>This is my JSP page. </h1> <h1>My JSP - NOT java SERVER pages but java SIGN pages</h1> <h2>out.println()</h2> <% for(int i = 0; i < datalist.size(); i++) { out.println(datalist.get(i) + "<br/>"); } %> <h2>special marker</h2> <% for(int i = 0; i < datalist.size(); i++) { %> <%= datalist.get(i) %><br/> <% } %> </body> </html>
请注意模板中的context对象,显而易见,我用它取代了jsp中的上下文:page、session、request、application
同时,我们保留了servlet中的 Printer类型实例: out
动态生成的java文件:
package net.csdn.blog.deltatang.jsp4me; import net.csdn.blog.deltatang.jsp4me.JspHandler; import java.util.*;public class TestJsp implements JspHandler { public String buildContent(Map context) { StringBuilder source = new StringBuilder(); List datalist = (List)context.get("datalist"); datalist.add("row1"); datalist.add("row2"); datalist.add("row3"); source.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); source.append("<html>"); source.append("<head>"); source.append("<title>My JSP - NOT java SERVER pages but java SIGN pages</title>"); source.append("</head>"); source.append("<body>"); source.append("<h1>This is my JSP page. </h1>"); source.append("<h1>My JSP - NOT java SERVER pages but java SIGN pages</h1>"); source.append("<h2>out.println()</h2>"); for(int i = 0; i < datalist.size(); i++) { source.append(datalist.get(i) + "<br/>"); } source.append("<h2>special marker</h2>"); for(int i = 0; i < datalist.size(); i++) { source.append( datalist.get(i) ); source.append("<br/>"); } source.append("</body>"); source.append("</html>"); return source.toString(); } }
main方法输出结果:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP - NOT java SERVER pages but java SIGN pages</title> </head> <body> <h1>This is my JSP page. </h1> <h1>My JSP - NOT java SERVER pages but java SIGN pages</h1> <h2>out.println()</h2> data----------1<br/> data----------2<br/> data----------3<br/> <h2>special marker</h2> data----------1<br/> data----------2<br/> data----------3<br/> </body> </html>
结果符合预期,我们造出了一个新的 模板工具~~!
相关文章推荐
- 拿起笔来做刀枪 · 之五 再造一个lucene
- 拿起笔来做刀枪 · 之一 再造一个dom4j
- 拿起笔来做刀枪 · 之四 再造一个struts
- 拿起笔来做刀枪 · 之六 再造一个hibernate
- 拿起笔来做刀枪 · 之二 再造一个spring
- 拿起笔来做刀枪 · 序言
- 《编程导论(Java)·例程》tips.Print的一个bug
- 拿起笔来做刀枪 · 之七 最终幻想 Final Fantasy
- Jsp&Servelet 学习笔记-创建一个部署描述文件
- Jsp&Servelet 学习笔记-编译一个servlet
- Jsp&Servelet 学习笔记- 在tomcat上部署一个单独的servlet的程序(Ant)
- Jsp&Servelet 学习笔记-写出一个 servelet 程序
- 介绍一个GWT的网站 和 decode javascript.encode using java +FCKEditor 在 jsp中的使用说明
- Jsp&Servelet 学习笔记- 为Servlet创建一个JSP类型的URL
- 使用Java将Word转为Html或txt等···
- 使用JSP + JAVABEAN + XML 开发的一个例子
- 用JSP+Servlet+JavaBean模式实现一个简单的登录网页设计(JSP+Tomcat+MySQL)
- 使用JSP + JAVABEAN + XML 开发的一个例子
- 使用JSP + JAVABEAN + XML 开发的一个例子 (转自arielxp !Java)
- ·Java Open Single Sign-On Project-介绍