拿起笔来做刀枪 · 之三 再造一个jsp(java sign pages)
来源:互联网 发布:淘宝神舟旗舰店 编辑:程序博客网 时间:2024/06/04 17:47
JSP的全称叫做: java server pages。
我们这里也打造一个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// print// "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, worldtest.CatImpl@578fd6I'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 startsource.append("package net.csdn.blog.deltatang.jsp4me;").append("\n");//importssource.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 endsource.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>
结果符合预期,我们造出了一个新的 模板工具~~!
0 0
- 拿起笔来做刀枪 · 之三 再造一个jsp(java sign pages)
- 拿起笔来做刀枪 · 之一 再造一个dom4j
- 拿起笔来做刀枪 · 之二 再造一个spring
- 拿起笔来做刀枪 · 之四 再造一个struts
- 拿起笔来做刀枪 · 之五 再造一个lucene
- 拿起笔来做刀枪 · 之六 再造一个hibernate
- 拿起笔来做刀枪 · 序言
- 拿起笔来做刀枪 · 之七 最终幻想 Final Fantasy
- 再一次拿起笔
- JSP(Java Server Pages)
- java之jsp(java servlet pages)
- JSP(Java Server Pages)内置对象
- JSP简介(java server pages)
- JSP(Java Server Pages)
- JSP--Java Server Pages
- JSP--Java server Pages
- JSP--初识Java Server Pages
- JSP-- Java Server Pages 笔记
- 你还在拼命考证吗?OUT了!从学历到学力的华丽转身
- HDU 1020 Encoding
- tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植u-boot-spl.bin(点亮led灯)
- 驱动开发之 文件系统识别器
- Pow(x, n)
- 拿起笔来做刀枪 · 之三 再造一个jsp(java sign pages)
- 大数据实践应用分享
- hdu 2007 平方和与立方和
- C风格字符串和C++string类对比 使用实例
- 如何转换成Ogg和MPEG4格式
- tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植u-boot.bin(修改显示信息)
- IOS NSDictionary扩展映射model(字典--》model;字典==》string)
- 拿起笔来做刀枪 · 之四 再造一个struts
- 拿起笔来做刀枪 · 之五 再造一个lucene