sparkjava: маршруты должны быть в основном методе?

Я новичок в спаркьяве и мне нравится в целом. Однако нужно ли определять новые маршруты / конечные точки в основном методе? Для любого значимого веб-приложения это приведет к очень длинному методу main, или мне нужно иметь несколько основных методов (и, следовательно, разделить ресурсы сервера между несколькими экземплярами).

Эти две страницы документации sparkjava, кажется, определяют маршруты в основном методе: http://sparkjava.com/documentation.html и здесь http://sparkjava.com/documentation.html.

Есть ли другой способ сделать это, которого я не вижу? Быстрый поиск в Google не показал мне лучшего способа...

=========

Вот полное решение, которое я сделал, основываясь на ответе Эндрю. По моему мнению, добавление конечных точек вне основного метода должно быть частью страницы документации sparkjava:

Основной метод:

public static void main(String[] args) {
    //Do I need to do something more with the Resource instance so that sparkjava notices it and/or reads the routes?
    Resource resource= new Resource(new Service());
}

Мой ресурс:

import static spark.Spark.*;
class Resource{

    private Service service;

    Resource(Service service){
        this.service = service;
        setupEndpoints();
    }

    private void setupEndpoints() {

        get("/user/:id", "application/json",(request, response)
                -> service.find(request.params(":id")), new JsonTransformer());

        get("/users", "application/json", (request, response)
                -> service.findAll(), new JsonTransformer());
    }
}

Мой сервис:

public class Service {

    public Object find(String id) {
        return null;
    }

    public Object findAll() {
        return null;
    }
}

Мой JsonTransformer:

import spark.ResponseTransformer;
public class JsonTransformer implements ResponseTransformer {
    @Override
    public String render(Object model) throws Exception {
        return null;
    }
}

3 ответа

Решение

Вы можете установить маршруты, где вы хотите. Вам просто нужно вызвать метод установки в главном потоке. например

 public static void main(String[] args){
     Resource resource= new Resource(new Service());
 }

 class Resource{

    private Service service;

    Resource(Service service){
      this.service = service;
      setupEndpoints();
    }

    private void setupEndpoints() {

      get("/user/:id", "application/json",(request, response)
            -> service.find(request.params(":id")), new JsonTransformer());

      get("/users", "application/json", (request, response)
            -> service.findAll(), new JsonTransformer());
    }
 }

Вот идея дизайна, которую вы можете использовать, когда есть несколько конечных точек для настройки:

Сначала создайте интерфейс разработчика:

public interface EndpointBuilder {
    void configure(Service spark, String basePath);
}

Теперь предположим, что у вас есть один из множества других ресурсов конечных точек для отдыха:

public class CustomerEndpoint implements EndpointBuilder {

    private final CustomerService customerService;

    public CustomerEndpoint(CustomerService service) {
        this.customerService = service;
    }

    @Override
    public void configure(Service spark, String basePath) {

        spark.get(basePath + "/customer", (req, res) -> {
            return "hello";
        });
    }
}

Наконец, создайте класс RestContext, который будет содержать экземпляр spark и позволит вам настроить любые маршруты, которые вы пожелаете:

public class RestContext {

    private static final Logger logger = LoggerFactory.getLogger(RestContext.class);

    private final Service spark;

    private final String basePath;

    public RestContext(int port, String basePath) {
        this.basePath = basePath;
        spark = Service.ignite().port(port); // import spark.Service;
    }

    public void addEndpoint(EndpointBuilder endpoint) {

        endpoint.configure(spark, basePath);
        logger.info("REST endpoints registered for {}.", endpoint.getClass().getSimpleName());
    }

    // Then you can even have some fun:
    public void enableCors() {

        spark.before((request, response) -> {
            response.header("Access-Control-Allow-Origin", "*");
            response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
            response.header("Access-Control-Allow-Headers", "Content-Type, api_key, Authorization");
        });

        logger.info("CORS support enabled.");
    }
}

Вы должны быть в состоянии использовать этот класс контекста в вашем методе main (и, возможно, в ваших тестовых классах):

public static void main(String... args) {

    RestContext context = new RestContext(8080, "/api");

    context.addEndpoint(new CustomerEndpoint(new CustomerService()));
    context.addEndpoint(new AnotherEndpoint()); // you can add or remove as many as you want.

    context.enableCors();
}

Obs.: Начиная с версии 2.5, Spark Java поддерживает несколько экземпляров через API Service.ignite().

Вы также можете интегрировать Spring в свое приложение Spark. Вот как я настроил свои маршруты.

@Configuration
public class RoutesConfiguration {
    RoutesConfiguration() {
        get("/hello", (req, res) -> "Hello World!");
    }
}

Это позволяет мне избежать шага вызова установки в методе Main SparkApp.

Ну, я думаю, что spark-java для людей, которым не нужны тонны дополнительных настроек.

Итак, я просто добавляю и добавляю дополнительный метод в контроллеры с именем DeclareRoutes, куда я помещаю объявления.

Для примера приложения:

public class LoginController {

    public static void declareRoutes(){
        get(Path.Web.LOGIN, LoginController.serveLoginPage);
        post(Path.Web.LOGIN, LoginController.handleLoginPost);
        post(Path.Web.LOGOUT, LoginController.handleLogoutPost);
    }

    public static Route serveLoginPage = (Request request, Response response) -> {
        Map<String, Object> model = new HashMap<>();
        model.put("loggedOut", removeSessionAttrLoggedOut(request));
        model.put("loginRedirect", removeSessionAttrLoginRedirect(request));
        return ViewUtil.render(request, model, Path.Template.LOGIN);
    };

Итак, в моем приложении я инициализирую все маршруты следующим образом:

 // Routes

 Class[] controllers = {
          IndexController.class,
          LoginController.class,
          SandboxController.class,
          ServicesController.class };

 for (Class controller: controllers) {
         Method m = controller.getMethod("declareRoutes");
         m.invoke(m);
 }

 // Catch all
 declareCatchAllRoute();

DeclareCatchAllRoute() просто:

private void declareCatchAllRoute() {
    get("*", ViewUtil.notFound);
}

Работает достаточно хорошо для моих нужд, не требует никакой новой абстракции.

НТН

Другие вопросы по тегам