因为是初学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、搭建过程中遇到的问题
- 在第一次跑起来的时候,项目可正常启动,首页也可以正常访问,但是访问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 都是捆绑在一起的。