学习 JSP 快速展示数据

简单的开场白:把我开发 Java Web 框架过程中想说的话,给说出来。先介绍下作者的背景,本人最先比较熟悉 JS,先是接触过 ASP(VBS)、ASP(用 JScript 编写,花时间不少)、ASP.net(不算太深入)、Java。最后确定了 Java 作为目标开发平台。小弟 2004 年学 MS Classic ASP 最老的那种 ASP,非 Net。到现在开始,正式使用 JSP。虽然小弟之前很早就接触 Java 了,大概知道一点点,却又不尽然。因此还是要边学边用。又因自学的,或者工作过程中自己摸索的,所以应该有非常多“小白”的地方,因此唐突不对的地方,请大家一一指正。是以为笔记吧。

缘由……

演进史

我的 Web 开发知识始发于微软 ASP,自然比较熟悉,所以遇到其他 Web 开发平台,难免不作为比较。ASP 更多的考虑是页面怎么样输出 HTML,一个 *.asp 页面固定为一个 URL,也对应着一个请求。同时期的 JSP/PHP 也是相仿的道理,当然 JSP 可以编写自己的  Servlet 显得更强大一些。于是后来的 .net 提出的 WebForm、Code Behind 也是力求页面与逻辑分离,这种概念当时大行其道,无不充分实践 Web 三层架构的旗号。其中值得一提的是 Classic ASP 也就是我刚才说我入门的 ASP,属于比较古老的语言,但架构上可以支持 COM/COM+ 组件开发——为此我还特意地买了一本很厚的 O'Reilly 出版的书《ASP 组件开发》,专门介绍不同的语言开发 ASP dll 组件。实话说,这种架构很不错,对开发者也挺友好(囊括 C++/Java/Python/Perl/WSH/JavaScript 等语言,只要有解析器的就可以),但随着 .Net 大势,COM/COM+ 技术也逐渐没落……

表示层、业务层、数据层,不论不同语言和平台有着它们不同的名词,但大体上 Web 架构的划分就是从这三个大块开始的,意思差不多。

ASP/PHP/JSP 这类的共同点都是有个 Pages,都内置了 Web 开发所必须的几大对象,例如 ASP 的 Request、Response、Session、Server、Application,JSP 对应的都有!从 ASP 到 JSP,后者只是把 Visual Basic Script 换成了 Java,然后这几大对象的 API 有所不同而已,都有 Request、Response 等等,但页面生成方式还是也页面为优先切入点,不约而同的使用 <%=%> 输出动态内容。当然了,HTML还是 HTML,CSS 还是 CSS,这些知识无论 ASP/PHP/JSP 都是一致的,应该说是毫无“违和感”的。总之,早期类型的开发模型做起页面来都是很快手,适合于前端优先的学习路径,——以至对影响我很深,使得我一直不肯放弃 <%=XXX%> 大法,甚至还一度排斥 Servlet:认为“直接输出 HTML 很爽,容易看到效果”、“Java 又不用编译、写 Servlet 麻烦”,那时候,我写 Java 不是写一个个 Class,而是一个个 JSP 然后 include……这种“避重就轻”的状况坚持了很久,直到今天,我所设计的程序结构,虽然已大幅度改善,更多地利用 Java 语言传统优势和 Java Web 框架的固有优点,但必须承认,中间“说服自己”的过程(弯路)走了很久……

对于复杂的逻辑还是需要更高层次的划分,那便是 MVC 了。MVC 足够经典,所以很有必要回顾以一下 Servlet。早期 Servlet 模型很朴素,1、Web.xml 指定 url;2、继承 HttpServlet,重写 doGet/doPost 方法;3、数据库 SQL 操作,例如读取一条记录(此为业务逻辑范畴);4、得到数据,塞入 request.setAttribute("name", rs.getString("name")) 然后分发到 JSP 到:req.getRequestDispatcher("hello.jsp").forward(req, resp);;5、JSP 模板中使用 EL 表达式或者标签渲染最终 HTML 出来。简单说,乃是 Servlet+Java Bean + JSP。随后 Struts/FreeMaker/Spring MVC 均为 MVC 模式的实作。

随着 Servlet 的发展,到 3.0 的 Servlet 已经支持注解等诸多方便功能了,无须其他第三方库都可以完成一般的工作了。

推荐教程:《Servlet/JSP 學習筆記》http://openhome.cc/Gossip/ServletJSP/

初期目标

我觉得,框架开发乃“摸着石头过河”,边写边修正目标,因此谈不上“超越 XX 框架”,或者更遑论“推广,介绍别人使用”!质言之,是为了记录下一些自问有价值的内容,是为笔记。根据自己的一点经验,初期的目标应该如下。

  • 轻量级,或曰“羽量级”。什么事轻量级呢?我认为,首先不要太多概念,众所周知,Java 是“名词帝国”,因此我们就是要避免走进为概念而概念的误区,其次尽可能不依赖太多第三方库,最后对于功能而言,先实现功能,再完善!
  • 逻辑尽可能自然,解决思路要彻底而且不失灵活,不要太 Hack。
  • 代码可读性要高,不要晦涩的代码。
  • 混合型编程,主张多语言参与开发。

很多事物应该是做出来了,才算有某个特性吧。这些特性如果不太偏离当初的目标,就可以具体化了。现在这个目标是比较模糊的,——等框架差不多的时候,再罗列一次各项特点。

基本选型如下。

前端:HTML5/CSS/JavaScript/LESS/Sea.js/Step.js/Bigfoot.js

后端:Java/JSP/Tag Files/Rhino

数据库:SQLite/MySql

项目构建:Eclipse/Node.js/Grunt

测试框架:JUnit/Mockito

上面我谈到了“混合型编程”,那么,什么是混合型编程呢?下面讲讲我的看法,当然其中也借鉴了别人的观点,包括图片资源也是。

混合型编程

现在有种混合型编程的观点,正好符合我使用 Rhino 的想法。具体说,就是大家针对 Java 静态类型不太灵活,编译比较麻烦,部署需要重启服务器,而且 Java 语法相对冗长,不够简洁等观点,提出在 JVM 上多语言开发的这么一种编程方式。他们认为,对于金字塔顶端的语言,应该是侧重的是灵活性和快速部署能力,而一方面,比较务实的做法是利用 Java 丰富的 API 和类库完成底层繁重的工作。

学习 JSP 快速展示数据_第1张图片

学习 JSP 快速展示数据_第2张图片

JVM 上有不少备用语言可供选择,如 JRuby、Groovy、Scala 和 Rhino 等,它们使用范围非常广泛,都是有相对生命力和影响力的语言,之所以选择 Rhino,基于下面的原因。

  • JavaScript 用起来比较顺手,简单
  • Rhino 从 Java 6 开始自带,无须额外依赖
  • Rhino 跟 Java 的交互操作十分容易,基本上它们之间是互通有无的。

实际上,我使用 ASP 开发之时,更多的是使用 JavaScript 的变种 JScript,生成 JSON 数据非常简单。JS 是动态语言,我认为在字符串处理(正则表达式)、反射、天然的 JSON 支持和函数式编程这几个方面有优势,就是十分便捷,Java 几十行的代码,JS 十几行或者更短就搞掂了。于是,我在这个 Java Web 框架中大量利用自带 JS 引擎 Rhino 来完成编码的工作。实际上,JavaScript 不负其名,果然是 Java 之脚本,既是 Java 的子集,也不与 Java 正面冲突,正好弥补 Java 静态语言的不足,定位十分鲜明准确。引申地想想,这不就像是 C 之于 C++,盖因很多人把 C 作为一种“脚本”了。 

然而在实际尝试中,却走了一段弯路……

这个框架第一版的时候,我用力过猛,造成有点过犹不及,js 大面积地使用,在 JVM 上完全构建了一门 JavaScript 的动态层,丧失了 Java 作为静态、编译型语言所固有的优点,例如完整成熟的 OO、类型安全、集成便捷的 IDE 和工具。乃至于到项目后期的时候,面对一大堆难以维护的动态语言,写再多的注释感觉也是苍白(与写前端组件感觉类似)。接着磕磕碰碰到第二版时候,我决定重构,并花不少时间想,什么时候用 Java,什么时候用 JS。结论是,那应该根据 Java 和 JS 语言特性来决定的——贸然舍弃 Java 是不明智的,而且 Java 那么的优美,怎么能一刀切呢?我真是有眼不识泰山啊。及后,我把以前许多用 JS 写的逻辑移到 Java。JS 的位置,我想应该是“短平快”,具体就是提供某个特定函数,特别是字符串处理(Web 开发很多场景是处理 String)和反射的场景。注意 JS 代码不要过渡设计,不要太大颗粒度,不要太多继承,简简单单一个个函数传参数就好了。

我当前使用 JS 的地方:

  • 服务端 JSON 读取解析,使用 Rhino,没有依赖第三方 JSON JAR 包
  • 配置系统,用 JSON 保存配置信息
  • 接口 url 分发器,使用正则分发
  • ORM 的方案基于 SQL 字符串拼凑,里面全部的逻辑使用 JS 编写。

程序概貌

请求接口

请求 Request/ 响应 Response 可以说是 Web 模型的两个基本概念,几乎每个 Web 框架都有这两个对象。

总结几种请求方式:

  • 经典 Servlet,上文已述
  • JSP,Form 表单 action 填 “.” 请求到本页面,但是执行 Bean 类,要求传入 requqest/response,并 return 返回不渲染剩下 JSP
  • 通过 JS Engine 控制器分发


配置系统的设计

数据库与业务设计

POJO

放弃笨重的 POJO 改为数据库表设计+Map 输出

ORM 实践

SQL 语句编译器

异常体系设计

Java 异常

异常是 Java 语言的大一特点,Java 拥有比较完善的异常机制。使用 try...catch 语句可以捕获任意类型的异常。如果catch()参数中 e 为所有异常的父类 Exception 或者接口 throwable,那么就可以在 catch 子语句中获取特定的异常。这样的做法缺点是不具体区分特定的异常,相当于强类型转换,会损失特定的方法或成员。

所以,我们建议,在一期生命周期中,由最后的 try……catch(Eexception e)捕获所有的异常,并输出。

Java 不像 JS,可以直接执行 throw 语句抛出异常,要么在 try...catch 中包裹着,要么在方法声明中 throws 对应的异常,否则 Java 会认为你没有异常(程序员偷懒了)。JS 中,同样有 try..catch 语句,不同的是,throw 可以在任意位置,只不过由 try...catch 堆栈中的最接近的那个接受这个异常。

相对来说,js 比较自由,Java 的强制性会大一些,而且提供了两种处理异常的基本机制:要么在 try...catch 中包裹着,要么在方法声明中 throws 对应的异常。我是这样理解的,如果编写一个方法,行数很多,try……catch 很多,那么一种简便的方法就是 throws 所有的异常,这样代码会显得清爽很多。throws 的作用,就是当前我已经预计了有这么一些异常,但先不处理,留给调用这个方法者来处理异常,也就是用 try...catch处理(这一步是必须的)。

Java 可以自定义异常类型,这个比 js 强大多。尽管 js 也不是不可以自定义异常类型,但是 catch 语句不能自动辨别类型。所以某些大型的 Java 系统,便有自己的异常框架和许许多多的自定义异常类型。但是在我这个框架中,则没那么多的异常类型。主要围绕以下几个点来设计。

  • 一般程序程序错误,例如除数不能为零,不能读取某个磁盘文件等等
  • 缺少某个参数,包括表单验证不通过
  • 业务错误,例如用户登录密码错误,也视为异常抛出

我有一点疑惑:使用 e.printStack() 方法,不知道为什么,只能在当前上下文的 catch 语句中使用,才有出错堆栈打印出来。把 e.printStack() 放置其他地方貌似不能打印。

关于异常我还补充了《恶补 Java 系列之异常》。

Java Web 异常设计

一般 java web 会把出错信息放到 request 对象中,如 request.setAttribute('err', 上传图片不正确')

了解 Tomcat

Tomcat 是 HTTP Server,也是 Web 容器。Tomcat 由以下的组件所构成:

  • Catalina (servlet container,所谓 Servlet,应该就是今天Web 框架里面的 Route、分发之类的问题),
  • Coyote (an HTTP connector 处理 HTTP 头和响应头的底层包)
  • Jasper (a JSP engine,说穿了就是一个模版系统)

开发者从对 Java 的热爱延伸到对 JSP 的热爱,同时 JSP 也是 J2EE 体系中最重要,而且又是最基础的一个组成部分,如果要体验 J2EE 带了的开发效率和优势,JSP 会是非常有效的入门方式。学习、使用 JSP 的好处如下:

  • JSP 程序容易上手,如果有 HTML 和 Java 的基本知识,或者接触过 ASP/PHP 的话,那么学习 JSP 程序就没有任何难度。
  • JSP 就是在 HTML 中嵌入 Java 代码,所以在本质上 JSP 程序就是 Java 程序,JSP 程序继承了Java 的一切优点(注,除了内部类稍有不同)。JSP 程序有严格的 Java 类库支持。JSP 页面在服务器中都会被 JSP 编译器编码称对应的 Servlet。
  • JSP 中可以使用 Java Bean 进行逻辑封装,这样就可以实现逻辑功能代码的重用,即经典的 Bean + Servlet + JSP,从而大大提高系统的可重用性,同时也提高了程序的开发效率。
  • 新版 Eclipse 4.2 完全做到对 JSP 开发给力的支持,包括错误校验、智能提示、调试等强大的辅助功能,甚至 include 文件的上下文都可支持。
  • 最重要的一点,JSP 不需要重启服务器!

请看官参阅以下网友资源:

java框架太多,感觉太复杂。web应用直接用Jsp+Servlet+JavaBean不是更简单?而且更灵活 实际上依然有公司在用纯Jsp 的script的形式写项目。
我觉得应用框架最大的作用就是尽量让项目变得灵活,同时让程序员不要那么灵活。因为项目灵活才能适应客户的需求变更,程序员加上框架的限制能够降低人员流动的成本。框架就像马鞍,给马套上框架不是为了让马更舒服,而是为了骑马的人更舒服。

bbs.csdn.net/topics/360099689

另外,坦率的说,此框架可能更适合有“经验”的开发人员,更适合开发需要复杂视觉表现力的产品级项目。对于真正实战用过Struts,JSF,Tapestry,Turbine,Webwork等框架的朋友,相信会找到一种久违的“自由”感觉。

敏捷开发,一个很老很年轻的话题,不得不谈而且必须谈的话题,无论你用ASP、PHP、JSP还是ROR,它随时都触动我们开发的神经,让我们在懵懵焦虑中度过一个个不眠之夜。困了,烦了,唉......与其在烦恼中困惑,不如在烦恼中爆发,让我们展开JSP敏捷开发的畅想吧!
……

泛组件化是敏捷开发的最大陷阱!我们的WEB必须要有视觉表现力,WEB2.0要求更甚,但这种表现力需要精烹细调,个中过程远非简单的HTML、CSS之类,开发人员随时可能更改程序部分,不仅仅美工的问题,如果更改部分是“组件”,那你的麻烦大了
……
WEB特色来自handy,而非component!为何ASP、PHP以及新近出现的ROR,无一例外都把JSP打的满地找牙?随便找三点原因:
1. 解释性语言简单明了,学习、开发、维护成本都很低廉,让JAVA学究式语言的规范整洁无用武之地。
2. WEB开发无需大量企业级应用组件,一般提供mysql编程接口即可,这让JAVA的海量组件形同虚设。
3. 语言本身决定了单纯动态页面的编码难度。排除语言本身的优势,VBS,PHP,RUBY相对都很简单,说白了,能完成简单逻辑和mysql编程即可。
再来看看RoR为何近年来很火!?它是OO类语言,这是潮流,看看这两年C#和PHP5都在OO方面大力跟进就知道了,但为何只有RoR有排山倒海之势呢?!甚至出现了Grails跟风。另外,后者会上演GoG大戏吗?因为它有Java这个OO鼻主当靠山啊。No,回答是否定的,原因何在呢?回答这个问题前,得先回答另外一个问题:如果没有Rails,Ruby还翱翔的翅膀吗?除了语言本身的简洁,Rails最大的特点就是:习惯约定优于配置。所以,与其说Ruby,还不如说是Rails给WEB开发带来了暂新的模式。正是这个满足八二原则的开发模式极大激发了WEB开发人员的热情。尤其是Java开发人员,他们身负“组件化”重任,饱受各种配置规范的折磨,这种handy风格让他们看到了解脱的希望。假如将这种handy风格应用到Jsp,又会出现怎样的情形?问题是Jsp是烂泥吗?能扶上墙吗?答案是:能!针锋相对的理由:
1. 语言规范整洁,符合企业严整风范
2. 超大规模的企业级应用组件,便于web应用未来扩大之后的进一步发展
3. 单纯JSP页面只包含显示逻辑,在IDEA、Ellipse插件支持下也能展开敏捷开发

http://www.jdon.com/33785

你可以说可爱的php ,可爱的ror ,可爱的python ,甚至可爱的.net ,但是javaee ?他太复杂了。相比前三种技术,javaee 的技术体系更全面、更规整也更复杂,他的复杂性也让很多厂商望而止步,宁可选择简单甚至简陋的php ,这充分说明快速开发是这个时代最迫切的需求。

javaee 的servlet 、javabean 、jdbc 规范给了我们组件和容器的唯一标准,而更高级的支持,jsf 、jdo 规范却没能给予我们唯一的框架级标准,他们被认可的程度远低于相同领域的开源框架。尽管开源社区给了我们最丰富的选择,但是相比.net 、php 、ror 的全栈式服务,javaee 开发者必须DIY 。DIY 不但需要时间而且需要冒险,这种发烧友做的事情是企业所不愿意做的。一段时间以来,公司javaee 方向的招聘几乎清一色的要求struts 、spring 、hibernate 这几种主流框架的能力就是一种证明。
……
“任何优秀的语言,都可以帮助开发者写出优秀的代码,但不能阻止开发者写出糟糕的代码”。在这一点上,无论是javaee ,.net ,ror ,php 都不会例外。而开发框架就像是“一间有很多屋梁的房子”,“框架的强大之处不是他能让你做什么,而是他不能让你做什么”,其实如同语言一样,框架虽然可以给予开发一定程度的规范指导,但是这种指导仍然是有限的,这真应了那句老话:事在人为。

http://javaonejcy.iteye.com/blog/505128

《使用spring-loaded 提高java 应用开发效率 》:

在 web 应用开发领域,java 平台相比较其它脚本语言有明显的性能优势。但在 java 平台开发 web 应用有一个缺点就是频繁系统重启带来的开发效率下降。php 之类的脚本语言开发 web 应用时都可以做到“click,refresh”的开发流程,代码修改后刷新立即就可以看到结果。java web 应用往往需要编译-重启-刷新,在这个过程中,重启是最耗时的环节,如果项目比较大或者使用了一些重量级的应用服务器,重启耗时更为明显。

虽然 jvm 提供了一定程度的代码替换功能,但有很大局限,仅能修改方法实现代码。某些应用服务器(例如 jetty)也提供了类的热加载功能,但经常会出现 PermGen OOM 错误,这些解决方案都不太理想。

总之,一个工具如果使用的好,取其长而去其短,自然可以飞花摘叶皆可伤人。

另请参阅 :

《极简风格Web架构,jsp+jdbc的二次复辟》http://www.blogjava.net/calvin/archive/2008/07/31/218903.html

https://github.com/spring-projects/spring-loaded

http://jinnianshilongnian.iteye.com/blog/1887788

一个例子,保存数据库:

先设置头内容:

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@page import="java.sql.*" %>
再写 JAVA 代码,既有 class 部分,也有直接写 Java 的:

class Connect {
	public Connection getConn(String driver, String jdbcUrl, java.util.Properties props){
		Connection conn = null;
		
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			System.out.println("创建数据库连接失败,请检查是否安装对应的 Driver"); 
			e.printStackTrace();
		}
		
		try {
			if(props == null){
				conn = DriverManager.getConnection(jdbcUrl);
			}else{
				conn = DriverManager.getConnection(jdbcUrl, props);
			}
			System.out.println("数据库连接成功:" + conn);
		} catch (SQLException e) {
			System.out.println("数据库连接失败!"); 
			e.printStackTrace();
		}
		return conn;
	}
	
	//demo
	public Connection getConnSqlite(){
		return getConn("org.sqlite.JDBC", "jdbc:sqlite:D:\\yuetv2014.sqlite", null);
	}
}

Connection conn = new Connect().getConnSqlite();
System.out.println(conn.getMetaData().getURL());
Statement statement = conn.createStatement();
String name 	= new String(request.getParameter("name").getBytes("iso-8859-1"), "UTF-8");
String contact	= new String(request.getParameter("contact").getBytes("iso-8859-1"), "UTF-8");
String msg		= new String(request.getParameter("msg").getBytes("iso-8859-1"), "UTF-8");

name = "('" + name + "',";
contact = "'" + contact + "',";
msg = "'" + msg + "')";

String sql = "INSERT INTO freeback (name, contact, msg) VALUES " + name + contact + msg;

System.out.println(sql);

try{
	statement.execute(sql);
	out.write("<script>alert('提交成功!');history.go(-1);</script>");
}catch(Exception e){
	e.printStackTrace();
	out.write("<script>alert('提交失败!');history.go(-1);</script>");
}finally{
	statement.close();
	conn.close();
}

内置对象

JSP 页面内置对象,这都是自带的、默认的,每张 JSP页面都会提供的。和 ASP 类似,它们是:

  ASP JSP
返回服务端的一些信息 Server

实际类型:

org.apache.catalina.core.StandardWrapperFacadeStandardWrapperFacade

实现接口javax.servlet.ServletConfig

page
实际类型:org.apache.jsp.index_jspindex_jsp
继承类org.apache.jasper.runtime.HttpJspBaseHttpJspBase
继承类javax.servlet.http.HttpServlet


程序作用域下的全局对象 Application

实际类型:
org.apache.catalina.core.ApplicationContextFacadeApplicationContextFacade

实现接口javax.servlet.ServletContext

客户端的请求 Request 实际类型:

org.apache.catalina.connector.RequestFacadeRequestFacade

实现接口javax.servlet.http.HttpServletRequest

e.g:String username=request.getParameter("username");

if(username.equals(""))...

响应客户端 Response 实际类型:
org.apache.catalina.connector.ResponseFacadeResponseFacade

实现接口javax.servlet.http.HttpServletRequest

response.sendRedirect(...);

会话 Seesion 实际类型:
org.apache.catalina.session.StandardSessionFacadeStandardSessionFacade
实现接口javax.servlet.http.HttpSession
页面上下文 ObjectContext pageContext
实际类型:
org.apache.jasper.runtime.PageContextImplPageContextImpl
继承类javax.servlet.jsp.PageContext
异常 exception

这方面应该多差文档,例如官方的就不错。待项目深入逐渐学习各个 API 之用法。

插入 HTML 片断 / 标签复用

最简单的一种 <%@ include file="public/class.jsp" %>,ASP 和 JSP 写法一样。

不过和 ASP 不一样,不能在方法中混搭 HTML,如下面的是不行的哦:

<% public static voidgetFooter(){
%>
 <div>...</div>
<%
}
%>
于是,得使用 JSP 标签。最妙的是可以使用 <%=var%> 读取上下文变量。

<jsp:include page="bar.jsp" >
    <jsp:param name="extraparam" value="TestTest" />
    <jsp:param name="extraparam2" value="<%=a%>" />
</jsp:include>

被 include 页面,用 $ 读取参数:

888-----------${param.extraparam}------${param.extraparam2}-------888

虽然 JSP 页面不如 ASP 那般灵活,但好在每个 include 页面都是独立的上下文,此时可以通过 request、session、application 等作用域共享的对象作为中介媒体,传递对象。它们本质上 map,因此可以通过 setArrtibute() 方法设置任意类型的对象。如下所示:

<% 
  String name="zhouhaigang";
  request.setAttribute("name", name);
%>

${ name }

更复杂一些数据类型……

// jsp页面开头要导入你的User类。 
List<User> userList = (List<User>)request.getAttribute("你传来的List");
int len = userList.size();
for(...){
  ...
}

导入 JAR / Classes

  • 使用已编译的 Class:按照命名空间放置 *.class 文件在 WEB-INF/Classes 目录下。然后 JSP 中使用 import iori.db 调用
  • 使用 JAR 包(JAR包就是包含很多 Class 的集合):一般情况下,放到WEB-INF/lib下就可以了,这也是推荐的做法;实在不行就放到/Tomcat /common/lib下,不过会启动服务器就自动加载的,但是太多了影响启动速度。最后就是在 JSP 中引入 <%@ page import="Com.bbpoint.Connect.*" %><jsp:useBean id="asd" scope="page" class="connect.Connect" />。这样前提 JAR 包中有相对应的类。JAR 是 ZIP 压缩包,用 7zip 之类的工具可以浏览。未知  JAR 包,要了解其 API 的话,最好用 Eclipse 或者反编译的手段。

下面包为什么不需要通过 Class/ JAR,引入就可以在 JSP 页面中直接使用?

<%@page   import="java.sql.Connection"%>
<%@page   import="java.sql.DriverManager"%>
<%@page   import="java.sql.Statement"%>
<%@page   import="java.sql.ResultSet"%> 

答案:因为 tomcat 已经通过系统环境变量 Classpath 获取到你的 JDK/JRE 的包,所以直接 import 就可以了。

如何编译一个 Class 呢?好处是别人不会轻易地看到你的代码!

详见该文《Tomcat+JSP经典配置实例 》,写得不错哦。

JSP 中如何定义一个方法或类

要定义方法,必须在 <% 后加个感叹号 !

<%!   //此处有感叹号  

private   void   aMethod(){ 
...;   
}  
// 也可以是属性
private   String   aVariableOfClassScope; 
……
%>

这样的做法相当于在 Servlet 中重新定义了一个方法;如果没感叹号,就是普通的那种情况,那表示在 Servlet.doService() 方法写逻辑,你在生成的 java 类中看到混搭 HTML / Java 的代码。

<%   
   //此处无感叹号,代码将会在 doService() 方法中
   ...; 
%> 

奇怪的是类也可以写在 doService() 方法中????

捕获异常

设置可以捕获代码中显式抛出的异常:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" errorPage="error.jsp"%>
接收异常的页面
<%@page isErrorPage="true"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>JSP Page</title>
</head>
<body>
	Error~!
	<%=exception.getMessage()%></body>
</html>

对于未知的、非捕获的异常也就是 500 出错,应该用 tomcat 的 500 err 代码跳转,但却又不利于调试,怎么两者都兼顾呢?

调试手段:

System.out.println("676"+uid_Str);

mylist.getClass().getName();

out.write(str);


设置 Tomcat 兼容中文 url:

在 Server.xml 中加入的 Connector 节点中加入  URIEncoding="UTF-8" 属性:

<Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" URIEncoding="UTF-8" />


去除JSP页面自动生成的空行 加入 <%@ page trimDirectiveWhitespaces="true" %>

----------------------------

输出 JAVA 变量,代替 <%=%>,这样就不会因为JSP inchuld 找不到上下文而让 Eclipse 报错了。

<jsp:expression>Global_WebRoot</jsp:expression>

---------------------------

JSP Mapping

    <servlet>
        <servlet-name>live_detail</servlet-name>
        <jsp-file>/live/detail.jsp</jsp-file>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>live_detail</servlet-name>
        <url-pattern>/live/detail</url-pattern>
    </servlet-mapping>

JSP 的路径 按照 URL 的虚拟路径为准,包括   <%@ include file="../../public/head.jsp" %> 都如是。

参阅

《为什么JSP的内置对象不需要声明》

《用TOMCAT作简单的jsp web开发》

《JSP 原理和 Tomcat 配置》

《Tomcat+JSP经典配置实例》 编写自己的 Class

Unknow

利用 JSP 2 提供的 SimpleTagSupport 开发自定义标签

为 JSP 文件。

头引用是:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ page import="java.net.*, java.util.*, java.io.*"%>

JSP 内容:

// 跨域用代理
request.setCharacterEncoding("UTF-8");
String url = null;
StringBuffer params = new StringBuffer();
Enumeration enu = request.getParameterNames();
int total = 0;
while (enu.hasMoreElements()) {
	String paramName = (String)enu.nextElement();
	if(paramName.equals("url")){
	  url = request.getParameter(paramName);
	}else{
	  if(total == 0){
	  	params.append(paramName).append("=").append(URLEncoder.encode(request.getParameter(paramName), "UTF-8"));
	  } else {
	  	params.append("&").append(paramName).append("=").append(URLEncoder.encode(request.getParameter(paramName), "UTF-8"));
	  }

	  System.out.println("paramName:" + paramName + "/" + request.getParameter(paramName)); 
	  ++total;
	}
}
String param = params.toString();


// out.println(url);
if(url != null){
	// 使用GET方式向目的服务器发送请求
	URL connect = new URL(url);
	HttpURLConnection connection = (HttpURLConnection)connect.openConnection();
	connection.setConnectTimeout(3000);  
	connection.setReadTimeout(3000);  
	connection.setDoOutput(true);
	connection.setDoInput(true);
	connection.setUseCaches(false);  
	connection.setRequestMethod("POST");
	connection.setRequestProperty("Content-type","application/x-www-form-urlencoded;charset=utf-8");
	
	connection.connect();

	System.out.println("url:" + url); 
	System.out.println("para:" + param); 
 
 	OutputStream os = connection.getOutputStream();  
    os.write(param.getBytes()); 
	os.flush();
	os.close();

    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));

	String line;
	while((line = reader.readLine()) != null){
	  out.println(line);
	}
	reader.close();
}

附详尽注释的 jsp,可支持 GET/POST:

<%@ page import="java.util.Enumeration"%>
<%!
// java.io.*,java.net.*
// 使用GET方式向目的服务器发送请求
public static String HTTPRequest(String url) throws IOException{
    String result = "", line;
	// 拼凑get请求的URL字串,使用URLEncoder.encode对特殊和不可见字符进行编码
	// String getURL = GET_URL + "&activatecode=" + URLEncoder.encode(url);
    URL getUrl = new URL(url);
    // 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection
    HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection();
    // 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到服务器
    connection.connect();
    // 取得输入流,并使用Reader读取,并设置编码,否则中文乱码
    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));

    while ((line = reader.readLine()) != null){
    	result += line;
    	// lines = new String(line.getBytes(), "utf-8");
        // System.out.println(line);
    }

    // System.out.println(result);

    reader.close();
    connection.disconnect();// 断开连接

    return result;		
}

// 使用 POST 方式向目的服务器发送请求
public static String HTTPPost(String url, String params) throws IOException{
	String result = "", line;
	
	URL connect = new URL(url);
	HttpURLConnection connection = (HttpURLConnection)connect.openConnection();
	connection.setConnectTimeout(3000);  
	connection.setReadTimeout(3000);  
	connection.setDoOutput(true);
	connection.setDoInput(true);
	connection.setUseCaches(false);  
	connection.setRequestMethod("POST");
	connection.setRequestProperty("Content-type","application/x-www-form-urlencoded;charset=utf-8");
	
	connection.connect();

	System.out.println("url:" + url); 
	System.out.println("para:" + params); 
 
 	OutputStream os = connection.getOutputStream();  
    os.write(params.getBytes()); 
	os.flush();
	os.close();

    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));

	while((line = reader.readLine()) != null){
		result += line;
		// out.println(line);
	}
	reader.close();

	return result;
}

public static String[] getPOST_Data() throws UnsupportedEncodingException{
	String url = null, param;
	StringBuffer params = new StringBuffer();
	Enumeration enu = req.getParameterNames();
	int total = 0;

	while (enu.hasMoreElements()) {
		String paramName = (String)enu.nextElement();
		if(paramName.equals("url")){
			url = req.getParameter(paramName);
		}else{
			String pair = URLEncoder.encode(req.getParameter(paramName), "UTF-8");
			//String pair = req.getParameter(paramName);
			
			if(total == 0)params.append(paramName).append("=").append(pair);
			else params.append("&").append(paramName).append("=").append(pair);
			
			System.out.println("paramName:" + paramName + "/" + req.getParameter(paramName)); 
			++total;
		}
	}
	param = params.toString();

	String [] arr = {url, param};
	return arr;
}
%>


http://www.jiucool.com/java-sending-http-requests-get-and-post-method-request/

Java 发送 http 请求 (get 与 post 方法请求),以下代码经本人亲自调试可用!可以直接使用之。注意:通过 BufferedReader 读取远程返回的数据时,必须设置读取编码,否则中文会乱码!

package com.jiucool.www.struts.action;
 
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
 
public class post_request {
	public static final String GET_URL = "http://www.jiucool.com/request.php?key=j0r56u2";
 
    public static final String POST_URL = "http://www.jiucool.com/request.php";
    public static void readContentFromGet() throws IOException{
        // 拼凑get请求的URL字串,使用URLEncoder.encode对特殊和不可见字符进行编码
        String getURL = GET_URL + "&activatecode=" + URLEncoder.encode("久酷博客", "utf-8");
        URL getUrl = new URL(getURL);
        // 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,
        // 返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection
        HttpURLConnection connection = (HttpURLConnection) getUrl
                .openConnection();
        // 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到
        // 服务器
        connection.connect();
        // 取得输入流,并使用Reader读取
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));//设置编码,否则中文乱码
        System.out.println("=============================");
        System.out.println("Contents of get request");
        System.out.println("=============================");
        String lines;
        while ((lines = reader.readLine()) != null){
        	//lines = new String(lines.getBytes(), "utf-8");
            System.out.println(lines);
        }
        reader.close();
        // 断开连接
        connection.disconnect();
        System.out.println("=============================");
        System.out.println("Contents of get request ends");
        System.out.println("=============================");
    }
	public static void readContentFromPost() throws IOException{
        // Post请求的url,与get不同的是不需要带参数
        URL postUrl = new URL(POST_URL);
        // 打开连接
        HttpURLConnection connection = (HttpURLConnection) postUrl
                .openConnection();
        // Output to the connection. Default is
        // false, set to true because post
        // method must write something to the
        // connection
        // 设置是否向connection输出,因为这个是post请求,参数要放在
        // http正文内,因此需要设为true
        connection.setDoOutput(true);
        // Read from the connection. Default is true.
        connection.setDoInput(true);
        // Set the post method. Default is GET
        connection.setRequestMethod("POST");
        // Post cannot use caches
        // Post 请求不能使用缓存
        connection.setUseCaches(false);
        // This method takes effects to
        // every instances of this class.
        // URLConnection.setFollowRedirects是static函数,作用于所有的URLConnection对象。
        // connection.setFollowRedirects(true);
 
        // This methods only
        // takes effacts to this
        // instance.
        // URLConnection.setInstanceFollowRedirects是成员函数,仅作用于当前函数
        connection.setInstanceFollowRedirects(true);
        // Set the content type to urlencoded,
        // because we will write
        // some URL-encoded content to the
        // connection. Settings above must be set before connect!
        // 配置本次连接的Content-type,配置为application/x-www-form-urlencoded的
        // 意思是正文是urlencoded编码过的form参数,下面我们可以看到我们对正文内容使用URLEncoder.encode
        // 进行编码
        connection.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
        // 连接,从postUrl.openConnection()至此的配置必须要在connect之前完成,
        // 要注意的是connection.getOutputStream会隐含的进行connect。
        connection.connect();
        DataOutputStream out = new DataOutputStream(connection
                .getOutputStream());
        // The URL-encoded contend
        // 正文,正文内容其实跟get的URL中'?'后的参数字符串一致
        String content = "key=j0r53nmbbd78x7m1pqml06u2&type=1&[email protected]" + "&activatecode=" + URLEncoder.encode("久酷博客", "utf-8");
        // DataOutputStream.writeBytes将字符串中的16位的unicode字符以8位的字符形式写道流里面
        out.writeBytes(content); 
        out.flush();
        out.close(); // flush and close
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));//设置编码,否则中文乱码
        String line="";
        System.out.println("=============================");
        System.out.println("Contents of post request");
        System.out.println("=============================");
        while ((line = reader.readLine()) != null){
            //line = new String(line.getBytes(), "utf-8");
            System.out.println(line);
        }
        System.out.println("=============================");
        System.out.println("Contents of post request ends");
        System.out.println("=============================");
        reader.close();
        connection.disconnect();
    }
}

HttpURLConnection.connect函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。无论是post还是get,http请求实际上直到HttpURLConnection.getInputStream()这个函数里面才正式发送出去。

在readContentFromPost() 中,顺序是重中之重,对connection对象的一切配置(那一堆set函数)都必须要在connect()函数执行之前完成。而对 outputStream的写操作,又必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。

http 请求实际上由两部分组成,一个是http头,所有关于此次http请求的配置都在http头里面定义,一个是正文content,在connect()函数里面,会根据HttpURLConnection对象的配置值生成http头,因此在调用connect函数之前,就必须把所有的配置准备好。

紧接着http头的是http请求的正文,正文的内容通过outputStream写入,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是在流关闭后,根据输入的内容生成http正文。

至此,http请求的东西已经准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数之后对connection对象进行设置(对http头的信息进行修改)或者写入 outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。

2014.4-30:这是 IP 库的第二个公开版本,这个版本放开了国内市一级的数据。个人感觉更为实用,下载:http://bbs.ajaxjs.com/forum.php?mod=viewthread&tid=3703

感谢高春辉大大提供资源:)http://tool.17mon.cn/ipdb.html

原版是 Java 文件的,要转换为 JSP 形式的也容易,改一下字符串控制方法就可以了。源码如下:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@page import="java.io.*" %>
<%@page import="java.util.*" %>
<%@page import="java.net.*" %>
<%@page import="java.nio.*" %>
<%@ page trimDirectiveWhitespaces="true" %>
<%
class IPDataHandler {
	private String IP_DATA_PATH = "C:/project/wlsc/mmc/17monipdb.dat";
	private DataInputStream inputStream = null;
	private long fileLength = -1;
	private int dataLength = -1;
	private Map<String, String> cacheMap = null;
	private byte[] allData = null;
	public IPDataHandler(){
           prefix = prefix.replace("ipLocation.jsp", "17monipdb.dat");
           File file = new File(prefix);
		try {
			inputStream = new DataInputStream(new FileInputStream(file));
			fileLength = file.length();
			cacheMap = new HashMap<String, String>();
			if (fileLength >Integer.MAX_VALUE) {
				throw new Exception("the filelength over 2GB");
			}
			
			dataLength = (int) fileLength;
			allData = new byte[dataLength];
			inputStream.read(allData, 0, dataLength);
			dataLength = (int)getbytesTolong(allData, 0, 4,ByteOrder.BIG_ENDIAN);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	private long getbytesTolong(byte[] bytes, int offerSet,int size,ByteOrder byteOrder){
		if ((offerSet+size) > bytes.length || size <= 0) {
			return -1;
		}
		byte[] b = new byte[size];
		for (int i = 0; i < b.length; i++) {
			b[i] = bytes[offerSet+i];
		}
		
		ByteBuffer byteBuffer = ByteBuffer.wrap(b);
		byteBuffer.order(byteOrder);
		
		long temp = -1;
		if (byteBuffer.hasRemaining()) {
			temp = byteBuffer.getInt();
		}
		return temp;
	}
	
	private long ip2long(String ip) throws UnknownHostException {
		InetAddress address = InetAddress.getByName(ip);
		byte[] bytes = address.getAddress();	
		long reslut = getbytesTolong(bytes, 0, 4,ByteOrder.BIG_ENDIAN);
		return reslut;
	}
	

	private int getIntByBytes(byte[] b,int offSet)
	{
		if (b == null || (b.length < (offSet+3))) {
			return -1;
		}
		
		byte[] bytes = Arrays.copyOfRange(allData, offSet, offSet+3);
		byte[] bs = new byte[4];
		bs[3] = 0;
		for (int i = 0; i < 3;i++) {
			bs[i]=bytes[i];
		}
		
		return (int)getbytesTolong(bs, 0, 4, ByteOrder.LITTLE_ENDIAN);
	}

	
	public String findGeography(String address){
		if (address == null) {
			return "illegal address";
		}
		
		if (dataLength < 4 || allData == null) {
			return "illegal ip data";
		}
		
		String ip = "127.0.0.1";
		try {
			ip = Inet4Address.getByName(address).getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} 
		
		// String[] ipArray = StringUtils.split(ip, ".");
		 // String[] ipArray = ip.split(".");

		//String[] ipArray = {"8", "8", "8", "8"};
		String[] ipArray = ip.split("\\.");
		int ipHeadValue = Integer.parseInt(ipArray[0]);
		if (ipArray.length !=4 || ipHeadValue < 0 || ipHeadValue > 255) {
			return "illegal ip";
		}
		
		if (cacheMap.containsKey(ip)) {
			return cacheMap.get(ip);
		}
		
		
		long numIp = 1;
		try {
			numIp = ip2long(address);
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
		}
		
		
		int tempOffSet = ipHeadValue* 4 + 4;
		long start = getbytesTolong(allData, tempOffSet, 4,ByteOrder.LITTLE_ENDIAN);
		int max_len = dataLength - 1028;
		long resultOffSet = 0;
		int resultSize = 0;
		
		for (start = start*8 + 1024; start < max_len; start+=8) {
			if (getbytesTolong(allData, (int)start+4, 4,ByteOrder.BIG_ENDIAN) >= numIp) {
				resultOffSet = getIntByBytes(allData, (int)(start+4+4));
				resultSize = (char)allData[(int)start+7+4];
				break;
			}
		}
		
		if (resultOffSet <= 0) {
			return "resultOffSet too small";
		}
		
		byte[] add = Arrays.copyOfRange(allData, (int)(dataLength+resultOffSet-1024), (int)(dataLength+resultOffSet-1024 + resultSize));
		try {
			if (add == null) {
				cacheMap.put(ip, new String("no data found!!"));
			} else {
				cacheMap.put(ip, new String(add,"UTF-8"));
			}
			
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return cacheMap.get(ip);
	}
}
IPDataHandler obj = new IPDataHandler();

%>
<%=obj.findGeography("18.248.9.180")%>

获取 ip 并调用之:

	// 获取请求 ip
	String ip = request.getHeader("x-forwarded-for");   
	if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
		ip = request.getHeader("Proxy-Client-IP");   

	if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) 
		ip = request.getHeader("WL-Proxy-Client-IP");   

	if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) 
		ip = request.getRemoteAddr();

	// 获取文件的绝对路径
	String adsoPath = request.getSession().getServletContext().getRealPath(request.getRequestURI()); 

	IPDataHandler obj = new IPDataHandler(adsoPath);
	//out.write(obj.findGeography("18.248.9.180"));
	out.write(obj.findGeography(ip));

Struts 2学习笔记 & 解决 EL 表达式不能调用方法、传参数的问题

初学入门推荐:《良葛格學習筆記》http://openhome.cc/Gossip/

Servlet 3.0 学习

JSP 部分

 编辑web.xml文件,在里边添加如下内容:

<servlet>
        <servlet-name>Test</servlet-name>
        <servlet-class>com.nantian.jndi.Test</servlet-class>
        <init-param>
            <param-name>jndi</param-name>
            <param-value>java:comp/env/jdbc/test</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Test</servlet-name>
        <url-pattern>/Test</url-pattern>
    </servlet-mapping>
jsp 也可以接受 url mapping,

<servlet>
        <servlet-name>service</servlet-name>
        <jsp-file>/public/service.jsp</jsp-file>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>service</servlet-name>
        <url-pattern>/service/projectcase/*</url-pattern>
    </servlet-mapping>

注解方式 @WebServlet("/service/*")

JAVA 语法部分

String.format("请求 URL 没有带有 %s 参数!", key);

IllegalArgumentException/NullPointerException

// 泛型的例子,调用
// bar obj = new bar<VideoInfo>();
// ArrayList<VideoInfo> list = obj.render(service, album.getId());
class bar<T>{
	public ArrayList<T> render(Service service, int albumId){
		AlbumInfoService videoList_Service = (AlbumInfoService)service.getServiceInCache();
		Map<String, Object> videoList = videoList_Service.findVideosByAlbum(albumId, 0 , 10).getVideos();
		ArrayList<T> list = (ArrayList<T>)videoList.get("results");

		return list;
		// Long totalCount = (Long)videoList.get("totalCount");
	}
}

/**
 * 获取任意的配置内容,读取某个节点的配置对象
 * 用法:<%=Config.getAnyConfig("companyInfo.name")%> 
 * @param key
 * @return
 */
public static String getAnyConfig(String node){
    return getAnyConfig(node, String.class);
}

/**
 *  Config.getConfigNode("companyInfo.name", String.class)
 *  ${viewController.companyInfo.name}
 * @param node
 * @param classType
 * @return
 */
@SuppressWarnings("unchecked")
public static <T> T getAnyConfig(String node, Class<T> classType){
    if(isLaunchByListener){
        if(!isConfig_Ready)
            throw new IllegalArgumentException("Application Level Error:未加载程序配置,请检查 Web.xml 是否已经添加 Listener");
        
        node = "bf.app_config." + node;
        System.out.println("正在获取节点:"+node);
        
        try {
            return (T)jsRuntime.eval(node);
        } catch (ScriptException e) {
            ajaxjs.Util.catchException(e, "读取配置%s失败!");
            return null;
        }
    }else{
        return (T)get(node, simpleConfig);
    }
}

泛型是没有数组的。编译器不承认 HashMap[]这种形式的

创建 MAP(匿名实例的写法)
 Map map = new HashMap() {{
          put( "Name" , "Unmi" );
          put( "QQ" , "1125535" );
}}; 
遍历 MAP:
for(java.util.Map.Entry mapEntry : responseData.entrySet()) {
	Key key = mapEntry.getKey();  
	Value value = mapEntry.getValue();  
}

for (String key : cookie.keySet())
       cookieStr += key + "=" + cookie.get(key) + ";";

反射

需要包 java.lang.reflect.*
class Article extends BaseService<ArticleInfo>{
	public void f(){
		Class clazz=this.getClass();
		Method[] methods=clazz.getMethods();

		for(Method method:methods){
			if(method.getName().equals("findById")) {
				System.out.println("---");
			    System.out.print(method.getReturnType().getName()+" "+method.getName()+" ");
		        Class<?>[] types=method.getParameterTypes();

		        for(Class<?> type:types){
		    	    System.out.print(type.getName()+" ");
		        }

		        System.out.println();
		    }
		}
	}
}

Struts 部分

Webwork 到 2.0 版本的时候就是 Struts。现在公司的 WAP 项目在用,也终于让我有了学习的机会大笑

学习的还是以模版语言为主。

基本流程语句:

<s:if test="%{false}">
    <div>Will Not Be Executed</div>
</s:if>
<s:elseif test="%{true}">
    <div>Will Be Executed</div>
</s:elseif>
<s:else>
    <div>Will Not Be Executed</div>
</s:else>

字符长度超出限定控制。如果超出 28 个,则自动截取,并显示 ……。

<p class="listDescription">
   <s:if test="description.length() > 28">
      <s:property value="description.substring(0, 28) + '……'" />
   </s:if>
   <s:else>
        <s:property value="description" />
   </s:else>
</p>

include 页面如何传参数?

<!--返回条-->
<s:set name="variable" value="'专辑'" />
<s:set name="variable2" value="'详情'" />
<%@ include file="public_new/returnBar.jsp" %>
<!--// 返回条-->
被引入的页面如下:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!--返回条-->
<div class="returnBar">
	<div class="goBackBtn" title="返回上一页" onclick="history.go(-1);"></div>
	<a href="." title="返回首页"><div class="homeBtn"></div></a>
	<s:property value="#variable" /><s:property value="#variable2" />
</div>
<!--// 返回条-->

工具篇:

  • Eclipse 可支持外部文件夹作为 src 源码:设置项目 Build Path--> Source-->Add Linked Folder 即可
  • 如果 Eclipse 不显示 Build 文件夹下面的 Class 文件,可在 Project Exlopoer --》三角下拉菜单--》 CustomView... 取消打勾即可显示
  • 如果某些类明明存在的,却不能成功 import 的话,可在 Build Path 将 JRE 删除再添加
  • Tomcat 可以快速热部署,设置 reload=true 即可。项目工程不要太大,否则会内存泄漏

大量 Java 教程资源(百度网盘)

技术文档
  内部教学课件及资料
 · 尚硅谷_教学课件_Java基础
 · 尚硅谷_教学课件_SQL
 · 尚硅谷_教学课件_oracle、sql、plsql
 · 尚硅谷_教学课件_JDBC
 · 尚硅谷_Java基础实战_Bank项目
 · 尚硅谷_教学课件_JavaScript DOM编程
 · 尚硅谷_教学课件_jQuery
 · 尚硅谷_教学课件_Ajax
 · 尚硅谷_教学课件_JavaWEB
 · 尚硅谷_教学课件_Struts2
 · 尚硅谷_教学课件_Hibernate4
  开发入门相关
 · Java工程师必知必会_[尚硅谷].pdf
 · JDK7的下载-安装-配置_[尚硅谷].pdf
 · Oracle 安装视频及课件_[尚硅谷].rar
 · Eclipse的安装配置与使用_[尚硅谷].pdf
 · Eclipse常用设置_[尚硅谷].pdf
 · Eclipse快捷键_[尚硅谷_宋红康].pdf
 · 计算机常见编码_[尚硅谷].pdf
 · Java常用英语汇总_[尚硅谷].pdf
 · 云计算入门指南_[尚硅谷].pdf
  Java基础及数据库
 · 参悟Java基础核心技术_[尚硅谷_宋红康].pdf
 · 深度解析Java内存原型_[尚硅谷_宋红康].pdf
 · Java反射机制_[尚硅谷_宋红康].pdf
 · Java反射机制的缺点_[尚硅谷_张晓飞].pdf
 · Java 之23种设计模式解析_[尚硅谷_宋红康].pdf
 · JDK中的设计模式应用实例_[尚硅谷_张晓飞].pdf
 · 常用sql操作总结_[尚硅谷_宋红康].pdf
 · Mysql 性能优化教程_[尚硅谷_张晓飞].pdf
 · 4天贯通JDBC_[尚硅谷_宋红康].pdf
 · 深入Java集合学习系列(一):HashMap的实现原理.pdf
 · 深入Java集合学习系列(二):ArrayList实现原理.pdf
 · 深入Java集合学习系列(三):ArrayList实现原理.pdf
 · 深入Java集合学习系列(四):LinkedHashMap的实现原理.pdf
  就业面试相关
 · 115个Java面试题和答案——终极(上).pdf
 · 115个Java面试题和答案——终极(下).pdf
 · plsql经典试题_[尚硅谷_宋红康].pdf
 · sql面试题_ [尚硅谷_宋红康].pdf
 · JavaWeb面试题_ [尚硅谷_张晓飞].pdf
 · Java程序员的10道XML面试题_ [尚硅谷_宋红康].pdf
 · Struts2面试题分析_[尚硅谷_佟刚].pdf
 · Spring 面试题分析_[尚硅谷_佟刚].pdf
 · Hibernate面试题分析_[尚硅谷_佟刚].pdf
 · Android面试题大全_[尚硅谷_张晓飞].pdf
  JavaWeb及相关技术
 · JavaWeb知识结构图_[尚硅谷].jpg
 · HTML培训教程_[尚硅谷_张晓飞].docx
 · CSS培训教程_[尚硅谷_张晓飞].docx
 · 核心Javascript培训教程_[尚硅谷_张晓飞].docx
 · JavaScript DOM编程_[尚硅谷_张晓飞].docx
 · jQuery培训教程_[尚硅谷_张晓飞].docx
 · CSS扫盲_[尚硅谷_封捷].pdf
 · HTML初步_[尚硅谷_封捷].pdf
 · JavaScript学习笔记_[尚硅谷_封捷].pdf
 · jQuery学习笔记_[尚硅谷_封捷].pdf
 · HTTP协议简介_[尚硅谷_封捷].pdf
 · Tomcat的设计模式分析_[尚硅谷_张晓飞].pdf
 · Tomcat系统架构分析_[尚硅谷_张晓飞].pdf
 · XML简介_[尚硅谷_封捷].pdf
 · UML模型图_[尚硅谷_张晓飞].pdf
 · Servlet_[尚硅谷_封捷].pdf
 · 尚硅谷WEB书城_[尚硅谷_张晓飞].docx
 · 正则表达式学习手册_[尚硅谷_张晓飞].pdf
 · JNDI原理_ [尚硅谷_张晓飞].pdf
 · ModelDriven和Preparable拦截器_[尚硅谷_封捷].pdf
 · Web基础架构:负载均衡和LVS_[尚硅谷_张晓飞].pdf
 · Web应用环境搭建_[尚硅谷_封捷].pdf
 · 版本控制器[上]服务器端安装与配置_[尚硅谷_封捷].pdf
 · 缓存技术浅谈_[尚硅谷_张晓飞].pdf
  JavaEE及相关技术
 · Mybatis_[尚硅谷_张晓飞].pdf
 · Webservice_[尚硅谷_张晓飞].pdf
 · JSR303验证_[尚硅谷_佟刚].pdf
 · Spring IOC 容器中 Bean 的生命周期_[尚硅谷_佟刚].pdf
 · Spring 整合 Struts2 详解_[尚硅谷_佟刚.pdf
 · SpringMVC+运行流程解析_[尚硅谷_佟刚].pdf
 · SpringSecurity之自定义用户权限信息的存取.pdf
 · Struts2 运行流程分析_[尚硅谷_佟刚].pdf
 · 扩展+Spring+Data+JPA_[尚硅谷_佟刚].pdf
 · 使用 PowerDesigner_[尚硅谷_佟刚].pdf
 · 图解Spring AOP_[尚硅谷_张晓飞].pdf
 · 性能调优之Weblogic调优_[尚硅谷_张晓飞].pdf
 · 性能调优之性能参数指标_[尚硅谷_张晓飞].pdf
开发工具
  Java基础必备
 ·JDK-7u71-windows-x64.exe[64位]
 ·JDK-7u71-windows-i586.exe[32位]
 ·Editplus.zip[文本编辑器]
  Eclipse 及其插件
 ·eclipse-jee-kepler-SR1-win32.zip[32位]
 ·eclipse-jee-kepler-SR1-win64.zip[64位]
 ·springsource-tool-suite-3.4.0.RELEASE.zip[spring插件]
 ·hibernatetools-Update-4.1.1.zip[hibernate插件]
 ·subclipse.zip[SVN插件]
 ·eclipse-maven3-plugin.7z[Maven插件]
  Oracle
 ·oracle 10g.zip[安装包]
 ·PL.SQL.Developer.v7.1.4.1390-Crack.zip[PL/SQL安装包]
 ·10201_client_win32.zip[客户端安装包]
 ·Toad for Oracle 12.rar[操作Oracle数据库的工具包]
  MySQL
 ·Mysql_win64.msi[64位]
 ·Mysql_win32.msi[32位]
 ·SQLyog-10.0.0-0.zip[客户端]
 ·MySQL_Workbench_5_2_37_Jisuxz.com.rar[客户端]
  Tomcat
 ·Apache-tomcat-6.0.16.zip[Tomcat安装包]
 ·Apache-tomcat-6.0.18-src.zip[Tomcat源码包]
  Android
 ·adt-bundle-windows-x86.zip[包含eclipse/sdk/adt的Android开发工具包]
 ·SQLiteExpertPersSetup.exe[android中的Sqlite数据库客户端工具]
 ·haxm-windows_r03.zip[模拟器的Intel硬件加速]
  建模工具
 ·Rose[项目开发建模]
 ·Staruml.zip[项目开发建模] 
 ·PowerDesigner15.1_CN_CR.rar[数据库建模]
  其它
 ·思维导图MindManager2012破解版.zip
 ·pache-james-2.3.2.zip[邮件服务器安装包]
 ·apache-james-2.3.2-src.zip[邮件服务器源码包]
 ·apache-ant-1.7.1-bin.zip[应用构建工具Ant安装包]
 ·apache-ant-1.7.1-src.zip[应用构建工具Ant源码包]
 ·apache-maven-3.0.4-bin.zip[应用管理工具Maven安装包] 
jar包开源框架
  Javascript & jQuery &Ajax&JSON
 · jquery-1.7.2.js
 · jquery-1.7.2.min.js
 · jQuery插件
 · EasyUI+v1.3.4官方API中文版
 · EasyUI+v1.3.4官方API中文版.rar
 · jackson-src-1.7.1.zip
 · ext-3.0.0.zip
 · google-gson-2.2.4-release.zip
  apache-commons框架
 · commons-validator-1.3.1-src.zip
 · commons-lang3-3.2.1-src.zip
 · commons-fileupload-1.2.1-src.zip
 · commons-dbutils-1.3-bin.zip
 · commons-pool-1.5.5-bin.zip
 · commons-io-2.0-bin.zip
 · commons-lang-2.5-src.zip
 · commons-logging-1.1.1-bin.zip
 · commons-io-2.0-src.zip
 · commons-lang3-3.2.1-bin.zip
 · commons-lang-2.5-bin.zip
 · commons-dbutils-1.3-src.zip
 · commons-pool-1.5.5-src.zip
 · commons-validator-1.3.1.zip
 · commons-logging-1.1.1-src.zip
 · commons-dbcp-1.4-src.zip
 · commons-fileupload-1.2.1-bin.zip
 · commons-codec-1.4-bin.zip
 · commons-dbcp-1.4-bin.zip
 · commons-collections-3.2.1-src.zip
 · commons-codec-1.4-src.zip
 · commons-beanutils-1.8.0-bin.zip
 · commons-beanutils-1.8.0-src.zip
 · commons-collections-3.2.1-bin.zip
  SSH框架
 · struts-menu-2.4.3.zip
 · spring-modules-0.9-with-dependencies.zip
 · spring-framework-3.1.0.CI-1163-dependencies.zip
 · spring-framework-2.5.6.SEC01-with-dependencies.zip
 · struts-menu-2.4.3-src.zip
 · struts-2.3.15.3-all.zip
 · spring-framework-4.0.0.RELEASE-dist.zip
 · struts-2.3.4-all.zip
 · struts-1.3.8-all.zip
 · spring-framework-3.1.1.RELEASE-with-docs.zip
 · struts2-2.2.1-all.zip
 · struts-2.1.8.1-all.zip
 · hibernate-distribution-3.6.0.Final-dist.zip
 · hibernate-distribution-3.5.1-Final-dist.zip
 · hibernate-release-4.2.4.Final.zip
  spring-data-jpa(1.4.2.RELEASE)
 · spring-data-jpa-1.4.2.RELEASE-sources.jar
 · spring-data-jpa-1.4.2.RELEASE-javadoc.jar
 · spring-data-jpa-1.4.2.RELEASE.jar
 · spring-data-jpa-reference.pdf
  spring-data-commons
 · spring-data-commons-1.6.2.RELEASE-sources.jar
 · spring-data-commons-1.6.2.RELEASE.jar
 · spring-data-commons-1.6.2.RELEASE-javadoc.jar
  shiro
 · shiro所有相关jar包
 · shiro-root-1.2.2-source-release.zip
  spring-security
 · spring-security-3.1.0.M1.zip
 · spring-security-2.0.5.zip
  工作流
 · jbpm-4.3.zip
 · jbpm-4.4.zip
 · jbpm-jpdl-suite-3.2.3.zip
 · activiti-5.15.1.zip
  android
 · activiti-5.15.1.zip
 · adt-bundle-windows-x86-20140702.zip
 · android-sdk-windows.zip
  其它
 · spring-modules-0.9.zip
 · poi-src-3.5-FINAL-20090928.zip
 · poi-bin-3.5-FINAL-20090928.zip
 · slf4j-1.6.1.zip
 · pinyin4j-2.5.0.zip
 · ognl.zip
 · mysql-connector-java-5.1.7.zip
 · joda-time-2.3-dist.zip
 · jfreechart-1.0.13-javadocs.zip
 · jfreechart-1.0.13.zip
 · jdom-1.1.zip
 · javamail-1_4_1.zip
 · jakarta-taglibs-standard-1.1.2-src.zip
 · jakarta-taglibs-standard-1.1.2.zip
 · jaf-1_1_1.zip
 · hibernate-validator-5.0.0.CR2-dist.zip
 · guice-1.0-src.zip
 · guice-1.0.zip
 · displaytag-1.2-bin.zip
 · displaytag-1.2-src.zip
 · cewolf-1.1.4.zip
 · cewolf-1.0-bin-src.zip
 · c3p0-0.9.1.2.src.zip
 · c3p0-0.9.1.2.bin.zip
 · apache-log4j-1.2.15.zip
 · xwork2-2.1.rar
 · dom4j-1.6.1.rar
 · elecfans.com-XPath.rar
 · xwork-assembly-2.1.6-all.zip
 · quartz-2.2.1-distribution.tar.gz
 · xloadtree_zh_cn.zip
 · xdoclet-src-1.2.3.zip
 · xdoclet-bin-1.2.3.zip
 · xfire-distribution-1.2.6.zip
 · xdoclet-lib-1.2.3.zip
API帮助文档
  J2SE相关
 · 设计模式手册.chm
 · jdk150.chm
 · JDK7_docs.CHM
 · J2SE6.0.chm
  JavaWEB相关
 · Java_EE_6_API.chm
 · J2EE1.5.chm
 · Ajax帮助文档.chm
 · XMLHTTP 手册.Chm
 · XML指南.chm
 · CSS2.0_DOC.chm
 · CSS_精通CSS滤镜.chm
 · CSS_5日精通CSS层叠样.chm
 · 样式表中文手册.chm
 · 网页设计本色常识.chm
 · servlet.chm
 · JSP语法.chm
 · j2ee-HttpServlet.chm
 · html̳.chm
 · DHTML文档对象.CHM
 · DHTML手册(英文).chm
 · css样式表滤镜.chm
 · CSS样式表.CHM
 · css2gb.chm
 · css2.chm
 · CSSFilter2.0_DOC_CN.chm
 · jQuery.chm
 · jdom.chm
 · DHTML_DOC_CN.chm
 · 网页制作完全手册.chm
 · XDoclet1.2.chm
 · Tomcat_Servlet&Jsp_API文档.chm
 · JScript 中文参考手册.chm
 · JspSmartUpload.chm
  数据库相关
 · MySQL.chm
 · PostgreSQL8.1_DOC_CN.chm
 · ORACLE_10g帮助文档(下载).zip
 · ORACLE 九阴真经.chm
 · MySQL_5.1_zh.chm
 · 数据库技术:《SQL 参考手册》中文版.chm
  框架相关
 · Hibernate3.1_DOC_CN.chm
 · StrutsAPI 1.2.chm
 · Validato_表单验证.chm
 · spring3.1.chm
 · Struts1.3.chm
 · Spring-Reference_zh_CN.chm
 · Spring+Security教程.chm
 · Spring2.0_DOC_CN.chm
 · Hibernate3.2.chm
 · hibernate 帮助文档.chm
 · jbpm3.chm
 · JBPM用户手册.chm
 · Struts2.chm
  其它
 · Comm2.0.chm
 · WebServices.chm
 · 英语资料大全.chm
 · VBScript_DOC.chm
 · J2ME2.5.chm
 · DOS实例手册.chm
 · jFreeChart.CHM
 · Ant1.7.chm
 · Log4j1.2.chm
 · JUnit4.1.chm

解决 EL & 表达式不能调用方法、传参数的问题

在自定义标签的使用中,EL 表达式是必不可少的一环。官方的 API 需要到了最新版本(EL v2.2, JDK7、Tomcat 7)才可以提供调用方法的直接方式。在老版本的 Tomcat 下,如何才可以像 Strus 那样调用方法呢?国外一位开发者给出了答案。首先复制以下两个类 ELMethod.java 和 Call.java 到你的项目中(适当修改包名)。

http://www.vineetmanohar.com/2010/07/how-to-pass-parameters-in-el-methods/

http://www.vineetmanohar.com/2010/08/calling-static-methods-from-el/

ELMethod.java:

package com.vineetmanohar.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Extend this class to implement a server side method that takes arguments that
 * you would like to call via expression language.
 * 
 * @author Vineet Manohar
 */
public abstract class ELMethod extends HashMap<Object, Object> {
	private static final long serialVersionUID = 1L;

	private final int numArgs;

	/**
	 * @param numArgs
	 *            number of arguments this method takes
	 */
	protected ELMethod(int numArgs) {
		this.numArgs = numArgs;
	}

	@Override
	public Object get(Object key) {
		// if exactly one argument, call the result() method
		if (numArgs == 1) {
			return result(new Object[] {key});
		}

		// if more tha one argument
		return new Arg(this, key);
	}

	public int getNumArgs() {
		return numArgs;
	}

	/**
	 * 1) Implement this method in the child class. This method becomes
	 * accesible via expression language.
	 * 
	 * 2) Call this method using map syntax, by treating the instance of the
	 * child class as a map of map of maps...
	 * 
	 * For example, you could extends this class and create a class called
	 * FormatDate. In that class, the result method would expect 2 arguments,
	 * format string and date object.
	 * 
	 * ${FormatDate["MMM dd"][user.creationDate]}, where dateFormat is an
	 * instance of the child class.
	 * 
	 * @param args
	 * @return
	 */
	public abstract Object result(Object[] args);
	
	public static class Arg extends HashMap<Object, Object> {
		private static final long serialVersionUID = 1L;
		private List<Object> args = new ArrayList<Object>();
		private ELMethod parent;

		public Arg(ELMethod eLMethod, Object key) {
			this.parent = eLMethod;
			this.args.add(key);
		}

		@Override
		public Object get(Object key) {
			this.args.add(key);

			// if all the arguments have been received, invoke the result method
			if (args.size() == parent.getNumArgs()) {
				Object retVal = parent.result(args.toArray());

				return retVal;
			}

			return this;
		}
	}
}
Call.java:

package com.vineetmanohar.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class lets you call static methods from EL
 * 
 * Step 1) Create an instance of this class and bind it to the "call" variable
 * in your EL. For example, in a JSP do the following:
 * request.setAttribute("call", new Call());
 * 
 * Step 2) Call any static method as follows:
 * 
 * ${call["some.package.SomeClass.methodName"]["arg1"][arg2]}
 * 
 * The first argument is the fully qualified class and method name. The
 * remaining arguments are arguments to the method that you are calling.
 * 
 * Note: method overloading not supported
 * 
 * Note: method must be static
 * 
 * @author Vineet Manohar
 */
public class Call extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;

	@Override
	public Object get(Object key) {
		String fullyQualifiedMethodName = (String) key;

		// format of key is package.Class.method
		Pattern pattern = Pattern.compile("(.+)\\.([^\\.]+)");
		Matcher m = pattern.matcher(fullyQualifiedMethodName);
		if (m.matches()) {
			String fqClassName = m.group(1);
			String methodName = m.group(2);
			Class<Object> clazz;
			try {
				clazz = (Class<Object>) Class.forName(fqClassName);
			} catch (ClassNotFoundException e) {
				throw new IllegalArgumentException("Invalid method name: "
						+ key, e);
			}
			Method[] methods = clazz.getMethods();
			for (final Method method : methods) {
				if ((method.getModifiers() & Modifier.STATIC) == 0) {
					continue;
				}

				if (method.getName().equals(methodName)) {
					// return the first method found
					int numParameters = method.getParameterTypes().length;

					if (numParameters == 0) {
						return invokeMethod(method);
					}

					return new ELMethod(numParameters) {
						@Override
						public Object result(Object[] args) {
							return invokeMethod(method, args);
						}
					};
				}
			}
		}

		throw new IllegalArgumentException("Invalid method name: " + key
				+ ". Must be a fully qualified class and method name");
	}

	private Object invokeMethod(final Method method, Object... args) {
		try {
			return method.invoke(null, args);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException("Exception while executing method", e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Exception while executing method", e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException("Exception while executing method", e);
		}
	}
}
然后实例化 Call 对象。反正在 JSP 里随你喜欢即可,如 request.setAttribute("call"new Call());<jsp:useBean id="call" class="Call" scope="application" /> 都冇问题。

最后一步就是解决问题的目标,调用方法并传参数了。试写出表达式:${call["com.mycompany.util.DateUtils.formatDate"]["MMM, dd"][account.creationDate]},其中 com.mycompany.util.DateUtils.formatDate 是 Java 静态方法,要写全称。最后两项是传入的参数,分别可以是字符串和当然 EL 对象(如account.creationDate)。

观其上述源码,实际是利用了 Java 反射的原理调用方法。不要注意一点的是,不支持方法的重载哦(Overloaded)。

如果不是静态方法,实例方法可不可以调用呢?按照作者的介绍也是可以的。

你可能感兴趣的:(java,tomcat,HashMap)