DWR (Direct Web Remoting) is a WEB Remote Call framework. using this framework can make AJAX development very simple. using DWR, you can use JavaScript on the client side to directly call the Java method on the server side and return the value to JavaScript, just like calling it directly on the local client (DWR dynamically generates JavaScrip code based on Java classes ). the latest version of DWR0.6 adds many features, such as support for automatic Dom Trees configuration, support for Spring (Remote JavaScript call of spring bean), and better browser support, an optional commons-logging log operation is also supported.
The above is taken from open-open. After reading it for a few days, it is indeed a very good project. It translates java into javascript through reflection, and then uses the callback mechanism, javascript is easy to call Java code.
The general development process is as follows:
1. Write the Business Code, which is irrelevant to dwr.
2. Confirm which classes and methods in the Business Code are directly accessed by javascript.
3. Compile the dwr component and encapsulate the method in step 2.
4. Configure the dwr component to the dwr. xml file. If necessary, configure convert to convert java and javascript types.
5. Using the reflection mechanism, dwr converts the class in Step 4 into javascript code and provides it to the front-end page for calling.
5. Compile the webpage, call the related methods in javascript in step 5 (indirectly call the methods of related classes on the server side), execute the business logic, and return the execution results using the callback function.
6. After the execution result is obtained in the callback function, you can continue to write javascript Code related to the business logic.
The following is an example of user registration. (Note: This example is only used for demonstration, indicating the use of DWR. The class design is not optimal ).
1. first introduce the relevant Java classes
User: User class,
Public class User {
// Login ID, which is unique in the primary key
Private String id;
// Name
Private String name;
// Password
Private String password;
// Email
Private String email;
// The getXXX and setXXX methods are as follows:
.......
}
UserDAO: Implements User database access. Here is a demo to write test code.
Public class UserDAO {
// Store the stored data
Private static Map dataMap = new HashMap ();
// Permanent user
Public boolean save (User user ){
If (dataMap. containsKey (user. getId ()))
Return false;
System. out. println ("start to save the user ");
System. out. println ("id:" + user. getId ());
System. out. println ("password:" + user. getPassword ());
System. out. println ("name:" + user. getName ());
System. out. println ("email:" + user. getEmail ());
DataMap. put (user. getId (), user );
System. out. println ("End of user saving ");
Return true;
}
// Search for users
Public User find (String id ){
Return (User) dataMap. get (id );
}
}
DWRUserAccess: The DWR component, which is provided for javascript access.
Public class DWRUserAccess {
UserDAO userDAO = new UserDAO ();
Public boolean save (User user ){
Return userDAO. save (user );
}
Public User find (String id ){
Return userDAO. find (id );
}
}
The following describes the procedure of program execution.
1. Enter the relevant registration information, such as id, name, password, and email, and click Submit.
2. javascript code execution starts. Based on the information filled in by the user, call the DWRUserAccess class save method of DWRUserAccess. js provided by dwr to save the registration information.
3. Use the find method in DWRUserAccess. jsp to call the find method in the DWRUserAccess class on the server side and execute user information search.
Note: In the preceding execution process, DWRUserAccess is called by DWR and is a DWR component. Therefore, you need to configure the DWRUserAccess class to dwr.
Next, we will explain how to configure the dwr test environment.
1. Create a New webapp named testApp
2. Copy dwr. jar to the lib directory of testApp's WEB-INF
3. Compile the above User, UserDAO, and DWRUserAccess classes and put them in the classes directory.
4. Configure the servlet in web. xml and adapt the path to the dwr directory, as shown below:
<Servlet>
<Servlet-name> dwr-invoker </servlet-name>
<Display-name> DWR Servlet </display-name>
<Description> Direct Web Remoter Servlet </description>
<Servlet-class> uk. ltd. getahead. dwr. DWRServlet </servlet-class>
<Init-param>
<Param-name> debug </param-name>
<Param-value> true </param-value>
</Init-param>
<Init-param>
<Param-name> scriptCompressed </param-name>
<Param-value> false </param-value>
</Init-param>
<Load-on-startup> 1 </load-on-startup>
</Servlet>
<Servlet-mapping>
<Servlet-name> dwr-invoker </servlet-name>
<Url-pattern>/dwr/* </url-pattern>
</Servlet-mapping>
The above configuration can intercept all requests directed to dwr in testApp. We will introduce this interceptor later.
5. Create a dwr. xml file under the WEB-INF with the following content:
<? Xml version = "1.0" encoding = "UTF-8"?>
<! DOCTYPE dwr PUBLIC "-// GetAhead Limited // DTD Direct Web Remoting 1.0 //" http://www.getahead.ltd.uk/dwr/dwr10.dtd ">
<Dwr>
<Allow>
<Create creator = "new" javascript = "DWRUserAccess">
<Param name = "class" value = "test. DWRUserAccess"/>
</Create>
<Convert converter = "bean" match = "test. User"/>
</Allow>
</Dwr>
Here we configure DWRUserAccess to dwr. In the create element, creater = "new" indicates that each time DWRUserAccess is called, a new class is required. javascript = "DWRUserAccess ", indicates that the specified cirpt file provided to the front-end page is DWRUserAccess. js.
The convert element is used for data type conversion, that is, the conversion between the java class and javascript. Because the User object is exchanged with the foreground, bean conversion is required. We will introduce this class later.
4. Compile the test HTML page test.html
<! Doctype html public "-// W3C // dtd html 4.0 Transitional // EN">
<HTML>
<HEAD>
<TITLE> DWR test </TITLE>
<Meta http-equiv = Content-Type content = "text/html; charset = gb2312">
<Script src = "/oblog312/dwr/engine. js"> </script>
<Script src = "/oblog312/dwr/util. js"> </script>
<Script src = "/oblog312/dwr/interface/DWRUserAccess. js"> </script>
</HEAD>
<BODY>
<B> User Registration </B> <br>
------------------------------------------------
<Br>
<Form name = "regForm">
Login ID: <input type = "text" name = "id"> <br>
Command: <input type = "password" name = "password"> <br>
Last name: <input type = "text" name = "name"> <br>
Email: <input type = "text" name = "email"> <br>
<Input type = "button" name = "submitBtn" value = "Submit" onclick = "OnSave ()"> <br>
</Form>
<Br>
<Br> <B> user query </B> <br>
------------------------------------------------
<Br>
<Form name = "queryForm">
Login ID: <input type = "text" name = "id"> <br>
<Input type = "button" name = "submitBtn" value = "Submit" onclick = "OnFind ()"> <br>
</Form>
<Br>
</BODY>
</HTML>
<Script language = "JavaScript">
<! --
Function saveFun (data ){
If (data ){
Alert ("registration successful! ");
} Else {
Alert ("Login ID already exists! ");
}
}
Function OnSave (){
Var userMap = {};
UserMap. id = regForm. id. value;
UserMap. password = regForm. password. value;
UserMap. name = regForm. name. value;
UserMap. email = regForm. email. value;
DWRUserAccess. save (userMap, saveFun );
}
Function findFun (data ){
If (data = null ){
Alert ("unable to find user:" + queryForm. id. value );
Return;
}
Alert ("find user, \ nid:" + data. id + ", \ npassword:" + data. password + ", \ nname:" + data. name + ", \ nemail:" + data. email );
}
Function OnFind (){
DWRUserAccess. find (queryForm. id. value, findFun );
}
// -->
</SCRIPT>
The following describes the javascript code on the page.
<Script src = "/oblog312/dwr/engine. js"> </script>
<Script src = "/oblog312/dwr/util. js"> </script>
The two are provided by dwr. You don't have to worry about them. You just need to import them.
<Script src = "/oblog312/dwr/interface/DWRUserAccess. js"> </script>
It is the DWRUserAccess class we wrote. After reflection by dwr, the javascript code generated, it and DWRUserAccess. java is corresponding for users to call. In fact, we use this js file to call the DWRUserAccess class on the server.
<Script language = "JavaScript">
<! --
Function saveFun (data ){
If (data ){
Alert ("registration successful! ");
} Else {
Alert ("the user name already exists! ");
}
}
Function OnSave (){
Var userMap = {};
UserMap. id = regForm. id. value;
UserMap. password = regForm. password. value;
UserMap. name = regForm. name. value;
UserMap. email = regForm. email. value;
DWRUserAccess. save (userMap, saveFun );
}
Function findFun (data ){
If (data = null ){
Alert ("unable to find user:" + queryForm. id. value );
Return;
}
Alert ("find user, \ nid:" + data. id + ", \ npassword:" + data. password + ", \ nname:" + data. name + ", \ nemail:" + data. email );
}
Function OnFind (){
DWRUserAccess. find (queryForm. id. value, findFun );
}
// -->
</SCRIPT>
In this Code, let's take a look at the OnSave function. First, it constructs a map, sets the form data to the map, then calls DWRUserAccess. save (userMap, saveFun), and executes the save operation. You can note that the save method in DWRUserAccess on the server side is as follows: boolean save (User user). Its parameter is a User object and a boolean value is returned; the client-side method is as follows: save (userMap, saveFun). The first parameter userMap is the map object in javascirpt, which is equivalent to the User object on the server (when executed on the server, will be converted to a User object through convert). As mentioned above, dwr uses the callback function to return the execution result. The second parameter saveFun is a callback function. In function saveFun (data), data is the execution result. Here is a bool value, which is very simple. We can determine whether the data is true and whether the user name is repeated, whether the user is successfully registered.
Let's take a look at the OnFind function. The execution result is in the callback function findFun (data), because the server returns a User object, which is converted to a javascript map object through convert,
In findFun, we can easily access this User object through data. id, data. name, data. password, and data. email.
After the configuration is complete, start the server and enter localhost/testApp/test.html in the directory.
1. in the "user registration" form, enter admin in the id box, enter 123456 in password, enter chenbug in name, enter chenbug@zj.com in email, click submit button, the dialog box is displayed: "registered successfully ", you can see the following information in the server Background:
Save the user
Id: admin
Password: 123456
Name: chenbug
Email: chenbug@zj.com
User save ended
Click Submit again to bring up the "Login ID already exists" dialog box ".
2. in the "user query" dialog box, enter the login ID as admin, click the submit button, prompt to find the user, and display the relevant information, enter admin123, and click the submit button, prompting that the user cannot be found.
Now, the test is complete.
Follow-up:
1. Interceptor uk. ltd. getahead. dwr. DWRServlet
This class intercepts all requests directed to the dwr directory and calls the handler method of Processor for processing. ltd. getahead. dwr. impl. under defaprocesprocessor, we can see the detailed processing process.
If (pathInfo. length () = 0 |
PathInfo. equals (HtmlConstants. PATH_ROOT) |
PathInfo. equals (req. getContextPath ()))
{
Resp. sendRedirect (req. getContextPath () + servletPath + HtmlConstants. FILE_INDEX );
}
Else if (pathInfo. startsWith (HtmlConstants. FILE_INDEX ))
{
Index. handle (req, resp );
}
Else if (pathInfo. startsWith (HtmlConstants. PATH_TEST ))
{
Test. handle (req, resp );
}
Else if (pathInfo. startsWith (HtmlConstants. PATH_INTERFACE ))
{
Iface. handle (req, resp );
}
Else if (pathInfo. startsWith (HtmlConstants. PATH_EXEC ))
{
Exec. handle (req, resp );
}
Else if (pathInfo. equalsIgnoreCase (HtmlConstants. FILE_ENGINE ))
{
File. doFile (req, resp, HtmlConstants. FILE_ENGINE, HtmlConstants. MIME_JS );
}
Else if (pathInfo. equalsIgnoreCase (HtmlConstants. FILE_UTIL ))
{
File. doFile (req, resp, HtmlConstants. FILE_UTIL, HtmlConstants. MIME_JS );
}
Else if (pathInfo. inclusignorecase (HtmlConstants. FILE_DEPRECATED ))
{
File. doFile (req, resp, HtmlConstants. FILE_DEPRECATED, HtmlConstants. MIME_JS );
}
Else
{
Log. warn ("Page not found (" + pathInfo + "). in debug/test mode try viewing/[WEB-APP]/dwr/"); // $ NON-NLS-1 $ // $ NON-NLS-2 $
Resp. sendError (HttpServletResponse. SC _NOT_FOUND );
}
By judging the servlet Path of the request and processing it, you can refer to it by yourself, which is not discussed in detail here.
2. bean converter, <convert converter = "bean" match = "test. User"/>
Decompress dwr. jar and you can see dwr. xml in the path uk \ ltd \ getahead \ dwr. Here some default converters are configured,
<Converter id = "bean" class = "uk. ltd. getahead. dwr. convert. beanConverter "/> is the User-class converter used just now. Let's go to the code and see how it is converted between javascript and java.
Open the BeanConverter code and locate the function.
Public Object convertInbound (Class paramType, InboundVariable iv, InboundContext inctx) throws ConversionException
Converts a javascript object to a java object.
ParamType is the Class type. In the preceding example, It is test. User,
InboundVariable iv is the input value. The passed javascript value string can be obtained through iv. getValue.
InboundContext inctx is the context of the entry parameter, used to save the converted java object.
Because the front-end inputs a javascript map type, and the map must end with {And}, this function starts to judge.
If (! Value. startsWith (ConversionConstants. INBOUND_MAP_START ))
{
Throw new IllegalArgumentException (Messages. getString ("BeanConverter. MissingOpener", ConversionConstants. INBOUND_MAP_START); // $ NON-NLS-1 $
}
If (! Value. endsWith (ConversionConstants. INBOUND_MAP_END ))
{
Throw new IllegalArgumentException (Messages. getString ("BeanConverter. MissingCloser", ConversionConstants. INBOUND_MAP_START); // $ NON-NLS-1 $
}
In javascript, items in map are connected by commas, such as var userMap = {id: 'admin', password: '000000', name: 'chenbug ', email: 'chenbug @ zj.com '}; the key-value pairs of each item are connected by colons,
In the subsequent processing of the convertInbound function, we analyze the map string, use paramType to construct a java instance (that is, the User class), and then use reflection, set these key-value pairs to the java instance and return.
This completes the conversion from javascript to java.
Another function
Public String convertOutbound (Object data, String varname, OutboundContext outctx) throws ConversionException
It is to convert a java object to a javascript Object (in fact, it is a declaration and a value assignment statement ).
Object data, which is the java Object to be converted
String varname: The variable name of the object in javascript.
OutboundContext outctx, the context of the output parameter, used to save the converted javascript Value
StringBuffer buffer = new StringBuffer ();
Buffer. append ("var"); // $ NON-NLS-1 $
Buffer. append (varname );
Buffer. append ("={};"); // $ NON-NLS-1 $
The map type variables are declared here.
The following Code assigns values to variables through reflection:
Buffer. append (varname );
Buffer. append ('.');
Buffer. append (name );
Buffer. append ('= ');
Buffer. append (nested. getAssignCode ());
Buffer. append (';');
You can refer to more code on your own.
3. dwr itself provides a test environment. After configuration, you can enter the http: // localhost/testApp/dwr/index.html address in IE to view the configured DWR components, and perform relevant tests.