让表示层(JSF)处理来自服务层(EJB)的业务异常
更新提供的实体的EJB方法(使用CMT):
@Override @SuppressWarnings("unchecked") public boolean update(Entity entity) throws OptimisticLockException { // Code to merge the entity. return true; } 如果检测到并发更新,则将抛出javax.persistence.OptimisticLockException,该更新将由调用者(托管bean)精确处理. public void onRowEdit(RowEditEvent event) { try { service.update((Entity) event.getObject()) } catch(OptimisticLockException e) { // Add a user-friendly faces message. } } 但这样做会对表示层上的javax.persistence API产生额外的依赖性,这是一种导致紧耦合的设计气味. 应该包装哪个例外,以便完全省略紧耦合问题?或者是否有一种标准方法来处理此异常,这反过来又不会导致在表示层上强制执行任何服务层依赖性? 顺便说一句,我发现在EJB中(在服务层本身上)捕获此异常然后向客户端(JSF)返回一个标志值是笨拙的. 解决方法
创建一个特定于自定义服务层的运行时异常,该异常使用带有rollback = true的
@ApplicationException 进行批注.
@ApplicationException(rollback=true) public abstract class ServiceException extends RuntimeException {} 为一般业务异常创建一些具体的子类,例如约束违规,必需实体,当然还有乐观锁. public class DuplicateEntityException extends ServiceException {} public class EntityNotFoundException extends ServiceException {} public class EntityAlreadyModifiedException extends ServiceException {} 其中一些可以直接抛出. public void register(User user) { if (findByEmail(user.getEmail()) != null) { throw new DuplicateEntityException(); } // ... } public void addToOrder(OrderItem item,Long orderId) { Order order = orderService.getById(orderId); if (order == null) { throw new EntityNotFoundException(); } // ... } 其中一些需要全局拦截器. @Interceptor public class ExceptionInterceptor implements Serializable { @AroundInvoke public Object handle(InvocationContext context) throws Exception { try { return context.proceed(); } catch (javax.persistence.EntityNotFoundException e) { // Can be thrown by Query#getSingleResult(). throw new EntityNotFoundException(e); } catch (OptimisticLockException e) { throw new EntityAlreadyModifiedException(e); } } } 在ejb-jar.xml中注册为默认拦截器(在所有EJB上),如下所示. <interceptors> <interceptor> <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class> </interceptor> </interceptors> <assembly-descriptor> <interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>com.example.service.ExceptionInterceptor</interceptor-class> </interceptor-binding> </assembly-descriptor> 作为一般提示,在JSF中,您还可以拥有一个全局异常处理程序,它只添加一个faces消息.从this kickoff example开始,您可以在YourExceptionHandler#handle()方法中执行以下操作: if (exception instanceof EntityAlreadyModifiedException) { // Unwrap if necessary. // Add FATAL faces message and return. } else { // Continue as usual. } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |