具有拦截器的简单Controller

工具:

IntelliJ IDEA 2018.2.5 (Ultimate Edition)
JRE: 1.8.0_152-release-1248-b19 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

拦截器Interceptor概念。

拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截然后再之前或者之后加入某些操作。

动态代理。

Java中的代理就是不直接操作目标类,而是通过一个代理类去间接的使用目标类中的方法,通过此种方法,在操作和目标类中间添加了一层中间层,能有效控制对目标类对象的直接访问,也可以很好的隐藏和保护目标类对象,同时在代理类中能给目标类实施多种控制策略,提高了设计上的灵活性,我们使用jdk动态代理,包括一个类Proxy和一个接口InvocationHandler,我们创建动态代理类必须继承InvocationHandler接口并实行invoke方法,当使用Proxy调用newProxyInstance方法后即创建了目标类的动态代理对象,此时通过代理对象调用目标对象方法时,这个方法就会被转发由InvocationHandler接口的invoke方法来进行调用。

1. 实现成果

        e3https://github.com/saaaaaail/J2eee3

2.在工程 UseSC 中定义源码包 water.ustc.interceptor,在该包中定义一个 POJO LogInterceptor 作为拦截器,在该类中定义方法preAction()和 afterAction(),分别实现功能为:记录每次客户端请求的 action 名称<name>、访问开始时间<s-time>,访问结束时间<e-time>、请求返回结果<result>,并将信息追加至日志文件 log.xml 保存在 PC 磁盘上。log.xml 格式可参考如下:

定义water.ustc.interceptor包,并定义LogInterceptor为拦截器类,

扫描二维码关注公众号,回复: 5638693 查看本文章

在类中定义preAction()和afterAction()方法,在preAction()方法中打印开始时间,在afterAction中打印结束时间并将action名称,开始时间,结束时间,返回结果写到“log.xml”文件中去,

在SimpleController中的XmlUtil工具类中编写writeToXml方法,并事先在资源resourse目录下创建“log.xml”文件,在writeToXml方法中读取log标签保存为Node,若没有log标签,则创建log标签添加为DOM树中的一个Node,分别创建action、name、start_time、end_time、result标签节点,给name、start_time、end_time、result标签写入值,将这四个标签添加到action标签中,最后使用log标签添加该action标签,最后使用Transformer对象将该DOM树转化为xml文件,

 

3.基于 E2 UseSC 工程的 controller.xml 的中增加<interceptor>节点作为拦截器节点,该节点指明拦截器定义类型及拦截方法。示例如下:

 

修改controller.xml文件添加拦截器如上图所示,

 

4.<action>增加<interceptor-ref>节点作为拦截器引用节点,<interceptor-ref>指向controller.xml 中已定义的<interceptor>节点name属性。

给login action添加拦截器引用结点,

 

5.修改 SimpleController 工程的控制器代码,当 http 请求某个类型 action 时,控制器检查该 action 是否配置了拦截器。如果有配置, action 执行之前,执行拦截器的 predo()方法,并在 action 执行之后执行拦截器的 afterdo()方法。如果没有配置拦截器,则直接访问目标action

在XmlUtil工具类中编写analyzeAction方法,解析controller.xml文件中的每个结点,首先获得所有标签为action的结点list actions,与所有标签为interceptor的结点list interceptors,

在actions中查找actionName结点,若找到保存该结点的所有属性,

并获得该结点的所有孩子结点list childs,

在childs找到标签为interceptor-ref的结点使用其name与interceptors中的拦截器name比较,若找的匹配项,则获得对应拦截器的所有属性,

然后通过action的属性获得action的Class对象与method对象,通过拦截器的属性获得其Class对象、predo方法对象与afterdo方法对象,先使用反射执行拦截器的predo方法,然后使用反射完成对应action方法的执行,最后执行拦截器的afterdo方法,完成模拟拦截器的实现,最后获得action的返回结果,

使用结果result与其所有result子标签的name进行比较,若匹配,则获得result的标签的所有属性并返回去解析,最后跳转到对应jsp页面,

6.将任务 5 中的内容通过 Java 的动态代理机制(JavaInvocationHandlerProxycglib)实现。即每次在访问目标 action 时, 先生成该 action 的代理,在代理中实施拦截功能。

使用动态代理机制实现拦截器,由于动态代理只能代理接口,而我们需要调用的action方法在SimpleController类中只能通过反射完成对UseSC的action方法的调用,因此需要在SimpleController中构建Action反射调用方法的封装,定义Action接口,

定义ActionPackage为Action接口的实现类,同时实现doAction方法,其中完成反射调用UseSC中的action方法的功能,

同时还需要构建动态代理类实现InvocationHandler接口,实现其中invoke方法,在方法中解析xml判断是否给action添加了拦截器,若没有添加则返回原方法,

若添加了,则在原调用方法前后添加拦截器的反射调用UseSC中拦截器方法的封装方法preAction与afterAction,

在preAction与afterAction方法中解析controller.xml文件,获得类地址,方法名,构建Class对象,构建method对象,调用该方法,完成对UseSC中的拦截器方法的调用,

7.自主添加辅助类,以使控制器代码简洁易读。重新打包输出 simple-controller.jar,并测试 UseSC 工程拦截器任务输出结果,直到调试正确。

请求http://localhost:8080/login.sc

返回failure,于是重定向到failure.jsp中,控制台打印输出,

同时在log.xml文件添加action标签,

        

请求http://localhost:8080/register.sc

返回success,控制台打印输出,

同时在log.xml文件中添加action标签,

猜你喜欢

转载自blog.csdn.net/y649014081/article/details/88231484