java - ReSTLet 条件路由到不同资源

标签 java restlet

我有一个 POST 请求,我想根据正文内容将其分配给不同的资源

如果正文包含非空 token :“token”:“1q2w3e4r5t”那么我想将请求路由到TokenedResource, 否则路由到 NonTokenResource

我想使用过滤器(@beforeHandle),但过滤器返回的唯一指示是CONTINUESTOP...

有什么建议吗?

最佳答案

为此,您需要扩展 ReSTLet 路由。后者负责根据计算的分数确定哪个路由与特定请求匹配。

特别是,路由涉及两个需要重写的类:RouterTemplateRoute。路由器负责创建模板路由。如果要提供自定义模板路由,则需要提供自定义路由器。在自定义模板 route ,您可以实现自己的有关路线得分的算法。

这是自定义路由器的实现:

public class CustomRouter extends InternalRouter {
    public CustomRouter(Context context) {
        super(context);
        setFinderClass(CustomFinder.class);
    }

    protected TemplateRoute createRoute(String uriPattern,
                Restlet target, int matchingMode) {
        CustomTemplateRoute result = new CustomTemplateRoute(
                                    this, uriPattern, target);

        result.getTemplate().setMatchingMode(matchingMode);
        result.setMatchingQuery(getDefaultMatchingQuery());
        return result;
    }
}

不太容易理解的是为什么我们需要使用方法 setFinderClass 指定自定义查找器。 ReSTLet 中的查找器负责为每个请求实例化服务器资源等。默认实现(Finder 类)的问题是您无法访问关联的类(targetClass)。如果您需要知道它(似乎是这样),您必须提供自己的实现。我们稍后会重点讨论这一点。

使用此类,可以在应用程序类中附加服务器资源的方法:

@Override
public Restlet createInboundRoot() {
    Router router = new CustomRouter(getContext());

    router.attach("/test", TokenedResource.class);
    router.attach("/test", NonTokenResource.class);

    return router;
}

我们必须将它们附加到同一路径上。

下面是自定义模板路由的实现:

public class CustomTemplateRoute extends TemplateRoute {
    public CustomTemplateRoute(Restlet next) {
        super(next);
    }

    public CustomTemplateRoute(Router router,
                  String uriTemplate, Restlet next) {
        super(router, uriTemplate, next);
    }

    public CustomTemplateRoute(Router router,
                  Template template, Restlet next) {
        super(router, template, next);
    }

    @Override
    public float score(Request request, Response response) {
        float result = super.score(request, response);
        (...)
        return result;
    }
}

在方法 score 中,如果我们针对类 TokenedResource 进行标记请求,我们将增加分数,否则会减少分数。这允许 ReSTLet 为正确的情况选择正确的服务器资源。

在继续之前,先提供 CustomFinder 类的内容:

public class CustomFinder extends Finder {
    private Class<? extends ServerResource> targetClass;

    public CustomFinder() {
        super();
    }

    public CustomFinder(Context context) {
        super(context);
    }

    public CustomFinder(Context context,
            Class<? extends ServerResource> targetClass) {
        super(context, targetClass);
        this.targetClass = targetClass;
    }
}

这是一种实现自定义处理来计算分数的方法:

@Override
public float score(Request request, Response response) {
    float result = super.score(request, response);

    if (isTokenedServerResource()) {
        boolean containsToken = containsToken(request);
        if (containsToken) {
            return result + 0.1f;
        } else {
            return result - 0.1f;
        }
    }

    return result;
}

方法isTokenedServerResource 检查与路由关联的服务器资源(如果有)是否是类TokenedResource。在本例中,我们使用 containsToken 方法查看有效负载,看看它是否确实包含 token 。

以下是方法 isTokenedServerResource 的示例内容:

private boolean isTokenedServerResource() {
    if (getNext() instanceof CustomFinder) {
        CustomFinder finder = (CustomFinder) getNext();
        if (MyServerResource1.class.isAssignableFrom(finder.getTargetClass())) {
            return true;
        }
    }
    return false;
}

以下是方法 containsToken 的示例内容。它假设使用 JSON 内容,我们使用 Jackson 来解析它。

private boolean containsToken(Request request) {
    try {
        Representation repr = request.getEntity();
        String content = repr.getText();

        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> jsonContent = objectMapper.readValue(
                                  content, Map.class);

        StringRepresentation sRepr = new StringRepresentation(
                              content, repr.getMediaType());
        request.setEntity(sRepr);

        if (jsonContent.get("token") != null) {
            return true;
        }
    } catch (Exception ex) {
        (...)
    }
    return false;
}

需要注意的重要一点是,我们需要在请求中再次设置请求实体(这里使用 StringRepresentation),因为默认情况下实体内容只能读取一次。

希望对你有帮助 蒂埃里

关于java - ReSTLet 条件路由到不同资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29876576/

相关文章:

java - 无法通过 Hibernate 连接到数据库...太令人沮丧了

java - 如何使用 ReSTLet 将所有路径路由到单个 ServerResource

调用 setter 和 getter 时出现 Java : org. hibernate.PropertyAccessException

java - 可扩展的 API 服务器,带有 ReSTLet?

java - CodeIgniter 将类加密为 java

java - 无法处理收到的短信

java - REST Web 服务使用 ReSTLet 接受 POST - 最佳实践

java - 当对象实现可序列化时,ReSTLet/Jackson 的工作方式有所不同

java - Java单元测试:如何验证是否调用了私有(private)方法?

java dbcp2 多线程连接访问