Pull to refresh

Простой вызов удалённых сервисных методов в одностраничных приложениях

Reading time 3 min
Views 9.2K
В этой статье, я хочу поделиться своим подходом в организации клиент-серверного взаимодействия, в одностраничных браузерных приложениях с серверной частью на Java.

Сокращённо, я называю этот подход «Json Remote Service Procedure Call» — JRSPC. (Не очень благозвучно, возможно, но из песни слова не выкинешь.)

Применение jrspc — позволяет отказаться от использования слоёв определений интерфейсов сервисов на клиенте и сервере, что сокращает количество кода, упрощает его рефакторинг, и снижает вероятность появления ошибок.
При использовании этого подхода — мы можем писать только код, отвечающий за бизнес-логику,
не нужаясь в дополнительном коде, при определении нового бизнес-метода.

Например, на сервере, определение бизнес-метода выглядит так:

@Component("testService")
public class TestService{
    @Remote
    public String testMethod(Long userId, String role, boolean test,
            List<User> users, User user){    
            ...
           return "ok"; 
    }   
}    


а его вызов на клиенте — так:

var params = [userId, role, true, [{id:1, login:"111"},  {id:2, login:"222"} ], {id:3, login:"333"}]
Server.call("testService", "testMethod",   params,  sucessCallback, errorCallback, controlWhichWillDisabledUntilResponse);	


Больше, при определении метода, нигде, никакого кода не пишется.


Как это работает


На транспортном уровне, jrspc — использует json-rpc, с возможностью указывать в вызове не только метод, но и сервис. Поэтому, такой json-rpc можно было бы назвать json-rspc (s-service).

Если бы на него существовала спецификация, то она была бы похожа на спецификацию json-rpc 2.0, за исключением того, что в объекте запроса было бы добавлено поле «service», а поле «id» — было бы не обязательным, и в ответе — необязателен errorCode.

Для демонстрации, я написал простое демо-приложение, в котором реализуются функциональности регистрации, логина, и изменения данных и прав пользователя.

Клиентская часть


Клиентская часть этого приложения — написана на фреймворке AngularJS.
предупреждение
(Считаю своим долгом — предупредить тех, кто ещё не пробовал писать на нём:
{{user.name}}, Ангуляр — тяжёлый наркотик!
Для попадения в зависимость от него — достатчно словить кайф всего один раз.)

Для оформления используется Bootstrap.

В серверной части — Spring.

В качестве реализации объекта json, используется JSONObject из библиотеки json-lib.

Клиентская часть состоит из трёх файлов:

ajax-connector.js.

Реализация механизма запросов к серверу, инкапсулированная в объекте Server.
(Префикс ajax — используется, чтобы отличать его от вебсокетного ws-connector.js, которым он может быть заменён, без изменения кода user-controller.js.)

user-controller.js

Здесь находится бизнес-логика приложения, инкапсулированная в функции userController.

application.html


Графический интерфейс приложения с логикой блокировки элементов.

Как видим, в представлении скриптового кода, удалённый сервер — выглядит как объект Server, который должен быть проинициализирован url'ом.

Через этот объект, мы можем обращаться к любому компоненту на сервере и вызывать любые его методы, таким способом:

Server.call(serviceName, mathodName, [param1, param2, ...], successCallBack, errorCallback, control);

Ответы или ошибки — приходят в соответствующие коллбэки.

Добавление нового сервиса или метода на сервере — никак не затрагивает клиентский код, и мы можем вызывать эти сервисы и методы сразу, после того как они появились в серверном коде.

Естественно, сказав «любому и любые» — я немного отошёл от истины.
На самом деле, как удалённые сервисы, вызываться могут только классы, производные от AbstractService, а вызываемые удалённо методы, должны быть аннотированы @Remote.

Для ограничения прав доступа к методам — используется аннотация @Secured(roleName).
Так, например, метод, аннотированный @Secured("Admin") — не может быть вызван пользователем с ролью «User».

Cерверная часть


Весь серверный «фреймворк», если можно так выразиться, занимает меньше 9 кб., и состоит из шести классов, два из которых — уже знакомые нам аннотации: Remote и Secured, а также AbstractService
абстрактный класс, от которого должны наследоваться все сервисы, и CommonServiceController

В его метод processAjaxRequest приходят запросы из скриптового объекта Service.

Далее, находится компонент, по имени сервиса, и на нём, после проверки прав доступа, рефлективно, вызвается указанный метод.

User (entity), для хранения данных о пользователе, и UserManager, для операций с объектом User (тестовая реализация с эмуляцией персистентности).

Бизнес-логика реализована в двух сервисах: TestUserService — сервис с методами для регистрации, логина, и редактирования данных, и TestAdminService — сервис с методами для удаления юзера, и изменения его роли.

Код написан максимально self-explanatory, поэтому надеюсь, что разобраться в нём будет легко.

Код демо-приложения на Гитхабе.

Что дальше?


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

Update2:
Update1 — перемещён в тело статьи.
Tags:
Hubs:
+4
Comments 20
Comments Comments 20

Articles