RestEasy与Jsonp(ajax跨域)

1. ajax跨域的是利用了动态加载js文件没有跨域限制的特性。

2. 服务端返回jsonp格式的文本:xx({weather:"晴天",temp:"30C",:wind:"东南风"});

    这本质上是一个函数调用语句,实参为json对象,函数名为xx。

3. 客户端:利用jquery插件:jquery.jsonp-2.4.0.js

   代码:  

<script type="text/javascript">

  function xx(data)
  {
   alert(data);
   if(data)
             {
              var weatherStr = "今日天气:&nbsp;&nbsp;";
              weatherStr +=  data.weather + "&nbsp;&nbsp;";
              weatherStr +=  data.temp + "&nbsp;&nbsp;";
              weatherStr +=  data.wind + "<br/>";
     alert(weatherStr);
                 document.getElementById("weather_zone").innerHTML = weatherStr;
    }
  }


  function getCurrentDayWeather()
  {
   var currentDayWeatherUrl = "http://localhost:9090/httpapi/service/weather/detail/101190501.json?callback=xx";

   $.jsonp({url: 'http://localhost:9090/httpapi/service/weather/detail/101190501.json?callback=xx'});
    
  }
  
  </script>

 

4. 服务端RestEasy的使用:

@Component("weatherService")
@Transactional
@Path("weather")
public class WeatherService
{
    @Autowired
    private WeatherDao weatherDao = null;
    
    public Weather queryById(String id)
    {
        Weather weather = weatherDao.get(id);
       
        return weather;
    }
   
    @GET
    @Path("/detail/{cityCode}.json")
    @Produces("application/json")
    public Weather getCurrentDayWeather(@PathParam("cityCode") String cityCode)
    {
        Weather weather = weatherDao.get(DateTimeUtil.getCurrentDay() + "_"
                + cityCode);
       
        if (null == weather || StringUtils.isEmpty(weather.getWeather()))
        {
            Weather emptyWeather = new Weather();
            emptyWeather.setWeatherId(DateTimeUtil.getCurrentDay() + "_"
                    + cityCode);
            emptyWeather.setWeather("暂无实况");
            emptyWeather.setTemp("暂无实况");
            emptyWeather.setWind("暂无实况");
           
            return emptyWeather;
        }
       
        return weather;
    }

    这个Rest接口只能返回 json,不能返回jsonp。

     RestEasy官方文档的21.2小结有几句话,基本是一句带过:

     http://docs.jboss.org/resteasy/docs/3.0-beta-3/userguide/html_single/index.html

      

21.2. JSONP Support

If you're use Jackson JSONP is supported right away. If the media type of the response is json and a callback query parameter is given, the response will be a javascript snippet with a method call of the method defined by the callback parameter. For example:

GET /resources/stuff?callback=processStuffResponse

will produce this response:

processStuffResponse(<nomal JSON body>)

This supports the default behavior of jQuery.

You can change the name of the callback parameter by setting the callbackQueryParameter property.

 

我用了Jackson ,可是总返回不了jsonp,老是返回json。

后来google到了老外的帖子(http://stackoverflow.com/questions/5350924/how-enable-jsonp-in-resteasy),

发现可能是我的RestEasy版本低的问题,我的是2.3.3,说高版本的支持的,我懒得换高版本,于是把那个帖子中老外DIY的代码拿来用了:

思路是自己建个Filter,Wrap HttpServletRequest和HttpSerletResponse,自己把返回的json转成jsonp。

代码如下:

I make draft workaround for this problem. Try it. This solution takes data via http get parameters and translate to virtual POST request.

JQuery:

function call(){
var val ='{"routes":[{"arrivalAddress":{"fullAddress":"DME"},"destinationAddress":{"fullAddress":"SVO"}}],"carsCount":"1"}';
var jHandler ="doMap";
$.getJSON("http://xxx:yyy/app-0.0.0.1/rest/requestPrice?callback="+ jHandler +"&json="+ encodeURIComponent(val)+"&jsoncallback=?",null,null,"json");}

function doMap(obj){
alert(obj);}

Declaration in Service interface

@POST
@Path("requestPrice")
@Produces("application/json")
@Consumes
("application/json")
PriceResponse requestPrice(PriceRequest request)throwsServiceException;

Filter class:

import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;import java.io.*;import java.util.Enumeration;import java.util.HashMap;import java.util.Iterator;import java.util.Map;publicclassJSONPRequestFilterimplementsFilter{privateString callbackParameter;publicvoid doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsIOException,ServletException{if(!(request instanceofHttpServletRequest)){thrownewServletException("This filter can "+" only process HttpServletRequest requests");}finalHttpServletRequest httpRequest =(HttpServletRequest) request;finalHttpServletResponse httpResponse =(HttpServletResponse) response;if(isJSONPRequest(httpRequest)){RequestWrapper requestWrapper =newRequestWrapper(httpRequest);
            requestWrapper.setContentType("application/json; charset=UTF-8");
            requestWrapper.setHeader("cache-control","no-cache");
            requestWrapper.setHeader("accept","application/json");
            requestWrapper.setCharacterEncoding("UTF-8");
            requestWrapper.setBody(httpRequest.getParameter("json"));finalByteArrayOutputStream baos =newByteArrayOutputStream();HttpServletResponseWrapper responseWrapper =newHttpServletResponseWrapper(httpResponse){@OverridepublicServletOutputStream getOutputStream()throwsIOException{returnnewServletOutputStream(){@Overridepublicvoid write(int b)throwsIOException{
                            baos.write(b);}};}@OverridepublicPrintWriter getWriter()throwsIOException{returnnewPrintWriter(baos);}publicString getData(){return baos.toString();}};

            chain.doFilter(requestWrapper, responseWrapper);
            response.getOutputStream().write((getCallbackParameter(httpRequest)+"(").getBytes());
            response.getOutputStream().write(baos.toByteArray());
            response.getOutputStream().write(");".getBytes());

            response.setContentType("text/javascript");}else{
            chain.doFilter(request, response);}}privateString getCallbackMethod(HttpServletRequest httpRequest){return httpRequest.getParameter(callbackParameter);}privateboolean isJSONPRequest(HttpServletRequest httpRequest){String callbackMethod = getCallbackMethod(httpRequest);return(callbackMethod !=null&& callbackMethod.length()>0);}privateString getCallbackParameter(HttpServletRequest request){return request.getParameter(callbackParameter);}publicvoid init(FilterConfig filterConfig)throwsServletException{
        callbackParameter = filterConfig.getInitParameter("callbackParameter");}publicvoid destroy(){}void printRequest(HttpServletRequest request)throwsIOException{{System.out.println("--------------Headers---------------");Enumeration en = request.getHeaderNames();while(en.hasMoreElements()){String val = en.nextElement().toString();System.out.println(val +" :");Enumeration en1 = request.getHeaders(val);while(en1.hasMoreElements()){System.out.println("\t"+ en1.nextElement());}}}{System.out.println("------------Parameters--------------");Enumeration en = request.getParameterNames();while(en.hasMoreElements()){String val = en.nextElement().toString();System.out.println(val +" :");String[] en1 = request.getParameterValues(val);for(String val1 : en1){System.out.println("\t"+ val1);}}}System.out.println("---------------BODY--------------");BufferedReader is = request.getReader();String line;while((line = is.readLine())!=null){System.out.println(line);}System.out.println("---------------------------------");System.out.println("ContentType: "+ request.getContentType());System.out.println("ContentLength: "+ request.getContentLength());System.out.println("characterEncodings: "+ request.getCharacterEncoding());System.out.println("AuthType: "+ request.getAuthType());System.out.println("ContextPath: "+ request.getContextPath());System.out.println("Method: "+ request.getMethod());}publicstaticclassRequestWrapperextendsHttpServletRequestWrapper{Map<String,String> headers =newHashMap<String,String>();int contentLength;BufferedReader reader;publicRequestWrapper(HttpServletRequest request){super(request);}publicvoid setHeader(String key,String value){
            headers.put(key, value);}ByteArrayInputStream bais;publicvoid setBody(String body){
            bais =newByteArrayInputStream(body.getBytes());
            contentLength = body.length();
            headers.put("content-length",Integer.toString(contentLength));}@OverridepublicBufferedReader getReader()throwsIOException{
            reader =newBufferedReader(newInputStreamReader(bais));return reader;}@OverridepublicServletInputStream getInputStream()throwsIOException{returnnewServletInputStream(){@Overridepublicint read()throwsIOException{return bais.read();}};}@OverridepublicString getMethod(){return"POST";}privateString contentType;publicvoid setContentType(String contentType){this.contentType = contentType;
            headers.put("content-type", contentType);}@OverridepublicString getContentType(){return contentType;}@Overridepublicint getContentLength(){return contentLength;}@OverridepublicString getHeader(String name){String val = headers.get(name);if(val !=null){return val;}returnsuper.getHeader(name);//To change body of overridden methods use File | Settings | File Templates.}@OverridepublicEnumeration getHeaders(finalString name){returnsuper.getHeaders(name);}@OverridepublicEnumeration getHeaderNames(){finalEnumeration en1 =super.getHeaderNames();finalIterator it = headers.keySet().iterator();returnnewEnumeration(){publicboolean hasMoreElements(){return en1.hasMoreElements()|| it.hasNext();}publicObject nextElement(){return en1.hasMoreElements()? en1.nextElement():(it.hasNext()? it.next():null);}};}@Overridepublicint getIntHeader(String name){String val = headers.get(name);if(val ==null){returnsuper.getIntHeader(name);}else{returnInteger.parseInt(val);}}}}

web.xml

<filter>
<filter-name>JSONPRequestFilter</filter-name>
<filter-class>xxxxx.JSONPRequestFilter</filter-class>
<init-param>
<param-name>callbackParameter</param-name>
<param-value>callback</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>JSONPRequestFilter</filter-name>
<url-pattern>/rest/*</url-pattern> </filter-mapping>
share|improve this answer
 
   

An enhancement to support JSONP is scheduled to be released in RESTEasy 2.3.6 Final/3.0-beta-4 (https://issues.jboss.org/browse/RESTEASY-342). I was able to "backport" it my project which uses RESTEasy 2.3.5 by simply copying their code from GitHub.

RESTEasy automatically picks up the new provider based on the annotation. It works automatically by wrapping your results in a js callback once it sees a query parameter named "callback" in the url. This is compatible with what JQuery sends to the server for JSONP requests.

 

posted @ 2013-06-14 11:14  TianChangjun  阅读(1673)  评论(1编辑  收藏  举报