JAX-RS Webservice mit Jersey - JSON über JQuery

Alistair87

Grünschnabel
Hallo Leute,

ich hoffe ihr könnt mir helfen.
Und zwar möchte ich gerne ein RESTful Webservice erstellen und diesen dann mit JQuery ansprechen. Das Informationen sollen mit JSON übermittelt werden.

Als Server benutze ich Tomcat v7.0.

Ich habe mir in Eclipse ein Dynamic Web Project angelegt.
Danach haben ich die Jersey Jar-Files in den Ordner WEB-INF/lib kopiert.

Zu Testzwecken habe ich mir zunächst nur eine Klasse erstellt:

Code:
package de.test.rest;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
@Path("/test")
public class TestREST
{
    @GET
    @Path("json")
    @Produces(MediaType.APPLICATION_JSON)
    public String test()
    {
        return "test123123123";
    }
}

Die web.xml Datei sieht so aus:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID"
    version="3.0">
  <display-name>testrest</display-name>
  <servlet>
      <servlet-name>testrest</servlet-name>
      <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
      <init-param>
         <param-name>com.sun.jersey.config.property.packages</param-name>
         <param-value>de.test.rest</param-value>
      </init-param>
      <init-param>
        <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
    </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>testrest</servlet-name>
      <url-pattern>/rest/*</url-pattern>
   </servlet-mapping>
</web-app>

Wenn ich nun über den Webbrowser den URL http://localhost:8080/test/rest/test/json aufrufe bekomme ich die JSON übermittelt.
Allerdings möchte ich gerne die Informationen über JQuery anfordern.

Das ganze habe ich mit folgendem Code getestet:

Code:
$(document).ready(function(){

var url = '',
    data = '';      
    url = 'http://localhost:8080/test/rest/test/json';

    

$.ajax({
    url: url,
    type: 'GET',
    dataType: 'json',
    success: function(data){
        alert(data);
    }
});

});

Doch dort bekomme ich als Antwort nichts zurück bzw. die Funktion success wird gar nicht aufgerufen. Woran könnte das liegen? Was habe ich falsch gemacht? Oder muss ich noch irgendwas am Server machen?
Hoffe ihr könnt mir helfen.

MfG
Alistair
 
Hallo,

welche JQuery Version verwendest du denn? Für neuen code sollte man laut JQuery Doku nicht mehr die ajax-callbacks success und error verwenden... siehe:
http://api.jquery.com/jQuery.ajax/
Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks will be deprecated in jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

basierend auf dem JAX-RS / Servlet 3.0 Beispiel unter:
http://www.tutorials.de/enterprise-java-jee-j2ee-spring-co/387359-jax-rs-json.html

hier ein kleines JQuery Javascript interface zum JAX-RS Service:

index.jsp
HTML:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>JAX RS / JQUERY Example</title>

<script type="text/javascript" src="res/js/jquery/jquery-1.7.2.min.js"></script>

<script type="text/javascript">
	var userAdminAPI = {
		newRequest : function(type, urlSuffix, data) {
			var request = {
				url : "resources" + urlSuffix,
				type : type,
				data : data ? JSON.stringify(data) : null,
				contentType : "application/json",
				dataType : "json"
			};
			return request;
		},

		addUser : function() {

			var request = userAdminAPI.newRequest("post", "/app/user/create",$("#txtUsername").val());

			$.ajax(request).done(function(response) {
				alert(JSON.stringify(response));
			});
		},

		listUsers : function() {
			var request = userAdminAPI.newRequest("get", "/app/user/list-all");

			$.ajax(request).done(function(response) {
				alert(JSON.stringify(response));
			});
		}

	};
</script>

</head>
<body>
	<label for="txtUsername">Benutzername</label>:
	<input type="text" id="txtUsername" />
	<a href="#" onclick="userAdminAPI.addUser()">add</a>
	<a href="#" onclick="userAdminAPI.listUsers()">list all users</a>
</body>
</html>

Die UserResource:
Java:
package de.tutorials.app.um.remote;

import java.util.Set;
import java.util.TreeSet;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;

import de.tutorials.app.um.data.UserDatabase;
import de.tutorials.app.um.model.User;

@Path("app")
public class UserResource {

	public UserResource() {
	}

	@POST
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	@Path("/user/create")
	public User create(String username, @Context ContextResolver<UserDatabase> cr) {
		User user = new User(username);
		cr.getContext(getClass()).save(user);
		return user;
	}

	@GET
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	@Path("/user/{id}")
	public User getUser(@PathParam("id") Long id,@Context ContextResolver<UserDatabase> cr) {
		return cr.getContext(getClass()).get(id);
	}

	@GET
	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	@Path("/user/list-all")
	public Set<User> getAllUsers(@Context ContextResolver<UserDatabase> cr) {
		return new TreeSet<>(cr.getContext(getClass()).list());
	}
}

Ein User:
Java:
package de.tutorials.app.um.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User implements Comparable<User>{

	private Long id;
	private String name;

	public User() {
	}

	public User(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	@Override
	public int compareTo(User o) {
		return this.name.compareTo(o.name);
	}
}

Das UserDatabase-Interface:
Java:
package de.tutorials.app.um.data;

import java.util.Set;

import de.tutorials.app.um.model.User;

public interface UserDatabase {
	User save(User user);
	User get(Long id);
	Set<User> list();
}

Die InMemoryUserDatabase (zum Testen):
Java:
package de.tutorials.app.um.data;

import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import de.tutorials.app.um.model.User;

class InMemoryUserDatabase implements UserDatabase {
	private ConcurrentMap<Long, User> userDatabase = new ConcurrentHashMap<>();

	public InMemoryUserDatabase() {
		User user = new User("admin");
		user.setId(1L);
		save(user);
	}

	@Override
	public User save(User user) {
		if (user.getId() == null) {
			user.setId(System.currentTimeMillis());
		}
		userDatabase.put(user.getId(), user);
		return user;
	}

	@Override
	public User get(Long id) {
		return userDatabase.get(id);
	}

	@Override
	public Set<User> list() {
		return new TreeSet<>(userDatabase.values());
	}

}

User UserDatabaseProvider:
Java:
package de.tutorials.app.um.data;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class UserDatabaseProvider implements ContextResolver<UserDatabase> {

	private final UserDatabase userDatabase;
	
	public UserDatabaseProvider() {
		this.userDatabase = new InMemoryUserDatabase();
	}

	@Override
	public UserDatabase getContext(Class<?> type) {
		return userDatabase;
	}
}

Hier noch unser angepasster Jersey JAX-RS Bootstrap (ohne web.xml - nur mit Servlet 3.0 Mitteln):
Java:
package de.tutorials.app.web.boot;

import java.util.Set;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;

public class Bootstrap implements ServletContainerInitializer {

	public void onStartup(Set<Class<?>> classes,ServletContext servletContext) throws ServletException {

		configureJaxRsProvider(servletContext);
	}

	private void configureJaxRsProvider(ServletContext sc) {
		Dynamic servletAdaptorConfig = sc.addServlet("ServletAdaptor",com.sun.jersey.spi.container.servlet.ServletContainer.class);
		servletAdaptorConfig.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true");
		servletAdaptorConfig.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter");
		servletAdaptorConfig.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.api.container.filter.LoggingFilter");
		servletAdaptorConfig.setLoadOnStartup(1);
		servletAdaptorConfig.addMapping("/resources/*");
	}

}

Das Beispiel habe ich angehängt.

Hier noch ein weiteres Beispiel zu JAX-RS mit JSON Serialisierung:
http://www.tutorials.de/enterprise-java-jee-j2ee-spring-co/387359-jax-rs-json.html

Hier findest du noch ein anderes Beispiel zu einem JQuery Server-Call (Spring Web MVC):
http://www.tutorials.de/java/385530...bernate-4-x-lombok-junit-4-und-maven-3-a.html

Gruß Tom
 

Anhänge

  • de.tutorials.web.training.zip
    55,3 KB · Aufrufe: 31
hey,

danke für diese super-hilfe!
jetzt bin ich schonmal einen großen schritt weiter gekommen.

ich steht aber jetzt vor dem problem, dass ich über jquery keine json über einen externen server bekommen kann. das kann ich nur, wenn das ganze über localhost geschieht.

muss ich dafür noch irgendwas spezielles einstellen?

mfg
Alistair
 
Hallo,

hast du denn Tomcat auch so konfiguriert, dass er auch auf der "externen" IP / dem externen Interface erreichbar ist?

Gruß Tom
 
Ist das nicht standardmäßig so eingestellt? Wenn ich über den webbrowser zugreife, bekomme ich ja den json string ausgegeben
 
also ich habe das ganze jetzt so probiert:

Code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>JAX RS / JQUERY Example</title>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>

<script type="text/javascript">
	var userAdminAPI = {
		newRequest : function(type, urlSuffix, data) {
			var request = {
				url : urlSuffix,
				type : type,
				data : data ? JSON.stringify(data) : null,
				contentType : "application/json",
				dataType : "json"
			};
			return request;
		},

		getJson : function() {
			var request = userAdminAPI.newRequest("get", "http://serverurl:8080/test/rest/json");

			$.ajax(request).done(function(response) {
				alert(JSON.stringify(response));
			});
		}

	};
</script>

</head>
<body>
	<a href="#" onclick="userAdminAPI.getJson()">getJson</a>
</body>
</html>


das klappt aber leider nicht :(
hab mir nebenbei die firebug konsole angeschaut. da macht er leider keinen mucks.

lokal funktioniert alles. aber das möchte ich ja nicht.

hoffe ihr könnt mir weiterhelfen
 
hey,

nein rufe die html seite nicht von der serverurl auf, da ich später mit einer ria app auf den server zugreifen möchte, um mir so die informationen per rest zu holen.
die html seite ist dann natürlich in der ria app integriert und liegt nicht auf dem server.
geht das etwa gar nicht?
 

Neue Beiträge

Zurück