Websphere Application Server environment configuration and application deployment best practices

Original Address

The release of a run on the WebSphere Application Server's J2EE application prior to the application server configuration and deployment is essential to a process, this process is very complex. WAS provides the user with visual management console (Web Admin Console) to complete this task. Even so, the development or deployment of personnel still need training, and spend some time and effort to complete the configuration and deployment. For a development team, if each team member must manually complete the configuration and application deployment environment, the cost is relatively high.
This article describes the script using the wsadmin tool to complete the server with the Jython environment configuration and application deployment. Configuration and deployment scripts, once written, can be used repeatedly. Automated scripts instead of manual operation, is to improve the efficiency of an important part. On this basis, the paper introduces a XML document using the wsadmin Jython script command-line tools, and extend the environment to achieve server configuration and application deployment. Our approach provides for the Jython implementation, the script has been associated with WAS 6.0 and 7.0 versions verified. In the article, we will elaborate on this approach and briefly describe the XML file format. In addition, this article describes the XML document parsing module implementation and operation of the principle, so that readers can add the required modules.
Wsadmin Tools and Scripts
About wsadmin tool
wsadmin scripting tool to introduce the IBM WebSphere Application Server V5. It is a scripting language input to accept a non-graphical management tool, users can use the wsadmin tool to perform with the management console that can perform the same task.
wsadmin Jython and Jacl currently only supports two scripting languages. Select this article as an example Jython script code, the use of automated scripts for server configuration, management explained. We will write an example Jython script to deploy applications, even the first contact with Jython script developers can quickly understand and use them.
Start wsadmin tool developers can wsadmin.bat (windows) or wsadmin.sh (Linux or AIX) to start the wsadmin tool. These two types of file can be in the WAS profile bin directory ($ {profile_root} / bin) is found, you can also WAS the bin directory ($ {app_server_root} / bin) is found. WAS in the bin directory in the startup command in the run need to specify the-profileName parameter, and in particular the profile of the bin directory of the startup command is not specified.
wsadmin tool can be interactive or batch-type operation in two ways. An interactive run-time, developers can run the wsadmin tool single command. In the windows system, start an interactive wsadmin tool command is as follows:
Start the wsadmin tool supports Jacl command: wsadmin.bat
Start support for Jython wsadmin command tool: wsadmin.bat-lang jython
In addition, developers can run the batch script by wsamin tool. Batch script needs to specify the-profile parameter:
Run Jacl script: wsadmin.bat-profile sample.jacl
Run the Jython script: wsadmin.bat-lang jython-profile sample.py
Back to Top
Jython language to introduce
Wsadmin Jython language is currently supported by one of the two scripting languages. Jython interpreter as the script provides the control flow of support and various auxiliary command, in addition, through the wsadmin scripting tool provides access to an object, Jython extend its functionality, so developers can use scripting to achieve the application deployment, server management and configuration.
The basic syntax of Jython
Python Jython language is a Java implementation, wsadmin tool uses Jython V2.1. Jython is a dynamically typed language like Java developers did not declare a variable type, because the variable type is determined at run time.
Jython's basic data types, including numeric types, Boolean types, and strings. Jython numeric types, including integer and floating-point type:
wsadmin> a = 1.33
wsadmin> print a
Floating-point 1.33 above statement will be assigned to the variable a, and through the print command in the console output variable a value. Jython in a Java string type also similar difference is that single quotes and double quotes in the function of Jython in the same: "My String" and 'My String' in Jython are considered the same. Jython to provide a variety of these basic types of operators: Boolean operators or and and digital types of +,-,*,/ and the% operator and a string of + operator.
wsadmin> print 'My' + 'String'
My String
The statement above two characters do connect and print to the console. In addition to operators, Jython string also provides a range of treatment methods, which are commonly used:
str1.find (str2): return str2 in str1 the first occurrence of the position;
str1.lower (): will become a lower-case characters in str1 and return;
str1.replace (str2, str3): all of the str1 str2 substring replaced str3;
str1.split (str2): to str2 str1 as separators to separate the list into;
len (str1): returns number of characters contained in str1;
cmp (str1, str2): Comparison of str1 and str2, then returns 0 if the same.
In the figures based on the types and strings, Jython provides a list of types, each element of the list can be a numeric type, Boolean type, string or a sub-list. Developers can use to create a list in parentheses:
wsadmin> list = ['a', 'b', ['c', 'd'], 'e']
wsadmin> print list [0]
wsadmin> print list [2] [1]
The statement above creates two lists, one containing ['c', 'd'] two elements at the same time, to the list for the first three elements (subscript 2) to create another list and assigned to the variable list . Jython list also provides various types of processing methods, which are commonly used:
len (list1): Returns the number of elements contained in list1;
cmp (list1, list2): if list1 and list2 contain the same element, return 0;
max (list1): returns the largest element values in list1;
min (list1): Returns the value of the smallest element in list1.
In addition to providing basic data types, Jython also control the flow of support. Jython language control flow statements supported include the following categories:
Conditions command: if-else;
Loop commands: while, for;
Error processing command: try.
In addition, developers can also use break, continue and pass statements to adjust the flow of control. We note if-else statement to control the flow of commands to use Jython:

if (len (list) == 0):
print 'The length of list is 0.'
print 'The first element is' + list [0]

Jython language to accomplish through the try statement error handling. Try statement can get the error when the statement is executed, when the error is captured, except sentence will be executed, otherwise, else sentence will be executed:

idef testFunc ():
div = 0
result = 10/div
import sys
print 'root cause:', sys.exc_type, sys.exc_value
print 'no exception is thrown.'

In the example above, when the div is 0, except sentence is executed, an exception is thrown. sys is a built-in Jython module, developers can import statement to import the built-in modules. Import sys module, developers can use the module exc_type and exc_value attribute display error messages. The implementation of the above statement results:
root cause: exceptions.ZeroDivisionError integer division or modulo
Jython scripts in the managed object
WebSphere wsadmin tool by using the following specific object, basic scripting language is extended:
AdminControl: used to run the operation command.
AdminConfig: run configuration commands WAS, WAS used to create or modify configuration elements.
AdminApp: application commands, including the deployment, uninstall, start, stop and other operations.
AdminTask: Systems Management for WAS to create servers, clusters, and so on.
Help: to get command help information.
These objects are used to perform administrative tasks. To use the scripting objects, specify the scripting objects, methods and method parameters. For example:
AdminConfig.attributes ('ApplicationServer')
This will be described in detail in the following sections related to these management methods and parameters object is used.
Top Jython script to deploy applications using the Jython language in the introduction, we will apply the use of Jython script to deploy the description. A typical enterprise-class J2EE applications, developers often do deployment phase are: (1) install or update the application ear package; (2) set the application classloader mode and classloader policy; (3) modify the package or war EJB package classloader; (4) to set the mapping of roles and users.
Install the application package if the ear is the first deployment of personnel deployed on WAS application server, we should install the application's ear package. Jython language allows developers to encapsulate the code into the relevant methods. The following is a WAS ear deploy applications on the server package approach installApp, its argument is the application name appName, ear file path earFile and server name server:

def installApp (server, appName, earFile):
# Declare global variable
global AdminApp
# Install ear file
server_attr = ['-server', server]
AdminApp.install (earFile, server_attr)
# EndDef

Deployed on the WAS server applications, is available by calling the install method of the object AdminApp done. In the method body, we first keyword AdminApp through global variables declared as global, so that way the rest of the body can use the variable. Ear after the server name and then file path as an argument to AdminApp object install method, End known as ear package deployment.
Assuming the need to deploy personnel deployed on server1 application SampleApp, ear package path is C: \ SampleAppEAR.ear, then the method call statement is:
installApp ('server1', 'SampleApp', 'C: / SampleAppEAR.ear')
Ear package updates the application because the application if the deployment of personnel changes in the update package on the ear, we should use object's update method to update AdminApp applications, the required parameter is the application name appName and ear file path earFile:

def updateEar (appName, earFile):
# Declare global variable
global AdminApp
# Update the existing application
AdminApp.update (appName, "app", "-operation update-contents" + earFile)
# End update ()

If the application SamleApp WAS has been installed on the server, then update the application ear package statement is:
updateEar ('SampleApp', 'C: / SampleAppEAR.ear')
Set the application classloader mode and classloader policy
Install or update applications in the ear package, deployment of personnel may need to modify the application classloader mode and the classloader policy. Used in the deployment default classloader mode is PARENT_FIRST, if the application is deployed using different classloader mode, need to be set at deployment time. Classloader policy refers to the application deployment strategy for war load the package, possible value of Module and Application:

def changeClassLoader (appName, classloaderMode, classloaderPolicy):
# Declare global variable
global AdminConfig
appid = AdminConfig.getid ("/ Deployment:" + appName + "/")
deployedApp = AdminConfig.showAttribute (appid, "deployedObject")
# Update classloader policy
if (len (classloaderPolicy)> 0):
policy = AdminConfig.showAttribute (deployedApp, "warClassLoaderPolicy")
if (cmp (classloaderPolicy.strip (), "Module") == 0):
policy = "MULTIPLE"
elif (cmp (classloaderPolicy.strip (), "Application") == 0):
policy = "SINGLE"
# End if
AdminConfig.modify (deployedApp, [["warClassLoaderPolicy", policy]])
# End if
# Update classloader mode
if (len (classloaderMode)> 0):
classLoader = AdminConfig.showAttribute (deployedApp, "classloader")
modeAttr = ["mode", classloaderMode]
AdminConfig.modify (classLoader, [modeAttr])
# End if
# End changeClassLoader ()

In the update classloader configuration, we first get through the appName application configuration ID, and ID obtained through the configuration information corresponding to the object deployedApp. If the parameter classloaderMode and classloaderPolicy non-empty, we will modify the object through the AdminConfig method of modifying the appropriate configuration.
If we need to configure the classloader mode and policy were PARENT_LAST and Application, we can use the following statement:
changeClassLoader ('SampleApp', 'PARENT_LAST', 'Application')
Modify the war package or EJB package classloader mode
In addition to using the wsadmin tool to specify the application classloader mode, can also apply the war package and EJB package set specific classloader mode, need to pass the parameters including the application name, module name and the specified classloader mode:

def changeModuleClassloaderMode (appName, moduleName, classloaderMode):
# Declare global variable
global AdminConfig
if len (classloaderMode)> 0:
appid = AdminConfig.getid ("/ Deployment:" + appName + "/")
deployedApp = AdminConfig.showAttribute (appid, "deployedObject")
modules = AdminConfig.showAttribute (deployedApp, "modules")
moduleList = modules [1: len (modules) -1]. split ("")
for module in moduleList:
uri = AdminConfig.showAttribute (module, "uri")
if cmp (moduleName, uri) == 0:
cmode = AdminConfig.showAttribute (module, "classloaderMode")
if (cmp (cmode, classloaderMode)! = 0):
print "Modifying classloader for module:" + uri
AdminConfig.modify (module, [["classloaderMode", classloaderMode]])
# End if
# End if
# End for
# End if
# End def

Modify the module's classloader mode and modify the application is very similar. Assuming SampleAppEar.ear contains a web module SampleWeb, then we can use the following statement to modify its classloader mode:
changeModuleClassloaderMode ('SampleApp', 'SampleWeb', 'PARENT_LAST')
Set the mapping of roles and some applications the user needs to control user rights, roles need to be mapped to a specific user or group, we can edit the object by AdminApp method to achieve this change MapRolesToUsers property configuration. Need to pass a list of roles for the role of parameters and user lists users:

def mapRolesToUsers (roles, users):
# Declare global variable
global AdminApp
if (len (roles)> 0):
roles_attr = []
for i in range (len (roles)):
role = roles [i]
user = users [i]
if (len (role)> 0):
print "Mapping role:" + role + "to user:" + user
role_attr = [role, "AppDeploymentOption.Yes",
"AppDeploymentOption.Yes", "", user]
roles_attr.append (role_attr)
# End if
# End for
mapRoles_attr = ["-MapRolesToUsers", roles_attr]
AdminApp.edit (self.app.name, mapRoles_attr)
# End if
# End def

If we need to role role1, role2 mapped to the user user1, user2, then we can call the following statement:
mapRolesToUsers (['role1', 'role2'], ['user1', 'user2'])
Update the application ear package, set the application classloader mode and classloader policy, set the war package or EJB package classloader mode, set roles and users to deploy a web mapping application and so is the typical procedure. Jython code on the above analysis, we found that complete specific steps need to write code only once, in the deployment of different applications, we only need to pass different parameters.
To isolate the script code and the specific configuration of different applications, using the configuration file is a good choice. Properties files are commonly used in the configuration file format, but face more complex, including the level of application deployment configuration (application configuration, application of the war package, EJB package configuration, application roles and user mapping, etc.), properties relatively simple structure of the file can not be a complete description of the structure we need. XML file itself has the structural characteristics and on the semantic description of our ability to make it the best choice. The article then describes how XML documents through the wsadmin tool and the Jython script extension.
Top XML file extension wsamin using Jython scripting tools and application deployment script on the above analysis, we found the same steps to configure the script are very similar, the difference is only configure the required parameters (such as application name and the ear file path). If a certain type of configuration parameters can be extracted, the existing script on the abstract, through the XML file to configure manage them, the next development and deployment of staff will need to repeat the preparation of Jacl or Jython script identical, only according to a predefined XML configuration file to provide the external parameters can reuse existing scripts to complete the WAS configuration and application deployment process.

XML file extension using the Jython script to deploy an example we still have to apply through the XML file describes how to configure the application deployment information. We first create a <app> node that has a name, ear, classloader, classloader-policy and map-to such properties, which is the application of the different attributes shared by the package, so we put them <app> node. <app> node may have <war>, <ejb>, <rar>, <role-mapping> and <conn-factory> other child nodes, each of these child nodes have different attributes and attribute values. Property values through these nodes, we can configure the application deployment information:

<App name = "SampleApp" ear = "C: \ SampleAppEAR.ear"
classloader = "PARENT_FIRST" classloader-policy = "Module"
map-to = "WebSphere: cell = myCell, node = myNode, server = myServer">
<War name = "SampleWar"
classloader = "PARENT_LAST"
file = "Sample.war" />
<Ejb name = "SampleEJB"
file = "SampleEJB.jar"
jndi-name = "eis / SampleEJB"
auth-data-alias = "jdbc / SAMPLE_DATA_SOURCE" />
<Rar name = "SampleRar"
file = "SampleRar.rar"
conn-factory-name = "sample conn factory"
jndi-name = "jndi / SAMPLE_CONN_FACTORY" />
<map user="user1" role="role1" />
<map user="user2" role="role2" />
</ Role-mapping>
<Conn-factory name = "SampleAppConnectionFactory"
auth-data-alias = "sample auth data">
<property name="ApplicationServerHost" value="" />
<property name="Client" value="600" />
</ Property-set>
</ Conn-factory>
</ App>

By the structural characteristics of XML, we can deploy the application to configure different levels of information. By reading these configurations, we can pass the correct parameters to the Jython script to complete the application on the WAS server deployment. We finally selected the ANT tool to complete reading the XML file and call the Jython script process, this article will be in the next chapter in detail.

XML configuration file format to complete the server through the wsadmin configuration and application deployment, application deployment in addition to the various parameters of the configuration, you also need to specify the server unit cell, node, node and server name, set the WAS environment variables, configure J2C authentication data and database connections, etc. Next, we supported the current description of the configuration one by one:
In reality the server configuration, application deployment is often the target server or server cluster (cluster). The target server with an application usually have the same unit name, so we can configure the server are:

<cell name="myCell">
<cluster name="myCluster" />
<server name="myServer" node="myNode" />
</ Cell>
</ Dest>

WAS environment variable configuration
WAS environment variable is a key-value pairs, assuming that we need to set the DB2 JDBC driver path, we can configure the following:

<var name="DB2_JDBC_DRIVER_PATH" value="C:\IBM\SQLLIB\java" />
</ Env>

WAS security configuration now, we support WAS security configuration is the J2C authentication data. J2C authentication data contains the name of the property include (alias), user name (user-id), password (pw) and description (desc). If you need to define a J2C authentication data sample auth data, we can configure the following:

<J2c-auth-data alias = "sample auth data" user-id = "myUser"
pw = "myPassword" desc = "sample auth data" />
</ Security>

WAS WAS commonly used in resource allocation of resources, including JDBC Provider, JDBC data source, J2C resource adapter, J2C connection factory, MQ MQ queue connection factory and queue. We have an example WAS JDBC Provider Resource Allocation: JDBC Provider attributes contain the name of (name), the implementation class (implementation class), type the path (classpath) and description (desc). Example of a JDBC Provider configuration is as follows:

<Jdbc-provider name = "DB2 Legacy CLI-based Type 2 JDBC Driver"
impl-class = "COM.ibm.db2.jdbc.DB2ConnectionPoolDataSource"
classpath = "$ {DB2_JDBC_DRIVER_PATH} / db2java.zip"
desc = "DB2 Legacy CLI-based Type 2 JDBC Driver" />

In this article the source code, you can find sample configuration files and the associated DTD. You can learn a different DTD WAS resources required property values.
Back to Top
XML file parsing and operating principles in order to enable the reader to easily add the required modules, then we will show parsing XML configuration files to achieve the principle and operation of the module. We use the XML configuration file parsing and run the module is implemented with a Jython script (you can find in the annex to this article the source code), Jython is Python for Java implementation, Jython who have been the realization of the goal is to seamlessly call powerful Java class libraries. Support in the Java class libraries, we are able to Jython script XML file for easy analysis and processing.

Analysis of XML parsing module
XML parsing module uses XML, DOM methods to parse the configuration file. Java class libraries provided by the DocumentBuilder, we parse the XML file into a Document object, Document objects through the analysis, we can get the server resources and the application deployment information:

def loadConfig (filepath):
factory = DocumentBuilderFactory.newInstance ();
builder = factory.newDocumentBuilder ()
fis = FileInputStream (filepath)
document = builder.parse (fis)
document.normalize ()
node = document.getDocumentElement ()
print "Exception:", sys.exc_type, sys.exc_value
print "Configuration file parsing failed."
sys.exit ()
# End except
......# Get config info from nodes
# End def

We have an example application deployment XML parsing module: DeployConfig XML parsing module is the core classes, according to the node name Node interface, return, DeployConfig generate an Application instance. Application examples include analysis of the child element node, and node name based on the respective sub-elements generate War, Rar, EJB and RoleMapping instance.

Figure 1. Parsing module

XML file to run the modules of our application deployment as an example the operation of the document analysis module. DeployConfig is to run the module provides an interface to the outside world, when running the module to deploy applications, it will call the Application object deploy method. If the application is the first time in the WAS server connection factory deployment package, then the Application object will call the method to install their own installEAR ear package, otherwise it will call the method update updateEAR ear package. After you install or update after the ear package, deploy object method call RoleMapping mapRoles method complete mapping.

Figure 2. Run Module

Ear application package contains a module needs to be mapped to the corresponding server, deploy method will call itself mapModulesToServers to complete this step. Then, deploy applications and methods were modified classloader configuration of each module. If one of the EJB module needs to call some server resources, mapResourcesToEJB method is called, in addition, if the application needs to access external resources through the resource adapter, you deploy the resource adapter configuration corresponding to the rar package connection factory. These common steps are completed, we deployed the WAS server application process to come to an end.
Extended use of ANT scripts to deploy applications to run through the wsadmin tool to configure the WAS server and deploy applications, in addition to resources and applications on the server configuration information, but also need to specify wsadmin.bat (or wsadmin.sh) the directory, deployment manager, and where the host required in connection deployment manager user name and password.
To avoid the need for each run Jython scripts are specified in the above command line parameters, we choose as our running ANT tool to tool. We will configure these parameters property elements of ANT scripts, and run the Jython script as a parameter:

<target name="init">
<! - The path where wsadmin.sh (. Bat) is in ->
<property name="wsadmin.path" value="C:/SDP/pf/wps/bin/wsadmin.bat" />
<! - Connect to which WAS server host to update target application ->
<property name="wsadmin.host" value="" />
<! - The user name to run wsadmin on a secured server ->
<property name="wsadmin.user" value="" />
<! - The password to run wsadmin on a secured server ->
<property name="wsadmin.pw" value="" />
<! - Main script to run ->
<property name="wsadmin.script" value="main.py" />
<! - Configuration file path ->
<property name="wsadmin.config" value="" />
</ Target>

In the build.xml, we will wsadmin.host, wsadmin.user and wsadmin.pw as wsadmin.bat (or wsadmin.sh) parameters, the path to the configuration file parameters as Jython script, run the wsadmin tool and the Jython script:

<target name="wsadmin">
<Property name = "args"
value = "-host $ {wsadmin.host}
-User $ {wsadmin.user}
-Password $ {wsadmin.pw}
-Lang jython
-F $ {wsadmin.script}
-Config $ {wsadmin.config} "/>
<exec executable="${wsadmin.path}" failonerror="true">
<arg line="${args}"/>
</ Exec>
</ Target>

Through ANT script, we can run the Jython script flexible, thus completing the WAS server configuration and application deployment. We assume that the script stored in C: \ wsadmin directory, configuration xml file sample.xml, then run the Ant command wsadmin steps would be:
ant-f C: / wsadmin / build.xml-Dwsadmin.config = C: / wsadmin / sample.xml
Top Summary This article wsadmin Jython scripting tools, and were introduced, and select the application deployment, for example, use of wsadmin and Jython scripting tools are described. wsadmin is a powerful tool that enables developers to deploy applications through the scripts, manage and configure the server, which allows developers do not need the management console (Web Admin Console) for manual configuration, reducing development or deployment of staff time and energy, human operator will also minimize the chance of introducing errors.
On this basis, the paper also introduces a XML document using wsadmin Jython script command-line tools, and extend the environment to achieve server configuration and application deployment methods, and a brief description of the configuration file format. In this way, development and deployment of staff will need to repeat the preparation of Jacl or Jython script identical, only need to follow a predefined XML configuration file to provide the external parameters can reuse existing scripts to complete the WAS configuration and application deployment process, improve the efficiency of staff deployment.
It is worth noting that we can not guarantee that the proposed server configuration and application deployment can be the perfect solution to all problems. If readers wish to adopt the program, refer to the IBM WebSphere Application Server Information Center for more information.

分类:Tech 时间:2010-12-11 人气:280
blog comments powered by Disqus


  • Doctrine2 use command line tools 2010-05-09

    Doctrine2 compressed package tools catalog is used to do some command line work. But must be downloaded from the SVN Doctrine2 to use them. Suppose you use the svn on doctrine2, depending on your server's configuration, if the operation for the mysql

  • Android SDK command line tools commonly used in 2010-09-16

    1. Startup and shutdown ADB Services (adb start-server and adb kill-server) Tested by the author, after a period of time to run the simulator, adb of the possible (in the Windows process can be found in the service, the service is used for the simula

  • Exe resources can be used for localization of a string of command line tools 2010-11-24

    Speaking before the windows of the exe file resource strings, I usually use eXeScope Restorator Resource Editor and the two resource editor to modify. But these two software are closed source. Look at the code recently PN2 discovered that TortoiseSVN

  • Advanced Course on the command line selection of CMD, eds (rpm) 2010-11-06

    Chapter I Section I often batch based on the internal command batch Introduction 1, REM, and:: 2, ECHO, and @ 3, PAUSE 4, ERRORLEVEL 5, TITLE 6, COLOR 7, mode configuration system equipment 8, GOTO and: 9, FIND 10, START 11, assoc and ftype 12, pushd

  • php command line for parameters 2010-06-24

    php command line for parameters The original program uses list.php? N = 1 to implement a function, now need to let automatically. In the command line, cd / www / hx /; / usr / local / bin / php / www / hx / list.php But list.php how to obtain argumen

  • [Reserved] XML document with Schema specification 2010-12-02

    [Reserved] XML document with Schema specification XML Schema is a XML-based alternative to DTD. XML Schema is also known as XML framework or XML model. And norms can be described by XML Schema document's data model and organizational structure, provi

  • Xiang Jie common Linux command line svn command 2010-03-31

    This article describes common Linux command line use svn command, in the hope of help to you. 1, Linux command line checkout files to a local directory svn checkout path (path is the directory on the server) For example: svn checkout svn: / / 192.168

  • javascript xml document processing 2010-06-06

    A few days ago about the next javascript xml parsing for some knowledge here, a little record. Here mainly for IE, Mozilla associated coding and testing, does not involve the browser chrome, chrome browser, so may be related to the code not work corr

  • php access the command line parameters 2010-06-24

    php command line for parameters The original program uses list.php? N = 1 to implement a function, now need to let automatically. In the command line, cd / www / hx /; / usr / local / bin / php / www / hx / list.php But list.php how to obtain argumen

  • Command line to run Java 2010-11-04

    Long time not to run Java on the command line, and suddenly want to run a think today is a strange, although the same has been before, but unfortunately not recorded, eat a cutting wisdom, this must be recorded. I first encountered the first problem

iOS 开发

Android 开发

Python 开发



PHP 开发

Ruby 开发






Javascript 开发

.NET 开发



Copyright (C) codeweblog.com, All Rights Reserved.

CodeWeblog.com 版权所有 黔ICP备15002463号-1

processed in 1.120 (s). 12 q(s)