dubbx雖然是基於jboss的resteasy實現restfull,但是對resteasy原生的配置卻不支持(可能是考慮到dubbo本事的設計模式及實現難度,但是和大部分framework的設計風格背道而馳),ExceptionMapper , Filter 和 Interceptor 需要配置在 <dubbo:protocol extension="x,x"/> ,參考 http://dangdangdotcom.github.io/dubbox/rest.html
一.Filter
Filter主要用於訪問和設置HTTP請求和響應的參數、URI等等。例如,設置HTTP響應的cache header
1.ContainerRequestFilter 服務器端請求處理之前,一般用於取請求參數做一些處理,比如記錄access log,流量控制,權限校驗 等。
常用的幾個點:
使用 @Context 獲取 HttpServletRequest 等servlet內置對象。
和標准的web filter一樣,Spring @Autowired 無法使用,必須通過 WebApplicationContext 獲取Spring管理的bean。
數據傳遞使用 SecurityContext (本人能力有限,沒找到更好的方式)。
直接返回結果 requestContext.abortWith(response);特別注意,調用此方法后,如果繼續有其他code,下邊的code一樣會執行的。(java語言本身的限制)。
package com.leon.filter; import java.io.IOException; import java.util.Date; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import org.springframework.stereotype.Component; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @Component public class SecurityFilter implements ContainerRequestFilter{ @Context private transient HttpServletRequest servletRequest; private SellerSecurityService sellerSecurityService; private AccessLogService accessLogService; private SellerPvService sellerPvService; @Override public void filter(ContainerRequestContext requestContext) throws IOException { Date now=new Date(); String appKey=HttpUtil.getParameterString(servletRequest,"appkey"); if(StringUtil.isEmpty(appKey)){ Response response=bulidUnauthResponse(Constant.missAppKeyResponse); requestContext.abortWith(response); return; } getService(); AccessLog accessLog=new AccessLog(); accessLogService.log(accessLog); SecurityContext securityContext=bulidSecurityContext("test"); requestContext.setSecurityContext(securityContext); } public static SecurityContext bulidSecurityContext(final String value){ return new SecurityContext() { @Override public boolean isUserInRole(String role) { return false; } @Override public boolean isSecure() { return false; } @Override public Principal getUserPrincipal() { return null; } @Override public String getAuthenticationScheme() { return value; } }; } private Response bulidUnauthResponse(String context){ return Response.ok().status(Constant.unAuthCode).entity(context).build(); } public void getService() { if(sellerSecurityService!=null){ return; } WebApplicationContext wac=WebApplicationContextUtils.getWebApplicationContext(servletRequest.getServletContext()); sellerSecurityService=wac.getBean(SellerSecurityService.class); accessLogService=wac.getBean(AccessLogService.class); sellerPvService=wac.getBean(SellerPvService.class); } }
2.ContainerResponseFilter 請求處理完之后調用,通常用作裝入公共信息到 response
public class CacheControlFilter implements ContainerResponseFilter { public void filter(ContainerRequestContext req, ContainerResponseContext res) { if (req.getMethod().equals("GET")) { res.getHeaders().add("Cache-Control", "someValue"); } } }
二.Interceptor
Interceptor主要用於訪問和修改輸入與輸出字節流,例如,手動添加GZIP壓縮:
1.ReaderInterceptor 攔截 MessageBodyReader.readFrom 可以用來實現校驗
2.WriterInterceptor 攔截 MessageBodyWriter.writeTo 可以用來實現數據壓縮
public class GZIPWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { OutputStream outputStream = context.getOutputStream(); context.setOutputStream(new GZIPOutputStream(outputStream)); context.proceed(); } }
三.ExceptionMapper
用來自定義Exception的處理方式。必須繼承 ExceptionMapper<E extends Throwable>,泛型為處理的異常類型
package com.leon.exception; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import org.apache.log4j.Logger; public class ExceptionMapperSupport implements ExceptionMapper<Exception> { private static final Logger LOGGER = Logger .getLogger(ExceptionMapperSupport.class); /** * 異常處理 * * @param exception * @return 異常處理后的Response對象 */ @Override public Response toResponse(Exception exception){ String response; int code; if(exception instanceof MyException){ MyException myException=(MyException)exception; response="{\"resp_code\":\""+myException.getRespCode()+"\",\"resp_info\":\""+myException.getRespInfo()+"\"}"; code=Constant.successCode; }else{ response=Constant.errorResponse; LOGGER.error(exception.getMessage(), exception); code=Constant.errorCode; } return Response.ok(response, MediaType.APPLICATION_JSON).status(code) .build(); } }