我有资源类,它本身与内部服务进行对话。此资源用作服务的rest API。服务层可能会抛出意外异常,因此资源应该处理那些处理了意外异常并记录它们。我正在使用dropwizard框架,后者又使用了球衣。它是这样的。
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
try {
User user = service.getUser(userId);
return Response.ok(user).build();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(moe.getMsg()).build();
}
}
这里的问题是我必须为每个REST api端点执行完全相同的异常处理。我可以为此特定资源执行某种异常映射,以便我可以将所有处理逻辑和日志记录放在那里吗? 我知道我可以为球衣中的特定异常构建一个映射器,但这对于整个模块而言不是一个单独的类。
答案 0 :(得分:3)
为什么不将异常处理分解为私有方法?
@PATH(/user)
@GET
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return handleExceptions(() -> {
User user = service.getUser(userId);
return Response.ok(user).build();
});
}
private Response handleExceptions(Callable<Response> callable) {
try {
return callable.call();
}
catch (MyOwnException moe) { //basically 400's
return Response.status(400).entity(moe.getMsg()).build();
}
catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
答案 1 :(得分:3)
您无法向资源方法注册ExceptionMapper
。我通过实施DynamicFeature
来寻找自定义注释,然后尝试使用ExceptionMapper
注册自定义FeatureContext
来尝试此操作。
结果是幻想破灭:
WARNING: The given contract (interface javax.ws.rs.ext.ExceptionMapper) of class path.to.CustomExceptionMapper provider cannot be bound to a resource method.
可能不起作用:
<击>但是...... 击>
对于资源类,这实际上很简单。只需在ExceptionMapper
内为您的资源类注册ResourceConfig
即可。对我来说,它看起来像:
@ApplicationPath("/")
public class ApplicationResourceConfig extends ResourceConfig {
public ApplicationResourceConfig() {
// [...]
register(YourExceptionMapper.class, YourResource.class);
// [...]
}
}
因此,如果你可以在资源类级别上使用它,那就这样做吧。
击>
否则你可能需要使用Aspects (但我没有看到任何理由这样做) 。例如:
@Aspect
public class ResourceAspect {
Logger logger = [...]
private static final String RESOURCE = "execution(public !static javax.ws.rs.core.Response path.to.resources..*(..)) && @annotation(path.to.HandleMyOwnException)";
@Around(RESOURCE)
public Object translateRuntimeException(ProceedingJoinPoint p) throws Throwable {
try {
return p.proceed();
} catch (MyOwnException moe) {
return Response.status(400).entity(moe.getMsg()).build();
} catch (Exception e) { //unexpected exceptions
logger.debug(e.getMessage);
return Response.status(500).entity(e.getMessage()).build();
}
}
}
请注意,RESOURCE
配置。这适用于none static
下的path.to.resources
方法,这些方法返回Response
并使用HandleMyOwnException
注释进行了语音处理。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleMyOwnException {}
@GET
@PATH("/user")
@HandleMyOwnException
public Response getUser(@QueryParam("id") String userId) {
assertNotNull(userId);
return Response.ok(service.getUser(userId)).build();
}
<!-- deps -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.2</version> <!-- or newer version -->
</dependency>
<!-- build plugins -->
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<versionRange>[1.7,)</versionRange>
<goals>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
<plugins>
<pluginManagement>
度过美好的一天!
〜添加了更完整的pom.xml配置
〜更正了ResourceAspect中注释的缺失路径