本帖已转向:http://www.javaeye.com/topic/201103



大家好,今天向大家推荐一个轻量级的java rest 框架 JRest4Guice

项目地址: http://code.google.com/p/jrest4guice/

这个项目借鉴了http://www.javaeye.com/topic/170289的一些思想和代码。本人在此先谢了。

特点:
1. 基于GUICE

2. 零配置式服务声明
@Restful(uri = "/contacts")
public class ContactListRestService

3. 服务的自动扫描注册

4. 非侵入式风格,用户不需要实现特定的接口来实现Restful服务
用户只要在指定的POJO上:
1. 声明为@Restful,并指明访问的URI格式
2. 在指定的方法上声明为@HttpMethod

5. 支持Rest的Post. Get. Put. Delete操作
用户在指定的方法上通过@HttpMethod注解来声明方法的类型,如下:
@HttpMethod(type = HttpMethodType.POST)
public String createContact(String name, @RequestParameter("homePhone") String homePhone, @ModelBean Contact contact)

@HttpMethod
public String getContact(@FirstResult int first, @MaxResults int max)
注:如果没有提供HttpMethodType类型的声明,系统会自动根据方法名称的前缀来自动识别(方法名必须以get/post/put/delete开头)

6. 灵活的注入
6.1. 支持HttpServletRequest. HttpServletResponse. ModelMap的注入
@Inject
private ModelMap modelMap;

@Inject
private HttpServletRequest request;

@Inject
private HttpServletResponse response;

6.2. 支持参数的自动注入
方法中的参数可以由系统自动注入,如下:
public String createContact(String name, @RequestParameter("homePhone") String homePhone, @ModelBean Contact contact)
注:如果参数没有任何注解,系统默认获取上下文ID为参数名称的参数值,否则通过@RequestParameter注解指定的参数名称来获取,@ModelBean可以将上下文中的参数转换成指定参数类型的Java bean

6.3. 支持对JndiResource的注入


示例代码:
@Restful(uri = { "/contact", "/contact/{contactId}" })
public class ContactRestService {
	@Inject
	private ModelMap modelMap;

	@Inject
	private HttpServletRequest request;

	@Inject
	private HttpServletResponse response;

	@Inject
	@JndiResource(jndi = "test/ContactService")
	private ContactService service;

	@HttpMethod(type = HttpMethodType.POST)
	public String createContact(String name, @RequestParameter("homePhone") String homePhone, @ModelBean Contact contact) {
		if (contact == null)
			return HttpResult.createFailedHttpResult("-1","联系人信息不能为空").toJson();
		String contactId = null;
		try {
			contactId = this.service.createContact(contact);
			return HttpResult.createSuccessfulHttpResult(contactId).toJson();
		} catch (RemoteException e) {
			return HttpResult.createFailedHttpResult(e.getClass().getName(),e.getMessage()).toJson();
		}
	}

	@HttpMethod
	public String putContact(@RequestParameter("contactId")
	String contactId, @ModelBean
	Contact contact) {
		if (contactId == null)
			return HttpResult.createFailedHttpResult("-1","没有指定对应的联系人标识符").toJson();

		try {
			this.service.updateContact(contact);
			return HttpResult.createSuccessfulHttpResult("修改成功").toJson();
		} catch (RemoteException e) {
			return HttpResult.createFailedHttpResult(e.getClass().getName(),e.getMessage()).toJson();
		}
	}

	@HttpMethod
	public String getContact(@RequestParameter("contactId")
	String contactId) {
		try {
			Contact contactDto = this.service.findContactById(contactId);
			return HttpResult.createSuccessfulHttpResult(contactDto).toJson();
		} catch (Exception e) {
			return HttpResult.createFailedHttpResult(e.getClass().getName(),e.getMessage()).toJson();
		}
	}

	@HttpMethod
	public String deleteContact(@RequestParameter("contactId")
	String contactId) {
		try {
			this.service.deleteContact(contactId);
			return HttpResult.createSuccessfulHttpResult("删除成功").toJson();
		} catch (Exception e) {
			return HttpResult.createFailedHttpResult(e.getClass().getName(),e.getMessage()).toJson();
		}
	}
}
评论
agapple 2008-04-15
小建议一下, 能否像webwork一样,使用maven进行管理依赖

这样checkout就不需要下载额外的jar
cnoss 2008-03-29
最新动态


经过几天的奋战,我们团队又发布了一个基于Guice的JPA实现--Jpa4Guice 0.1 预览版,示例如下:

1、业务接口
@ImplementedBy(ContactServiceBean.class)
public interface ContactService {
	public String createContact(Contact contact) throws RemoteException;
	public List<Contact> listContacts(int first,int max) throws RemoteException;
	public Contact findContactById(String contactId) throws RemoteException;
	public void updateContact(Contact contact) throws RemoteException;
	public void deleteContact(String contactId) throws RemoteException;
}


2、业务实现
public class ContactServiceBean implements ContactService {
	@Inject
	private EntityManager entityManager;//JPA实体管理器的注入

	@Transactional//事务声明
	public String createContact(Contact contact) throws RemoteException {
		if (contact == null)
			throw new RemoteException("联系人的内容不能为空");
		
		if(this.entityManager.createNamedQuery("byName").setParameter("name", contact.getName()).getResultList().size()>0){
			throw new RemoteException("联系人的姓名相同,请重新输入");
		}

		this.entityManager.persist(contact);
		return contact.getId();
	}

	@Transactional//事务声明
	public void deleteContact(String contactId) throws RemoteException {
		Contact contact = this.findContactById(contactId);
		if (contact == null)
			throw new RemoteException("联系人不存在");

		this.entityManager.remove(contact);
	}

	@Transactional//事务声明
	public Contact findContactById(String contactId) throws RemoteException {
		return this.entityManager.find(Contact.class, contactId);
	}

	@Transactional//事务声明
	public List<Contact> listContacts(int first, int max)
			throws RemoteException {
		return this.entityManager.createNamedQuery("list").setFirstResult(first)
				.setMaxResults(max).getResultList();
	}

	@Transactional//事务声明
	public void updateContact(Contact contact) throws RemoteException {
		if (contact == null)
			throw new RemoteException("联系人的内容不能为空");

		this.entityManager.merge(contact);
	}
}


3、Rest的控制类
@Restful(uri = { "/contact", "/contact/{contactId}" })
public class ContactController {
@Inject
private ContactService service;//注入的业务接口

@HttpMethod(type = HttpMethodType.POST)
public String createContact(String name, @RequestParameter("homePhone") String homePhone, @ModelBean Contact contact) {}

...
...
}

===========================================
我们会在下一个版本中增加动态DAO的支持
===========================================

注:
1、由于最近的更新比较频繁,所以没有打包,有需要的朋友请从SVN上直接下载原代码,源代码中有详细的例子。
2、示例已经可以运行jboss/tomcat/jetty服务器上,已经完全脱离了EJB环境。

谢谢大家的参与和批评。

-- cnoss小组
ajoo 2008-03-29
不错。我也不确定我对资源的理解是不是准确。只不过我觉得不绑HttpMethod的话,你可以有灵活性,想domain就domain,想service就service。

另外,不是强迫整合,而是说,嵌入能力是一个比较好的特性。不能嵌入,而非得从头到尾用你的框架就有些局限罢了。
y_franky 2008-03-28
ajoo 写道
不绑@HttpMethod,那么一般通过url映射的就是Contact这种domain model,也就是rest的资源的概念。

而绑了@HttpMethod,那么写的就是你例子中的ContactService的这种服务模型。

那么前者怎么处理put/create/get呢?

很灵活,可以用你提出的Restable的接口,但是这个接口不是框架定义的,而是客户自己定义的,然后客户就这么调用:
Restable restable = resourceLocator.getResource(path, Restable.class);
restable.get();


也可以,干脆不搞什么接口。比如我的应用还是传统的servlet或者struts action。只想在某个servlet里面嵌入rest的url映射,那么在某个FooServlet的doGet()里面,我就这么做:
Foo foo = resourceLocator.getResource(request.getPathInfo(), Foo.class);
response.getWriter().write(foo.getName());


而如果绑了@HttpMethod,框架做的事情更多,更大,更复杂,但是客户程序的灵活性就低了,你只能针对服务模型设计,必须在FooService里面处理get/put,而不能交给系统别的部分去做。

所以我觉得,除非@HttpMethod有特别突出的优点是domain model提供不了的,还是不要强迫客户走这个服务模型。



嗯,我大概明白你的想法了,理由确实也是很充分的。不过有些地方,我的看法与你有些不同。

1、对REST上资源的理解,我不认为它必须与Domain Model对应,我只会把它们看为有固定结构的数据体,当然它们也可以和Domain Model对应,但更多时候它们可能只是某种数据视图。所以我只会把它们看成是某种有含义受约束的URI,而不会将它们和Domain Model画等号。

2、由于有第一点的观点,所以我认为REST内资源的(GET, POST, PUT, DELETE)的含义是可由应用定义的,也不一定需要全部实现。

3、至于和其它MVC整合,我觉得不需要强迫要在其它MVC内完成REST的工作,两者完全可以在URI级就很好地分离开。对于某些需要公用的东西,则可以通过应用的上下文共享。
ajoo 2008-03-28
不绑@HttpMethod,那么一般通过url映射的就是Contact这种domain model,也就是rest的资源的概念。

而绑了@HttpMethod,那么写的就是你例子中的ContactService的这种服务模型。

那么前者怎么处理put/create/get呢?

很灵活,可以用你提出的Restable的接口,但是这个接口不是框架定义的,而是客户自己定义的,然后客户就这么调用:
Restable restable = resourceLocator.getResource(path, Restable.class);
restable.get();


也可以,干脆不搞什么接口。比如我的应用还是传统的servlet或者struts action。只想在某个servlet里面嵌入rest的url映射,那么在某个FooServlet的doGet()里面,我就这么做:
Foo foo = resourceLocator.getResource(request.getPathInfo(), Foo.class);
response.getWriter().write(foo.getName());


而如果绑了@HttpMethod,框架做的事情更多,更大,更复杂,但是客户程序的灵活性就低了,你只能针对服务模型设计,必须在FooService里面处理get/put,而不能交给系统别的部分去做。

所以我觉得,除非@HttpMethod有特别突出的优点是domain model提供不了的,还是不要强迫客户走这个服务模型。
y_franky 2008-03-28
ajoo 写道
还是不喜欢@HttpMethod。

为什么需要它呢?难道简单的这样不好么?

Contact contact = resourceLocator.getResource(path, Contact.class);
contactRepository.addContact(contact);


为什么非要把rest method绑在pojo里?


注解的方式是把资源看成是URI的映射,如果把资源看成是具体的类,虽然说可以通过超类继承很多基础方法,但带来的是对类的扩展无法更方便的支持。

如果不使用@HttpMethod,也许我们会这样:
1、让每个Rest 服务必须要实现一个特定的接口,如:
public interface RestAble{
    public void get();
    public void post();
    public void put();
    public void delete();
}


2、通过一种方法名的约束,让具体的Rest方法前必须以类似get/post/put/delete的前缀

而引入@HttpMethod,可以:
1、从平台特定的API中解放出来,不要实现任何带限制的接口,就像EJB2.0那样要求每个EJB实现home/remote接口一样。
2、不会限制用户的业务方法的命名,如下:
public void registUser(....);
public void postUser(....);


以下两种方式,哪一种各能让用户接受呢?
ajoo 2008-03-27
还是不喜欢@HttpMethod。

为什么需要它呢?难道简单的这样不好么?

Contact contact = resourceLocator.getResource(path, Contact.class);
contactRepository.addContact(contact);


为什么非要把rest method绑在pojo里?
backbase 2008-03-27
学习中 ,永远支持你 ,谢谢发表好的知识。
cnoss 2008-03-27
不想用SVN的朋友可以直接下载这个压缩包,里面包含了例子
发表评论

提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则

您还没有登录,请登录后发表评论

cnoss
搜索本博客
博客分类
最近加入圈子
最新评论