问题描述
更新提供的实体的 EJB 方法(使用 CMT):
The EJB method (using CMT) that updates an entity supplied :
@Override
@SuppressWarnings("unchecked")
public boolean update(Entity entity) throws OptimisticLockException {
// Code to merge the entity.
return true;
}
这将抛出 javax.persistence.OptimisticLockException
,如果检测到并发更新将由调用者(托管 bean)精确处理.
This will throw the javax.persistence.OptimisticLockException
, if concurrent update is detected which is to be handled precisely by the caller (a managed bean).
public void onRowEdit(RowEditEvent event) {
try {
service.update((Entity) event.getObject())
} catch(OptimisticLockException e) {
// Add a user-friendly faces message.
}
}
但这样做会使 javax.persistence
API 额外依赖表示层,这是一种导致紧耦合的设计味道.
But doing so makes an additional dependency from the javax.persistence
API on the presentation layer compulsory which is a design smell leading to tight-coupling.
它应该包含在哪个异常中,以便可以完全忽略紧耦合问题?或者有没有一种标准的方法来处理这个异常,从而不会导致在表示层上强制执行任何服务层依赖?
In which exception should it be wrapped so that the tight-coupling issue can be omitted in its entirely? Or is there a standard way to handle this exception which in turn does not cause any service layer dependencies to be enforced on the presentation layer?
推荐答案
创建一个自定义的服务层特定的运行时异常,用 @ApplicationException
和 rollback=true
.
Create a custom service layer specific runtime exception which is annotated with @ApplicationException
with rollback=true
.
@ApplicationException(rollback=true)
public abstract class ServiceException extends RuntimeException {}
为一般业务异常创建一些具体的子类,例如违反约束、必需的实体,当然还有乐观锁.
Create some concrete subclasses for general business exceptions, such as constraint violation, required entity, and of course optimistic lock.
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();
}
// ...
}
其中一些需要全局拦截器.
Some of them need a global interceptor.
@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上)如下.
Which is registered as default interceptor (on all EJBs) as below in ejb-jar.xml
.
<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 消息.从这个启动示例开始时,你可以在 YourExceptionHandler#handle()
方法中做这样的事情:
As a general hint, in JSF you can also have a global exception handler which just adds a faces message. When starting with this kickoff example, you could do something like this in YourExceptionHandler#handle()
method:
if (exception instanceof EntityAlreadyModifiedException) { // Unwrap if necessary.
// Add FATAL faces message and return.
}
else {
// Continue as usual.
}
这篇关于让表示层 (JSF) 处理来自服务层 (EJB) 的业务异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!