Jersey

前提要求

  1. 对SpringMVC有一定的使用经验
  2. 有RESTful的经验

概述

JAX-RS(Java API for RESTful Web Services)是Java语言领域RESTful风格的Web服务器的标准规范。直至JavaEE 6 通过JCP组织的JSR311将REST在Java语言领域标准化。JSR311其中一个实现是GlassFish项目的Jersey1.0,在时隔5年后JavaEE7包含了JSR339,即JAX-RS2.0,JAX-RS2.0在前面的版本基础上加上了很多实用功能,比如REST客户端API的定义,异步REST等。

JAX-RS的版本对应是实现的Jersey版本信息,如下表:

JAX-RS标准JAX-RS名称JAX-RS实现JDK版本
311JAX-RS1.0Jersey 1.0Java 6
339JAX-RS 2.0Jersey 2.0Java 7

Spring MVC,其也实现REST,但并没有对JAX-RS标准做实现。若之前有使用Spring MVC的经验,用Jersey起来用容易上手。

入门

Jersey包括三个部分:

  • 核心服务器(Core Server):经过提供JAX-RS中标准化的注解和API标准化,能够用直观的方式开发RESTful Web服务。
    • 要做RESTful Web服务,就要添加这个依赖。
  • 核心客户端(Core Client):Jersey客户端API可以帮助开发者与RESTful服务轻松通讯。
    • 如果要做测试,写单元测试,通过Jersey的API去测试,你做的web服务能不能正常通信,能不能正常返回之类的,那就需要添加这个依赖。我们现在目前用不到,我们一般是使用浏览器或者postman等工具去测试
  • 集成(Integration):Jersey还提供能够轻松与Spring集成。

这里入门仅仅使用了核心服务器,没有使用Spring,在Tomcat服务容器环境运行。

项目准备

新建Maven项目,打包方式为war,pom.xml主要内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jersey01-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.23.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <!--    Tomcat Maven插件  -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <port>80</port>
                    <path>/</path>
                    <uriEncoding>UTF-8</uriEncoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

编写资源类

提供对外访问的资源的方法(类似Spring MVC中的控制器)

package com.example.web.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    // 类似 Spring MVC 处理方法
    @GET //表示这个资源是用GET请求方式访问
    @Produces(MediaType.TEXT_PLAIN) //指定我们响应的数据格式是什么?这里响应的数据格式是纯文本
    public String get(){
        return "jersey resource";
    }
}

编写资源配置类

作用告诉项目有哪些资源(类似SpringMVC中的配置)

package com.example.web.config;

import com.example.web.resource.PersonResource;
import org.glassfish.jersey.server.ResourceConfig;

// 配置类,配置这个项目有什么资源
public class ApiResourceConfig extends ResourceConfig {

    public ApiResourceConfig(){
        //注册资源
        register(PersonResource.class);
    }
}

配置ServletContainer

在web.xml配置ServletContainer(本质是一个Servlet,类似Spring MVC中的前端控制器DispatcherServlet),指定加载资源配置。

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
        <!-- 配置ServletContainer 类似Spring MVC前端控制器 -->
        <servlet>
            <servlet-name>jerseyServlet</servlet-name>
            <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
            <init-param>
                <param-name>javax.ws.rs.Application</param-name>
                <param-value>com.example.web.config.ApiResourceConfig</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>jerseyServlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
</web-app>

启动测试

使用Tomcat Maven插件启动项目测试,访问路径:localhost/person

在这里插入图片描述

注解

Jersey里面提供很多注解,帮助开发者来定义资源的路径,请求方式等等。

@Path

用来指定资源的路径,可以贴资源类上,也可以贴资源类中的方法上。其支持路径参数,也支持路径表达式。一个@Path中的路径是否以“/”开头都没有区别,同样是否以“/”结尾也没有什么区别。

package com.example.web.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{id}")
    public String getPerson(@PathParam("id") Long id){
        return "Get Person resource" + id + "!";
    }
}

启动tomcat,访问路径localhost/person/1试下

package com.example.web.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/{username:[a-zA-Z]{5,8}}")
    public String getExpression(@PathParam("username") String name){
        return "Get Person resource expression " + name;
    }
}

启动tomcat,访问路径:localhost/person/lony。但若访问的路径不匹配正则表达式,则访问会出现404。

请求方式注解

用来指定资源的请求,可以贴在资源类中的方法上。在JAX-RS标准定义了@GET,@PUT,@POST,@DELETE,@HEAD,@OPTIONS这些注解,类似与HTTP中的请求方法名。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @POST
    @Path("/save")
    @Produces(MediaType.TEXT_PLAIN)
    public String save(){
        return "save Person resouce";
    }
}

启动tomcat,使用浏览器访问路径localhost/person/save,访问会报405,这里需要使用Postman用POST方式访问才可以。

@Produces

用来指定返回值给客户端的MIME媒体类型(响应的数据类型),可以贴在资源类上,也可以贴在资源类中的方法上。若同时都贴了,以访问的方法上为准。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
@Produces(MediaType.TEXT_PLAIN)
public class PersonResource {
    
    @GET
    @Path("/plain")
    public String getTextPlain(){
        return "Person Text Plain";
    }
    
    @GET
    @Path("/html")
    @Produces(MediaType.TEXT_HTML)
    public String getHtml(){
        return "Person HTML";
    }
}

访问路径localhost/person/plain,响应头Content-Type:text/plain;访问路径:localhost/person/html,响应头Content-Type:text/html。

@Consumes

用来指定可由资源消耗的MIME媒体类型(请求的数据类型)。@Consumes既可以贴在资源类上,也可以贴资源类中的方法上。若同时都贴了,以访问的方法上为准。而且声明可以不只一种媒体类型。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @POST
    @Path("/consumes")
    @Consumes("text/plain")
    public void postMessage(String message){
        System.out.println(message);
    }
}

访问路径localhost/person/consumes,请求方式为POST,指定请求头Content-Type:text/plain,服务器没有内容返回。而是把一个204状态码响应给客户端;如果请求头Content-Type不为text/plain,则会返回415(Unsupported Media Type)状态码。访问路径localhost/person/consumes,请求方式POST,指定请求头Content-Type:application/x-www-form-urlencoded,服务器把一个415状态码响应给客户端。

在这里插入图片描述

参数注解

@PathParam

用来获取URL请求中的路径参数(前面已演示过)。

@QueryParam

用于获取GET请求中的查询参数,同时也是配置@DefaultValue指定默认值。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {
    
    @GET()
    @Path("/queryParam")
    public String queryParam(@QueryParam("name") String name, @QueryParam("age") int age){
        return "name:"+name + ",age:" + age;
    }
}

访问路径localhost/person/queryParam,发现形参name为null,形参age为0;访问路径localhost/person/queryParam?name=lony&age=18试下,发现形参name为lony,形参age为18。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET()
    @Path("/queryParamDefaultValue")
    public String queryParamDefaultValue(@DefaultValue("lucy") @QueryParam("name") String name,
                                         @DefaultValue("20") @QueryParam("age") int age){
        return "name:"+name + ",age:" + age;
    }

}

访问路径localhost/person/queryParamDefaultValue,发现形参name为lucy,形参age为20

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {
    
    @DELETE
    @Path("/delete")
    public void delete(List<Long> ids){
        System.out.println(ids);
    }

}

访问路径localhost/person/delete,请求方式DELETE,不管是否携带参数,ids打印都为null。但是上面方法形参ids贴@QueryParam(“ids”)注解之后,访问路径localhost/person/delete,请求方式DELETE,ids打印为[];访问路径:localhost/person/delete?ids=1&ids=2,请求方式DELETE,ids打印为[1,2]。

@MatrixParam

用来获取路径上矩阵变量格式的参数,比如请求路径是这样的localhost/person;id=1;name=Lucy,Ben

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET
    @Path("/matrix")
    public String matrix(@MatrixParam("id") Long id, @MatrixParam("name") List<String> names){
        return id + names.toString();
    }

}

访问路径localhost/person/matrix;id=1;name=Lucy,Bean,请求方式GET,测试一下。

@FormParam

用来从POST请求的表单参数(请求的MIME媒体类型为application/x-www-form-urlencoded)中获取数据。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @POST
    @Path("/from")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public void save(@FormParam("name") String name, @FormParam("age") int age){
        System.out.println(name + ":" + age);
    }

}

访问路径localhost/person/from,请求方式POST,携带表单数据测试一下。

@HeaderParam & @CookieParam

@HeaderParam用来获取请求头,@CookieParam用来获取Cookie。

package com.example.web.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET()
    @Path("/headAndCookie")
    public String getHeadAndCookid(@HeaderParam("HOST") String host,
                                   @CookieParam("name") String name){
        return host + ":" + name;
    }

}

访问路径localhost/person/headAndCookie,请求方式GET,携带Cookie测试以下。

在这里插入图片描述

@BeanParam

当请求参数不少时,好比客户端提交一个保存Person的POST请求,请求中包含较多Person信息,这时能够用@BeanParam。

package com.example.web.domain;

import lombok.Data;

import javax.ws.rs.FormParam;

@Data
public class Person {
    @FormParam("id")
    private Long id;
    @FormParam("name")
    private String name;
    @FormParam("age")
    private int age;
}
package com.example.web.resource;

import com.example.web.domain.Person;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Path("/beanParam")
    public void savePerson(@BeanParam Person person){
        System.out.println(person);
    }

}

访问localhost/person/beanParam,请求方法POST,携带表单数据测试一下。

@BeanParam可以包含所有的注入参数的注解:@PathParam、@QueryParam、@MatrixParam、HeaderParam、@CookieParam、@FormParam。

@Context

一般可以用于获得一个Java类型的请求或响应的上下文,比如获取ServletConfig、ServletContext、HttpServletRequest、HttpServletResponse和HttpHeaders。

在pom.xml添加如下依赖

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
package com.example.web.resource;

import com.example.web.domain.Person;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @Context
    private ServletContext servletContext;

    @GET
    @Path("/getHttpInfo")
    public void getHttpInfo(@Context HttpServletRequest request, @Context HttpServletResponse response){
        System.out.println(this);
        System.out.println(servletContext);
        System.out.println(request);
        System.out.println(response);
    }

}

访问路径localhost/person/getHttpInfo,请求方式GET测试一下。

生命周期注解

上面的代码演示发现,每次请求打印的this都是不同的。但是Jersey提供如下注解让开发者修改资源实例的生命周期。这些注解是贴在资源类上的。

  • @RequestScoped(默认注解),每个新的请求都会创建一个新实例用于处理请求(同一请求的实例不会被重复创建)
  • @PerLookup,每次请求都会创建新实例(即使处理的是同一个请求)。
  • @Singleton,每一个资源类只创建一个实例。

JSON

Jersey支持MOXy-JSON,JSON-P,Jackson,Jettison处理JSON。我们这里选择Jaskson。

添加依赖

在pom.xml添加如下依赖:

        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>2.23.2</version>
        </dependency>

配置转换器

在资源配置类中注册JSON转换器

package com.example.web.config;

import com.example.web.resource.PersonResource;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.glassfish.jersey.server.ResourceConfig;

// 配置类,配置这个项目有什么资源
public class ApiResourceConfig extends ResourceConfig {

    public ApiResourceConfig(){
        //注册资源
        register(PersonResource.class);
        // 注解转换器
        register(JacksonJsonProvider.class);
    }
}

实体类

用来封装数据

package com.example.web.domain;

import lombok.Data;

import javax.ws.rs.FormParam;

@Data
public class Student {

    private Long id;

    private String name;

    private int age;
}

资源类

package com.example.web.resource;

import com.example.web.domain.Person;
import com.example.web.domain.Student;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;

// 类似 Spring MVC控制器
@Path("/person")
public class PersonResource {

    @GET
    @Path("/jsonReq")
    @Produces("application/json")
    public Student getStudent(){ //响应JSON数据
        Student student = new Student();
        student.setId(12L);
        student.setName("哈哈");
        student.setAge(23);
        return student;
    }

    @POST
    @Path("/jsonRes")
    @Consumes(MediaType.APPLICATION_JSON)
    public void getStudentJson(Student student){ //接收JSON数据
        System.out.println(student);
    }

}

访问路径localhost/person/jsonReq,请求方式GET测试一下。

访问路径localhost/person/jsonRes,请求方式POST,携带JSON数据测试一下。

REST接口最佳实践

package com.example.resource;

import com.example.domain.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.Arrays;
import java.util.List;

/**
 * Response类,提供方法设置状态,响应头,响应数据
 */
@Path("/persons")
@Component
public class PersonResource {

    @Autowired
    private ApplicationContext ctx;

    /**
     * 删除功能
     * 请求方式 DELETE
     * 路径/persons/{id}
     * 状态204  响应体中没有数据
     * @return
     */
    @DELETE
    @Path("/{id}")
    public Response delete(@PathParam("id") String id){

        return Response.noContent() //设置状态,设置响应头 location
                .build();
    }


    /**
     * 更新功能
     * 请求方式 PUT
     * 路径/persons
     * 参数 application/json 在请求体中
     * 状态204  响应体中没有数据
     * @return
     */
    @PUT
    @Consumes(MediaType.APPLICATION_JSON)
    public Response update(Person person){

        return Response.noContent() //设置状态,设置响应头 location
                .build();
    }

    /**
     * 新增功能
     * 请求方式POST
     * 路径/persons
     * 参数 application/json 在请求体中
     * 状态201
     * 响应数据类型 application/json
     * 响应体中的数据就是person数据
     * @return
     */
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response save(Person person, @Context UriInfo uriInfo){

        URI uri = uriInfo.getAbsolutePathBuilder().path(person.getId() + "").build();
        return Response.created(uri) //设置状态,设置响应头 location
                .entity(person)
                .build();
    }

    /**
     * 分页查询功能
     * 请求方式GET
     * 路径/persons
     * 状态200
     * 响应数据类型 application/json
     * 响应体中的数据就是多个person数据
     * 响应头,设置后端有多少条数据  X-Total-Count
     * @return
     */
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response page(){
        Person person1 = new Person();
        person1.setId(1L);
        person1.setName("zhangsan");
        person1.setAge(8);

        Person person2 = new Person();
        person2.setId(2L);
        person2.setName("lisi");
        person2.setAge(82);
        List<Person> people = Arrays.asList(person1, person2);
        int count = 20;
        return Response.ok(people)
                .header("total-count",count)
                .build();//设置状态码200,设置响应体中数据
    }

    /**
     * 查看详情功能
     * 请求方式GET
     * 路径/persons/id值
     * 状态200
     * 响应数据类型 application/json
     * 响应体中的数据就是person数据
     * @param id
     * @return
     */
    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response person(@PathParam("id") Long id){
        Person person = new Person();
        person.setId(id);
        person.setName("zhangsan");
        person.setAge(8);
        return Response.ok(person).build();//设置状态码200,设置响应体中数据
    }
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值