`
rustlingwind
  • 浏览: 20877 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

挥之不去的噩梦,struts2 rest 的通病

阅读更多
话说前天碰到的问题,已经被一个好心的eye友给轻松解决了。真的非常感谢。
但今天又碰到一个问题。
而且跟前天碰到的其实应该是一类问题。

前天问题的解决方法,其实是换了一种途径。但我当时想用的方法为什么不行,我还是不清楚。
@Action(interceptorRefs={@InterceptorRef("authorization"), @InterceptorRef("restDefaultStack")})
    public String update() {
        ordersService.save(model);
        addActionMessage("Order updated successfully");
        return "success";
    }

就是说,拦截器不能直接加在 method level 上面,而只能加在 Action.class级别。
问题的原因不清楚,但我想或许与没有指定 @Action(value="xxx")的value值有关!

如果只是使用struts2 的 convention 插件,当然可以指定value,但是rest方式下,标准的那7个方法如何指定别名呢?即便能够指定,也很奇怪!

为何说今天遇到的问题类似。因为我在完善action的返回值的处理的时候,发现Result竟然也无法加在method level上,而只能是 action.class上,与拦截器的问题一样。

代码如下:

  @Action(
        results={@Result(name="exception", type="httpheader", params={"status", "503", "errorMessage", "Internal Error"})}
    )
    public HttpHeaders show() {
        int i = 1/0;
        return new DefaultHttpHeaders("show").disableCaching();
    }
   
    @Action(results={@Result(name="exception", type="httpheader", params={"status", "504", "errorMessage", "Internal Error"})})
    public HttpHeaders index() {
        int i = 1/0;
        list = ordersService.getAll();
        return new DefaultHttpHeaders("index").disableCaching();
    }

与官方文档对照再三,唯一的区别就是我没有指定 @Action 的 value 属性。
给上面这段代码的 @Action 加上 value 属性,果然不出所料。

本来下面的url可以访问某个order:
/orders/3.xml
如果添加了value,就只能写成:
/orders/show/3.xml   --> @Action(value="/orders/show/")

这还叫rest么?

不明白,难道 struts2 rest plugin 就没办法指定 method level 的 Result 么?还有拦截器,也有这个问题。其实还有异常声明,也是。@ExceptionMapping也没法直接加在method level上,官方文档说行,那也是 Convention plugin ,换成rest,都不行了。

难道一点辙都没了?那我的程序该咋办啊,异常处理/返回结果值处理 都没法弄了。。。
狂晕中,老板让俺今天把这块儿东西做完,可是这个问题就像钉在那里一样,一点都无计可施。。。我的希望全寄托在mht19840918老兄身上了,盼大师能给在下指点一下迷津!
1
1
分享到:
评论
8 楼 rustlingwind 2010-03-02  
mht19840918 写道
刚看了下源码,说说现在最笨的办法,这个只对比较简单的返回,rest插件也就是拦截url的后缀(.以后的),也就是.json/.xml/.xhtml默认xhtml,你也在拦截器中而外识别下访问的后缀,
预备三套返回模板,如:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchKey</Code>
  <Message>The resource you requested does not exist</Message>
  <Resource>/mybucket/myfoto.jpg</Resource>
  <RequestId>4442587FB7D0A2F9</RequestId>
</Error>
or
json
or
xhtml
然后Response的writer出去,比较复杂的返回建议改源码


OK,终于盼到您的回复了!呵呵!我今天晚上就试试!下午把其他的写完。谢谢哈~
7 楼 mht19840918 2010-03-02  
刚看了下源码,说说现在最笨的办法,这个只对比较简单的返回,rest插件也就是拦截url的后缀(.以后的),也就是.json/.xml/.xhtml默认xhtml,你也在拦截器中而外识别下访问的后缀,
预备三套返回模板,如:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchKey</Code>
  <Message>The resource you requested does not exist</Message>
  <Resource>/mybucket/myfoto.jpg</Resource>
  <RequestId>4442587FB7D0A2F9</RequestId>
</Error>
or
json
or
xhtml
然后Response的writer出去,比较复杂的返回建议改源码
6 楼 mht19840918 2010-03-02  
这个恐怕要看下源代码了,我最近项目赶的紧,实在帮不上你
5 楼 rustlingwind 2010-02-27  
mht19840918 写道
可以再异常拦截器中,设置response头信息以及响应状态碼,需要注意的是Struts2本身的设计不是一个完全rest的框架,他之所以这样宣称也仅仅是一个嚼头罢了


mht19840918 您好!
俺真是遇到好人了啊,呵呵,多谢你每次都这么耐心帮我答复!
我想可能我需要先把我的需求说清楚一些:
我现在做的rest服务,主要用于客户端形式的网游,其业务数据都由我的rest服务提供。
所以我必须返回xml形式的数据,而不是网页。当然因为rest支持内容协商,strut2 rest plugin也对内容协商这一特性做了较好的支持,可以根据请求后缀的不同返回xml、json或xhtml,这样我觉得假如以后会将一些数据展示在web上,后台服务的重用性就有了保证。

正是出于这一目的,我在做返回值、异常错误等处理的时候,首先希望能够做到用户请求何种类型(xml,json,xhtml),如果有错误,就返回何种类型的表示。
比如xml类型的请求,如果出错,就返回一段xml出错文本,类似:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>NoSuchKey</Code>
  <Message>The resource you requested does not exist</Message>
  <Resource>/mybucket/myfoto.jpg</Resource>
  <RequestId>4442587FB7D0A2F9</RequestId>
</Error>
并附带http错误状态码,比如500。

还有,我还希望,这种处理能够由struts2 rest 框架自动完成。而通过我的试验,我发现这方面框架本身已经做了一定的支持,但支持的程度并不清楚。
比如,在action的validate()中,如果有fielderror,也就是如果返回“input”,并且如果用户请求的是xml类型,struts2 rest 能够自动返回一段xml,这个我试过,是没有问题的。

所以,我就是希望达到这个目的,当出错的时候,能够返回一段xml表示错误信息以及一个错误状态码。成功的时候也一样,一段xml和一个状态码。

如果struts2 rest 框架不能满足这个基本的需求,而需要自定义拦截器去完成的话。那么我有个问题就是,在异常处理的拦截器中,是如何做到内容协商的呢?

我看到你提供的例子:ExceptionInterceptor 中,通过:
if (request.getParameter("ajax") != null)
来判断是否是ajax类型的请求,如果是,则返回json数据类型的错误提示。可是我的应用中,没有提供也不想提供给用户一个标识:ajax,xml,而是想通过访问的后缀:
.xml ,.json, .xhtml 来自动判断。这在自定义拦截器中可以实现么?

//////////

另外,还有一个跟本贴主题无关的几个问题:

new DefaultHttpheaders("xxx"),这里的"xxx"是什么意思,是不是等同于 传统的 result字符串,比如"success","input"?








4 楼 mht19840918 2010-02-27  
可以再异常拦截器中,设置response头信息以及响应状态碼,需要注意的是Struts2本身的设计不是一个完全rest的框架,他之所以这样宣称也仅仅是一个嚼头罢了
3 楼 mht19840918 2010-02-27  
action级别的@Restlt映射:以@Actions组合多个@Action后修饰Action 类,如你的配置。
method级别的result映射:将多个@Result组成数组后作为@Action的Result属性值。

个人的意见如果仅仅是异常的处理,加个异常拦截器就可以。在异常拦截器中指定错误页面就可以。

package com.fost.card.webcommon;

import com.fost.card.CardCustomException;
import com.fost.card.CardRunException;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import net.sf.json.JSONObject;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* 自定义异常处理拦截器
*
* @author MHT
*
*/
public class ExceptionInterceptor extends AbstractInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionInterceptor.class);
    private static final long serialVersionUID = 1L;

    @Override
    public String intercept(ActionInvocation invocation) {

        @SuppressWarnings("all")
        HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().getContext().get(
                ServletActionContext.HTTP_RESPONSE);
        @SuppressWarnings("all")
        HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().getContext().get(
                ServletActionContext.HTTP_REQUEST);
        String result = "";
        String op = "";
        Exception excep = null;
        try {
            result = invocation.invoke();
        } catch (CardCustomException e) {
            excep = e;
            result = "error";
            op = e.getMessage();
        } catch (CardRunException ex) {
            excep = ex;
            result = "error";
            op = "对不起, 系统发生错误,请稍后再试";
            LOGGER.error("CardRunException", excep);
        } catch (Exception exx) {
            excep = exx;
            result = "error";
            op = "对不起, 系统发生错误,请稍后再试";
            LOGGER.error("Exception", excep);
        }
        if (excep != null) {
            if (request.getParameter("ajax") != null) {
                response.reset();
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json");
                JSONObject jo = new JSONObject();
                jo.put("op", op);
                try {
                    response.getWriter().print(jo.toString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
            request.setAttribute("javax.servlet.error.exception", excep);

        }
        return result;
    }

}

result就是你想要指向的异常页面。你甚至可以有多个异常页面。

2 楼 rustlingwind 2010-02-26  
mht19840918 写道
小意思,晚上回去帮你看

谢谢谢谢!全拜托您了!
1 楼 mht19840918 2010-02-26  
小意思,晚上回去帮你看

相关推荐

Global site tag (gtag.js) - Google Analytics