<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。