利用GAE构建第一个REST风格的java webservice
1. 配置好你的Eclipse GAE开发环境
2. 测试一下你的GAE环境的配置是否正确。写个HelloWorld发布一下试试。
3. 让我们开始
? 利用GAE建一个gaeRest项目.记得把use google web toolkit勾去
项目如下
注意,droidinvokeRest是客户端调用的例子,现在先不管。下载RestEasy 框架http://sourceforge.net/projects/resteasy/files/Resteasy%20JAX-RS/注意,2.2.2.GA该版本在使用过程时会出现java.lang.IllegalAccessException: Reflection is not allowed on protected final java.lang.Class 错误。我使用了2.0.0.GA,虽然版本比较老,但是无论是本地发布还是正式发布都没有问题。为此问题,我也纠结了许久。最终在google app engine 官方开发论坛上找到答案。下载后,将里边的所有jar包拷贝到当前项目的war\web-inf\lib文件中(记得不这样做,会运行会报错。。),然后创建userlibray,链接到该lib路径,添加这些包的引用。? 创建数据实体,Book类,同时使用jaxb 注解,以用于对象序列化为 xml。关于jaxb你可以在网上找到相关资料。代码如下
2
3 import javax . xml . bind . annotation . XmlElement;
4 import javax . xml . bind . annotation . XmlRootElement;
5
6 @XmlRootElement(name = " book " )
7 public class Book {
8 private String name;
9 private String content;
10
11 public Book() {
12 }
13
14 public Book(String name, String content) {
15 this . name = name;
16 this . content = content;
17 }
18
19 @XmlElement
20 public String getName() {
21 return name;
22 }
23
24 public void setName(String name) {
25 this . name = name;
26 }
27
28 @XmlElement
29 public String getContent() {
30 return content;
31 }
32
33 public void setContent(String content) {
34 this . content = content;
35 }
36 }
37
? 创建服务类Library,里边用来处理客户端的请求。使用@Path标注来标识资源路径。请求该路径时就会执行该方法。代码如下
2
3 import javax . ws . rs . * ;
4 import java . util . * ;
5 import javax . ws . rs . core . * ;
6
7 @Path( " /library " )
8 public class Library {
9
10 /* *
11 * 利用books来模拟数据存储区
12 * 在构造函数中添加数据
13 */
14 public static List < Book > books = new ArrayList < Book > ();
15 static {
16 books . add( new Book( " huhu " , " huhu " ));
17 books . add( new Book( " haha " , " haha " ));
18 }
19
20 /* *
21 * 获得所有的book列表
22 * @return
23 */
24 @GET
25 @Produces( { MediaType . APPLICATION_ATOM_XML, MediaType . APPLICATION_JSON } ) // 设定返回的数据类型 xml 格式和json格式
26 @Path( " /books " ) // 资源的相对路径
27 public List < Book > listBooks() {
28 return books;
29 }
30
31 /* *
32 * 获得指定id的书籍信息
33 * @param id
34 * @return
35 */
36
37 @GET
38 @Produces( { MediaType . APPLICATION_XML,MediaType . APPLICATION_JSON } )
39 @Path( " /book/{id} " )
40 public Book getBook(@PathParam( " id " ) String id) { // 将传入的id赋值给di
41 if ( " 1 " . equals(id))
42 return new Book( " huhu " , " huhu " );
43 else
44 return new Book( " haha " , " haha " );
45 }
46
47 /* *
48 * 利用put提交方式进行数据更新
49 * @param book
50 */
51 @PUT
52 @Path( " /book/{name} " )
53 public void updateBook(@PathParam( " name " ) PathSegment book) {
54 Iterator < Book > it = books . iterator();
55 String name = String . valueOf(book . getMatrixParameters() . get( " name " ));
56 String content = String . valueOf(book . getMatrixParameters() . get(
57 " content " ));
58 while (it . hasNext()) {
59 Book booktmp = it . next();
60 if (name . equals(booktmp . getName())) {
61 booktmp . setContent(content);
62 break ;
63 }
64 }
65 }
66
67 /* *
68 * 利用post方式进行数据增加
69 * @param name
70 * @param content
71 */
72 @POST
73 @Path( " /book/{name}/{content} " )
74 public void addBook(@PathParam( " name " ) String name,
75 @PathParam( " name " ) String content) {
76 books . add( new Book(name, content));
77 }
78
79 @DELETE
80 @Path( " /book/{name} " )
81 public void deleteBookByName(@PathParam( " name " ) String name) {
82 Iterator < Book > iterator = books . iterator();
83 while (iterator . hasNext()) {
84 Book book = iterator . next();
85 if (name . equals(name)) {
86 iterator . remove();
87 }
88 }
89 }
90 }
91
? 创建Application,类名 EasyRestApplication告知有哪些应用。继承与javax.ws.rs.core.Application代码如下
2
3 import java . util . * ;
4 import javax . ws . rs . core . Application;
5 import org . jboss . resteasy . plugins . server . servlet . ResteasyBootstrap;
6
7 public class EasyRestApplication extends Application {
8
9 HashSet < Object > singletons = new HashSet < Object > ();
10
11 public EasyRestApplication() {
12 singletons . add( new Library());
13 }
14
15 @Override
16 public Set < Class < ? > > getClasses() {
17 HashSet < Class < ? > > set = new HashSet < Class < ? > > ();
18 // set.add(Library.class);
19 return set;
20 }
21
22 @Override
23 public Set < Object > getSingletons() {
24 return singletons;
25 }
26 }
27
? 接下来还要配置war文件夹中的web.xml添加配置如下
2 < context-param >
3 < param-name > javax.ws.rs.Application < /param-name >
4 < param-value > henu.cjt.webservice.EasyRestApplication < /param-value >
5 < /context-param >
6 < context-param >
7 < param-name > resteasy.servlet.mapping.prefix < /param-name >
8 < param-value > /gaerest < /param-value >
9 < /context-param >
10 < listener >
11 < listener-class > org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap < /listener-class >
12 < /listener >
13 < servlet >
14 < servlet-name > GaeRest < /servlet-name >
15 < servlet-class > org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher < /servlet-class >
16 < /servlet >
17 < servlet-mapping >
18 < servlet-name > GaeRest < /servlet-name >
19 < url-pattern > /gaerest/* < /url-pattern >
20 < /servlet-mapping >
上述工作完成后,就可以点击运行了。然后在浏览器中输入地址(如果你使用代理上网,你可能接受不到数据。。把代理去掉。)http://localhost:8888/gaerest/library/books你可以接受到如下内容
本地发布成功。
正式发布
在https://appengine.google.com/登录后,创建相应的应用后。 然后点击Eclipse中的GAE发布按钮
如果没有登录google 账户,会提示你登陆接下来填写project名字时候,记得填写名字需要是你在google上创建的应用的名字。
而且该改名字你需要配置在 appengine-web-xml中, <application>cjtmobiles</application>。虽然,这一点已经超出了本文章的讲述范围,但是我还是愿意你能够顺利的发布。
发布成功后,你可以访问http://cjtmobiles.appspot.com/gaerest/library/books ,当然,cjtmobiles是我创建的应用的名字,记得改成你的。查看结果。
如果出现500内部server错误,你可以通过点击查看相应的日志
如果出现如下错误Caused by: java.lang.IllegalAccessException: Reflection is not allowed on protected final java.lang.Class java.lang.ClassLoader.findLoadedClass(java.lang.String)那么就是上边我说的RestEasy版本的问题,其实是其中jaxb的版本问题。我用jaxb 2.1.12也就是resteasy2.0.0 解决了这个问题。访问http://cjtmobiles.appspot.com/gaerest/library/books 成功返回相应数据后,恭喜你,你的服务端模型算是完成了
你也可使用cURL简单测试restful web service来使用各种提交方式,进行测试。
接下来,我们可以写一个简单的android客户端,模拟调用。
本文转自HDDevTeam 51CTO博客,原文链接:http://blog.51cto.com/hddev/662621,如需转载请自行联系原作者