开发者

Need to write a RESTful JSON service in Java

开发者 https://www.devze.com 2023-04-10 04:12 出处:网络
Here i开发者_StackOverflow中文版s my requirement: I have a simple table in mysql(Consider any table with a few fields)

Here i开发者_StackOverflow中文版s my requirement:

  1. I have a simple table in mysql(Consider any table with a few fields)
  2. I need to write a simple RESTFUL JSON webservice in Java that performs CRUD operations on this table.

I tried searching on the net for some comprehensive example for this but could not find any. Can anyone help?


Jersey is a JAX-RS implementation for building RESTful webservices.

Start with their tutorial. It's pretty easy.

http://jersey.java.net/nonav/documentation/latest/getting-started.html

Edit: Also, there's a great O'Riley book on the subject (shocking, I know); RESTful Java with JAX-RS


I would take a look at what Spring has to offer. There are RestTemplate's, and Spring MVC, Both of which should be able to help you out.

Another thing which will be helpful is some sort of JSON-Mapping library. I will recommend Jackson Object Mapper. Take a look at their tutorials for an idea of how it will work.


I will outline the essential parts of my blog post Building a RESTful Web Service in Java, which shows the steps you can take to connect to the database and create a RESTful Web Service using the following.

  • IDE: Eclipse IDE for Jave EE Developers (Kepler), comes with Maven built in
  • Database: MySQL (also makes use of MySQL Workbench)
  • Application Server: GlassFish 4.0
  • Java EE 7 (JAX-RS, JPA, JAXB, etc)
  • Any REST Client for testing: (eg Postman)

The following description assumes you have already installed the technology listed above. The service is for a database table 'item' that stores items with the fields id, itemName, itemDescription, itemPrice.

The Persistence Layer

  • Create a MySQL database schema using MySQL Workbench's ‘create a new schema in connected server‘ icon. In this example the schema is called 'smallbiz'.
  • Connect Eclipse to MySQL
    • Download the MySQL JDBC driver and save in a convenient location.
    • In Eclipse, create a new Database Connection in the Data Source Explorer tab. During this process you will need to browse to the MySQL JDBC driver.
  • Create a MySQL JDBC Connection Pool and Resource in GlassFish (this is required for the application to be able to connect the database once deployed on the server).
    • Copy the MySQL JDBC driver to the ext directory in GlassFish i.e. $glassfish_install_folder\glassfish\lib\ext. Then restart GlassFish.
    • Loggin into the GlassFish admin area using a browser (located at http://localhost:4848 by default).
    • Under Resources > JDBC > Connection Pools, create a new connection pool with a 'Resource Type' of java.sql.Driver.
    • On the 'New JDBC Connection Pool (Step 1 of 2)' screen.
      • Enter a 'Pool Name' (eg SmallBizPool).
      • Select the 'Resource Type' (java.sql.Driver).
      • Select the 'Database Driver Vendor' (MySQL).
      • Next.
    • On the bottom section of the following screen in Additional Properties.
      • URL: jdbc:mysql://localhost:3306/smallbiz
      • user: yourUser (root in my set-up)
      • password: yourPassword
      • Finish
      • Ping on the following screen to test the connection.
    • Create a JDBC Resource from the connection pool at Resources > JDBC > JDBC Resources:
      • Enter a 'JNDI Name' (eg jdbc/SmallBiz). We use this in the persistence.xml file so the application knows how to connect to the database.
      • Select the connection pool previously created from the 'Pool Name' drop down list.
    • For more Information on JDBC Connection Pool and Resource
      • This answer has some screen shots that may help. Note it uses a 'Resource Type' of javax.sql.DataSource
      • Making datasource in Glassfish
      • Some confusion surrounding JDBC Resources and JDBC Connection pools Glassfish
  • Connect Eclipse to GlassFish.
    • Add GlassFish Tools to Eclipse by searching Help > Eclipse Marketplace.
    • Connect GlassFish to Eclipse by creating a new server using the Servers tab.
      • Select GlassFish 4.0 on the Define a New Server screen.
      • Ensure 'jdk7' i selected and the JDK in the New GlasssFish 4.0 Runtime screen.
      • On the screen that follows, ensure the correct domain directory is selected (the default is domain1, eg. $glassfish_install_folder\glassfish\domains\domain1), then enter the admin credential for GlassFish.
      • You can now interact with GlassFish (start, stop, restart, run on, etc) from in Eclipse.
  • Create a new Maven Project in Eclipse and add dependencies using m2e (which is built in) for:
    • EclipseLink (for JPA) “org.eclipse.persistence eclipselink”

To map to the database, a JPA Entity is used. A JPA Entity is simple a POJO (Plain Old Java Object) annotated with JPA annotations. If the database already exists, Eclipse can generate the JPA Entity from the database.

  • Create a database table using the SQL scrapbook in Eclipse with the following SQL

    CREATE TABLE item (
         id VARCHAR(36) NOT NULL,
         itemName TEXT NOT NULL,
         itemDescription TEXT,
         itemPrice DOUBLE,
         PRIMARY KEY (id)
     )
    
  • Create a JPA entity from the database table by right clicking a package created in Eclipse and selecting New > JPA Entities from Table.

  • Annotate the JPA entity with JAXB annotation in order to be able to marshal it to and from xml or json.

Since this example uses UUID's for the primary key, there are also annotations (@UuidGenerator and @GeneratedValue) that are specific to EclipseLink to take care of creating them. It is not necessary to use UUID's as the primary keys but one of the reasons I use it is so that I can create a model on the client complete with a UUID and then PUT that new model to the server (eg in offline mode, new models created and stored locally are PUT to the server when cell signal returns). If the server created the UUID then new model is sent to the server without an id using POST.

package com.zangolie.smallbiz.entities;

import java.io.Serializable;

import javax.persistence.*;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.annotations.UuidGenerator;


/**
 * The persistent class for the item database table.
 * 
 */
@UuidGenerator(name="UUID")
@XmlRootElement
@Entity
@NamedQuery(name="Item.findAll", query="SELECT i FROM Item i")
public class Item implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator="UUID")
    @Column(length=36)
    private String id;

    private String itemDescription;

    @Lob
    private String itemName;

    private double itemPrice;

    public Item() {
    }

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getItemDescription() {
        return this.itemDescription;
    }

    public void setItemDescription(String itemDescription) {
        this.itemDescription = itemDescription;
    }

    public String getItemName() {
        return this.itemName;
    }

    public void setItemName(String itemName) {
        this.itemName = itemName;
    }

    public double getItemPrice() {
        return this.itemPrice;
    }

    public void setItemPrice(double itemPrice) {
        this.itemPrice = itemPrice;
    }

}
  • Create folder src\main\webapp\WEB-INF\classes\META-INF and create a persistence.xml file.

    <?xml version="1.0" encoding="UTF-8"?>
    
    <persistence version="2.1"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
        <persistence-unit name="testPU" transaction-type="JTA">
            <jta-data-source>jdbc/SmallBiz</jta-data-source>
        </persistence-unit>
    </persistence>
    
    • See Understanding Persistence.xml in JPA for more information.

The RESTful Service Layer

  • Set the Maven Compiler to 1.7
    • Right click the pom.xml file and select Open With > Maven POM Editor. Add the following just before the closing tag.

xml snippet

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • Add dependencies using m2e for:
    • Servlet 3.1 (JAX-RS 2.0 requires this) "javax.servlet javax.servlet.api"
    • Jersey (for JAX-RS) "org.glassfish.jersey.core jersey-sever"
    • EJB (required to use the @Stateless annotation) "javax.ejb javax.ejb.api"
  • Create a POJO (plain old java object) and annotate it with JAX-RS annotations to create an endpoint.
    • @Path("/your-app-api-uri"): To indicate the path, relative to your server base uri, that a resource is located
    • @Produces ({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}): The representation produced can be json or xml.
    • @Consumes ({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}): The representation consumed can be json or xml
    • @Stateless: There server does not store state between interactions (this is one of the principles of the RESTful architecture).
  • Annotate methods that map to CRUD operations
    • @POST: Create
    • @GET: Read
    • @PUT: Update
    • @DELETE: Delete

The JAX-RS Service

package com.zangolie.smallbiz.services.rest;

import java.net.URI;
import java.util.Collection;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
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.core.Response;
import javax.ws.rs.core.UriInfo;

import com.zangolie.smallbiz.entities.Item;

@Path("/item")
@Produces ({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Consumes ({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Stateless
public class ItemRestService {
    //the PersistenceContext annotation is a shortcut that hides the fact
    //that, an entity manager is always obtained from an EntityManagerFactory.
    //The peristitence.xml file defines persistence units which is supplied by name
    //to the EntityManagerFactory, thus  dictating settings and classes used by the
    //entity manager
    @PersistenceContext(unitName = "testPU")
    private EntityManager em;

    //Inject UriInfo to build the uri used in the POST response
    @Context
    private UriInfo uriInfo;

    @POST
    public Response createItem(Item item){
        if(item == null){
            throw new BadRequestException();
        }
        em.persist(item);

        //Build a uri with the Item id appended to the absolute path
        //This is so the client gets the Item id and also has the path to the resource created
        URI itemUri = uriInfo.getAbsolutePathBuilder().path(item.getId()).build();

        //The created response will not have a body. The itemUri will be in the Header
        return Response.created(itemUri).build();
    }

    @GET
    @Path("{id}")
    public Response getItem(@PathParam("id") String id){
        Item item = em.find(Item.class, id);

        if(item == null){
            throw new NotFoundException();
        }

        return Response.ok(item).build();
    }

    //Response.ok() does not accept collections
    //But we return a collection and JAX-RS will generate header 200 OK and
    //will handle converting the collection to xml or json as the body
    @GET
    public Collection<Item> getItems(){
        TypedQuery<Item> query = em.createNamedQuery("Item.findAll", Item.class);
        return query.getResultList();
    }

    @PUT
    @Path("{id}")
    public Response updateItem(Item item, @PathParam("id") String id){
        if(id == null){
            throw new BadRequestException();
        }

        //Ideally we should check the id is a valid UUID. Not implementing for now
        item.setId(id);
        em.merge(item);

        return Response.ok().build();
    }

    @DELETE
    @Path("{id}")
    public Response deleteItem(@PathParam("id") String id){
        Item item = em.find(Item.class, id);
        if(item == null){
            throw new NotFoundException();
        }
        em.remove(item);
        return Response.noContent().build();
    }

}
  • Create an Application Class that defines the base uri. eg for http://localhost:8080/smallbiz/rest

    package com.zangolie.smallbiz.services.rest;
    
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    @ApplicationPath("rest")
    public class ApplicationConfig extends Application {
    
    }
    
  • Deploying to GlassFish from within Eclipse.

    • Right click the project Run As > Run on Server
    • Select the connected GlassFish server.
  • Test with any HTTP client (such as Postman which works in chrome).

Though the example uses GlassFish, any Java EE 7 compliant container will work. If you do use a different container (and assuming you use the same EclipseLink for JPA and Jersey for JAX-RS implementations), you will have to:

  • Sort out how to connect to it from Eclipse.
  • Change the Maven dependencies for Jersey and EclipseLink from provided to compile (since those are the implementations in GlassFish and may be different in other containers).

Hope it is helpful.


this might be doing exactly what you are looking for: http://restsql.org/doc/Overview.html

DISCLAIMER: I have never used it - just remembered seeing it recently in a news post.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号