End-to-End Tracing of Ajax/Java Applications Using DTrace

   
   
By Amit Hurvitz, July 2007    
Ajax, DTrace and Where They Meet

Ajax is an emerging technology, which got a significant boost with the rise of applications like Google Maps. Ajax is increasing the level of interaction between the code running under the browser and the server, thus allowing web applications, like Google Maps, to be more interactive. This higher granularity of communication to the server might make understanding performance issues tougher. Sometimes you need to understand the call flow, and check the time spent in any client JavaScript function and server (probably Java) method. DTrace will help.

DTrace is a Solaris (10 and above) tracing infrastructure with scripting capabilities, which enables high observation capabilities into both system and user activities. It allows probing of almost every system (I/O, network, scheduling, memory) operation, as well as tracing user native and Java programming language code. It also has an easy-to-implement and straightforward mechanism, called USDT, to add user probes to a C program. For basic and advanced information on DTrace, start at the OpenSolaris community DTrace page.

The Mozilla DTrace project at OpenSolaris offers JavaScript tracing capabilities using DTrace. You will need to have the DTrace instumented Firefox in order to trace JavaScript functions with DTrace. In order to use this Mozilla DTrace capability, you will also need to run on a recent Solaris Express build (63 or higher).

Java tracing by DTrace is enabled in Java 1.4.2 and 5.0 by published agents, based on JVMPI/JVMTI. In Java 6.0, DTrace instrumentation is built in the JVM on Solaris, so there is no need to dynamically link with a JVMPI/JVMTI shared library in order to use DTrace probes. Java 6.0 probes are described in detail in Keith McGuigan's weblog. Good examples for using Java probes can be found at Katya's examples.

An Ajax Application Tracing Example

I am using an Ajax validation example from Sang Shin's excellent Introduction to Ajax course. To run this example, either follow that page's directions, or the quick direction list below.

In my simplistic environment, I run both the browser and the application server (a servlet engine) on the same machine. This allows me to use one DTrace script to trace both, and easily see one combined sequence of JavaScript functions and Java methods. You might DTrace JavaScript on a client machine and DTrace the back-end on another server machine, as long as they both run Solaris (10 and above) for Java (server), Solaris Express build 63 or higher for the browser (client).

The traced processes will be the Firefox JavaScript engine and the Java process of the servlet engine (Jakarta Tomcat), embedded with NetBeans 5.5, with JRE 6.0. The Java tracing script is generic and can trace any Java 6.0 process, provided that we enableExtendedDTraceProbes by either specifying the JVM flag -XX:+ExtendedDTraceProbes at startup, or by using JDK 6.0 jinfo utility, which can enable/disable flags ( jinfo -flag +ExtendedDTraceProbes <Java-process-ID>).

To run the examples:

Installations and Configuration

  1. Make sure you are running on Solaris Express build 63 or higher from OpenSolaris. I have tested on build 63.
  2. Download and install a DTrace instrumented Firefox.
  3. Make sure Java 6.0 is installed (default with recent Solaris Express builds).
  4. Download and install NetBeans 5.5.
  5. Download and unzip 4257_Ajaxbasics2.zip from Sang Shin's course lab.
  6. Configure NetBeans to use Firefox as the default browser (Tools/Options).
  7. In NetBeans, open the project Ajax-validation from <4257_Ajaxbasics2 unzipped directory>/Ajaxbasics2/samples
  8. Add “ -XX:+ExtendedDTraceProbes ” flag to JAVA_OPTS in <netbeans-base-dir>/enterprise3/apache-tomcat-5.5.17/bin/catalina.sh. You might skip this and perform (4) in next sequence ('Running').

Running

  1. In NetBeans, right click on the Ajax-validation project you have created and choose 'Run Project'
  2. Check that JavaScript DTrace probes are enabled. Run:
  1. #
  2. dtrace -P 'trace_mozilla*' -l

You should see something like:

  1. ID PROVIDER MODULE FUNCTION NAME
  2. 73007 trace_mozilla9547 libmozjs.so jsdtrace_execute_done js_execute-done
  3. 73008 trace_mozilla9547 libmozjs.so js_Execute js_execute-done
  4. 73009 trace_mozilla9547 libmozjs.so jsdtrace_execute_start js_execute-start
  5. 73010 trace_mozilla9547 libmozjs.so js_Execute js_execute-start
  6. 73011 trace_mozilla9547 libmozjs.so jsdtrace_function_entry js_function-entry
  7. 73012 trace_mozilla9547 libmozjs.so js_Interpret js_function-entry
  8. 73013 trace_mozilla9547 libmozjs.so jsdtrace_function_return js_function-return
  9. 73014 trace_mozilla9547 libmozjs.so js_Interpret js_function-return
  10. 73015 trace_mozilla9547 libmozjs.so jsdtrace_object_create js_object-create
  11. 73016 trace_mozilla9547 libmozjs.so js_NewObject js_object-create
  12. 73017 trace_mozilla9547 libmozjs.so jsdtrace_object_create_done js_object-create-done
  13. 73018 trace_mozilla9547 libmozjs.so js_NewObject js_object-create-done
  14. 73019 trace_mozilla9547 libmozjs.so jsdtrace_object_create_start js_object-create-start
  15. 73020 trace_mozilla9547 libmozjs.so js_NewObject js_object-create-start
  16. 73021 trace_mozilla9547 libmozjs.so jsdtrace_object_finalize js_object-finalize
  17. 73022 trace_mozilla9547 libmozjs.so js_FinalizeObject js_object-finalize
  1. After the application page shows up in Firefox, locate the Java servlet engine (Tomcat) process (by pgrep -n java if you have not run any other JVM meanwhile, or by ' ptree NetBeans') and see the bottom Java process. Find the process ID.
  1. If you have not performed (8) in previous sequence, use this (as JVM-PID) and run
  1. # jinfo -flag + ExtendedDTraceProbes <JVM-PID>
  1. Run:
  1. # <dtrace script name> <JavaScript-engine-PID> <JVM-PID>.

This should be done as root user or as a DTrace privileged user.

Note: 
There are naming changes expected for in the Mozilla Dtrace provider:

module name will change from trace_mozilla* to javascript 
probe names will change from js_X to X (i.e., js_function-entry to function-entry)

trace_mozilla*:::js_function-entry
javascript*:::function-entry

Tracing Ajax and Java Call Flow

In this example, we are tracing the call flow of the JavaScript functions and the Java servlet methods, which responds to the Ajax calls. We are doing this by the following script ( javax_java_call_flow.d).

  1. #!/usr/sbin/dtrace -Zs
  2.  
  3. #pragma D option quiet
  4. #pragma D option switchrate=10
  5.  
  6. dtrace:::BEGIN
  7. {
  8. jsIndent = 0;
  9. jsFile = "ajax-validation";
  10. javaMethodBoundary= "doGet";
  11. startTimestamp = timestamp;
  12. }
  13.  
  14. *mozilla$1:::js_function-entry
  15. /basename(copyinstr(arg0)) == jsFile/
  16. {
  17. jsIndent += 2;
  18. printf("%*s -> %s:%s (JavaScript)(elapsed ms: %d)\n", jsIndent, "",
  19. jsFile, copyinstr(arg2), (timestamp - startTimestamp) / 1000);
  20. }
  21.  
  22. *mozilla$1:::js_function-return
  23. /basename(copyinstr(arg0)) == jsFile/
  24. {
  25. printf("%*s <- %s:%s (JavaScript)(elapsed ms: %d)\n", jsIndent, "",
  26. jsFile, copyinstr(arg2), (timestamp - startTimestamp) / 1000);
  27. jsIndent -= 2;
  28. }
  29.  
  30. hotspot$2:::method-entry
  31. {
  32. self->strPtr = (char *)copyin(arg1, args[2]+1);
  33. self->strPtr[(int)args[2]] = '\0';
  34. self->classStr = (string)self->strPtr;
  35. self->strPtr = (char *)copyin(arg3, (int)args[4]+1);
  36. self->strPtr[(int)args[4]] = '\0';
  37. self->methodStr = (string)self->strPtr;
  38. }
  39.  
  40. hotspot$2:::method-entry
  41. /javaMethodBoundary == self->methodStr/
  42. {
  43. self->interested = 1;
  44. self->indent = 0;
  45. }
  46.  
  47. hotspot$2:::method-entry
  48. /self->interested/
  49. {
  50. self->indent += 2;
  51. printf("%*s -> %s:%s (Java)(elapsed ms: %d)\n", self->indent, "",
  52. self->classStr, self->methodStr, (timestamp - startTimestamp) / 1000);
  53. }
  54.  
  55. hotspot$2:::method-return
  56. {
  57. self->strPtr = (char *)copyin(arg1, args[2]+1);
  58. self->strPtr[(int)args[2]] = '\0';
  59. self->classStr = (string)self->strPtr;
  60. self->strPtr = (char *)copyin(arg3, (int)args[4]+1);
  61. self->strPtr[(int)args[4]] = '\0';
  62. self->methodStr = (string)self->strPtr;
  63. }
  64.  
  65. hotspot$2:::method-return
  66. /self->interested/
  67. {
  68. printf("%*s <- %s:%s (Java)(elapsed ms: %d)\n", self->indent, "",
  69. self->classStr, self->methodStr, (timestamp - startTimestamp) / 1000);
  70. self->indent -= 2;
  71. }
  72.  
  73. hotspot$2:::method-return
  74. /javaMethodBoundary == self->methodStr/
  75. {
  76. self->interested = 0;
  77. /* exit(0); */
  78. }

Run the script like this (as a root or a DTrace privileged user):

# ajax_java_call_flow.d <JavaScript-engine-PID> <JVM-PID>

  1. JavaScript-engine-PID can be retrieved from the provider name in " dtrace -P 'trace_mozilla*' -l" output. For Example:

    73007 trace_mozilla 9547 libmozjs.so jsdtrace_execute_done js_execute-done ( 9547 is the pid).

  2. JVM-PID can be taken, after invoking the application, by running, for example, " ptree `pgrep -n netbeans`" and see the bottom Java process
  3. Type a character in the application form, wait 2 seconds and type <Ctrl-C> to stop the script. Check the script output.

The JavaScript probes (right after the BEGIN{} blocks:

  • *mozilla*:::js_function-entry is fired whenever a JavaScript function is called. A predicate is filtering out all calls besides those in the ajax-validation ( arg0points to the URL in which the JavaScript function resides) URL. It prints the function name and the time passed from last function call/return, properly indented.
  • *mozilla*:::js_function-return does the same for every 'ajax-validation' function return.

Then there are the Java probes

  • hotspot$target:::method-entry is fired whenever a Java method is called. There are a few action blocks here for the same probe, since we want to filter out calls which are not inside the boundaries of the doGet() servlet method. Only when inside these boundaries, the probe prints class name, method name and time passed from last class:method call/return, in a proper indentation
  • hotspot$target:::method-return does the same for every method return inside that boundaries.

The output will look like this (though much longer...):

  1. -> ajax-validation:validateUserId (JavaScript)(elapsed ms: 4288375)
  2. -> ajax-validation:escape (JavaScript)(elapsed ms: 4288497)
  3. <- ajax-validation:escape (JavaScript)(elapsed ms: 4288514)
  4. -> ajax-validation:initRequest (JavaScript)(elapsed ms: 4288529)
  5. <- ajax-validation:initRequest (JavaScript)(elapsed ms: 4288588)
  6. -> ajax-validation:open (JavaScript)(elapsed ms: 4288642)
  7. <- ajax-validation:open (JavaScript)(elapsed ms: 4288955)
  8. -> ajax-validation:send (JavaScript)(elapsed ms: 4288969)
  9. <- ajax-validation:send (JavaScript)(elapsed ms: 4289758)
  10. <- ajax-validation:validateUserId (JavaScript)(elapsed ms: 4289769)
  11. -> com/sun/j2ee/blueprints/bpcatalog/ajax/ValidationServlet:doGet (Java)(elapsed ms: 4721275)
  12. -> org/netbeans/modules/web/monitor/server/MonitorRequestWrapper:getParameter (Java)(elapsed ms: 4721289)
  13. -> org/apache/catalina/connector/RequestFacade:getParameter (Java)(elapsed ms: 4721300)
  14. -> java/lang/System:getSecurityManager (Java)(elapsed ms: 4721309)
  15. <- java/lang/System:getSecurityManager (Java)(elapsed ms: 4721319)
  16. -> org/apache/catalina/connector/Request:getParameter (Java)(elapsed ms: 4721330)
  17. -> org/apache/catalina/connector/Request:parseParameters (Java)(elapsed ms: 4721341)
  18.  
  19. ...
  20. ...
  21. ...
  22. <- org/apache/tomcat/util/buf/CharChunk:min (Java)(elapsed ms: 4729143)
  23. -> java/lang/String:getChars (Java)(elapsed ms: 4729156)
  24. -> java/lang/System:arraycopy (Java)(elapsed ms: 4729166)
  25. <- java/lang/System:arraycopy (Java)(elapsed ms: 4729176)
  26. <- java/lang/String:getChars (Java)(elapsed ms: 4729185)
  27. <- org/apache/tomcat/util/buf/CharChunk:append (Java)(elapsed ms: 4729196)
  28. <- org/apache/catalina/connector/OutputBuffer:write (Java)(elapsed ms: 4729207)
  29. <- org/apache/catalina/connector/CoyoteWriter:write (Java)(elapsed ms: 4729218)
  30. <- org/apache/catalina/connector/CoyoteWriter:write (Java)(elapsed ms: 4729228)
  31. <- com/sun/j2ee/blueprints/bpcatalog/ajax/ValidationServlet:doGet (Java)(elapsed ms: 4729242)
  32. -> ajax-validation:getElementsByTagName (JavaScript)(elapsed ms: 4922548)
  33. <- ajax-validation:getElementsByTagName (JavaScript)(elapsed ms: 4922644)
  34. -> ajax-validation:setMessageUsingDOM (JavaScript)(elapsed ms: 4922782)
  35. -> ajax-validation:getElementById (JavaScript)(elapsed ms: 4922812)
  36. <- ajax-validation:getElementById (JavaScript)(elapsed ms: 4922866)
  37. -> ajax-validation:createTextNode (JavaScript)(elapsed ms: 4923003)
  38. <- ajax-validation:createTextNode (JavaScript)(elapsed ms: 4923040)
  39. -> ajax-validation:replaceChild (JavaScript)(elapsed ms: 4923142)
  40. <- ajax-validation:replaceChild (JavaScript)(elapsed ms: 4923437)
  41. <- ajax-validation:setMessageUsingDOM (JavaScript)(elapsed ms: 4923449)
  42. -> ajax-validation:getElementById (JavaScript)(elapsed ms: 4923471)
  43. <- ajax-validation:getElementById (JavaScript)(elapsed ms: 4923523)

Each call (->) or return (<-) function/method shows the time passed from last call/return

Use this script with a special care for your applications: simultaneous Ajax requests and several servlet threads might make some mess in the output. This example shows one Java thread. In a more complex environment, especially if we are only interested in understanding the flow, it might make sense to serialize the application threads by using only one CPU (if you are running on a multi core/CPU machine). Look for pbind andpsrset Solaris main pages, for more information on restricting the application to specific CPU[s].

Profiling Ajax and Java Functions/Methods times

You can also show inclusive function time by changing the previous script to do that (ajax_java_functions.d).

  1. #!/usr/sbin/dtrace -Zs
  2.  
  3. #pragma D option quiet
  4. #pragma D option switchrate=10
  5.  
  6. dtrace:::BEGIN
  7. {
  8. jsFile = "ajax-validation";
  9. JavaMethodBoundary = "doGet";
  10. }
  11.  
  12. *mozilla$1:::js_function-entry
  13. /basename(copyinstr(arg0)) == jsFile/
  14. {
  15. depth++;
  16. jsFEntry[copyinstr(arg2), depth] = vtimestamp;
  17. }
  18.  
  19. *mozilla$1:::js_function-return
  20. /basename(copyinstr(arg0)) == jsFile/
  21. {
  22. @jsFTimes[copyinstr(arg2)] = sum(vtimestamp - jsFEntry[copyinstr(arg2), depth]);
  23. depth--;
  24. }
  25.  
  26. hotspot$2:::method-entry
  27. {
  28. self->strPtr = (char *)copyin(arg1, args[2]+1);
  29. self->strPtr[(int)args[2]] = '\0';
  30. self->classStr = (string)self->strPtr;
  31. self->strPtr = (char *)copyin(arg3, (int)args[4]+1);
  32. self->strPtr[(int)args[4]] = '\0';
  33. self->methodStr = (string)self->strPtr;
  34. }
  35.  
  36. hotspot$2:::method-entry
  37. /JavaMethodBoundary == self->methodStr/
  38. {
  39. self->interested = 1;
  40. }
  41.  
  42. hotspot$2:::method-entry
  43. /self->interested/
  44. {
  45. self->depth++;
  46. javaFEntry[self->classStr, self->methodStr, self->depth] = vtimestamp;
  47. }
  48.  
  49. hotspot$2:::method-return
  50. {
  51. self->strPtr = (char *)copyin(arg1, args[2]+1);
  52. self->strPtr[(int)args[2]] = '\0';
  53. self->classStr = (string)self->strPtr;
  54. self->strPtr = (char *)copyin(arg3, (int)args[4]+1);
  55. self->strPtr[(int)args[4]] = '\0';
  56. self->methodStr = (string)self->strPtr;
  57. }
  58.  
  59. hotspot$2:::method-return
  60. /self->interested/
  61. {
  62. @javaFTimes[self->classStr, self->methodStr] = sum(vtimestamp - javaFEntry[self->classStr, self->methodStr,
  63. self->depth]);
  64. self->depth--;
  65. }
  66.  
  67. hotspot$2:::method-return
  68. /JavaMethodBoundary == self->methodStr/
  69. {
  70. self->interested = 0;
  71. }
  72.  
  73. END
  74. {
  75. normalize(@jsFTimes, 1000);
  76. normalize(@javaFTimes, 1000);
  77. printf("JavaScript Functions\n");
  78. printf("--------------------\n");
  79. printf("%-10s %-25s\n", "inc. time", "Function");
  80. printa("%@-10u %-25s\n", @jsFTimes);
  81. printf("\n\n\n");
  82. printf("Java Methods\n");
  83. printf("------------\n");
  84. printf("%-10s %-50s %s\n", "inc. time", "Class", "Method");
  85. printa("%@-10u %-50s %s\n", @javaFTimes);
  86. }

Run the script like this (as a root or a DTrace privileged user):

ajax_java_functions.d <JavaScript-engine-PID> <JVM-PID>

  1. JavaScript-engine-PID can be retrieved from the provider name in dtrace -P 'trace_mozilla*' -l output. For Example:

    73007 trace_mozilla 9547 libmozjs.so jsdtrace_execute_done js_execute-done ( 9547 is the pid).

  2. JVM-PID can be taken, after running the application by running, for example, “ ptree `pgrep -n netbeans`” and see the bottom Java process
  3. <Ctrl-C> once you would like to stop your tracing, and results will show up in standard output

That produced the output below on my machine. First column shows inclusive execution time (in milliseconds, some Java methods might return zero after moving from nanoseconds to milliseconds). Inclusive time means the time spent in the function/method, including all function/method calls inside the function body. Net time spent in a function/method, excluding time spent in methods/calls contained in its body, is called exclusive time.

See below the last processParameters() method, with an inclusive time which is bigger than doGet() method, in which it is contained. This is becauseprocessParameters() is recursive. Since we consider inclusive time, recursive function have overlapped time, which is counted more than once.

  1. JavaScript Functions
  2. --------------------
  3. inc. time Function
  4. 5 escape
  5. 29 createTextNode
  6. 59 initRequest
  7. 84 getElementsByTagName
  8. 89 getElementById
  9. 295 replaceChild
  10. 318 open
  11. 465 send
  12. 569 setMessageUsingDOM
  13. 1048 validateUserId
  14.  
  15. Java Methods
  16. ------------
  17. inc. time Class Method
  18. 0 org/apache/tomcat/util/buf/CharChunk min
  19. 0 org/apache/tomcat/util/http/ContentType getCharsetFromContentType
  20. 0 org/apache/tomcat/util/buf/MessageBytes toString
  21.  
  22. ...
  23. ...
  24. ...
  25. 94 org/apache/catalina/connector/ResponseFacade setHeader
  26. 100 javax/servlet/http/HttpServletResponseWrapper setHeader
  27. 191 java/lang/StringCoding$StringDecoder decode
  28. 372 java/lang/StringCoding decode
  29. 384 java/lang/String <init>
  30. 388 org/apache/tomcat/util/buf/ByteChunk toStringInternal
  31. 455 org/apache/tomcat/util/buf/StringCache toString
  32. 459 org/apache/tomcat/util/buf/ByteChunk toString
  33. 492 org/apache/tomcat/util/http/Parameters urlDecode
  34. 585 org/apache/tomcat/util/http/Parameters handleQueryParameters
  35. 664 org/apache/catalina/connector/Request parseParameters
  36. 680 org/apache/catalina/connector/Request getParameter
  37. 688 org/apache/catalina/connector/RequestFacade getParameter
  38. 691 org/netbeans/modules/web/monitor/server/MonitorRequestWrapper getParameter
  39. 927 com/sun/j2ee/blueprints/bpcatalog/ajax/ValidationServlet doGet
  40. 1082 org/apache/tomcat/util/http/Parameters processParameters

In many cases, though, we are more interested in exclusive function times. This let us quickly realize the hotspots in our applications. I have used the previous script (ajax_java_call_flow.d) output, which I redirected to a file, and processed it with a Perl script (ajax_java_time_from_callflow.pl):

Run:

  1. #
  2. ajax_java_call_flow.d <JavaScript-engine-PID> <JVM-PID> > <output-file>
  3.  
  4. #
  5. perl
  6. ajax_java_time_from_callflow.txt
  7. <output-file>

This will create a list of all function/methods (mixed JavaScript and Java), their exclusive and inclusive time. The list is sorted in a descending order of the functions exclusive time.

  1. Method/Function Exc. time Inc. time
  2. ajax-validation:send 789 789
  3. ajax-validation:open 313 313
  4. ajax-validation:replaceChild 295 295
  5. ajax-validation:setMessageUsingDOM 281 667
  6. java/lang/StringCoding$StringDecoder:decode 252 1944
  7. sun/nio/cs/UTF_8$Decoder:decodeArrayLoop 244 429
  8. ajax-validation:validateUserId 216 1394
  9. org/apache/tomcat/util/buf/MessageBytes:equalsIgnoreCase 213 314

We can go further and trace system calls time by adding these probes (tracing here is not limited to the doGet() function boundaries)

  1. syscall:::entry
  2. /pid == $2/
  3. {
  4. scEntry[probefunc] = vtimestamp;
  5. }
  6.  
  7. syscall:::return
  8. /pid = $2/
  9. {
  10. @scTimes[probefunc] = sum(vtimestamp - scEntry[probefunc]);
  11. }
  12. and adding these lines to the END clause to do the printing:
  13.  
  14. END
  15. {
  16. ...
  17. normalize(@scTimes, 1000);
  18. printf("System Calls\n");
  19. printf("------------\n");
  20. printf("%-10s %-50s\n", "inc. time", "Syscall");
  21. printa("%@-10u %-50s\n", @scTimes);
  22. }

We can trace every aspect of the system (network, I/O, processes, etc.) using DTrace. For basic DTrace utilities that cover most systems aspects, see the DTrace toolkit.

Conclusion

We have seen how you can trace a joint JavaScript and Java call flow using DTrace. We have also seen how to trace JavaScript function times and Java method times. Each tracing task might have probably done with a specialized profiling tool. DTrace offers one tool that can replace them all. Finding out where does your application spend most of the time, no matter if these are Java methods, JavaScript function, or system activity done on behalf of a user function. No need to deal with a variety of tools, each capable of doing a partial task. DTrace technology lets you trace everything you want in the system.

For More Information

End-to-End Tracing of Ajax/Java Applications Using DTrace的更多相关文章

  1. Gradle Goodness: Running Java Applications from External Dependency

    With Gradle we can execute Java applications using the JavaExec task or the javaexec() method. If we ...

  2. Ajax&Java

    AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML) 是一种基于浏览器的XMLHttpRequest对象实现的创建交互式网页应用的网页开发技 ...

  3. ajax java base64 图片储存

    js代码 //利用formdata上传 var dataUrl = $('#canvas').getDataUrl(); var img = $('<img>').attr('src', ...

  4. Struts2 Spring Hibernate Ajax Java总结(实时更新)

    1. 在form表单的onload属性里的方法无法执行? 若忘记了在<%=request.getSession().getAttribute("userName")%> ...

  5. React+ajax+java 上传图片并预览

    之前有在网上找ajax上传图片的资料,大部分的人写得都是用jQuery,但是在这里用JQuery就大才小用了,所以我就自己写了,先上图. 由上图,首先点击上面的选择文件,在选择图片之后,将会自动上传图 ...

  6. JWT ajax java spingmvc 简洁教程

    1.添加依赖 <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</ ...

  7. html5 ajax Java接口 上传图片

    html5图片上传[文件上传]在网上找了很多资料,主要也就2种 1.from表单提交的方式 <form action="pushUserIcon" method=" ...

  8. Ajax+Java实现大文件切割上传

    技术体系:html5(formdata) + java + servlet3.0+maven + tomcat7 <!DOCTYPE html> <html> <head ...

  9. An HTTP & HTTP/2 client for Android and Java applications OkHttp

    HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP effic ...

随机推荐

  1. bzoj 1964: hull 三维凸包 计算几何

    1964: hull 三维凸包 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 54  Solved: 39[Submit][Status][Discuss ...

  2. js node

    http://blogs.msdn.com/b/scott_hanselman/archive/2011/11/29/window-iis-node-js.aspx http://www.16kan. ...

  3. weixin

    http://gps.yesky.com/19/34467019.shtml http://***/goods.php?id=320 http://www.sablog.net/blog/archiv ...

  4. Java RMI简单例子HelloWorld

    Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...

  5. FFmpeg发送流媒体的命令(UDP,RTP,RTMP)

    http://blog.csdn.net/leixiaohua1020/article/details/38283297

  6. ANDROID_MARS学习笔记_S04_001_OAuth简介

    一.OAuth简介

  7. Windows.document对象

    一.找到元素: docunment.getElementById("id"):根据id找,最多找一个:var a =docunment.getElementById("i ...

  8. 故障模块名称: NetdiskExt64.dll的解决之法

    故障模块名称: NetdiskExt64.dll的解决之法 2013年8月5日 开机,资源管理器报错.详细报错信息如下:   问题签名:   问题事件名称:    APPCRASH   应用程序名:  ...

  9. C# 验证码识别基础方法及源码

    先说说写这个的背景 最近有朋友在搞一个东西,已经做的挺不错了,最后想再完美一点,于是乎就提议把这种验证码给K.O.了,于是乎就K.O.了这个验证码.达到单个图片识别时间小于200ms,500个样本人工 ...

  10. asp.net EasyUI DataGrid 实现增删改查

    转自:http://www.cnblogs.com/create/p/3410314.html 前台代码: <!DOCTYPE html> <html xmlns="htt ...