c#远程获取网页内容

mikel阅读(638)

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace thief
{
class Program
{
static void Main(string[] args)
{
try {
WebClient MyWebClient = new WebClient();
MyWebClient.Credentials = CredentialCache.DefaultCredentials;//获取或设置用于对向Internet资源的请求进行身份验证的网络凭据。
Byte[] pageData = MyWebClient.DownloadData("http://www.chinaaspx.com");//从指定网站下载数据
string pageHtml = Encoding.Default.GetString(pageData);  //如果获取网站页面采用的是GB2312,则使用这句
//string pageHtml = Encoding.UTF8.GetString(pageData); //如果获取网站页面采用的是UTF-8,则使用这句
Console.WriteLine(pageHtml);//在控制台输入获取的内容
using (StreamWriter sw = new StreamWriter("c:\\test\\ouput.html"))//将获取的内容写入文本
{
sw.Write(pageHtml);
}
Console.ReadLine(); //让控制台暂停,否则一闪而过了
}
catch(WebException webEx) {
Console.WriteLine(webEx.Message.ToString());
}
}
}
}

30 分钟教会你Flex和java沟通

mikel阅读(658)

http://coenraets.org/testdrive/flex4j/index.htm
30 Minutes Flex Test-Drive for Java Developers
By Christophe Coenraets
Last update: September 6th, 2006
Update (1/12/2007): I put together a Tomcat-based Test Drive Server that includes these samples running out-of-the box. Read this post for more info.
The objective of this test-drive is to give you, in a very short amount of time, an understanding of how Flex works and what it can do. This test-drive consists of a series of samples kept as concise as possible (typically between 10 and 50 lines of code) to clearly expose features of interest. The samples focus primarily on using Flex with a Java back-end. The intended audience is Java developers with no prior knowledge of Flex.
A few things to know before you start…
1. The Flex programming model is made of:
* MXML, an XML language used to declaratively lay out the user interface of your application.
* ActionScript, an ECMAScript compliant, object-oriented programming model. With some syntactical differences, ActionScript looks and feels similar to Java, and supports the same object-oriented constructs: packages, classes, inheritance, interfaces, strong (but also dynamic) typing etc.
* An extensive set of class libraries. The online API documentation is available here in a Javadoc-like format.
2. The Flex source code (.mxml and .as files) is compiled into Flash bytecode (.swf) that is executed at the client-side by the Flash virtual machine.
There are different ways you can use the Flex compiler (mxmlc):
* From the command line
* As part of an ant script
* Using FlexBuilder: the compilation process is integrated in the IDE
* Using the web compiler (available with the Flex Data Services). This is similar to the JSP compilation model: The first time an application is requested it is compiled into bytecode, which is then cached to serve subsequent requests.
You typically don't use the web compiler in a production environment. However, we are using it in this test-drive to minimize the number of components to install on your machine (all you will need to install is a war file).
3. The Flex product line includes:
* The Flex SDK which is free and includes the Flex libraries, the compiler (mxmlc), the Debugger, and the documentation.
* Flex Data Services (FDS), an optional set of server-side components deployed in your J2EE application server. FDS includes a Java RPC service (sample 3), publish/subscribe messaging (samples 6 and 7), and data management services (sample 8). FDS is free for a single-CPU deployment (FDS Express), and is licensed per CPU when deployed on multiple CPUs.
* FlexBuilder, an optional IDE for Flex development. Built as an Eclipse plug-in, FlexBuilder includes a design view and a code view, code hinting, visual Debugging, etc. FlexBuilder is licensed on a per developer basis.
* Optional charting components licensed on a per developer basis.
You can develop and deploy Flex applications entirely for free using the SDK and the IDE of your choice. I will highlight the examples in this test-drive that require the Flex Data Services.
Installing the Test Drive Files
Since we will be using the Flex Data Services, you need a J2EE server, or, at a minimum, a Servlet container.
1. Download the testdrive war file.
* If you use an application server that implements the full J2EE stack (IBM Websphere, BEA Weblogic, JBoss, JRun, etc.), download the version below. It includes the Flex Data Services, the sample applications, and an embedded HSQLDB database to support the samples.
Proceed to license and download
* If you use Tomcat 5.5.x, download the version below. It includes the Flex Data Services, the sample applications, an embedded HSQLDB database to support the samples, and JOTM (an open source implementation of the Java Transaction API required by the data management services wich are used in sample 8).
Proceed to license and download
* If you use Tomcat 5.0.x, download the version below. It includes the Flex Data Services, the sample applications, an embedded HSQLDB database to support the samples, and JOTM (an open source implementation of the Java Transaction API required by the data management services wich are used in sample 8):
Proceed to license and download
Note: the only difference between the 5.5.x and 5.0.x version is the configuration of JOTM in META-INF\context.xml (the way you configure UserTransaction has changed in Tomcat 5.5).
2. Deploy testdrive.war in your application server
3. Access http://localhost:8080/testdrive (change the host name and port number as appropriate).
Sample 1: Accessing data using HTTPService
Run the sample:
1. Access http://localhost:8080/testdrive/sample1/SampleXML.mxml
Notice that there is a delay the first time you access an application in this test-drive. This is because we are using the web compiler which compiles your application into bytecode the first time it is accessed (similar to the JSP compilation model). Subsequent requests to the same application will be much faster since the application is already compiled. In a production environment, you would typically deploy precompiled applications.
Note: Depending on your configuration, you may need to increase the heap size of your application server's JVM to use the web compiler. This would not be required in a production environement since you typically don't use the web compiler. If you get a java.lang.OutOfMemoryError exception while trying to access a sample for the first time, you must increase your heap size.
2. Click “Get Data”: The DataGrid is populated with XML data returned by catalog.jsp
3. Also notice some of the built-in DataGrid features:
* Sortable columns (click on a column header)
* Moveable columns (click on a column header and, with the mouse button pressed, move the column to a new position)
Code walkthrough:
Open the following files in a code editor:
* testdrive/sample1/SampleXML.mxml
* testdrive/sample1/catalog.jsp
Using HTTPService, you can send HTTP requests to a server, and consume the response. Although the HTTPService can be used to consume different types of responses, it is typically used to consume XML. You can use the HTTPService with any kind of server-side technology: JSP, Servlet, ASP, Ruby on Rails, PHP, etc. You specify the target service in the url property of HTTPService.
Flex provides sophisticated data binding capabilities. You can bind the value of a property to the value of another property, or to an expression in general. In this example, the dataProvider property of the DataGrid is bound (using the curly braces notation) to the lastResult property of the HTTPService.
HTTPService calls are asynchronous. The result event is triggered on the HTTPService when the data becomes available to the client application. The fault event is triggered if an error occurs at the server-side, or if the network becomes unavailable. (See sample 5, for an example of coding result and fault event handlers).
By default, the XML document retrieved from the server is deserialized into an object graph. This allows you to navigate through the result using the dot notation. You can also get the result as an XML document by specifying resultFormat=”e4x” on the HTTPService. In that case, you can parse the document using E4X (ECMAScript for XML).
More info:
* Both HTTP and HTTPS are supported
* Instead of using the url property to specify a hardcoded URL, you can specify a logical name in the destination property. You then map this logical name to an actual URL in WEB-INF\flex\proxy-config.xml. In this example, you could replace url=”catalog.jsp” with destination=”catalog” (open WEB-INF\flex\proxy-config.xml to see how the catalog destination is configured). As another example, to get the headlines from the New York Times, specify destination=”news”, and change the DataGrid data binding to: dataProvider=”{srv.lastResult.rss.channel.item}”.
Sample 2: Accessing data using Web Services
Run the sample:
1. Access http://localhost:8080/testdrive/sample2/SampleWebService.mxml
2. Click “Get Data”: The DataGrid is populated with data returned by the ProductWS web service hosted on my blog.
Code walkthrough:
Open the following file in a code editor:
* testdrive/sample2/SampleWebService.mxml
Access the wsdl file for the web service used in this example:
* http://coenraets.org/services/ProductWS?wsdl
Using the WebService tag, you can invoke SOAP-based web services deployed in your application server or on the internet. Objects returned by a web service are automatically deserialized into ActionScript objects. Similarly ActionScript objects passed as arguments to a web service operation are serialized according the wsdl description.
Notice that we also added DataGrid column definitions (using DataGridColumn) in this example.
More Info:
* Flex supports both RPC-encoded and document-literal web services
* Like HTTPService, WebService calls are asynchronous: You can code result and fault event handlers
* Like when using HTTPService, you can use a logical name instead of a hardcoded URL to identify the service, and map the logical name in WEB-INF\flex\proxy-config.xml.
Sample 3: Accessing data using Java RPC
Run the sample:
1. Access http://localhost:8080/testdrive/sample3/SamplePOJO.mxml
2. Click “Get Data”: The DataGrid is populated with data returned by the getProducts() method of the ProductService Java class.
Code walkthrough:
Open the following files in a code editor:
* sample3\SamplePOJO.mxml
* WEB-INF\src\flex\testdrive\store\ProductService.java
* WEB-INF\flex\remoting-config.xml
Using RemoteObject, you can directly invoke methods of Java objects deployed in your application server, and consume the return value. The return value can be a value of a primitive data type, an object, a collection of objects, an object graph, etc.
The value of the destination property of RemoteObject is a logical name that is mapped to a fully qualified java class in remoting-config.xml.
Java objects returned by server-side methods are deserialized into either dynamic or typed ActionScript objects. In this example, we don't have an explicit ActionScript version of the Product Java class. Product objects are therefore deserialized into dynamic objects. In sample 5, we work with an explicit Product class in ActionScript.
More info:
* Like HTTPService and WebService, RemoteObject calls are asynchronous. You use the result and fault events of the RemoteObject to handle results and errors (see sample 5).
Sample 4: Flex Programming Model 101
Run the sample:
1. Access http://localhost:8080/testdrive/sample4/MasterDetail.mxml
2. Click a phone in the list: the details for the selected phone appear in the right panel
Code walkthrough:
Open the following files in a code editor:
* sample4\MasterDetail.mxml
* sample4\Thumb.mxml
* sample4\ProductView.mxml
Like in any other object-oriented programming language, a Flex application is made of a collection of classes. Using Flex, you can create classes using MXML or ActionScript. You typically create view classes in MXML, and Model and Controller classes in ActionScript.
When you create an mxml file, you are actually creating a class. The root node of the mxml document indicates the class you extend. For example, creating a file named MasterDetail.mxml with an root node is equivalent to creating an ActionScript class with the following signature:
public class MasterDetail extends Application {
}
Similarly, creating a file named ProductView.mxml with a root node is similar to creating a class with the following signature:
public class ProductView extends Panel {
}
Once you have defined a class, you can use it programatically or declaratively (as a tag in MXML) without the need for an additional descriptor file. Public properties are automatically available as tag attributes. For example, in MasterDetail.mxml, we define the tag and bind its product attribute to the selected item in the product list.
Also notice the support for CSS style sheets.
Sample 5: Updating Data
Run the sample:
1. Access http://localhost:8080/testdrive/sample5/SampleUpdate.mxml
2. Select a phone
3. Modify some data in the right panel. For example, the price.
4. Click Update: changes are sent to the back-end and persisted in the database by the ProductService class.
Code walkthrough:
Open the following files in a code editor:
* sample5\SampleUpdate.mxml
* sample5\ProductForm.mxml
* sample5\Product.as
* WEB-INF\src\flex\testdrive\store\ProductService.java
* WEB-INF\flex\remoting-config.xml
In Product.as we use the [RemoteClass(alias=”flex.testdrive.store.Product”)] annotation to map the ActionScript version of the Product class (Product.as) to the Java version (Product.java). As a result, Product objects returned by the getProducts() method of ProductService are deserialized into instances of the ActionScript Product class. Similarly, the instance of the ActionScript Product class passed as an argument to the update method of the RemoteObject is deserialized into an instance of the java version of the Product class at the server-side.
Sample 6: Publish/Subscribe Messaging (Data Push Use Case)
Run the sample:
In this example, a Java component publishes simulated real time values to a message queue. The Flex client subscribes to that queue and displays the values in real time.
1. To start the feed component at the server-side: access http://localhost:8080/testdrive/sample6/startfeed.jsp.
(You can stop the feed by accessing http://localhost:8080/testdrive/sample6/stopfeed.jsp)
2. Open a browser and access http://localhost:8080/testdrive/sample6/FeedClient.mxml
3. Click the “Subscribe to 'feed' destination” button: Pushed values appear in the text field
Code walkthrough:
Open the following files in a code editor:
* sample6\FeedClient.mxml
* WEB-INF\src\flex\testdrive\feed\Feed.Java
* WEB-INF\flex\messaging-config.xml
Flex supports publish/subscribe messaging through the Flex Message Service (part of the Flex Data Services). The Flex Message Service manages a set of destinations that Flex clients can publish and subsribe to. Flex provides two components, Producer and Consumer, that you use to respectively publish and subscribe to a destination. To subscribe to a destination, you use the subscribe() method of the Consumer class. When a message is published to a destination you subscribed to, the message event is triggered on the Consumer.
In Feed.java, the Flex Java API (MessageBroker, AsyncMessage) is used to publish messages to the Flex destination. The Javadoc documentation for the Java API is available here. Another option to exchange messages bewteen Flex and Java applications is to map Flex destinations to JMS topics, essentially allowing a Flex client to publish and subscribe to JMS topics. In addition to JMS, the Flex Message Service adapter architecture allows you to integrate with any kind of messaging system.
Flex destinations are configured in messaging-config.xml. You can configure a destination to deliver the messages using a real-time protocol or using polling.
Additional resources:
Check out the portfolio viewer sample for a more complete example of data push.
Sample 7: Publish/Subscribe Messaging (Collaboration Use Case)
Run the sample:
1. Open http://localhost:8080/testdrive/sample7/Chat.mxml in two different browser windows
2. Type a message in one of the chat clients and click “Send”: the message appears in the two chat clients
Code walkthrough:
Open the following files in a code editor:
* sample7\Chat.mxml
* WEB-INF\flex\messaging-config.xml
This sample builds on the concepts and APIs introduced in the previous example. To publish a message from a client, you use the send() method of the Producer class.
The messaging and real time infrastructure available in Flex enables collaboration and data push applications to be built in a scalable and reliable manner while preserving the lightweight web deployment model.
Additional resources:
Check out the Google Map collaboration sample.
Sample 8: Data Management Services
Testing persistence:
1. Open a browser and access http://localhost:8080/testdrive/sample8/SampleDataService.mxml
2. Click a DataGrid cell, modify the data in that cell, and press Enter
3. Click the Refresh button in your browser: Notice that the new value appears in the cell indicating that the data has been successfully persisted.
Testing data synchronization across clients:
1. Open the same application in a second browser window
2. Resize the two browser windows so that you can see both at the same time on your screen
3. Modify data in one browser, and press Enter: notice that the update is automatically pushed to the other client
Code walkthrough:
Open the following files in a code editor:
* sample8\SampleDataService.mxml
* sample8\Product.as
* WEB-INF\src\flex\testdrive\store\ProductAssembler.java
* WEB-INF\src\flex\testdrive\store\ProductService.java
* WEB-INF\flex\data-management-config.xml
In addition to the RPC services described in samples 1, 2, and 3, the Flex Data Management Services provide an innovative and highly productive approach to synchronize data across tiers and between clients. The Flex Data Management Services consist of a client-side API and server-side services:
At the client-side, “managed objects” keep track of changes made to the data, and notify the back-end of these changes. In SampleDataService.mxml, all you have to do is:
* Define a DataService pointing to the “product” destination defined in data-management-config.xml
* Invoke the DataService's fill() method to populate the “products” array
* Bind the DataGrid to the products array
You don't have to keep track of changes made to the data, nor do you have to invoke remote services to notify the back-end of the changes (create, update, delete) made at the client side.
At the server-side, the Data Service receives the list of changes and passes it to your server-side persistence components. The Data Service also pushes the changes to other clients. In this example, the “product” DataService configured in data-management-config.xml uses the java-dao adapter, indicating that we will take care of the persistence code with our own Java classes (another option is to use the Hibernate adapter). There is no specific contract imposed on the Java class that provides the persistence implementation: You map methods such as fill and sync to actual methods in an assembler class (in this case: ProductAssembler). In the assembler class, you typically delegate the actual persistence implementation to existing persistence classes (in this case: ProductService).
Sample 9: Data Visualization
Run the sample :
1. Access http://localhost:8080/testdrive/sample9/Dashboard.mxml
2. Click on any data point on the line chart, the column chart at the bottom of the screen is updated to display a product breakdown for the selected month.
Code walkthrough:
Open the following files in a code editor:
* sample9\Dashboard.mxml
Flex provides and extensive library of charting components such as LineChart and PieChart used in this example. Other charting components include ColumnChart, BarChart, AreaChart, BubbleChart, CandlestickChart, PlotChart, HLOCChart.
Flex charting components work like the other data aware components: you use the dataProvider property to bind a chart to data.
Because they leverage vector graphics, charting components can be redrawn and animated at the client-side, helping the end-user to better understand data trends and transitions.
Additional resources:
* Dashboard sample on adobe.com
* Ely Greenfield's Chart Sampler
* Interactive bubble chart, another charting component example from Ely
Sample 10: Rich Media
Run the sample:
1. Access http://localhost:8080/testdrive/sample10/SampleMedia.mxml
2. Click on a question in the list: a video appears, adding a rich media experience to this traditional “FAQ” application.
Code walkthrough:
Open the following files in a code editor:
* sample10\SampleMedia.mxml
* sample10\questions.mxml
HTTPService is used to retrieve an XML document that contains the list of questions, video links, and cuepoints.
The source attribute of the VideoDisplay component is bound to the selectedItem in the List, so that the “answer video” automatically starts palying when a question is clicked.
The cuepoint event is used on VideoDisplay to synchronize the captions (the captions are not part of the video, but where read from the XML document).
Also notice how the resizeEffect is used on the Panel component, to animate the panel when it is resized.
Finally the applications has two view states: the default state and the “videoPlaying” state. View states allow you to declaratively (using MXML) represent different states of the applications. In this simple case, the Panel is expanded in the videoPlaying state to reveal the VideoDisplay component.
Appendix A: Data Access and Rendering Performance
To test data retrieval and rendering:
1. Access http://localhost:8080/testdrive/appendixa/Perf.mxml
2. Specify a number of rows to retrieve
3. Click “Get Data”
4. Watch the number of milliseconds it took to retrieve and render the data
To test client-side sorting:
1. Specify 20000 rows
2. Click “Get Data”
3. Click on a column header to sort 20000 rows at the client-side
Code walkthrough:
Open the following files in a code editor:
* sample11\Perf.mxml
* WEB-INF\src\flex\testdrive\census\CensusService.java
* WEB-INF\flex\remoting-config.xml
At the client-side, we use RemoteObject to remotely invoke the getItems method on the CensusService class deployed in the application server. The CensusService class accesses the embedded HSQLDB database and returns the number of rows requested. Using RemoteObject, the data is transferred in a binary format over HTTP.
Appendix B: Creating Custom UI Components
Run the sample:
1. Access http://localhost:8080/testdrive/appendixb/Store.mxml
2. Modify the price range using the slider: filtered items are animated in and out of the list to help the user visualize the products affected by the filter
Code walkthrough:
Open the following files in a code editor:
* sample12\Store.mxml
* sample12\AnimatedTileList.as
Although many Flex applications are built entirely using the UI components available in the Flex framework, you can create custom UI components by extending classes in the Flex framework. AnimatedTileList.as provides an example of a class that extends Canvas to provide an animated version of the TileList component.
Summary and Next Steps
This test-drive has provided you with a first experience of Flex, primarily focused on Java integration. However, we have just scratched the surface, and there are many other online resources focusing on the different aspects of the product. flex.org is a great place to start to become familiar with these resources. The developer experience is an important aspect of Flex. So also make sure you download FlexBuilder to start building your own Flex projects.
Don't hesitate to send me your questions/comments on this test-drive and any suggestion to improve it. Thanks! christophe at coenraets dot org.

Flex+Java中小型项目的代码研究

mikel阅读(698)

Flex Structure
前言
这两天写了一个研究Flex + Java的例子,供大家参考,这个例子主要是出于以下几点考虑的
1. 系统性能和系统可维护性上的平衡(Value Object lazy load)
2. 开发效率和代码可读性上的平衡(Command and CommandManager)
3. 如何让Flex调用服务端的Service(AMF3, Remote Object)
4. 使用Cache Framework提升我们的性能
花絮:其实做项目和生活,管理等等都是一样,做到最好是不太现实的,但要和谐,什么叫和谐?就是在成本,进度,质量等外在压力下把代码写得最好!所以我下面的例子代码也是一样,追求的是一个平衡J
一. 系统性能和系统可维护性上的平衡(Value Object lazy load)
最佳性能时,系统只在网络上传输必要的数据,如显示用户清单时只传输user name和department name。
而结构最优时,传输的却是规范的数据结构。
这个时候矛盾来了
A. 传输规范的数据结构。这时候必然会带上一些冗余数据,如显示用户清单时传输的UserVO,而UserVO里同时也包含了标志这个用户部门的DepartmentVO,这时就会带来不必要的数据传输,如果显示的用户清单有100条,那么这100个UserVO里面的DepartmentVO必然会带来不小的数据冗余。
B. 只在网络上传输必要的数据。这时有两种方法可以做到,设计一个UserListVO,里面包含user name和department name这两样field,然后在Business Logic里组装这个UserListVO。但这种方法显然有个大的缺点,这个VO或对应的业务逻辑代码不可以共用,因为不同的地方会有不同的业务需求,比如有一个模块中会要显示用户的年龄。另一个方法就是,使用规范的数据结构,但只为这些数据结构中必要的栏位设值,如上面所说的,可以只为userVO.departmentVO.name设值,但其它栏位保持null,显然,这个VO的共用性也不好,因为我没法知道这个VO里面的栏位是否已经被设值了。
综上所说,所以我取上面两种方法的一个中间点来解决这个问题(如下图),即使用完整的数据结构来存储数据,但不是必要的数据不会被加载上来,如果要用时,可以通过Lazy Load的方式加载。如UserVO里有DepartmentVO,但在显示清单时不需要user对应的department信息,在编辑时才需要,所以我们可以在popup出用户编辑窗口的时候才在UserVO的getDepartmentVO()方法中加载相应的DepartmentVO。

class diagram for data model
请参见附件中的class diagram for data model
二. 开发效率和代码可读性上的平衡(Command and CommandManager)
往往在开发的时候,标准的结构会多写很多代码,虽然结构很清晰,但老实说,对于我们的项目,好像不需要这样“清晰”,比如Cairngorm中有command, event, controller等等,这确实是一种清晰的结构,但写起来很麻烦,所以我下面设计了一种简化的结构来实现它(如下图)。

class diagram for command
Class Diagram
请参见附件中的class diagram for command
Cache
sequence diagram for command pattern
Sequence Diagram
请参见附件中的sequence diagram for command pattern
关于Command Pattern,请参考以下的链接
http://www.javaworld.com/javaworld/jw-06-2002/jw-0628-designpatterns.html
这里,CommandManager就是那个Invoker。而com.novem.farc.command.UserSaveCommand.datagrid就是那个receiver。
Why not Cairngorm Event or Command?
我们以查找一个user为例,来看看Cairngorm是怎么调用一个Command并返回结果的。
1. 创建一个CairngormEvent,并在这个Event里要有一个userId:Number的field。
2. 创建一个Command,这个Command要实现两个接口,ICommand和IResponder。
3. 创建一个FrontController来建立Event和Command的关连。
然后,在客户端调用的时候,书写如下的代码:
var event: EventFindUser = new EventFindUser ();
event.userId = userVO.id;
CairngormEventDispatcher.getInstance().dispatchEvent( event );
我们现在新的结构是这样实现的:
var command:CommandFindUser = new CommandFindUser();
command.userId = userVO.id;
NovemCommandManager.execute(command);
可以看出来,Cairngorm通过注册Event,并通过Event来传递输入参数,而我们自己的结构是将参数直接传递给Command,所以Cairngorm并没有给我们提供特别的方便,反而增加了不少麻烦的Event,而它提供的这种解耦,也并不实在。
Why not Cairngorm Model Locator?
Cairngorm Model Locator提供的其实是一种静态全局变量。
那么,谁都可以来改变这个Model Locator中的值,这显然是一个很危险的事。
如果大家也和我一样认为Cairngorm Model Locator就是一种静态全局变量的话,我想我在这里不用说得太多,只要去查一下静态全局变量的好处坏处就可以了。
三. 如何让Flex调用服务端的Service(AMF3, Remote Object)
暂且假定,我们的项目使用的Remote Object方式去访问服务端
Why not Cairngorm Delegate?
老规矩,我们先来看看Cairngorm是怎么来调用服务端的
1. 在service.xml里添加配置项
2. 创建Delegate.as,并为RemoteObject添加对应的方法(这里需要为每个服务端对象都创建对应的Delegate和方法,工作量不但不小,而且很烦哦)
再来看看我们的写法吧:
1.在ServiceFactory里添加需要调用的Service和method的名字常量
2.调用方法
ServiceFactory.getService(ServiceFactory.USER_BIZ)
.callService(ServiceFactory.USER_BIZ_Insert, [newVO], this.result);
四. 使用Cache Framework提升我们的性能
有空再做哦……
但主要的思路是使用第三方的Cache工具在业务层做
如何在业务层管理你的Cache
上次初步研究了一下前台与后台的关系,但还遗留了一个Server端的Cache问题。
前言
在看过很多的Cache的文章和讨论后,我是这样使用Cache的
1. 在Session的生命周期内使用Hibernate的First Level Cache来缓存对象(数据访问层,细粒度缓存)
2. 使用EHCache对Value Object在业务层做缓存(粗粒度缓存,写代码实现)
为什么我不想使用Hibernate的二级缓存呢?主要有以下几点思考
为了提高它的性能,我们把Cache和持久层关连起来,值得吗?
有必要所有的地方都做Cache吗?这些性能的提升是客户想要的吗?
哪些地方需要做Cache不是只有业务层才知道吗?
关于Hibernate二级缓存详细的介绍,大家还是看看下面几篇文章吧,讲得很好
分析Hibernate的缓存机制
http://www.enet.com.cn/article/2008/0115/A20080115110243.shtml
hibernate二级缓存攻略
http://www.javaeye.com/topic/18904
Speed Up Your Hibernate Applications with Second-Level Caching
http://www.devx.com/dbzone/Article/29685/1954?pf=true
在现实生活中,在业务层做Cache又会有一些问题
在业务层需要做Cache的方法里要加上添加Cache或清除Cache的代码,这样不但做起来很麻烦,而且把Cache代码和业务逻辑混杂在一起。
在执行一个方法时,哪些关连的Cache需要被清除。如执行了UserBiz.update(userVO)后,需要清除findAll产生的所有Cache,同时也应该把id相同的findById产生的Cache清除。
下面的文章和代码也就是着重解决上面提到的问题
如附图所示,Spring会为所有的Biz方法加上MethodCacheInterceptor.java和 MethodCacheAfterAdvice.java,当方法执行之前,Interceptor会对照Annotation的配置去看此方法的结果需不需要和有没有被Cache,然后决定是否直接从Cache中获得结果(如findAll方法)。而After Advice是在方法执行后决定是否要做一些Cache的清理工作(如update方法)。
具体的Annotation配置方法请参照后面的UserBiz.java
废话和理论还是少说点,上代码才是硬道理
ApplicationContext.xml
Java代码 复制代码
1.
2.
3. 4. classpath:ehcache.xml
5.
6.

7.
8.
9. 10.
11.
12. 13. com.novem.common.cache.ehcache.METHOD_CACHE
14.
15.

16.
17.
18. 19.
20.
21.

22.
23.
24. 25.
26.
27.

28.
29.
30. 31. *Biz
32.
33. 34. 35. methodCacheInterceptor
36. methodCacheAfterAdvice
37.
38.
39.


classpath:ehcache.xml
com.novem.common.cache.ehcache.METHOD_CACHE


*Biz methodCacheInterceptor
methodCacheAfterAdvice

MethodCacheInterceptor.java
Java代码 复制代码
1. package com.novem.common.cache.ehcache;
2.
3. import java.io.Serializable;
4.
5. import net.sf.ehcache.Cache;
6. import net.sf.ehcache.Element;
7.
8. import org.aopalliance.intercept.MethodInterceptor;
9. import org.aopalliance.intercept.MethodInvocation;
10. import org.springframework.beans.factory.InitializingBean;
11. import org.springframework.util.Assert;
12.
13. import com.novem.common.cache.annotation.MethodCache;
14.
15. public class MethodCacheInterceptor implements MethodInterceptor,
16. InitializingBean
17. {
18. private Cache cache;
19.
20. /**
21. * sets cache name to be used
22. */
23. public void setCache(Cache cache)
24. {
25. this.cache = cache;
26. }
27.
28. /**
29. * Checks if required attributes are provided.
30. */
31. public void afterPropertiesSet() throws Exception
32. {
33. Assert.notNull(cache,
34. “A cache is required. Use setCache(Cache) to provide one.”);
35. }
36.
37. /**
38. * main method caches method result if method is configured for caching
39. * method results must be serializable
40. */
41. public Object invoke(MethodInvocation invocation) throws Throwable
42. {
43. // do not need to cache
44. if(!invocation.getMethod().isAnnotationPresent(MethodCache.class)
45. || MethodCache.FALSE.equals(invocation.getMethod().getAnnotation(MethodCache.class).isToCache()))
46. {
47. return invocation.proceed();
48. }
49.
50. String targetName = invocation.getThis().getClass().getName();
51. String methodName = invocation.getMethod().getName();
52. Object[] arguments = invocation.getArguments();
53. Object result;
54.
55. String cacheKey = getCacheKey(targetName, methodName, arguments);
56. Element element = cache.get(cacheKey);
57. if (element == null)
58. {
59. // call target/sub-interceptor
60. result = invocation.proceed();
61.
62. // cache method result
63. element = new Element(cacheKey, (Serializable) result);
64. cache.put(element);
65. }
66. return element.getValue();
67. }
68.
69. /**
70. * creates cache key: targetName.methodName.argument0.argument1…
71. */
72. private String getCacheKey(String targetName, String methodName,
73. Object[] arguments)
74. {
75. StringBuffer sb = new StringBuffer();
76. sb.append(targetName).append(“.”).append(methodName);
77. if ((arguments != null) && (arguments.length != 0))
78. {
79. for (int i = 0; i < arguments.length; i++) 80. { 81. sb.append(".").append(arguments[i]); 82. } 83. } 84. 85. return sb.toString(); 86. } 87. } package com.novem.common.cache.ehcache; import java.io.Serializable; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import com.novem.common.cache.annotation.MethodCache; public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean { private Cache cache; /** * sets cache name to be used */ public void setCache(Cache cache) { this.cache = cache; } /** * Checks if required attributes are provided. */ public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "A cache is required. Use setCache(Cache) to provide one."); } /** * main method caches method result if method is configured for caching * method results must be serializable */ public Object invoke(MethodInvocation invocation) throws Throwable { // do not need to cache if(!invocation.getMethod().isAnnotationPresent(MethodCache.class) || MethodCache.FALSE.equals(invocation.getMethod().getAnnotation(MethodCache.class).isToCache())) { return invocation.proceed(); } String targetName = invocation.getThis().getClass().getName(); String methodName = invocation.getMethod().getName(); Object[] arguments = invocation.getArguments(); Object result; String cacheKey = getCacheKey(targetName, methodName, arguments); Element element = cache.get(cacheKey); if (element == null) { // call target/sub-interceptor result = invocation.proceed(); // cache method result element = new Element(cacheKey, (Serializable) result); cache.put(element); } return element.getValue(); } /** * creates cache key: targetName.methodName.argument0.argument1... */ private String getCacheKey(String targetName, String methodName, Object[] arguments) { StringBuffer sb = new StringBuffer(); sb.append(targetName).append(".").append(methodName); if ((arguments != null) && (arguments.length != 0)) { for (int i = 0; i < arguments.length; i++) { sb.append(".").append(arguments[i]); } } return sb.toString(); } } MethodCacheAfterAdvice.java Java代码 复制代码 1. package com.novem.common.cache.ehcache; 2. 3. import java.lang.reflect.Method; 4. import java.util.List; 5. 6. import net.sf.ehcache.Cache; 7. 8. import org.springframework.aop.AfterReturningAdvice; 9. import org.springframework.beans.factory.InitializingBean; 10. import org.springframework.util.Assert; 11. 12. import com.novem.common.cache.annotation.CacheCleanMethod; 13. import com.novem.common.cache.annotation.MethodCache; 14. 15. public class MethodCacheAfterAdvice implements AfterReturningAdvice, 16. InitializingBean 17. { 18. private Cache cache; 19. 20. public void setCache(Cache cache) 21. { 22. this.cache = cache; 23. } 24. 25. public MethodCacheAfterAdvice() 26. { 27. super(); 28. } 29. 30. public void afterReturning(Object returnValue, Method method, 31. Object[] args, Object target) throws Throwable 32. { 33. // do not need to remove cache 34. if (!method.isAnnotationPresent(MethodCache.class) 35. || method.getAnnotation(MethodCache.class).cacheCleanMethods().length == 0) 36. { 37. return; 38. } 39. else 40. { 41. String targetName = target.getClass().getName(); 42. 43. CacheCleanMethod[] cleanMethods = method.getAnnotation( 44. MethodCache.class).cacheCleanMethods(); 45. List list = cache.getKeys(); 46. for (int i = 0; i < list.size(); i++) 47. { 48. for (int j = 0; j < cleanMethods.length; j++) 49. { 50. String cacheKey = String.valueOf(list.get(i)); 51. 52. StringBuffer tempKey = new StringBuffer(); 53. tempKey.append(targetName); 54. tempKey.append("."); 55. tempKey.append(cleanMethods[j].methodName()); 56. 57. if (CacheCleanMethod.CLEAN_BY_ID.equals(cleanMethods[j].cleanType())) 58. { 59. tempKey.append("."); 60. tempKey.append(getIdValue(target, method, args[0])); 61. } 62. 63. if (cacheKey.startsWith(tempKey.toString())) 64. { 65. cache.remove(cacheKey); 66. } 67. } 68. } 69. } 70. } 71. 72. private String getIdValue(Object target, Method method, Object idContainer) 73. { 74. String targetName = target.getClass().getName(); 75. 76. // get id value 77. String idValue = null; 78. if (MethodCache.TRUE.equals(method.getAnnotation(MethodCache.class) 79. .firstArgIsIdContainer())) 80. { 81. if (idContainer == null) 82. { 83. throw new RuntimeException( 84. "Id container cannot be null for method " 85. + method.getName() + " of " + targetName); 86. } 87. 88. Object id = null; 89. try 90. { 91. Method getIdMethod = idContainer.getClass().getMethod("getId"); 92. id = getIdMethod.invoke(idContainer); 93. } 94. catch (Exception e) 95. { 96. throw new RuntimeException("There is no getId method for " 97. + idContainer.getClass().getName()); 98. } 99. 100. if (id == null) 101. { 102. throw new RuntimeException("Id cannot be null for method " 103. + method.getName() + " of " + targetName); 104. } 105. idValue = id.toString(); 106. } 107. else if (MethodCache.TRUE.equals(method 108. .getAnnotation(MethodCache.class).firstArgIsId())) 109. { 110. if (idContainer == null) 111. { 112. throw new RuntimeException("Id cannot be null for method " 113. + method.getName() + " of " + targetName); 114. } 115. idValue = idContainer.toString(); 116. } 117. 118. return idValue; 119. } 120. 121. public void afterPropertiesSet() throws Exception 122. { 123. Assert.notNull(cache, 124. "Need a cache. Please use setCache(Cache) create it."); 125. } 126. 127. } package com.novem.common.cache.ehcache; import java.lang.reflect.Method; import java.util.List; import net.sf.ehcache.Cache; import org.springframework.aop.AfterReturningAdvice; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import com.novem.common.cache.annotation.CacheCleanMethod; import com.novem.common.cache.annotation.MethodCache; public class MethodCacheAfterAdvice implements AfterReturningAdvice, InitializingBean { private Cache cache; public void setCache(Cache cache) { this.cache = cache; } public MethodCacheAfterAdvice() { super(); } public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { // do not need to remove cache if (!method.isAnnotationPresent(MethodCache.class) || method.getAnnotation(MethodCache.class).cacheCleanMethods().length == 0) { return; } else { String targetName = target.getClass().getName(); CacheCleanMethod[] cleanMethods = method.getAnnotation( MethodCache.class).cacheCleanMethods(); List list = cache.getKeys(); for (int i = 0; i < list.size(); i++) { for (int j = 0; j < cleanMethods.length; j++) { String cacheKey = String.valueOf(list.get(i)); StringBuffer tempKey = new StringBuffer(); tempKey.append(targetName); tempKey.append("."); tempKey.append(cleanMethods[j].methodName()); if (CacheCleanMethod.CLEAN_BY_ID.equals(cleanMethods[j].cleanType())) { tempKey.append("."); tempKey.append(getIdValue(target, method, args[0])); } if (cacheKey.startsWith(tempKey.toString())) { cache.remove(cacheKey); } } } } } private String getIdValue(Object target, Method method, Object idContainer) { String targetName = target.getClass().getName(); // get id value String idValue = null; if (MethodCache.TRUE.equals(method.getAnnotation(MethodCache.class) .firstArgIsIdContainer())) { if (idContainer == null) { throw new RuntimeException( "Id container cannot be null for method " + method.getName() + " of " + targetName); } Object id = null; try { Method getIdMethod = idContainer.getClass().getMethod("getId"); id = getIdMethod.invoke(idContainer); } catch (Exception e) { throw new RuntimeException("There is no getId method for " + idContainer.getClass().getName()); } if (id == null) { throw new RuntimeException("Id cannot be null for method " + method.getName() + " of " + targetName); } idValue = id.toString(); } else if (MethodCache.TRUE.equals(method .getAnnotation(MethodCache.class).firstArgIsId())) { if (idContainer == null) { throw new RuntimeException("Id cannot be null for method " + method.getName() + " of " + targetName); } idValue = idContainer.toString(); } return idValue; } public void afterPropertiesSet() throws Exception { Assert.notNull(cache, "Need a cache. Please use setCache(Cache) create it."); } } MethodCache.java Java代码 复制代码 1. package com.novem.common.cache.annotation; 2. 3. import java.lang.annotation.Retention; 4. import java.lang.annotation.RetentionPolicy; 5. 6. @Retention(RetentionPolicy.RUNTIME) 7. public @interface MethodCache 8. { 9. String TO_CACHE = "TO_CACHE"; 10. String NOT_TO_CACHE = "NOT_TO_CACHE"; 11. 12. String TRUE = "TRUE"; 13. String FALSE = "FALSE"; 14. 15. public String isToCache() default TO_CACHE; 16. 17. public String firstArgIsId() default FALSE; 18. 19. public String firstArgIsIdContainer() default FALSE; 20. 21. public CacheCleanMethod[] cacheCleanMethods() default {}; 22. } package com.novem.common.cache.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface MethodCache { String TO_CACHE = "TO_CACHE"; String NOT_TO_CACHE = "NOT_TO_CACHE"; String TRUE = "TRUE"; String FALSE = "FALSE"; public String isToCache() default TO_CACHE; public String firstArgIsId() default FALSE; public String firstArgIsIdContainer() default FALSE; public CacheCleanMethod[] cacheCleanMethods() default {}; } CacheCleanMethod.java Java代码 复制代码 1. package com.novem.common.cache.annotation; 2. 3. import java.lang.annotation.Retention; 4. import java.lang.annotation.RetentionPolicy; 5. 6. @Retention(RetentionPolicy.RUNTIME) 7. public @interface CacheCleanMethod 8. { 9. String CLEAN_ALL = "CLEAN_ALL"; 10. String CLEAN_BY_ID = "CLEAN_BY_ID"; 11. 12. public String methodName(); 13. 14. public String cleanType() default CLEAN_ALL; 15. } package com.novem.common.cache.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface CacheCleanMethod { String CLEAN_ALL = "CLEAN_ALL"; String CLEAN_BY_ID = "CLEAN_BY_ID"; public String methodName(); public String cleanType() default CLEAN_ALL; } UserBiz.java Java代码 复制代码 1. package com.novem.farc.biz; 2. 3. import java.util.List; 4. 5. import com.novem.common.cache.annotation.CacheCleanMethod; 6. import com.novem.common.cache.annotation.MethodCache; 7. import com.novem.farc.vo.UserVO; 8. 9. public interface UserBiz 10. { 11. @MethodCache() 12. public UserVO findById(Long id); 13. 14. @MethodCache() 15. public List findAll(int firstResult, int maxResults); 16. 17. @MethodCache( 18. isToCache = MethodCache.FALSE, 19. firstArgIsIdContainer = MethodCache.TRUE, 20. cacheCleanMethods = {@CacheCleanMethod(methodName="findById", cleanType = CacheCleanMethod.CLEAN_BY_ID), 21. @CacheCleanMethod(methodName="findAll")} 22. ) 23. public void update(UserVO vo); 24. 25. @MethodCache( 26. isToCache = MethodCache.FALSE, 27. firstArgIsIdContainer = MethodCache.TRUE, 28. cacheCleanMethods = {@CacheCleanMethod(methodName="findAll")} 29. ) 30. public Long insert(UserVO vo); 31. 32. @MethodCache( 33. isToCache = MethodCache.FALSE, 34. firstArgIsId = MethodCache.TRUE, 35. cacheCleanMethods = {@CacheCleanMethod(methodName="findById", cleanType = CacheCleanMethod.CLEAN_BY_ID), 36. @CacheCleanMethod(methodName="findAll")} 37. ) 38. public void remove(Long id); 39. } package com.novem.farc.biz; import java.util.List; import com.novem.common.cache.annotation.CacheCleanMethod; import com.novem.common.cache.annotation.MethodCache; import com.novem.farc.vo.UserVO; public interface UserBiz { @MethodCache() public UserVO findById(Long id); @MethodCache() public List findAll(int firstResult, int maxResults); @MethodCache( isToCache = MethodCache.FALSE, firstArgIsIdContainer = MethodCache.TRUE, cacheCleanMethods = {@CacheCleanMethod(methodName="findById", cleanType = CacheCleanMethod.CLEAN_BY_ID), @CacheCleanMethod(methodName="findAll")} ) public void update(UserVO vo); @MethodCache( isToCache = MethodCache.FALSE, firstArgIsIdContainer = MethodCache.TRUE, cacheCleanMethods = {@CacheCleanMethod(methodName="findAll")} ) public Long insert(UserVO vo); @MethodCache( isToCache = MethodCache.FALSE, firstArgIsId = MethodCache.TRUE, cacheCleanMethods = {@CacheCleanMethod(methodName="findById", cleanType = CacheCleanMethod.CLEAN_BY_ID), @CacheCleanMethod(methodName="findAll")} ) public void remove(Long id); } 注意:如果@CacheCleanMethod的cleanType = CacheCleanMethod.CLEAN_BY_ID,则此方法的第一个参数一定要是对象的ID(userId)或ID container(UserVO, 并且此对象中要有getId方法)。之所以要有这样的限制,我是觉得在企业开发中,大家follow这样的规则就好,没必要为了能灵活地取出ID再多搞出一些配置项出来。 为什么我不使用XML来配置Cache呢? 下面是我最早的时候写的一个配置XML,但后来发现,使用这种方法,就得为每一个Biz配置一个XML,就和早期的xxx.hbm.xml一样,管理起来比较麻烦,不如Annotation简洁 UserBiz.cache.xml Java代码 复制代码 1.
2.
3.
4.
5.
6.
7.
8.
9.

10.

11.
12.
13.
14.

15.

16.
17.
18.
19.
20.

21.

22.

23.

Spring Rich Client Project

mikel阅读(742)

官方介绍:
What is spring-richclient?
Spring-RCP's mission is to provide an elegant way to build highly-configurable, GUI-standards-following rich-client applications faster by leveraging the Spring Framework, and a rich library of UI factories and support classes.
官方网站:
http://spring-rich-c.sourceforge.net/1.0.0/

使用 Django 和 Python 开发 Web 站点

mikel阅读(805)

文档选项
将此页作为电子邮件发送
将此页作为电子邮件发送
级别: 中级
Ian Maurer (ian@itmaurer.com), 资深顾问, Brulant, Inc.
2006 年 7 月 03 日
本系列文章一共有两篇,本文是其中的第一篇。在这一篇文章中,我们将展示 Django 的用法,Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC)风格的 Web 应用程序框架。使用 Django,我们在几分钟之内就可以创建高品质、易维护、数据库驱动的应用程序。
Django 项目是一个定制框架,它源自一个在线新闻 Web 站点,于 2005 年以开源的形式被释放出来。Django 框架的核心组件有:
* 用于创建模型的对象关系映射
* 为最终用户设计的完美管理界面
* 一流的 URL 设计
* 设计者友好的模板语言
* 缓存系统
本文是有关 Python Web 框架的由两篇文章组成的系列文章的第一篇。第二篇文章将向您介绍 TurboGears 框架。
要使用并理解本文中提供的代码,则需要安装 Python,并了解在初学者的水平上如何使用 Python。要查看是否安装了 Python 以及 Python 的版本号,可以输入 python -V。Django 至少需要 2.3.5 版本的 Python,可以从 Python Web 站点上下载它(关于链接请参阅本文后面 参考资料 部分)。我们至少还应该顺便熟悉一下 MVC 架构。
安装 Django
本文使用了 Django 的开发版本,以便能够利用 Django 框架的最新改进。建议您在 0.95 版正式发布之前使用这个版本。关于最新发行版本,请参阅 Django 的 Web 站点(再次请您参阅 参考资料 来获得链接)。
按照以下步骤下载并安装 Django:
清单 1. 下载并安装 Django
~/downloads# svn co http://code.djangoproject.com/svn/django/trunk/ django_src
~/downloads# cd django_src
~/downloads# python setup.py install
回页首
Django 管理工具
在安装 Django 之后,您现在应该已经有了可用的管理工具 django-admin.py。清单 2 给出了这个管理工具中可以使用的一些命令:
清单 2. 使用 Django 管理工具
~/dev$ django-admin.py
usage: django-admin.py action [options]
actions:
adminindex [modelmodule …]
Prints the admin-index template snippet for the given model
module name(s).
… snip …
startapp [appname]
Creates a Django app directory structure for the given app name
in the current directory.
startproject [projectname]
Creates a Django project directory structure for the given
project name in the current directory.
validate
Validates all installed models.
options:
-h, –help show this help message and exit
–settings=SETTINGS Python path to settings module, e.g.
“myproject.settings.main”. If this isn't
provided, the DJANGO_SETTINGS_MODULE
environment variable will be used.
–pythonpath=PYTHONPATH
Lets you manually add a directory the Python
path, e.g. “/home/djangoprojects/myproject”.
回页首
Django 项目和应用程序
要启动 Django 项,请使用 django-admin startproject 命令,如下所示:
清单 3. 启动项目
~/dev$ django-admin.py startproject djproject
上面这个命令会创建一个 djproject 目录,其中包含了运行 Django 项目所需要的基本配置文件:
清单 4. djproject 目录的内容
__init__.py
manage.py
settings.py
urls.py
对于这个项目来说,我们要构建一个职位公告板应用程序 “jobs”。要创建应用程序,可以使用 manage.py 脚本,这是一个特定于项目的 django-admin.py 脚本,其中 settings.py 文件可以自动提供:
清单 5. 使用 manage.py startapp
~/dev$ cd djproject
~/dev/djproject$ python manage.py startapp jobs
这将创建一个应用程序骨架,其中模型有一个 Python 模块,视图有另外一个 Python 模块。jobs 目录中包含以下文件:
清单 6. jobs 应用程序目录中的内容
__init__.py
models.py
views.py
提供应用程序在项目中的位置纯粹是为新 Django 开发人员建立的一种惯例,并不是必需的。一旦开始在几个项目中混合使用应用程序,就可以将应用程序放到自己的命名空间中,并使用设置和主 URL 文件将它们绑定在一起。现在,请按照下面给出的步骤执行操作。
为了使 Django 认识到新应用程序的存在,还需要向 settings.py 文件中的 INSTALLED_APPS 添加一个条目。对于这个职位公告板应用程序来说,我们必须添加字符串 djproject.jobs:
清单 7. 向 settings.py 中添加一个条目
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'djproject.jobs',
)
回页首
创建一个模型
Django 提供了自己的对象关系型数据映射组件(object-relational mapper,ORM)库,它可以通过 Python 对象接口支持动态数据库访问。这个 Python 接口非常有用,功能十分强大,但如果需要,也可以灵活地不使用这个接口,而是直接使用 SQL
orM 目前提供了对 PostgreSQL、MySQL、SQLite 和 Microsoft® SQL 数据库的支持。
这个例子使用 SQLite 作为后台数据库。SQLite 是一个轻量级数据库,它不需要进行任何配置,自身能够以一个简单文件的形式存在于磁盘上。要使用 SQLite,可以简单地使用 setuptools 来安装 pysqlite(有关 setuptools 的更多资料,尤其是有关 easy_install 工具(需要单独安装)的资料,请参阅 参考资料):
easy_install pysqlite
在使用这个模型之前,需要在设置文件中对数据库进行配置。SQLite 只需要指定数据库引擎和数据库名即可。
清单 8. 在 settings.py 中配置数据库
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = '/path/to/dev/djproject/database.db'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
这个职位公告板应用程序有两种类型的对象:Location 和 Job。Location 包含 city、state(可选)和 country 字段。Job 包含 location、title、description 和 publish date 字段。
清单 9. jobs/models.py 模块
from django.db import models
class Location(models.Model):
city = models.CharField(maxlength=50)
state = models.CharField(maxlength=50, null=True, blank=True)
country = models.CharField(maxlength=50)
def __str__(self):
if self.state:
return “%s, %s, %s” % (self.city, self.state, self.country)
else:
return “%s, %s” % (self.city, self.country)
class Job(models.Model):
pub_date = models.DateField()
job_title = models.CharField(maxlength=50)
job_description = models.TextField()
location = models.ForeignKey(Location)
def __str__(self):
return “%s (%s)” % (self.job_title, self.location)
__str__ 方法是 Python 中的一个特殊类,它返回对象的字符串表示。Django 在 Admin 工具中显示对象时广泛地使用了这个方法。
要设置这个模型的模式,请返回 manage.py 的 sql 命令。此时模式尚未确定。
清单 10. 使用 manage.py sql 命令查看数据库模式
~/dev/djproject$ python manage.py sql jobs
BEGIN;
Create TABLE “jobs_job” (
“id” integer NOT NULL PRIMARY KEY,
“pub_date” date NOT NULL,
“job_title” varchar(50) NOT NULL,
“job_description” text NOT NULL,
“location_id” integer NOT NULL
);
Create TABLE “jobs_location” (
“id” integer NOT NULL PRIMARY KEY,
“city” varchar(50) NOT NULL,
“state” varchar(50) NULL,
“country” varchar(50) NOT NULL
);
COMMIT;
为了初始化并安装这个模型,请运行数据库命令 syncdb:
~/dev/djproject$ python manage.py syncdb
注意,syncdb 命令要求我们创建一个超级用户帐号。这是因为 django.contrib.auth 应用程序(提供基本的用户身份验证功能)默认情况下是在 INSTALLED_APPS 设置中提供的。超级用户名和密码用来登录将在下一节介绍的管理工具。记住,这是 Django 的超级用户,而不是系统的超级用户。
回页首
查询集
Django 模型通过默认的 Manager 类 objects 来访问数据库。例如,要打印所有 Job 的列表,则应该使用 objects 管理器的 all 方法:
清单 11. 打印所有的职位
>>> from jobs.models import Job
>>> for job in Job.objects.all():
… print job
Manager 类还有两个过滤方法:一个是 filter,另外一个是 exclude。过滤方法可以接受满足某个条件的所有方法,但是排除不满足这个条件的其他方法。下面的查询应该可以给出相同的结果(“gte” 表示 “大于或等于”,而 “lt” 表示 “小于”)。
清单 12. 排除和过滤职位
>>> from jobs.models import Job
>>> from datetime import datetime
>>> q1 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1))
>>> q2 = Job.objects.exclude(pub_date__lt=datetime(2006, 1, 1))
filter 和 exclude 方法返回一些 QuerySet 对象,这些对象可以链接在一起,甚至可以执行连接操作。下面的 q4 查询会查找从 2006 年 1 月 1 日开始在俄亥俄州的 Cleveland 张贴的职位:
清单 13. 对职位进行更多的排除和过滤
>>> from jobs.models import Job
>>> from datetime import datetime
>>> q3 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1))
>>> q4 = q3.filter(location__city__exact=”Cleveland”,
… location__state__exact=”Ohio”)
QuerySets 是惰性的,这一点非常不错。这意味着只在对数据库进行求值之后才会对它们执行查询,这会比立即执行查询的速度更快。
这种惰性利用了 Python 的分片(slicing)功能。下面的代码并没有先请求所有的记录,然后对所需要的记录进行分片,而是在实际的查询中使用了 5 作为 OFFSET、10 作为 LIMIT,这可以极大地提高性能。
清单 14. Python 分片
>>> from jobs.models import Job
>>> for job in Job.objects.all()[5:15]
… print job
注意:使用 count 方法可以确定一个 QuerySet 中有多少记录。Python 的 len 方法会进行全面的计算,然后统计那些以记录形式返回的行数,而 count 方法执行的则是真正的 SQL COUNT 操作,其速度更快。我们这样做,数据库管理员会感激我们的。
清单 15. 统计记录数
>>> from jobs.models import Job
>>> print “Count = “, Job.objects.count() # GOOD!
>>> print “Count = “, len(Job.objects.all()) # BAD!
有关的更多信息,请参阅 参考资料 部分给出的 Django “Database API reference” 的链接。
回页首
管理员工具
Django 的最大卖点之一是其一流的管理界面。这个工具是按照最终用户的思路设计的。它为我们的项目提供了很多数据输入工具。
管理工具是 Django 提供的一个应用程序。与 jobs 应用程序一样,在使用之前也必须进行安装。第一个步骤是将应用程序的模块(django.contrib.admin)添加到 INSTALLED_APPS 设置中:
清单 16. 修改 settings.py
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'djproject.jobs',
'django.contrib.admin',
)
要让该管理工具可以通过 /admin URL 使用,只需要简单地取消项目的 urls.py 文件中提供的对应行的内容即可。下一节将详细介绍 URL 的配置。
清单 17. 使管理工具可以通过 urls.py 使用
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls.admin')),
)
这个管理应用程序有自己的数据库模型,但也需要进行安装。我们可以再次使用 syncdb 命令来完成这个过程:
python manage.py syncdb
要查看这个管理工具,可以使用 Django 提供的测试服务器。
清单 18. 使用测试服务器来查看管理工具
~/dev/djproject$ python manage.py runserver
Validating models…
0 errors found.
Django version 0.95 (post-magic-removal), using settings 'djproject.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).
现在可以使用 http://localhost:8000/admin 启动管理工具,并使用前面创建的超级用户帐号进行登录。我们注意到现在还没有可用的模块。
要让一个类可以通过管理工具进行访问,我们需要为其创建一个 Admin 子类。然后可以通过为这个子类添加类属性来定制如何对每个类进行管理。清单 19 展示了如何将 Location 类添加到这个管理工具中。
清单 19. 使用管理工具添加 Location 类
class Location(meta.Model):

class Admin:
list_display = (“city”, “state”, “country”)
现在就可以通过管理界面来创建、更新和删除 Location 记录了。
图 1. 使用管理工具编辑位置
使用管理工具编辑位置
可以按照 list_display 类的属性指定的城市、州和国家来列出记录并对它们进行排序。
图 2. 使用管理工具显示位置
使用管理工具显示位置
管理工具有无数用来管理每种模块类的选项。清单 20 给出了几个适用于 Job 类的例子:
清单 20. 管理模块类的选项
class Job(meta.Model):

class Admin:
list_display = (“job_title”, “location”, “pub_date”)
ordering = [“-pub_date”]
search_fields = (“job_title”, “job_description”)
list_filter = (“location”,)
根据以上设置,职位的标题、位置和发布日期都会在显示职位记录时用到。职位可以按照发布时间进行排序,最开始是最近发布的职位(减号表示降序)。用户可以按照标题和说明来查找职位,管理员可以根据位置对记录进行过滤。
图 3. 使用管理工具显示职位
使用管理工具显示职位
回页首
设计 URL 方案
Django URL 分发系统使用了正则表达式配置模块,它可以将 URL 字符串模式映射为 Python 方法 views。这个系统允许 URL 与底层代码完全脱节,从而实现最大的控制和灵活性。
urls.py 模块被创建和定义成 URL 配置的默认起点(通过 settings.py 模块中的 ROOT_URLCONF 值)。URL 配置文件的惟一要求是必须包含一个定义模式 urlpatterns 的对象。
这个职位公告板应用程序会在启动时打开一个索引和一个详细视图,它们可以通过以下的 URL 映射进行访问:
* /jobs 索引视图:显示最近的 10 个职位
* /jobs/1 详细视图:显示 ID 为 1 的职位信息
这两个视图(索引视图和详细视图)都是在这个 jobs 应用程序的 views.py 模块中实现的。在项目的 urls.py 文件中实现这种配置看起来如下所示:
清单 21. 在 djproject/urls.py 中实现视图的配置
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls.admin')),
(r'^jobs/$', 'djproject.jobs.views.index'),
(r'^jobs/(?P\d+)/$', 'djproject.jobs.views.detail'),
)
注意 部分,这在后面非常重要。
最佳实践是提取出应用程序特有的 URL 模式,并将它们放入应用程序自身中。这样可以取消应用程序与项目的耦合限制,从而更好地实现重用。jobs 使用的应用程序级的 URL 配置文件如下所示:
清单 22. 应用程序级的 URL 配置文件 urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^$', 'djproject.jobs.views.index'),
(r'^(?P\d+)/$', 'djproject.jobs.views.detail'),
)
由于 view 方法现在都是来自同一个模块,因此第一个参数可以使用这个模块的根名称来指定 djproject.jobs.views,Django 会使用它来查找 index 方法和 detail 方法:
清单 23. jobs/urls.py:查找 index 和 detail 方法
from django.conf.urls.defaults import *
urlpatterns = patterns('djproject.jobs.views',
(r'^$', 'index'),
(r'^(?P\d+)/$', 'detail'),
)
尝试上面的 jobs URL 会返回到这个项目中,因为它们是使用 include 函数将其作为一个整体来实现的。应用程序级的 URL 被绑定到下面的 /jobs 部分:
清单 24. djproject/urls.py:将 URL 送回该项目
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls.admin')),
(r'^jobs/', include('djproject.jobs.urls')),
)
如果现在尝试使用测试服务器来访问索引页(http://localhost:8000/jobs),会得到一个错误,因为正在调用的视图(djproject.jobs.views.index)不存在。
回页首
实现视图
视图是一个简单的 Python 方法,它接受一个请求对象,负责实现:
* 任何业务逻辑(直接或间接)
* 上下文字典,它包含模板数据
* 使用一个上下文来表示模板
* 响应对象,它将所表示的结果返回到这个框架中
在 Django 中,当一个 URL 被请求时,所调用的 Python 方法称为一个视图(view),这个视图所加载并呈现的页面称为模板(template)。由于这个原因,Django 小组将 Django 称为一个 MVT(model-view-template)框架。另一方面,TurboGears 把自己的方法称作控制器(controller),将所呈现的模板称为视图(view),因此缩写也是 MVC。其区别在于广义的语义,因为它们所实现的内容是相同的。
最简单的视图可能会返回一个使用字符串初始化过的 HttpResponse 对象。创建下面的方法,并生成一个 /jobs HTTP 请求,以确保 urls.py 和 views.py 文件都已经正确设置。
清单 25. jobs/views.py (v1)
from django.utils.httpwrappers import HttpResponse
def index(request):
return HttpResponse(“Job Index View”)
下面的代码将获取最近的 10 个职位,并通过一个模板呈现出来,然后返回响应。没有 下一节 中的模板文件,这段代码就无法 正常工作。
清单 26. jobs/views.py (v2)
from django.template import Context, loader
from django.http import HttpResponse
from jobs.models import Job
from django.template import Context, loader
from django.http import HttpResponse
from jobs.models import Job
def index(request):
object_list = Job.objects.order_by('-pub_date')[:10]
t = loader.get_template('jobs/job_list.html')
c = Context({
'object_list': object_list,
})
return HttpResponse(t.render(c))
在上面的代码中,模板是由 jobs/job_list.html 字符串进行命名的。该模板是使用名为 object_list 的职位列表的上下文呈现的。所呈现的模板字符串随后被传递到 HTTPResponse 构造器中,后者通过这个框架被发送回请求客户机那里。
加载模板、创建内容以及返回新响应对象的步骤在下面都被 render_to_response 方法取代了。新增内容是详细视图方法使用了一个 get_object_or_404 方法,通过该方法使用所提供的参数获取一个 Job 对象。如果没有找到这个对象,就会触发 404 异常。这两个方法减少了很多 Web 应用程序中的样板代码。
清单 27. jobs/views.py (v3)
from django.shortcuts import get_object_or_404, render_to_response
from jobs.models import Job
def index(request):
object_list = Job.objects.order_by('-pub_date')[:10]
return render_to_response('jobs/job_list.html',
{'object_list': object_list})
def detail(request, object_id):
job = get_object_or_404(Job, pk=object_id)
return render_to_response('jobs/job_detail.html',
{'object': job})
注意,detail 使用 object_id 作为一个参数。这是前面提到过的 jobs urls.py 文件中 /jobs/ URL 路径后面的数字。它以后会作为主键(pk)传递给 get_object_or_404 方法。
上面的视图仍然会失败,因为它们所加载和呈现的模板(jobs/job_list.html and jobs/job_detail.html)不存在。
回页首
创建模板
Django 提供了一种模板语言,该语言被设计为能够快速呈现且易于使用。Django 模板是利用 {{ variables }} 和 {% tags %} 中嵌入的文本创建的。变量会使用它们表示的值进行计算和替换。标记用来实现基本的控制逻辑。模板可以用来生成任何基于文本的格式,包括 HTML、XML、CSV 和纯文本。
第一个步骤是定义将模板加载到什么地方。为了简便起见,我们需要在 djproject 下面创建一个 templates 目录,并将这个路径添加到 settings.py 的 TEMPLATE_DIRS 条目中:
清单 28. 在 settings.py 中创建一个 templates 目录
TEMPLATE_DIRS = (
'/path/to/devdir/djproject/templates/',
)
Django 模板支持称为模板继承(template inheritance)的概念,它允许站点设计人员创建一个统一的外表,而不用替换每个模板的内容。我们可以通过使用块标记定义骨干文档或基础文档来使用继承。这些块标记都是使用一些包含内容的页面模板来填充的。这个例子给出了一个包含称为 title、extrahead 和 content 的块的 HTML 骨干:
清单 29. 骨干文档 templates/base.html



Company Site: {% block title %}Page{% endblock %}
{% block extrahead %}{% endblock %}


{% block content %}{% endblock %}


为了取消应用程序与项目之间的耦合,我们使用了一个中间基本文件作为 Job 应用程序所有页面文件的基础。对于这个例子来说,为了简便起见,我们将应用程序的 CSS 放到这个基本文件中。在实际的应用程序中,需要有一个正确配置的 Web 服务器,将这个 CSS 提取出来,并将其放到 Web 服务器所服务的静态文件中。
清单 30. 中间基础文件 templates/jobs/base.html
{% extends “base.html” %}
{% block extrahead %}

{% endblock %}
默认情况下,Django 测试服务器并不会为静态文件提供服务,因为这是 Web 服务器的工作。但是在开发过程中,如果您希望 Django 可以提供图像、样式表等,那么请参阅 参考资料 中有关如何激活这个特性的链接。
现在我们要创建视图所加载并呈现的两个页面模板。jobs/job_list.html 模板简单地循环遍历 object_list,它通过索引视图遍历其内容,并显示一个到每条记录的详细页面的链接。
清单 31. templates/jobs/job_list.html 模板
{% extends “jobs/base.html” %}
{% block title %}Job List{% endblock %}
{% block content %}

Job List

{% endblock %}
jobs/job_detail.html 页面会显示一条称为 job 的记录:
清单 32. templates/jobs/job_detail.html 页面
{% extends “jobs/base” %}
{% block title %}Job Detail{% endblock %}
{% block content %}

Job Detail

{{ job.job_title }}

{{ job.location }}
Posted: {{ job.pub_date|date:”d-M-Y” }}
{{ job.job_description }}

{% endblock %}
Django 模板语言已经被设计为只能实现有限的功能。这种限制可以为非程序员保持模板的简单性,同时还可以让程序员不会将业务逻辑放到不属于自己的地方,即表示层。请参阅 参考资料 中模板语言文档的链接。
回页首
通用视图
Django 提供了 4 种通用视图(generic view),它们可以让开发人员创建遵循典型模式的应用程序:
* 页面列表/详细页面(与上面的例子类似)
* 基于数据的记录分类(对于新闻或 blog 站点非常有用)
* 对象的创建、更新和删除(CRUD)
* 简单直接的模板表示或简单地对 HTTP 重新进行定向
我们没有创建样板视图方法,而是将所有的业务逻辑都放入了 urls.py 文件中,它们都由 Django 提供的通用视图进行处理。
清单 33. jobs/urls.py 中的通用视图
from django.conf.urls.defaults import *
from jobs.models import Job
info_dict = {
'queryset': Job.objects.all(),
}
urlpatterns = patterns('django.views.generic.list_detail',
(r'^$', 'object_list', info_dict),
(r'^(?P\d+)/$', 'object_detail', info_dict),
)
这个 urls.py 文件中的 3 个主要变化如下:
* info_dict 映射对象会为要访问的 Job 提供一个查询集。
* 它使用了 django.views.generic.list_detail,而不是 djproject.jobs.views。
* 真正的视图调用是 object_list 和 object_detail。
这个项目需要遵循一些要求才能让通用视图自动工作:
* 通用详细视图期望获得一个 object_id 参数。
* 模板遵循下面的命名模式:app_label/model_name_list.html (jobs/job_list.html) app_label/model_name_detail.html (jobs/job_detail.html)
* 列表模板处理一个名为 object_list 的列表。
* 详细模板处理一个名为 object 的对象。
更多选项可以通过 info_dict 来传递,其中包括指定每个页面中对象个数的 paginate_by 值。
回页首
结束语
本系列的下一篇文章将介绍 TurboGears,这是另外一个 Python Web 框架;并且会将该框架与 Django 进行比较。
参考资料
学习
* 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
* 请参阅 Wikipedia 上的 overview of the MVC architecture。
* “使用 Ruby on Rails 快速开发 Web 应用程序”(developerWorks,2005 年 6 月)展示了如何使用 Ruby on Rails 创建基于 Web 的应用程序。
* Python.org 是 Python 编程语言的大本营,在那里可以找到下载 Python 解释器和标准库的链接。
* Python 教程 可以帮助我们快速入门 Python。
* DjangoProject.com 是 Django 框架的主页。其中的文档包括:
o How to install Django,展示了如何在一台开发机器上设置 Django
o Database API reference,使用 Django orM 库的指南
o Django template language,为模板作者准备的一份简单指南
o How to serve static files,如何在开发过程中通过设置 Django 来提供静态文件服务的介绍(不要在产品环境中这样做)
o How to use Django with mod_python,这是一份有关利用 mod_python 组合使用 Django 和 Apache 的指南
o Generic views,展示了如何使用 Django 的通用视图更快地实现通用的 Web 应用程序模式
* Building and Distributing Packages with setuptools 展示了如何安装 setuptools 和 easy_install(Python Eggs 包的一部分)
* Django performance tips 展示了如何使用 Django 处理大量通信
* 在 developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多资源。
* 随时关注 developerWorks 技术事件和网络广播。
获得产品和技术
* 订购免费的 SEK for Linux,它有两张 DVD,其中包括最新的 IBM for Linux 的试用版软件,这些软件包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
* 可以使用 IBM 试用版软件 改进您的下一个开发项目,从 developerWorks 可以直接下载该软件。
讨论
* 通过参与 developerWorks blogs 加入 developerWorks 社区。
关于作者
作者照片:Ian Maurer
Ian Maurer 是 Brulant, Inc. 的一名资深顾问,他擅长使用开源软件和 IBM WebSphere 技术为各个行业开发集成的电子商务解决方案,其中包括消费品和零售行业。Ian 居住在东北部的俄亥俄州,他是 Cleveland Area Python Interest Group 的成员。

分页SQL

mikel阅读(996)

表中主键必须为标识列,[ID] int IDENTITY (1,1)
1.分页方案一:(利用Not In和Select TOP分页)
语句形式:
Select TOP 10 *
FROM TestTable
Where (ID NOT IN
(Select TOP 20 id
FROM TestTable
orDER BY id))
orDER BY ID
Select TOP 页大小 *
FROM TestTable
Where (ID NOT IN
(Select TOP 页大小*页数 id
FROM 表
orDER BY id))
orDER BY ID
2.分页方案二:(利用ID大于多少和Select TOP分页)
语句形式:
Select TOP 10 *
FROM TestTable
Where (ID >
(Select MAX(id)
FROM (Select TOP 20 id
FROM TestTable
orDER BY id) AS T))
orDER BY ID
Select TOP 页大小 *
FROM TestTable
Where (ID >
(Select MAX(id)
FROM (Select TOP 页大小*页数 id
FROM 表
orDER BY id) AS T))
orDER BY ID
3.分页方案三:(利用SQL的游标存储过程分页)
create procedure SQLPager
@sqlstr nvarchar(4000), –查询字符串
@currentpage int, –第N页
@pagesize int –每页行数
as
set nocount on
declare @P1 int, –P1是游标的id
@rowcount int
exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1, @rowcount=@rowcount output
select ceiling(1.0*@rowcount/@pagesize) as 总页数–,@rowcount as 总行数,@currentpage as 当前页
set @currentpage=(@currentpage-1)*@pagesize+1
exec sp_cursorfetch @P1,16,@currentpage,@pagesize
exec sp_cursorclose @P1
set nocount off
其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。
建议优化的时候,加上主键和索引,查询效率会提高。
通过SQL 查询分析器,显示比较:我的结论是:
分页方案二:(利用ID大于多少和Select TOP分页)效率最高,需要拼接SQL语句
分页方案一:(利用Not In和Select TOP分页) 效率次之,需要拼接SQL语句
分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用
我们在编写MIS系统和Web应用程序等系统时,都涉及到与数据库的交互,如果数据库中数据量很大的话,一次检索所有的记录,会占用系统很大的资源,因此我们常常采用,需要多少数据就只从数据库中取多少条记录,即采用分页语句。根据自己使用过的内容,把常见数据库Sql Server,Oracle和My sql的分页语句,从数据库表中的第M条数据开始取N条记录的语句总结如下:
SQL Server
从数据库表中的第M条记录开始取N条记录,利用Top关键字:注意如果Select语句中既有top,又有order by,则是从排序好的结果集中选择:
Select *
FROM ( Select Top N *
FROM (Select Top (M + N – 1) * FROM 表名称 order by 主键 desc) t1 ) t2
order by 主键 asc
例如从表Sys_option(主键为sys_id)中从10条记录还是检索20条记录,语句如下:
Select *
FROM ( Select TOP 20 *
FROM (Select TOP 29 * FROM Sys_option order by sys_id desc) t1) t2
order by sys_id asc
oralce数据库
从数据库表中第M条记录开始检索N条记录
Select *
FROM (Select ROWNUM r,t1.* From 表名称 t1 where rownum < M + N) t2 where t2.r >= M
例如从表Sys_option(主键为sys_id)中从10条记录还是检索20条记录,语句如下:
Select *
FROM (Select ROWNUM R,t1.* From Sys_option where rownum < 30 ) t2 Where t2.R >= 10
My sql数据库
My sql数据库最简单,是利用mysql的LIMIT函数,LIMIT [offset,] rows从数据库表中M条记录开始检索N条记录的语句为:
Select * FROM 表名称 LIMIT M,N
例如从表Sys_option(主键为sys_id)中从10条记录还是检索20条记录,语句如下:
select * from sys_option limit 10,20

Spring.net

mikel阅读(742)

第一章. 介绍
1.1. 概览
Spring.NET 是一个关注于.NET企业应用开发的应用程序框架。它能够提供宽广范围的功能,例如依赖注入、面向方面编程(AOP)、数据访问抽象, 以及ASP.NET集成等。基于java的spring框架的核心概念和价值已被应用到.NET。Spring.NET 1.0 包含一个完全功能的依赖注入容器和AOP库。后续的发布将包含对ASP.NET、Remoting和数据访问的支持。下图展现出了 Spring .NET的各个模块。具有黑色阴影的模块包含在1.0版本中,其他模块计划在将来的发布中推出。在很多情况下,你可以在我们的下载网站中发现可以工作的计划模块的实现。

Spring.Core 库是框架的基础, 提供依赖注入功能。Spring.NET中大多数类库依赖或扩展了Spring.Core的功能。IObjectFactory接口提供了一个简单而优雅的工厂模式,移除了对单例和一些服务定位stub写程序的必要。允许你将真正的程序逻辑的配置和依赖的详细情况解耦。作为对IObjectFactory的扩展,IApplicationContext接口也在Spring.Core库中,并且添加了许多企业应用为中心的功能,例如利用资源文件进行文本本地化、事件传播、资源加载等等。
Spring.Aop 库提供对业务对象的面向方面编程(AOP) 的支持。Spring.Aop 库是对Spring.Core库的补充,可为声明性地建立企业应用和为业务对象提供服务提供坚实的基础。
Spring.Web 库扩展了ASP.NET,添加了一些功能,如对ASP.NET页面的依赖注入,双向数据绑定,针对 ASP.NET 1.1的Master pages以及改进的本地化支持。
Spring.Services库可让你将任何“一般”对象(即没有从其他特殊的服务基类继承的对象)暴露为企业服务或远程对象,使得.NET Web services 获得依赖注入的支持,并覆盖属性元数据。此外还提供了对Windows Service的集成。
Spring.Data 库提供了数据访问层的抽象,可以被多个数据访问提供者(从ADO.NET 到多个ORM 提供者)应用。它还包含一个对ADO.NET的抽象层,移除了为ADO.NET编写可怕的编码和声明性的事务管理的必要。
Spring.ORM库提供了对常见对象关系映射库的的集成,提供了一些功能,比如对声明性事务管理的支持。
官方网站:http://www.springframework.net/
官方文档:[urlhttp://www.springframework.net/documentation.html#Reference_Manual_and_API]document
[/url]
官方下载:点击下载

xFire下载及实例

mikel阅读(831)

http://xfire.codehaus.org/Download
终于,使用Java完成了一个WebService的例子,其中的一个非常小的问题,折腾了我将近一天的时间。下面给出步骤,说明在Java平台上如何开发WebService。
采用的工具:Eclipse3.1.2 + Tomcat5.5 + XFire1.1 。使用XFire开发WebService应该说非常的容易,只需要按照下面例子的步骤来做:
(1)在Eclipse中新建一个dynamic Web Project ,假设名为XFireZhuweiTest。
(2)导入XFire用户库。该库中应包含xfire-1.1目录下的xfire-all-1.1.jar文件,以及xfire-1.1\lib目录下的所有文件。
(3)将上述的XFire用户库中的所有文件拷贝到XFireZhuweiTest项目的WebContent\WEB-INF\lib目录下。
(4)修改WebContent\WEB-INF\web.xml配置文件的内容,下面是修改后web.xml:



XFireZhuweiTest


index.html
index.htm
index.jsp
default.html
default.htm
default.jsp


XFireServlet

org.codehaus.xfire.transport.http.XFireConfigurableServlet



XFireServlet
/servlet/XFireServlet/*


XFireServlet
/services/*


web.xml中添加的servlet映射表明,所有匹配“/services/*”的url请求全部交给org.codehaus.xfire.transport.http.XFireConfigurableServlet来处理。
(5)编写需要发布为WebService的Java类,这个例子中是一个非常简单的MathService.java。
package com.zhuweisky.xfireDemo;
public class MathService
{
public int Add(int a ,int b)
{
return a+b ;
}
}
(6)在WebContent\META-INF目录下新建xfire文件夹,然后在xfire目录下添加一个XFire使用的配置文件services.xml,该配置文件中的内容反映了要将哪些java类发布为web服务。本例中的services.xml内容如下:



MathService
http://com.zhuweisky.xfireDemo/MathService
com.zhuweisky.xfireDemo.MathService


XFire会借助Spring来解析services.xml,从中提取需要发布为WebService的配置信息。
很多文章介绍到这里就完了,然而当我按照他们所说的启动WebService ,然后通过http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 来访问服务描述时,却抛出了异常,说services.xml文件不存在--
“org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [META-INF/xfire/services.xml]; nested exception is java.io.FileNotFoundException: class path resource [META-INF/xfire/services.xml] cannot be opened because it does not exist”。
(7)非常关键的一点,就是这个小难题花费了我将近一天的时间。
在WebContent\WEB-INF目录下新建classes文件夹,然后需要将WebContent下的整个META-INF文件夹剪切到新建的classes文件夹下。
到这里,项目的完整目录结构如下:

(8)在Package Explorer中选中XFireZhuweiTest项目,右键->Run As ->Run On Server,关联到你机器上的TomCat,然后会启动Tomcat,以启动web服务。(注意,在进行此步骤之前,请先停止TomCat)
(9)在IE中输入 http://localhost:8080/XFireZhuweiTest/services/MathService?wsdl 会得到正确的web服务描述文档。
(10)测试刚发布的webService。我使用C#动态调用Web服务:
//C#
string url = “http://localhost:8080/XFireZhuweiTest/services/MathService” ;
object[] args ={1,2} ;
object result = ESFramework.WebService.WebServiceHelper.InvokeWebService(url ,”Add” ,args) ;
MessageBox.Show(result.ToString());
(关于C#动态调用Web服务,请参见这里)
执行后,弹出对话框,显示结果是3。

spring+xfire+webservice+helloworld

mikel阅读(868)

由于我们网站的sso系统要实行夸语言,跨服务器的特点,按照领导的指示
要用webService 我就google找了一下关于webService的资料,发现webService还非常复杂,自然我只能最简单的办法来搞了,找了近一个小时,终于在一个老外的网站上看到了关于xfire插件支持java,最重要的是支持spring框架而且非常简单就实现了功能,好在简单提示英语只有初中水平就可以看懂,要不以我这我英语水平是根本看不懂的,我把例子download下来后查看代码,发现老外还是非常友好的代码在ecilpse下打包后直接在 tomcat发布就ok了,和想像的结果一样
我就不这webService的例子拿出来和大家分享了。
Echo.java
package org.codehaus.xfire.spring.example;
public interface Echo{
String echo(String in);
}
EchoImpl.java
package org.codehaus.xfire.spring.example;
public class EchoImpl implements Echo{
public String echo(String in){
return in;
}
}
applicationContext.xml




这上面的就最简单的spring IoC 下helloworld的例子
这文件xfire-servlet.xml配置是关键:
xfire-servlet.xml






org.codehaus.xfire.spring.example.Echo

接下来是客户端的test就更简单了
客户端
applicationContext-client.xml


org.codehaus.xfire.spring.example.Echo http://127.0.0.1:8080/xfire/EchoService?wsdl

package test;
import java.util.*;
import junit.framework.TestCase;
import org.codehaus.xfire.spring.example.*;
public class WebServiceClientTest extends TestCase {
Echo echo=null;
static {
ApplicationContextFactory.init(/test/applicationContext-client.xml);
}
public static void main(String[] args) {
junit.swingui.TestRunner.run(PlayContextDaoTest.class);
}
protected void setUp() throws Exception {
echo=(Echo)ApplicationContextFactory.getApplicationContext().getBean(testWebService);
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testCilient(){
System.out.print(echo.echo(haoha i haohao));
}
}
XmlSchema-1.0.3.jar activation-1.1.jar
bcprov-jdk15-133.jar
commons-attributes-api-2.1.jar
commons-beanutils-1.7.0.jar
commons-codec-1.3.jar
commons-discovery-0.2.jar
commons-httpclient-3.0.jar
commons-logging-1.0.4.jar
jaxb-api-1.0.jar
jaxb-api-2.0EA3.jar
jaxb-impl-1.0.5.jar
jaxb-impl-2.0EA3.jar
jaxb-xjc-2.0EA3.jar
jaxen-1.1-beta-8.jar
jdom-1.0.jar
jmock-1.0.1.jar
junit-3.8.1.jar
log4j-1.2.6.jar
mail-1.4.jar
opensaml-1.0.1.jar
org.mortbay.jetty-5.1.3.jar
relaxngDatatype-20050913.jar
spring-1.2.6.jar
stax-api-1.0.1.jar
stax-utils-snapshot-20040917.jar
sun-jaxws-api-2.0-ea3.jar
sun-saaj-api-2.0-ea3.jar
sun-saaj-impl-2.0-ea3.jar
wsdl4j-1.5.2.jar
wss4j-1.5.0.jar
wstx-asl-2.9.3.jar
xbean-2.1.0.jar
xbean-spring-2.3.jar
xercesImpl-2.6.2.jar
xfire-aegis-1.1.jar
xfire-annotations-1.1.jar
xfire-core-1.1.jar
xfire-distribution-1.1.jar
xfire-generator-1.1.jar
xfire-java5-1.1.jar
xfire-jaxb-1.1.jar
xfire-jaxb2-1.1.jar
xfire-jaxws-1.1.jar
xfire-jsr181-api-1.0-M1.jar
xfire-spring-1.1.jar
xfire-ws-security-1.1.jar
xfire-xmlbeans-1.1.jar
xml-apis-1.0.b2.jar
xmlsec-1.3.0.jar
xsdlib-20050913.jar