Java框架之Struts2(一)
在学习Struts2之前,我们要知道Java为什么要有反射机制呢?反射机制可以说是填补Java不能动态访问某一个类的空白。利用反射机制,动态的创建一个对象。动态的访问类的某个属性,而且访问哪一个属性自己可能还不知道,只能通过有个变量进行访问。
一、反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能:
1.在运行时判断任意一个对象所属的类;
2.在运行时构造任意一个类的对象;
3.在运行时判断任意一个类所具有的成员变量和方法;
4.在运行时调用任意一个对象的方法;
5.生成动态代理。
Java 中反射相关的类,都在 java.lang.reflect 包下,主要有以下几个类
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
Constructor <T> 提供关于类的单个构造方法的信息以及对它的访问权限。
java.lang 包下的 java.lang 类 Class<T>
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。 注意:可以这样 int.class
//例一 通过调用无参构造函数,创建对象 public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException { Dog dog=(Dog)createObj(Dog.class); dog.shout(); Cat cat=(Cat)createObj(Cat.class); cat.shout(); } //这个方法用来创建类的实例 static Object createObj(Class clazz) throws InstantiationException, IllegalAccessException{ return clazz.newInstance(); //创建对象(注意:它是调用对象的构造函数(无参)) } } class Dog{ public void shout(){ System.out.println("汪汪"); } } class Cat{ public void shout(){ System.out.println("喵喵"); } }
//例二 调用带参的数构造函数 class Dog{ private String dogName; public Dog(String dogName){ //有了一个有参的构造函数,就没有无参的构造函数了 this.dogName=dogName; } public void shout(){ System.out.println("汪汪 我的名字是"+this.dogName); } } static Object createObj(Class clazz) throws Exception{ // return clazz.newInstance(); 这样不可以 Constructor con=clazz.getConstructor(String.class);//它的参数是这样声明的 Class ... parameterTypes Object obj= con.newInstance("tom狗"); //Object ... initargs return obj; } public static void main(String[] args) throws Exception { Dog dog=(Dog)createObj(Dog.class); dog.shout(); //汪汪 我的名字是tom狗 }
//例三 方法的调用 class Dog{ private String dogName; public Dog(String dogName){ //有了一个有参的构造函数,就没有无参的构造函数了 this.dogName=dogName; } public void shout(){ System.out.println("汪汪 我的名字是"+this.dogName); } public void shout(String content){ System.out.println(content); } public void shout(String content,int age){ System.out.println(content+" 我的年龄是:" +age); } public void eat(){ System.out.println("小狗正在吃东西"); } } //动态调用类对象中的方法 //ojb 代表要被调用方法的对象 //methodName 代表要被调用的方法 static void invokeTest(Object obj,String methodName )throws Exception { //Method [] methods=obj.getClass().getDeclaredMethods(); //取得所有方法,但除了继承来的 //Method [] methods=obj.getClass().getMethods(); //取得所有公共方法,包含继承来的 /*for(Method m: methods){ System.out.println(m.getName()); }*/ /* Method m=obj.getClass().getMethod(methodName, String.class); //第二个参数 :Object ... parameterTypes m.invoke(obj, "这是做为一只狗想说的话");*/ Method m=obj.getClass().getMethod(methodName, String.class,int.class); m.invoke(obj, "这是我的另一句话",2); } public static void main(String[] args) throws Exception { Dog dog=(Dog)createObj(Dog.class); invokeTest(dog,"shout"); }
//例四 属性的调用 Field static void fieldTest(Dog dog)throws Exception{ //Field [] filedList=dog.getClass().getFields() ; //取得所有的公共字段,包含继承来的 Field [] filedList=dog.getClass().getDeclaredFields(); //取得所有的字段,除了继承来的 for(Field field : filedList){ System.out.println(field.getName()); System.out.println(field.get(dog)); //注意,这里要把 类对象传进去 Field 才知道要访问哪个类对象的属性 } } class Dog{ public String dogName ="tom"; public int age=90; } main 方法 : { Dog dog=(Dog)createObj(Dog.class); fieldTest(dog); }
二、Struts2 简介
Struts 2 是在 struts1 和 WebWork 的技术基础上进行了合并的mvc 框架,其全新的 Struts 2 的体系结构与 Struts1 的体系结构差别巨大。Struts2 以 WebWork 为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts2 可以理解为WebWork的更新产品。虽然从Struts1 到Struts2 有着太大的变化,但是相对于WebWork,Struts2 的变化很小
为什么要使用 struts2 呢?
传统的MVC模式的问题, 主要就是以下操作有重复性。
重复性一:得到请求参数 Servlet 中
String userName=request.getParameter("userName");
String password=request.getParameter("password");
UserInfo user=new UserInfo();
user.setUserName(userName);
....
重复性二:请得到的请求参数进行类型转换
int id=Integer.parseInt(request.getParameter("id"));
重复性三:对请求参数的校验 (服务端)
重复性四:请求的跳转 ... request.getRequestDispatcher("xxx.jsp").forward(reques,response)
常用的 MVC 框架
struts1
struts2
spring mvc
jsf (sun 公司提供的mvc 规范
三、Struts2环境的搭建
在struts2的开发包中,有四个文件夹,和一些文本的授权文件
apps, docs, lib , src
apps:示例程序
--struts2-blank.war //空的struts应用
如何搭建一个最最简单的Struts2的项目;它还会告诉你,Struts2至少需要依赖哪些jar包 (请以后不要再为jar包错误而苦恼);同时,也给你做出了一些范例,web.xml怎么写,struts.xml又怎么写。
--struts2-mailreader.war //给出了注册流程、以及发邮件功能
--struts2-portlet.war // 则给出了在Portal环境下的Struts2的应用
// Portal是一个基于web的应用程序,它主要提供个性化、单点登录、
// 不同来源的内容整合以及存放信息系统的表示层。
--struts2-rest-showcase.war //rest是 针对WEB 提出的一种构架风格 和 SOAP (简单的对象访问协议)是并列的概念
--struts2-showcase.war
Struts2的特性的大杂烩,这对于你看reference是相当有帮助的。比如说,当在看文档时看到了"文件上传"的章节,那么你就可以参考项目中的upload子目录。相当于你一边看文档,一边已经有一个现成的跑得通的例子在这里提供给你。
docs:文档,API 和相关的指南 (Guide)
注意,要从home.html 开始,过去的版本 是 index.html,现在换了
lib:jar
src:源码
四、开发struts依赖的jar
==最少的配置:
struts2-core-2.x.x.jar : Struts2 框架的核心类库
xwork-2.x.x.jar XWork类库,Struts 在其上构建
ognl-2.6.x.jar 对象导航语言(Object Graph Navigation Lanaguage) Struts2 框架使用的一种表达式语言
freemarker-2.3.x.jar Struts2 的 UI标签模板 使用 freeMarker 编写
commons-logging-1.1.x.jar ASF 出品的日志包,Struts2 框架使用这个日志包来支持log4j 和 jdk1.4+的日志记录
Commons-fileupload
==还有一种最省事的方法:
如果不需要跟第三方框架集成,把不带-plugin 结尾的jar文件都添加到类路径即可,反之要加入对应的 plugin.jar文件,例如 和 spring 的集成,需要加入 struts2-spring-plugin-2.x.x.jar
==或者是把 struts2-blank\WEB-INF\lib 下所有的 jar 都导入
--asm-3.3.jar //小巧轻便的 Java 字节码操控框架 ,它能方便地生成和改造 Java 代码。 Hibernate 和 Spring 在底层都用到了 ASM(CgLib 底层用的 asm)
--asm-commons-3.3.jar //提供了基于事件的表现形式
--asm-tree-3.3.jar //提供了基于对象的表现形式
--commons-fileupload-1.3.1.jar //Struts文件的上传下载
--commons-io-2.2.jar //apache的一个开源的工具包,封装了IO操作的相关类,使用Commons IO可以很方便的读写文件,url源代码等
--commons-lang3-3.1.jar //用来处理Java基本对象方法的工具类包,可以简化很多平时经常要用到的写法,例如判断字符串是否为空等等。
--commons-logging-1.1.3.jar //提供的是一个日志(Log)接口(interface)
--freemarker-2.3.19.jar //是一个模板引擎,一个基于模板生成文本输出的通用工具,更适合作为Model2框架(如Struts)的视图组件,你也可以在模板中使用JSP标记库
--javassist-3.11.0.GA.jar //(JAVA编程助手)使Java字节码操纵简单。这是一个编辑Java字节码的类库。
--log4j-1.2.17.jar //非常强大的log记录软件
--ognl-3.0.6.jar //对象图导航语言,是一种功能强大的表达式语言
--struts2-core-2.3.16.1.jar //核心包
--xwork-core-2.3.16.1.jar //webwork的核心包,因为struts2的前身是webwork
五、搭建Struts2 的初始环境:
1) 导包
apps\struts2-blank\WEB-INF\lib 下所有的jar包
2) 配置全局的一个过滤器 在 web.xml 中配置
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3) 建一个struts.xml 文件,放到src目录下即可
内容如下 是空的
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
</struts>
4) 布署项目,如果启动没报错,则环境搭建成功
六、第一个struts2 应用
1)
login.jsp <form action="gogogo" method="post"> 账号:<input type="text" name="userName" /> 密码:<input type="text" name="password" /> <input type="submit" value="提交" /> ${msg } </form>
2)
//在工程中建 cat.action这个包,然后在包下建 UserAction 这个类 //这个 UserAction 就是个普通类 public class UserAction { private String userName; //一定要和form表单中的字段同名 private String password; private String msg; .. 要生成 get set 方法 //方法的返回类型必须String 型,方法名任意 public String execute(){ UserInfo user=UserDao.getLoginUser(userName,password); if(user!=null){ msg="用户名和密码正确,OK"; return "my_success" ; //视图 } else{ msg="用户名或密码错误 Error"; return "my_error"; } }
3)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="packageOne" namespace="" extends="struts-default"> <action name="gogogo" class="cat.action.UserAction" method="execute" > <result name="my_success">/main.jsp</result> <result name="my_error">/login.jsp</result> </action> </package> </struts>
注意
1) execute 这个方法, 它的名字可以是任意的,如果就叫 execute ,则在配置文件中,不用指定 method
2) 方法的返回值必须是String
3) 要传值的属性必须有 get set 方法
总结 struts2 的开发流程
1) 定义能发送请求的页面,这个页面要么包含表单,要么包含超链接,个另情况可以不用(比如用javasript发请求,或从地址栏直接访问)
2) 定义处理请求的 action
3) 在配置文件中,配置 请求 和action的对应关系, 还要配置处理结果和物理视图之间的对应关系
4) 编写视图 (通常是jsp 或 html 等)
对于Action 的说明
对于 Action struts2 没有太多的要求,但通常建议
1) 实现Action接口 ,或 者继承自 ActionSupport 类(这个类实现了 Action 这个的接口),它增加了一些类型转换,输入输出校验等支持,而且它实现了execute这个方法,该方法直接返回 SUCCESS
2) 为每个请求参数都提供一个 field ,并提供get 和 set 方法 , 为传递的结果也定义field ,并提供get 和 set 方法
3) 提供一个无参的,返回值为String型的 execute 方法
对于配置文件中的Action 的配置
1) 要求所有的Action都在包中 (package)
2) action 元素通常用如下配置
-- name //皀定action处理哪个请求,也就是请求的名称 ,(gogogo)
-- class //指定action对应哪个类,
-- method //指定avction类中用哪个方法来处理请求
七、继承 ActionSupport 的Action 类
==GoodsAction ==
public class GoodsAction extends ActionSupport { private GoodsDao _dao=new GoodsDao(); private GoodsInfo goodsInfo; public String execute(){ if( _dao.addGoods(goodsInfo)==1) return SUCCESS; else{ return ERROR; } }
== goods_add.jsp===
<form action="goods/goodsAction" method="post"> 商品名称:<input type="text" name="goodsInfo.goodsName" /> 商品单价:<input type="text" name="goodsInfo.price" /> 商品描述:<input type="text" name="goodsInfo.des" /> 商品单位:<input type="text" name="goodsInfo.unit" /> <input type="submit" value="添加" > </form>
==配置文件==
<package name="pacakgeTwo" namespace="/goods" extends="struts-default" > <action name="goodsAction" class="cat.action.GoodsAction" method="execute" > <result name="success">/WEB-INF/goods_manage.jsp</result> <result name="error" >/error.jsp</result> </action> </package>
本例的知识点:
1) 可以使用对象传参,在页面用 goods.goodsName 这样的方式命名
2) extends ActionSupport
3) action 的配置文件中的namespace 的使用
4) 可以把内容放在WEB-INF下,这样可以防止客户端直接访问,只能由服务端进行跳转
例子:商品查询功能
//在 goods_manage.jsp 中 <a href="${pageContext.request.contextPath }/goods/listgoods" >查看所有商品</a> public class GoodsAction extends ActionSupport { private GoodsDao _dao=new GoodsDao(); private GoodsInfo goodsInfo; //这个是用来做商品添加的 private List<GoodsInfo>goodsList; //添加商品 public String execute(){ if( _dao.addGoods(goodsInfo)==1) return SUCCESS; else{ return ERROR; } } //查询所有商品 public String listGoods(){ goodsList=_dao.getGoodsList(); return SUCCESS; }
//在配置文件 <package name="pacakgeTwo" namespace="/aaa/bbb/ccc/goods" extends="struts-default" > <action name="goodsAction" class="cat.action.GoodsAction" method="execute" > <result name="success">/WEB-INF/goods_manage.jsp</result> <result name="error" >/error.jsp</result> </action> <action name="listgoods" class="cat.action.GoodsAction" method="listGoods" > <result name="success" >/WEB-INF/goods_list.jsp</result> </action> </package>
goods_list.jsp <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="/struts-tags" prefix="s" %> ... <body> <table width="80%" border=1 cellspacing="0"> <c:forEach var="goods" items="${goodsList}"> <tr> <td> ${goods.id} </td> <td> ${goods.goodsName} </td> <td> ${goods.unit } </td> <td> ${goods.price } </td> <td> ${goods.des} </td> </tr> </c:forEach> </table> // 用 struts 标签 方式一 <s:iterator var="goods" value="goodsList"> ${goods.id } | ${goods.goodsName } | ${goods.des } | ${goods.price } <br /> </s:iterator> <br> // 用 struts 标签 方式二 <s:iterator value="goodsList"> ${id } | ${ goodsName } | ${des } | ${price } <br /> </s:iterator> </body> </html>
总结:
1 该例继承自 ActionSupport 类,通常action都要继承自该类,以获得一些Struts提供的功能
2 Action中的 Field 是对象类型,所以form表单中的字段,也是 对象.属性这样的写法
3 它自动完成了类型转换
4 jsp文件(或其他 html等) 放在 WEB-INF 文件夹中,安全性更高
5 可以指定Action namespace 属性
6 namespace ,存在搜索顺序的问题,其规则如下:
1) 获得请求路径的URL 例如URL 是 http://localhost:8080/StrutsTest/p1/p2/p3/hellow.action
2) 先按长的路径,在 p1/p2/p3 下找有没有 namespace= p1/p2/p3的 package ,有这个package的话,则找pacakge里有没有名字为hellow的Action
如果没有这个package的话,则去默认 namespace的 package里去找
3) 如果没找到 namespace= p1/p2/p3的 package ,则递减,找 names民pace =p1/p2/的包
4) 以此类推
原则 : 不管有没有.只要找到包了,就不递减了
什么是默认 namespace 的 package ? 就是 不指定namespace 或指定 namespace="" 的包
7 请注意 url 的写法 <a href="${pageContext.request.contextPath }/goodsManage/listGoods" >
实际上,对请求的路径,经常要进行这样的处理 包扩 form表单的 action 属性也这样写
附: 如何在编写 struts.xml的时候能出现提示?
在 这个配置文件的上面,可以看到有对dtd 文件的引用
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> //这里可以在struts 提供的包中,搜索 struts-2.3.dtd 这个文件,找到后,复制出来放到一个地方 然后 点击 windows -> prefrences ->Myeclipse ->Files and Editors ->XML ->XML Catalog 点击右边的 add 按钮,
在弹出的对话框中, 上面的location 选刚才放置的struts-2.3.dtd文件的位置,
下面的 Key type 中选 uri,key的值输入 http://struts.apache.org/dtds/struts-2.3.dtd ,点击 ok 即可,一般来说要重启这个 struts.xml文件
附: 折叠代码插件 code folding 使用方法
解压后,把com.cb.eclipse.folding_1.0.6.jar复制到MyEclipse 8.5\dropins包下面
重启 myeclipse
点击Window > Preferences > Java >Editor>Folding ,进行设置,使用的时候:
/_start public String nihao="nihao"; public String tahao="tahao"; //_end