In this article, I want to share my approach in the organization of client-server interaction, in single-page browser applications with the server part in Java.
In short, I call this approach the “Json Remote Service Procedure Call” - JRSPC. (Not very harmonious, perhaps, but you can't throw a word out of a song.)
The use of jrspc - allows you to abandon the use of layers of definitions of service interfaces on the client and server, which reduces the amount of code, simplifies its refactoring, and reduces the likelihood of errors.
Using this approach, we can only write code that is responsible for business logic,
not needing additional code when defining a new business method.
')
For example, on a server, the definition of a business method looks like this:
@Component("testService") public class TestService{ @Remote public String testMethod(Long userId, String role, boolean test, List<User> users, User user){ ... return "ok"; } }
and his call on the client is:
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);
No more code is written anywhere in the method definition.
How it works
At the transport level, jrspc - uses json-rpc, with the ability to specify in the call not only the method, but also the service. Therefore, such a json-rpc could be called json-rspc (s-service).
If there were a specification for it, it would be similar to the specification of
json-rpc 2.0 , except that the “service” field would be added to the request object, and the “id” field would be optional, and in the response - optional errorCode.
For the demonstration, I wrote a simple
demo application that implements the registration, login, and change of data and user rights.
Client part
The client part of this application is written on the framework of
AngularJS .
a warning(I consider it my duty to warn those who have not tried to write on it:
{{user.name}}, Angulyar is a hard drug!
To get addicted to it, it’s enough to catch a buzz only once.)
For design used
Bootstrap .
In the server part -
Spring .
As an implementation of the json object,
JSONObject
from the
json-lib library is used.
The client part consists of three files:
ajax-connector.js .
The implementation of the server request mechanism, encapsulated in a
Server
object.
(The ajax prefix is ​​used to distinguish it from the ws-connector.js web socket, with which it can be replaced, without changing the user-controller.js code.)
user-controller.js
Here is the business logic of the application, encapsulated in the
userController
function.
application.html
The graphical interface of the application with the logic of blocking elements.
As you can see, in the script code view, the remote server looks like a Server object, which must be initialized with a url.
Through this object, we can access any component on the server and call any of its methods in this way:
Server.call(serviceName, mathodName, [param1, param2, ...], successCallBack, errorCallback, control);
Answers or errors come to the appropriate callbacks.
Adding a new service or method on the server does not affect the client code in any way, and we can call these services and methods immediately after they appear in the server code.
Naturally, saying “to any and all” - I moved away a bit from the truth.
In fact, as remote services, only classes derived from
AbstractService
can be called, and methods called remotely should be annotated with
@Remote
.
To restrict access rights to methods — the
@Secured(roleName)
annotation
@Secured(roleName)
.
For example, the method annotated by
@Secured("Admin")
- cannot be called by the user with the role "User".
Server part
The whole server "framework", if I may say so, takes less than 9 Kb, and consists of six classes, two of which are annotations already familiar to us:
Remote and
Secured , and also
AbstractService -
abstract class from which all services should inherit, and
CommonServiceControllerIts
processAjaxRequest
method receives requests from the
Service
script object.
Next, there is a component, by the name of the service, and on it, after checking access rights, reflectively, the specified method is called.
User (entity) , for storing user data, and
UserManager , for operations with a
User
object (test implementation with persistence emulation).
Business logic is implemented in two services:
TestUserService - a service with methods for registering, login, and editing data, and
TestAdminService - a service with methods for deleting a user, and changing his role.
The code is written as self-explanatory as possible, so I hope that it will be easy to understand it.
Demo code for Github .
What's next?
In the next article, I plan to write how, on the basis of this approach, you can organize client-server interaction through the web sockets, and how, on the server, from the web context of the context, get the http session.
Update2:Update1 - moved to the body of the article.