struts2: 玩转 rest-plugin

2024-06-11 02:58
文章标签 struts2 rest plugin 玩转

本文主要是介绍struts2: 玩转 rest-plugin,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

近期使用struts2的rest-plugin,参考官方示例struts2-rest-showcase,做了一个restful service小项目,但官网提供的这个示例过于简单,埋下了巨坑无数,下面是一些遇到的问题及解决办法:

注:下面这些问题,很多是相互关联的,要解决一个,得同时解决另一个。 

一、与config-browser-plugin、convension-plugin、非rest Action 共存的问题

rest-plugin的气场实在太强,一旦使用,config-browser-plugin、convension-plugin这二个plugin就挂了

解决思路:将所有rest服务,都放在/rest/路径下,用package的namespace把它隔离出来,其它常规的action,放在其它路径,这样二者就不冲突了

复制代码
 1     <!-- Overwrite Convention -->
 2     <constant name="struts.convention.action.suffix" value="Controller" />
 3     <constant name="struts.convention.action.mapAllMatches" value="true" />
 4     <!--<constant name="struts.rest.content.restrictToGET" value="false" />-->
 5     <constant name="struts.convention.default.parent.package" value="rest-default" />
 6     <constant name="struts.convention.package.locators" value="action" />
 7     <!-- <constant name="struts.rest.namespace" value="/rest" /> -->
 8     <constant name="struts.convention.action.includeJars" value=".*?/_wl_cls_gen.*?jar(!/)?" />
 9     <constant name="struts.convention.exclude.parentClassLoader" value="true" />
10     <constant name="struts.convention.action.fileProtocols" value="jar,zip,vfsfile,vfszip" />
11 
12     <constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" />
13     <constant name="struts.mapper.prefixMapping" value="/rest:rest,:struts" />
14     <constant name="struts.mapper.alwaysSelectFullNamespace" value="false" />
15 
16         <package name="default" namespace="/rest" extends="rest-default" />
复制代码

 

二、拦截器及ModelDrive的问题

如果自定义拦截器(比如:自定义异常拦截器),默认情况下是无法拦截rest的Action

解决办法:

a) strut2.xml中定义二个package:rest-package、page-package,并在这二个package中,加上自己的拦截器,完整strut2.xml参考下面的内容:

View Code

b) 所有rest Action继承自一个自定义基类,所有常规page的Action,继承自另一个自定义基类

这二个基类用@ParentPackage 指定package,分别对应struts2.xml中的配置,这样运行时,不管是rest action,还是非rest action,都能被拦截器拦截

View Code
View Code

另外:官方的示例为了简便,在setId方法里,直接给Model赋值了,但这有点误导,因为拦截器拦截到的方法,并不是setId(),而是show()/index()之类的方法,所以应该在show方法里,调用 model = xxx.getModel(id),否则按原来的写法,如果getModel这里报错 -> setId()报错,但show()方法并没有出错,拦截器会认为没有异常发生。

View Code

 

三、返回XML节点的别名(alias)问题

默认情况下,返回的xml根节点为dto对应的完整package名,看上去很别扭

解决方法:

dto的class上,用@XStreamAlias指定别名

View Code

然后再创建自己的XmlHandler,为了节省系统开销,下面的代码用了一个单例:

View Code
View Code

注:别名一定要在toObject方法里,明确指定,否则别名的注解不起作用。

最后在struts2.xml里,还要注册bean,参考前面完整的xml内容。

 

四、返回JSON的Date属性格式化的问题

默认情况下,如果model有日期型属性,返回的json格式十分长,看上去太臃肿,类似的,可以自己定义ContentTypeHandler来解决

View Code
View Code

 

五、restful service 该返回哪种视图,xhtml? json? xml?

通常用rest-plugin,是为了开发rest-service,但是官网的示例返回的默认都是页面视图,这个显然不适合,最理想情况是,如果在页面上操作,操作完以后,应该返回页面视图(即: xxx.xhtml),如果是用xml参数进来的,应该返回xml视图(即: xxx.xml),如果是ajax用json post过来的,应该返回到json视图(即:xxx.json)

解决办法:根据Request的Header来判断来源,然后做相应的分支处理

View Code

 

六、json post到service,model取不到值的问题

这个问题最恶心,连官方默认提供的org.apache.struts2.rest.handler.JsonLibHandler都有问题,原因在json反序列化的机制,大家可以感受下这段代码:

View Code

输出结果:

id:null,clientName:null,amount:0,createTime:Wed Oct 22 15:05:12 CST 2014

29791
----
id:3,clientName:Bob,amount:33,createTime:Wed Oct 22 11:04:48 CST 2014
2137470
----

id:null,clientName:null,amount:0,createTime:Wed Oct 22 15:05:12 CST 2014
29791

虽然传递的参数是Object,因java只有值传递,这里传递的值即为对象的“指针地址值”,但是json内部反序列化时,入口并非这个指针值,而是xxx.getClass(),即类型指针,导致最后toObject执行完,原来的指针是啥还是啥,跟反序列过程中"新创建"出来的新Object instance,完全豪无关联。因此,不得不改造成

View Code

手动把新对象的属性,复制到target对象上,这样就保证了反序列后的结果,在toObject执行完以后,会反映到target上。

注:可能有朋友会问了,为什么只有json会这样,xml不会呢?再仔细看下XStreamHandler的toObject方法

View Code

最后一行xstream.fromXML(in, target);这是开始xml->object的入口,这里传递的就是target的地址对应的值,而不是象json那样是xxx.getClass()。如果进一步看源码,最后会发现执行的是com.thoughtworks.xstream.core.TreeUnmarshaller类里的

View Code

整个过程,都没有新对象实例创建,所以相应的变化,能一直保持到toObject调用完成后。

 

七、id参数太单一的问题

这个其实并不是大太的问题,GET方式下,url里本来就不适合传递过多参数,实在想用多个参数,做个约定,比如  /orders/show/a-b-c,即id值为"a-b-c",然后拆解一下,a,b,c对应不同的含义即可

POST方式,更不成问题,直接post过来一段xml或json,最终映射成model,想要多少参数都不是问题

 

最后给出源码示例:struts-rest-ex-src.zip (基于官网的rest-showcase修改而来)

这篇关于struts2: 玩转 rest-plugin的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1050023

相关文章

Struts2与struts1与springmvc比较

最近做项目用到了struts2,之前一直是用struts1和springMVC。感觉到了struts2从很大程度上和这两个还是有很大区别的,所以今天搜集了些资料,给他们做一下对比。            Struts1官方已经停止更新,现在用的也比较少,这里主要讲一下struts2和struts1比较都有哪些不同和进步。Struts2可以说不是完全从struts1改进来的,因为

spring-boot-maven-plugin多模块install问题

一、问题描述:   项目分多个模块,open-eureka注册中心、open-provider服务提供者、open-common公共部分,provider依赖common。父pom使用spring-boot-maver-plugin插件,项目直接运行Main主类没问题,但是install报common中的类找不到符号. 二、查找问题:   spring-boot-maven-plugin 打

Android IDE Plugin ViewInject

前言 目前为止,Android使用的插件的已经很多了,但是自己在这块确实空白的,之前写过了ViewInject博客了,在优化findViewById之后,考虑到不需要手写问题的情况下,采用插件辅助来开发,网上目前已经有了ButterKnife的辅助的插件,为自己开发ViewInject插件,个人建议不要光看我写的一部分我用到的方法,需要你自己看IDE Plugin API刚好这段时间有空闲时间。

gradle plugin baseExtension getCompileSdkVersion为null问题

自定义了一个gradle插件,在里面用如下代码获取compileSdkVersion val plugin = project.plugins.getPlugin(AppPlugin::class.java)val sdkDirectory = plugin.baseExtension.sdkDirectoryprintln("androidExtension compileSdkVersion

玩转Web之servlet(三)---一张图看懂B/S架构

学WEB, 首先 要明白B/S架构,本文将简单说一下小编的愚见,若有不当,欢迎大家指正。 首先,什么是B/S架构?B/S是Broweser/Server的缩写,即浏览器/服务器模式,简单说就是客户端使用浏览器,服务端使用Web服务器,客户端与服务端之间使用http协议进行通讯。 那么,为什么要使用B/S架构呢?当然是其有一定的优点:           1.传统的C/S架构 需要单独安装客户

玩转Web之Json(四)---json与(Object/List/Map)的相互转化

在做web应用时,经常需要将json转化成Object/list/map或者将Object/List/map转化成json,通过简单封装可以在写代码是减轻很多负担。本文将给出json转化的一系列方法。 闲话不 多说,直接上代码: 先是Object /List /Map转化为Json /* 功能 :将一个对象转成json数组* 参数 :object对象* retu

玩转Web之Json(三)-----easy ui怎么把前台显示的dataGird中的所有数据序列化为json,返回到后台并解析

最近做一个项目时,需要在dataGird中插入<input>,即文本输入框,当点击提交时,需要把文本框里填的数据返以及其他列的一些信息以json数组的格式返回到后台,虽然我实现了该功能,但一直没找到简便的方法,今天终于在一位版主的点拨下找到了非常简单的方法。   var all = $("#dg").datagrid("getData");var json =JSON.

玩转Web之easyui(三)-----easy ui dataGird 重新指定url以获取不同数据源信息

如果已经写了一个dataGird并且已经通过url绑定数据源,能不能在其他地方改变url使其从不同数据源获取信息,从而实现查询等操作?答案当然是肯定的,而且仅需要几行代码 $('#btnq').bind('click', function(){ $('#dg').datagrid({ url: '../servlet/Student_search' });//重新指定url$('#dg'

玩转Web之easyui(二)-----easy ui 异步加载生成树节点(Tree),点击树生成tab(选项卡)

关于easy ui 异步加载生成树及点击树生成选项卡,这里直接给出代码,重点部分代码中均有注释 前台: $('#tree').tree({ url: '../servlet/School_Tree?id=-1', //向后台传送id,获取根节点lines:true,onBeforeExpand:function(node,param){ $('#tree').tree('options'

玩转Web之easyui(一)-----easy ui datagird 分页

无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。   easy ui 中数据表格的分页其实是很简单的,分页是在数据表格可以正常显示数据的基础上进行的,在这里给出servlet的代码,其中selectAll()方法是从数据库中提取所有数据, 分页的一种思路是:从数据表中取出所