JaxRS中@QueryParam绑定Long类型参数的非数字输入异常处理
处理JAX-RS中Long类型QueryParam的非数字参数异常
当请求传入非数字类型的id参数时,JAX-RS会在参数转换阶段抛出BadRequestException(或对应实现的子类,如Resteasy的ReaderException),原因是无法将字符串转换为Long类型。以下是两种无需将Long改为String的解决方案:
方案一:自定义异常映射器(ExceptionMapper)
通过实现ExceptionMapper接口捕获参数转换异常,返回友好的错误响应。
通用BadRequestException映射器
适用于大多数JAX-RS实现(如Jersey):
import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; @Provider public class BadRequestExceptionMapper implements ExceptionMapper<BadRequestException> { @Override public Response toResponse(BadRequestException exception) { // 精准匹配Long转换失败的场景 if (exception.getCause() instanceof NumberFormatException) { return Response.status(Response.Status.BAD_REQUEST) .entity("参数id必须为有效的数字类型") .build(); } // 处理其他请求参数错误场景 return Response.status(Response.Status.BAD_REQUEST) .entity("请求参数格式错误") .build(); } }
Resteasy专属ReaderException映射器
如果使用Resteasy框架,参数转换失败会抛出ReaderException,可针对性处理:
import org.jboss.resteasy.spi.ReaderException; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; @Provider public class ReaderExceptionMapper implements ExceptionMapper<ReaderException> { @Override public Response toResponse(ReaderException exception) { if (exception.getCause() instanceof NumberFormatException) { return Response.status(Response.Status.BAD_REQUEST) .entity("参数id必须为有效的数字类型") .build(); } return Response.status(Response.Status.BAD_REQUEST).build(); } }
说明:添加@Provider注解后,JAX-RS会自动注册该映射器,异常发生时自动触发响应处理。
方案二:自定义参数转换器(ParamConverter)
在参数转换阶段直接校验并处理异常,实现更精细的控制。
实现Long参数转换器及提供者
import jakarta.ws.rs.ext.ParamConverter; import jakarta.ws.rs.ext.ParamConverterProvider; import jakarta.ws.rs.ext.Provider; import java.lang.annotation.Annotation; import java.lang.reflect.Type; // 自定义Long类型转换器 public class LongParamConverter implements ParamConverter<Long> { @Override public Long fromString(String value) { if (value == null) { return null; } try { return Long.parseLong(value); } catch (NumberFormatException e) { // 转换失败直接抛出BadRequestException throw new jakarta.ws.rs.BadRequestException("参数id必须为有效的数字"); } } @Override public String toString(Long value) { return value == null ? null : value.toString(); } } // 注册转换器提供者 @Provider public class LongParamConverterProvider implements ParamConverterProvider { @Override public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { // 仅对Long类型生效 if (rawType.equals(Long.class) || rawType.equals(long.class)) { return (ParamConverter<T>) new LongParamConverter(); } return null; } }
说明:该方案在参数解析时就完成校验,转换失败立即抛出异常,可结合方案一的异常映射器统一处理响应,也可直接在转换器中定义错误信息。
方案对比
- 异常映射器:通用性强,可一次性处理所有参数转换失败的场景,无需修改现有接口代码。
- 自定义转换器:灵活性高,可针对特定类型定制转换逻辑,适合需要复杂校验的场景。
内容的提问来源于stack exchange,提问作者mah454
相关产品推荐
相关产品推荐

