Создание блога на Dart. Часть 2.

12.07.2017 at 18:01

Создание блога на Dart. Часть 1.
Создание блога на Dart. Часть 2.
Создание блога на Dart. Часть 3.

Роутинг

Роутинг я реализовал просто – обработкой запросов занимаются контроллеры, каждый из которых сам решает, может он обработать запрос или нет. Запрос обрабатывается первым подходящим контроллером.

Класс базового контроллера:

abstract class ControllerBase {
  Future processRequest(HttpRequest request);
  Future<bool> canProcessRequest(HttpRequest request);   
}

Базовый класс для контроллеров, возвращающих HTML:

abstract class HttpController extends ControllerBase {
  Future processRequest(HttpRequest request)  async {
    request.response.headers.contentType = ContentType.HTML;    
  }
}

Класс контроллера, отдающего содержимое поста по пермалинку:

class PostController extends HttpController {
  PostRepository postRepository = injector.get(PostRepository);
  PostController() {}

  Future processRequest(HttpRequest request) async {
    await super.processRequest(request);
    var requestPermalink = StringUtils.Trim(request.requestedUri.path, '/');
    postRepository.getAllPosts().then((List<Post> posts) {
      var post = posts.where((p) => p.permalink == requestPermalink).single;
      request.response
        ..write(post.body)
        ..close();
    });
  }

  Future<bool> canProcessRequest(HttpRequest request) {
    var requestPermalink = StringUtils.Trim(request.requestedUri.path, '/');
    return postRepository.getAllPosts().then((List<Post> posts) {
      return posts.any((p) => p.permalink == requestPermalink);
    });
  }
}

Урл для этого контроллера выглядит так: /permalink

Из репозитория постов получаются все посты, из них выбирается единственный с соответствующим пермалинком и в ответ пишется содержимое поста. Верстку и шаблонизацию пока не делал, хотя пара шаблонизаторов для Dart есть.

Класс контроллера, отдающего список постов:

class ListController extends HttpController {
  PostRepository postRepository = injector.get(PostRepository);

  static const int postsPerPage = 2;
  Future processRequest(HttpRequest request) async {
    await super.processRequest(request);
    int pageNum = int.parse(request.requestedUri.queryParameters["p"]);
    List<Post> posts = await postRepository.getAllPosts();
    List<Post> shownPosts =
        posts.skip(postsPerPage * (pageNum - 1)).take(postsPerPage).toList();
    shownPosts.forEach((Post post) {
      request.response
        ..write("<h1>${post.title}</h1><br>${post.body}<br><br><br>");
    });
    request.response.close();
  }

  Future<bool> canProcessRequest(HttpRequest request) async {
    var requestlink = StringUtils.Trim(request.requestedUri.path, '/');
    if (requestlink != 'list') return false;
    if (!request.requestedUri.queryParameters.containsKey("p")) return false;
    return true;
  }
}

Полезные мелочи

В базовой библиотеке Dart пока не хватает всех привычных полезных функций, так что trim() для строки пришлось делать самому:

class StringUtils {
  static String Trim(String string, String part) {
    if (part.length != 1)
      throw new ArgumentError('part.length should be equal to 1');
    String result = string;
    if (result.startsWith(part)) 
      result = result.substring(1);
    if (result.endsWith(part)) 
      result = result.substring(0, result.length - 1);
    return result;
  }
}