如何在java REST API中用GZip和Jersey压缩相应

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在java REST API中用GZip和Jersey压缩相应相关的知识,希望对你有一定的参考价值。

有许多情景当你的RESTapi提供的相应是非常长的,并且都知道传递速度和贷款在移动设备/网络上是多重要。当开发支持RESTapis的移动app的时候,首要的性能最优化的点就是需要解决。猜猜是什么?因为响应式文本,因此能压缩这些文本。而且随着当前的只能手机和平板的能力,在客户端解压文本应该不是个大问题因此在这篇文章中,如果你使用java的Jersey构建它,将介绍你怎么能有选择性的压缩RESTAPI响应,这个Jersey事JAX-RS的映射实现(还有)  1.Jersey过滤器和拦截器  啊,感谢Jersey的强大的过滤器和拦截器特性,这个实现是相当容易的。然后过滤器是主要打算来维护像HTTPheaders,URIs和/或HTTPmethods的request和response的参数,拦截器是维护实体,通过维护实体的输入/输出流。  但是对于压缩将使用一个GZipWriterInterceptor,一个写拦截器被用于这种情况,在那个类里,实体被写到"wire",当在这种情况中时,它在服务器这边,这就意味着输出一个响应实体。  1.1GZipWriterInterceptor  那来看看GZipWriterInterceptor吧:  GZipWriterInterceptor  packageorg.codingpedia.demo.rest.interceptors;  importjava.io.IOException;  importjava.io.OutputStream;  importjava.util.zip.GZIPOutputStream;  importjavax.ws.rs.WebApplicationException;  importjavax.ws.rs.core.MultivaluedMap;  importjavax.ws.rs.ext.WriterInterceptor;  importjavax.ws.rs.ext.WriterInterceptorContext;  @Provider  @Compress  publicclassGZIPWriterInterceptorimplementsWriterInterceptor  @Override  publicvoidaroundWriteTo(WriterInterceptorContextcontext)  throwsIOException,WebApplicationException  MultivaluedMapheaders=context.getHeaders();  headers.add("Content-Encoding","gzip");  finalOutputStreamoutputStream=context.getOutputStream();  context.setOutputStream(newGZIPOutputStream(outputStream));  context.proceed();      注意:  它实现了WriterInterceptor,这是一个写拦截器的消息体的接口,这个接口包装调用javax.ws.rs.ext.MessageBodyWriter.writeTo  供应商实现WriterInterceptor协议必须要么以编程方式注册进一个JAX-RS运行环境,要么必须用@Provider注解来注解在一个提供商扫描语句期间自动的被JAX-RS运行环境发现。  @Compress是绑定注解的名称,在接下来的段落中将更详细的讨论它  “拦截器从WriterInterceptorContext中获得一个输出流并且设置一个新的用原始的GZIP包装器包装的输出流。在所有的拦截器被执行以后,输出流最终设置WriterInterceptorContext将用于序列化实体。在上面的例子中,实体字节将被写到GZIPOutputStream中,这个类将压缩流数据,然后把他们写到原始输出流。原始流总是把数据写到wire中。当拦截器被用在服务器上时,原始输出流会把数据写到底层服务器容器的流中,然后发送响应给客户端。”  “重载方法aroundWriteTo()获取WriterInterceptorContextz作为参数。这个上下文包括请求头参数getters和setters,请求属性,实体,实体流和其它属性;当你压缩你的响应时,你应当设置\'Content-Encoding\'头位gzip”  1.2压缩注解  过滤器和拦截器能被绑定名字。名称绑定是一种概念,这种概念就是允许告诉一个JAX-RS的运行时,一个只为特定资源方法的特定的过滤器或者拦截器将被执行。当一个过滤器或者拦截器只对一些特定的资源方法限制,那我们就认为它是名称绑定。过滤器和拦截器没有这样的限制就被称作global。在我们的例子中我们已经构建了@Compress注解:  Compressannotation  packageorg.codingpedia.demo.rest.interceptors;  importjava.lang.annotation.Retention;  importjava.lang.annotation.RetentionPolicy;  importjavax.ws.rs.NameBinding;  //@Compressannotationisthenamebindingannotation  @NameBinding  @Retention(RetentionPolicy.RUNTIME)  public@interfaceCompress  而且用它来标记在资源上的方法,这个方法应该是被压缩的(eg:当GET-ing的时候,所有的博客用PodcastsResource)  @Compressannotation在资源方法上的使用  @Component  @Path("/podcasts")  publicclassPodcastsResource  @Autowired  privatePodcastServicepodcastService; 参考技术A 有许多情景当你的REST api提供的相应是非常长的

如何在java中进行rest api调用并映射响应对象?

【中文标题】如何在java中进行rest api调用并映射响应对象?【英文标题】:How to make a rest api call in java and map the response object? 【发布时间】:2018-11-25 08:14:56 【问题描述】:

我目前正在开发我的第一个 java 程序,它将调用一个 rest api(jira rest api,更具体一点)。

所以,如果我进入浏览器并输入 url = "http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog"

我得到一个包含当前用户所有工作日志的响应(json)。 但我的问题是,我的 java 程序如何做到这一点? 比如,连接到这个 url,获取响应并将其存储在一个对象中?

我使用弹簧,有人知道如何使用它。 提前谢谢各位。

我补充一下,我的代码在这里:

RestTemplate restTemplate = new RestTemplate();
String url;
url = http://my-jira-domain/rest/api/latest/search/jql=assignee=currentuser()&fields=worklog
jiraResponse = restTemplate.getForObject(url,JiraWorklogResponse.class);

JiraWorkLogResponse 是一个简单的类,只有一些属性。

编辑, 我的整个班级:

@Controller
@RequestMapping("/jira/worklogs")
public class JiraWorkLog 

    private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );
@RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")

    public ResponseEntity getWorkLog() 


    RestTemplate restTemplate = new RestTemplate();
    String url;
    JiraProperties jiraProperties = null;


    url = "http://my-jira-domain/rest/api/latest/search?jql=assignee=currentuser()&fields=worklog";

    ResponseEntity<JiraWorklogResponse> jiraResponse;
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders = this.createHeaders();


    try 
        jiraResponse = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),JiraWorklogResponse.class);



    catch (Exception e)
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
    

    return ResponseEntity.status(HttpStatus.OK).body(jiraResponse);




private HttpHeaders createHeaders()
    HttpHeaders headers = new HttpHeaders()
        
            set("Authorization", "Basic something");
        
    ;
    return headers;

此代码正在返回: org.springframework.http.converter.HttpMessageNotWritableException

有人知道为什么吗?

【问题讨论】:

【参考方案1】:

您所需要的只是 http 客户端。例如,它可能是 RestTemplate(与 spring、easy 客户端相关)或更高级且对我 Retrofit(或您最喜欢的客户端)更具可读性。

使用此客户端,您可以执行这样的请求来获取 JSON:

 RestTemplate coolRestTemplate = new RestTemplate();
 String url = "http://host/user/";
 ResponseEntity<String> response
 = restTemplate.getForEntity(userResourceUrl + "/userId", String.class);

在 Java 中映射 beetwen JSON 和对象/集合的一般推荐方法是 Jackson/Gson 库。相反,他们可以快速检查您是否可以:

    定义 POJO 对象:

    public class User implements Serializable 
    private String name;
    private String surname;
    // standard getters and setters
    
    

    使用 RestTemplate 的 getForObject() 方法。

    User user = restTemplate.getForObject(userResourceUrl + "/userId", User.class);
    

要获得有关使用 RestTemplate 和 Jackson 的基本知识,我向您推荐来自 baeldung 的非常棒的文章:

http://www.baeldung.com/rest-template

http://www.baeldung.com/jackson-object-mapper-tutorial

【讨论】:

好的。但是您知道我如何使用 java 通过 http 标头传递我的凭据吗?因为可能其余的 api 会有一些身份验证。 在身份验证的情况下更容易使用 RestTemplate.exchange 方法。只需检查第一个答案:***.com/questions/15462128/… 是的,现在越来越清楚了。在你的帮助下,我现在可以制作标题了,但是我收到了这个错误:“org.springframework.http.converter.HttpMessageNotWritableException”我要发布我的代码到目前为止 Estudeiro 看起来映射 beetwen http 响应存在问题,并且您对 JiraWorklogResponse 进行了分类。要验证它,您应该检查来自 Jira 的响应是否有可能映射到此类(这只是一个问题)。如果问题仍然存在,您应该提供异常的完整堆栈跟踪。【参考方案2】:

由于您使用的是Spring,您可以查看RestTemplatespring-web 项目。

使用RestTemplate 的简单休息调用可以是:

RestTemplate restTemplate = new RestTemplate();
String fooResourceUrl = "http://localhost:8080/spring-rest/foos";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));

【讨论】:

我正在使用这样的东西,我会在这里发布我的代码。你能解释一下为什么我们使用 (fooResourceUrl + "/1") 吗? “/1”是干什么用的?【参考方案3】:

问题可能是由于序列化。定义一个适当的模型,其中包含响应的字段。这应该可以解决您的问题。

对于新手来说可能不是更好的选择,但我觉得 spring-cloud-feign 帮助我保持代码整洁。

基本上,您将拥有一个用于调用 JIRA api 的接口。

@FeignClient("http://my-jira-domain/")
public interface JiraClient   
    @RequestMapping(value = "rest/api/latest/search?jql=assignee=currentuser()&fields=", method = GET)
    JiraWorklogResponse search();

在你的控制器中,你只需要注入 JiraClient 并调用方法

jiraClient.search();

它还提供了传递headers 的简便方法。

【讨论】:

【参考方案4】:

我回来了,并且有一个解决方案(:

@Controller
@RequestMapping("/jira/worklogs")
public class JiraWorkLog 

    private static final Logger logger = Logger.getLogger(JiraWorkLog.class.getName() );

    @RequestMapping(path = "/get", method = RequestMethod.GET, produces = "application/json")
    public ResponseEntity<JiraWorklogIssue> getWorkLog(@RequestParam(name = "username") String username) 


        String theUrl = "http://my-jira-domain/rest/api/latest/search?jql=assignee="+username+"&fields=worklog";
        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<JiraWorklogIssue> response = null;
        try 
            HttpHeaders headers = createHttpHeaders();
            HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
            response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);
            System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
        
        catch (Exception eek) 
            System.out.println("** Exception: "+ eek.getMessage());
        

        return response;

    

    private HttpHeaders createHttpHeaders()
    
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add("Authorization", "Basic encoded64 username:password");
        return headers;
    


上面的代码有效,但是有人可以向我解释这两行吗?

HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
                response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, JiraWorklogIssue.class);

而且,这是一个很好的代码? 谢谢(:

【讨论】:

以上是关于如何在java REST API中用GZip和Jersey压缩相应的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JAVA 中将 JSON 和文件传递给 REST API?

使用 HttpClient、REST 和 gzip 读取 JSON

如何在java中进行rest api调用并映射响应对象?

如何使用 REST API 和数据库扩展 Java 应用程序?

如何在 java 中使用 REST API 身份验证? [关闭]

如何在 JAVA 的 rest API 中将图像返回给浏览器?