Jersey架构下的Restful接口学习笔记(二)

来源:互联网 发布:安徽铜陵网络台 编辑:程序博客网 时间:2024/05/23 14:08
Jersey2.0客户端代码编写示例: 
学习笔记1中客户端代码属于Jersey 1 版本,后来我给客户提供的demo中全部使用的是Jersey2.0以上的版本,在使用上稍微有点差别。 

pom.xml  client依赖库:


<dependency>  <groupId>org.glassfish.jersey.core</groupId>    <artifactId>jersey-client</artifactId>    <version>2.23.2</version></dependency>


代码示例:

String tar = "http://localhost:8080/VIID/"; Client client = ClientBuilder.newBuilder()                             .register(JacksonJsonProvider.class)                             .build();WebTarget target = client.target(tar); target.path("dev/info").queryParam("DevIP", DevIP)      .request().acceptEncoding("UTF-8")      .header(HttpHeaders.AUTHORIZATION, token)      .post(Entity.entity(data,MediaType.APPLICATION_JSON_TYPE),JSONObject.class); 

其中getdelete方法不能携带数据,接口设计的时候需要注意。 

Jersey过滤器:

当每个接口被调用时,都需要鉴权。我们的令牌规定是存在http消息头中的AUTHORIZATION 中。令牌在每次登陆时获取。 
那么每次调用接口都要手动敲一次鉴权的代码是不是很麻烦。这时就要使用Jersey中自带的过路器:


/** * 安全过滤器,进行统一鉴权操作 */@Providerpublic class SecurityFilter implements ContainerRequestFilter {    private static UserManager user = UserManager.getInstance();    @Override    public void filter(ContainerRequestContext requestContext) throws IOException {/* 获取客户端Header中提交的token */        String token = requestContext.getHeaderString("Authorization");        if(token == null){/* 如果token为空值,则检查请求路径是否为登录或者测试路径,如果是,则不需要鉴权 */            String path = ((ContainerRequest)requestContext).getPath(true);            if(!path.equals("login") && !path.equals("gethello")){throw new TokenCheckException("无效用户");}       }else { /* 检查token是否有效 */            boolean valid = user.checkAccessToken(token);            if(valid) {user.updateUserInfo(token);}else { throw new TokenCheckException("无效用户");}}    }}


再把这个自定义的过滤器添加到资源加载器中就可以了:

/* 注册过路器 */register(SecurityFilter.class);


统一异常处理
在上面的过路器中可以看到抛出了一个TokenCheckException 自定义异常。 
该异常归纳在统一异常处理机制中。 
统一异常的中心思想就是把所有异常转换成unchecked 异常,由统一的异常中心处理,这个统一异常管理可以自动抓住程序中所有抛出的异常由程序员自定义返回给客户端。 

先看自定义的统一异常管理类:


/** * 统一异常管理类 * rest服务中出现的unchecked异常全部走这里 */@Providerpublic class ExceptionMapperSupport implements ExceptionMapper<Exception> {    private static Logger logger = Logger.getLogger(ExceptionMapperSupport.class);    @Override    public Response toResponse(Exception exception) {JSONObject object = new JSONObject();if(exception instanceof RestfulBaseExcept){/* rest服务中出现的异常处理 */ RestfulBaseExcept restfulBaseExcept = (RestfulBaseExcept)exception;object.put("errcode", restfulBaseExcept.getErrcode());object.put("errmsg", restfulBaseExcept.getErrmsg());}else if(exception instanceof NotFoundException){/* 无效URL异常处理 */object.put("errcode", 404);object.put("errmsg", "NOT FOUND!目的端不存在");}else {/* 其它异常处理 */object.put("errcode", 5000);object.put("errmsg", exception.getMessage());}        /* 异常栈信息全部日志记录 */logger.error(exception.getMessage(), exception);return Response.ok(object, MediaType.APPLICATION_JSON_TYPE).build();    }}


该异常管理类把所有异常以错误码和错误信息的json形式返回给客户端。 

上述代码中的RestfulBaseExcept自定义异常类如下:


public class RestfulBaseExcept extends RuntimeException{        /** 查询条件错误码 */    static int QUERY_CONDITION_CODE = 50001;    /** 携带参数错误码 */    static int PARAM_CHECK_CODE = 50002;    /** json、结构体数据异常错误码 */    static int STRUCT_ERROR_CODE = 50003;    /** 鉴权失败错误码 */    static int TOKRN_ERROR_CODE = 50004; /** 错误码 */    private int errcode;    /** 错误信息 */    private String errmsg;    public RestfulBaseExcept(int errcode, String errmsg){super(errmsg);        this.errcode = errcode;        this.errmsg = errmsg;}   public RestfulBaseExcept(String errmsg, Throwable cause, int errcode) {super(errmsg, cause);this.errcode = errcode;        this.errmsg = errmsg;    }public int getErrcode() {return errcode;    }public void setErrcode(int errcode) {this.errcode = errcode;}    public String getErrmsg() {return errmsg;    }   public String getErrmsgByCode() {return ResponseInfoMng.getErrmsg(errcode);}   public void setErrmsg(String errmsg) {this.errmsg = errmsg;}}


过路器中的TokenCheckException 异常继承该异常:


/** * 鉴权出错异常*/public class TokenCheckException extends RestfulBaseExcept {    public TokenCheckException(String errmsg) {super(TOKRN_ERROR_CODE, errmsg);}   public TokenCheckException(String errmsg, Throwable cause) {super(errmsg, cause, TOKRN_ERROR_CODE);}}

自定义的统一异常类也应该在web入口时加载:


/* 注册异常统一机制 */register(ExceptionMapperSupport.class);

有了统一异常机制,整个工程的容错性就强大多了。 



与Spring架构的整合:
这里用到Spring架构是为了在中间业务层的一些只需要初始化一次的类的自动注入。而且jersey和架构整合起来都很方便。

1.在pom.xml中除了加入Spring架构所需的依赖库以外,还要加入:


<dependency>   <groupId>org.glassfish.jersey.ext</groupId>   <artifactId>jersey-spring3</artifactId>   <version>${jersey.version}</version></dependency>

没有这个库会自动注入失败。

2.在web.xml中添加:

<!-- Spring Application Context Listener Start --><listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></context-param>

这里applicationContext.xml中怎么写就不提了,和大部分Spring架构写法一样。 

是不是很简单。














                                             
0 0