研究了兩天CXF對restful的支持。
現在,想實現一個以
http://localhost:9999/roomservice 為入口,
http://localhost:9999/roomservice/room為房間列表,
http://localhost:9999/roomservice/room/001/ 為001號房間的信息,
http://localhost:9999/roomservice/room/001/person 為在001號房間主的人的列表
實現用HTTP請求對以上資源的CRUD。
首先建立room,person的POJO,這里只有一點需要注意:
package com.DAO; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="Person") public class Person { private String name; private String sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
一定要在類的前邊加上annotation ,這樣才能讓這個person的信息在POJO和XML之間轉換。Room同理:
import java.util.Map; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="Room") public class Room { public Room() { persons=new HashMap<String,Person>(); } String id; Map<String,Person> persons; public String getId() { return id; } public void setId(String id) { this.id = id; } public Map<String, Person> getPersons() { return persons; } public void setPersons(Map<String, Person> persons) { this.persons = persons; } }
POJO有了,接下來要寫DAO,由於主要是為了學習restful,為了方便,不必要將數據持久化到數據庫,而是存在一個靜態的HashMap中:
package com.DAO; import java.util.HashMap; import java.util.Map; public class RoomDAO { private static Map<String, Room> rooms; static { rooms = new HashMap<String, Room>(); Person p1=new Person(); p1.setName("Boris"); p1.setSex("male"); Room r=new Room(); r.setId("001"); r.getPersons().put(p1.getName(), p1); rooms.put("001", r); } public static void addRoom(Room room) { rooms.put(room.getId(), room); } public static void deleteRoom(String id) { if (rooms.containsKey(id)) { rooms.remove(id); } } public static void updateRoom(String id,Room room) { rooms.remove(id); rooms.put(room.getId(), room); } public static Room getRoom(String id) { if (rooms.containsKey(id)) { return rooms.get(id); } else { return null; } } /*operations to persons*/ public static void addPerson(String id_room,Person person) { if(rooms.containsKey(id_room)) { Room room=rooms.get(id_room); room.getPersons().put(person.getName(), person); } } public static Rooms getRooms() { return new Rooms(); } public static void deletePerson(String id_room,String name) { if(rooms.containsKey(id_room)) { Room room=rooms.get(id_room); room.getPersons().remove(name); } } public static Map<String, Room> getMapOfRooms() { return rooms; } }
接下來是重點,如果想發布restful webservice,要通過一個叫JAXRSServerFactoryBean的類來發布。這個類有幾個方法是要了解的:
public void setResourceClasses(Class... classes);
那一系列的Class類型的參數,是告訴這個類,發布服務時,會用到的POJO(就像上邊寫的Room,Person)。
public void setAddress(String address);
這個方法是告訴這個類,服務的地址,比如"http://localhost:9999"
public void setServiceBeans(Object... beans)
這里是重點,這個方法,要給這個用來發布服務的類一個Service bean.這個Bean是我們要手動編寫的,作用是告訴服務,收到什么樣的請求,應該怎么樣處理。
現在,先來編寫這個Service bean:
package com.server; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; 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 com.DAO.Person; import com.DAO.Room; import com.DAO.RoomDAO; import com.DAO.Rooms; @Path("/roomservice") @Produces("application/xml") public class RoomService { @GET @Path("/room/{id}") @Consumes("application/xml") public Room getRoom(@PathParam("id")String id ) { System.out.println("get room by id= "+id); Room room=RoomDAO.getRoom(id); return room; } @GET @Path("/room") @Consumes("application/xml") public Rooms getAllRoom() { System.out.println("get all room"); Rooms rooms=RoomDAO.getRooms(); return rooms; } @POST @Path("/room") @Consumes("application/xml") public void addRoom(Room room) { System.out.println("add room which id is:"+room.getId()); RoomDAO.addRoom(room); } @PUT @Path("/room/{id}") @Consumes("application/xml") public void updateRoom(@PathParam("id")String id,Room room) { System.out.println("update room which original id is:"+room.getId()); RoomDAO.updateRoom(id,room); } @DELETE @Path("/room/{id}") @Consumes("application/xml") public void deleteRoom(@PathParam("id")String id) { System.out.println("remove room by id= "+id); RoomDAO.deleteRoom(id); } @POST @Path("/room/{id}") @Consumes("application/xml") public void addPerson(@PathParam("id") String id,Person person) { System.out.println("add person who's name is:"+person.getName()); RoomDAO.addPerson(id, person); } @DELETE @Path("/room/{id}/{name}") @Consumes("application/xml") public void deletePerson(@PathParam("id")String id,@PathParam("name")String name) { System.out.println("remove person who's name is: "+name); RoomDAO.deletePerson(id, name); } }
需要注意:每個方法之前,要用annotation聲明http請求的method類型,比如GET,DELETE,POST, PUT.
@Produces("application/xml")我還沒弄清楚到底是聲明的接受格式還是返回格式,還是其他。
@Path("/room/{id}")中的id是一個參數,應該在方法的參數列表中聲明:
public void deletePerson(@PathParam("id")String id,@PathParam("name")String name)
這樣就能得到URL中的id了。
現在,這些房間被資源化了,id為001的房間被資源化為一個URL,那地址應該是
http:{服務器地址}:{端口}/roomservice/rrom/001
現在,創建一個Server:
package com.server; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import com.DAO.Person; import com.DAO.Room; import com.DAO.Rooms; public class Server { public static void main(String[] args) { RoomService service = new RoomService(); // Service instance JAXRSServerFactoryBean restServer = new JAXRSServerFactoryBean(); restServer.setResourceClasses(Room.class,Person.class,Rooms.class); restServer.setServiceBeans(service); restServer.setAddress("http://localhost:9999/"); restServer.create(); } }
現在,服務已經發布成功了,在瀏覽器輸入http://localhost:9999/roomservice/room/001 得到結果:
<room> <id>001</id> − <persons> − <entry> <key>Boris</key> − <value> <name>Boris</name> <sex>male</sex> </value> </entry> </persons> </room>
如果用瀏覽器去訪問,發送的http請求只能所GET,因此如果想對數據進行操作,必須寫一個客戶端。
在寫客戶端之前,有一個問題:
在瀏覽器輸入http://localhost:9999/roomservice/room/
什么都看不到,可是,我想要得到房間列表。但是,cxf發布restful只認你給他的類的class。所以你想讓服務器返回一個room的列表給客戶端,是不行的。所以,必須想別的辦法,我是又寫了一個POJO,這個POJO里只有一個屬性,就是一個存放所有room的Map:
package com.DAO;
import java.util.Map; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name="rooms") public class Rooms { Map<String,Room> rooms; public Rooms() { rooms=RoomDAO.getMapOfRooms(); } public Map<String, Room> getRooms() { return rooms; } public void setRooms(Map<String, Room> rooms) { this.rooms = rooms; } }
這樣,然后再把DAO的方法加上:
@GET @Path("/room") @Consumes("application/xml") public Rooms getAllRoom() { System.out.println("get all room"); Rooms rooms=RoomDAO.getRooms(); return rooms; }
這樣就能以list的形式顯示出所有room了。
訪問http://localhost:9999/roomservice/room/
結果如下:
<rooms> − <rooms> − <entry> <key>006</key> − <value> <id>006</id> <persons/> </value> </entry> − <entry> <key>001</key> − <value> <id>001</id> − <persons> − <entry> <key>Boris</key> − <value> <name>Boris</name> <sex>male</sex> </value> </entry> </persons> </value> </entry> </rooms> </rooms>