<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function(){
$('#username').blur(function(){
$.post('service/examuser/exists.json',{"username":$(this).val()},function(data){
if(data==’true’){
alert('已经存在');
}
});
});
});
</script>
在实际开发过程中总会有
ajax
验证数据的需求。
AJAX
服务器端可以用各种技术实现,
jsp
,
servlet
,
JAX-RS
都行,但是最好用的还是
JAX-RS
。
JAX-RS
做
AJAX
返回
JSON
相当方便,另外取请求数据的时候也相当地方便。
Ajax代码的添加相当简单,加点js就可以了。
这是一个简单的验证,只是alert了一下。
服务层自然是使用JPA技术:
@ApplicationScoped
@Named
public class UserExistService {
@PersistenceContext
private EntityManager em;
public boolean exists(String username){
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<ExamUser> query = criteriaBuilder.createQuery(ExamUser.class);
Root<ExamUser> root = query.from(ExamUser.class);
query.where(criteriaBuilder.equal(root.get("username"), username));
TypedQuery<ExamUser> typedQuery = em.createQuery(query);
return !typedQuery.getResultList().isEmpty();
}
}
CriteriaBuilder是JPA构建安全查询的一个类。它用来创建查询类,用来创建约束条件。
criteriaBuilder.createQuery(ExamUser.class);就是用来创建查询类的,这个查询类可以转换为TypedQuery。criteriaBuilder.equal就是用来创建约束条件的。
Root<ExamUser>其实相当于SQL from后面的东西,可以认为是对表的抽象。
Query用来添加查询条件,并通过TypedQuery提交给实体管理器。
这仅仅是做了一个服务,还需要做一个rest资源类。因为MVC思想,负责路由的rest资源类就不直接注入EntityManager,而是直接注入刚才写好的service。
REST环境的搭建就是写一个类继承自Application 。因为rest服务不能拦截所有的URL,这样会影响到servlet,所以在注解中需要配置一个前缀。
@ApplicationPath("/service")
public class ExamApplication extends Application {
}
REST服务器是支持子资源的。所谓的子资源就是根资源通过URL路由选择子资源类来处理请求。
先介绍下根资源类。这个类它具有两种角色,因为加了@Path注解,所以成为了一个REST资源类。
@RequestScoped
@Path("/examuser")
public class ExamUserResource {
@Context
private ResourceContext resourceContext;
@Path("/")
public ExistingResource exist() {
return resourceContext.getResource(ExistingResource.class);
}
}
REST是有上下文的,CDI也有自己的上下文,如果仅仅是这样加注解,两个上下文是隔开的,也就是两个容器是隔开的。自然不能在资源类里取到CDI的对象。而CDI上下文里的资源类对象,浏览器也根本访问不到。
这个时候就需要配置了。
在web.xml中配置以下这一项内容就可以了。
<context-param>
<param-name>resteasy.injector.factory</param-name>
<param-value>org.jboss.resteasy.cdi.CdiInjectorFactory</param-value>
</context-param>
因为wildfly服务器使用了resteasy-cdi插件,这个插件会读取
Resteasy.injector.factory的配置,然后就可以将两个上下文进行融合,也就是将REST的上下文并入CDI上下文中,让CDI对象来充当REST资源类。
@Context是REST的注解,注入的是REST的资源上下文,通过这个资源上下文找到其余的rest资源,作为子资源进行返回,exist就是一个简单的路由方法。
@RequestScoped
public class ExistingResource {
@Inject
private UserExistService userExistService;
@POST
@Path("/exists.json")
@Produces("text/plain")
public String exist(@FormParam("username") String username){
return userExistService.exists(username)+"";
}
}
ExistingResource 是一个子资源类,与根资源类不同的是,子资源类不需要加@Path注解,因为它是通过根资源类的路由来指定URL的。所以看起来就是个CDI对象,但是还是加了REST的注解的,比如@POST和@Path("/exists.json")@Produces("text/plain")。
Text/plain注解是指定返回的MIME类型的。@POST注解是限定了只接收POST请求。
至此,整个就做完了。这个小功能涉及的技术比较多,有REST,CDI,JPA和RESTEASY-CDI。