记录第一次搭建基于JAX-RS的REST风格DEMO

因为是初学REST风格,所以并不打算马上就用springMVC这些框架去实现restful,所以先用jersey搭建一个rest的demo上手玩玩,本文记录了搭建所需要引入的jar包,以及搭建过程碰到的坑,希望能让大家有所收获,欢迎交流!

1、Maven jar包引入

 <dependencies>

    <!-- https://mvnrepository.com/artifact/javax/javaee-api -->
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
      <scope>provided</scope>
    </dependency>

    <!-- Part 1: jersey包 -->
      <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.containers/jersey-container-servlet-core -->
    <dependency>
      <groupId>org.glassfish.jersey.core</groupId>
      <artifactId>jersey-server</artifactId>
      <version>2.23.2</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.core</groupId>
      <artifactId>jersey-common</artifactId>
      <version>2.23.2</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-servlet</artifactId>
      <version>2.23.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.11.0</version>
      <scope>test</scope>
    </dependency>

    <!-- Part 2:支持Json格式 ,否则会报: MessageBodyWriter not found for media type=application/json ... 的错误-->
    <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-moxy</artifactId>
      <version>2.23.2</version>
    </dependency>

    <!-- Part 3:支持复杂的Json格式翻译,例如Map<K,E>,当然我们也可以使用Gson -->
    <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-json-jackson</artifactId>
      <version>2.23.2</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.8.1</version>
    </dependency>

    <!-- Part 4: 支持XML格式,否则会报MessageBodyWriter not found for media type=application/xml.... -->
    <dependency>
      <groupId>com.fasterxml.jackson.jaxrs</groupId>
      <artifactId>jackson-jaxrs-xml-provider</artifactId>
      <version>2.8.1</version>
    </dependency>

    <!--
    JAXB API是java EE 的API,因此在java SE 9.0 中不再包含这个 Jar 包。
    java 9 中引入了模块的概念,默认情况下,Java SE中将不再包含java EE 的Jar包
    而在 java 6/7 / 8 时关于这个API 都是捆绑在一起的
    -->
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>activation</artifactId>
      <version>1.1.1</version>
    </dependency>

2、代码

  • rest api 类
package com.test;

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

/**
 * test rest api
 */
@Path("/helloworld")
public class HelloWorld {
    private final String ROOT_NODE = "root";


    /**
     * 无参简单调用
     *
     * @return
     */
    @GET
    @Path("/sayhello")
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHelloWorld() {
        return "hello,world!";
    }

    /**
     * 带参方法,多个参数用多个/{}引住
     *
     * @param userName
     * @param age
     * @return
     */
    @GET
    @Path("/{name}/{age}")
    @Produces("text/plain;charset=UTF-8")
    public String helloName(@PathParam("name") String userName, @PathParam("age") String age) {
        return "hello," + userName + ",你今年" + age + "岁";
    }

    /**
     * 以xml形式返回一个user对象
     * 其中有多个方案可以注入对象的成员属性值,如下例子:
     * 1、首先要在User类注解@XmlRootElement
     * 2、可以注解@XmlElement给set方法,在new出User实例后,调用set方法注入属性值
     * 3、可以注解@XmlElement给get方法,通过在构造方法调用get方法获取属性值
     * 4、可以注解@XmlElement给set方法,通过在构造方法调用set方法注入属性值
     *
     * @return
     */
    @GET
    @Path("/getUserXml")
    @Produces("application/xml")
    public User getUserXml() {
        User user = new User("jams", "26", "programer", "4453");
        user.setJob("programer"); //对应注释1

//        User user = new User();
//        user.setAge("25");
//        user.setIdcard("123");
//        user.setJob("pro");
//        user.setUsername("james");
        return user;
    }

    /**
     * 以xml形式返回一个user对象
     * 其中有多个方案可以注入对象的成员属性值,如下例子:
     * 1、首先要在User类注解@XmlRootElement
     * 2、可以注解@XmlElement给set方法,在new出User实例后,调用set方法注入属性值
     * 3、可以注解@XmlElement给get方法,通过在构造方法调用get方法获取属性值
     * 4、可以注解@XmlElement给set方法,通过在构造方法调用set方法注入属性值
     *
     * @return
     */
    @GET
    @Path("/getUserJson")
    @Produces(MediaType.APPLICATION_JSON)
    public UserJson getUserJson() {
        UserJson userJson = new UserJson("jams", "26", "programer", "4453");
        userJson.setJob("程序猿");
        return userJson;
    }

    /**
     * url传入参数方式
     * http://localhost:8080/mavenTest2/rest/helloworld/getMessage?from=10&to=100
     * @param from
     * @param to
     * @return
     */
    @GET
    @Path("/getMessage")
    @Produces({MediaType.APPLICATION_JSON})
    public HashMap getClientedMessage(@QueryParam("from") int from, @QueryParam("to") int to) {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("abc", "def");
        map.put("abc1", "" + from);
        map.put("abc2", "" + to);
        return map;
    }
}
  • xml格式的user对象
package com.test;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * 以xml形式返回一个user对象
 * 其中有多个方案可以注入对象的成员属性值,如下例子:
 * 1、首先要在User类注解@XmlRootElement
 * 2、可以注解@XmlElement给set方法,在new出User实例后,调用set方法注入属性值
 * 3、可以注解@XmlElement给get方法,通过在构造方法调用get方法获取属性值
 * 4、可以注解@XmlElement给set方法,通过在构造方法调用set方法注入属性值
 */
@XmlRootElement
public class User {

    private String username;
    private String age;
    private String job;
    private String idcard;

    public User() {
    }

    public User(String username, String age, String job, String idcard) {
//        username = this.username;
//        age = this.age;
//        job = this.job;
//        idcard = this.idcard;

//        this.setUsername("jams");
//        this.setJob("programer");
        this.setIdcard("445381");  //对应注释3
        setAge("26");  //对应注释3

        username = this.getUsername();  //对应注释2
//        age = this.getAge();
//        job = this.getJob();
//        idcard = getIdcard();
    }

    @XmlElement
    public String getUsername() {
        return "安德丽娜·朱莉";
    }
//    @XmlElement
    public String getAge() {
        return age;
    }
//    @XmlElement
    public String getJob() {
        return job;
    }
//    @XmlElement
    public String getIdcard() {
        return idcard;
    }

//    @XmlElement
    public void setUsername(String username) {
        this.username = username;
    }

    @XmlElement
    public void setAge(String age) {
        this.age = age;
    }

    @XmlElement
    public void setJob(String job) {
        this.job = job;
    }

    @XmlElement
    public void setIdcard(String idcard) {
        this.idcard = idcard;
    }
}
  • json格式的user对象
package com.test;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonSetter;


/**
 * 以json形式返回一个user对象
 * 其中有多个方案可以注入对象的成员属性值,如下例子:
 * 1、可以注解@JsonSetter给set方法,在new出UserJson实例后,调用set方法注入属性值
 * 2、可以注解@JsonGetter给get方法,通过在构造方法调用get方法获取属性值
 * 3、可以注解@JsonSetter给set方法,通过在构造方法调用set方法注入属性值
 */
public class UserJson {

    private String username;
    private String age;
    private String job;
    private String idcard;

    public UserJson() {
    }

    public UserJson(String username, String age, String job, String idcard) {
//        username = this.username;
//        age = this.age;
//        job = this.job;
//        idcard = this.idcard;

//        this.setUsername("jams");
//        this.setJob("programer");
        this.setIdcard("445381");  //对应注释3
        setAge("26");  //对应注释3

        username = this.getUsername();  //对应注释2
//        age = this.getAge();
//        job = this.getJob();
//        idcard = getIdcard();
    }

    @JsonGetter
    public String getUsername() {
        return "安德丽娜·朱莉";
    }
    public String getAge() {
        return age;
    }
    public String getJob() {
        return job;
    }
    public String getIdcard() {
        return idcard;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @JsonSetter
    public void setAge(String age) {
        this.age = age;
    }

    @JsonSetter
    public void setJob(String job) {
        this.job = job;
    }

    @JsonSetter
    public void setIdcard(String idcard) {
        this.idcard = idcard;
    }
}
  • web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>javax.ws.rs.core.Application</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

3、搭建过程中遇到的问题

  1. 在第一次跑起来的时候,项目可正常启动,首页也可以正常访问,但是访问rest接口的时候就报错,错误如下:
HTTP Status 500 – Internal Server Error
Type Exception Report

Message Servlet.init() for servlet [javax.ws.rs.core.Application] threw exception

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

javax.servlet.ServletException: Servlet.init() for servlet [javax.ws.rs.core.Application] threw exception
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.base/java.lang.Thread.run(Thread.java:844)
Root Cause

java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
    org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:274)
    org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:221)
    org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:453)
    org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:387)
    org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
    org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
    javax.servlet.GenericServlet.init(GenericServlet.java:158)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.base/java.lang.Thread.run(Thread.java:844)
Note The full stack trace of the root cause is available in the server logs.

Apache Tomcat/8.5.23

找来找去没发现那里有问题,最后无意中发现原来是JAVAEE包的问题,JAXB API是java EE 的API,因此在java SE 9.0 中不再包含这个 Jar 包。java 9 中引入了模块的概念,默认情况下,Java SE中将不再包含java EE 的Jar包,而在 java 6/7/8 时关于这个API 都是捆绑在一起的。

    原文作者:双层巴士
    原文地址: https://segmentfault.com/a/1190000014980668
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞