随笔-295  评论-26  文章-1  trackbacks-0
  2007年6月28日



            //允许输入字母、点、回退键、数字
            if (((int)e.KeyChar >= (int)'a' && (int)e.KeyChar <= (int)'z') || (((int)e.KeyChar > 48 && (int)e.KeyChar < 57) || (int)e.KeyChar == 8 || (int)e.KeyChar == 46))
            {
                e.Handled = false;
            }
            else e.Handled = true;



      //允许输入字母、回退键、数字
            if (((int)e.KeyChar >= (int)'a' && (int)e.KeyChar <= (int)'z') || (((int)e.KeyChar > 48 && (int)e.KeyChar < 57) || (int)e.KeyChar == 8))
            {
                e.Handled = false;
            }
            else e.Handled = true; 


// 只能输入字母数字以及中文字
  if ((e.KeyChar != '\b') && (!Char.IsLetter(e.KeyChar)) && (!char.IsDigit(e.KeyChar)))
            {
                e.Handled = true;
            }

//只输入数字
 if (e.KeyChar != 8 && (!Char.IsDigit(e.KeyChar)))
            {
                e.Handled = true;
            }

只能输入数字以及字母X

  if (e.KeyChar != 88 && e.KeyChar != 8 && (!Char.IsDigit(e.KeyChar)))
            {
                e.Handled = true;
            }
posted @ 2020-06-13 10:46 华梦行 阅读(157) | 评论 (0)编辑 收藏
Install-Package NLog.Config -Version 3.2.1



Install-Package NLog -Version 3.2.1
posted @ 2020-01-06 16:10 华梦行 阅读(124) | 评论 (0)编辑 收藏
  • mysql5.7以上版本在常会报关于only_full_group_by的错误,可以在sql_mode中关闭他,网上查找的解
  • 在[mysqld]中添加代码
sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

重启mysql

sudo service mysql restart

mysql5.7以上版本在常会报关于only_full_group_by的错误,可以在sql_mode中关闭他,网上查找的解
查看参数是否存在

mysql> SELECT @@sql_mode;
+------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                                             |
+------------------------------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT @@GLOBAL.sql_mode;
+------------------------------------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                                                      |
+------------------------------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
posted @ 2019-09-15 22:02 华梦行 阅读(151) | 评论 (0)编辑 收藏

MYSQL_HOME     解压路径   C:\DevelopTool\MySQL\mysql-5.7.25-winx64    

 

 

 Path     %MYSQL_HOME%\bin



>mysqld --initialize --user=mysql --console
mysqld -install 

先启动服务:

net start MySQL【或者是MySQL57】

修改密码
mysqladmin -uroot -p123456 password 123 


sc delete 服务名例如: sc delete mysql



https://www.cnblogs.com/july7/p/11489029.html

远程访问
use mysql;
GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '密码' WITH GRANT OPTION;
flush privileges;
posted @ 2019-09-14 22:51 华梦行 阅读(129) | 评论 (0)编辑 收藏
需要添加一个环境变量POSTMAN_DISABLE_GPU = true。
posted @ 2019-05-18 11:11 华梦行 阅读(524) | 评论 (0)编辑 收藏

在了解REST API URI设计的规则之前,让我们快速浏览一些我们将要讨论的术语。

URIs

REST API使用统一资源标识符(URI)来寻址资源。在当今互联网上,充斥着各种各样的URI设计规则,既有像//api.example.com/louvre/leonardo-da-vinci/mona-lisa这样能够清楚的传达API资源模型的文章,也有很难理解的文章,例如://api.example.com/68dd0-a9d3-11e0-9f1c-0800200c9a66 ;Tim Berners-Lee在他的“Axioms of Web Architecture”一文中将URI的不透明度总结成一句话:

唯一可以使用标识符的是引用对象。在不取消引用时,就不应该查看URI字符串的内容以获取其他信息。 
——蒂姆·伯纳斯 - 李

客户端必须遵循Web的链接范例,将URI视为不透明标识符。

REST API设计人员应该在考虑将REST API资源模型传达给潜在的客户端开发者的前提下,创造URI。在这篇文章中,我将尝试为REST API URI 引入一套设计规则

先跳过规则,URI的通用语法也适用与本文中的URI。RFC 3986定义了通用URI语法,如下所示:

URI = scheme “://” authority “/” path [ “?” query ][ “#” fragment ]

规则1:URI结尾不应包含(/)

这是作为URI路径中处理中最重要的规则之一,正斜杠(/)不会增加语义值,且可能导致混淆。REST API不允许一个尾部的斜杠,不应该将它们包含在提供给客户端的链接的结尾处。

许多Web组件和框架将平等对待以下两个URI: 
http://api.canvas.com/shapes/ 
http://api.canvas.com/shapes

但是,实际上URI中的每个字符都会计入资源的唯一身份的识别中。

两个不同的URI映射到两个不同的资源。如果URI不同,那么资源也是如此,反之亦然。因此,REST API必须生成和传递精确的URI,不能容忍任何的客户端尝试不精确的资源定位。

有些API碰到这种情况,可能设计为让客户端重定向到相应没有尾斜杠的URI(也有可能会返回301 - 用来资源重定向)。

规则2:正斜杠分隔符(/)必须用来指示层级关系

URI的路径中的正斜杠(/)字符用于指示资源之间的层次关系。

例如: 
(http://api.canvas.com/shapes/polygons/quadrilaterals/squares ;

规则3:应使用连字符( - )来提高URI的可读性

为了使您的URI容易让人们理解,请使用连字符( - )字符来提高长路径中名称的可读性。在路径中,应该使用连字符代空格连接两个单词 。

例如: 
http://api.example.com/blogs/guy-levin/posts/this-is-my-first-post

规则4:不得在URI中使用下划线(_)

一些文本查看器为了区分强调URI,常常会在URI下加上下划线。这样下划线(_)字符可能被文本查看器中默认的下划线部分地遮蔽或完全隐藏。

为避免这种混淆,请使用连字符( - )而不是下划线

规则5:URI路径中首选小写字母

方便时,URI路径中首选小写字母,因为大写字母有时会导致一些问题。RFC 3986将URI定义为区分大小写,但scheme 和 host components除外。

例如: 
http://api.example.com/my-folder/my-doc

HTTP://API.EXAMPLE.COM/my-folder/my-doc 
这个URI很好。URI格式规范(RFC 3986)认为该URI与URI#1相同。

http://api.example.com/My-Folder/my-doc 
而这个URI与URI 1和2不同,这可能会导致不必要的混淆。

规则6:文件扩展名不应包含在URI中

在Web上,(.)字符通常用于分隔URI的文件名和扩展名。 
REST API不应在URI中包含人造文件扩展名,来指示邮件实体的格式。相反,他们应该依赖通过Content-Type中的header传递media type,来确定如何处理正文的内容。

http://api.college.com/students/3248234/courses/2005/fall.json 
http://api.college.com/students/3248234/courses/2005/fall

如上所示:不应使用文件扩展名来表示格式。

应鼓励REST API客户端使用HTTP提供的格式选择机制Accept request header。

为了是链接和调试更简单,REST API应该支持通过查询参数来支持媒体类型的选择。

规则7:端点名称是单数还是复数?

keep-it-simple的原则在这里同样适用。虽然一些”语法学家”会告诉你使用复数来描述资源的单个实例是错误的,但实际上为了保持URI格式的一致性建议使用复数形式。

本着API提供商更容易实施和API使用者更容易操作的原则,可以不必纠结一些奇怪的复数(person/people,goose/geese)。

但是应该怎么处理层级关系呢?如果一个关系只能存在于另一个资源中,RESTful原则就会提供有用的指导。我们来看一下这个例子。学生有一些课程。这些课程在逻辑上映射到学生终端,如下所示:

http://api.college.com/students/3248234/courses - 检索id为3248234的学生学习的所有课程的清单。 
http://api.college.com/students/3248234/courses/physics -检索该学生的物理课程

结论

当你在设计REST API服务时,您必须注意这些由URI定义的资源。

正在构建的服务中的每个资源将至少有一个URI标识它。这个URI最好是有意义的,且能充分描述资源。URI应遵循可预测的层次结构,用来提高其可理解性,可用性:可预测的意义在于它们是一致的,它的层次结构在数据关系上是有意义的。

RESTful API是为使用者编写的。URI的名称和结构应该能够向使用者传达更清晰的含义。通过遵循上述规则,您将创建一个更清晰的的REST API与更友好的客户端。这些并不是REST的规则或约束,仅仅是API的增强和补充。

我也建议你来看看http://blog.restcase.com/5-basic-rest-api-design-guidelines/这篇文章。

最后,望大家牢记:你在为你的客户端设计API URI,而不仅仅是为你的数据。

posted @ 2017-06-26 09:50 华梦行 阅读(222) | 评论 (0)编辑 收藏

* this.getClass().getClassLoader().getResourceAsStream("testVariables.bpmn")

       classpath根目录下加载指定名称的文件

 * this.getClass().getResourceAsStream("testVariables.bpmn")   

       从当前包下加载指定名称的文件

 * this.getClass().getResourceAsStream("/testVariables.bpmn") 

       从classpath根目录下加载指定名称的文件

posted @ 2017-06-19 14:45 华梦行 阅读(115) | 评论 (0)编辑 收藏
package org.gdharley.activiti.integration.rest;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.JavaDelegate;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;


/**
 * Created by gharley on 5/2/17.
 
*/
public class SimpleRestDelegate implements JavaDelegate {
    private static final Logger logger = LoggerFactory.getLogger(SimpleRestDelegate.class);

    protected Expression endpointUrl;
    protected Expression httpMethod;
    protected Expression isSecure;
    protected Expression payload;

//    一个Content-Type是application/json的请求,具体看起来是这样的:
//    POST /some-path HTTP/1.1
//    Content-Type: application/json
//
//    { "foo" : "bar", "name" : "John" }
//
//
//    { "foo" : "bar", "name" : "John" } 就是这个请求的payload



    protected Expression headers;
    protected Expression responseMapping;

    protected ObjectMapper objectMapper = new ObjectMapper();

    // Create a mixin to force the BasicNameValuePair constructor
    protected static abstract class BasicNameValuePairMixIn {
        private BasicNameValuePairMixIn(@JsonProperty("name") String name, @JsonProperty("value") String value) {
        }
    }

    public void execute(DelegateExecution execution) throws Exception {
        logger.info("Started Generic REST call delegate");

        if (endpointUrl == null || httpMethod == null) {
            throw new IllegalArgumentException("An endpoint URL and http method are required");
        }

        String restUrl = getExpressionAsString(endpointUrl, execution);
        String payloadStr = getExpressionAsString(payload, execution);
        String headersJSON = getExpressionAsString(headers, execution); // [{"name":"headerName", "value":"headerValue"}]
        String method = getExpressionAsString(httpMethod, execution);
        String rMapping = getExpressionAsString(responseMapping, execution);
        String secure = getExpressionAsString(isSecure, execution);
        String scheme = secure == "true" ? "https" : "http";

        // validate URI and create create request
        URI restEndpointURI = composeURI(restUrl, execution);

        logger.info("Using Generic REST URI " + restEndpointURI.toString());

        HttpRequestBase httpRequest = createHttpRequest(restEndpointURI, scheme, method, headersJSON, payloadStr, rMapping);

        // create http client
        CloseableHttpClient httpClient = createHttpClient(httpRequest, scheme, execution);

        // execute request
        HttpResponse response = executeHttpRequest(httpClient, httpRequest);

        // map response to process instance variables
        if (responseMapping != null) {
            mapResponse(response, rMapping, execution);
        }

        logger.info("Ended Generic REST call delegate");

    }

    protected URI composeURI(String restUrl, DelegateExecution execution)
            throws URISyntaxException {

        URIBuilder uriBuilder = null;
        uriBuilder = encodePath(restUrl, uriBuilder);
        return uriBuilder.build();
    }

    protected URIBuilder encodePath(String restUrl, URIBuilder uriBuilder) throws URISyntaxException {

        if (StringUtils.isNotEmpty(restUrl)) {

            // check if there are URL params
            if (restUrl.indexOf('?') > -1) {

                List<NameValuePair> params = URLEncodedUtils.parse(new URI(restUrl), "UTF-8");

                if (params != null && !params.isEmpty()) {
                    restUrl = restUrl.substring(0, restUrl.indexOf('?'));
                    uriBuilder = new URIBuilder(restUrl);
                    uriBuilder.addParameters(params);

                }
            } else {
                uriBuilder = new URIBuilder(restUrl);
            }
        }

        return uriBuilder;
    }

    protected HttpRequestBase createHttpRequest(URI restEndpointURI, String scheme, String httpMethod, String headers, String payload, String responseMapping) {

        if (StringUtils.isEmpty(httpMethod)) {
            throw new ActivitiException("no HTTP method provided");
        }
        if (restEndpointURI == null) {
            throw new ActivitiException("no REST endpoint URI provided");
        }

        HttpRequestBase httpRequest = null;
        HttpMethod parsedMethod = HttpMethod.valueOf(httpMethod.toUpperCase());
        StringEntity input;
        URIBuilder builder = new URIBuilder(restEndpointURI);

        switch (parsedMethod) {
            case GET:
                try {
                    httpRequest = new HttpGet(builder.build());
                    httpRequest = addHeadersToRequest(httpRequest, headers);
                } catch (URISyntaxException use) {
                    throw new ActivitiException("Error while building GET request", use);
                }
                break;
            case POST:
                try {
                    httpRequest = new HttpPost(builder.build());
                    input = new StringEntity(payload);
//                input.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                    ((HttpPost) httpRequest).setEntity(input);
                    httpRequest = addHeadersToRequest(httpRequest, headers);
                    break;
                } catch (Exception e) {
                    throw new ActivitiException("Error while building POST request", e);
                }
            case PUT:
                try {
                    httpRequest = new HttpPut(builder.build());
                    input = new StringEntity(payload);
//                input.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                    ((HttpPut) httpRequest).setEntity(input);
                    httpRequest = addHeadersToRequest(httpRequest, headers);
                    break;
                } catch (Exception e) {
                    throw new ActivitiException("Error while building PUT request", e);
                }
            case DELETE:
                try {
                    httpRequest = new HttpDelete(builder.build());
                    httpRequest = addHeadersToRequest(httpRequest, headers);
                } catch (URISyntaxException use) {
                    throw new ActivitiException("Error while building DELETE request", use);
                }
                break;
            default:
                throw new ActivitiException("unknown HTTP method provided");
        }

        return httpRequest;
    }


    protected CloseableHttpClient createHttpClient(HttpRequestBase request, String scheme, DelegateExecution execution) {

        SSLConnectionSocketFactory sslsf = null;

        // Allow self signed certificates and hostname mismatches.
        if (StringUtils.equalsIgnoreCase(scheme, "https")) {
            try {
                SSLContextBuilder builder = new SSLContextBuilder();
                builder.loadTrustMaterial(nullnew TrustSelfSignedStrategy());
                sslsf = new SSLConnectionSocketFactory(builder.build(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            } catch (Exception e) {
                logger.warn("Could not configure HTTP client to use SSL", e);
            }
        }

        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();

        if (sslsf != null) {
            httpClientBuilder.setSSLSocketFactory(sslsf);
        }

        return httpClientBuilder.build();
    }

    protected HttpResponse executeHttpRequest(CloseableHttpClient httpClient, HttpRequestBase httpRequest) {

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpRequest);
        } catch (IOException e) {
            throw new ActivitiException("error while executing http request: " + httpRequest.getURI(), e);
        }

        if (response.getStatusLine().getStatusCode() >= 400) {
            throw new ActivitiException("error while executing http request " + httpRequest.getURI() + " with status code: "
                    + response.getStatusLine().getStatusCode());
        }

        return response;
    }

    protected void mapResponse(HttpResponse response, String responseMapping, DelegateExecution execution) {

        if (responseMapping == null || responseMapping.trim().length() == 0) {
            return;
        }

        JsonNode jsonNode = null;
        try {
            String jsonString = EntityUtils.toString(response.getEntity());
            jsonNode = objectMapper.readTree(jsonString);

        } catch (Exception e) {
            throw new ActivitiException("error while parsing response", e);
        }

        if (jsonNode == null) {
            throw new ActivitiException("didn't expect an empty response body");
        }
        execution.setVariable(responseMapping, jsonNode.toString());
    }

    protected HttpRequestBase addHeadersToRequest(HttpRequestBase httpRequest, String headerJSON) {
        Boolean contentTypeDetected = false;
        if (headerJSON != null) {
            // Convert JSON to array
            try {
                // configuration for Jackson/fasterxml
                objectMapper.addMixInAnnotations(BasicNameValuePair.class, BasicNameValuePairMixIn.class);
                NameValuePair[] headers = objectMapper.readValue(headerJSON, BasicNameValuePair[].class);
                for (NameValuePair header : headers) {
                    httpRequest.addHeader(header.getName(), header.getValue());
                    if (header.getName().equals(HTTP.CONTENT_TYPE)) {
                        contentTypeDetected = true;
                    }
                }
            } catch (Exception e) {
                throw new ActivitiException("Unable to parse JSON header array", e);
            }
        }
        // Now add content type if necessary
        if (!contentTypeDetected) {
            httpRequest.addHeader(HTTP.CONTENT_TYPE, "application/json");
        }
        return httpRequest;
    }

    /**
     * 
@return string value of expression.
     * 
@throws {@link IllegalArgumentException} when the expression resolves to a value which is not a string
     *                or if the value is null.
     
*/
    protected String getExpressionAsString(Expression expression, DelegateExecution execution) {
        if (expression == null) {
            return null;
        } else {
            Object value = expression.getValue(execution);
            if (value instanceof String) {
                return (String) value;
            } else {
                throw new IllegalArgumentException("Expression does not resolve to a string or is null: " + expression.getExpressionText());
            }
        }
    }
}
posted @ 2017-05-26 08:01 华梦行 阅读(229) | 评论 (0)编辑 收藏

1、概述

activiti系统一共有23个表,包括流程定义表、一般数据信息表、流程运行实例表、流程历史记录表、用户用户组表。

2、Activiti 流程定义表

流程定义表,流程定义表也可以叫做是静态资源库,静态资源包括图片、定义规则等。它有部署信息表、流程模型表、流程定义表

1、ACT_RE_DEPLOYMENT(部署信息表)

包括:部署流程名称、类型、部署时间

2、ACT_RE_MODEL(模型表)

名称,key、类型、创建时间、最后修改时间、版本、数据源信息、部署ID、编辑源值ID、编辑源额外值ID(外键ACT_GE_BYTEARRAY )

3、ACT_RE_PROCDEF(流程定义表) 

包括流程定义、类型、流程名称、流程key、版本号、部署ID、资源名称、图片资源名称、描述信息、是否从key启动、暂停状态。

3、Activiti 运行实例表

运行实例表记录流程流转过程中产生的数据,一般数据分为两个部分流程数据、业务数据。流程数据是指activiti流程引擎流转过程中的数据,包括流程执行实例数据接、任务数据、执行任务人员信息、变量信息。业务数据则是流程过程中保存的表单数据,例如:如请假的请假单数据、报销单数据、审批意见信息等,此部分数据一般需要自己建数据表进行保存,在之前的jbpm4中没有保存业务数据。

1、ACT_RU_EVENT_SUBSCR(事件子脚本)作用未知

事件名称(EVENT_NAME_)、事件类型(EVENT_TYPE_)、流程执行ID(EXECUTION_ID_)、流程实例ID(PROC_INST_ID_)、活动ID(ACTIVITY_ID_)、配置信息(CONFIGURATION_)、创建时间(CREATED_)

2、ACT_RU_EXECUTION(执行中流程执行)核心我的代办任务查询表

流程实例ID(PROC_INST_ID_),业务key(BUSINESS_KEY_)、父执行流程(PARENT_ID_)、流程定义Id(外键PROC_DEF_ID_)、实例id(ACT_ID_)、激活状态(IS_ACTIVE_)、并发状态(is_concurrent)、is_scope、is_evnet_scope、暂停状态(suspension_state)、缓存结束状态(cached_end_state)

3、ACT_RU_IDENTITYLINK(身份联系)

用户组ID(GROUP_ID_)、用户组类型(TYPE_)、用户ID(USER_ID_)、任务Id(外键:TASK_ID_)、流程实例ID(外键:PROC_INST_ID_)、流程定义Id(外键:PROC_DEF_ID_)

4、ACT_RU_JOB(运行中的任务)

5、ACT_RU_TASK(执行中实时任务)代办任务查询表

实例id(外键EXECUTION_ID_)、流程实例ID(外键PROC_INST_ID_)、流程定义ID(PROC_DEF_ID_)、任务名称(NAME_)、父节任务ID(PARENT_TASK_ID_)

、任务描述(DESCRIPTION_)、任务定义key(TASK_DEF_KEY_)、所属人(OWNER_)、代理人员 (ASSIGNEE_)、代理团(DELEGATION_)、优先权(PRIORITY_)、创建时间(CREATE_TIME_)、执行时间(DUE_DATE_)、暂停状态(SUSPENSION_STATE_)

6、ACT_RU_VARIABLE(实时变量)

变量名称(NAME_)、编码类型(TYPE_)、执行实例ID(EXECUTION_ID_)、流程实例Id(PROC_INST_ID_)、任务id(TASK_ID_)、字节组ID(BYTEARRAY_ID_)、DOUBLE_、LONG_、TEXT_、TEXT2_

3、流程历史记录

流程历史信息表,activiti历史记录表包括节点信息表、附件信息表、历史审批记录表、理想详细信息表、历史身份信息表、流程实例历史表、任务历史表、历史变量表。(节点信息表、附件信息表、历史审批记录表、理想详细信息表、历史身份信息表)这些表目前还未知是如何用的。(流程实例历史表、任务历史表、历史变量)三个表可以查询我已完成任务、任务追踪等。

1、ACT_HI_ACTINST(活动实例信息)

流程定义ID(PROC_DEF_ID_)、流程实例ID(PROC_INST_ID_)、流程执行ID(EXECUTION_ID_)、活动ID(ACT_ID_)、活动名称(TASK_ID_)、活动类型(ACT_TYPE_)、任务ID、(TASK_ID_)、请求流程实例ID(CALL_PROC_INST_ID_)、代理人员(ASSIGNEE_)、开始时间(START_TIME_)、结束时间(END_TIME_)、时长(DURATION_)

2、ACT_HI_ATTACHMENT(附件信息)

用户id(USER_ID_)、名称(NAME_)、描述(DESCRIPTION_)、类型(TYPE_)、任务Id(TASK_ID_)、流程实例ID(PROC_INST_ID_)、连接(URL_)、内容Id(CONTENT_ID_)

3、ACT_HI_COMMENT(历史审批信息)

类型(TYPE_)、时间(TIME_)、用户Id(USER_ID_)、任务Id(TASK_ID_)、流程实例Id(PROC_INST_ID_)、活动(ACTION_)、消息(MESSAGE_)、全部消息(FULL_MSG_)

4、ACT_HI_DETAIL(历史详细信息)

数据类型(TYPE_)、创建时间(TIME_)、名称(NAME_)、流程实例ID(PROC_INST_ID_)、执行实例Id(EXECUTION_ID_)、任务Id(TASK_ID_)、活动实例Id(ACT_INST_ID_)、变量类型(VAR_TYPE_)、字节数组Id、DOUBLE_、LONG_、值(TEXT_)、值2(TEXT2_)

5、ACT_HI_IDENTITYLINK(历史身份信息)

任务Id(TASK_ID_)、流程实例Id(PROC_INST_ID_)、userId(USER_ID_)、用户组类型Type(TYPE_)、用户组ID(GROUP_ID_)

6、ACT_HI_PROCINST(历史流程实例信息)核心表

流程实例ID(PROC_INST_ID_)、业务Key(BUSINESS_KEY_)、流程定义Id(PROC_DEF_ID_)、开始时间(START_TIME_)、结束时间(END_TIME_)、时长(DURATION_)、发起人员Id(START_USER_ID_)、开始节点(START_ACT_ID_)、结束节点(END_ACT_ID_)、超级流程实例Id(SUPER_PROCESS_INSTANCE_ID_)、删除理由(DELETE_REASON_)

7、ACT_HI_TASKINST(历史任务流程实例信息)核心表

流程实例ID(PROC_INST_ID_)、任务定义Key(BUSINESS_KEY_)、流程定义Id(PROC_DEF_ID_)、执行ID(EXECUTION_ID_)、名称(NAME_)、父任务iD(PARENT_TASK_ID_)、描述(DESCRIPTION_)、所属人(OWNER_)、代理人(ASSIGNEE_)、开始时间(START_TIME_)、结束时间(END_TIME_)、时长(DURATION_)、删除理由(DELETE_REASON__)、优先级(PRIORITY_)、应完成时间(DUE_DATE_)、表单key(FORM_KEY_)

8、ACT_HI_VARINST(历史变量信息)

流程实例ID(PROC_INST_ID_)、执行ID(EXECUTION_ID_)、任务Id、名称(NAME_)、变量(TASK_ID_)、类型(VAR_TYPE_)、字节数组ID(BYTEARRAY_ID_)、DOUBLE_、LONG_、TEXT_、TEXT2_

4、一般数据

1、ACT_GE_BYTEARRAY(字节数据表)

名称(NAME_)、部署Id(DEPLOYMENT_ID_)、字节数据(BYTES_)、发生的(GENERATED_)

2、ACT_GE_PROPERTY(一般属性表)

名称(NAMe_)、值(VALUe_)

5、用户用户组表

Activit 的用户用户组表,包括用户信息、用户组信息、用户与用户组间的关系、用户信息与用户之间的关系。在实际开发中未采用,用的实际系统中用户。

1、ACT_ID_GROUP(用户组表)

名称(NAME_)、类型(TYPE_)

2、ACT_ID_USER(用户表)

姓(FIRST_)、名称(LAST_)、邮件(EMAIL_)、密码(PWD_)、头像Id (PICTURE_ID_)

3、ACT_ID_INFO(用户信息表)

用户Id(USER_ID_)、类型(TYPE_)、formINPut名称(KEY_)、值(VALUE_)、密码(PASSWORD_)、父节点(PARENT_ID_)

4、ACT_ID_MEMBERSHIP(用户用户组关联表)

用户Id(user_ID_)、用户组Id(group_Id)

Activiti表结构分析完成,花了5个小时,还有很多问题不明白。后续慢慢开发过程中再理一次表之间关系吧,初步想法在系统中需要扩建表,把业务数据和流程数据分开。

posted @ 2017-05-16 16:31 华梦行 阅读(2118) | 评论 (0)编辑 收藏
     摘要: Activiti工作流引擎数据库表结构 数据库表的命名 Acitiviti数据库中表的命名都是以ACT_开头的。第二部分是一个两个字符用例表的标识。此用例大体与服务API是匹配的。 l  ACT_RE_*:’RE’表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。 l  ACT_RU_*:̵...  阅读全文
posted @ 2017-05-15 22:23 华梦行 阅读(227) | 评论 (0)编辑 收藏
@Transient 可选 @Transient表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性. 如果一个属性并非数据库表的字段映射,就务必将其标示为@Transient,否则,ORM框架默认其注解为@Basic 示例: //根据birth计算出age属性 @Transient public int getAge() { return getYear(new Date()) - getYear(birth); } 注意是加在get方法上的
posted @ 2017-05-10 16:59 华梦行 阅读(1091) | 评论 (0)编辑 收藏
Snmpwalk –v 2 –c public 192.168.20.114 1.3.6.1.2.1.2.2.1.3
snmpget -r:127.0.0.1 -o:.1.3.6.1.2.1.25.3.3.1.2
E:\>snmpget -r:127.0.0.1 -o:.1.3.6.1.2.1.1.1.0
SnmpGet v1.01 - Copyright (C) 2009 SnmpSoft Company
[ More useful network tools on http://www.snmpsoft.com ]
OID=.1.3.6.1.2.1.1.1.0
Type=OctetString
Value=Hardware: Intel64 Family 6 Model 60 Stepping 3 AT/AT COMPATIBLE - Software
: Windows Version 6.1 (Build 7601 Multiprocessor Free)
snmpwalk -v:2c -c:public -r:127.0.0.1
posted @ 2017-03-22 15:28 华梦行 阅读(132) | 评论 (0)编辑 收藏

Druid是什么?

Druid是一个JDBC组件,它包括四个部分:

http://download.csdn.net/download/feelnature/1580901
http://tomcat.apache.org/tomcat-8.5-doc/monitoring.html#Enabling_JMX_Remote

http://download.csdn.net/detail/qq_21163257/9695557

 

  • DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。
  • DruidDataSource 高效可管理的数据库连接池。
  • SQLParser
  • 扩展组件
  • Binary: http://code.alibabatech.com/mvn/releases/com/alibaba/druid/0.1.2/druid-0.1.2.jar
  • Source: http://code.alibabatech.com/mvn/releases/com/alibaba/druid/0.1.2/druid-0.1.2-sources.jar

Druid可以做什么?

  • 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  • 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  • 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  • SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  • 扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

DruidDriver,是一个ProxyJdbcDriver,它提供了Filter-Chain模式的扩展机制,使得在Jdbc扩展编程特别方便。

Druid提供了一些内置的扩展机制,包括StatLogTrace、HA等扩展。


DruidDataSource是一个数据库连接池的实现,它的设计目标是提供一个当前最好的数据库连接池,在性能、扩展性等方面取得最合适的平衡,取代DBCP、C3P0等连接池。

  • 高性能。测试数据表明,Druid比DBCP、C3P0、BoneCP的性能都好很多。具体请看测试数据
  • 可管理性,DruidDataSource本身提供了很多监控属性,具体看这里。DruidDataSource支持StatFilter,具体配置看 这里
  • 可扩展性,提供基于Filter-Chain模式的扩展机制。具体自定义扩展的例子看这里
  • 替换DBCP,配置和DBCP兼容,可以方便替换DBCP。
  • 适合大规模应用。结合Alibaba使用数据库连接池的经验,避免一些已知问题,例如数据库不可用恢复之后产生的连接风暴问题等。

设计

这是DruidDataSource的设计图示:
http://code.alibabatech.com/svn/druid/trunk/doc/druid-pool.txt
如果发现有乱码,请选择utf-8的编码方式查看。

Druid提供一个手工编写的高性能的方便扩展的SQL Parser。将会支持MySQL、Oracle等流行关系数据库的SQL Parser。

Parser组件包括如下几个部分:

  • Lexer 词法解析
  • Parser,Parser包括ExprParser,各种StatementParser。
  • AST, Abstract Syntax Tree。ParserParse出来的结果就是AST。
  • Visitor。对AST做各种处理,比如FormatOutput,遍历等等。

简介

 

Druid提供了强大的监控功能,能够监控连接池行为和SQL执行情况,让你能够详细了解应用的数据库访问行为。

监控对象

  • Druid的统计信息定义代码实现在com/alibaba/druid/stat下。所有的Stat都全局静态变量的方式保存,这样做使得外部获取监控信息更容易。
  • 获取Druid监控信息的入口是com.alibaba.druid.stat.JdbcStatManager
  • Druid的监控统计信息都是通过StatFilter来实现的,如果你需要数据源进行监控,那你需要启用StatFilter
 
posted @ 2017-03-21 00:11 华梦行 阅读(274) | 评论 (0)编辑 收藏
http://repo.spring.io/release/org/springframework/spring/4.3.6.RELEASE/
http://spring.io/tools/sts http://www.loveweir.com/posts/view/19
https://github.com/rahulyewale/springmvcjpa
http://download.csdn.net/download/jiuqiyuliang/8640621
http://blog.csdn.net/suzunshou/article/details/49949005
https://repo1.maven.org/maven2/org/mybatis/mybatis/
http://blog.csdn.net/jiuqiyuliang/article/details/45132493/
https://github.com/mybatis/generator/releases
posted @ 2017-03-19 22:39 华梦行 阅读(148) | 评论 (0)编辑 收藏
今天从windows上导出一个sql执行文件,再倒入到unbutn中,结果出现乱码,折腾7-8分钟, 
解决方式 
在导出mysql sql执行文件的时候,指定一下编码格式: 
复制代码 代码如下:
mysqldump -uroot -p --default-character-set=utf8 mo(dbname) > E://xxxx.sql 
导入的时候OK了 
执行如下 
复制代码 代码如下:
mysql -u root -p --default-character-set=utf8 
use dbname 
source /root/newsdata.sql 
posted @ 2016-07-21 13:33 华梦行 阅读(129) | 评论 (0)编辑 收藏

CentOS
1、备份
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 
2、下载新的CentOS-Base.repo 到/etc/yum.repos.d/
CentOS 5
 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo  
CentOS 6
 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo  
CentOS 7
 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo  
3、之后运行yum makecache生成缓存
相关链接
##官方主页: http://www.centos.org/
##邮件列表: http://www.centos.org/modules/tinycontent/index.php?id=16
##论坛: http://www.centos.org/modules/newbb/
##文档: http://www.centos.org/docs/
##Wiki: http://wiki.centos.org/
posted @ 2016-06-27 17:42 华梦行 阅读(139) | 评论 (0)编辑 收藏

对输入数据进行正态化

 

为了使神经网络有效,我们必须对数据进行正态化。这是激活函数的正确计算所需要的。正态化是一种数学处理,将数据转换为 0..1 或 -1..1 的范围。正态化后的数据可以进行去正态化,即转换回原来的范围。

要将神经网络输出解码为人类可读的形式,需要对数据进行去正态化。谢天谢地,负责标准化和去标准化,因此不需要实施它。如果您对它的工作原理感到好奇,您可以分析以下代码:  


public static double INPUT_LOW = -20;
    public static double INPUT_HIGH = 20;
    public static double OUTPUT_HIGH = 1;
    public static double OUTPUT_LOW = -1;
    public static double normalize(final double value) {
        return ((value - INPUT_LOW) / (INPUT_HIGH - INPUT_LOW))
                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        // return ((10f + 20f) / (40f)) * (2f) + OUTPUT_LOW;
    }
    public static double deNormalize(final double data) {
        double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                / (OUTPUT_LOW - OUTPUT_HIGH);
        return result;
    }

x=-5:.01:5;
   plot(x,tanh(x)),grid on;
posted @ 2016-05-11 18:27 华梦行 阅读(231) | 评论 (0)编辑 收藏

1. Quickstart

The cron4j main entity is the scheduler. With a it.sauronsoftware.cron4j.Scheduler instance you can execute tasks at fixed moments, during all the year. A scheduler can execute a task once a minute, once every five minutes, Friday at 10:00, on February the 16th at 12:30 but only if it is Saturday, and so on.

The use of the cron4j scheduler is a four steps operation:

  1. Create your Scheduler instance.
  2. Schedule your actions. To schedule an action you have to tell the scheduler what it has to do and when. You can specify what using a java.lang.Runnable or a it.sauronsoftware.cron4j.Task instance, and you can specify when using a scheduling pattern, which can be represented with a string or with a it.sauronsoftware.cron4j.SchedulingPattern instance.
  3. Starts the scheduler.
  4. Stops the scheduler, when you don't need it anymore.

Consider this simple example:

import it.sauronsoftware.cron4j.Scheduler;  public class Quickstart {  	public static void main(String[] args) { 		// Creates a Scheduler instance. 		Scheduler s = new Scheduler(); 		// Schedule a once-a-minute task. 		s.schedule("* * * * *", new Runnable() { 			public void run() { 				System.out.println("Another minute ticked away..."); 			} 		}); 		// Starts the scheduler. 		s.start(); 		// Will run for ten minutes. 		try { 			Thread.sleep(1000L * 60L * 10L); 		} catch (InterruptedException e) { 			; 		} 		// Stops the scheduler. 		s.stop(); 	}  }

This example runs for ten minutes. At every minute change it will print the sad (but true) message "Another minute ticked away...".

Some other key concepts:

  • You can schedule how many tasks you want.
  • You can schedule a task when you want, also after the scheduler has been started.
  • You can change the scheduling pattern of an already scheduled task, also while the scheduler is running (reschedule operation).
  • You can remove a previously scheduled task, also while the scheduler is running (deschedule operation).
  • You can start and stop a scheduler how many times you want.
  • You can schedule from a file.
  • You can schedule from any source you want.
  • You can supply listeners to the scheduler in order to receive events about the executed task.
  • You can control any ongoing task.
  • You can manually launch a task, without using a scheduling pattern.
  • You can change the scheduler working Time Zone.
  • You can validate your scheduling patterns before using them with the scheduler.
  • You can predict when a scheduling pattern will cause a task execution.

Back to index

2. Scheduling patterns

A UNIX crontab-like pattern is a string split in five space separated parts. Each part is intended as:

  1. Minutes sub-pattern. During which minutes of the hour should the task been launched? The values range is from 0 to 59.
  2. Hours sub-pattern. During which hours of the day should the task been launched? The values range is from 0 to 23.
  3. Days of month sub-pattern. During which days of the month should the task been launched? The values range is from 1 to 31. The special value "L" can be used to recognize the last day of month.
  4. Months sub-pattern. During which months of the year should the task been launched? The values range is from 1 (January) to 12 (December), otherwise this sub-pattern allows the aliases "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov" and "dec".
  5. Days of week sub-pattern. During which days of the week should the task been launched? The values range is from 0 (Sunday) to 6 (Saturday), otherwise this sub-pattern allows the aliases "sun", "mon", "tue", "wed", "thu", "fri" and "sat".

The star wildcard character is also admitted, indicating "every minute of the hour", "every hour of the day", "every day of the month", "every month of the year" and "every day of the week", according to the sub-pattern in which it is used.

Once the scheduler is started, a task will be launched when the five parts in its scheduling pattern will be true at the same time.

Scheduling patterns can be represented with it.sauronsoftware.cron4j.SchedulingPattern instances. Invalid scheduling patterns are cause of it.sauronsoftware.cron4j.InvalidPatternExceptions. The SchedulingPattern class offers also a static validate(String) method, that can be used to validate a string before using it as a scheduling pattern.

Some examples:

5 * * * *
This pattern causes a task to be launched once every hour, at the begin of the fifth minute (00:05, 01:05, 02:05 etc.).

* * * * *
This pattern causes a task to be launched every minute.

* 12 * * Mon
This pattern causes a task to be launched every minute during the 12th hour of Monday.

* 12 16 * Mon
This pattern causes a task to be launched every minute during the 12th hour of Monday, 16th, but only if the day is the 16th of the month.

Every sub-pattern can contain two or more comma separated values.

59 11 * * 1,2,3,4,5
This pattern causes a task to be launched at 11:59AM on Monday, Tuesday, Wednesday, Thursday and Friday.

Values intervals are admitted and defined using the minus character.

59 11 * * 1-5
This pattern is equivalent to the previous one.

The slash character can be used to identify step values within a range. It can be used both in the form */c and a-b/c. The subpattern is matched every c values of the range 0,maxvalue or a-b.

*/5 * * * *
This pattern causes a task to be launched every 5 minutes (0:00, 0:05, 0:10, 0:15 and so on).

3-18/5 * * * *
This pattern causes a task to be launched every 5 minutes starting from the third minute of the hour, up to the 18th (0:03, 0:08, 0:13, 0:18, 1:03, 1:08 and so on).

*/15 9-17 * * *
This pattern causes a task to be launched every 15 minutes between the 9th and 17th hour of the day (9:00, 9:15, 9:30, 9:45 and so on... note that the last execution will be at 17:45).

All the fresh described syntax rules can be used together.

* 12 10-16/2 * *
This pattern causes a task to be launched every minute during the 12th hour of the day, but only if the day is the 10th, the 12th, the 14th or the 16th of the month.

* 12 1-15,17,20-25 * *
This pattern causes a task to be launched every minute during the 12th hour of the day, but the day of the month must be between the 1st and the 15th, the 20th and the 25, or at least it must be the 17th.

Finally cron4j lets you combine more scheduling patterns into one, with the pipe character:

0 5 * * *|8 10 * * *|22 17 * * *
This pattern causes a task to be launched every day at 05:00, 10:08 and 17:22.

Back to index

3. How to schedule, reschedule and deschedule a task

The simplest manner to build a task is to implement the well-known java.lang.Runnable interface. Once the task is ready, it can be scheduled with the it.sauronsoftware.cron4j.Scheduler.schedule(String, Runnable) method. This method throws an it.sauronsoftware.cron4j.InvalidPatternException when the supplied string does not represent a valid scheduling pattern.

Another way to build a task is to extend the it.sauronsoftware.cron4j.Task abstract class, which is more powerful and let the developer access some other cron4j features. This is better discussed in the "Building your own task" paragraph. Task instances can be scheduled with the schedule(String, Task) and the schedule(SchedulingPattern, Task) methods.

Scheduling methods available in the scheduler always return an ID used to recognize and retrieve the scheduled operation. This ID can be used later to reschedule the task (changing its scheduling pattern) with the reschedule(String, String) or the reschedule(String, SchedulingPattern) methods, and to deschedule the task (remove the task from the scheduler) with the deschedule(String) method.

The same ID can also be used to retrieve the scheduling pattern associated with a scheduled task, with the getSchedulingPattern(String) method, or to retrieve the task itself, with the getTask(String) method.

Back to index

4. How to schedule a system process

System processes can be easily scheduled using the ProcessTask class:

ProcessTask task = new ProcessTask("C:\\Windows\\System32\\notepad.exe"); Scheduler scheduler = new Scheduler(); scheduler.schedule("* * * * *", task); scheduler.start(); // ... 

Arguments for the process can be supplied by using a string array instead of a single command string:

String[] command = { "C:\\Windows\\System32\\notepad.exe", "C:\\File.txt" }; ProcessTask task = new ProcessTask(command); // ...

Environment variables for the process can be supplied using a second string array, whose elements have to be in the NAME=VALUE form:

String[] command = { "C:\\tomcat\\bin\\catalina.bat", "start" }; String[] envs = { "CATALINA_HOME=C:\\tomcat", "JAVA_HOME=C:\\jdks\\jdk5" }; ProcessTask task = new ProcessTask(command, envs); // ...

The default working directory for the process can be changed using a third parameter in the constructor:

String[] command = { "C:\\tomcat\\bin\\catalina.bat", "start" }; String[] envs = { "CATALINA_HOME=C:\\tomcat", "JAVA_HOME=C:\\jdks\\jdk5" }; File directory = "C:\\MyDirectory"; ProcessTask task = new ProcessTask(command, envs, directory); // ...

If you want to change the default working directory but you have not any environment variable, the envs parameter of the constructor can be set to null:

ProcessTask task = new ProcessTask(command, null, directory);

When envs is null the process inherits every environment variable of the current JVM:

Environment variables and the working directory can also be set by calling the setEnvs(String[]) and setDirectory(java.io.File) methods.

The process standard output and standard error channels can be redirected to files by using the setStdoutFile(java.io.File) and setStderrFile(java.io.File) methods:

ProcessTask task = new ProcessTask(command, envs, directory); task.setStdoutFile(new File("out.txt")); task.setStderrFile(new File("err.txt"));

In a siminal manner, the standard input channel can be read from an existing file, calling the setStdinFile(java.io.File) method:

ProcessTask task = new ProcessTask(command, envs, directory); task.setStdinFile(new File("in.txt"));

5. How to schedule processes from a file

The cron4j scheduler can also schedule a set of processes from a file.

You have to prepare a file, very similar to the ones used by the UNIX crontab, and register it in the scheduler calling the scheduleFile(File) method. The file can be descheduled by calling the descheduleFile(File) method. Scheduled files can be retrieved by calling the getScheduledFiles() method.

Scheduled files are parsed every minute. The scheduler will launch every process declared in the file whose scheduling pattern matches the current system time.

Syntax rules for cron4j scheduling files are reported in the "Cron parser" paragraph.

Back to index

6. Building your own task

A java.lang.Runnable object is the simplest task ever possible, but to gain control you need to extend the it.sauronsoftware.cron4j.Task class. In the plainest form, implementing Runnable or extending Task are very similar operations: while the first requires a run() method, the latter requires the implementation of execute(TaskExecutionContext). The execute(TaskExecutionContext) method provides a it.sauronsoftware.cron4j.TaskExecutionContext instance, which the Runnable.run() method does not provide. The context can be used in the following ways:

  • A task can communicate with its executor, by notifying its internal state with a textual description. This is called status tracking. If you are interested in supporting status tracking in your task, you have to override the supportsStatusTracking() method, which should return true. Once this has been done, within the execute(TaskExecutionContext) method you are enabled to call the context setStatusMessage(String) method. This will propagate your task status message to its executor. The status message, through the executor, can be retrieved by an external user (see the "Executors" paragraph).

  • A task can communicate with its executor, by notifying its completeness level with a numeric value. This is called completeness tracking. If you are interested in supporting completeness tracking in your task, you have to override the supportsCompletenessTracking() method, which should return true. Once this has been done, within the execute(TaskExecutionContext) method you are enabled to call the context setCompleteness(double) method, with a value between 0 and 1. This will propagate your task completeness level to its executor. The completeness level, through the executor, can be retrieved by an external user (see the "Executors" paragraph).

  • A task can be optionally paused. If you are interested in supporting pausing and resuming in your task, you have to override the canBePaused() method, which should return true. Once this has been done, within the execute(TaskExecutionContext) method you have to periodically call the context pauseIfRequested() method. This will pause the task execution until it will be resumed (or stopped) by an external user (see the "Executors" paragraph).

  • A task can be optionally stopped. If you are interested in supporting stopping in your task, you have to override the canBeStopped() method, which should return true. Once this has been done, within the execute(TaskExecutionContext) method you have to periodically call the context isStopped() method. This will return true when the execution has be demanded to be stopped by an external user (see the "Executors" paragraph). Then it's your responsibility to handle the event, by letting your task gently stop its ongoing activities.

  • Through the context, the task can retrieve the scheduler, calling getScheduler().

  • Through the context, the task can retrieve its executor, calling getTaskExecutor().

A custom task can be scheduled, launched immediately or returned by a task collector.

Back to index

7. Building your own collector

You can build and plug within the scheduler your own task source, via the task collector API.

The cron4j scheduler supports the registration of one or more it.sauronsoftware.cron4j.TaskCollector instances, with the addTaskCollector(TaskCollector) method. Registered collectors can be retrieved with the scheduler getTaskCollectors() method. A previously registered collector can be removed from the scheduler with the removeTaskCollector(TaskCollector) method. Collectors can be added, queried or removed at every moment, also when the scheduler is started and it is running.

Each registered task collector is queried by the scheduler once a minute. The scheduler calls the collector getTasks() method. The implementation must return a it.sauronsoftware.cron4j.TaskTable instance. A TaskTable is a table that associates tasks and scheduling patterns. The scheduler, once the table has been retrieved, will examine the reported entries, and it will execute every task whose scheduling pattern matches the current system time.

A custom collector can be used to tie the scheduler with an external task source, i.e. a database or a XML file, which can be managed and changed in its contents also at run time.

Back to index

8. Building your own scheduler listener

The it.sauronsoftware.cron4j.SchedulerListener API can be used to listen to scheduler events.

The SchedulerListener interface requires the implementation of the following methods:

See the "Executors" paragraph for more info about task executors.

Once your SchedulerListener instance is ready, you can register it on a Scheduler object by calling its addSchedulerListener(SchedulerListener) method. Already registered listeners can be removed by calling the removeSchedulerListener(SchedulerListener) method. The scheduler can also give back any registered listener, with the getSchedulerListeners() method.

SchedulerListeners can be added and removed at every moment, also while the scheduler is running.

Back to index

9. Executors

The scheduler, once it has been started and it is running, can be queried to give back its executors. An executor is similar to a thread. Executors is used by the scheduler to execute tasks.

By calling the Scheduler.getExecutingTasks() method you can obtain the currently ongoing executors.

You can also obtain an executor through a SchedulerListener instance (see the "Building your own scheduler listener" paragraph).

Each executor, represented by a it.sauronsoftware.cron4j.TaskExecutor instance, performs a different task execution.

The task can be retrieved with the getTask() method.

The executor status can be checked with the isAlive() method: it returns true if the executor is currently running.

If the executor is running, the current thread can be paused until the execution will be completed, calling the join() method.

The supportsStatusTracking() method returns true if the currently executing task supports status tracking. It means that the task communicates to the executor its status, represented by a string. The current status message can be retrieved by calling the executor getStatusMessage() method.

The supportsCompletenessTracking() method returns true if the currently executing task supports completeness tracking. It means that the task communicates to the executor its own completeness level. The current completeness level can be retrieved by calling the executor getCompleteness() method. Returned values are between 0 (task just started and still nothing done) and 1 (task completed).

The canBePaused() method returns true if the currently executing task supports execution pausing. It means that the task execution can be paused by calling the executor pause() method. The pause status of the executor can be checked with the isPaused() method. A paused executor can be resumed by calling its resume() method.

The canBeStopped() method returns true if the currently executing task supports execution interruption. It means that the task execution can be stopped by calling the executor stop() method. The interruption status of the executor can be checked with the isStopped() method. Stopped executors cannot be resumed.

The getStartTime() method returns a time stamp reporting the start time of the executor, or a value less than 0 if the executor has not been yet started.

The getScheduler() method returns the scheduler which is the owner of the executor.

The getGuid() method returns a textual GUID for the executor.

Executors offer also an event-driven API, through the it.sauronsoftware.cron4j.TaskExecutorListener class. A TaskExecutorListener can be added to a TaskExecutor with its addTaskExecutorListener(TaskExecutorListener) method. Listeners can be removed with the removeTaskExecutorListener(TaskExecutorListener) method, and they can also be retrieved with the getTaskExecutorListeners() method. A TaskExecutorListener must implement the following methods:

  • executionPausing(TaskExecutor)
    Called when the executor is requested to pause the ongoing task. The given parameter represents the source TaskExecutor instance.

  • executionResuming(TaskExecutor)
    Called when the executor is requested to resume the execution of the previously paused task. The given parameter represents the source TaskExecutor instance.

  • executionStopping(TaskExecutor)
    Called when the executor is requested to stop the task execution. The given parameter represents the source TaskExecutor instance.

  • executionTerminated(TaskExecutor, Throwable)
    Called when the executor has completed the task execution. The first parameter represents the source TaskExecutor instance, while the second is the optional exception that has caused the task to be terminated. If the task has been completed successfully, the given value is null.

  • statusMessageChanged(TaskExecutor, String)
    Called every time the execution status message changes. The first parameter represents the source TaskExecutor instance, while the second is the new message issued by the task.

  • completenessValueChanged(TaskExecutor, double)
    Called every time the execution completeness value changes. The first parameter represents the source TaskExecutor instance, while the second is the new completeness value (between 0 and 1) issued by the task.

Back to index

10. Manual task launch

If the scheduler is started and running, it is possible to manually launch a task, without scheduling it with a pattern. The method is Scheduler.launch(Task). The task will be immediately launched, and a TaskExecutor instace is returned to the caller. The returned object can be used to control the task execution (see the "Executors" paragraph).

Back to index

11. Working with Time Zones

Scheduler instances, by default, work with the system default Time Zone. I.e. a scheduling pattern whose value is 0 2 * * * will activate its task at 02:00 AM according to the default system Time Zone. The scheduler can be requested to work with a different Time Zone, which is not the system default one. Call Scheduler.setTimeZone(TimeZone) and Scheduler.getTimeZone() to control this feature.

Once the default Time Zone has been changed, system current time is adapted to the supplied zone before comparing it with registered scheduling patterns. The result is that any supplied scheduling pattern is treated according to the specified Time Zone. Suppose this situation:

  • System time: 10:00
  • System time zone: GMT+1
  • Scheduler time zone: GMT+3

The scheduler, before comparing system time with patterns, translates 10:00 from GMT+1 to GMT+3. It means that 10:00 becomes 12:00. The resulted time is then used by the scheduler to activate tasks. So, in the given configuration at the given moment, any task scheduled as 0 12 * * * will be executed, while any 0 10 * * * will not.

Back to index

12. Daemon threads

The Java Virtual Machine exits when the only threads running are all daemon threads. The cron4j scheduler can be configured to spawn only daemon threads. To control this feature call the Scheduler.setDaemon(boolean) method. This method must be called before the scheduler is started. Default value is false. To check the scheduler current daemon status call the Scheduler.isDaemon() method.

Back to index

13. Predictor

The it.sauronsoftware.cron4j.Predictor class is able to predict when a scheduling pattern will be matched.

Suppose you want to know when the scheduler will execute a task scheduled with the pattern 0 3 * jan-jun,sep-dec mon-fri. You can predict the next n execution of the task using a Predictor instance:

String pattern = "0 3 * jan-jun,sep-dec mon-fri"; Predictor p = new Predictor(pattern); for (int i = 0; i < n; i++) { 	System.out.println(p.nextMatchingDate()); }

Back to index

14. Cron parser

The it.sauronsoftware.cron4j.CronParser class can be used to parse crontab-like formatted file and character streams.

If you want to schedule a list of tasks declared in a crontab-like file you don't need the CronParser, since you can do it by adding the file to the scheduler, with the Scheduler.scheduleFile(File) method.

Consider to use the CronParser if the Scheduler.scheduleFile(File) method is not enough for you. In example, you may need to fetch the task list from a remote source which is not representable as a java.io.File object (a document on a remote server, a DBMS result set and so on). To solve the problem you can implement your own it.sauronsoftware.cron4j.TaskCollector, getting the advantage of the CronParser to easily parse any crontab-like content.

You can parse a whole file/stream, but you can also parse a single line.

A line can be empty, can contain a comment or it can be a scheduling line.

A line containing no characters or a line with only space characters is considered an empty line.

A line whose first non-space character is a number sign (#) is considered a comment.

Empty lines and comment lines are ignored by the parser.

Any other kind of line is parsed as a scheduling line.

A valid scheduling line respects the following structure:

scheduling-pattern [options] command [args]
  • scheduling-pattern is a valid scheduling pattern, according with the definition given by the it.sauronsoftware.cron4j.SchedulingPattern class.
  • options is a list of optional information used by cron4j to prepare the task execution environment. See below for a more detailed description.
  • command is a system valid command, such an executable call.
  • args is a list of optional arguments for the command.

After the scheduling pattern item, other tokens in each line are space separated or delimited with double quotation marks (").

Double quotation marks delimited items can take advantage of the following escape sequences:

  • \" - quotation mark
  • \\ - back slash
  • \/ - slash
  • \b - back space
  • \f - form feed
  • \n - new line
  • \r - carriage return
  • \t - horizontal tab
  • \ufour-hex-digits - the character at the given Unicode index

The options token collection can include one or more of the following elements:

  • IN:file-path - Redirects the command standard input channel to the specified file.
  • OUT:file-path - Redirects the command standard output channel to the specified file.
  • ERR:file-path - Redirects the command standard error channel to the specified file.
  • ENV:name=value - Defines an environment variable in the scope of the command.
  • DIR:directory-path - Sets the path of the working directory for the command. This feature is not supported if the executing JVM is less than 1.3.

It is also possible to schedule the invocation of a method of a Java class in the scope of the parser ClassLoader. The method has to be static and it must accept an array of strings as its sole argument. To invoke a method of this kind the syntax is:

scheduling-pattern java:className#methodName [args]

The #methodName part can be omitted: in this case the main(String[]) method will be assumed.

Please note that static methods are invoked within the scheduler same JVM, without spawning any external process. Thus IN, OUT, ERR, ENV and DIR options can't be applied.

Invalid scheduling lines are discarded without blocking the parsing procedure, but an error message is sent to the application standard error channel.

Valid examples:

0 5 * * * sol.exe 0,30 * * * * OUT:C:\ping.txt ping 10.9.43.55 0,30 4 * * * "OUT:C:\Documents and Settings\Carlo\ping.txt" ping 10.9.43.55 0 3 * * * ENV:JAVA_HOME=C:\jdks\1.4.2_15 DIR:C:\myproject OUT:C:\myproject\build.log C:\myproject\build.bat "Nightly Build" 0 4 * * * java:mypackage.MyClass#startApplication myOption1 myOption2
posted @ 2016-05-07 15:39 华梦行 阅读(2000) | 评论 (0)编辑 收藏

阿里云Linux安装软件镜像源

阿里云是最近新出的一个镜像源。得益与阿里云的高速发展,这么大的需求,肯定会推出自己的镜像源。
阿里云Linux安装镜像源地址:http://mirrors.aliyun.com/

CentOS系统更换软件安装源
第一步:备份你的原镜像文件,以免出错后可以恢复。

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
第二步:下载新的CentOS-Base.repo 到/etc/yum.repos.d/
CentOS 5

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo
CentOS 6

wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
第三步:运行yum makecache生成缓存

yum clean all

yum makecache

posted @ 2016-04-30 21:11 华梦行 阅读(217) | 评论 (0)编辑 收藏
 yum -y update
centos6 mysql5.5 yum安装
  
 
默认使用centos yum安装的mysql不是5.5版本的,我们需要增加两个新的repo
rpm -Uvh http://mirror.steadfast.net/epel/6/i386/epel-release-6-8.noarch.rpm
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
centos6下php php-fpm的yum安装
查看一下是不是有mysql 5.5了
yum --enablerepo=remi,remi-test list mysql mysql-server
安装mysql5.5
yum --enablerepo=remi,remi-test install mysql mysql-server
启动mysql5.5
/etc/init.d/mysqld start
设置开机启动
chkconfig --levels 345 mysqld on
要启用MySQL 安全设置请输入以下命令
/usr/bin/mysql_secure_installation


CentOS/RHEL 7.x:

rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm

CentOS/RHEL 6.x:

rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm

CentOS/RHEL 5.x:

rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-5.noarch.rpm rpm -Uvh http://mirror.webtatic.com/yum/el5/latest.rpm

Now you can install PHP 5.5’s mod_php SAPI (along with an opcode cache) by doing:

yum install php55w php55w-opcache

You can alternatively install PHP 5.5’s php-fpm SAPI (along with an opcode cache by doing:





  rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm
  

rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpm
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
如果想删除上面安装的包,重新安装
rpm -qa | grep webstatic
rpm -e  上面搜索到的包即可
3.运行yum install
  yum install php55w php55w-cli php55w-common php55w-gd php55w-ldap php55w-mbstring php55w-mcrypt php55w-mysql php55w-pdo php55w-xml
yum install php56w php56w-cli php56w-common php56w-gd php56w-ldap php56w-mbstring php56w-mcrypt php56w-mysql php56w-pdo php56w-xml

php 另外一种方式
 Remi官方网站:http://rpms.famillecollet.com/
添加Remi源,不管32位还是64位的系统,运行下面命令:
rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
 Remi源默认是没有启用的,我们来启用Remi源,修改 /etc/yum.repos.d/remi.repo 文件,把文件内的 enabled=0 改为 enabled=1 ,注意:改文件内有2个 enabled=0 我们修改 [remi]下面的,不要修改[remi-test]下面的。
 到这里yum源的配置结束,下面安装软件就简单了。安装时候有询问y/n的时候都是y
安装php,php-fpm以及php扩展:
yum install php php-fpm php-bcmatch php-gd php-mbstring php-mcrypt php-mysql php-pdo   php-dom


wget https://files.phpmyadmin.net/phpMyAdmin/4.0.10.15/phpMyAdmin-4.0.10.15-english.zip
 
posted @ 2016-03-23 15:15 华梦行 阅读(273) | 评论 (1)编辑 收藏

在CentOS安装PHP5.6

A-A+
 

美国时间2014年11月13日,PHP开发团队,在「PHP 5.6.3 is available|PHP: Hypertext Preprocessor」上公布了PHP5.6系的最新版本「PHP 5.6.3」。

在最新的版本5.6.3不仅修改了多个Bug,并且修改了fileinfo模块里存在的安全漏洞。

PHP团队推荐使用PHP5.6系列的用户,升级到最新版本5.6.3。

简单介绍一下,如何在CentOS上安装PHP5.6。

配置yum源

追加CentOS 6.5的epel及remi源。

# rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm 
# rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

以下是CentOS 7.0的源。

# yum install epel-release # rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm 

使用yum list命令查看可安装的包(Packege)。

# yum list --enablerepo=remi --enablerepo=remi-php56 | grep php 

安装PHP5.6

yum源配置好了,下一步就安装PHP5.6。

# yum install --enablerepo=remi --enablerepo=remi-php56 php php-opcache php-devel php-mbstring php-mcrypt php-mysqlnd php-phpunit-PHPUnit php-pecl-xdebug php-pecl-xhprof 

用PHP命令查看版本。

# php --version PHP 5.6.0 (cli) (built: Sep  3 2014 19:51:31) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies     with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies     with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans 

在这里安装的版本是PHP5.6.0,细心的用户可能已经发现ZendGuardLoader变成Zend OPcahe了。

对从PHP5.5开始PHP代码缓存从APC变成了Zend OPcache了。

posted @ 2016-03-23 12:16 华梦行 阅读(171) | 评论 (0)编辑 收藏

Step1: 检测系统是否自带安装mysql

#yum list installed | grep mysql 

Step2: 删除系统自带的mysql及其依赖
命令:

# yum -y remove mysql-libs.x86_64 

Step3: 给CentOS添加rpm源,并且选择较新的源
命令:

#wget dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm 
#yum localinstall mysql-community-release-el6-5.noarch.rpm
# yum repolist all | grep mysql
# yum-config-manager --disable mysql55-community
# yum-config-manager --disable mysql56-community
# yum-config-manager --enable mysql57-community-dmr
# yum repolist enabled | grep mysql

Step4:安装mysql 服务器
命令:

# yum install mysql-community-server 

Step5: 启动mysql
命令:

#service mysqld start 

Step6: 查看mysql是否自启动,并且设置开启自启动
命令:

# chkconfig --list | grep mysqld # chkconfig mysqld on 

Step7: mysql安全设置
命令:

# mysql_secure_installation 

参考相关文档地址: 
http://www.rackspace.com/knowledge_center/article/installing-mysql-server-on-centos
http://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html
http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html

posted @ 2016-03-23 11:43 华梦行 阅读(176) | 评论 (0)编辑 收藏
1、d:\mysql\bin\>mysql -h localhost -u root //这样应该可以进入MySQL服务器 2、mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION //赋予任何主机访问数据的权限 3、mysql>FLUSH PRIVILEGES //修改生效 4、mysql>EXIT //退出MySQL服务器 # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html 修改默认端口 [mysqld] port=3309
posted @ 2016-02-24 14:34 华梦行 阅读(146) | 评论 (0)编辑 收藏

1. Change root user

su - ## OR ## sudo -i

2. Install Remi repository

## CentOS 6 and Red Hat (RHEL) 6 ## rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

 

3. Check Available MySQL versions

yum --enablerepo=remi,remi-test list mysql mysql-server

Output:

Loaded plugins: changelog, fastestmirror, presto, refresh-packagekit ... remi                                                            | 3.0 kB     00:00      remi/primary_db                                                 | 106 kB     00:00      Available Packages mysql.i686                               5.5.37-1.fc18.remi                        @remi mysql-server.i686                        5.5.37-1.fc18.remi                        @remi

4. Update or Install MySQL 5.5.37

yum --enablerepo=remi install mysql mysql-server

 

5. Start MySQL server and autostart MySQL on boot

/etc/init.d/mysqld start ## use restart after update ## OR ## service mysqld start ## use restart after update   chkconfig --levels 235 mysqld on

 

6. MySQL Secure Installation

/usr/bin/mysql_secure_installation

 

7. Connect to MySQL database (localhost) with password

mysql -u root -p   ## OR ## mysql -h localhost -u root -p

 

8. Create Database, Create MySQL User and Enable Remote Connections to MySQL Database

复制代码
## CREATE DATABASE ## mysql> CREATE DATABASE webdb;   ## CREATE USER ## mysql> CREATE USER 'webdb_user'@'10.0.15.25' IDENTIFIED BY 'password123';   ## GRANT PERMISSIONS ## mysql> GRANT ALL ON webdb.* TO 'webdb_user'@'10.0.15.25';   ##  FLUSH PRIVILEGES, Tell the server TO reload the GRANT TABLES  ## mysql> FLUSH PRIVILEGES;
复制代码
posted @ 2015-12-07 19:36 华梦行 阅读(182) | 评论 (0)编辑 收藏

mysql> use mysql;
 
  查询host值:
mysql> select user,host from user;
 
如果没有"%"这个host值,就执行下面这两句:
mysql> update user set host='%' where user='root';
mysql> flush privileges;
或者也可以执行:
mysql>grand all privileges on  *.*  to root@'%'  identifies  by ' xxxx';
其中 第一个*表示数据库名;第二个*表示该数据库的表名;如果像上面那样 *.*的话表示所有到数据库下到所有表都允许访问;
‘%':表示允许访问到mysql的ip地址;当然你也可以配置为具体到ip名称;%表示所有ip均可以访问;
 后面到‘xxxx'为root 用户的password;
 

举例:

任意主机以用户root和密码mypwd连接到mysql服务器
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'mypwd' WITH GRANT OPTION;
mysql> flush privileges;

IP为192.168.1.102的主机以用户myuser和密码mypwd连接到mysql服务器
mysql> GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'192.168.1.102' IDENTIFIED BY 'mypwd' WITH GRANT OPTION;
mysql> flush privileges;

posted @ 2015-12-06 22:29 华梦行 阅读(264) | 评论 (0)编辑 收藏
Linux(centos) 更改MySQL数据库目录位置

MySQL默认的数据文件存储目录为/var/lib/mysql。假如要把目录移到/home/data下需要进行下面几步:

1、home目录下建立data目录

cd /homemkdir data
2、把MySQL服务进程停掉: 

mysqladmin -u root -p shutdown
3、把/var/lib/mysql整个目录移到/home/data

mv /var/lib/mysql /home/data/
这样就把MySQL的数据文件移动到了/home/data/mysql下

4、找到my.cnf配置文件

如果/etc/目录下没有my.cnf配置文件,请到/usr/share/mysql/下找到*.cnf文件,拷贝其中一个到/etc/并改名为my.cnf)中。命令如下:

[root@test1 mysql]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf
5、编辑MySQL的配置文件/etc/my.cnf

为保证MySQL能够正常工作,需要指明mysql.sock文件的产生位置。修改socket=/var/lib/mysql/mysql.sock一行中等号右边的值为:/home/mysql/mysql.sock 。操作如下:

vi  my.cnf  (用vi工具编辑my.cnf文件,找到下列数据修改之)# The MySQL server[mysqld]  port = 3306#socket  = /var/lib/mysql/mysql.sock(原内容,为了更稳妥用“#”注释此行)socket  = /home/data/mysql/mysql.sock (加上此行)
6、修改MySQL启动脚本/etc/init.d/mysql

最后,需要修改MySQL启动脚本/etc/init.d/mysql,把其中datadir=/var/lib/mysql一行中,等号右边的路径改成你现在的实际存放路径:home/data/mysql。

[root@test1 etc]# vi /etc/init.d/mysql#datadir=/var/lib/mysql(注释此行)datadir=/home/data/mysql (加上此行)

如果是CentOS还要改 /usr/bin/mysqld_safe 相关文件位置;

最后 做一个mysql.sock 链接:
ln -s /data/ljl/mysql/mysql.sock /var/lib/mysql/mysql.sock

7、重新启动MySQL服务
/etc/init.d/mysqld start

或用reboot命令重启Linux

如果工作正常移动就成功了,否则对照前面的7步再检查一下。还要注意目录的属主和权限。 
复制内容到剪贴板 
代码:
[root@sample ~]# chown -R mysql:mysql /home/data/mysql/  ← 改变数据库的归属为mysql

[root@sample ~]# chmod 700 /home/data/mysql/test/  ← 改变数据库目录属性为700

[root@sample ~]# chmod 660 /home/data/mysql/test/*  ← 改变数据库中数据的属性为660


posted @ 2015-12-06 22:28 华梦行 阅读(222) | 评论 (0)编辑 收藏
1. title 是关键字 ,尽量不要用
posted @ 2015-11-24 23:18 华梦行 阅读(102) | 评论 (0)编辑 收藏
CSS Sprites 原理:其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置。 CSS Sprites 优点: 1、利用CSS Sprites能很好地减少网页的http请求,从而大大的提高页面的性能,这也是CSS Sprites最大的优点,也是其被广泛传播和应用的主要原因; 2、CSS Sprites能减少图片的字节,曾经比较过多次3张图片合并成1张图片的字节总是小于这3张图片的字节总和。 3、解决了网页设计师在图片命名上的困扰,只需对一张集合的图片上命名就可以了,不需要对每一个小元素进行命名,从而提高了网页的制作效率。 4、更换风格方便,只需要在一张或少张图片上修改图片的颜色或样式,整个网页的风格就可以改变。维护起来更加方便。 通过打开目前您的CSS文件夹下面的CSS图片碎片后,您可以自行拖拽CSS图片碎片技进行适当的位置调整,可以通过双击图片来移除该图片,进行CSS Sprite 操作时,拖拽与CSS Sprite 两个选项可随时切换使用。
posted @ 2015-10-25 21:52 华梦行 阅读(98) | 评论 (0)编辑 收藏
最近朋友在搞网易的企业免费邮箱,拥有自己的独立域名,这个其实很简单,只要网易的邮箱mx设置就行了,但是尝试了很久,按照设置设置完之后还是不行,我用的是万网的域名解析,如下图 :



最主要的就是网易的帮助缺少了一个cname的解析,主机记录设置mail 然后记录值和mx的一致,然后重要的是 mx和txt的设置主机记录都要是@。这里网易都没有说,所以完整的来说就是这样的: 设置mx主机记录为@记录值为mx.ym.163.cin mx优先级是10 设置txt主机记录为@ 记录值为v=spf1 include:spf.163..com ~all 设置cname 主机记录为mail 记录值是ym.163.com
posted @ 2015-10-20 11:24 华梦行 阅读(188) | 评论 (0)编辑 收藏
wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u60-b27/jdk-8u60-linux-x64.rpm
posted @ 2015-10-13 23:19 华梦行 阅读(137) | 评论 (0)编辑 收藏
相当于-dpR,保持文件的连接(d),保持原文件的属性(p)并作递归处理(R)
-a 参数的意义等同于  -dR  --preserve=all

就是以下几个意义的组合:

-d:   保持软链接
-R:   递归
--preserve=all  :保持文件原有属性
posted @ 2015-10-03 18:38 华梦行 阅读(440) | 评论 (0)编辑 收藏
 iptables -I INPUT  -p tcp -s 115.28.190.242 --dport 83 -j ACCEPT
[root@www.jstong.com bin]# service iptables save
iptables:将防火墙规则保存到 /etc/sysconfig/iptables:     [确定]
[root@ZWCLC bin]# service iptables restart
posted @ 2015-09-17 23:57 华梦行 阅读(187) | 评论 (0)编辑 收藏

1、方法一,编辑rc.loacl脚本 

Ubuntu开机之后会执行/etc/rc.local文件中的脚本,

所以我们可以直接在/etc/rc.local中添加启动脚本。

当然要添加到语句:exit 0 前面才行。

如:

sudo vi /etc/rc.local

/usr/local/ssdb/ssdb-server -d  /usr/local/ssdb/ssdb.conf

然后在 exit 0 前面添加好脚本代码。

posted @ 2015-09-12 20:25 华梦行 阅读(189) | 评论 (0)编辑 收藏

Ubuntu 默认是DHCP自动获取IP。设定好静态IP,重启了也会变。

1、设定IP
sudo vi /etc/network/interfaces

auto lo
iface lo inet loopback            #lo 是本地回环地址:127.0.0.1

auto eth0
iface eth0 inet static              #将dhcp修改为static
address 192.168.1.152         #添加下面的IP、网关等
gateway 192.168.1.1
netmask 255.255.255.0
network 192.168.1.0
broadcast 192.168.1.255

2. 修改dns解析

因为以前是dhcp解析,所以会自动分配dns服务器地址

而一旦设置为静态ip后就没有自动获取到的dns服务器了

要自己设置一个

sudo vim /etc/resolv.conf

写上一个公网的DNS

nameserver 114.114.114.114

(注意:8.8.8.8是谷歌的DNS服务器,但是解析速度慢,还是找到一个国内的dns来用)

3. 重启网卡:

sudo /etc/init.d/networking restart




注意:重启Ubuntu后发现又不能上网了,问题出在/etc/resolv.conf。重启后,此文件配置的dns又被自动修改为默认值。所以需要永久性修改DNS。方法如下:

# vim /etc/resolvconf/resolv.conf.d/base
nameserver 192.168.1.1
nameserver 114.114.114.114






posted @ 2015-09-12 16:46 华梦行 阅读(788) | 评论 (0)编辑 收藏
在Solr中该如何使用IK分词器呢,这是小伙伴们问的频率比较高的一个问题,今晚特此更新此篇博客。其实之前我在其他博客里已经使用了IK分词器,只是我没做详细说明。 在schema.xml配置中其实有很多关于分词器的配置示例,我从中摘录一段配置示例,比如: fileType是用来定义域类型的,name即表示域名称,class即表示域类型对应的class类,如果是solr内置的域类型则可以直接使用solr.前缀+域类型的类名即可,如果是你自定义的域类型,则class表示自定义域类型的完整类名(包含完整的包路径),在fileType元素下有analyzer元素,用来配置当前域类型使用什么分词器,你肯定很奇怪,为什么要配置两个analyzer,其实主要是为了区分两个阶段:索引建立阶段和Query查询阶段,索引建立阶段需要分词毋庸置疑,查询阶段是否需要分词,则取决于你的业务需求,用过Google的知道,用户在查询输入框里输入查询关键字,这时候我们需要对用户输入的查询关键字进行分词器,这时候我们就需要配置查询阶段使用什么分词器,为什么把分开配置?两者可以使用统一配置不行吗,配置两遍不是显得很冗余且繁琐吗?analyzer的type元素就表示这两个阶段,之所以要分阶段配置分词器,是为了满足用户潜在的需求,因为查询阶段的分词需求和索引阶段的分词需求不一定是相同的。我们都知道分词器Analyzer是由一个Tokenizer + N个tokenFilter组成,这就是为什么analyzer元素下会有tokenizer元素和filter元素,但tokenizer元素只允许有一个,filter元素可以有N个。之所以这样设计是为了为用户提供更细粒度的方式来配置分词器的行为,即你可以任意组合tokenizer和filter来实现你的特定需求,当然你也可以把这种组合写在Analyzer类里,然后直接在analyzer元素的class属性里配置自定义分词器的完整类名,这样就不需要这么繁琐的配置tokenizer和filter,即把实现细节屏蔽在analyzer类内部,但这样做的话,如果你需要更改实现细节,则需要修改Analyzer源码,然后重新打包成jar,相对来说,比较麻烦点,而使用analyzer,tokenizer,filter这样来配置,虽然繁琐点,但更灵活。而且采用 然后我们在代码里String useSmart = DOMUtil.getAttr(attrs,"useSmart");就可以获取到属性值了,然后就是通过反射把属性值设置到IKAnalyzer类的useSmart属性中了,这是基本的Java反射操作,下面我提供几个反射工具方法: /** * 循环向上转型, 获取对象的DeclaredField. 若向上转型到Object仍无法找到, 返回null. */ protected static Field getDeclaredField(final Object object, final String fieldName) { if (null == object || null == fieldName || fieldName.equals("")) { return null; } for (Class superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { try { return superClass.getDeclaredField(fieldName); } catch (NoSuchFieldException e) { // Field不在当前类定义,继续向上转型 continue; } } return null; } /** * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. */ public static void setFieldValue(final Object object, final String fieldName, final Object value) { Field field = getDeclaredField(object, fieldName); if (field == null) { throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); } makeAccessible(field); try { field.set(object, value); } catch (IllegalAccessException e) { throw new RuntimeException("直接设置对象属性值出现异常", e); } } /** * 强行设置Field可访问 */ protected static void makeAccessible(final Field field) { if (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) { field.setAccessible(true); } } 直接调用setFieldValue方法即可,比如在 Analyzer analyzer = clazz.newInstance();这句下面添加一句 setFieldValue(analyzer,"useSmart",Boolean.valueOf( useSmart )); 这样我们在xml中配置的useSmart参数就设置到Analyzer类中了,这样才能起作用。solr源码如何导入Eclipse上篇博客里我已经介绍过了,至于如果把修改过后的代码打包成jar,直接使用eclipse自带的export功能即可,如图: 然后一路Next即可。我只是说说思路,剩下留给你们自己去实践。 但是采用改源码方式不是很优雅,因为你本地虽然是修改好了,哪天你由Solr5.1.0升级到5.2.0,还要再改一遍,没升级一次就要改一次,你的代码copy给别人用,别人运行代码后看不到效果,增加沟通成本,你还得把你改过源码的jar包共享给别人,这也就是为什么有那么多人找我要什么IK jar包。 在Solr中可以使用TokenizerFactory方式来解决我刚才提出的问题:IKAnalyzer分词器的useSmart参数无法通过schema.xml配置文件进行设置。我花了点时间扩展了IKTokenizerFactory类,代码如下: package org.apache.lucene.analysis.ik; import java.util.Map; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.util.TokenizerFactory; import org.apache.lucene.util.AttributeFactory; import org.wltea.analyzer.lucene.IKTokenizer; public class IKTokenizerFactory extends TokenizerFactory { public IKTokenizerFactory(Map args) { super(args); useSmart = getBoolean(args, "useSmart", false); } private boolean useSmart; @Override public Tokenizer create(AttributeFactory attributeFactory) { Tokenizer tokenizer = new IKTokenizer(attributeFactory,useSmart); return tokenizer; } } 同时我对 IKTokenizer类也稍作了修改,修改后源码如下: /** * IK分词器 Lucene Tokenizer适配器类 * 兼容Lucene 4.0版本 */ public final class IKTokenizer extends Tokenizer { //IK分词器实现 private IKSegmenter _IKImplement; //词元文本属性 private final CharTermAttribute termAtt; //词元位移属性 private final OffsetAttribute offsetAtt; //词元分类属性(该属性分类参考org.wltea.analyzer.core.Lexeme中的分类常量) private final TypeAttribute typeAtt; //记录最后一个词元的结束位置 private int endPosition; private Version version = Version.LATEST; /** * Lucene 4.0 Tokenizer适配器类构造函数 * @param in * @param useSmart */ public IKTokenizer(Reader in , boolean useSmart){ //super(in); offsetAtt = addAttribute(OffsetAttribute.class); termAtt = addAttribute(CharTermAttribute.class); typeAtt = addAttribute(TypeAttribute.class); _IKImplement = new IKSegmenter(input , useSmart); } public IKTokenizer(AttributeFactory factory, boolean useSmart) { super(factory); offsetAtt = addAttribute(OffsetAttribute.class); termAtt = addAttribute(CharTermAttribute.class); typeAtt = addAttribute(TypeAttribute.class); _IKImplement = new IKSegmenter(input , useSmart); } /* (non-Javadoc) * @see org.apache.lucene.analysis.TokenStream#incrementToken() */ @Override public boolean incrementToken() throws IOException { //清除所有的词元属性 clearAttributes(); Lexeme nextLexeme = _IKImplement.next(); if(nextLexeme != null){ //将Lexeme转成Attributes //设置词元文本 termAtt.append(nextLexeme.getLexemeText()); //设置词元长度 termAtt.setLength(nextLexeme.getLength()); //设置词元位移 offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition()); //记录分词的最后位置 endPosition = nextLexeme.getEndPosition(); //记录词元分类 typeAtt.setType(nextLexeme.getLexemeTypeString()); //返会true告知还有下个词元 return true; } //返会false告知词元输出完毕 return false; } /* * (non-Javadoc) * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader) */ @Override public void reset() throws IOException { super.reset(); _IKImplement.reset(input); } @Override public final void end() { // set final offset int finalOffset = correctOffset(this.endPosition); offsetAtt.setOffset(finalOffset, finalOffset); } 修改后重新打包的IKAnalyzer jar请见底下的附件。 然后我把它打包成了 solr-analyzer-ik-5.1.0.jar,只需要把这个jar包复制到你的core\lib目录下即可,然后你就可以像配置StandardTokenizerFactory一样的使用我们自定义的IKTokenizerFactory类了,并且能配置useSmart参数,这正是我想要的,能灵活的控制分词器参数,so cool。配置示例如下: 然后field域里应用我们配置的这个text_ik域类型,如图: 然后你还需要把IKAnalyzer jar包以及我们自定义的IKTokenizerFactory的jar包copy到你当前core\lib目录下,如图: IKAnalyzer jar建议使用底下附件里我新上传的,因为源码我稍作了修改,上面已经提到过了。然后你需要把IKAnalyzer.cfg.xml配置文件copy到E:\apache-tomcat-7.0.55\webapps\solr\WEB-INF\classes目录下,其中E :\apache-tomcat-7.0.55为我的Tomcat安装根目录,请类比成你自己的tomcat安装根目录,你懂的。如图: IKAnalyzer.cfg.xml配置如图: ext.dic为IK分词器的自定义扩展词典,内容如图: 我就在里面加了两个自定义词语。 然后你就可以启动你的tomcat,然后如图进行分词测试了, 上图是用来测试useSmart参数设置是否有生效,如果你看到如图的效果,说明配置成功了。 上图是用来测试自定义词典是否有生效,因为我在ext.dic自定义词典里添加了 劲爆 和 屌丝 这两个词,所以IK能分出来,逆袭和白富美没有在自定义扩展词典里添加,所以IK分不出来。如果你能看到如图效果,说明IK的自定义扩展词典也配置成功了。到此,关于在Solr中使用IK分词器就介绍到这儿了,如果你还有任何疑问,请通过以下方式联系到我,谢谢!!!博客里提到的相关jar包配置文件等等资源文件,我待会儿都会上传到底下的附件里,特此提醒!!!!!
posted @ 2015-09-11 17:26 华梦行 阅读(647) | 评论 (0)编辑 收藏

“以直代曲”的思想是利用直线段来近似曲线,也即通过某点的切线来代替曲线,这样使得有关曲线的问题转化到直线段上来,从而得到简化。

posted @ 2015-09-02 16:13 华梦行 阅读(317) | 评论 (0)编辑 收藏












posted @ 2015-09-01 23:24 华梦行 阅读(154) | 评论 (0)编辑 收藏
随机变量x的分布函数

A=0B=0.5 c=2 
clc;
clf;
x=-3:0.01:3;
length(x)
for i=1:length(x)
if x(i)<0
    y(i)=0;
else if x(i)<1
        y(i)=0.5*(x(i)^2);
    else if x(i)<2
            y(i)=2*x(i)-0.5*(x(i)^2)-1;
        else
            y(i)=1;
        end 
    end
end
end
plot(x,y);
grid on;
hold on;
posted @ 2015-09-01 00:19 华梦行 阅读(159) | 评论 (0)编辑 收藏
% 调用二项分布的概率值函数 binopd
% 格式 binopdf (k, n, p) , p — 每次试验事件A发生的概率;K—事件A发生K次;n—试验总次数

clear;
px=binopdf(45,100,0.5) % 计算x=45的概率 
%作图
x=1:100;
p=binopdf(x,100,0.5);
plot(x,p);title('概率分布图')
posted @ 2015-08-26 22:35 华梦行 阅读(151) | 评论 (0)编辑 收藏

 a=[-1,1,2;-2,3,1;4,0,9]
for i=1:size(a,2) 
    for j=1:size(a,2) 
        c(i,j)=sum((a(:,i)-mean(a(:,i))).*(a(:,j)-mean(a(:,j))))/(size(a,1)-1);
    end 
end

c =

   10.3333   -4.1667    3.0000

   -4.1667    2.3333   -1.5000

    3.0000   -1.5000    1.0000 

复制代码

 c为求得的协方差矩阵,在matlab以矩阵a的每一列为变量,对应的每一行为样本。这样在矩阵a中就有3个列变量分别为a(:,1), a(:,2), a(:,3)。

 在协方差矩阵c中,每一个元素c(i,j)为对第i列与第j列的协方差,例如c(1,2) = -4.1667为第一列与第二列的协方差。

 

 拿c(1,2)的求解过程来说

 c(1,2)=sum((a(:,1)-mean(a(:,1))).*(a(:,2)-mean(a(:,2))))/(size(a,1)-1);

 1. a(:,1)-mean(a(:,1)),第一列的元素减去该列的均值得到

   -1.3333

   -2.3333

    3.6667

2,  a(:,2)-mean(a(:,2)),第二列的元素减去该列的均值得到

   -0.3333

    1.6667

   -1.3333

3, 再将第一步与第二部的结果相乘

   -1.3333        -0.3333           0.4444

   -2.3333  .*     1.6667  =     -3.8889

    3.6667         -1.3333          -4.8889

 

4, 再将结果求和/size(a,1)-1 得 -4.1667,该值即为c(1,2)的值。

 

再细看一下是不是与协方差公式:Cov(X,Y) = E{ [ (X-E(X) ] [ (Y-E(Y) ] } 过程基本一致呢,只是在第4步的时候matlab做了稍微的调整,自由度为n-1,减少了一行的样本值个数。

>> a=[-1,1,2;-2,3,1;4,0,9]
a =
    -1     1     2
    -2     3     1
     4     0     9
>> cov(a)
ans =
   10.3333   -4.1667   14.0000
   -4.1667    2.3333   -5.5000
   14.0000   -5.5000   19.0000
>> dim1=a(:,1)
dim1 =
    -1
    -2
     4
>> dim2=a(:,2)
dim2 =
     1
     3
     0
>> dim3=a(:,3)
dim3 =
     2
     1
     9
>> dim1-mean(dim1)
ans =
   -1.3333
   -2.3333
    3.6667
>> dim2-mean(dim2)
ans =
   -0.3333
    1.6667
   -1.3333
>> m=dim1-mean(dim1)
m =
   -1.3333
   -2.3333
    3.6667
>> m=dim2-mean(dim2)
m =
   -0.3333
    1.6667
   -1.3333
>> m=dim1-mean(dim1)
m =
   -1.3333
   -2.3333
    3.6667
>> n=dim2-mean(dim2)
n =
   -0.3333
    1.6667
   -1.3333
>> m.*n
ans =
    0.4444
   -3.8889
   -4.8889
>> size(a,1)
ans =
     3
>> sum(m.*n)
ans =
   -8.3333
>> ans/2
ans =
   -4.1667







posted @ 2015-08-26 19:06 华梦行 阅读(254) | 评论 (0)编辑 收藏

本文来自网上,本人只是整理一下,放到这里以备查用。

1. 特殊变量与常数

主题词意义主题词意义
ans 计算结果的变量名 computer 确定运行的计算机
eps 浮点相对精度 Inf 无穷大
I 虚数单位 inputname 输入参数名
NaN 非数 nargin 输入参数个数
nargout 输出参数的数目 pi 圆周率
nargoutchk 有效的输出参数数目 realmax 最大正浮点数
realmin 最小正浮点数 varargin   实际输入的参量
varargout 实际返回的参量    

2. 操作符与特殊字符

主题词意义主题词意义
+ -
* 矩阵乘法 .* 数组乘(对应元素相乘)
^ 矩阵幂 .^ 数组幂(各个元素求幂)
\ 左除或反斜杠 / 右除或斜面杠
./ 数组除(对应元素除) kron Kronecker张量积
: 冒号 () 圆括号
[] 方括 . 小数点
.. 父目录 ... 继续,下一行接着上一行
, 逗号(分割多条命令) ; 分号(禁止结果显示),矩阵行分割
% 注释 ! 感叹号
' 转置或引用 = 赋值
== 相等 <>或~= 不等于
& 逻辑与 | 逻辑或
  ~ 逻辑非 xor 逻辑异或

         3、基本数学函数

主题词意义主题词意义
abs 绝对值和复数模长 acos,acosh 反余弦,反双曲余弦
acot,acoth 反余切,反双曲余切 acsc,acsch 反余割,反双曲余割
angle 复数z的相角(Phase angle) asec,asech 反正割,反双曲正割
secant 正切 asin,asinh 反正弦,反双曲正弦
atan,atanh 反正切,双曲正切 tangent 正切
atan2 四象限反正切 ceil 向着无穷大舍入
complex   建立一个复数 conj 复数z的共轭复数
cos,cosh

余弦,双曲余弦

csc,csch 余切,双曲余切
cot,coth

余切,双曲余切

exp 指数
fix 朝0方向取整  gcd 最大公因数
lcm 最小公倍数 log 自然对数
log2 以2为底的对数 log10 常用对数
mod   有符号的求余 nchoosek

二项式系数和全部组合数

real 复数的实部 imag 复数值的虚部
rem 相除后求余 round 取整为最近的整数
sec,sech 正割,双曲正割 sign 符号数
sin,sinh 正弦,双曲正弦 sqrt 平方根
tan,tanh 正切,双曲正切 floor 朝负无穷取整

       4、基本矩阵和矩阵操作

主题词意义主题词意义
blkding 从输入参量建立块对角矩阵 eye 单位矩阵
  linespace 产生线性间隔的向量 logspace

产生对数间隔的向量

numel 元素个数 cat 连接数组
zeros 建立一个全0矩阵 colon 等间隔向量
ones   产生全为1的数组 rand 均匀颁随机数和数组
randn 正态分布随机数和数组 diag 对角矩阵和矩阵对角线
fliplr 从左自右翻转矩阵 flipud 从上到下翻转矩阵
repmat 复制一个数组 reshape 改造矩阵
roy90 矩阵翻转90度 tril 矩阵的下三角
triu

矩阵的上三角

dot 向量点集
cross 向量叉集 ismember 检测一个集合的元素
intersect 向量的交集 setxor 向量异或集
setdiff 向是的差集 union 向量的并集

    5.数值分析和傅立叶变换

主题词意义主题词意义
cumprod 累积 cumsum 累加
cumtrapz 累计梯形法计算数值微分 factor 质因子
inpolygon 删除多边形区域内的点 max 最大值
mean 数组的均值 mediam 中值
min 最小值 perms 所有可能的转换
polyarea 多边形区域 primes 生成质数列表
prod 数组元素的乘积 rectint 矩形交集区域
sort 按升序排列矩阵元素 sortrows 按升序排列行
  std 标准偏差   var

方差

sum 求和 trapz 梯形数值积分
del2 离散拉普拉斯 diff 差值和微分估计
gradient 数值梯度 cov 协方差矩阵
corrcoef 相关系数 conv2 二维卷积
   conv 卷积和多项式乘法 deconv 反卷积和多项式除法
filter IIR或FIR滤波器 filter2 二维数字滤波器
cplxpair 将复数值分类为共轭对 fft 一维的快速傅立叶变换
fft2 二维快速傅立叶变换 fftshift 将FFT的DC分量移到频谱中心
ifft 一维快速反傅立叶变换
ifft2 二维傅立叶反变换
ifftn 多维快速傅立叶变换 ifftshift

   反FFT偏移

nextpow2 最靠近的2的幂次 unwrap 校正相位角

 6.多项式与插值

主题词意义主题词意义
conv

卷积和多项式乘法

roots 多项式的根
  poly 具有设定根的多项式 polyder 多项式微分
polyeig 多项式的特征根 polyfit 多项式拟合
polyint 解析多项式积分 polyval 多项式求值
polyvalm   矩阵变量多项式求值 residue 部分分式展开
interp1 一维插值 interp2 二维插值
interp3 三维插值 interpft 使用FFT的一维插值
interpn 多维插值 meshgrid 为3维点生成x和y的网格
ndgrid 生成多维函数和插值的数组
pchip 分段3次Hermite插值多项式
ppval 分段多项式的值 spline 3次样条数据插值

           
 7.绘图函数

主题词意义主题词意义
bar 竖直条图 barh 水平条图
hist 直方图 histc 直方图计数
hold 保持当前图形 loglog x,y 对数坐标图
pie 饼状图 plot 绘二维图
polar

极坐标图

semilogy y轴对数坐标图
semilogx x轴对数坐标 subplot 绘制子图
bar3 数值3D竖条图 bar3h 水平3D条形图
comet3 3D慧星图 cylinder   圆柱体
fill3 填充的3D多边形 plot3 3维空间绘图
quiver3 3D震动(速度)图 slice 体积薄片图
sphere stem3 绘制离散表面数据
waterfall 绘制瀑布 trisurf 三角表面
clabel 增加轮廓标签到等高线图中   datetick 数据格式标记
grid 加网格线 gtext 用鼠标将文本放在2D图中
legend 图注   plotyy 左右边都绘Y轴
title 标题 xlabel X轴标签
ylabel   Y轴标签   zlabel Z轴标签
contour 等高线图 contourc 等高线计算
contourf 填充的等高线图 hidden 网格线消影
meshc 连接网格/等高线 mesh 具有参考轴的3D网格
peaks 具有两个变量的采样函数 surf 3D阴影表面图
surface 建立表面低层对象 surfc 海浪和等高线的结合
surfl 具有光照的3D阴影表面 trimesh 三角网格图
http://www.cnblogs.com/gtts/archive/2011/05/20/2052271.html
posted @ 2015-08-22 11:11 华梦行 阅读(169) | 评论 (0)编辑 收藏
将DocumentRoot设在/var/www/html下可以访问
但是将DocumentRoot设在其他目录(如:/webroot)下就出现Forbidden了。在./etc/httpd/conf/httpd.conf中的相关部分是这样的:
Alias /query "/home/query"

Options Indexes MultiViews
AllowOverride None

Order allow,deny
Allow from all

但是在浏览器中输入:http://localhost/query/ 时,出现Forbidden:

Forbidden

You don't have permission to access /query on this server.

Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request.
Apache/2.0.52 (Red Hat) Server at localhost Port 80


对于刚使用Redhat Enterprise Linux4 或Fedora Core 2以上/CentOS 4的用户,一定会为Apache经常无法正常运转,报以"Permission denied"等错误而大为不解,甚至大为恼火。

其实这是因为这些系统里激活了SELinux,而用户的apache配置与SELinux的配置策略有抵触产生的,只有通过适当调整,使apache的配置和访问符合策略才能正常使用。

现在下面来分析一下SELinux中有关httpd(apache)的context定义(略有删节)

/home/[^/]+/((www)|(web)|(public_html))(/.+)? system_u:object_r:httpd_user_content_t
/var/www(/.*)? system_u:object_r:httpd_sys_content_t
/var/www/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t
/usr/lib/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t
/var/www/perl(/.*)? system_u:object_r:httpd_sys_script_exec_t
/var/www/icons(/.*)? system_u:object_r:httpd_sys_content_t
/var/cache/httpd(/.*)? system_u:object_r:httpd_cache_t
/etc/vhosts -- system_u:object_r:httpd_config_t
/usr/sbin/httpd -- system_u:object_r:httpd_exec_t
/usr/sbin/apache(2)? -- system_u:object_r:httpd_exec_t
/usr/sbin/suexec -- system_u:object_r:httpd_suexec_exec_t
/var/log/httpd(/.*)? system_u:object_r:httpd_log_t
/var/log/apache(2)?(/.*)? system_u:object_r:httpd_log_t
/var/log/cgiwrap.log.* -- system_u:object_r:httpd_log_t
/var/cache/ssl.*.sem -- system_u:object_r:httpd_cache_t
/var/cache/mod_ssl(/.*)? system_u:object_r:httpd_cache_t
/var/run/apache(2)?.pid.* -- system_u:object_r:httpd_var_run_t
/var/lib/httpd(/.*)? system_u:object_r:httpd_var_lib_t
/var/lib/php/session(/.*)? system_u:object_r:httpd_var_run_t
/etc/apache-ssl(2)?(/.*)? system_u:object_r:httpd_config_t
/usr/lib/apache-ssl(/.*)? -- system_u:object_r:httpd_exec_t
/usr/sbin/apache-ssl(2)? -- system_u:object_r:httpd_exec_t
/var/log/apache-ssl(2)?(/.*)? system_u:object_r:httpd_log_t
/var/run/apache-ssl(2)?.pid.* -- system_u:object_r:httpd_var_run_t
/var/run/gcache_port -s system_u:object_r:httpd_var_run_t
/var/lib/squirrelmail/prefs(/.*)? system_u:object_r:httpd_squirrelmail_t
/usr/bin/htsslpass -- system_u:object_r:httpd_helper_exec_t
/usr/share/htdig(/.*)? system_u:object_r:httpd_sys_content_t
/var/lib/htdig(/.*)? system_u:object_r:httpd_sys_content_t

针对上述的内容,可以对如下的几个常见问题进行简单处理:

1.phpmyadmin在非默认/var/www/html目录下无法运转
通常类似的情况都是在配置了虚拟主机时,访问/phpmyadmin等提示403访问拒绝,日志里也提示Permission denied,这是因为phpmyadmin防止的目录及文件本身属性不符合context要求。

假设phpmyadmin放在/web目录下,那么执行:

chcon -R -t httpd_user_content_t /web

则会令/web及其下所有子目录/文件,包括phpmyadmin文件都获得了httpd_user_content_t的属性,如果其传统的Unix属性对httpd来说是可读的话,再重新访问一下就应该可以了。

2./home目录下的虚拟主机无法运转
与问题1也是类似的,不过根据上文中context的定义,/home目录下必须是用户的$HOME/www或public_html或web目录才是 httpd_user_content_t类型,因此建议将要作为web页面的内容放置在用户的$HOME/www或web或public_html里,并确保其属性是httpd_user_content_t,使用如下命令查看:

ls -Z /home/abc/
drwxr-xr-x abc abc user_u:object_r:user_home_dir_t tmp
drwxrwxr-x abc abc user_u:object_r:httpd_user_content www

如不是,则可通过chcon来逐级目录及文件更改,直至最后能访问:

chcon -R -t httpd_user_content_t /home/abc/web
chcon -t user_home_dir_t /home/abc

3.CGI程序无法运行
如果cgi程序放在/var/www/cgi-bin/里也无法执行,遇到403或500错误的话,可以检查cgi 程序的属性,按SELinux contexts文件里定义的,/var/www/cgi-bin/里必须是httpd_sys_script_exec_t 属性。通过ls -Z查看,如果不是则通过如下命令更改:

chcon -t httpd_sys_script_exec_t /var/www/cgi-bin/*.cgi

如果是虚拟主机里的cgi,则参考问题2使之能正常使用普通的功能后,再通过chcon设置cgi文件的context为httpd_sys_script_exec_t即可。

4.Setuid/gid 程序无法运行
例如早期的SqWebMail及qmailadmin等,需要setuid/gid的支持,但在SELinux下这将受到严格限制。第一种方法是比较彻底的办法,能保留系统的安全性,通过:

audit2allow -l -i /var/log/messages

将SELinux拒绝的信息转换为相应的policy allow指令,将这些指令添加到SELinux policy 的src里相应的配置文件,重新生成policy并加载。但这样做相对比较麻烦。

另一个方法最简单,但将使apache得不到保护。首先确定SELinux 类型是targeted的:

cat /etc/selinux/config|grep SELINUXTYPE

然后,使apache脱离SELinux保护:

setsebool -P httpd_disable_trans 1

然后重启动apache:

/etc/init.d/httpd restart

这样所有apache强制的检查都失效,需要setuid/gid的程序可以正常使用。但这样带来了增加漏洞的危险,对于迫切需要运行而又很急的情况,本方法是一个最大限度减少系统安全缺失的最后办法。对于取消SELinux 未必是一个好方法。
posted @ 2015-08-15 00:21 华梦行 阅读(376) | 评论 (0)编辑 收藏
挂载好新硬盘后输入fdisk -l命令看当前磁盘信息
可以看到除了当前的第一块硬盘外还有一块sdb的第二块硬盘,然后用fdisk /dev/sdb 进行分区
进入fdisk命令,输入h可以看到该命令的帮助,按n进行分区
这里输入e即分为逻辑分区,按p即分为主分区,我们要将这块盘分为主分区即输入p
到这里输入该主分区为第几个主分区,由于是新盘我们输入1来分第一个主分区
First Cylinder是选择该分区的起始磁盘数,这里可自定义也可不做选择,默认是1,如无特殊需求强烈建议选择默认,也就是1来分区(直接按回车)
接下来是定义该分区的大小,如果按默认(按回车)即是使用全部可用存储额,也可以是用M或m单位结尾的数字(大写M是大B的意思,如果输入1M实际上是X8也就是8m的空间),这里我们先分一个1G的空间,所以输入+1024m
之后输入w写入分区,等待结束皆可
再输入fdisk -l 可以看到我们刚才分的一个分区,之后用mkfs -t ext3 -c /dev/sdb1进行格式化,如有多个分区可把sdb1改成sdb2 sdb3...以此类推,具体可用fdisk -l看到每个分区的名字
上图蓝色部分是写硬盘卷标的,如不想要卷标可直接按回车,现在分区好了我们用mount 挂载一下该分区即可使用了,这里我把它挂载到mnt目录下,也可以自建一个目录挂载
来看一下分区大小是否和预定的一样,使用df -TH命令看一下当前挂载的分区和大小,看到我们刚分的分区了吧
如果想每次系统重启都能自动挂载该分区可修改/etc/fstab文件,在最后加一段 /dev/sdb1    /www    ext3    defaults 1 2 (格式说明:/dev/sdb1 代表哪个分区  ext3是该分区的格式 defaults 是挂载时所要设定的参数(只读,读写,启用quota等),输入defaults包括的参数有(rw、dev、exec、auto、nouser、async) ,1是使用dump是否要记录,0是不要。 2是开机时检查的顺序,是boot系统文件就为1,其他文件系统都为2,如不要检查就为0)
posted @ 2015-08-14 19:04 华梦行 阅读(117) | 评论 (0)编辑 收藏

Centos 

辛辛苦苦编译安装完Ngnix,mysql ,PHP,后发现不能访问,后来发现是防火墙把80端口给禁用了。开启之:(以下参考自:http://llhdf.javaeye.com/blog/526176)

 
#/sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT 
#/sbin/iptables -I INPUT -p tcp --dport 22 -j ACCEPT 
 
然后保存: 
#/etc/rc.d/init.d/iptables save 
 
再查看是否已经有了: 
[root@vcentos ~]# /etc/init.d/iptables status 
Table: filter 
Chain INPUT (policy ACCEPT) 
num  target     prot opt source               destination         
1    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:80 
2    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 
3    RH-Firewall-1-INPUT  all  --  0.0.0.0/0            0.0.0.0/0           
 
Chain FORWARD (policy ACCEPT) 
num  target     prot opt source               destination         
1    RH-Firewall-1-INPUT  all  --  0.0.0.0/0            0.0.0.0/0
二.重启电脑。
 
1.CentOS操作系统防火墙默认已经开放了80和22端口
 
2.这里应该也可以不重启计算机:
#/etc/init.d/iptables restart
防火墙的关闭,关闭其服务即可:
 
3.查看防火墙信息:
#/etc/init.d/iptables status
 
4.关闭防火墙服务:
#/etc/init.d/iptables stop
 
三.永久关闭防火墙
 
我们也可以永久的关闭防火墙,但是我不建议大家这样做.永久关闭防火墙可以这样:
#chkconfig –level 35 iptables off
也可以直接修改
/etc/sysconfig/iptables
添加一条
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
posted @ 2015-08-14 19:02 华梦行 阅读(433) | 评论 (0)编辑 收藏
今天我们这篇php的技术文章主要为各位朋友们介绍如何使用yum进行安装php的5.4或者5.5版本。当然我们使用centos6.5作为我们的测试机器。其实非常简单,只要下面的两个命令就可以轻松的进行安装php的5.4版本了。


yum remove php php-bcmath php-cli php-common php-devel php-fpm php-gd php-imap php-ldap php-mbstring php-mcrypt php-mysql php-odbc php-pdo php-pear php-pecl-igbinary php-xml php-xmlrpc

rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm

yum install php54w php54w-bcmath php54w-cli php54w-common php54w-devel php54w-fpm php54w-gd php54w-imap php54w-ldap php54w-mbstring php54w-mcrypt php54w-mysql php54w-odbc php54w-pdo php54w-pear php54w-pecl-igbinary php54w-xml php54w-xmlrpc php54w-opcache php54w-intl php54w-pecl-memcache


当然扩展的话,可以根据你自己的需要进行添加或者删除哦,至于说php5.5的安装,跟php5.4的安装还是大同小异的哦。

yum remove php php-bcmath php-cli php-common php-devel php-fpm php-gd php-imap php-ldap php-mbstring php-mcrypt php-mysql php-odbc php-pdo php-pear php-pecl-igbinary php-xml php-xmlrpc

rpm -Uvh http://mirror.webtatic.com/yum/el6/latest.rpm

yum install php55w php55w-bcmath php55w-cli php55w-common php55w-devel php55w-fpm php55w-gd php55w-imap php55w-ldap php55w-mbstring php55w-mcrypt php55w-mysql php55w-odbc php55w-pdo php55w-pear php55w-pecl-igbinary php55w-xml php55w-xmlrpc php55w-opcache php55w-intl php55w-pecl-memcache
posted @ 2015-07-30 14:53 华梦行 阅读(187) | 评论 (0)编辑 收藏
遇到页面显示空白很有可能的一种原因就是编码不正确                  
posted @ 2012-09-07 09:23 华梦行 阅读(213) | 评论 (0)编辑 收藏
var main_frame:damain=Application.application as damain;var main_frame:damain=Application.application as damain;
posted @ 2010-09-02 11:43 华梦行 阅读(218) | 评论 (0)编辑 收藏
写给c/c++的新同行门,CTO门把你们的宝贵经验拿出来吧,让这个帖对大伙有用

1、越界

 越界是最难查的,注意memcpy strcpy,strncpy这些函数使用前一定要检查边界

 特别是你提供函数给别人用时,你的函数中用到了这些东西,一定要检查别人传给你的指针的
 边界

2、变量初始化

 这种问题要养成好习惯,否则出来偶然性问题,非常难查

3、多线程指针管理

 在多线程环境下使用指针时,最好采用引用计数,让最后一个放充引用计数时,指针删除,避免一个线程在使用指针,另外线程删除掉

4、多线程锁的管理

 多线程锁要粒度要适中,尽量减少 一个函数 进入多个锁,避免一个大函数一个大锁影响性能,可学习数据库的表级,行级锁

 尽量不要在回调函数中放锁,易 引起死锁

做到线程安全函数单向调用,上层往下层调用,下屋向上层采用事件驱动反馈,避免调用栈

 过深,易引起死锁 

5、多线程对象生存期管理

 尽量当多线程共享对象 尽量不要直接删除,建议采用状态机形式来管理,其它线程设置状态

 由一个线程统一按状态管理生存期

6、构造函数

函造函数中不要放虚函数,绝对不要在构造函数中开线程,并且线程调用自己的成员

7、内联
 
  虚函数不要内联

8、多线程创建办法

如果用C运行库函数,要注意用C运行库的方法

9,内存管理

建议采用内存池管理

10、线程生存期管理

线程中尽量不要调用同步函数,不要强行杀线程,要让线程不断循环,等待死亡信号自己退出

posted @ 2010-05-08 19:30 华梦行 阅读(226) | 评论 (0)编辑 收藏
 int  **p1;  //指向指针的指针
    int  *p2;    //指向指针的变量  其中所存储的值为变量的地址,或者变量的地址的地址
    int  i=3;
    p2=&i;
    p1=&p2;
 printf("Hello World!\n"); 
 printf("%d\n",i);  //3
 printf("%d\n",**p1); //3
 printf("%d\n",*p2); //3
 printf("%d\n",&i);  //1245044
 printf("%d\n",*p1);  //1245044
 printf("%d\n",p2);   //1245044
 printf("%d\n",p1);   //1245048
 printf("%d\n",&p2);  //1245048
 printf("%d\n",&p1);  //1245052
 return 0;
posted @ 2010-03-08 11:07 华梦行 阅读(225) | 评论 (0)编辑 收藏

架构设计是一个非常大的话题,不管写几篇文章,接触到的始终只是冰山一角,更多的是实践中去体会。这篇文章主要介绍面向对象OO、面向方面AOP和面向服务SOA这三个要素在架构设计中的位置与作用。

架构设计有三个维度,或者说是我们在考虑架构时需要思考三个方向。

这三个维度分别为面向对象、面向方面、面向服务。

这三个维度可以看作是正交的,但不同维度会互相印证,互相支撑,整个架构的示意图如图所示。

软件架构设计的三个维度
图:架构三维度结构图

面向对象

面向对象技术最初是从面向对象的程序设计开始的,它的出现以上世纪60年代Simula语言为标志,并在Smalltalk语言的完善和标准化过程中得到更多的扩展和对以前思想的重新注解。

上世纪80年代中后期,面向对象程序设计逐渐成熟,被计算机界理解和接受,人们又开始进一步考虑面向对象的开发问题。直到现在,面向对象已经成为一种非常流行的编程方式,以及软件设计的架构。

面向对象提出有三个主要目标:重用性、灵活性和扩展性,强调对象的“抽象”、“封装”、“继承”和“多态”。它能让人们以更加接近于现实世界的方式来思考程序,这点可以说是面向对象最大的进步。

在OO思想的运用上,业界出现了很多好的经验与技巧,从而涌现出大量的设计模式,可以说面向对象是系统分析与设计时的一个很重要的方面。

面向方面

面向方面最初来源于hook技术,本质上就是满足扩展的需求,可以在程序中自由扩展功能。

面向方面不仅仅是一门编程技术,同样也是一种架构设计的思路。如果说OO是纵向地分析、切割整个系统,那么可以认为AOP是横向地对系统作切片。

简单地理解,OO与AOP分别从两个不同的角度给我们提供了分析系统的思路。面向方面可以弥补面向对象的缺陷,两种方式有机的结合在一起,可以更加有效地对系统进行分析。

我们认为OO是接近于人类认识自然的思维方式,但对于东方而言却并不一定是这样的。

当西方人看到一个复杂系统的时候,只会有一种思路,就是“分解”,将系统分解成一块一块,然后每个部分进行研究。

当东方人看到一个复杂系统的时候,更多地会关注系统中存在的关系,将系统作为一个有机的整体进行研究,这也是东方和西方在事物看法上存在的差异。

这两种思维方式都没有问题,如果结合起来分析问题,解决问题会更好。面向对象与面向方面也同样如此,都能对应到人类认识自然的思维方式上。

面向服务

面向服务可以说是最近炒得比较火热的概念。包括现在提到的SaaS(Software as a service),软件即服务。准确而言,面向服务不仅仅是软件行业的概念,这个要从社会的产业结构说起。

社会产业总共分为三个,第一产业农业,第二产业工业,第三产业服务业。最早社会的主要产业是第一产业农业,将近有几万年的历史。

十八世纪下半叶在英国开始的工业革命,对人们的生活产生了根本性的影响,社会的主要产业成了第二产业工业。

现在仍然属于工业时代,或者有人说的“后工业时代”。而在后工业时代,社会的经济体制必定要向第三产业服务业逐渐转型。面向服务其实是社会经济体制重心的一种迁移。

还是说回到软件行业,社会的主要产业将转变成服务业,自然软件行业也会出现对应的变化,那就是这里提到的面向服务。面向服务今后会影响到软件的交付模式,会对整个软件行业的体制产生影响。

而说到架构层面,面向服务是系统发布功能的一种方式。并且基于这种方式下不同的系统之间能有效地通信、协作。常见的实现技术就是Web Service。

软件全局观

软件架构设计的三个维度:面向对象、面向方面、面向服务。

最年长的一个维度就是面向对象,发展了好几十年,也是相对而言比较成熟的一个维度。它解决的问题是系统内部结构的设计。

面向方面思想的提出能够弥补面向对象的缺陷。面向对象的方式不能实现横切关注点的分离,而面向方面正是为了解决这个问题。面向方面与面向对象一样都是解决系统内部结构的设计。

面向服务更多的是涉及到系统的外部,简单地说就是发布功能。它并不关注系统内部结构的实现,所以说面向服务与面向对象或者面向方面并不冲突。

这三个维度并不是绝对孤立的,它们之间会互相影响、制约,相互发展的。我们在分析架构的时候需要同时考虑到这三个维度的问题,这样有助于我们设计出更加优秀的架构。

posted @ 2010-02-04 16:34 华梦行 阅读(264) | 评论 (0)编辑 收藏
    if(!/^[a-zA-Z0-9]{6,15}$/.test($('oldpwd').value)){  正则,6-15 位的字母或者数字

(^$)|(^\w{5,11}$)   为空或者 5-10为字符
posted @ 2010-02-04 11:24 华梦行 阅读(215) | 评论 (0)编辑 收藏

十几年软件研发的沧桑岁月,和一度险濒于破产的痛苦经历,让俺对软件产品开发有了更深层的体会。新年到来之际,写出来和大家作个交流。

一、农业境界

  刚参加工作,朋友问我,你能用电脑干啥?我口出狂言,只要你想得出来的,我都能做得到。其实,我说这话相当无知。

  柏拉图曾经说过,人的知识犹如一个圆,圆内是你已经知道的,圆外是你还不知道的,圆周就是你已经知道的还没解决的问题。你的知识越丰富,这个圆就越大,圆的周长也越长,也就是你知道的没解决的问题也越多。

  如果你觉得自己没有啥问题,就说明你很无知。

  无数年轻人就是凭自己的热情,初生牛犊不怕虎的冲劲,在完全没有经验和章法的情况下,投入了不会取得胜利的第一场战斗。通俗一点讲,就是试图用垒狗窝的技术建高楼大厦。

  企业在这个阶段,充其量就是个手工作坊。有人说,我的研发团队上百号人呢。对不起,您是否出于这个阶段和企业人数没多大关系。

二、工业境界

  了解到软件产品设计研发是一个复杂的系统工程,很多人会尝试运用一些必要的技术把复杂系统分解成简单子系统。在这个阶段,一些软件工程理论开始逐步被吸收。这包括:

  面向对象的设计思想

  UML、RUP、XP编程、设计模式等软件工程理论和工具

  组件化系统设计——COM、DCOM、ActiveX、Corba、WebServices等技术开始进入产品设计

  简单地讲,已经知道如何把高楼大厦拆解成多个狗窝,化繁为简;已经懂得遵循软件工业标准开发能重用的系统组件。

  很多人以为已经到达软件研发的终点,掌握了终极的技术手段。然而,这只是软件产品研发的启蒙阶段,随着发现更多并解决深层次的问题,你需要更有效的理论提升你对软件产品开发的驾驭能力。

三、数学境界

  工业化境界提供了化繁为简的技术支撑和思路,但是,好的工具并不能保证出现正确的设计。

  我们学习解一元二次方程的时候,什么十字相乘法、配方法等等,开始会学习很多技巧性的解法。这类似工业化境界——让你把复杂问题分解转化成更简单的问题。但是,这些技巧不总是有效,最终的解决方案还是推导出求解公式,彻底解决此类问题。

  软件产品设计是否存在从需求到代码的求解公式呢?这是一个已经被研究半个世纪的课题了,可惜国内99%的软件研发人员并不了解这方面的进展。等到洋人的坚船利炮打到你家门口的时候,你才发现人家用这么好的技术武装自己,那就为时太晚了。

  在这个阶段,你会用数学方法保障软件系统设计的正确性。你可能会把下面这些理论引入你的设计过程:

  在系统设计中自觉运行有限状态机、Petri网等数学模型去设计、分析系统结构。

  引进诸如净室技术、B方法、Z语言等形式化软件工程技术,确保系统设计的正确性。

  最后你会发现,软件产品设计真正是一件严格科学过程,如果以山野村夫的心态做这件事情,最终必然一塌糊涂。

四、艺术境界

  人本质上是非理性的动物,我们为人类设计产品的最终目标不是为了正确,因此,数学境界并未把你带到最终目的地。

  人类还没解决温饱问题的时候,就学会了在岩石上涂鸦,在脖子上挂项链,为人类设计产品,得满足他们这些貌似毫无价值的癖好。

  因此,在能熟练驾驭正确设计产品的技能之后,软件产品设计将为艺术而战——我们不是在替客户设计干活的工具,相反,我们是在为他们设计一个吸引眼球的超级玩具,一件艺术品。

  软件产品设计师——你不仅仅是工程师,更进一步,你应该是一名驾驭高科技技术的艺术家!

五、宗教境界

  阿克毛被枪毙了,他不是为科学而来,亦不是为艺术而来,而是为夺取我们的心灵而来!

  之所以被枪毙,是因为他采取了文明社会不认可的手段和产品——海洛因。

  异曲同工,软件产品设计的最高境界亦是征服客户的心灵,让客户像崇拜上帝一样被您的软件所征服。似乎除了海洛因,能做到这一点的就是宗教了。

  看看IBM、看看微软、看看Intel、看看苹果,这些超级商业巨人,为了让你把口袋的钱老老实实地掏出来,是不是一个个俨然一副布道者的模样?

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/quicmous/archive/2010/01/03/5125373.aspx

posted @ 2010-01-23 09:33 华梦行 阅读(258) | 评论 (0)编辑 收藏

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;
import java.util.StringTokenizer;

/*
用Java语言实现HTTP服务器,首先启动一个java.net.ServerSocket在提供服务的端口上监听连接.向客户返回文本时,可以用
PrintWriter,但是如果返回二进制数据,则必须使用OutputStream.write(byte[])方法,返回的应答消息字符串可以使用
String.getBytes()方法转换为字节数组返回,或者使用PrintStream的print()方法写入文本,用
write(byte[])方法写入二进制数据.

以工程所在目录为web的根目录。 在工程的根目录下放一个大概如下的index.html

<!DOCTYPE html PUBLIC "-//WDTD HTML  Transitional//EN"
 * "http://www.wg/TR/htmlose.dtd"> <html> <head> <meta
 * http-equiv="Content-Type" content="text/html; charset=gbk">
 * <title>简单的测试</title> </head> <body> 你好!这是一个 简单的web服务器。<br>
 * 这是一个图片!br>
 *
 * <form action="/index.html"> <img alt="" src="images/test.gif"><br>
 * 姓名:<input type="text" name="name" /><br>
 * 密码:<input type="password" name="pass"></input><br>
 * <input type="submit"/> </form> </body> </html>
 *
 * 放入图片位置: 工程根目录/images/test.gif <br>
 * 打开浏览器输入http://localhost/index.html 可以展示index.html
 *
 * @author guazi
 */
public class SimpleHttpServer implements Runnable {

    ServerSocket serverSocket;// 服务器Socket
    /**
     * 服务器监听端口, 默认为
     */
    public static int PORT = 81; // 标准HTTP端口

    /**
     * 开始服务器 Socket 线程.
     */
    public SimpleHttpServer() {
        try {
            serverSocket = new ServerSocket(PORT);
        } catch (Exception e) {
            System.out.println("无法启动HTTP服务器:" + e.getMessage());
        }
        if (serverSocket == null) {
            System.exit(0);
        }

        new Thread(this).start();
        System.out.println("HTTP服务器正在运行,端口:" + PORT);
    }

    /**
     * 运行服务器主线程, 监听客户端请求并返回响应.
     */
    public void run() {
        while (true) {
            try {
                Socket client = null;// 客户Socket
                client = serverSocket.accept();// 客户机(这里是 IE 等浏览器)已经连接到当前服务器
                if (client != null) {
                    System.out.println("连接到服务器的用户:" + client);
                    try {
                        // 第一阶段: 打开输入流
                        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));

                        System.out.println("客户端发送的请求信息: ***************");
                        // 读取第一行, 请求地址
                        System.out.println("http协议头部信息:");

                        String line = in.readLine();
                        System.out.println("开始:"+line+"结束");
                        String resource = line.substring(line.indexOf('/'), line.lastIndexOf('/') - 5);
                        // 获得请求的资源的地址
                        resource = URLDecoder.decode(resource, "gbk");// 反编码

                        String method = new StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者 POST

                        // 读取浏览器发送过来的请求参数头部信息
                        while ((line = in.readLine()) != null) {
                            System.out.println(line);

                            if (line.equals("")) {
                                break;
                            }
                        }

                        System.out.println("http协议头部结束 ***************");
                        System.out.println("用户请求的资源是:" + resource);
                        System.out.println("请求的类型是: " + method);

                        String params = null;

                        if (resource.indexOf("?") > -1) {
                            params = resource.substring(resource.indexOf("?") + 1);
                            resource = resource.substring(0, resource.indexOf("?"));
                        }

                        // 显示 POST 表单提交的内容, 这个内容位于请求的主体部分
                        if ("POST".equalsIgnoreCase(method)) {
                            if (params != null) {
                                params += "&" + in.readLine();
                            } else {
                                params = in.readLine();
                            }
                        }

                        System.out.println("打印提交的数据:");
                        printParams(params);

                        // 读取资源并返回给客户端
                        fileReaderAndReturn(resource, client);
                        // 关闭客户端链接
                        client.close();
                        System.out.println("客户端返回完成!");
                    } catch (Exception e) {
                        System.out.println("HTTP服务器错误:" + e.getMessage());
                    }
                }

            } catch (Exception e) {
                System.out.println("HTTP服务器错误:" + e.getMessage());
            }
        }
    }

    /**
     * 读取一个文件的内容并返回给浏览器端.
     *
     * @param fileName
     *            文件名
     * @param socket
     *            客户端 socket.
     * @throws IOException
     */
    void fileReaderAndReturn(String fileName, Socket socket) throws IOException {
        if ("/".equals(fileName)) {// 设置欢迎页面,呵呵!
            fileName = "/index.html";
        }
        fileName = fileName.substring(1);
        PrintStream out = new PrintStream(socket.getOutputStream(), true);
        File fileToSend = new File(fileName);

        String fileEx = fileName.substring(fileName.indexOf(".") + 1);
        String contentType = null;
        // 设置返回的内容类型
        // 此处的类型与tomcat/conf/web.xml中配置的mime-mapping类型是一致的。测试之用,就写这么几个。
        if ("htmlhtmxml".indexOf(fileEx) > -1) {
            contentType = "text/html;charset=GBK";
        } else if ("jpegjpggifbpmpng".indexOf(fileEx) > -1) {
            contentType = "application/binary";
        }
        if (fileToSend.exists() && !fileToSend.isDirectory()) {
            // http 协议返回头
            out.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答
            out.println("Content-Type:" + contentType);
            out.println("Content-Length:" + fileToSend.length());// 返回内容字节数
            out.println();// 根据 HTTP 协议, 空行将结束头信息

            FileInputStream fis = null;
            try {
                fis = new FileInputStream(fileToSend);
            } catch (FileNotFoundException e) {
                out.println("<h1>404错误!</h1>" + e.getMessage());
            }
            byte data[];
            try {
                data = new byte[fis.available()];

                fis.read(data);
                out.write(data);
            } catch (IOException e) {
                out.println("<h1>500错误!</h1>" + e.getMessage());
                e.printStackTrace();
            } finally {
                out.close();
                try {
                    fis.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
        } else {
            out.println("<h1>404错误!</h1>" + "文件没有找到");
            out.close();

        }

    }

    void printParams(String params) throws IOException {
        if (params == null) {
            return;
        }
        String[] maps = params.split("&");
        for (String temp : maps) {
            String[] map = temp.split("=");
            System.out.println(map[0] + "==" + map[1]);
        }
    }

    /**
     * 启动 HTTP 服务器
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.out.println("这是一个简单的web服务器 ,端口是: 80.");
            } else if (args.length == 1) {
                PORT = Integer.parseInt(args[0]);
            }
        } catch (Exception ex) {
            System.err.println("服务器初始化错误" + ex.getMessage());
        }

        new SimpleHttpServer();

    }
}

posted @ 2009-12-29 08:59 华梦行 阅读(262) | 评论 (0)编辑 收藏

在python中import this就会展示出The Zen of Python如下:


The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


从网上搜寻了一下,这被称为python之禅,以下是翻译


Python之禅
赖勇浩翻译

优美胜于丑陋(Python 以编写优美的代码为目标)
明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
可读性很重要(优美的代码是可读的)
即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)
不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)
当存在多种可能,不要尝试去猜测
而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)
虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )
做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)
如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)
命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)

 

The Zen of Python,
蛇宗三字经

作者:Tim Peters
翻译:元创


Beautiful is better than ugly.
美胜丑
Explicit is better than implicit.
明胜暗
Simple is better than complex.
简胜复
Complex is better than complicated.
复胜杂
Flat is better than nested.
浅胜深
Sparse is better than dense.
疏胜密
Readability counts.
辞达意
Special cases aren't special enough to break the rules.
不逾矩
Although practicality beats purity.
弃至清
Errors should never pass silently.
无阴差
Unless explicitly silenced.
有阳错
In the face of ambiguity, refuse the temptation to guess.
拒疑数
There should be one-- and preferably only one --obvious way to do it.
求完一
Although that way may not be obvious at first unless you're Dutch.
虽不至,向往之
Now is better than never.
敏于行
Although never is often better than *right* now.
戒莽撞
If the implementation is hard to explain, it's a bad idea.
差难言
If the implementation is easy to explain, it may be a good idea.
好易说
Namespaces are one honking great idea -- let's do more of those!
每师出,多有名


比较恶搞的是,其实 this 模块的代码完全违背了这些原则,为了方便你查看它的代码,我把它贴出来:
s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print "".join([d.get(c, c) for c in s])

这段晦涩、复杂、凌乱的代码,莫非是 Tim Peters 提供的反例?

posted @ 2009-11-05 10:54 华梦行 阅读(4805) | 评论 (0)编辑 收藏

再谈如何成为技术领袖寇卫东

——技术不是充分条件

被访者:IBM软件集团两岸三地大中华区
总工程师  寇卫东

文/卢鸫翔

要想成为一名优秀的技术领袖,需要具备哪些方面的素质?我在IBM辅导很多年轻同事,如何才能帮助他们在职业生涯中成长为技术领军人物?是否只要拥有了过硬的技术本领,就能成为技术领袖?许多年轻的朋友技术拔尖,然而却觉得没有得到领导的赏识, 这又是什么原因呢?我常常都在思考这些问题。去年这个时候,我同读者朋友们分享了一些心得,我想结合自己多年的高校教育和IT从业经验,再同大家谈谈这一话题。

1.我很清楚地告诉大家,要成为技术领袖,技术是必要条件,但不是充分条件。如果一个人技术基础不够扎实,他几乎等同外行,领导其他技术人员不说没有可能,但至少会相当困难。另一方面我们在国内外都能看到不少拔尖的技术人员,有的是一流的科学家,有的是一流的技术专才,可一旦把他们放在领导岗位上,却都以失败告终。他们虽然技术出色,但是没有当领袖的能力,工作中四处碰壁,缺乏凝聚力,不得人心。

2.要成为技术领袖就要清楚公司的业务,知道技术应当如何配合业务需求。作为技术领袖,只有做到这点,才能使公司业务有大的发展,才会得到高层领导的认同。如果你只懂技术而不懂公司业务,或者你在大学工作而不懂领导教学科研,是没有办法胜任技术领袖的。我们钻研技术的朋友往往忽略了这一点,对某项技术非常专注,但是两耳不闻窗外事,没有把注意力放到公司的发展需求上来。

为了更好地协调个人职业发展与企业业务发展,需要处理好工作的优先级,分清主次。在日常工作当中,我常常为同事画下面这幅图,帮助他们进行分析。

如果有一项工作摆在面前,我们如何定义它的重要性,应该花多少力气去做?我们可以通过象限分析找出答案。第I象限表示此项工作对企业业务发展和个人职业发展都很重要,这是最完美的结合,优先级应该放在最高级。我们在企业中应该多做此类工作。第II象限表示此项工作对企业业务非常重要,但是对个人目前的职业发展看似并不特别重要。我们要以企业的利益为重,所以优先级应该放在第二位。第III象限表示此项工作对个人职业发展很重要,但是对企业业务发展不那么重要,我们应该把它放在第三位。第IV象限表示此项工作对企业业务发展和个人职业发展都不重要,优先级应该是最低的。对这类工作,自己最好不做或者少做;就是做,也应该尽可能少花时间去做;或是请其他同事去做,因为对你的个人职业发展不重要的工作不等于对其他同事的个人职业发展也不重要,换言之,此项工作可能对其他同事的个人职业发展很重要呢。

许多企业都在创造一种文化,希望能将企业业务发展和员工的个人职业发展紧密结合起来,尽管有时候很难兼顾。作为一名领袖人物,他一定更多地在关注大局,而不是仅仅看到自己。关注大局的人会处处从公司的业务、公司的需求出发。在实际工作中我们常常可以看到,一个真正把大局放在第一位的人,即便今天不是领袖,明天也一定非他莫属。现在的领导不欣赏,将来必会为其他领导所赏识。

3.一个能把握大局的人需要具备很多能力,其中非常重要的一项就是我下面要谈到的第三点——决策力。作为技术领袖,要有坚强的领导能力,敢于面对各种困难的挑战,敢于决断。有些人天生就有准确的决策能力,而更多人需要靠后天来培养。

在我的孩子还小的时候,我就给他灌输这种思想,培养锻炼他。如果他要问我,我就让他自己做决定,不论决定是对是错、是好是坏,在我看来都是正确的。因为最大的错误是该做决定时你举棋不定。再举一个例子,美国前总统布什刚刚上任的时候,很多人批评他没有总统的风范,但是经过几年的洗礼他的确拥有了总统的气质。原因又是什么呢?因为那个职位训练了他,很多情况他必须要做出决策。

对于程序员来说,虽然无法像领导那样做重大的决定,但仍然可以在自己的范围内做出决策。例如使用什么样的技术手段, 采用何种算法实现, 选择哪种数据结构,如何撰写文档,同谁一起合作,这些并不一定非要等老板或者构架师来判断。大家应该有意识地锻炼自己,慢慢成长,直到将来能够领导大的项目。每个人不可能一开始就能对一个完整的系统做出决策,可是如果不从当程序员的时候就开始锻炼自己,将来也做不了。

面对决策失败可能带来的后果,我们应该学会坦然面对,学会承担。如果不去做决策,不愿承担责任,就永远无法取得进步,无法获得做技术领袖的能力。

4.要想成为技术领袖必须有远见,有智慧。有远见有智慧的人才能有承担。我有一个在加拿大的同事,开始的时候只是一般的技术人员,很短的时间内就变成经理,再后来没有经过多长时间又被提升为主管。原因很简单:他有远见,并且有足够的智慧知道应该如何去做。像他这样的员工虽然刚开始的职位很低,但是公司领导觉得这样的人才对公司将来的发展大有帮助,另外,如果这样的员工离职,不但是公司的损失,还会助长竞争对手的实力。所以公司一旦有职位就会提升这样的员工。我们作为技术人员也是一样的道理,面对一套大的系统方案,只有穿透障碍看到未来,才有机会获得提升,成为技术领袖。

5.成为技术领袖需要自信、自觉和自律。自信,这和领导能力有关,没自信怎么来领导别人呢?自觉包含两个方面的内容:自我感知和自我解嘲。自我感知是要对自己有一个正确的评价,“人贵有自知之明”——我们老祖宗都这样讲。有些人不知道自己的情况,要么估计过低,要么估计过高,对自己没有一个公正的评价。很多事情要靠下意识的感觉,你可能并不知道具体发生了什么事情,但是凭感觉就能判断出对错。自嘲是能给自己台阶下,这很重要,往往很多人都做不到,一不小心就陷入骑虎难下的境地。另外对自己有一个正确的评价,才不会弄得自己下不来台。

自律就是要约束自己,保持良好的品行。自律不是做给别人看,也不是做给领导看,而是为自己而做。每个人心中都应该有把标尺,衡量什么事情该做,什么事情不该做。自律很关键,年轻人尤其应该加以重视。有好的人品才会得到大家信任,如果不自律,没有良好的品行,有谁会对他心悦诚服,又怎样来做大家的榜样呢?

6.勇于承担,敢于付出。也就是说一个人的工作既不是为了金钱,也不是为了名誉,单单只是为了实现自己人生的价值,获得成功。自己驱动自己,不畏艰难险阻,不达目的誓不罢休。不愿意承担,不愿意付出,处处计较得失的人是没有办法成为领袖的。

这里所说的成功,并非单纯的职位上的成功,还包括技术上的成功,做人的成功等。其中做人的成功最重要,往往却被最多的人所忽视。职位只不过是领导给的一个头衔,技术领袖所具有的影响力并不是单单靠领导所给的头衔就能获得的。不管大公司小公司,很重要的一点就是先做人。我认为衡量一个人是否成功,首先看做人,然后看技术,最后才是职位、名誉、金钱。而且往往人和技术做好了,金钱名誉就会随之而来。正如诺贝尔奖得主们无一人不是勤勤恳恳做事,假使一开始就想着名誉、奖金,或许他们永远都无法取得举世瞩目的成就。

成功是一个很宽泛的概念,如何衡量成功是因人而异的。一般来说,成功是一个正态分布的频谱,不是一个单脉冲。有些人拥有很高的职位、很丰厚的收入,但却没有家庭、没有生活,因为他们把所有心思都放在了工作上,最终获得了事业上的成功,一个脉冲式的成功。相对他们的度量标准来说是成功了,然而对另一些人来说,他们并不成功、或者不值得效仿。因为事业成功只是一方面,除了工作,我们还有生活,还有家庭的维系、子女的教育、八小时后的个人爱好。一个和谐的成功是一个频谱式的成功:也许没有哪一方面是特别突出的,但是有几个方面是相当好的,其他方面也还可以,这样综合来看是最好的。

7.能领会别人的感觉和想法,会与他人相处。一个拥有领袖潜质的人,往往能够很快感知周围的氛围,别人的感受,他能够通过简单的语言、位置调整,使大家轻松舒服地投入工作。

8.能把大家团结起来,人气旺。很多时候,某个人并不是领导,但是大家都愿意听他的话,成了无冕之王,这样的人即便现在不是,将来也必然会成为领袖,这只是时间的问题。

读者朋友们大多都是技术人员,但是大家不要被技术所束缚。我年轻的时候也走过弯路,希望这些心得体会能对年轻的朋友们有所帮助。成为技术领袖并非遥不可及,只需要比别人多付出一点坚定和执著,多注重先做人后做事。

posted @ 2009-10-28 16:13 华梦行 阅读(203) | 评论 (0)编辑 收藏
java 观察者模式
2009-09-10 09:51

观察者模式可以参考邮件订阅的例子

邮件订阅设计到2个主要角色,一个是订阅者(观察者),一个是发布者

发布者可以拥有一个观察者的集合,可以添加,删除观察者,当发布者发布一个新的消息时,要邮件通知观察者集合中的每一个。

所以,发布者实现的接口至少应具备三个方法,即注册观察者,注销观察者,通知观察者。

通知有两种方式,一种是推(push),一种是拉(pull).

推,即发布者通过调用观察者提供的接口,来告之所有的变动(比如新增一个消息),主动推送给观察者。

拉,及观察者可以按需提取所要接受的数据,而不是全盘接受,主要体现在程序自己主动调用观察者的传值接口,而区别于推由发布者来调用,此时,需要这个借口中的参数包含发布者对象,让程序知道扫描变动来自于哪个发布者。

JDK中内置了观察者模式,位于java.util包中,一个接口Observer,一个类Observable,将这两个类组合起来使用,既可以推,又可以拉。

一个普通的类,如果继承了Observable,就成了一个发布者,实现了Observer接口,就成了观察者。

JDK中的观察者模式有一个弊端,就是发布者需要继承一个类,而不是实现一个接口,如果需要成为发布者的类已经集成了一个类,就不能再继承Observable了。这时候,就需要自己来设计一种观察者模式了。

JDK 中Swing包中,大量运用了观察者模式,所有的组件都继承了JComponent,这就是一个发布者,它里面包含一个监听器的集合:EventListenerList,用户可以自定义一个监听器,然后添加到一个组件中的时候,该组件就会把这个监听器注册到 EventListenerList中,相当于添加了一个发布者,当用户对组件做出反映时,所有的监听器(发布者)都会收到信息并作出反应。

网上商店中的商品在名称、价格发生变化时,必须自动通知会员,Java的API为我们提供了
   Observer接口和Observable类来实现所谓观察者模式。Observable(可观察者)类允许在自身发生改变时,通知其它对象(实现接口Observer,观察者)。


   下面是一个可观察者(产品类):
import java.util.*;
public class product extends Observable{
   private String name;////产品名
   private float price;////价格

   public String getName(){ return name;}
   public void setName(String name){
   this.name=name;
   ////设置变化点
   setChanged();
   notifyObservers(name);////通知观察者

   }   

   public float getPrice(){ return price;}
   public void setPrice(float price){
   this.price=price;
   ////设置变化点
   setChanged();
   notifyObservers(new Float(price));

   }

   ////以下可以是数据库更新 插入命令.
   public void saveToDb(){
   System.out.println("saveToDb");
     }

}

下面是两个观察者:
import java.util.*;
public class NameObserver implements Observer{

   private String name=null;
   public void update(Observable obj,Object arg){
     if (arg instanceof String){
     name=(String)arg;
     ////产品名称改变值在name中
     System.out.println("NameObserver :name changet to "+name);

     }

        }
   }

import java.util.*;
public class PriceObserver implements Observer{
   private float price=0;
   public void update(Observable obj,Object arg){
     if (arg instanceof Float){

     price=((Float)arg).floatValue();
  
     System.out.println("PriceObserver :price changet to "+price);

     }


   }

}
下面是测试类:
public class Test {

   public static void main(String args[]){
      Product product=new Product();
      NameObserver nameobs=new NameObserver();
      PriceObserver priceobs=new PriceObserver();

      ////加入观察者
      product.addObserver(nameobs);
      product.addObserver(priceobs);

      product.setName("applet");
      product.setPrice(9.22f);

   }
}
运行结果:
C:\java>java    Test
NameObserver :name changet to applet

posted @ 2009-10-22 10:16 华梦行 阅读(516) | 评论 (0)编辑 收藏
     摘要:   Struts2架构图         请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。  &nb...  阅读全文
posted @ 2009-10-21 10:05 华梦行 阅读(7475) | 评论 (2)编辑 收藏
1、父子二人经过五星级饭店门口,看到一辆十分豪华的进口轿车。 儿子不屑地对他的父亲说:「坐这种车的人,肚子里一定没有学问!」 父亲则轻描淡写地回答:说这种话的人,口袋里一定没有钱 (注:你对事情的看法,是不是也反映出你内心真正的态度?) 2、晚饭后,母亲和女儿一块儿洗碗盘,父亲和儿子在客厅看电视。 突然,厨房里传来打破盘子的响声,然后一片沉寂。 儿子望着他父亲,说道:「一定是妈妈打破的。」 「你怎么知道?」 「她没有骂人」 (注:我们习惯以不同的标准来看人看己,以致往往是责人以严,待己以宽。) 3、有两个台湾观光团到日本伊豆半岛旅游,路况很坏,到处都是坑洞。 其中一位导游连声抱歉,说路面简直像麻子一样。 而另一个导游却诗意盎然地对游客说:诸位先生,我们现在走的这条道路,正是赫赫有名的伊豆迷人酒窝大道。」 (注:虽是同样的情况,然而不同的意念,就会产生不同的态度。思想是何等奇妙的事,如何去想,决定权在你。) 4、同样是小学三年级的学生,在作文中说他们将来的志愿是当小丑。 中国的老师斥之为:「胸无大志,孺子不可教也!」 外国的老师则会说:「愿你把欢笑带给全世界!」 (注:身为长辈的我们,不但容易要求多于鼓励,更狭窄的界定了成功的定义。) 5、有一个欧巴桑在首饰店里看到二只一模一样的手环。一个标价五百五十元,另一个却只标价二百五十元。 她大为心喜,立刻买下二百五十元的手环,得意洋洋的走出店门。 临出去前,听到里面的店员悄悄对另一个店员说:「看吧,这一招屡试不爽。」 (注:试探如饵,可以轻而易举的使许多人显露出贪婪的本性,然而那常常是吃亏受骗的开始。) 6、乞丐:「能不能给我一百块钱?」 路人:「我只有八十块钱。」 乞丐:「那你就欠我二十块钱吧」 (注:有些人总以为是上苍欠他的,老觉得老天爷给的不够多、不够好,贪婪之欲早已取代了感恩之心。) 7、在故宫博物院中,有一个太太不耐烦地对她先生说: 「我说你为甚么走得这么慢。原来你老是停下来看这些东西。」 (注:有人只知道在人生的道路上狂奔,结果失去了观看两旁美丽花朵的机会。) 8、妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停:慢些。小心!火太大了。 赶快把鱼翻过来。快铲起来,油放太多了!把豆腐整平一下。哎唷,锅子歪了!」 「请你住口!」妻子脱口而出,「我懂得怎样炒菜。」 「你当然懂,太太,」丈夫平静地答道:「我只是要让你知道,我在开车时,你在旁边 喋喋不休,我的感觉如何。」 (注:学会体谅他人并不困难,只要你愿意认真地站在对方的角度和立场看问题。) 9、第一名 毕业典礼上,校长宣布全年级第一名的同学上台领奖,可是连续叫了好几声之後,那位学生才慢慢的走上台。 後来,老师问那位学生说:"怎麽了?是不是生病了?还是没听清楚?" 学生答:"不是的,我是怕其他同学没听清楚。" (名与利是多少人的捆绑、多少人的心结?我们被教育要争气、要出头,但是争气出头的,不过是少数人,沉默的大众毕竟还多数。想一想,有那麽多人都和你我一样,不也是很兴奋的一件事吗?) 10、理由充份 一辆载满乘客的公共汽车沿着下坡路快速前进着,有一个人後面紧紧地追赶着这辆车子。 一个乘客从车窗中伸出头来对追车子的人:"老兄!算啦,你追不上的!" "我必须追上它,"这人气喘吁吁地说:"我是这辆车的司机" (有些人必须非常认真努力,因为不这样的话,後果就十分悲惨了!然而也正因为必须全力以赴,潜在的本能和不为人知的特质终将充份展现出来。) 11、原来如此 甲:「新搬来的邻居好可恶,昨天晚上三更半夜、夜深人静之时然跑来猛按我家的门。」 乙:「的确可恶!你有没有马上报警?」「没有。我当他们是疯子,继续吹我的小喇 叭。」 (事出必有因,如果能先看到自己的不是,答案就会不一样。在你面对冲突和争执时,先想一想是否心中有亏,或许很快就能释怀了。) 12、误会 某日,张三在山间小路开车。 正当他悠哉地欣赏美丽风景时,突然迎面开来一辆货车,而且满囗黑牙的司机还摇下窗 户对他大骂一声:"猪" 张三越想越纳闷,也越想越气,於是他也摇下车窗回头大骂:"你才是猪!" 才刚骂完,他便迎头撞上一群过马路的猪。 (不要错误的诠释别人的好意,那只会让自己吃亏,并且使别人受辱。 在不明所以之前,先学会按捺情绪,耐心观察,以免事後生发悔意。) 13、後生可畏 小男孩问爸爸:"是不是做父亲的总比做儿子的知道得多?" 爸爸回答:"当然啦!" 小男孩问:"电灯是谁发明的?" 爸爸:"是爱迪生。" 小男孩又问:"那爱迪生的爸爸怎麽没有发明电灯?" (很奇怪,喜欢倚老卖老的人,特别容易栽跟斗。权威往往只是一个经不起考验的空壳子,尤其在现今这个多元开放的时代。) 14、不必紧张 小明洗澡时不小心吞下一小块肥皂,他的妈妈慌慌张张地打电话向家庭医生求助。 医生说:"我现在还有几个病人在,可能要半小时後才能赶过去。" 小明妈妈说:"在你来前,我该做甚麽?" 医生说:"给小明喝一杯白开水,然後用力跳一跳,你就可以让小明用嘴巴吹泡泡消磨时间了。" (Take it easy!放轻松些,生活何必太紧张?事情既然已经发生了,何不坦然自在的面对。担心不如宽心,穷紧张不如穷开心。) 15、钥匙 一把坚实的大锁挂在大门上,一根铁杆费了九牛二虎之力,还是无法将它撬开。 钥匙来了,他瘦小的身子钻进锁孔,只轻轻一转,大锁就"啪"地一声打开了。 铁杆奇怪地问:"为什麽我费了那麽大力气也打不开,而你却轻而易举地就把它打开了呢?" 钥匙说:"因为我最了解他的心。" (每个人的心,都像上了锁的大门,任你再粗的铁棒也撬不开。唯有关怀,才能把自己变成一只细腻的钥匙,进入别人的心中,了解别人。)
posted @ 2009-10-14 14:36 华梦行 阅读(157) | 评论 (0)编辑 收藏
中国民企的行销中的沟通,主要是语言方面的沟通,如何与客户有效地交谈是一项很重要的商业技能。 孔子说过:“言不顺,则事不成”。 鬼谷子人际兵法是古代游说技术的集大成者,古代纵横家们就是凭借出色的口才来说服那些帝王将相们的。 据历史记载,苏秦、张仪等纵横家们的口才都是非常出众、且富有煽动性,他们甚至能够将黑的说成白的,没有的说成有的,充满了诡辩的色彩。 今天的商业,以诚信为本无疑是企业发展的根本动力。 行销中与人沟通,完全不讲策略性是不够的,但是颠倒黑白,混淆视听也是不足取的。 语言才华与个人天赋有关,也与一个人的自身修养、知识积累有关,本章重点不是讨论如何提高语言表达的才华,而是从策略性方面来讨论如何提高语言沟通的效果。 对于绝大多数的行销人员来说,如何说话似乎是一件简单得不能够再简单的事情了,但实际上,我们经常会遇到一些行销人员在与客户交谈中所表现出来的幼稚性。 一次,某公司的行销人员拜访一位客户,这位行销人员问客户:“什么时候讨论我们的产品啊?” 客户说:“要下个月。” 行销人员说:“这么久哇,能不能这个月就讨论呢?” 客户说:“这是我们自己的事情,我们愿意什么时候讨论就什么时候讨论!” 这位行销人员并不气馁,又谈起了别的话题:“某某客户已经与我们合作了,你们也应该与我们合作。” 客户说:“某某客户是个小公司,我们是大公司,请你不要用小公司与我们比较!” 也许你会说这是新手们常犯的毛病,那么我曾经听说过这样一个故事:一次,某经理请客户甲吃饭,由于客户甲与客户乙关系很好,于是一起邀来吃饭。 席间,某经理夸夸其谈,说他们公司多大多大,他本人多有本事,如何会做生意云云。 客户乙属于那种爱较真的性情中人,当某经理说道“没有我搞不定的客户”时,客户乙一拍桌子,指着某经理说道:“如果这样说,我你就搞不定!” 果然,到现在某经理也没有搞定客户乙。 某经理不是没有能力,但是讲话太不注意小节,结果造成了不必要的麻烦,实在应该引以为诫。 鬼谷子认为,嘴巴是用来吃饭的,而不是用来乱讲话的,因为言多必失。 在古代,政治斗争十分残酷,因此,官僚们都是以无事少言、缄默其口作为安身立命的准则。 今天,与客户沟通交谈时,注重说话的策略更显重要,因为你说的每一句话,都可能会使客户产生不同的心理反应。 客户是上帝,甚至是被宠坏的上帝,不恰当的话语:——可以令和睦的关系转为生疏;——可以令生疏的关系转为紧张;——可以令紧张的关系转为破裂。 鬼谷子对于语言的沟通提出了许多充满智慧的见解,对于我们从事行销工作很有帮助。 鬼谷子认为,人之常情是:——说出来的话就希望被别人接受;——做出来的事就希望能够成功。 因此,游说的关键在于掌握扬长避短的策略,例如:——我们极力宣传某种行为的利益,是因为我们可以提供这方面的利益;——我们极力宣传某种行为的危害,是因为我们不擅长这种行为的操作;掌握了扬长避短的沟通策略,就可以有针对性地游说人物了:——与精明的人交谈,要思路广博,多方论证,避免纠缠一点不放;——与知识广博的人交谈,要善于抓住重点,辨析事理;——与地位高的人交谈,不要表现出一种自卑的气势;——与自觉富有的人交谈,要从人生意义、社会价值等方面来发挥;——与自觉贫穷的人交谈,要从如何获利的角度来探讨;——与地位低下的交谈,要表现出充分的尊重来;——与有魄力的人交谈,要表现出果敢的一面来;——与愚蠢的人交谈,要从最有说服力的几个要点来反复阐述;针对不同的目标对象,有策略地沟通,东西方自古以来都有类似的看法。 古希腊哲学家亚里士多德认为,说服别人就要研究:——“人类性格”的类型与人类感情之间的关系;——“人类性格”的类型与人类道德之间的关系;——“人类性格”的类型与人物年龄之间的联系;——“人类性格”的类型与人类“命运”如:出身、财产、地位之间的联系;等等。 因此,亚里士多德将人物分为:——“青年型”、——“壮年型”、——“老年型”、——“富人型”、——“权贵型”等类型。 并分别对这些类型的人物进行了详细的心理特征描述,与鬼谷子的观点十分相似。 按照人物的:——性格特征;——社会地位;——职业特点;——年龄状况;——智力水平;——气质风格;——经济条件,等内容。 将这些特征、条件综合起来,针对不同的目标个体,采取个性化的沟通策略,无疑是古今不变的沟通秘诀。 除了针对不同的目标人物,采劝看人下菜碟”式的沟通策略外,鬼谷子对于语言沟通的表达形式也做了深入的研究。 例如,语言沟通的三种常见形式是:——陈述观点、——回答问题、——提出反驳。 对于这三种常见的沟通形式,掌握了基本的操作要领,可以有效地与人物沟通,而不会犯下无谓的错误。 下面分别介绍:1、陈述观点鬼谷子认为,与人物沟通,是为了说服别人接受自己的观点,并认同自己。而要达到这样的目的,一定要注意采取有利于对方的沟通方式,令对方觉得所陈述的观点、主张确实有利于对方,是对方所需要的。 这一观点在今天看来,是行销常识了。 诉诸利益,是行销过程中最关键的环节,如果你所诉诸的利益确实是对方所需要的、或最感兴趣的,那么行销就成功一大半了。 然而,对于利益的陈述,不是简单地将利益讲清楚就可以了,还需要在沟通中作进一步地修饰。 鬼谷子式语言沟通的特点是,与人物交谈犹如炒菜,加减佐料,完全视人物的口味来调整,但是菜的性质并没有改变。 现在一些公司要求行销人员学会背诵固定的销售台词,如果行销人员不会临场发挥,只是一味机械地照本宣科,其行销效果如何就不必多说了。 2、回答问题鬼谷子认为,回答问题的要领在于简单明了,尽量不要过于随便地发挥,更不要轻易地表态。 在鬼谷子智能行销工具中,回答客户问题的内容完全是策略上的需要,而不是想怎么说就怎么说,要注意说话的场合与背景。 例如,在回答客户的问题时,有的人生怕回答得不够详细,恨不得把所知道的全都讲出来,这其实是很愚蠢的:——一方面言多必失,话说多了,可能会导致相反的效果;——另一方面,讲得越多,客户对你的心理透视也越深入,就会很被动。 因此,行销中点到为止式的回答技巧是鬼谷子所推崇的。观察那些行销高手们说话,虽然表面上看起来似乎轻松随意,但是仔细分析,你会发现:他们所讲的每句话,并不是随随便便地脱口而说的,而是设下了很多前提,埋下了很多伏笔。 3、提出反驳在鬼谷子看来,提出反驳,目的不在于因此而说服对方,相反,却是一种试探人物心理虚实的策略。 鬼谷子认为,反驳别人的观点,不是说服别人的最好办法,却是了解别人真实想法的有效办法。 行销中,与客户沟通不是举行辩论赛,说服客户不是靠论理明确、论据充分,而是靠客户心甘情愿的认同。 记住,与客户洽谈生意,谈的不是道理,而是合作。道理只是形式,合作才是根本。你把客户说服了并不能够获得合作,你把客户说得心动了才能够获得合作。 因此,鬼谷子反对用反驳的方式来证明自己、打击客户(当然,与竞争对手较量时适当的反驳会很重要),却主张用反驳的方式来刺激对方,从而获得更多的信息。 需要说明的是,鬼谷子的这些语言表达的要领,只适合特定情形下的沟通,而不适合学术辩论会等形式的沟通,因而其特殊的沟通思维方式,与人们平时的习惯性思维是有区别的。 一些人总搞不清楚的是:在不同的环境与情形中,语言沟通的特点是不同的。 甚至有些人以为只要掌握了辩论赛式的口才就足以应付行销工作了,殊不知,有时候这种辩论赛式的语言表达不但于事无补,反而可能会“火上浇油”,令沟通无法有效展开。 鬼谷子式语言表达形式的另一个特点,就是强调语言表达方式的策略性,这种策略性根据我们在行销中的体会,主要表现为:——幽默性、——奇特性等内容。 正如有学者说所言:“当谋略靠幽默的语言来实现时,这幽默的语言本身就是谋略,谋略就是幽默的语言,二者是统一的……幽默的语言必定是精炼含蓄的语言,妙趣横生的语言。”(刘建国《谋略初论》)鬼谷子也认为:——语言的表达贵在奇特性。 下面,我们从将从语言表达的——幽默性、——奇特性两方面来具体分析:1、行销言语的幽默性行销中,与客户沟通,语言的幽默性是十分重要的,因为幽默具有艺术性的含蓄与夸张等特点:——含蓄是幽默的深层;——夸张则是幽默的表层。 含蓄的语言往往暗示性较强,更容易令客户在心里上接受,许多难以用道理说明的事情,用含蓄的幽默表达方式会更方便些。 夸张的语言风格,虽然会导致逻辑上的荒谬,但是却更容易启发客户领悟到荒谬背后的真相,而不至于伤害彼此感情。 同时,夸张还带有某种证明性,可以更吸引他人的注意。 记得有一部外国电影,其中有这样一个情节:一个人当街推销领带,这位老兄在大街上侃侃而谈:“女士们,先生们,现在是卫星发射的时代!”(观众笑)这位老兄更加得意了:“我的领带质量非常的好,昨天我就发射了一条,到现在还没有回收呢!”(观众大笑)幽默感强的行销高手们,往往以自我嘲讽的方式来回避客户的刁难,既避免了难堪,却又不伤和气。 2、行销言语的奇特性策略性语言的另一个特点是语言的奇特性,这种语言风格的奇特性虽然也部分地包含在幽默当中了,却具有更广阔的发挥空间。 语言的奇特性,是指与人们的习惯思维、常识认知等相违背的,一种非常规的、独特的表达方式,其目的是制造出一种出人意料的戏剧性效果。 这种戏剧性的效果,可以令客户的兴趣指数在极短的时间内迅速扩大数倍,将客户的重视程度迅速放大数倍,从而为工作的开展打下良好的基矗需要注意的是,实践中语言的幽默性与奇特性发挥是有一定限度的,过分地追求语言的幽默性与奇特性,有时候反而会影响沟通的效果。 某公司的经理与业务员拜访客户,这位经理开玩笑说:“我代表我们公司来贵单位拜访,是想关心关心你们。” 不料,这位客户今天的心情并不好,于是脸一沉地说:“我很忙,你们给我出去!” 搞得这位经理一脸的难堪。 鬼谷子不愧是语言表达的专家,除了针对不同的语言表达方式提出了应对策略外,还提出了几种可以产生不同效果的语言表达系列套餐。 鬼谷子认为,运用语言来获得他人的喜欢与重视,需要学会:——佞言;——谀言;——平言;——戚言;——静言等五种表达技巧。 因为:——佞言可以表现你的忠诚;——谀言可以表现你的智慧;——平言可以表现你的果断;——戚言可以表现你的可信性;——静言可以表现你的权威性。 对于今天的人们来说,佞言、谀言等都带有贬义色彩,其实鬼谷子的思维方式与今天的思维方式是有所区别的,正如鬼谷子强调“阴谋”,在鬼谷子的字典里“阴谋”是隐性策略的意思,而不是今天汉语中“阴谋诡计”的贬义解释。 上述的五种语言技巧,其功能主要是表现出你的:——忠诚;——智慧;——果断;——可信性;——权威性。 这是五种含有浓厚包装色彩的语言表达技巧,目的是获得他人的好感,或者展示个人魅力以及能力。 当然,究竟向客户表达出你的哪些优点,还需要视具体情况来定。 例如:——如果客户需要你是个忠诚、可信的人,就需要运用语言的策略性来表现出这方面的优点;——如果客户需要你的建议具有权威性,就需要运用语言的策略性来表现出你这方面的优点;等等。 那么,如何具体操作呢? 1、“忠诚”的语言表达技巧操作要领:预先知道客户的意图、需求,只要顺着客户的意图、需求来说话,经过一段时间后,就可以令客户欣赏你的为人了,因为你们的想法与需求是如此的一致。 回顾一下你周围的朋友,你觉得对你最忠诚的朋友是哪些?他们有什么样的特征? 经过思考,你会发现,你认为对你最忠心的朋友,一定是那些最能理解你、并总是和你的行事意图相一致的人。 他们凭什么获得了你的好感呢? 很简单,他们的想法总是与你保持高度的一致,而很少会违背你的意愿。 2、“智慧”的语言表达技巧操作要领:在论述、发表意见时,要表现出你的知识渊博来。虽然你的智慧程度与你的知识面可能无法划等号,但是,在你的客户看来,你广博的知识往往会给客户留下智慧的印象。 行销中,智慧的表现方式不是要求你就某个人生命题讲解得十分透彻,这样很难,而且你的大多数客户也没有这个雅兴,他们中很多是普通人。 因此,只要平时能够表现出你广博的知识面来,就可以给客户一个充满智慧的印象,并开始重视你的为人。 3、“果断”的语言表达技巧操作要领:果断是自信的表现;优柔寡断是不自信的表现。 你的果断表现在:——你的是非观念是否分明? ——你的判断依据是否符合逻辑? ——你的分析能力是否可以洞察问题的本质? 等等。 你平时与客户交流中,如果所作的分析,常常可以洞察事物的本质,并且针对这些分析,可以做出较明确的判断。 那么一段时间后,你在客户心目中无疑会留下十分果断的印象。 4、“可信性”的语言表达技巧操作要领:你的观点是否可信,在于你的证据是否可信,你的论证是否符合逻辑。这需要你列举出一些有说服力的证据,通过论证的方式,将各种方案的优劣、长短逐一比较分析,并从中优选出最佳的方案来。 摆事实,讲道理,这是说服客户最有效的办法。 任何客户都具有精明、理智的一面,如果你能够通过有力证据、有说服力的方案而获得客户的认可,一段时间后,客户对于你的建议的可信性自然提高许多。 5、“权威性”的语言表达技巧操作要领:树立权威的最好办法就是找出其他待选方案的缺点与不足,通过这些比较,自然可以建立起自己的权威性来。当然,有时候如果能够找出权威性的依据自然更好。 所谓“打击别人,抬高自己”。 古代纵横家们,往往善于玩弄诡辩伎俩,无限夸大竞争对手或竞争方案的缺点,同时无限夸大自己方案的优点,通过对于异己力量的打击与自我吹捧,达到树立权威的目的。 当然,这种作法即使一时得逞,终究会被人揭穿的。 行销中,我们主张以诚信为本,对于一些有根有据的东西,可以适当地宣传,但不要超出一个度,否则适得其反。 以上,我们介绍了鬼谷子式语言策略的五个自我表现技巧,对于我们从事行销工作有很大帮助,因为从:——忠诚;——智慧;——果断;——可信性;——权威性五个方面来表现自己,可以在一定程度上获得客户的欣赏与重视,这也是你提高个人魅力的一个有效办法。 但是,客户是很现实的,他们最终还是要通过行动来考核你。 因此,语言表达的威力充其量只是你行销的一个辅助性工具,你还需要不断地用你的行动来“说话”。 以上,我们从策略性的角度将鬼谷子的语言表达艺术做了一点总结,中国古代纵横家们的口才是中华民族文学宝库中的奇葩,许多脍炙人口的文章都出自于纵横家之口,对于纵横家们口才的研究是一个具有相当深度与广度的课题,显然本文只是沧海一粟,难窥全貌,希望有机会与大家共同探讨、切磋。
posted @ 2009-10-14 14:03 华梦行 阅读(250) | 评论 (0)编辑 收藏
1. 当艺术评论家聚在一起的时候他们谈论的都是关于版式结构以及意蕴之类的话题,而真正的艺术家在一起的时候谈论的则是到哪里才能买到便宜的松节油。 2.软件开发的过程: 1)定义问题 2)需求分析 3)规划构架 4)软件构件 5)详细设计 6)编码与调试 7)单元测试 8)集成测试 9)集成 10)系统测试 11)保障维护 3.重要的研发成果产出产自类比。通常把不理解的东西和一些较为理解的且十分相似的东西作比较,可以对理解不深刻的东西产生更深刻的理解。这种隐喻的方法叫做建模。 4. 文字写作编程模式这一隐喻暗示着软件开发过程是一种代价昂贵的试错过程,而非仔细的 规划和设计。 5.三思而后行。 6.有一些程序员确实知道如何进行这些前期工作,但是他们并没有这么做。因为他们不能抵抗'尽快开始编码'的欲望。为什么会这样?是一种基于什么样的心理状态才导致了这种近似幼稚的情况的出现呢?
posted @ 2009-10-13 17:08 华梦行 阅读(452) | 评论 (0)编辑 收藏
文档流是文档中可显示对象在排列时所占用的位置。比如网页的div标签它默认占用的宽度位置是一整行,p标签默认占用宽度也是一整行,因为div标签和p标签是块状对象。 网页中大部分对象默认是占用文档流,也有一些对象是不占文档流的,比如表单中隐藏域。当然我们也可以让占用文档流的元素转换成不占文档流,这就要用到CSS中属性position来控制。 看看CSS 2.0对position的定义:检索对象的定位方式。共有4种取值。 static:默认值,无特殊(静态)定位。对象遵循HTML定位规则 。 absolute:绝对定位。将对象从文档流中拖出,使用left,right,top,bottom等属性相对于其最接近的一个最有定位设置的父对象进行绝对定位。如果不存在这样的父对象,则依据body对象。而其层叠通过z-index属性定义 。当对象定位在浏览器窗口以外,浏览器因此显示滚动条。 fixed:固定定位。对象定位遵从绝对(absolute)方式。但是要遵守一些规范。当对象定位在浏览器窗口以外,浏览器不会因此显示滚动条,而当滚动条滚动时,对象始终固定在原来位置。 relative:相对定位。对象不可层叠,但将依据left,right,top,bottom等属性在正常文档流中偏移位置。当对象定位在浏览器窗口以外,浏览器因此显示滚动条。 inherit:继承值,对象将继承其父对象相应的值
posted @ 2009-10-13 16:56 华梦行 阅读(902) | 评论 (0)编辑 收藏
发现一个不错的养生网站 养生之道 www.yszd.org ,希望大家喜欢。
posted @ 2009-09-25 22:25 华梦行 阅读(267) | 评论 (0)编辑 收藏
hessian
posted @ 2009-08-24 09:26 华梦行 阅读(228) | 评论 (0)编辑 收藏
http://xstream.codehaus.org/json-tutorial.html
posted @ 2009-08-12 08:55 华梦行 阅读(268) | 评论 (0)编辑 收藏
/* CSS Reset for Taobao 注意:这里是 ONLY for Taobao 的 reset rules 维护:玉伯(lifesinger@gmail.com), 正淳(ragecarrier@gmail.com) */ /* require(reset.css) */ html { color: #404040; /* 淘宝文字默认色 */ background: #fff; /* 覆盖掉用户在不知情的情况下,设置的页面背景 */ } /* 淘宝链接默认色 */ a { color: #404040; } a:hover { color: #f60; } /* 重置 hr */ hr { color: #ccc; background-color: #ccc; } /* misc */ html { /* 让非ie浏览器默认也显示垂直滚动条,防止因滚动条引起的闪烁 */ overflow-y: scroll; }
posted @ 2009-07-29 18:09 华梦行 阅读(507) | 评论 (0)编辑 收藏
javascript的继承机制并不是明确规定的,而是通过模仿实现的,意味着继承不是由解释程序处理,开发者有权决定最适合的继承方式. 下面我给出几种常用的方法: 1 .对象冒充 原理: 构造函数使用this关键字给所有属性和方法赋值, 因为构造函数只是一个函数,所以可以使ClassA的构造函数成为classB的方法,然后调用它.这样classB就会收到classA的构造函数中定义的属性和方法.例子: function classA(name) { this.name=name; this.showName=function(){alert(this.name);} } function classB(name) { this.newMethod = classA; this.newMethod(name); } obj = new classA("hero"); objB = new classB("dby"); obj.showName(); // print hero objB.showName(); // print dby 说明classB 继承了classA的方法. 对象冒充可以实现多重继承 例如 function classz(){ this.newMethod = classX; this.newMethod(); delete this.newMethod; this.newMethod=classY; this.newMethod(): delete this.newMethod; } 但是如果classX和classY有相同的属性或者方法,classY具有高优先级. 2.call()方法 call方法使与经典的对象冒充法就相近的方法,它的第一个参数用作this的对象,其他参数都直接传递给函数自身. function sayName(perfix) { alert(perfix+this.name); } obj= new Object(); obj.name="hero"; sayName.call(obj,"hello," ); function classA(name) { this.name=name; this.showName=function(){alert(this.name);}; } function classB(name) { classA.call(this,name); } objB = new classB("bing"); objB.showName();////说明classB继承classA的showName方法 3.apply()方法 aplly()方法有2个参数,一个用作this对象,一个使传递给函数的参数数组. function sayName(perfix) { alert(perfix+this.name); } obj= new Object(); obj.name="hero"; sayName.aplly(obj,new Array("hello,") ); 4. 原型链 prototype对象的任何属性和方法都会被传递给对应类的所有实例,原型链就是用这种方式来显现继承. function classA (){} classA.prototype.name="hero"; classA.prototype.showName=function(){alert(this.name)} function classB(){} classB.prototype=new classA(); objb = new classB() objb.showName();//print hero 说明b继承了a的方法 这里需要注意 调用classA的构造函数时,没有给它传递参数,这是原型链的标准做法,确保函数的构造函数没有任何参数. 并且 子类的所有属性和方法,必须出现在prototype属性被赋值后,应为在它之前赋的值会被删除.因为对象的prototype属性被替换成了新对象,添加了新方法的原始对象将被销毁. 5 混和方式 就是用冒充方式 定义构造函数属性,用原型法定义对象方法. function classA(name) { this.name=name; } classA.prototype.showName=function(){alert(this.name)} function classB(name) { classA.call(this,name); } classB.prototype = new classA(); classB.prototype.showName1=function(){alert(this.name+"*****");}; obj = new classB("hero"); obj.showName(); obj.showName1(); 在classB的构造函数中通过调用call方法 继承classA中的name属性,用原型链来继承classA的showName方法.
posted @ 2009-07-16 13:47 华梦行 阅读(116) | 评论 (0)编辑 收藏
1)Sun的JVM在实现Selector上,在Linux和Windows平台下的细节。 2)Selector类的wakeup()方法如何唤醒阻塞在select()系统调用上的细节。 先给大家做一个简单的回顾,在Windows下,Sun的Java虚拟机在Selector.open()时会自己和自己建立loopback的TCP链接;在Linux下,Selector会创建pipe。这主要是为了Selector.wakeup()可以方便唤醒阻塞在select()系统调用上的线程(通过向自己所建立的TCP链接和管道上随便写点什么就可以唤醒阻塞线程) 我们知道,无论是建立TCP链接还是建立管道都会消耗系统资源,而在Windows上,某些Windows上的防火墙设置还可能会导致Java的Selector因为建立不起loopback的TCP链接而出现异常。 而在我的另一篇文章《用GDB调试Java程序》中介绍了另一个Java的解释器——GNU的gij,以及编译器gcj,不但可以比较高效地运行Java程序,而且还可以把Java程序直接编译成可执行文件。 GNU的之所以要重做一个Java的编译和解释器,其一个重要原因就是想解释Sun的JVM的效率和资源耗费问题。当然,GNU的Java编译/解释器并不需要考虑太多复杂的平台,他们只需要专注于Linux和衍生自Unix System V的操作系统,对于开发人员来说,离开了Windows,一切都会变得简单起来。在这里,让我们看看GNU的gij是如何解释Selector.open()和Selector.wakeup()的。 同样,我们需要一个测试程序。在这里,为了清晰,我不会例出所有的代码,我只给出我所使用的这个程序的一些关键代码。 我的这个测试程序中,和所有的Socket程序一样,下面是一个比较标准的框架,当然,这个框架应该是在一个线程中,也就是一个需要继承Runnable接口,并实现run()方法的一个类。(注意:其中的s是一个成员变量,是Selector类型,以便主线程序使用) //生成一个侦听端 ServerSocketChannel ssc = ServerSocketChannel.open(); //将侦听端设为异步方式 ssc.configureBlocking(false); //生成一个信号监视器 s = Selector.open(); //侦听端绑定到一个端口 ssc.socket().bind(new InetSocketAddress(port)); //设置侦听端所选的异步信号OP_ACCEPT ssc.register(s,SelectionKey.OP_ACCEPT); System.out.println("echo server has been set up ......"); while(true){ int n = s.select(); if (n == 0) { //没有指定的I/O事件发生 continue; } Iterator it = s.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); if (key.isAcceptable()) { //侦听端信号触发 …… …… …… …… …… …… } if (key.isReadable()) { //某socket可读信号 …… …… …… …… …… …… } it.remove(); } } 而在主线程中,我们可以通过Selector.wakeup()来唤醒这个阻塞在select()上的线程,下面是写在主线程中的唤醒程序: new Thread(this).start(); try{ //Sleep 30 seconds Thread.sleep(30000); System.out.println("wakeup the select"); s.wakeup(); }catch(Exception e){ e.printStackTrace(); } 这个程序在主线程中,先启动一个线程,也就是上面那个Socket线程,然后休息30秒,为的是让上面的那个线程有阻塞在select(),然后打印出一条信息,这是为了我们用strace命令查看具体的系统调用时能够快速定位。之后调用的是Selector的wakeup()方法来唤醒侦听线程。 接下来,我们可以通过两种方式来编译这个程序: 1)使用gcj或是sun的javac编译成class文件,然后使用gij解释执行。 2)使用gcj直接编译成可执行文件。 (无论你用那种方法,都是一样的结果,本文使用第二种方法,关于gcj的编译方法,请参看我的《用GDB调试Java程序》) 编译成可执行文件后,执行程序时,使用lsof命令,我们可以看到没有任何pipe的建立。可见GNU的解释更为的节省资源。而对于一个Unix的C程序员来说,这意味着如果要唤醒select()只能使用pthread_kill()来发送一个信号了。下面就让我们使用strace命令来验证这个想法。 下图是使用strace命令来跟踪整个程序运行时的系统调用,我们利用我们的输出的“wakeup the select”字符串快速的找到了wakeup的实际系统调用。
posted @ 2009-06-16 14:50 华梦行 阅读(565) | 评论 (0)编辑 收藏
很早就听说tomcat6使用nio了,这几天突然想到一个问题,使用nio代替传统的bio,ThreadLocal岂不是会存在冲突?   如果读者有socket的编程基础,应该会接触过堵塞socket和非堵塞socket,堵塞socket就是在accept、read、write等IO操作的的时候,如果没有可用符合条件的资源,不马上返回,一直等待直到有资源为止。而非堵塞socket则是在执行select的时候,当没有资源的时候堵塞,当有符合资源的时候,返回一个信号,然后程序就可以执行accept、read、write等操作,这个时候,这些操作是马上完成,并且马上返回。而windows的winsock则有所不同,可以绑定到一个EventHandle里,也可以绑定到一个HWND里,当有资源到达时,发出事件,这时执行的io操作也是马上完成、马上返回的。一般来说,如果使用堵塞socket,通常我们时开一个线程accept socket,当有socket链接的时候,开一个单独的线程处理这个socket;如果使用非堵塞socket,通常是只有一个线程,一开始是select状态,当有信号的时候马上处理,然后继续select状态。  按照大多数人的说法,堵塞socket比非堵塞socket的性能要好。不过也有小部分人并不是这样认为的,例如Indy项目(Delphi一个比较出色的网络包),它就是使用多线程+堵塞socket模式的。另外,堵塞socket比非堵塞socket容易理解,符合一般人的思维,编程相对比较容易。     nio其实也是类似上面的情况。在JDK1.4,sun公司大范围提升Java的性能,其中NIO就是其中一项。Java的IO操作集中在java.io这个包中,是基于流的阻塞API(即BIO,Block IO)。对于大多数应用来说,这样的API使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用,往往需要一个更为有效的方式来处理IO。从JDK 1.4起,NIO API作为一个基于缓冲区,并能提供非阻塞O操作的API(即NIO,non-blocking IO)被引入。  BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。   这个时候,问题就出来了:我们非常多的java应用是使用ThreadLocal的,例如JSF的FaceContext、Hibernate的session管理、Struts2的Context的管理等等,几乎所有框架都或多或少地应用ThreadLocal。如果存在冲突,那岂不惊天动地?    后来终于在Tomcat6的文档(http://tomcat.apache.org/tomcat-6.0-doc/aio.html)找到答案。根据上面说明,应该Tomcat6应用nio只是用在处理发送、接收信息的时候用到,也就是说,tomcat6还是传统的多线程Servlet,我画了下面两个图来列出区别:   tomcat5:客户端连接到达 -> 传统的SeverSocket.accept接收连接 -> 从线程池取出一个线程 -> 在该线程读取文本并且解析HTTP协议 -> 在该线程生成ServletRequest、ServletResponse,取出请求的Servlet -> 在该线程执行这个Servlet -> 在该线程把ServletResponse的内容发送到客户端连接 -> 关闭连接。      我以前理解的使用nio后的tomcat6:客户端连接到达 -> nio接收连接 -> nio使用轮询方式读取文本并且解析HTTP协议(单线程) -> 生成ServletRequest、ServletResponse,取出请求的Servlet -> 直接在本线程执行这个Servlet -> 把ServletResponse的内容发送到客户端连接 -> 关闭连接。 实际的tomcat6:客户端连接到达 -> nio接收连接 -> nio使用轮询方式读取文本并且解析HTTP协议(单线程) -> 生成ServletRequest、ServletResponse,取出请求的Servlet -> 从线程池取出线程,并在该线程执行这个Servlet -> 把ServletResponse的内容发送到客户端连接 -> 关闭连接。    从上图可以看出,BIO与NIO的不同,也导致进入客户端处理线程的时刻有所不同:tomcat5在接受连接后马上进入客户端线程,在客户端线程里解析HTTP协议,而tomcat6则是解析完HTTP协议后才进入多线程,另外,tomcat6也比5早脱离客户端线程的环境。   实际的tomcat6与我之前猜想的差别主要集中在如何处理servlet的问题上。实际上即使抛开ThreadLocal的问题,我之前理解tomcat6只使用一个线程处理的想法其实是行不同的。大家都有经验:servlet是基于BIO的,执行期间会存在堵塞的,例如读取文件、数据库操作等等。tomcat6使用了nio,但不可能要求servlet里面要使用nio,而一旦存在堵塞,效率自然会锐降。   所以,最终的结论当然是tomcat6的servlet里面,ThreadLocal照样可以使用,不存在冲突
posted @ 2009-06-16 14:30 华梦行 阅读(209) | 评论 (0)编辑 收藏
我就拿一个房子来做一个比方吧,服务器好比就是一幢房子,黑客最直接的方式就是带着一些撬锁的工具,去把房子的锁给撬掉,然后夺门而入,这种方式被称为服务器入侵。还有一类就是它直接撬大门锁撬不开,它就把这个房子的窗打破,从窗子里面钻进去,来进行破坏,这种方式叫做网站入侵。还有一类就是黑客带着一只训练有素的小猴子,让小猴子爬到房子的房顶,从烟囱里面钻进去,然后把大门打开,这种方式叫做特洛伊木马入侵。还有一类就是我们前面讲到那个事件的DDOS攻击这个技术,这个相当于黑客带着一大帮人过来把房子的大门给堵住了,让房子里面的人出不来,让外面的人也进不去,这就是DDOS攻击。
posted @ 2009-06-10 10:40 华梦行 阅读(139) | 评论 (0)编辑 收藏
SELECT DATEADD(mm,DATEDIFF(mm,0,getdate()),0) //首先选出当前月,然后把他转换为日期 select (2009-1900)*12 select DATEDIFF(mm,0,getdate())
posted @ 2009-06-08 14:39 华梦行 阅读(178) | 评论 (0)编辑 收藏
 #define   WINVER   0x0050  
#define   WINVER   0x0500,这个表示是为Windows   2000编译,不保证Windows   98/NT4可以正常运行  

Windows   Server   2003  
  WINVER>=0x0502  
     
  Windows   XP    
  WINVER>=0x0501  
     
  Windows   2000  
  WINVER>=0x0500  
     
  Windows   NT   4.0  
  WINVER>=0x0400  
     
  Windows   Me  
  WINVER>=0x0500  
     
  Windows   98  
  WINVER>=0x0410  
     
  Windows   95  
  WINVER>=0x0400   
     
posted @ 2009-03-26 22:15 华梦行 阅读(175) | 评论 (0)编辑 收藏

 // TODO: Add your message handler code here and/or call default
 /*HDC hdc;
 hdc=::GetDC(m_hWnd);
 MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
 LineTo(hdc,point.x,point.y);
 ::ReleaseDC(m_hWnd,hdc);*/
 /*CDC *pDC=GetDC();
 pDC->MoveTo(m_ptOrigin);
 pDC->LineTo(point);
 ReleaseDC(pDC);*/

 //CClientDC dc(this);
 /*CClientDC dc(GetParent());
 dc.MoveTo(m_ptOrigin);
 dc.LineTo(point);*/

 //CWindowDC dc(this);
 //CWindowDC dc(GetParent());
 /*CWindowDC dc(GetDesktopWindow());
 dc.MoveTo(m_ptOrigin);
 dc.LineTo(point);*/
 /*CPen pen(PS_DOT,1,RGB(0,255,0));
 CClientDC dc(this);
 CPen *pOldPen=dc.SelectObject(&pen);
 dc.MoveTo(m_ptOrigin);
 dc.LineTo(point);
 dc.SelectObject(pOldPen);*/
// CBrush brush(RGB(255,0,0));

 /*CBitmap bitmap;
 bitmap.LoadBitmap(IDB_BITMAP1);
 CBrush brush(&bitmap);*/
 /*CClientDC dc(this);
 //dc.FillRect(CRect(m_ptOrigin,point),&brush);
 CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
 CBrush *pOldBrush=dc.SelectObject(pBrush);
 dc.Rectangle(CRect(m_ptOrigin,point));
 dc.SelectObject(pOldBrush);*/
 m_bDraw=FALSE;
 CView::OnLButtonUp(nFlags, point);

posted @ 2009-03-24 16:25 华梦行 阅读(160) | 评论 (0)编辑 收藏

#include <iostream.h>
#include <string>
char* strToBinary(int x);
char* strToHex(int i);
char* transToGKB(char *t);

int main ()

{
char *p=strToBinary(233);
//cout<<p;

//cout<<strToHex(233);
cout<<transToGKB("商");
return 0;
}
char* transToGKB(char *t){
 int res=0;
   int intlen;
   intlen=strlen(t);
   if(intlen>1){
    char *result=new char[5];
   int i=0;
 if(0>t[0]){
    res=256+t[0];
  }
 char *p1=strToHex(res);
 if(0>t[1]){
  res=256+t[1];
 }
 char *p2=strToHex(res);
 result=p1;
 result[2]=p2[0];
 result[3]=p2[1]; 
 result[4]='\0'; 
 return result;
 }
   else{
    //if(t[0]>64)
    char * p=new char[3];
    p=strToHex(t[0]);
    p[2]='\0';
    return  p;
   }

}

 

//数字转为二进制(255以内的正数)
char* strToBinary(int i){
 char *result=new   char[9];
 int n=1;
 int m;
 int c=0;
 int j=8;
 for(c=0;c<8;c++){
  m=i%2;
  j=j-1;
  i=n=i/2;
  if(n>=0){
   if (m>0){
    result[j]='1';
   }else
   {
    result[j]='0';
   } 
  }
  
 }
 result[8]='\0';
 
// cout<<result;
 return result;
}
//数字转为十六进制(255以内的正数)
char* strToHex(int i){
 char *result=new   char[3];
 int n=1;
 int m;
 int c=0;
 int j=2;
 for(c=0;c<2;c++){
  m=i%16;
  j=j-1;
  i=n=i/16;
  if(n>=0){
   if (m>0){
    if (m==1){
                  result[j]='1';
    }
    else if (m==2){
     result[j]='2';
    }
    else if (m==3){
     result[j]='3';
    }
    else if (m==4){
     result[j]='4';
    }
    else if (m==5){
     result[j]='5';
    }
    else if (m==6){
     result[j]='6';
    }
    else if (m==7){
     result[j]='7';
    }
    else if (m==8){
     result[j]='8';
    }
    else if (m==9){
     result[j]='9';
    }
    else if (m==10){
     result[j]='A';
    }
    else if (m==11){
     result[j]='B';
    }
    else if (m==12){
     result[j]='C';
    }
    else if (m==13){
     result[j]='D';
    }
    else if (m==14){
     result[j]='E';
    }
    else if (m==15){
     result[j]='F';
    }
   }else
   {
    result[j]='0';
   } 
  }
 }
 result[2]='\0';
 return result;
}

posted @ 2009-03-19 16:37 华梦行 阅读(180) | 评论 (0)编辑 收藏

#include <iostream.h>

#include <string>
void yihuo(char *t,int n, int m);
void  myToBinary();
void transToGKB(char *t);
void  myToHex();
int main(){
//cout<<"GOOD";
int i=122;
int j=233;
int m=j^i;
 char t[128]={0xC9,0xCC,0xC9,0xCC,0xC9,0xCC,'\0',0xC9,0xCC,0xC9,0xCC};
yihuo(t,0, 2);
// transToGKB(t);
//cout<<m;
//yihuo(2, 3);
//myToHex();
// myToBinary();
cout<<endl;
return 0;
}
//进制之间的转换
  // 字符串传为16进制
void  myToHex(){
 char c[] = "CC";
 unsigned long tt= strtoul(c, NULL, 16);
cout<<strtol(c, NULL, 16);

}

// 字符串传为16进制
void  myToBinary(){
 char c[] = "10000000";
// unsigned long tt= strtoul(c, NULL, 2);
 cout<<strtol(c, NULL, 2);
 
 
}
//汉字的转换, 16进制转换为汉字
void transToGKB(char *t){

 
 // char *t="商户";
 // CharN
 //如果是负数,则转为正整数
 // if(0>t[0]){
 //    res=256+t[0];
 // }
 int j=t[0];
 cout<<t<<endl;

}


void yihuo(char *t,int n, int m) {

 char *tt="商户说的算";
    //转成数字并且保存到数组,然后求异或

 //求的长度
const int mylen=strlen(tt)+1;
char mysplit[1000];
//循环对这个整形数组进行赋值
int i=0;
for(i<0;i<mylen-1;i++){
 if (tt[i]<0){
mysplit[i]=256+tt[i];
 }else
 {
mysplit[i]=tt[i];
 }
}
int result=mysplit[n-1];
int j;
for(j=n;j<n+m;j++){
 result=result^mysplit[n];
 cout<<"L"<<endl;
cout<<mysplit[n];
 cout<<"M"<<endl;

}

//进行遍历求异或
mysplit[mylen-1]='\0';
cout<<mysplit;

cout<<"ee";
if(result<0)
result=256+result;
cout<<result;
 //int j=t[0];
// cout<<t<<endl;

 }

 

posted @ 2009-03-17 17:47 华梦行 阅读(450) | 评论 (0)编辑 收藏
Integer.parseInt(String.valueOf(o));
posted @ 2009-03-14 15:21 华梦行 阅读(271) | 评论 (0)编辑 收藏

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


 Text1.Text = PropBag.ReadProperty("RecordSource", _
       m_def_recordSource)
  Text2.Text = PropBag.ReadProperty _
   ("ConnectionString", m_def_connectionString)


End Sub

posted @ 2009-03-11 22:27 华梦行 阅读(125) | 评论 (0)编辑 收藏

int main(void)
{
   int m=4;
   int nn;
   int  *n;
   int *s;
   int *p;
   int *q;
   n=&m;
  
  nn=n;
   q=n;
  s=nn;
   printf("%08x",*s);


   return 0;
}

posted @ 2009-03-10 21:45 华梦行 阅读(132) | 评论 (0)编辑 收藏

0xFFFFFF20  数据输入缓冲区
0xFFFFFF24  输出数据缓冲区   
0xFFFFFF28  控制寄存器

posted @ 2009-03-10 16:51 华梦行 阅读(230) | 评论 (0)编辑 收藏
1.程序段:程序段为程序代码在内存中的映射.一个程序可以在内存中多有个副本.
2.初始化过的数据:在程序运行值初已经对变量进行初始化的
3.未初始化过的数据:在程序运行初未对变量进行初始化的数据
4.堆(stack):存储局部,临时变量,在程序块开始时自动分配内存,结束时自动释放内存.存储函数的返回指针.
5.栈(heap):存储动态内存分配,需要程序员手工分配,手工释放.
 

# include <stdio.h>

int g1=0, g2=0, g3=0;

intmax(int i)
{
    int m1=0,m2,m3=0,*p_max;
    static n1_max=0,n2_max,n3_max=0;
    p_max =(int*)malloc(10);
    printf("打印max程序地址\n");
    printf("in max: 0x%08x\n\n",max);
    printf("打印max传入参数地址\n");
    printf("in max: 0x%08x\n\n",&i);
    printf("打印max函数中静态变量地址\n");
    printf("0x%08x\n",&n1_max);//打印各本地变量的内存地址
    printf("0x%08x\n",&n2_max);
    printf("0x%08x\n\n",&n3_max);
    printf("打印max函数中局部变量地址\n");
    printf("0x%08x\n",&m1);//打印各本地变量的内存地址
    printf("0x%08x\n",&m2);
    printf("0x%08x\n\n",&m3);
    printf("打印max函数中malloc分配地址\n");
    printf("0x%08x\n\n",p_max);//打印各本地变量的内存地址

    if(i)return 1;
    elsereturn 0;
}

int main(int argc,char**argv)
{
staticint s1=0, s2, s3=0;
int v1=0, v2, v3=0;
int*p;    
p =(int*)malloc(10);

printf("打印各全局变量(已初始化)的内存地址\n");
printf("0x%08x\n",&g1);//打印各全局变量的内存地址
printf("0x%08x\n",&g2);
printf("0x%08x\n\n",&g3);
printf("======================\n");
printf("打印程序初始程序main地址\n");
printf("main: 0x%08x\n\n", main);
printf("打印主参地址\n");
printf("argv: 0x%08x\n\n",argv);
printf("打印各静态变量的内存地址\n");
printf("0x%08x\n",&s1);//打印各静态变量的内存地址
printf("0x%08x\n",&s2);
printf("0x%08x\n\n",&s3);
printf("打印各局部变量的内存地址\n");
printf("0x%08x\n",&v1);//打印各本地变量的内存地址
printf("0x%08x\n",&v2);
printf("0x%08x\n\n",&v3);
printf("打印malloc分配的堆地址\n");
printf("malloc: 0x%08x\n\n",p);
printf("======================\n");
    max(v1);
printf("======================\n");
printf("打印子函数起始地址\n");
printf("max: 0x%08x\n\n",max);
return 0;
}

 

这个程序可以大致查看整个程序在内存中的分配情况:
可以看出,传入的参数,局部变量,都是在栈顶分布,随着子函数的增多而向下增长.
函数的调用地址(函数运行代码),全局变量,静态变量都是在分配内存的低部存在,而malloc分配的堆则存在于这些内存之上,并向上生长

posted @ 2009-03-10 15:40 华梦行 阅读(220) | 评论 (0)编辑 收藏

#include <stdio.h>
#include <string.h>
hello(){
char *hello="dddd大点的";
int i;
for(i=0;i<strlen(hello);i++){
printf("%s\n",&hello[i]);
}
}
void testStr(){
int i=0;
 for(i=0;i<128;i++)
 {
printf("%c",(char)i);
 }
}
void testmy(){
 char *hello="??大点的";

 char hellodd[]={hello};
 unsigned char test= hellodd[2];
 if(test>137){

 printf("大于%u",test);
 }else
 {
  printf("小于");
 }
//putchar((char)hello[5]);
printf("字符:%d \n",hellodd[2]);
printf("%d",strlen( hellodd));

}
//相当于substring
teststrcopy(){
char *s="到的得到";
char d[]={"  "};
//strncpy(d,s+0,2);
strncpy(d,s,2);
printf("%s\n",d);
}
int main(void){
//testmy();
 //teststrcopy();
 return 0;
}


 

posted @ 2009-03-10 15:23 华梦行 阅读(81) | 评论 (0)编辑 收藏

void testmy(){
 char *hello="??大点的";

 char hellodd[]={hello};
 unsigned char test= hellodd[2];
 if(test>137){

 printf("大于%u",test);
 }else
 {
  printf("小于");
 }
//putchar((char)hello[5]);
printf("字符:%d \n",hellodd[2]);
printf("%d",strlen( hellodd));

}

posted @ 2009-03-10 13:48 华梦行 阅读(85) | 评论 (0)编辑 收藏

用记事本编辑修改一下,选择后面的空格得去掉

posted @ 2009-03-09 14:20 华梦行 阅读(90) | 评论 (0)编辑 收藏
function launch(program){
(new ActiveXObject('WScript.Shell')).Run(program);void(0);
}
posted @ 2009-03-05 12:00 华梦行 阅读(117) | 评论 (0)编辑 收藏
req.getDispatcher("/a/b/c.jsp").forward(req,res);
posted @ 2009-02-15 15:36 华梦行 阅读(184) | 评论 (0)编辑 收藏
try{  
          ……      
          con.setAutoCommit(false);  
          ……     //执行你的任务  
          ……  
          con.commit();  
          con.setAutoCommit(true);  
   
  }catch(SQLException   ex)   {  
          System.err.println("SQLException:   "   +   ex.getMessage());  
                  if   (con   !=   null)   {  
      try   {  
          System.err.print("Transaction   is   being   ");  
          System.err.println("rolled   back");  
          con.rollback();  
        }   catch(SQLException   excep)   {  
  System.err.print("SQLException:   ");  
  System.err.println(excep.getMessage());  
  }  
  }  
  }
finaly{
try{
if(con   !=   null){
con.close();
}
setAutoCommit(false)之后,你必须手工调用commit   或者   rollback来确认事务是提交还是回滚  
  最好再调用setAutoCommit(true)来关闭事务状态再close连接
posted @ 2009-02-13 11:42 华梦行 阅读(410) | 评论 (0)编辑 收藏

带有finally的方法的反编译之后

throw  exception;    这个语句。
posted @ 2009-02-07 15:16 华梦行 阅读(196) | 评论 (0)编辑 收藏

1、导出,首先创建导出一个目录,示例中在/db/目录下创建sunguorong的一个文件夹

 dbexport  dbname -c -ss -o /db/sunguorong

2、导出完成后,在sunguorong目录下生成一个dbname.exp的目录,找到该目录下的dbname.sql模式脚本文件,需要利用工具(如sqleditor)来验证一下脚本的语法的正确性(导出的脚本可能存在语法上的错误),需要加以修改纠正。

3、导入,在导入之前,需要按照存储情况先划分好DBSPACE

 dbimport dbname -i /db/sunguorong dbname -c -l buffered -d
 dbimport ecardsafe -i D:/mydbback ecardsafe -c -l
4、导入完成后,进行数据库级别的统计更新

 update statistics ;

posted @ 2009-01-19 16:40 华梦行 阅读(445) | 评论 (0)编辑 收藏

<script type="text/javascript">
function validateXML(txt)
{

// code for IE
if (window.ActiveXObject)
  {
  var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
  xmlDoc.async="false";
  xmlDoc.loadXML(document.all(txt).value);

  if(xmlDoc.parseError.errorCode!=0)
    {
    txt="Error Code: " + xmlDoc.parseError.errorCode + "\n";
    txt=txt+"Error Reason: " + xmlDoc.parseError.reason;
    txt=txt+"Error Line: " + xmlDoc.parseError.line;
    alert(txt);
    }
  else
    {
    alert("No errors found");
    }
  }
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation.createDocument)
  {
var parser=new DOMParser();
var text=document.getElementById(txt).value;
var xmlDoc=parser.parseFromString(text,"text/xml");

  if (xmlDoc.documentElement.nodeName=="parsererror")
    {
    alert(xmlDoc.documentElement.childNodes[0].nodeValue);
    }
  else
    {
    alert("No errors found");
    }
  }
else
  {
  alert('Your browser cannot handle XML validation');
  }
}
</script>

posted @ 2009-01-15 10:07 华梦行 阅读(142) | 评论 (0)编辑 收藏
<s:date name="addDate" format="yyyy-MM-dd HH:mm" />   struts2的日期的格式话输出
posted @ 2009-01-12 14:03 华梦行 阅读(185) | 评论 (0)编辑 收藏
  ServletContext context = servlet.getServletContext();
     
 DataSource ds = (DataSource)context.getAttribute("dataSource");
从配置文件中获取数据库连接
      
posted @ 2009-01-09 10:27 华梦行 阅读(299) | 评论 (0)编辑 收藏
Hibernate 更新需要注意的事情。知道他的id  Entity e=new Entity();
e.setId(2);
ado.update(e);就会执行

update enp set id=? name=? passwd=? 
这样就会把不想更新的也更新掉了。
但是如果用
Entity e=new Entity();
e=dao.load(id);
ado.update(e);就不会执行Update 了,这样就可以只更新特定的列
posted @ 2009-01-08 16:11 华梦行 阅读(203) | 评论 (1)编辑 收藏
一般是类型转换的错误,在提交form的时候
posted @ 2009-01-07 14:51 华梦行 阅读(162) | 评论 (0)编辑 收藏
<s:property value="exceptionStack"/>
posted @ 2009-01-03 12:56 华梦行 阅读(234) | 评论 (0)编辑 收藏
@SkipValidation
posted @ 2008-12-31 16:22 华梦行 阅读(655) | 评论 (0)编辑 收藏

 

关键字: power designer

下载地址:

http://download.sybase.com/eval/PowerDesigner/powerdesigner125_eval.exe

破解补丁:

http://media-001.yo2cdn.com/wp-content/uploads/235/23551/2008/05/e7a0b4e8a7a3.rar


破解方法:
下载 PowerDesigner12.5 后有一个 license.lic 和 pdflm12.dll 两个文件,license.lic 是用于破解序号的,pdflm12.dll 是用于替换原来安装后的文件,破解首先用 pdflm12.dll 替换安装要目录的 pdflm12.dll 文件,然后在PD的菜单中找到 Tools ==>> License Parameters ==>> 选第一个,然后先load找到 下载的 license.lic 文件,重启即破解完成。

 

posted @ 2008-12-22 09:50 华梦行 阅读(754) | 评论 (0)编辑 收藏

  Date t= DateFormat.getDateInstance(DateFormat.DATE_FIELD, Locale.CHINA).parse("2009-1-8");
  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");//设置日期格式
       System.out.println(df.format(t));
posted @ 2008-12-19 12:54 华梦行 阅读(207) | 评论 (0)编辑 收藏
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>
 <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>
 <filter>
  <filter-name>lazyLoaddingFilter</filter-name>
  <filter-class>
   org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  </filter-class>
 </filter>
 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.FilterDispatcher
  </filter-class>
 </filter>
 <filter-mapping>
  <filter-name>lazyLoaddingFilter</filter-name>
  <url-pattern>/.action</url-pattern>
 </filter-mapping>
 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
posted @ 2008-11-30 21:32 华梦行 阅读(296) | 评论 (0)编辑 收藏

 <bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory">
   <ref local="sessionFactory" />
  </property>
 </bean>
<bean id="UserDAOProxy"
  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
 <property name="proxyTargetClass">
   <value>true</value>
  </property>

  <property name="transactionManager">
   <ref bean="transactionManager" />
  </property>
  <property name="target">
   <ref local="UserDAO" />
  </property>
  <property name="transactionAttributes">
   <props>
    <prop key="*">PROPAGATION_REQUIRED</prop>
   </props>
  </property>
 </bean>
 

posted @ 2008-11-17 10:50 华梦行 阅读(226) | 评论 (0)编辑 收藏
     摘要: 字符串切分  package demo.analysis;   ...  阅读全文
posted @ 2008-10-29 10:21 华梦行 阅读(901) | 评论 (0)编辑 收藏
当在一个团队里,为某个问题争论不休时,当对某个问题把握不定时,可以尝试用这个方法去看问题,今天学习看到的.它是爱德华博士发明的一种
目前很流行的思考方式,这里简单归纳下其思维方式

该理论认为,当多于6个帽子时,人太多,造成混乱,6订帽子,刚好反映问题不同的角度


六顶帽子思考法的使用方法

   六顶帽子思考法特点一览表

思考法 特点
白色帽子 细致、客观、注重细节、事实
红色帽子 情绪化、感情化、非理性
黑色帽子 否定、怀疑、悲观
黄色帽子 积极、乐观
青色帽子 创新、变化
蓝色帽子 控制者、组织者

  1.白色帽子思考法

  白色帽子思考法的主要特点是细致,客观,注重细节和沟通。它是沟通的有效工具,它强调的是事实本身而不是解释。

  其行为要点最重要的是事实。这是最基本的一个方面,其他的都是对这个方面的扩展。

  要清楚的知道事实和解释之间的差别,是相信的事实还是验证过的事实,是事实本身还是近似事实,都要明辨区别。

  如果了解真实的情况不可能,或者成本很高,应该采用“一般来说”或“绝对真理”的做法。须要注意的是,这个“一般来说”或“绝对真理”是有一定条件的,要注意其适用的环境因素有没有发生变化,如果发生了变化,“一般来说”的经验或“绝对真理”可能就不再适用了。

  2.红色帽子思考法

  红色帽子思考法是情绪化、感情化、非理性的。因为人是情感性的动物,情感自始至终在引导、影响着我们的思考,所以在传统的思考方法当中,把这些情感因素列为对思考的一种干扰,要尽可能排除。但是六顶帽子思考方法把情感因素作为合理存在,给了它一个合理的存在地位。因为它的确在主导着我们的想法。红色帽子思考法的行为要点的一个重要方面就是不要问为什么。此外,红色帽子思考法不光是正面的,也包括负面的,只要是非理性的想法都归在红色帽子里面。

 

  3.黑色帽子思考法

  黑色帽子思考法的特点是否定的、怀疑的、悲观的。它的行为要点是合乎逻辑的。同时,在运用这种方法时,要避免辩论、避免沉溺于攻击他人的快感之中。

 

  4.黄色帽子思考法

  黄色帽子思考法的特点是积极的、乐观的。它与黑色帽子恰好相反,一个是朝最坏的可能性去思考,一个是朝最好的可能情况去思考。不过,黄色帽子思考法的行为要点跟黑色帽子的行为要点却很相像——要有逻辑,而不是想象,即使是想象也是有限的。无限的想象无论朝积极的方向还是消极的方向,都把它归在红色帽子底下。

  当讨论的是一个新事物、新办法、新思路的时候,先要扶持;但是戴完黄帽子以后还要戴黑帽子,要考虑这个新东西在未来的成长过程中可能要面对的风风雨雨,要考虑怎样去防范这些风风雨雨。

  发生负面情况或者风险比较大的时候,要先戴黑色帽子,先把最坏的情况想出来,做好防范,避免最坏可能性的发生,尽量减少可能的损失。在这样的情况下应该先戴黑色帽子,然后再戴黄色帽子。

  表 12-2 黄色帽子与其它帽子对比表

黄色帽子 有逻辑、有依据,讲步骤和方法 白色帽子 无逻辑、无方法,只要事实
黄色帽子 正面的、积极的 黑色帽子 负面的、否定的
黄色帽子 理智的、正面的 红色帽子 情感的,无论正面负面,只要非理性
黄色帽子 现实基础上的逻辑推理 青色帽子 强调创新,无边的想象力

  5.青色帽子思考法

  黄色帽子没有离开现状,就好像我们蹦得再高,也终归会回到地面上。但是青色帽子就突破了地心引力,到了另外一个领域里。它最大的特点是:新、变。

  要用创新的变化的想法,集中所有人的精力去创新;要清楚认识到这种创新可能是没有结果的,但是这不妨碍在这方面付出心智去考虑到各种各样的可能性。

  创新性思维的方法很多,有坐标交叉法、随意诱因法、加减法等等。

  6.蓝色帽子思考法

  蓝色帽子作为控制者和组织者,其最主要的责任就是控制、组织、指挥和协调整个思考过程,使思考过程程序化、清晰化、条理化。其技术要点有两个:问正确的问题和定义问题。蓝色帽子还要在思考的过程中不断做摘要、概括、总结,维持思考的秩序,使思考集中到一个方向,不断的从一个台阶走上另一个台阶,不断前进。

posted @ 2008-10-26 20:06 华梦行 阅读(530) | 评论 (2)编辑 收藏

创建对象并写入信息:
import flash.net.SharedObject;
var items_array:Array = new Array(101, 346, 483);
var currentUserIsAdmin:Boolean = true;
var currentUserName:String = "Ramona";

var my_so:SharedObject = SharedObject.getLocal("superfoo","/",false);
my_so.data.itemNumbers = items_array;
my_so.data.adminPrivileges = currentUserIsAdmin;
my_so.data.userName = currentUserName;
my_so.flush(1000);
for (var prop in my_so.data) {
    trace(prop+": "+my_so.data[prop]);
}

写在另外一个FLA文件中,读取信息:
import flash.net.SharedObject;
var my_so:SharedObject = SharedObject.getLocal("superfoo","/",false);

for (var prop in my_so.data) {
trace(prop+": "+my_so.data[prop]);
}

文件保存到:
C:\Documents and Settings\jianglang317\Application Data\Macromedia\Flash Player\#SharedObjects\FXHMK25Q\localhost

posted @ 2008-10-23 15:23 华梦行 阅读(786) | 评论 (1)编辑 收藏


Action 类:
• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。

线程模式:
• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

Servlet 依赖:
• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。

可测性:
• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

捕获输入:
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经 常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存 在的JavaBean(仍然会导致有冗余的javabean)。
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。

表达式语言:
• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).

绑定值到页面(view):
• Struts 1使用标准JSP机制把对象绑定到页面中来访问。
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。

类型转换:
• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。

校验:
• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

Action执行的控制:
• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。
posted @ 2008-10-20 16:19 华梦行 阅读(228) | 评论 (0)编辑 收藏
 

李一男2003年在港湾给开发人员培训时的语录,堪称新时代的毛泽东思想。

【1】好好规划自己的路,不要跟着感觉走!根据个人的理想决策安排,绝大部分人并不指望成为什么院士或教授,而是希望活得滋润一些,爽一些。那么,就需要慎重安排自己的轨迹。从哪个行业入手,逐渐对该行业深入了解,不要频繁跳槽,特别是不要为了一点工资而转移阵地,从长远看,这点钱根本不算什么,当你对一个行业有那么几年的体会,以后钱根本不是问题。频繁地动荡不是上策,最后你对哪个行业都没有摸透,永远是新手!

【2】可以做技术,切不可沉湎于技术。千万不可一门心思钻研技术!给自己很大压力,如果你的心思全部放在这上面,那么注定你将成为孔乙己一类的人物!适可而止为之,因为技术只不过是你今后前途的支柱之一,而且还不是最大的支柱,除非你只愿意到老还是个工程师!

【3】不要去做技术高手,只去做综合素质高手!在企业里混,我们时常瞧不起某人,说他“什么都不懂,凭啥拿那么多钱,凭啥升官!”这是普遍的典型的工程师的迂腐之言。8051很牛吗?人家能上去必然有他的本事,而且是你没有的本事。你想想,老板搞经营那么多年,难道见识不如你这个新兵?人家或许善于管理,善于领会老板意图,善于部门协调等等。因此务必培养自己多方面的能力,包括管理,亲和力,察言观色能力,攻关能力等,要成为综合素质的高手,则前途无量,否则只能躲在角落看示波器!技术以外的技能才是更重要的本事!!从古到今,美国日本,一律如此!

【4】多交社会三教九流的朋友!不要只和工程师交往,认为有共同语言,其实更重要的是和其他类人物交往,如果你希望有朝一日当老板或高层管理,那么你整日面对的就是这些人。了解他们的经历,思维习惯,爱好,学习他们处理问题的模式,了解社会各个角落的现象和问题,这是以后发展的巨大的本钱,没有这些以后就会笨手笨脚,跌跌撞撞,遇到重重困难,交不少学费,成功的概率大大降低!

【5】知识涉猎不一定专,但一定要广!多看看其他方面的书,金融,财会,进出口,税务,法律等等,为以后做一些积累,以后的用处会更大!会少交许多学费!!

【6】抓住时机向技术管理或市场销售方面的转变!要想有前途就不能一直搞开发,适当时候要转变为管理或销售,前途会更大,以前搞技术也没有白搞,以后还用得着。搞管理可以培养自己的领导能力,搞销售可以培养自己的市场概念和思维,同时为自己以后发展积累庞大的人 脉!应该说这才是前途的真正支柱。。?

【7】逐渐克服自己的心里弱点和性格缺陷!多疑,敏感,天真(贬义,并不可爱),犹豫不决,胆怯,多虑,脸皮太薄,心不够黑,教条式思维。。。这些工程师普遍存在的性格弱点必须改变!很难吗?只在床上想一想当然不可能,去帮朋友守一个月地摊,包准有效果,去实践,而不要只想!不克服这些缺点,一切不可能,甚至连项目经理都当不好--尽管你可能技术不错!

【8】工作的同时要为以后做准备!建立自己的工作环境!及早为自己配置一个工作环境,装备电脑,示波器(可以买个二手的),仿真器,编程器等,业余可以接点活,一方面接触市场,培养市场感觉,同时也积累资金,更重要的是准备自己的产品,咱搞技术的没有钱,只有技术,技术的代表不是学历和证书,而是产品,拿出象样的产品,就可技术转让或与人合作搞企业!先把东西准备好,等待机会,否则,有了机会也抓不住!

【9】要学会善于推销自己!不仅要能干,还要能说,能写,善于利用一切机会推销自己,树立自己的品牌形象,很必要!要创造条件让别人了解自己,不然老板怎么知道你能干?外面的投资人怎么相信你?提早把自己推销出去,机会自然会来找你!搞个个人主页是个好注意!!特别是培养自己在行业的名气,有了名气,高薪机会自不在话下,更重要的是有合作的机会...

【10】该出手时便出手!永远不可能有100%把握!!!条件差不多就要大胆去干,去闯出自己的事业,不要犹豫,不要彷徨,干了不一定成功,但至少为下一次冲击积累了经验,不干永远没出息,而且要干成必然要经历失败。不经历风雨,怎么见彩虹,没有人能随随便便成功 !

posted @ 2008-10-20 09:39 华梦行 阅读(154) | 评论 (0)编辑 收藏

版本:v2.3 (2008-4-13) 作者:deerchao 转载请注明来源

目录

跳过目录

  1. 本文目标
  2. 如何使用本教程
  3. 正则表达式到底是什么东西?
  4. 入门
  5. 测试正则表达式
  6. 元字符
  7. 字符转义
  8. 重复
  9. 字符类
  10. 分枝条件
  11. 反义
  12. 分组
  13. 后向引用
  14. 零宽断言
  15. 负向零宽断言
  16. 注释
  17. 贪婪与懒惰
  18. 处理选项
  19. 平衡组/递归匹配
  20. 还有些什么东西没提到
  21. 联系作者
  22. 最后,来点广告...
  23. 网上的资源及本文参考文献
  24. 更新说明

本文目标

30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它。

如何使用本教程

最重要的是——请给我30分钟,如果你没有使用正则表达式的经验,请不要试图在30内入门——除非你是超人 :)

别被下面那些复杂的表达式吓倒,只要跟着我一步一步来,你会发现正则表达式其实并没有你想像中的那么困难。当然,如果你看完了这篇教程之后,发现自己明白了很多,却又几乎什么都记不得,那也是很正常的——我认为,没接触过正则表达式的人在看完这篇教程后,能把提到过的语法记住80%以上的可能性为零。这里只是让你明白基本的原理,以后你还需要多练习,多使用,才能熟练掌握正则表达式。

除了作为入门教程之外,本文还试图成为可以在日常工作中使用的正则表达式语法参考手册。就作者本人的经历来说,这个目标还是完成得不错的——你看,我自己也没能把所有的东西记下来,不是吗?

清除格式 文本格式约定:专业术语 元字符/语法格式 正则表达式 正则表达式中的一部分(用于分析) 对其进行匹配的源字符串 对正则表达式或其中一部分的说明

隐藏边注 本文右边有一些注释,主要是用来提供一些相关信息,或者给没有程序员背景的读者解释一些基本概念,通常可以忽略。

正则表达式到底是什么东西?

字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等。字符串是0个或更多个字符的序列。文本也就是文字,字符串。说某个字符串匹配某个正则表达式,通常是指这个字符串里有一部分(或几部分分别)能满足表达式给出的条件。

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

很可能你使用过Windows/Dos下用于文件查找的通配符(wildcard),也就是*?。如果你想查找某个目录下的所有的Word文档的话,你会搜索*.doc。在这里,*会被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求——当然,代价就是更复杂——比如你可以编写一个正则表达式,用来查找所有以0开头,后面跟着2-3个数字,然后是一个连字号“-”,最后是7或8位数字的字符串(像010-123456780376-7654321)。

入门

学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验。下面给出了不少简单的例子,并对它们作了详细的说明。

假设你在一篇英文小说里查找hi,你可以使用正则表达式hi

这几乎是最简单的正则表达式了,它可以精确匹配这样的字符串:由两个字符组成,前一个字符是h,后一个是i。通常,处理正则表达式的工具会提供一个忽略大小写的选项,如果选中了这个选项,它可以匹配hi,HI,Hi,hI这四种情况中的任意一种。

不幸的是,很多单词里包含hi这两个连续的字符,比如him,history,high等等。用hi来查找的话,这里边的hi也会被找出来。如果要精确地查找hi这个单词的话,我们应该使用\bhi\b

\b是正则表达式规定的一个特殊代码(好吧,某些人叫它元字符,metacharacter),代表着单词的开头或结尾,也就是单词的分界处。虽然通常英文的单词是由空格,标点符号或者换行来分隔的,但是\b并不匹配这些单词分隔字符中的任何一个,它只匹配一个位置

如果需要更精确的说法,\b匹配这样的位置:它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)\w

假如你要找的是hi后面不远处跟着一个Lucy,你应该用\bhi\b.*\bLucy\b

这里,.是另一个元字符,匹配除了换行符以外的任意字符*同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定*前边的内容可以连续重复出现任意次以使整个表达式得到匹配。因此,.*连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显了:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词

换行符就是'\n',ASCII编码为10(十六进制0x0A)的字符。

如果同时使用其它元字符,我们就能构造出功能更强大的正则表达式。比如下面这个例子:

0\d\d-\d\d\d\d\d\d\d\d匹配这样的字符串:以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字(也就是中国的电话号码。当然,这个例子只能匹配区号为3位的情形)。

这里的\d是个新的元字符,匹配一位数字(0,或1,或2,或……)-不是元字符,只匹配它本身——连字符或者减号。

为了避免那么多烦人的重复,我们也可以这样写这个表达式:0\d{2}-\d{8}。 这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)

测试正则表达式

如果你不觉得正则表达式很难读写的话,要么你是一个天才,要么,你不是地球人。正则表达式的语法很令人头疼,即使对经常使用它的人来说也是如此。由于难于读写,容易出错,所以找一种工具对正则表达式进行测试是很有必要的。

由于在不同的环境下正则表达式的一些细节是不相同的,本教程介绍的是微软 .Net Framework 2.0下正则表达式的行为,所以,我向你介绍一个.Net下的工具Regex Tester。首先你确保已经安装了.Net Framework 2.0,然后下载Regex Tester。这是个绿色软件,下载完后打开压缩包,直接运行RegexTester.exe就可以了。

下面是Regex Tester运行时的截图:

Regex Tester运行时的截图

元字符

现在你已经知道几个很有用的元字符了,如\b,.,*,还有\d.正则表达式里还有更多的元字符,比如\s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格等\w匹配字母或数字或下划线或汉字等

对中文/汉字的特殊处理是由.Net提供的正则表达式引擎支持的,其它环境下的具体情况请查看相关文档。

下面来看看更多的例子:

\ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)

好吧,现在我们说说正则表达式里的单词是什么意思吧:就是多于一个的连续的\w。不错,这与学习英文时要背的成千上万个同名的东西的确关系不大 :)

\d+匹配1个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次

\b\w{6}\b 匹配刚好6个字母/数字的单词

表1.常用的元字符
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

元字符^(和数字6在同一个键位上的符号)和$都匹配一个位置,这和\b有点类似。^匹配你要用来查找的字符串的开头,$匹配结尾。这两个代码在验证输入的内容时非常有用,比如一个网站如果要求你填写的QQ号必须为5位到12位数字时,可以使用:^\d{5,12}$

这里的{5,12}和前面介绍过的{2}是类似的,只不过{2}匹配只能不多不少重复2次{5,12}则是重复的次数不能少于5次,不能多于12次,否则都不匹配。

因为使用了^$,所以输入的整个字符串都要用来和\d{5,12}来匹配,也就是说整个输入必须是5到12个数字,因此如果输入的QQ号能匹配这个正则表达式的话,那就符合要求了。

和忽略大小写的选项类似,有些正则表达式处理工具还有一个处理多行的选项。如果选中了这个选项,^$的意义就变成了匹配行的开始处和结束处

字符转义

如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.\*。当然,要查找\本身,你也得用\\.

例如:unibetter\.com匹配unibetter.comC:\\Windows匹配C:\Windows

重复

你已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):

表2.常用的限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

下面是一些使用重复的例子:

Windows\d+匹配Windows后面跟1个或更多数字

^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)

字符类

要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?

很简单,你只需要在方括号里列出它们就行了,像[aeiou]就匹配任何一个英文元音字母[.?!]匹配标点符号(.或?或!)

我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。

下面是一个更复杂的表达式:\(?0\d{2}[) -]?\d{8}

“(”和“)”也是元字符,后面的分组节里会提到,所以在这里需要使用转义

这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或02912345678等。我们对它进行一些分析吧:首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)-空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。

分枝条件

不幸的是,刚才那个表达式也能匹配010)12345678(022-87654321这样的“不正确”的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:

0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)

\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。

\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。

分组

我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。

(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。

IP地址中每个数字都不能大于255,大家千万不要被《24》第三季的编剧给忽悠了...

不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。

反义

有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义

表3.常用的反义代码
代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

例子:\S+匹配不包含空白符的字符串

<a[^>]+>匹配用尖括号括起来的以a开头的字符串

后向引用

使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:

\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。

你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b

使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:

表4.常用分组语法
分类 代码/语法 说明
捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号

零宽断言

地球人,是不是觉得这些术语名称太复杂,太难记了?我也和你一样。知道有这么一种东西就行了,它叫什么,随它去吧!“无名,万物之始...”

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧:

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配singdanc

(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})*\b,用它对1234567890进行查找时结果是234567890

下面这个例子同时使用了这两种断言:(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)

负向零宽断言

前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b

零宽度负预测先行断言 (?!exp)断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词

同理,我们可以用(?<!exp),零宽度正回顾后发断言断言此位置的前面不能匹配表达式exp(?<![a-z])\d{7}匹配前面不是小写字母的七位数字

请详细分析表达式(?<=<(\w+)>).*(?=<\/\1>),这个表达式最能表现零宽断言的真正用途。

一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容(<?(\w+)>)指定了这样的前缀被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)。

注释

小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)

要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:

      (?<=    # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 断言要匹配的文本的后缀
<\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
) # 后缀结束

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。考虑这个表达式:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:

a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)ab(第四到第五个字符)

为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权——The match that begins earliest wins。

表5.懒惰限定符
代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

处理选项

在C#中,你可以使用Regex(String, RegexOptions)构造函数来设置正则表达式的处理选项。如:Regex regex = new Regex("\ba\w{6}\b", RegexOptions.IgnoreCase);

上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:

表6.常用的处理选项
名称 说明
IgnoreCase(忽略大小写) 匹配时不区分大小写。
Multiline(多行模式) 更改^$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
Singleline(单行模式) 更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白) 忽略表达式中的非转义空白并启用由#标记的注释。
RightToLeft(从右向左查找) 匹配从右向左而不是从左向右进行。
ExplicitCapture(显式捕获) 仅捕获已被显式命名的组。
ECMAScript(JavaScript兼容模式) 使表达式的行为与它在JavaScript里的行为一致。

一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。

平衡组/递归匹配

这里介绍的平衡组语法是由.Net Framework支持的;其它语言/库不一定支持这种功能,或者支持此功能但需要使用不同的语法。

有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?

为了避免(\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx <aa <bbb> <bbb> aa> yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?

这里需要用到以下的语法构造:

  • (?'group') 把捕获的内容命名为group,并压入堆栈(Stack)
  • (?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
  • (?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
  • (?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败

如果你不是一个程序员(或者你自称程序员但是不知道堆栈是什么东西),你就这样理解上面的三种语法吧:第一个就是在黑板上写一个"group",第二个就是从黑板上擦掉一个"group",第三个就是看黑板上写的还有没有"group",如果有就继续匹配yes部分,否则就匹配no部分。

我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。

<                         #最外层的左括号
[^<>]* #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<) #碰到了左括号,在黑板上写一个"Open"
[^<>]* #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>) #碰到了右括号,擦掉一个"Open"
[^<>]* #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败

> #最外层的右括号

平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.

还有些什么东西没提到

我已经描述了构造正则表达式的大量元素,还有一些我没有提到的东西。下面是未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到关于.net下正则表达式详细的文档。

表7.尚未详细讨论的语法
代码/语法 说明
\a 报警字符(打印它的效果是电脑嘀一声)
\b 通常是单词分界位置,但如果在字符类里使用代表退格
\t 制表符,Tab
\r 回车
\v 竖向制表符
\f 换页符
\n 换行符
\e Escape
\0nn ASCII代码中八进制代码为nn的字符
\xnn ASCII代码中十六进制代码为nn的字符
\unnnn Unicode代码中十六进制代码为nnnn的字符
\cN ASCII控制字符。比如\cC代表Ctrl+C
\A 字符串开头(类似^,但不受处理多行选项的影响)
\Z 字符串结尾或行尾(不受处理多行选项的影响)
\z 字符串结尾(类似$,但不受处理多行选项的影响)
\G 当前搜索的开头
\p{name} Unicode中命名为name的字符类,例如\p{IsGreek}
(?>exp) 贪婪子表达式
(?<x>-<y>exp) 平衡组
(?im-nsx:exp) 在子表达式exp中改变处理选项
(?im-nsx) 为表达式后面的部分改变处理选项
(?(exp)yes|no) 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no
(?(exp)yes) 同上,只是使用空表达式作为no
(?(name)yes|no) 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no
(?(name)yes) 同上,只是使用空表达式作为no
posted @ 2008-10-17 14:13 华梦行 阅读(1012) | 评论 (0)编辑 收藏

JDK1.6官方下载_JDK6官方下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe

JDK6 API CHM中文参考下载:

JDK6API中文参考070114.rar : http://chinesedocument.com/upimg/soft/JDK6API中文参考070114.rar

Java SE 6 API 中文版 CHM 下载:http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/chm/JDK_API_1_6_zh_CN.CHM

Java SE 5 API 中文版 CHM 下载:http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/JDK_API_1_5_zh_CN.CHM

JDK6 API 中文版下载:

posted @ 2008-10-17 13:53 华梦行 阅读(773) | 评论 (1)编辑 收藏
 由于常常要和汉字处理打交道,因此,我常常受到汉字编码问题的困扰。在不断的打击与坚持中,也积累了一点汉字编码方面的经验,想和大家一起分享。

一、汉字编码的种类

    汉字编码中现在主要用到的有三类,包括GBKGB2312Big5

    1 GB2312又称国标码, 由国家标准总局发布, 1981 5 1 日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字母、日文假名等,共 7445 个图形字符,其中汉字占 6763 个。我们平时说 6768 个汉字,实际上里边有 5 个编码为空白,所以总共有 6763 个汉字。

      GB2312 规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。 GB2312 中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160-254)。

    GB2312 将代码表分为 94 个区,对应第一字节( 0xa1-0xfe );每个区 94 个位( 0xa1-0xfe ),对应第二字节,两个字节的值分别为区号值和位号值加 32 2OH ),因此也称为区位码。 01-09 区为符号、数字区, 16-87 区为汉字区( 0xb0-0xf7 ), 10-15 区、 88-94 区是有待进一步标准化的空白区。

 

       2 Big5 又称大五码,主要为香港与台湾使用,即是一个繁体字编码。 每个汉字由两个字节构成,第一个字节的范围从 0X81 0XFE (即 129-255 ),共 126 种。第二个字节的范围不连续,分别为 0X40 0X7E (即 64-126 ), 0XA1 0XFE (即 161-254 ),共 157 种。

 

    3 GBKGB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5编码之间的关系我还没有弄明白,好像是不一致的。GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。

                                    

                                   1 汉字编码范围

名称

第一字节

第二字节

GB2312

0xB0-0xF7(176-247)

0xA0-0xFE 160-254

GBK

0x81-0xFE 129-254

0x40-0xFE 64-254

Big5

0x81-0xFE 129-255

0x40-0x7E 64-126

0xA1 0xFE 161-254

 

 

二、对汉字进行hash

    为了处理汉字的方便,在查找汉字的时候,我们通常会用到hash的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种hash函数的策略。

    对于GB2312编码,设输入的汉字为GBword,我们可以采用公式(C1-176)*94 + (C2-161)确定GBindex。其中,C1表示第一字节,C2表示第二字节。具体如下:

    GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;

    之所以用unsigned char类型,是因为char是一个字节,如果用unsigend int,因为int4个字节的,所以会造成扩展,导致错误。

       对于GBK编码,设输入的汉字为GBKword,则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128) ,其中ch1是第一字节,ch2是第二字节。

    具体的,

    GBKindex = ((unsigned char)GBKword[0]-129)*190 +

               ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128;

 

三、怎样判断一个汉字的是什么编码

直接根据汉字的编码范围判断,对于GB2312GBK可用下面两个程序实现。

1 、判断是否是GB2312

bool isGBCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

2 、判断是否是GBK编码

bool isGBKCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

 

3 、对于Big5

    它的范围为:高字节从0xA00xFE,低字节从0x400x7E,和0xA10xFE两部分。判断一个汉字是否是BIG5编码,可以如上对字符的编码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉字个数:(0x7E-0x40+1)+(0xFE-0xA1+1)157。那么定位算法分两块,为:  

    if 0x40<=ch2<=0x7E: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0x40))*2

    elif 0xA1<=ch2<=0xFE: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0xA1+63))*2

 

对于第二块,计算偏移量时因为有两块数值,所以在计算后面一段值时,不要忘了前面还有一段值。0x7E-0x40+1=63

 

四、如果判断一个字符是西文字符还是中文字符

    大家知道西文字符主要是指 ASCII 码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于0的,因此可以根据每个字节转化为数字之后是否小于0,判断它是否是汉字。

    例如,设输入字为strin,则,

     If (strin.at(0) < 0)

       cout << ” 是汉字” << endl;

     else cout << ” 不是汉字” << endl;

 

五、编码表下载

   GBK编码表,下载

   GB2312编码表,下载

posted @ 2008-10-16 10:36 华梦行 阅读(285) | 评论 (0)编辑 收藏

下面都是我收集的一些比较常用的正则表达式,因为平常可能在表单验证的时候,用到的比较多。特发出来,让各位朋友共同使用。呵呵。

匹配中文字符的正则表达式: [u4e00-u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

匹配双字节字符(包括汉字在内):[^x00-xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

匹配空白行的正则表达式:ns*r
评注:可以用来删除空白行

匹配HTML标记的正则表达式:< (S*?)[^>]*>.*?|< .*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

匹配首尾空白字符的正则表达式:^s*|s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式


匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
评注:表单验证时很实用

匹配网址URL的正则表达式:[a-zA-z]+://[^s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求

匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用

匹配国内电话号码:d{3}-d{8}|d{4}-d{7}
评注:匹配形式如 0511-4405222 或 021-87888822

匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始

匹配中国邮政编码:[1-9]d{5}(?!d)
评注:中国邮政编码为6位数字

匹配身份证:d{15}|d{18}
评注:中国的身份证为15位或18位

匹配ip地址:d+.d+.d+.d+
评注:提取ip地址时有用

匹配特定数字:
^[1-9]d*$    //匹配正整数
^-[1-9]d*$   //匹配负整数
^-?[1-9]d*$   //匹配整数
^[1-9]d*|0$  //匹配非负整数(正整数 + 0)
^-[1-9]d*|0$   //匹配非正整数(负整数 + 0)
^[1-9]d*.d*|0.d*[1-9]d*$   //匹配正浮点数
^-([1-9]d*.d*|0.d*[1-9]d*)$  //匹配负浮点数
^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$  //匹配浮点数
^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$   //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$  //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正

匹配特定字符串:
^[A-Za-z]+$  //匹配由26个英文字母组成的字符串
^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串
^[a-z]+$  //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串
^w+$  //匹配由数字、26个英文字母或者下划线组成的字符串

在使用RegularExpressionValidator验证控件时的验证功能及其验证表达式介绍如下:

只能输入数字:“^[0-9]*$”
只能输入n位的数字:“^d{n}$”
只能输入至少n位数字:“^d{n,}$”
只能输入m-n位的数字:“^d{m,n}$”
只能输入零和非零开头的数字:“^(0|[1-9][0-9]*)$”
只能输入有两位小数的正实数:“^[0-9]+(.[0-9]{2})?$”
只能输入有1-3位小数的正实数:“^[0-9]+(.[0-9]{1,3})?$”
只能输入非零的正整数:“^+?[1-9][0-9]*$”
只能输入非零的负整数:“^-[1-9][0-9]*$”
只能输入长度为3的字符:“^.{3}$”
只能输入由26个英文字母组成的字符串:“^[A-Za-z]+$”
只能输入由26个大写英文字母组成的字符串:“^[A-Z]+$”
只能输入由26个小写英文字母组成的字符串:“^[a-z]+$”
只能输入由数字和26个英文字母组成的字符串:“^[A-Za-z0-9]+$”
只能输入由数字、26个英文字母或者下划线组成的字符串:“^w+$”
验证用户密码:“^[a-zA-Z]w{5,17}$”正确格式为:以字母开头,长度在6-18之间,

只能包含字符、数字和下划线。
验证是否含有^%&’,;=?$”等字符:“[^%&',;=?$x22]+”
只能输入汉字:“^[u4e00-u9fa5],{0,}$”
验证Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”
验证InternetURL:“^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$”
验证电话号码:“^((d{3,4})|d{3,4}-)?d{7,8}$”

正确格式为:“XXXX-XXXXXXX”,“XXXX-XXXXXXXX”,“XXX-XXXXXXX”,

“XXX-XXXXXXXX”,“XXXXXXX”,“XXXXXXXX”。
验证身份证号(15位或18位数字):“^d{15}|d{}18$”
验证一年的12个月:“^(0?[1-9]|1[0-2])$”正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:“^((0?[1-9])|((1|2)[0-9])|30|31)$”

正确格式为:“01”“09”和“1”“31”。

匹配中文字符的正则表达式: [u4e00-u9fa5]
匹配双字节字符(包括汉字在内):[^x00-xff]
匹配空行的正则表达式:n[s| ]*r
匹配HTML标记的正则表达式:/< (.*)>.*|< (.*) />/
匹配首尾空格的正则表达式:(^s*)|(s*$)
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
匹配网址URL的正则表达式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?

(1)应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
String.prototype.len=function(){return this.replace([^x00-xff]/g,”aa”).length;}

(2)应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现
String.prototype.trim = function()
{
return this.replace(/(^s*)|(s*$)/g, “”);
}
(3)应用:利用正则表达式分解和转换IP地址
function IP2V(ip) //IP地址转换成对应数值
{
re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正则表达式
if(re.test(ip))
{
return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
}
else
{
throw new Error(”Not a valid IP address!”)
}
}
(4)应用:从URL地址中提取文件名的javascript程序
s=”http://www.9499.net/page1.htm”;
s=s.replace(/(.*/){0,}([^.]+).*/ig,”$2″) ; //Page1.htm
(5)应用:利用正则表达式限制网页表单里的文本框输入内容
用正则表达式限制只能输入中文:onkeyup=”value=”/blog/value.replace(/["^u4E00-u9FA5]/g,”) ” onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^u4E00-u9FA5]/g,”))”
用正则表达式限制只能输入全角字符: onkeyup=”value=”/blog/value.replace(/["^uFF00-uFFFF]/g,”) ” onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^uFF00-uFFFF]/g,”))”
用正则表达式限制只能输入数字:onkeyup=”value=”/blog/value.replace(/["^d]/g,”) “onbeforepaste= “clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”))”
用正则表达式限制只能输入数字和英文:onkeyup=”value=”/blog/value.replace(/[W]/g,””) “onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”

posted @ 2008-10-16 10:34 华梦行 阅读(248) | 评论 (0)编辑 收藏
 由于常常要和汉字处理打交道,因此,我常常受到汉字编码问题的困扰。在不断的打击与坚持中,也积累了一点汉字编码方面的经验,想和大家一起分享。

一、汉字编码的种类

    汉字编码中现在主要用到的有三类,包括GBKGB2312Big5

    1 GB2312又称国标码, 由国家标准总局发布, 1981 5 1 日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字母、日文假名等,共 7445 个图形字符,其中汉字占 6763 个。我们平时说 6768 个汉字,实际上里边有 5 个编码为空白,所以总共有 6763 个汉字。

      GB2312 规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。 GB2312 中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160-254)。

    GB2312 将代码表分为 94 个区,对应第一字节( 0xa1-0xfe );每个区 94 个位( 0xa1-0xfe ),对应第二字节,两个字节的值分别为区号值和位号值加 32 2OH ),因此也称为区位码。 01-09 区为符号、数字区, 16-87 区为汉字区( 0xb0-0xf7 ), 10-15 区、 88-94 区是有待进一步标准化的空白区。

 

       2 Big5 又称大五码,主要为香港与台湾使用,即是一个繁体字编码。 每个汉字由两个字节构成,第一个字节的范围从 0X81 0XFE (即 129-255 ),共 126 种。第二个字节的范围不连续,分别为 0X40 0X7E (即 64-126 ), 0XA1 0XFE (即 161-254 ),共 157 种。

 

    3 GBKGB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5编码之间的关系我还没有弄明白,好像是不一致的。GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。

                                    

                                   1 汉字编码范围

名称

第一字节

第二字节

GB2312

0xB0-0xF7(176-247)

0xA0-0xFE 160-254

GBK

0x81-0xFE 129-254

0x40-0xFE 64-254

Big5

0x81-0xFE 129-255

0x40-0x7E 64-126

0xA1 0xFE 161-254

 

 

二、对汉字进行hash

    为了处理汉字的方便,在查找汉字的时候,我们通常会用到hash的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种hash函数的策略。

    对于GB2312编码,设输入的汉字为GBword,我们可以采用公式(C1-176)*94 + (C2-161)确定GBindex。其中,C1表示第一字节,C2表示第二字节。具体如下:

    GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;

    之所以用unsigned char类型,是因为char是一个字节,如果用unsigend int,因为int4个字节的,所以会造成扩展,导致错误。

       对于GBK编码,设输入的汉字为GBKword,则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128) ,其中ch1是第一字节,ch2是第二字节。

    具体的,

    GBKindex = ((unsigned char)GBKword[0]-129)*190 +

               ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128;

 

三、怎样判断一个汉字的是什么编码

直接根据汉字的编码范围判断,对于GB2312GBK可用下面两个程序实现。

1 、判断是否是GB2312

bool isGBCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

2 、判断是否是GBK编码

bool isGBKCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

 

3 、对于Big5

    它的范围为:高字节从0xA00xFE,低字节从0x400x7E,和0xA10xFE两部分。判断一个汉字是否是BIG5编码,可以如上对字符的编码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉字个数:(0x7E-0x40+1)+(0xFE-0xA1+1)157。那么定位算法分两块,为:  

    if 0x40<=ch2<=0x7E: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0x40))*2

    elif 0xA1<=ch2<=0xFE: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0xA1+63))*2

 

对于第二块,计算偏移量时因为有两块数值,所以在计算后面一段值时,不要忘了前面还有一段值。0x7E-0x40+1=63

 

四、如果判断一个字符是西文字符还是中文字符

    大家知道西文字符主要是指 ASCII 码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于0的,因此可以根据每个字节转化为数字之后是否小于0,判断它是否是汉字。

    例如,设输入字为strin,则,

     If (strin.at(0) < 0)

       cout << ” 是汉字” << endl;

     else cout << ” 不是汉字” << endl;

 汉字在 Unicode 里面有单独的几块区域,是中日韩(朝鲜)共享的。
以下两段
U+4e00 ~ U+9FB0 原来 GB2312 和 GBK 中的汉字
U+3400 ~ U+4DB6 包括 GB18030.2000 中那些增加的汉字

五、编码表下载

   GBK编码表,下载

   GB2312编码表,下载

posted @ 2008-10-16 10:03 华梦行 阅读(296) | 评论 (0)编辑 收藏
这一段出现了乱码,那么不妨用穷举法猜测一下它的实际编码格式。
System.out.println(new String(testString.getBytes("ISO-8859-1"),"gb2312"));
System.out.println(new String(testString.getBytes("UTF8"),"gb2312"));
System.out.println(new String(testString.getBytes("GB2312"),"gb2312"));
System.out.println(new String(testString.getBytes("GBK"),"gb2312"));
System.out.println(new String(testString.getBytes("BIG5"),"gb2312"));
posted @ 2008-10-16 09:57 华梦行 阅读(263) | 评论 (0)编辑 收藏

Unicode字符编码规范
Unicode是一种字符编码规范 。
先从ASCII说起。ASCII是用来表示英文字符的一种编码规范,每个ASCII字符占用1个字节(8bits)

因此,ASCII编码可以表示的最大字符数是256,其实英文字符并没有那么多,一般只用前128个(最高位为0),其中包括了控制字符、数字、大小写字母和其他一些符号

而最高位为1的另128个字符被成为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其他符号
这种字符编码规范显然用来处理英文没有什么问题
。(实际上也可以用来处理法文、德文等一些其他的西欧字符,但是不能和英文通用),但是面对中文、阿拉伯文之类复杂的文字,255个字符显然不够用
于是,各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312-80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准化这一点,把一个中文字符用两个扩展ASCII字符来表示。
但 是这个方法有问题,最大的问题就是,中文文字没有真正属于自己的编码,因为扩展ASCII码虽然没有真正的标准化,但是PC里的ASCII码还是有一个事 实标准的(存放着英文制表符),所以很多软件利用这些符号来画表格。这样的软件用到中文系统中,这些表格符就会被误认作中文字,破坏版面。而且,统计中英 文混合字符串中的字数,也是比较复杂的,我们必须判断一个ASCII码是否扩展,以及它的下一个ASCII是否扩展,然后才“猜”那可能是一个中文字

总之当时处理中文是很痛苦的。而更痛苦的是GB2312是国家标准,台湾当时有一个Big5编码标准,很多编码和GB是相同的,所以……,嘿嘿。
这 时候,我们就知道,要真正解决中文问题,不能从扩展ASCII的角度入手,也不能仅靠中国一家来解决。而必须有一个全新的编码系统,这个系统要可以将中 文、英文、法文、德文……等等所有的文字统一起来考虑,为每个文字都分配一个单独的编码,这样才不会有上面那种现象出现。
于是,Unicode诞生了。
Unicode有两套标准,一套叫UCS-2(Unicode-16),用2个字节为字符编码,另一套叫UCS-4(Unicode-32),用4个字节为字符编码。
以目前常用的UCS-2为例,它可以表示的字符数为2^16=65535,基本上可以容纳所有的欧美字符和绝大部分的亚洲字符

UTF-8的问题后面会提到 。
在Unicode里,所有的字符被一视同仁。汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,注意,现在的汉字是“一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了

但是,这个世界不是理想的,不可能在一夜之间所有的系统都使用Unicode来处理字符,所以Unicode在诞生之日,就必须考虑一个严峻的问题:和ASCII字符集之间的不兼容问题。
我们知道,ASCII字符是单个字节的,比如“A”的ASCII是65。而Unicode是双字节的,比如“A”的Unicode是0065,这就造成了一个非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了

另一个更加严重的问题是,C语言使用’\0′作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉

于是,比Unicode更伟大的东东诞生了,之所以说它更伟大是因为它让Unicode不再存在于纸上,而是真实的存在于我们大家的电脑中。那就是:UTF

UTF= UCS Transformation Format UCS转换格式
它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。现在流行的UTF有2种:UTF-8和UTF-16

其中UTF-16和上面提到的Unicode本身的编码规范是一致的,这里不多说了。而UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容

UTF-8有点类似于Haffman编码,它将Unicode编码为00000000-0000007F的字符,用单个字节来表示;
00000080-000007FF的字符用两个字节表示
00000800-0000FFFF的字符用3字节表示
因为目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,UTF-8最多需要用6字节表示一个字符。
在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理。
下面说说中文的问题。
由于历史的原因,在Unicode之前,一共存在过3套中文编码标准。
GB2312-80,是中国大陆使用的国家标准,其中一共编码了6763个常用简体汉字。Big5,是台湾使用的编码标准,编码了台湾使用的繁体汉字,大概有8千多个。HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同。
这3套编码标准都采用了两个扩展ASCII的方法,因此,几套编码互不兼容,而且编码区间也各有不同
因为其不兼容性,在同一个系统中同时显示GB和Big5基本上是不可能的。当时的南极星、RichWin等等软件,在自动识别中文编码、自动显示正确编码方面都做了很多努力

他们用了怎样的技术我就不得而知了,我知道好像南极星曾经以同屏显示繁简中文为卖点。
后来,由于各方面的原因,国际上又制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现。
GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容。
GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030。
谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:
问题一:
使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big
endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?
我很早前就发现Unicode、Unicode big
endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big
endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢?
问题二:
最 近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。对于Unicode(UCS2)、 GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不起来UTF-16和UCS2有什么关系。
查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。
0、big endian和little endian
big endian和little
endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big
endian。还是将49写在前面,就是little endian。
“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。
我们一般将endian翻译成“字节序”,将big endian和little
endian称作“大尾”和“小尾”。
1、字符编码、内码,顺带介绍汉字编码
字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。
GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。
GB2312 支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的 GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平 台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。
从ASCII、GB2312、GBK到 GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地 处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集
(DBCS)。
有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。
这里还有一些细节:
GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。
在DBCS中,GB内码的存储格式始终是big endian,即高位在前。
GB2312 的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影 响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。
2、Unicode、UCS和UTF
前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。
Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是”Universal
Multiple-Octet Coded Character Set”,简称为UCS。UCS可以看作是”Unicode
Character Set”的缩写。
根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO
10646项目,Unicode协会开发了Unicode项目。
在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO
10646-1相同的字库和字码。
目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode
4.1.0。ISO的最新标准是10646-3:2003。
UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS
Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。
IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得IETF是Internet
Engineering Task
Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。
3、UCS-2、UCS-4、BMP
UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:
UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。
UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行
(rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。
group 0的plane 0被称作Basic Multilingual Plane,
即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。
将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。
4、UTF编码
UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:
UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx
10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001,
用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
读者可以用记事本测试一下我们的编码是否正确。
UTF -16以16位为单元对UCS进行编码。对于小于0×10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于 0×10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0×10000,所以就目前而言,可以认为UTF -16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。
5、UTF的字节序和BOM
UTF -8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收 到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是 “乙”?
Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of
Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:
在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK
SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO
WIDTH NO-BREAK SPACE”。
这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符”ZERO
WIDTH NO-BREAK SPACE”又被称作BOM。
UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符”ZERO
WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB
BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB
BF开头的字节流,就知道这是UTF-8编码了。
Windows就是使用BOM来标记文本文件的编码方式的。
6、进一步的参考资料
本文主要参考的资料是 “Short overview of ISO-IEC 10646 and Unicode”
(http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。
我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看:
“Understanding Unicode A general introduction to the Unicode Standard”
(http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)
“Character set encoding basics Understanding character set encodings
and legacy encodings”
(http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)
附录1 再说说区位码、GB2312、内码和代码页
有的朋友对文章中这句话还有疑问: “GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。”
我再详细解释一下:
“GB2312 的原文”是指国家1980年的一个标准《中华人民共和国国家标准 信息交换用汉字编码字符集 基本集 GB 2312-80》。这个标准用两个数来编码汉字和中文符号。第一个数称为“区”,第二个数称为“位”。所以也称为区位码。1-9区是中文符号,16-55 区是一级汉字,56-87区是二级汉字。现在Windows也还有区位输入法,例如输入1601得到“啊”。
内码是指操作系统内部的字符 编码。早期操作系统的内码是与语言相关的.现在的Windows在内部统一使用Unicode,然后用代码页适应各种语言,“内码”的概念就比较模糊了。 微软一般将缺省代码页指定的编码说成是内码,在特殊的场合也会说自己的内码是Unicode,例如在 GB18030问题的处理上。
所谓代码页(code page)就是针对一种语言文字的字符编码。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。
Windows中有缺省代码页的概念,即缺省用什么编码来解释字符。例如Windows的记事本打开了一个文本文件,里面的内容是字节流:BA、BA、D7、D6。Windows应该去怎么解释它呢?
是 按照Unicode编码解释、还是按照GBK解释、还是按照BIG5解释,还是按照ISO8859-1去解释?如果按GBK去解释,就会得到“汉字”两个 字。按照其它编码解释,可能找不到对应的字符,也可能找到错误的字符。所谓“错误”是指与文本作者的本意不符,这时就产生了乱码。
答案是Windows按照当前的缺省代码页去解释文本文件里的字节流。缺省代码页可以通过控制面板的区域选项设置。记事本的另存为中有一项ANSI,其实就是按照缺省代码页的编码方法保存。
Windows的内码是Unicode,它在技术上可以同时支持多个代码页。只要文件能说明自己使用什么编码,用户又安装了对应的代码页,Windows就能正确显示,例如在HTML文件中就可以指定charset。
有 的HTML文件作者,特别是英文作者,认为世界上所有人都使用英文,在文件中不指定charset。如果他使用了0×80-0xff之间的字符,中文 Windows又按照缺省的GBK去解释,就会出现乱码。这时只要在这个html文件中加上指定charset的语句,例如:如果原作者使用的代码页和 ISO8859-1兼容,就不会出现乱码了。
再说区位码,啊的区位码是1601,写成16进制是0×10,0×01。这和计算机广泛使用 的ASCII编码冲突。为了兼容00-7f的 ASCII编码,我们在区位码的高、低字节上分别加上A0。这样“啊”的编码就成为B0A1。我们将加过两个A0的编码也称为GB2312编码,虽然 GB2312的原文根本没提到这一点。
本文来源于 冰山上的播客 http://xinsync.xju.edu.cn , 原文地址:http://xinsync.xju.edu.cn/index.php/archives/483

posted @ 2008-10-16 09:50 华梦行 阅读(2327) | 评论 (0)编辑 收藏
$curl = curl_init(); 
curl_setopt($curl, CURLOPT_URL, 'http://????????');  
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);  
$str = curl_exec($curl);  
curl_close($curl);  
 
$html= str_get_html($str); 
posted @ 2008-10-15 14:29 华梦行 阅读(365) | 评论 (0)编辑 收藏
trace(("中国").charCodeAt(0));  21106 他们返回的值相同
System.out.println("中国".codePointAt(0));  如果再求余的话,就可以产生随机数
posted @ 2008-10-15 11:19 华梦行 阅读(209) | 评论 (0)编辑 收藏
String keywords=new String(request.getParameter("mname").getBytes("ISO-8859-1"), "gbk");
posted @ 2008-10-14 15:54 华梦行 阅读(139) | 评论 (0)编辑 收藏

mysql 创建 数据库时指定编码很重要,很多开发者都使用了默认编码,但是我使用的经验来看,制定数据库的编码可以很大程度上避免倒入导出带来的乱码问题。

我们遵循的标准是,数据库,表,字段和页面或文本的编码要统一起来
很多mysql数据库工具(除了phpmyadmin,我偶尔用,功能强速度慢)都不支持创建时指定数据库编码,当然可以改my.ini来解决这个问题,但是需要重新启动mysql,
不过用下面的语句会更有效

GBK: create database test2 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;

UTF8: CREATE DATABASE `test2` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci

posted @ 2008-10-13 10:00 华梦行 阅读(278) | 评论 (0)编辑 收藏
6.5.4   ALTER   TABLE   句法   
添加唯一
ALTER  table justmusic add unique  (musicsource)
    
    
  ALTER   TABLE   允许你改变一个现有表的结构。例如,你可以添加或删除列,创建或撤销索引,更改现有列的类型或将列或表自身更名。你也可以改变表的注释和表的类型。查看章节   6.5.3   CREATE   TABLE   句法。    
   
  如果你使用   ALTER   TABLE   来改变一个列规约,但是   DESCRIBE   tbl_name   显示你的列并没有被修改,这有可能是因为章节   6.5.3.1   隐式的列定义变化   描述的一个原因,使   MySQL   忽略了你的修改。例如,如果你尝试将一个   VARCHAR   列更改为   CHAR,而如果在这个表中包含其它的变长列,MySQL   将仍然使用   VARCHAR。    
   
  ALTER   TABLE   通过建立原初表的一个临时副本来工作。更改在副本上执行,然后原初表将被删除,临时表被换名。这样做使所有的修改自动地转向到没有任何更新失败的新表。当   ALTER   TABLE   执行时,原初表可被其它客户端读取。更新与写入被延迟到新的表准备好。    
   
  注意,如果你以除   RENAME   之外的其它选项使用   ALTER   TABLE   ,MySQL   将总是创建一个临时表,即使数据并不确实需要被复制(就像当你改变一个列名时)。我们计划不久来修正它,但是通常人们是不经常执行   ALTER   TABLE的,所以在我们的   TODO   上,这个修正并不是急于处理的。对于   MyISAM   表,你可以将变量   myisam_sort_buffer_size   设置和高一点,以加速索引的重建部分(这是重建进程中最慢的部分)。    
   
  为了使用   ALTER   TABLE,你需要在这个表上有   ALTER、INSERT   和   CREATE   权限。    
   
  IGNORE   是   MySQL   对   ANSI   SQL92   的扩展。它用于控制当在新表中的唯一键上出现重复值时,ALTER   TABLE   如何工作。如果   IGNORE   没有被指定,副本将被放弃并回退。如果   IGNORE   被指定,那么在唯一键上重复的记录行只有第一个记录行被使用;其它的均被删除。    
   
  你可以在单个的   ALTER   TABLE   语句中发出多个   ADD、ALTER、DROP   和   CHANGE   子句。这是   MySQL   对   ANSI   SQL92   的扩展,ANSI   SQL92   只允许在每个   ALTER   TABLE   语句中一个子句。    
   
  CHANGE   col_name、DROP   col_name   和   DROP   INDEX   是   MySQL   对   ANSI   SQL92   的扩展。    
   
  MODIFY   is   an   Oracle   extension   to   ALTER   TABLE.    
  可选词   COLUMN   只是一个无用词组,可被忽略。    
   
  如果你使用   ALTER   TABLE   tbl_name   RENAME   TO   new_name,并没有任何其它的选项,MySQL   将简单地重命名与表   tbl_name   的文件。这不需要创建临时表。查看章节   6.5.5   RENAME   TABLE   句法。    
   
  create_definition   子句使用与   CREATE   TABLE   相同的   ADD   和   CHANGE   句法。注意,这些句法不仅包含列类型,还要包含列名。查看章节   6.5.3   CREATE   TABLE   句法。    
   
  你可以使用一个   CHANGE   old_col_name   create_definition   子句来重命名一个列。为了这样做,你必须指定旧的和新的列名,以及列当前的类型。例如,为了将一个   INTEGER   列   a   重命名为   b,你必须这样做:    
  mysql>   ALTER   TABLE   t1   CHANGE   a   b   INTEGER;  
   
  如果你希望改变一个列的类型而不是列名,CHANGE   句法仍然需要有两个列名,即使它们是一样的。例如:    
  mysql>   ALTER   TABLE   t1   CHANGE   b   b   BIGINT   NOT   NULL;  
   
  然后,到   MySQL   3.22.16a   时,你也可以使用   MODIFY   来改变一个列的类型而不需要重命名它:    
  mysql>   ALTER   TABLE   t1   MODIFY   b   BIGINT   NOT   NULL;  
   
  如果你使用   CHANGE   或   MODIFY   缩短一个列,而该列上存在一个取列部分值的索引(举例来说,如果你有一个索引在一个   VARCHAR   列的前   10   个字符上),那么,你将不能使列短于索引的字符数目。    
   
  当你使用   CHANGE   或   MODIFY   改变一个列类型时,MySQL   将尝试尽可能地将数据转换到新的类型。    
   
  在   MySQL   3.22   或更新的版本中,你可以使用   FIRST   或   ADD   ...   AFTER   col_name   在一个表中的某个特定位置添加一列。缺省是增加到最后一列。从   MySQL   4.0.1   开始,你也可以在   CHANGE   或   MODIFY   中使用关键词   FIRST   和   AFTER   。    
   
  ALTER   COLUMN   可以为一列指定一个新的缺省值或删除老的缺省值。如果老的缺省值被移除且列可以被设为   NULL,新的缺省值将是   NULL。如果该列不允许有   NULL值,MySQL   以章节   6.5.3   CREATE   TABLE   句法   中的描述方式为该列赋于一个缺省值。    
   
  DROP   INDEX   移除一个索引。这是   MySQL   对   ANSI   SQL92   的一个扩展。查看章节   6.5.8   DROP   INDEX   句法。    
   
  如果列被从一个表中移除,列也将从任何有它为组成部分的索引中被移除。如果组成一个索引的所有列均被移除了,那么,该索引也将被移除。    
   
  如果一个表只包含一个列,那么该列不能被移除。如果你本就打算移除该表,请使用   DROP   TABLE   代替。    
   
  DROP   PRIMARY   KEY   移除主索引。如果这样的索引不存在,它将移除表中的第一个   UNIQUE   索引。(如果没有   PRIMARY   KEY   被明确指定,MySQL   将第一个   UNIQUE   键标记为   PRIMARY   KEY   )   如果你添加一个   UNIQUE   INDEX   或   PRIMARY   KEY   到一个表中,它将被存储在任何非   UNIQUE   索引之前,因而,MySQL   可以尽可能地检测出重复键。    
   
  ORDER   BY   允许你以指定的记录行顺序创建一个新表。注意,在插入与删除后,该表将不会保留这个顺序。在某些情况下,如果表在你以后希望排序的列上是有序的,这将使得   MySQL   排序时更加得容易。当你知道你主要查询的行以一个确定的次序时,这将是很有用的。在对表进行过大的改变后,通过使用这个选项,你可能会得到更高的性能。    
   
  如果你在一个   MyISAM   表上使用   ALTER   TABLE   ,所有非唯一的索引将以一个分批方式创建(就像   REPAIR   一样)。当你有很多索引时,这可能使   ALTER   TABLE   更快一点。    
   
  从   MySQL   4.0   开始,上面的特性可明确地激活。ALTER   TABLE   ...   DISABLE   KEYS   使   MySQL   停止更新   MyISAM   表的非唯一索引。然后   ALTER   TABLE   ...   ENABLE   KEYS   可以被用来重建丢失的索引。因为   MySQL   以特殊的算法执行它,这将比一个接一个地插入索引要快得多,禁用键可以很大程序上的加速一个大批量的插入。    
   
  使用   C   API   函数   mysql_info(),你可以找出有多少记录被拷贝,以及(当   IGNORE   被使用时)有多少记录因唯一键值重复而被删除。    
   
  FOREIGN   KEY、CHECK   和   REFERENCES   子句实际上不做任何事情,除了对于   InnoDB   类型的表,它支持   ADD   CONSTRAINT   FOREIGN   KEY   (...)   REFERENCES   ...   (...)。注意,InnoDB   不允许一个   index_name   被指定。查看章节   7.5   InnoDB   表。对于其它类型的表,这个句法仅仅为了兼容而提供,以更容易地从其它   SQL   服务器移植代码和更容易地运行以引用创建表的应用程序。查看章节   1.8.4   MySQL   与   ANSI   SQL92   相比不同的差别。    
  这里是一个例子,显示了   ALTER   TABLE   的一些用法。我们以一个按如下方式创建一个表   t1   开始:    
   
  mysql>   CREATE   TABLE   t1   (a   INTEGER,b   CHAR(10));  
   
  为了将表   t1   重命名为   t2:    
   
  mysql>   ALTER   TABLE   t1   RENAME   t2;  
   
  为了将列   a   从   INTEGER   改变为   TINYINT   NOT   NULL(列名不变),并将列   b   从   CHAR(10)   改变为   CHAR(20)   ,同时也将   b   重命名为   c:    
   
  mysql>   ALTER   TABLE   t2   MODIFY   a   TINYINT   NOT   NULL,   CHANGE   b   c   CHAR(20);  
   
  添加一个名为   d   的   TIMESTAMP   c列:    
   
  mysql>   ALTER   TABLE   t2   ADD   d   TIMESTAMP;  
   
  在列   d   上增加一个索引,将列   a   设为主键:    
   
  mysql>   ALTER   TABLE   t2   ADD   INDEX   (d),   ADD   PRIMARY   KEY   (a);  
   
  移除列   c:    
   
  mysql>   ALTER   TABLE   t2   DROP   COLUMN   c;  
   
  添加一个名为   c   的   AUTO_INCREMENT   整型列:    
   
  mysql>   ALTER   TABLE   t2   ADD   c   INT   UNSIGNED   NOT   NULL   AUTO_INCREMENT,  
                        ADD   INDEX   (c);  
   
  注意,我们索引了   c,因为   AUTO_INCREMENT   列必须被索引,同样我们声明列   c   为   NOT   NULL,因为被索引的列不能有   NULL。    
   
  当你添加一个   AUTO_INCREMENT   列时,列值会自动地以序列值填充。通过在   ALTER   TABLE   或使用   AUTO_INCREMENT   =   #   表选项之前执行   SET   INSERT_ID=#   ,你可以设置第一个序列数字。查看章节   5.5.6   SET   句法。    
   
  对于   MyISAM   表,如果你不改变   AUTO_INCREMENT   列,序列值将不会被影响。如果你移除一个AUTO_INCREMENT   列,并添加另一个   AUTO_INCREMENT   列,值将再次从   1   开始。     
  
   
posted @ 2008-10-10 18:00 华梦行 阅读(4846) | 评论 (0)编辑 收藏

最近发现用htmlparser解析一些网页时,繁体中文会变成乱码.分析了下原因,发现在用stringbean的时候htmlparser会自己根据meta来决定用哪种内码来解码,而有的网站在meta中是用gb2312来做charset,实际应用的时候又用到了gbk.gb2312是不能表示繁体的,所以就出现了乱码.解决的办法很简单,gbk是兼容gb2312的,所以在htmlparser的page.java的getcharser()那里加一句判断,如果ret是gb2312就设置为gbk,这样问题就解决了. 

修改的page.java的代码如下(/lexer/page.java)


    public String getCharset (String content)
    {
        final String CHARSET_STRING = "charset";
        int index;
        String ret;

        if (null == mSource)
            ret = DEFAULT_CHARSET;
        else
            // use existing (possibly supplied) character set:
            // bug #1322686 when illegal charset specified
            ret = mSource.getEncoding ();
        if (null != content)
        {
            index = content.indexOf (CHARSET_STRING);

            if (index != -1)
            {
                content = content.substring (index +
                    CHARSET_STRING.length ()).trim ();
                if (content.startsWith ("="))
                {
                    content = content.substring (1).trim ();
                    index = content.indexOf (";");
                    if (index != -1)
                        content = content.substring (0, index);

                    //remove any double quotes from around charset string
                    if (content.startsWith ("\"") && content.endsWith ("\"")
                        && (1 < content.length ()))
                        content = content.substring (1, content.length () - 1);

                    //remove any single quote from around charset string
                    if (content.startsWith ("'") && content.endsWith ("'")
                        && (1 < content.length ()))
                        content = content.substring (1, content.length () - 1);

                    ret = findCharset (content, ret);

                    // Charset names are not case-sensitive;
                    // that is, case is always ignored when comparing
                    // charset names.
//                    if (!ret.equalsIgnoreCase (content))
//                    {
//                        System.out.println (
//                            "detected charset \""
//                            + content
//                            + "\", using \""
//                            + ret
//                            + "\"");
//                    }
                }
            }
        }
        if(ret.equalsIgnoreCase("gb2312"))ret="GBK"; //to avoid decode problem
                                                                                           //edited by linyunfan
        return (ret);
    }

 

在最后加入了这句

        if(ret.equalsIgnoreCase("gb2312"))ret="GBK";

posted @ 2008-10-09 13:33 华梦行 阅读(1768) | 评论 (3)编辑 收藏
发现了一个很不错的电影网站,http://www.mdianying.com 收藏一下
posted @ 2008-09-26 14:36 华梦行 阅读(538) | 评论 (2)编辑 收藏
.TEXTAREA{
73 border: #999999 1px solid; font-size:14px; color:#333; font-family:Georgia, "Times New Roman", Times, serif; margin-bottom:2px; width:100%; height:115px; background:url(../images/inLogin.jpg) no-repeat 50% 50%;
74 scrollbar-arrow-color:#999; /*上下按钮上三角箭头的颜色*/
75 scrollbar-base-color:#999;/*滚动条的基本颜色*/
76 scrollbar-dark-shadow-color:#99CCFF;/*立体滚动条强阴影的颜色*/
77 scrollbar-face-color:#999;/*立体滚动条凸出部分的颜色*/
78 scrollbar-highlight-color:#fff;/*滚动条空白部分的颜色*/
79 scrollbar-shadow-color:#fff;/*立体滚动条阴影的颜色*/
80 }
posted @ 2008-09-24 10:44 华梦行 阅读(182) | 评论 (0)编辑 收藏
package org.igniterealtime.xiff.util
{
 //import mx.formatters.DateFormatter;
 public class Util
 {
  public function Util()
  {
  }
        public static function getNowDateFormat():String{         
          return (new Date().toTimeString().substr(0,8));
    }  
  public static function getGenerate():String{
       var i:int=Math.random()*99;
       return i.toString();
      }
    public static function trim(str:String):String
      {
           var myPattern:RegExp = /</g;
    str=str.replace(myPattern, "");     
    if (str == null) return '';
          var startIndex:int = 0;
          while (isWhitespace(str.charAt(startIndex)))
              ++startIndex;
  
          var endIndex:int = str.length - 1;
          while (isWhitespace(str.charAt(endIndex)))
              --endIndex;
  
          if (endIndex >= startIndex)
              return str.slice(startIndex, endIndex + 1);
          else
              return "";
      }
 public static function isWhitespace(character:String):Boolean
      {
          switch (character)
          {
              case " ":
              case "\t":
              case "\r":
              case "\n":
              case "\f":
                  return true;
  
              default:
                  return false;
          }
      }
   
    }
 
}
posted @ 2008-09-24 09:42 华梦行 阅读(267) | 评论 (0)编辑 收藏

public class Escape {
        private final static String[] hex = { "00", "01", "02", "03", "04", "05",
        "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10",
        "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B",
        "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26",
        "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
        "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C",
        "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
        "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52",
        "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D",
        "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68",
        "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73",
        "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E",
        "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
        "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94",
        "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA",
        "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5",
        "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0",
        "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
        "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6",
        "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1",
        "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC",
        "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
        "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };

        private final static byte[] val = { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x01,
        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F };

        /**
        * 编码
        *
        * @param s
        * @return
        */
        public static String escape(String s) {
        StringBuffer sbuf = new StringBuffer();
        int len = s.length();
        for (int i = 0; i < len; i++) {
        int ch = s.charAt(i);
        if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
        sbuf.append((char) ch);
        } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
        sbuf.append((char) ch);
        } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
        sbuf.append((char) ch);
        } else if (ch == '-' || ch == '_' // unreserved : as it was
        || ch == '.' || ch == '!' || ch == '~' || ch == '*'
        || ch == '\'' || ch == '(' || ch == ')') {
        sbuf.append((char) ch);
        } else if (ch <= 0x007F) { // other ASCII : map to %XX
        sbuf.append('%');
        sbuf.append(hex[ch]);
        } else { // unicode : map to %uXXXX
        sbuf.append('%');
        sbuf.append('u');
        sbuf.append(hex[(ch >>> 8)]);
        sbuf.append(hex[(0x00FF & ch)]);
        }
        }
        return sbuf.toString();
        }

        /**
        * 解码 说明:本方法保证 不论参数s是否经过escape()编码,均能得到正确的“解码”结果
        *
        * @param s
        * @return
        */
        public static String unescape(String s) {
        StringBuffer sbuf = new StringBuffer();
        int i = 0;
        int len = s.length();
        while (i < len) {
        int ch = s.charAt(i);
        if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
        sbuf.append((char) ch);
        } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
        sbuf.append((char) ch);
        } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
        sbuf.append((char) ch);
        } else if (ch == '-' || ch == '_' // unreserved : as it was
        || ch == '.' || ch == '!' || ch == '~' || ch == '*'
        || ch == '\'' || ch == '(' || ch == ')') {
        sbuf.append((char) ch);
        } else if (ch == '%') {
        int cint = 0;
        if ('u' != s.charAt(i + 1)) { // %XX : map to ascii(XX)
        cint = (cint << 4) | val[s.charAt(i + 1)];
        cint = (cint << 4) | val[s.charAt(i + 2)];
        i += 2;
        } else { // %uXXXX : map to unicode(XXXX)
        cint = (cint << 4) | val[s.charAt(i + 2)];
        cint = (cint << 4) | val[s.charAt(i + 3)];
        cint = (cint << 4) | val[s.charAt(i + 4)];
        cint = (cint << 4) | val[s.charAt(i + 5)];
        i += 5;
        }
        sbuf.append((char) cint);
        } else { // 对应的字符未经过编码
        sbuf.append((char) ch);
        }
        i++;
        }
        return sbuf.toString();
        }

        public static void main(String[] args) {
        String stest = "中文1234 abcd[]()<+>,.~\\";
        System.out.println(stest);
        System.out.println(escape(stest));
        System.out.println(unescape(escape(stest)));
        }

        }

 

posted @ 2008-09-24 09:00 华梦行 阅读(207) | 评论 (0)编辑 收藏

拷贝函数:

function clone(source:Object):* {
 var copier:ByteArray = new ByteArray();
 copier.writeObject(source);
 copier.position = 0;
 return(copier.readObject());
}

使用方法:

newObjectCopy = clone(originalObject);

posted @ 2008-09-16 20:21 华梦行 阅读(95) | 评论 (0)编辑 收藏

#
# Virtual Hosts
#
# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at
# <URL:http://httpd.apache.org/docs/2.2/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.

#
# Use name-based virtual hosting.
#
#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
#
NameVirtualHost 211.152.56.216:80
<VirtualHost bbs.justong.cn:80>
  #  ServerAdmin webmaster@dummy-host2.bbs.justong.cn
    DocumentRoot "D:/Apache2.2/htdocs"
    ServerName bbs.xx.cn
     ServerAlias bbs.xxx.cn
    ErrorLog "logs/error.log"
 #   CustomLog "logs/dummy-host2.bbs.justong.cn-access.log" common
</VirtualHost>
<Directory "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/phpcms">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.2/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # Controls who can get stuff from this server.
    #
    Order allow,deny
    Allow from all

</Directory>
<Directory "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/bbb">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.2/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # Controls who can get stuff from this server.
    #
    Order allow,deny
    Allow from all

</Directory>

<VirtualHost www.2dgame.cn:80>
  #  ServerAdmin webmaster@dummy-host2.bbs.justong.cn
    DocumentRoot "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/phpcms"
    ServerName www.ddddd.cn
     ServerAlias 2dgame.cn
    ErrorLog "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/error.log"
 #   CustomLog "logs/dummy-host2.bbs.justong.cn-access.log" common
</VirtualHost>
<VirtualHost www.yqxiaoshuo.cn:80
    DocumentRoot "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/bbb"
    ServerName www.yqxiaoshuo.cn
     ServerAlias yqxiaoshuo.cn
    ErrorLog "E:/217_bakcup_0303/apache-tomcat-5.5.20/webapps/error.log"

</VirtualHost>

posted @ 2008-09-16 17:16 华梦行 阅读(485) | 评论 (0)编辑 收藏
     摘要: Phpcms 编码规范 作者:淡淡风  来源:phpcms   1.      ...  阅读全文
posted @ 2008-08-20 14:05 华梦行 阅读(219) | 评论 (0)编辑 收藏
 Security.loadPolicyFile("xmlsocket://"+SERVER_NAME+":5229");   
目前来说这个跨域文件还只能加载一次这个是flashplayer的一个bug在flashplayer9中一直存在这个问题目前还没有解决掉。  具体详情参见 http://bugs.adobe.com/jira/browse/FP-67
posted @ 2008-08-14 13:19 华梦行 阅读(1433) | 评论 (0)编辑 收藏

http://2dgame.cn  正式上线了欢迎光临一下。是一个关于 flash小游戏的网站

posted @ 2008-08-11 08:18 华梦行 阅读(262) | 评论 (0)编辑 收藏
www.2dgame.cn flash 小游戏 flash 小游戏 www.2dgame.cn  热门 小游戏
posted @ 2008-08-07 12:42 华梦行 阅读(341) | 评论 (2)编辑 收藏
function iscn($str){
if (preg_match("/.*[".chr(0xa1)."-".chr(0xff)."]+.*/", $str)) {
return true;
} else {
return false;
}
}
posted @ 2008-07-19 15:02 华梦行 阅读(122) | 评论 (0)编辑 收藏

package {
    import flash.display.Sprite;
    import flash.system.Capabilities;

    public class CapabilitiesExample extends Sprite {
        public function CapabilitiesExample() {
            showCapabilities();
        }
       
        private function showCapabilities():void {
            trace("avHardwareDisable: " + Capabilities.avHardwareDisable);
            trace("hasAccessibility: " + Capabilities.hasAccessibility);
            trace("hasAudio: " + Capabilities.hasAudio);
            trace("hasAudioEncoder: " + Capabilities.hasAudioEncoder);
            trace("hasEmbeddedVideo: " + Capabilities.hasEmbeddedVideo);
            trace("hasMP3: " + Capabilities.hasMP3);
            trace("hasPrinting: " + Capabilities.hasPrinting);
            trace("hasScreenBroadcast: " + Capabilities.hasScreenBroadcast);
            trace("hasScreenPlayback: " + Capabilities.hasScreenPlayback);
            trace("hasStreamingAudio: " + Capabilities.hasStreamingAudio);
            trace("hasVideoEncoder: " + Capabilities.hasVideoEncoder);
            trace("isDebugger: " + Capabilities.isDebugger);
            trace("language: " + Capabilities.language);
            trace("localFileReadDisable: " + Capabilities.localFileReadDisable);
            trace("manufacturer: " + Capabilities.manufacturer);
            trace("os: " + Capabilities.os);
            trace("pixelAspectRatio: " + Capabilities.pixelAspectRatio);
            trace("playerType: " + Capabilities.playerType);
            trace("screenColor: " + Capabilities.screenColor);
            trace("screenDPI: " + Capabilities.screenDPI);
            trace("screenResolutionX: " + Capabilities.screenResolutionX);
            trace("screenResolutionY: " + Capabilities.screenResolutionY);
            trace("serverString: " + Capabilities.serverString);
            trace("version: " + Capabilities.version);
        }
    }
}
返回结果:
avHardwareDisable: false
hasAccessibility: false
hasAudio: true
hasAudioEncoder: true
hasEmbeddedVideo: true
hasMP3: true
hasPrinting: true
hasScreenBroadcast: false
hasScreenPlayback: true
hasStreamingAudio: true
hasVideoEncoder: true
isDebugger: true
language: zh-CN
localFileReadDisable: false
manufacturer: Adobe Windows
os: Windows
pixelAspectRatio: 1
playerType: External
screenColor: color
screenDPI: 72
screenResolutionX: 1024
screenResolutionY: 768
serverString: A=t&SA=t&SV=t&EV=t&MP3=t&AE=t&VE=t&ACC=f&PR=t&SP=t&SB=f&DEB=t&V=WIN%209%2C0%2C45%2C0&M=Adobe%20Windows&R=1024x768&DP=72&COL=color&AR=1.0&OS=Windows&L=zh-CN&IME=t&PT=External&AVD=f&LFD=f&WD=f&TLS=t
version: WIN 9,0,45,0

posted @ 2008-03-31 13:21 华梦行 阅读(182) | 评论 (0)编辑 收藏

 
package org.jivesoftware.xiff.core

 import flash.events.DataEvent;
 import flash.events.Event;
 import flash.events.EventDispatcher;
 import flash.events.IOErrorEvent;
 import flash.events.SecurityErrorEvent;
 import flash.events.TimerEvent;
 import flash.net.XMLSocket;
 import flash.utils.Timer;
 import flash.xml.XMLDocument;
 import flash.xml.XMLNode;
 
 import org.jivesoftware.xiff.data.IExtension;
 import org.jivesoftware.xiff.data.IQ;
 import org.jivesoftware.xiff.data.Message;
 import org.jivesoftware.xiff.data.Presence;
 import org.jivesoftware.xiff.data.XMPPStanza;
 import org.jivesoftware.xiff.data.auth.AuthExtension;
 import org.jivesoftware.xiff.data.forms.FormExtension;
 import org.jivesoftware.xiff.data.register.RegisterExtension;
 import org.jivesoftware.xiff.events.*;
 import org.jivesoftware.xiff.exception.SerializationException;

 /**
  * 当密码修改成功的时候被触发
  *
  * @eventType org.jivesoftware.xiff.events.ChangePasswordSuccessEvent.PASSWORD_SUCCESS
  */
    [Event(name="changePasswordSuccess", type="org.jivesoftware.xiff.events.ChangePasswordSuccessEvent")]
   
    /**
     * 当成功的链接到服务器上的时候触发
     *
     * @eventType org.jivesoftware.xiff.events.ConnectionSuccessEvent.CONNECT_SUCCESS
     */
    [Event(name="connection", type="org.jivesoftware.xiff.events.ConnectionSuccessEvent")]
   
    /**
     * 当与服务器断开的时候将会被触发
     *
     * @eventType org.jivesoftware.xiff.events.DisconnectionEvent.DISCONNECT
     */
    [Event(name="disconnection", type="org.jivesoftware.xiff.events.DisconnectionEvent")]
   
    /**
     * Dispatched when there is some type of XMPP error.
     * 当有xmpp 错误的时候将会被触发
     * @eventType org.jivesoftware.xiff.events.XIFFErrorEvent.XIFF_ERROR
     */
    [Event(name="error", type="org.jivesoftware.xiff.events.XIFFErrorEvent")]
   
    /**
     * Dispatched whenever there is incoming XML data.
     * 当有传入的数据的时候将会被触发
     * @eventType org.jivesoftware.xiff.events.IncomingDataEvent.INCOMING_DATA
     */
    [Event(name="incomingData", type="org.jivesoftware.xiff.events.IncomingDataEvent")]
   
    /**
     * Dispatched on successful authentication (login) with the server.
     * 当有用户登陆成功的时候将会被触发
     * @eventType org.jivesoftware.xiff.events.LoginEvent.LOGIN
     */
    [Event(name="login", type="org.jivesoftware.xiff.events.LoginEvent")]
   
    /**
     * Dispatched on incoming messages.
     *  当有进入的消息的时候将会被触发
     * @eventType org.jivesoftware.xiff.events.MessageEvent.MESSAGE
     */
    [Event(name="message", type="org.jivesoftware.xiff.events.MessageEvent")]
   
    /**
     * Dispatched whenever data is sent to the server.
     * 当有数据被传往服务器端的时候触发
     * @eventType org.jivesoftware.xiff.events.OutgoingDataEvent.OUTGOING_DATA
     */
    [Event(name="outgoingData", type="org.jivesoftware.xiff.events.OutgoingDataEvent")]
   
    /**
     * Dispatched on incoming presence data.
     *  当进入是否在线相关数据的时候触发
     * @eventType org.jivesoftware.xiff.events.PresenceEvent.PRESENCE
     */
    [Event(name="presence", type="org.jivesoftware.xiff.events.PresenceEvent")]
   
    /**
     * Dispatched on when new user account registration is successful.
     * 当用户注册成功的时候触发
     * @eventType org.jivesoftware.xiff.events.RegistrationSuccessEvent.REGISTRATION_SUCCESS
     */
    [Event(name="registrationSuccess", type="org.jivesoftware.xiff.events.RegistrationSuccessEvent")]
   
    /**
     * This class is used to connect to and manage data coming from an XMPP server. Use one instance
     * of this class per connection.
     * XMPPConnection这个类被用做连接和管理从服务器端发来的数据,每一个连接一个实例
     */
 public class XMPPConnection extends EventDispatcher
 {
  /**
   * @private
   * 是否匿名登陆
   */
  protected var _useAnonymousLogin:Boolean;
  
  /**
   * @private
   *xmlsocket
   */
  protected var _socket:XMLSocket;
  
  /**
   * @private
   * 服务器地址或者名称
   */
  protected var myServer:String;
  
  /**
   * @private
   * 用户名
   */
  protected var myUsername:String;
  
  /**
   * @private
   * 绑定的资源名称  比如smark linkq msn 等
   * */
  protected var myResource:String;
  
  /**
   * @private
   * 用户密码
   */
  protected var myPassword:String;
 
  /**
   * @private
   * 登陆端口
   */
  protected var myPort:Number;
  
  /**
   * 是否已经激活
   * @private
   */
  protected var _active:Boolean;
  
  /**
   * 是否已经登陆
   * @private
   */
  protected var loggedIn:Boolean;
  
  /**
   * 是否忽略空白字符
   * @private
   */
  protected var ignoreWhitespace:Boolean;
  
  /**
   * @private
   * 打开流的标签
   */
  protected var openingStreamTag:String;
  
  /**
   * @private
   * 关闭流的标签
   */
  protected var closingStreamTag:String;

  /**
   * @private
   * 会话id
   */
  protected var sessionID:String;
  
  /**
   * @private
   */
  protected var pendingIQs:Object;
  
  /**
   * @private
   */
  protected var _expireTagSearch:Boolean;
  
  protected static var _openConnections:Array = [];
  
  public function XMPPConnection()
  { 
   
   // Hash to hold callbacks for IQs
   pendingIQs = new Object();
   
   _useAnonymousLogin = false;
   active = false;
   loggedIn = false;
   ignoreWhitespace = true;
   //初始化为忽略空白字符
   resource = "xiff";
   //初始化资源为xiff
   port = 5222;
   
   AuthExtension.enable();
   RegisterExtension.enable();
   FormExtension.enable();
  }
  
  /**
   * Connects to the server.
   * 链接到服务器端
   * @param streamType (Optional) The type of initial stream negotiation, either &lt;flash:stream&gt; or &lt;stream:stream&gt;.
   * Some servers, like Jabber, Inc.'s XCP and Jabberd 1.4 expect &lt;flash:stream&gt; from a Flash client instead of the standard &lt;stream:stream&gt;.
   * The options for this parameter are: "flash", "terminatedFlash", "standard" and "terminatedStandard". The default is "terminatedStandard".
   *返回是否找到服务器
   * @return A boolean indicating whether the server was found.
   */
  public function connect( streamType:String = "terminatedStandard" ):Boolean
  {
   
   // Create the socket 创建一个socket连接字
   _socket = _createXmlSocket();
   
   active = false;
   loggedIn = false;
   
   ///  创建流样式  <stream:flash>
   // Stream type lets user set opening/closing tag - some servers (jadc2s) prefer <stream:flash> to the standard
   // <stream:stream>
   switch( streamType ) {
    /////在xiff中用flash
    case "flash":
     openingStreamTag = new String( "<?xml version=\"1.0\"?><flash:stream to=\"" + server + "\" xmlns=\"jabber:client\" xmlns:flash=\"http://www.jabber.com/streams/flash\" version=\"1.0\">" );
     closingStreamTag = new String( "</flash:stream>" );
     break;
     
    case "terminatedFlash":
     openingStreamTag = new String( "<?xml version=\"1.0\"?><flash:stream to=\"" + server + "\" xmlns=\"jabber:client\" xmlns:flash=\"http://www.jabber.com/streams/flash\" version=\"1.0\" />" );
     closingStreamTag = new String( "</flash:stream>" );
     break;
     
    case "standard":
     openingStreamTag = new String( "<?xml version=\"1.0\"?><stream:stream to=\"" + server + "\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">" );
     closingStreamTag = new String( "</stream:stream>" );
     break;
   
    case "terminatedStandard":
    default:
     openingStreamTag = new String( "<?xml version=\"1.0\"?><stream:stream to=\"" + server + "\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\" />" );
     closingStreamTag = new String( "</stream:stream>" );
     break;
   }
   //链接到服务器如果成功返回true
   _socket.connect( server, port );
   return true;
  }
  
  /**
   * 关闭与服务器的连接
   * Disconnects from the server if currently connected. After disconnect,
   * a <code>DisconnectionEvent.DISCONNECT</code> event is broadcast.
   */
  public function disconnect():void
  {
   //如果链接是活动的,发送一个关闭流  设置活动状态为false
   if( isActive() ) {
    sendXML( closingStreamTag );
    _socket.close();
    active = false;
    loggedIn = false;
    var event:DisconnectionEvent = new DisconnectionEvent();
    dispatchEvent(event);
    //将关闭连接这个事件分发( 广播)
   }
  }
  
  /**
   * Sends data to the server. If the data to send cannot be serialized properly, this method throws a <code>SerializeException</code>.
   *发送数据给服务器,如果数据不能被序列号则不能被发送
   * @param o The data to send. This must be an instance of a class that implements the ISerializable interface.
  * 参数必须是已经实现了ISerriable接口的实例
   *  * @see org.jivesoftware.xiff.data.ISerializable
   * @example The following example sends a basic chat message to the user with the JID "sideshowbob@springfieldpenitentiary.gov".<br />
   * <pre>var msg:Message = new Message( "sideshowbob@springfieldpenitentiary.gov", null, "Hi Bob.", "<b>Hi Bob.</b>", Message.CHAT_TYPE );
   * myXMPPConnection.send( msg );</pre>
   */
  public function send( o:XMPPStanza ):void
  {
   if( isActive() ) {
    ///主要是处理  IQ(info 、query)
    if( o is IQ ) {
                 var iq:IQ = o as IQ;
                 if ((iq.callbackName != null && iq.callbackScope != null) || iq.callback != null)
                 {
                  addIQCallbackToPending( iq.id, iq.callbackName, iq.callbackScope, iq.callback );
                 }  
    }
    var root:XMLNode = o.getNode().parentNode;
    if (root == null) {
     root = new XMLDocument();
    }
 
    if (o.serialize(root)) {
     sendXML( root.firstChild );
    } else {
     throw new SerializationException();
    }
   }
  }
  ///发送一个空包,保持这个联结
  public function sendKeepAlive():void
  {
   if( isActive() ) {
    sendXML(" ");
   }
  }
  
  /**
   * Determines whether the connection with the server is currently active. (Not necessarily logged in.
   * For login status, use the <code>isLoggedIn()</code> method.)
   * 检测这个连接是否是活动的
   * @return A boolean indicating whether the connection is active.
   * @see org.jivesoftware.xiff.core.XMPPConnection#isLoggedIn
   */
  public function isActive():Boolean
  {
   return active;
  }
  
  /**
   * Determines whether the user is connected and logged into the server.
   * 判断用户是否已经登陆
   * @return A boolean indicating whether the user is logged in.
   * @see org.jivesoftware.xiff.core.XMPPConnection#isActive
   */
  public function isLoggedIn():Boolean
  {
   return loggedIn;
  }
  
  /**
   * Issues a request for the information that must be submitted for registration with the server.
   * 发布一个请求去获取必须提交的信息以用来向服务器注册,注册用户时用到
   * When the data returns, a <code>RegistrationFieldsEvent.REG_FIELDS</code> event is dispatched
   * containing the requested data.
   */
  public function getRegistrationFields():void
  {
   var regIQ:IQ = new IQ( new JID(server), IQ.GET_TYPE, XMPPStanza.generateID("reg_info_"), "getRegistrationFields_result", this, null);
   regIQ.addExtension(new RegisterExtension(regIQ.getNode()));
 
   send( regIQ );
  }
  
  /**
   * Registers a new account with the server, sending the registration data as specified in the fieldMap paramter.
   * 向服务注册一个新的帐号,发送注册所需的数据
   * @param fieldMap An object map containing the data to use for registration. The map should be composed of
   * attribute:value pairs for each registration data item.
   * @param key (Optional) If a key was passed in the "data" field of the "registrationFields" event,
   * that key must also be passed here.
   * required field needed for registration.
   */
  public function sendRegistrationFields( fieldMap:Object, key:String ):void
  {
   var regIQ:IQ = new IQ( new JID(server), IQ.SET_TYPE, XMPPStanza.generateID("reg_attempt_"), "sendRegistrationFields_result", this, null );
   var ext:RegisterExtension = new RegisterExtension(regIQ.getNode());
 
   for( var i:String in fieldMap ) {
    ext[i] = fieldMap[i];
   }
   if (key != null) {
    ext.key = key;
   }
 
   regIQ.addExtension(ext);
   send( regIQ );
  }
  
  /**
   * Changes the user's account password on the server. If the password change is successful,
   * the class will broadcast a <code>ChangePasswordSuccessEvent.PASSWORD_SUCCESS</code> event.
   *变更用户帐号密码, 如果成功将会触发事件:ChangePasswordSuccessEvent.PASSWORD_SUCCESS
   * @param newPassword The new password
   */
  public function changePassword( newPassword:String ):void
  {
   var passwdIQ:IQ = new IQ( new JID(server), IQ.SET_TYPE, XMPPStanza.generateID("pswd_change_"), "changePassword_result", this, null );
   var ext:RegisterExtension = new RegisterExtension(passwdIQ.getNode());
 
   ext.username = jid.toBareJID();
   ext.password = newPassword;
 
   passwdIQ.addExtension(ext);
   send( passwdIQ );
  }
  
  /**
   * Gets the fully qualified JID (user@server/resource) of the user. A fully-qualified JID includes
   * the resource. A bare JID does not. To get the bare JID, use the <code>getBareJID()</code> method.
   * 返回一个完整的jid user@server/resource
   * @return The fully qualified JID
   * @see #getBareJID
   */
  public function get jid():JID
  {
   return new JID(myUsername + "@" + myServer + "/" + myResource);
  }
  
  /**
   * @private  修改密码的返回情况
   */
  protected function changePassword_result( resultIQ:IQ ):void
  {
   if( resultIQ.type == IQ.RESULT_TYPE ) {
    var event:ChangePasswordSuccessEvent = new ChangePasswordSuccessEvent();
    dispatchEvent(event);
   }
   else {
    // We weren't expecting this
    ////400  修改密码错误
    dispatchError( "unexpected-request", "Unexpected Request", "wait", 400 );
   }
  }
  
  /**
   * @private 注册用户的返回情况
   */
  protected function getRegistrationFields_result( resultIQ:IQ ):void
  {
   try
   {
    var ext:RegisterExtension = resultIQ.getAllExtensionsByNS(RegisterExtension.NS)[0];
    var fields:Array = ext.getRequiredFieldNames(); //TODO, phase this out
    
    var event:RegistrationFieldsEvent = new RegistrationFieldsEvent();
    event.fields = fields;
    event.data = ext;
   }
   catch (e:Error)
    {
     trace(e.getStackTrace());
    }
  }
  
  /**
   * @private
   */
  protected function sendRegistrationFields_result( resultIQ:IQ ):void
  {
   if( resultIQ.type == IQ.RESULT_TYPE ) {

    var event:RegistrationSuccessEvent = new RegistrationSuccessEvent();
    dispatchEvent( event );
   }
   else {
    // We weren't expecting this
    dispatchError( "unexpected-request", "Unexpected Request", "wait", 400 );
   }
  }
  
  // Listener function from the ListenerXMLSocket
  /**
   * @private
   */
  protected function socketConnected(ev:Event):void
  {
   active = true;
   sendXML( openingStreamTag );
   var event:ConnectionSuccessEvent = new ConnectionSuccessEvent();
   dispatchEvent( event );
  }
  
  /**
   * @private
   */
  protected function socketReceivedData( ev:DataEvent ):void
  {
   // parseXML is more strict in AS3 so we must check for the presence of flash:stream
   // the unterminated tag should be in the first string of xml data retured from the server
   if (!_expireTagSearch)
   {
    var pattern:RegExp = new RegExp("<flash:stream");
    var resultObj:Object = pattern.exec(ev.data);
    if (resultObj != null) // stop searching for unterminated node
    {
     ev.data = ev.data.concat("</flash:stream>");
     _expireTagSearch = true;
    }
   }
   
   if(ev.data == "</flash:stream>")
   {
    socketClosed(null);
    return; 
   } 
   
   var xmlData:XMLDocument = new XMLDocument();
   xmlData.ignoreWhite = this.ignoreWhite;
   xmlData.parseXML( ev.data );
   
   var event:IncomingDataEvent = new IncomingDataEvent();
   event.data = xmlData;
   dispatchEvent( event );
   
   // Read the data and send it to the appropriate parser
   var firstNode:XMLNode = xmlData.firstChild;
   var nodeName:String = firstNode.nodeName.toLowerCase();
   //trace("RECV: " + firstNode);
   switch( nodeName )
   {
    case "stream:stream":
    case "flash:stream":
     _expireTagSearch = false;
     handleStream( firstNode );
     break;
     
    case "stream:error":
     handleStreamError( firstNode );
     break;
     
    case "iq":
     handleIQ( firstNode );
     break;
     
    case "message":
     handleMessage( firstNode );
     break;
     
    case "presence":
     handlePresence( firstNode );
     break;
     
    case "stream:features":
     break;
     
    default:
     // silently ignore lack of or unknown stanzas
     // if the app designer wishes to handle raw data they
     // can on "incomingData".
 
     // Use case: received null byte, XMLSocket parses empty document
     // sends empty document
     
     // I am enabling this for debugging
     dispatchError( "undefined-condition", "Unknown Error", "modify", 500 );
     break;
   }
  }
  
  /**
   * @private
   */
  protected function socketClosed(e:Event):void
  { 
   var event:DisconnectionEvent = new DisconnectionEvent();
   dispatchEvent( event );
  }
  
  /**
   * @private
   */
  protected function handleStream( node:XMLNode ):void
  {
   sessionID = node.attributes.id;
   server = node.attributes.from;
   
   if(_useAnonymousLogin) {
    // Begin anonymous login
    sendAnonymousLogin();
   } else if( username != null && username.length > 0 ) {
    // Begin login sequence
    beginAuthentication();
   } else {
    //get registration fields
    getRegistrationFields();
   }
  }
  
  /**
   * @private
   */
  protected function handleStreamError( node:XMLNode ):void
  {
   dispatchError( "service-unavailable", "Remote Server Error", "cancel", 502 );
   
   // Cancel everything by closing connection
   try {
    _socket.close();
   }
   catch (error:Error){
    
   }
   active = false;
   loggedIn = false;
   var event:DisconnectionEvent = new DisconnectionEvent();
   
   dispatchEvent( event );
  }
  
  protected function set active(flag:Boolean):void
  {
   if(flag)
   {
    _openConnections.push(this);
   }
   else
   {
    _openConnections.splice(_openConnections.indexOf(this), 1);
   }
   _active = flag;
  }
  
  protected function get active():Boolean
  {
   return _active;
  }
  
  public static function get openConnections():Array
  {
   return _openConnections;
  }
  
  /**
   * @private
   */
  protected function handleIQ( node:XMLNode ):IQ
  {
   var iq:IQ = new IQ();
   // Populate the IQ with the incoming data
   if( !iq.deserialize( node ) ) {
    throw new SerializationException();
   }
   
   // If it's an error, handle it
   
   if( iq.type == IQ.ERROR_TYPE && !pendingIQs[iq.id]) {
    dispatchError( iq.errorCondition, iq.errorMessage, iq.errorType, iq.errorCode );
   }
   else {
    
    // Start the callback for this IQ if one exists
    if( pendingIQs[iq.id] !== undefined ) {
     var callbackInfo:* = pendingIQs[iq.id];
     
     if(callbackInfo.methodScope && callbackInfo.methodName) {
      callbackInfo.methodScope[callbackInfo.methodName].apply( callbackInfo.methodScope, [iq] );
     }   
     if (callbackInfo.func != null) {
      callbackInfo.func( iq );
     }
     pendingIQs[iq.id] = null;
     delete pendingIQs[iq.id];
    }
    else {
     var exts:Array = iq.getAllExtensions();
     for (var ns:String in exts) {
      // Static type casting
      var ext:IExtension = exts[ns] as IExtension;
      if (ext != null) {
       var event:IQEvent = new IQEvent(ext.getNS());
       event.data = ext;
       event.iq = iq;
       dispatchEvent( event );
      }
     }
    }
   }
         return iq;
  }
  
  /**
   * @private
   */
  protected function handleMessage( node:XMLNode ):Message
  {
   var msg:Message = new Message();
   //trace(msg); 
   // Populate with data
   if( !msg.deserialize( node ) ) {
    throw new SerializationException();
   }
   // ADDED in error handling for messages
   if( msg.type == Message.ERROR_TYPE ) {
    dispatchError( msg.errorCondition, msg.errorMessage, msg.errorType, msg.errorCode );
   }
   else
   {
    var event:MessageEvent = new MessageEvent();
    event.data = msg;
    dispatchEvent( event );  
   }
         return msg;
  }
  
  /**
   * @private
   */
  private var presenceQueue:Array = [];
  private var presenceQueueTimer:Timer;
  protected function handlePresence( node:XMLNode ):Presence
  {
   if(!presenceQueueTimer)
   {
    presenceQueueTimer = new Timer(1, 1);
    presenceQueueTimer.addEventListener(TimerEvent.TIMER_COMPLETE, flushPresenceQueue);
   }
   
   var pres:Presence = new Presence();
   
   // Populate
   if( !pres.deserialize( node ) ) {
    throw new SerializationException();
   }
   
   presenceQueue.push(pres);
   
   presenceQueueTimer.reset();
   presenceQueueTimer.start();

         return pres;
  }
  
  protected function flushPresenceQueue(evt:TimerEvent):void
  {
   var event:PresenceEvent = new PresenceEvent();
   event.data = presenceQueue;
   dispatchEvent( event );
   presenceQueue = [];
  }
  
  /**
   * @private
   */
  protected function onIOError(event:IOErrorEvent):void{
   /*
   this fires the standard dispatchError method. need to add
   the appropriate error code
   */
   dispatchError( "service-unavailable", "Service Unavailable", "cancel", 503 );
  }
  
  /**
   * @private
   */
  protected function securityError(event:SecurityErrorEvent):void{
   trace("there was a security error of type: " + event.type + "\nError: " + event.text);
   dispatchError( "not-authorized", "Not Authorized", "auth", 401 );
  }
  
  /**
   * @private
   */
  protected function dispatchError( condition:String, message:String, type:String, code:Number ):void
  {
   var event:XIFFErrorEvent = new XIFFErrorEvent();
   event.errorCondition = condition;
   event.errorMessage = message;
   event.errorType = type;
   event.errorCode = code;
   dispatchEvent( event );
  }
  
  /**
   * @private
   */
  protected function sendXML( someData:* ):void
  {
   //trace("SEND: " + someData);
   // Data is untyped because it could be a string or XML
   _socket.send( someData );
   var event:OutgoingDataEvent = new OutgoingDataEvent();
   event.data = someData;
   dispatchEvent( event );
  }
  
  // anonymous login
  /**
   * @private
   */
  protected function sendAnonymousLogin():void
  {
   var anonIQ:IQ = new IQ(null, IQ.SET_TYPE, XMPPStanza.generateID("log_anom_"), "sendAnonymousLogin_result", this, null );
   var authExt:AuthExtension = new AuthExtension(anonIQ.getNode());
   anonIQ.addExtension(authExt);
   send(anonIQ);
  }
  
  /**
   * @private
   */
  protected function sendAnonymousLogin_result(resultIQ:IQ):void
  {resultIQ
   if( resultIQ.type == IQ.RESULT_TYPE ) {
    // update resource
    var jid:JID = resultIQ.to;
    resource = jid.resource;
    username = jid.node;
    // dispatch login event
    loggedIn = true;
    var event:LoginEvent = new LoginEvent();
    dispatchEvent( event );
   }
  }
  
  /**
   * @private
   */
  protected function beginAuthentication():void
  {
   var authIQ:IQ = new IQ( null, IQ.GET_TYPE, XMPPStanza.generateID("log_user_"), "beginAuthentication_result", this, null );
   var authExt:AuthExtension = new AuthExtension(authIQ.getNode());
   authExt.username = username
   
   authIQ.addExtension(authExt);
   send( authIQ );
  }
  
  /**
   * @private
   */
  protected function beginAuthentication_result( resultIQ:IQ ):void
  {
   var connectionType:String = "none";
 
   // Begin authentication procedure
   if( resultIQ.type == IQ.RESULT_TYPE ) {
    var authIQ:IQ = new IQ( null, IQ.SET_TYPE, XMPPStanza.generateID("log_user2_"), "sendAuthentication_result", this, null );
    try
    {
     var resultAuth:* = resultIQ.getAllExtensionsByNS(AuthExtension.NS)[0];
     var responseAuth:AuthExtension = new AuthExtension(authIQ.getNode());
     responseAuth.password = password;
     responseAuth.username = username;
     responseAuth.resource = resource;
     authIQ.addExtension(responseAuth);
     send( authIQ );
    }
    catch (e:Error)
    {
     trace("Error : null trapped. Resuming.");
    }
   }
   else {
    // We weren't expecting this
    dispatchError( "unexpected-request", "Unexpected Request", "wait", 400 );
   }
  }
  
  /**
   * @private
   */
  protected function sendAuthentication_result( resultIQ:IQ ):void
  {
   if( resultIQ.type == IQ.RESULT_TYPE ) {
    loggedIn = true;
    var event:LoginEvent = new LoginEvent();
    dispatchEvent( event );
   }
   else {
    // We weren't expecting this
    dispatchError( "unexpected-request", "Unexpected Request", "wait", 400 );
   }
  }
  
  /**
   * @private
   */
  protected function addIQCallbackToPending( id:String, callbackName:String, callbackScope:Object, callbackFunc:Function ):void
  {
   pendingIQs[id] = {methodName:callbackName, methodScope:callbackScope, func:callbackFunc};
  }
  
  /**
   * The XMPP server to use for connection.
   */
  public function get server():String
  {
   return myServer;
  }
  
  /**
   * @private
   */
  public function set server( theServer:String ):void
  {
   myServer = theServer;
  }
  
  /**
   * The username to use for connection. If this property is null when <code>connect()</code> is called,
   * the class will fetch registration field data rather than attempt to login.
   */
  public function get username():String
  {
   return myUsername;
  }
  
  /**
   * @private
   */
  public function set username( theUsername:String ):void
  {
   myUsername = theUsername;
  }
  
  /**
   * The password to use when logging in.
   */
  public function get password():String
  {
   return myPassword;
  }
  
  public function set password( thePassword:String ):void
  {
   myPassword = thePassword;
  }
  
  /**
   * The resource to use when logging in. A resource is required (defaults to "XIFF") and
   * allows a user to login using the same account simultaneously (most likely from multiple machines).
   * Typical examples of the resource include "Home" or "Office" to indicate the user's current location.
   */
  public function get resource():String
  {
   return myResource;
  }
  
  /**
   * @private
   */
  public function set resource( theResource:String ):void
  {
   if( theResource.length > 0 )
   {
    myResource = theResource;
   }
  }
  
  /**
   * Whether to use anonymous login or not.
   */
  public function get useAnonymousLogin():Boolean
  {
   return _useAnonymousLogin;
  }
  
  /**
   * @private
   */
  public function set useAnonymousLogin(value:Boolean):void
  {
   // set only if not connected
   if(!isActive()) _useAnonymousLogin = value;
  }
  
  /**
   * The port to use when connecting. The default XMPP port is 5222.
   */
  public function get port():Number
  {
   return myPort;
  }
  
  public function set port( portNum:Number ):void
  {
   myPort = portNum;
  }
 
  /**
   * Determines whether whitespace will be ignored on incoming XML data.
   * Behaves the same as <code>XML.ignoreWhite</code>
   */
  public function get ignoreWhite():Boolean
  {
   return ignoreWhitespace;
  }
 
  public function set ignoreWhite( val:Boolean ):void
  {
   ignoreWhitespace = val;
  }
  
  private function _createXmlSocket():XMLSocket {
   var socket:XMLSocket = new XMLSocket(server, port);
   socket.addEventListener(Event.CONNECT,socketConnected);
   socket.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
   socket.addEventListener(Event.CLOSE,socketClosed);
   socket.addEventListener(DataEvent.DATA,socketReceivedData);
   socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityError);
   return socket;
  }
 }
}

posted @ 2008-03-26 14:59 华梦行 阅读(3268) | 评论 (0)编辑 收藏
http://is.qq.com/webpresence/code.shtml
<a target=blank href=tencent://message/?uin=331998039&Site=bbs.justong.cn&Menu=yes><img border="0" SRC=http://wpa.qq.com/pa?p=1:331998039:10 alt="有事就Q我"></a>
posted @ 2008-03-22 10:24 华梦行 阅读(324) | 评论 (1)编辑 收藏
[client]
default-character-set = utf8
[mysqld]
init-connect='SET NAMES utf8'
default-storage-engine = INNODB
character-set-server = utf8
collation-server = utf8_general_ci
default-character-set = utf8
max_connections=150
[mysql]
default-character-set = utf8
posted @ 2008-03-21 09:39 华梦行 阅读(207) | 评论 (0)编辑 收藏

mysql 远程访问的设置

登陆以后运行以下命令,给予远程访问客户端权限.. 

grant all on *.* to 'remote'@'172.16.21.39' identified by 'password';

remote表示用户名.

'172.16.21.39' 远程ip地址

password表示远程登陆密码.

posted @ 2008-03-05 21:02 华梦行 阅读(250) | 评论 (0)编辑 收藏

VNC,全称为Virtual Network Computing,它是一个桌面共享系统。它的功能,类似于Windows中的远程桌面功能。VNC使用了RFB(Remote FrameBuffer,远程帧缓冲)协议来实现远程控制另外一台计算机。它把键盘鼠标动作发送到远程计算机,并把远程计算机的屏幕发回到本地。

VNC技术与平台无关,VNC VIEwer可以和VNC Server在不同的操作系统上。VNC几乎支持所有的操作系统,也支持Java,甚至可以通过支持Java的浏览器来访问VNC Server。多个VNC客户端可以同时连接到一个VNC Server上。

VNC最初由AT&T开发的,它的源代码是开源的。

在CentOs 4.3上配置VNC服务很简单(这里假定你的计算机上已经安装了VNC软件)

首先需要配置VNC密码,密码在使用客户端连接服务器时使用。

注意:VNC密码保存在用户的主目录中,每个用户都可以设置自己的密码。因此,请使用你的用户名(尽量不要使用root)运行下列命令:

vncpasswd

然后输入密码。

接下来就可以启动VNC server了。在启动VNC server时,需要为你的server指定一个display参数。你可以把display理解为一个桌面,每个用户都可以有自己的桌面。VNC客户端在连接时,可以指定连接到哪个桌面上。在系统中,display号不能重复,也就是说,如果有用户已经建立了名为“:1”的display,另外一个用户就不能再使用“:1”了,他可以使用“:2”。

启动VNC server的命令是:

vncserver <display>

例如,

vncserver :1

最后,需要配置一下防火墙,允许VNC客户端连接VNC server。VNC server监听的端口从5900开始,display :1的监听5901,display :2监听5902,以此类推。CentOs的防火墙缺省是不允许连接这些端口的,所以需要使用下面的步骤打开防火墙(需要root权限):

vi /etc/sysconfig/iptables

找到下面的语句:

-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited

在此行之前,加上下面的内容:

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 5900:5903 -j ACCEPT

这句话的含义是,允许其它机器访问本机的5900到5903端口,这样,display:1, display:2, display:3的用户就可以连接到本机。

然后使用root身份重新启动防火墙:

/sbin/service iptables restart

好了,现在就可以运行客户端软件,连接到VNC server上了。

VNC客户端软件很多,在Linux下有vncviewer,KDE还提供了一个krdc(它的菜单项就是”Remote Desktop Connection",远程桌面连接)。

在window也有不少vnc客户端,你可以到http://www.realvnc.com/去下载一个,安装就可以用了。

假设VNC server的IP地址是192.168.1.1,display是:1。在VNC viewer的server栏中输入:“192.168.1.1:1”,然后连接。OK,你可以看到自己的桌面了。以后不管你什么时候关闭自己的本地PC机都不怕了,只要server不关机,你只要连接到VNC server,你就可以看到你前一天关闭本地PC机时的桌面还保持着原样。

不过...这个桌面怎么这么丑?!

原来vncserver默认使用的窗口管理器是twm,这是一个很简陋的窗口管理器,你可以把你的桌面改成GNOME或KDE。

方法是,进入你自己的home目录,然后编辑这个文件:.vnc/xstartup,下面是这个文件的内容:

#!/bin/sh

# Uncomment the following two lines for normal desktop:

#unset SESSION_MANAGER

#exec /etc/X11/xinit/xinitrc

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup

[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources

xsetroot -solid grey

vncconfig -iconic &

xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &

#twm &

gnome-session &

你可以把像上面这样把"twm &"这一行注释掉,然后在下面加入一行"gnome-session &",或者是"startkde &",分别启动GNOME桌面和KDE桌面。

如果server重启了,那你就需要重新运行一次vncserver命令来启动VNC server,这很麻烦。有没有更好的方法呢?

有!我们可以把VNC server启动成后台服务。执行如下步骤:

首先要允许VNC server在系统启动过程中被启动。这可以通过“系统设置-->服务器设置-->服务”菜单来配置,把vncserver一项选上就可以了。

如果使用命令行的话,以root身份运行以下两条命令:

cd /etc/rc5.d

mv K35vncserver S35vncserver

然后编辑/etc/sysconfig/vncservers,以下是文件内容:

																# The VNCSERVERS variable is a list of display:user pairs.
#
# Uncomment the line below to start a VNC server on display :1
# as my 'myusername' (adjust this to your own).  You will also
# need to set a VNC passWord; run 'man vncpasswd' to see how
# to do that.
#
# DO NOT RUN THIS SERVICE if your local area network is
# untrusted!  For a secure way of using VNC, see
# <URL:http://www.uk.research.att.com/vnc/sshvnc.HTML>.
VNCSERVERS="1:user1 2:user2 3:user3"
VNCSERVERARGS[1]="-geometry 1024x768"
VNCSERVERARGS[2]="-geometry 1024x768"
VNCSERVERARGS[3]="-geometry 800x600"
														

解释一下这个文件:

VNCSERVERS这一行是配置在系统启动时启动几个VNC server,上面的例子里运行了三个VNC server,其中user1在display :1,user2在display :2,user3在display :3。

VNCSERVERARGS这三行,分别为VNC server 1, 2, 3配置启动参数,上面的例子里对user1和user2使用屏幕分辨率1024x768,对user3使用800x600。

其它支持的参数请使用“man vncserver”命令查询。

编辑好这个文件后,保存,然后以root身份运行:

/sbin/service vncserver start

这样user1, user2, user3的vncserver就启动了。

以后每次系统重启时,都会自动启动这三个用户的vncserver。

注意:上面三个用户必须已经使用vncpasswd命令设置过vnc密码,不然他的vncserver启动会失败

posted @ 2008-03-04 19:21 华梦行 阅读(366) | 评论 (0)编辑 收藏
/etc/my.conf下添加配置

[client]
default-character-set = utf8
[mysqld]
init-connect='SET NAMES utf8'
default-storage-engine = INNODB
character-set-server = utf8
collation-server = utf8_general_ci
default-character-set = utf8
[mysql]
default-character-set = utf8
posted @ 2008-03-04 19:18 华梦行 阅读(145) | 评论 (0)编辑 收藏

允许Flash跨域加载数据

Flash 文档可通过使用以下某种数据加载调用方法从外部源加载数据:XML.load()XML.sendAndLoad()LoadVars.load()LoadVars.sendAndLoad()loadVariables()loadVariablesNum()、MovieClip.loadVariables()XMLSocket.connect() 和 Macromedia Flash Remoting (NetServices.createGatewayConnection)。另外,SWF 文件可以在运行时导入运行时共享库 (RSL) 或另一个 SWF 文件中定义的资源。默认情况下,数据或 RSL 必须与加载该外部数据或媒体的 SWF 文件驻留在同一个域中。

若要使运行时共享库中的数据和资源可用于其它域中的 SWF 文件,应使用跨域策略文件。跨域策略文件是一个 XML 文件,该文件提供的方法可以使服务器指示其数据和文档可用于从某些域或所有域提供的 SWF 文件。服务器的策略文件指定的域所提供的所有 SWF 文件都将被允许访问该服务器中的数据、资源或 RSL。

如果您加载外部数据,即使不想将任何文件移植到 Flash Player 7 中,也应创建策略文件。如果您使用 RSL,并且调用或被调用文件是以 Flash Player 7 为目标播放器发布的,则应创建策略文件。

允许跨域数据加载

当 Flash 文档试图访问另一个域中的数据时,Flash Player 将自动试图从该域加载策略文件。如果试图访问数据的 Flash 文档所在的域包括在该策略文件中,则数据将自动成为可访问数据。

策略文件必须命名为 crossdomain.xml,并且可以驻留在服务器的根目录和其它目录之中,该服务器提供具有其它 ActionScript 的数据。只有在通过 HTTP、HTTPS 或 FTP 进行通信的服务器上,策略文件才起作用。策略文件特定于它所驻留的服务器的端口和协议。

例如,位于 https://www.macromedia.com:8080/crossdomain.xml 的策略文件只适用于在端口 8080 通过 HTTPS 对 www.macromedia.com 进行的数据加载调用。

此规则的例外情况是,使用 XMLSocket 对象连接到另一个域中的套接字服务器。如果是这种情况,运行于与套接字服务器所在的同一个域中端口 80 上的 HTTP 服务器必须提供该方法调用的策略文件。

XML 策略文件包含单个 <cross-domain-policy> 标签,该标签又包含零个或多个 <allow-access-from> 标签。每个 <allow-access-from> 标签包含一个属性 domain,该属性指定一个确切的 IP 地址、一个确切的域或一个通配符域(任何域)。通配符域由单个星号 (*)(匹配所有域和所有 IP 地址)或后接后缀的星号(只匹配那些以指定后缀结尾的域)表示。后缀必须以点开头。但是,带有后缀的通配符域可以匹配那些只包含后缀但不包含前导点的域。例如,cenfun.com 可以看作是 *.cenfun.com 的一部分。IP 域规范中不允许使用通配符。

如果您指定了一个 IP 地址,则将只向使用 IP 语法从该 IP 地址(例如 http://65.57.83.12/flashmovie.swf)加载的 SWF 文件授予访问权限,而不向使用域名语法加载的 SWF 文件授予访问权限。Flash Player 不执行 DNS 解析。

下面的示例显示一个策略文件,该策略文件允许从 cenfun.com 上的 Flash 文档访问来自 cenfun.com、www.friendOfcenfun.com、*.cenfun.com 和 105.216.0.40 的 Flash 文档:

<?xml version="1.0"?>
<!-- http://www.cenfun.com/crossdomain.xml -->
<cross-domain-policy>
<allow-access-from domain="www.friendOfcenfun.com" />
<allow-access-from domain="*.cenfun.com" />
<allow-access-from domain="105.216.0.40" />
</cross-domain-policy>

您也可以允许访问来自任何域的文档,如下面的示例所示:(http://www.cenfun.com/crossdomain.xml )

								<?xml version="1.0"?>
<!-- http://www.cenfun.com/crossdomain.xml -->
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
						

每个 <allow-access-from> 标签还具有可选的 secure 属性。secure 属性默认为 true。如果您的策略文件在 HTTPS 服务器上,并且要允许 HTTP 服务器上的 SWF 文件从 HTTPS 服务器加载数据,则可以将此属性设置为 false

secure 属性设置为 false 可能会危及 HTTPS 提供的安全性。

如果您正在下载来自 HTTPS 服务器的 SWF 文件,而加载它的 SWF 文件在 HTTP 服务器上,则您需要为 <allow-access-from> 标签添加 secure="false" 属性,如下面的代码所示:

<allow-access-from domain="www.cenfun.com" secure="false" />

不包含任何 <allow-access-from> 标签的策略文件相当于服务器上没有策略。

posted @ 2008-02-28 14:50 华梦行 阅读(2397) | 评论 (0)编辑 收藏

 

public class Escape {
        private final static String[] hex = { "00", "01", "02", "03", "04", "05",
        "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10",
        "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B",
        "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26",
        "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
        "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C",
        "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
        "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52",
        "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D",
        "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68",
        "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73",
        "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E",
        "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
        "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94",
        "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
        "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA",
        "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5",
        "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0",
        "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
        "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6",
        "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1",
        "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC",
        "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
        "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };

        private final static byte[] val = { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x01,
        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
        0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F };

        /**
        * 编码
        *
        * @param s
        * @return
        */
        public static String escape(String s) {
        StringBuffer sbuf = new StringBuffer();
        int len = s.length();
        for (int i = 0; i < len; i++) {
        int ch = s.charAt(i);
        if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
        sbuf.append((char) ch);
        } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
        sbuf.append((char) ch);
        } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
        sbuf.append((char) ch);
        } else if (ch == '-' || ch == '_' // unreserved : as it was
        || ch == '.' || ch == '!' || ch == '~' || ch == '*'
        || ch == '\'' || ch == '(' || ch == ')') {
        sbuf.append((char) ch);
        } else if (ch <= 0x007F) { // other ASCII : map to %XX
        sbuf.append('%');
        sbuf.append(hex[ch]);
        } else { // unicode : map to %uXXXX
        sbuf.append('%');
        sbuf.append('u');
        sbuf.append(hex[(ch >>> 8)]);
        sbuf.append(hex[(0x00FF & ch)]);
        }
        }
        return sbuf.toString();
        }

        /**
        * 解码 说明:本方法保证 不论参数s是否经过escape()编码,均能得到正确的“解码”结果
        *
        * @param s
        * @return
        */
        public static String unescape(String s) {
        StringBuffer sbuf = new StringBuffer();
        int i = 0;
        int len = s.length();
        while (i < len) {
        int ch = s.charAt(i);
        if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
        sbuf.append((char) ch);
        } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
        sbuf.append((char) ch);
        } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
        sbuf.append((char) ch);
        } else if (ch == '-' || ch == '_' // unreserved : as it was
        || ch == '.' || ch == '!' || ch == '~' || ch == '*'
        || ch == '\'' || ch == '(' || ch == ')') {
        sbuf.append((char) ch);
        } else if (ch == '%') {
        int cint = 0;
        if ('u' != s.charAt(i + 1)) { // %XX : map to ascii(XX)
        cint = (cint << 4) | val[s.charAt(i + 1)];
        cint = (cint << 4) | val[s.charAt(i + 2)];
        i += 2;
        } else { // %uXXXX : map to unicode(XXXX)
        cint = (cint << 4) | val[s.charAt(i + 2)];
        cint = (cint << 4) | val[s.charAt(i + 3)];
        cint = (cint << 4) | val[s.charAt(i + 4)];
        cint = (cint << 4) | val[s.charAt(i + 5)];
        i += 5;
        }
        sbuf.append((char) cint);
        } else { // 对应的字符未经过编码
        sbuf.append((char) ch);
        }
        i++;
        }
        return sbuf.toString();
        }

        public static void main(String[] args) {
        String stest = "中文1234 abcd[]()<+>,.~\\";
        System.out.println(stest);
        System.out.println(escape(stest));
        System.out.println(unescape(escape(stest)));
        }

        }

 

posted @ 2008-02-27 21:18 华梦行 阅读(483) | 评论 (0)编辑 收藏
     摘要: 附录B:错误代码和消息 目录 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 ...  阅读全文
posted @ 2008-02-26 21:28 华梦行 阅读(1746) | 评论 (0)编辑 收藏
<marquee scrollAmount=2 onMouseOver=this.stop() onMouseOut=this.start()>    调节速度:scrollAmount
ln -s /data/oracle9/product/9.2.0/oracle.swd.jre/bin/i386/native_threads/java

/data/oracle9/product/9.2.0/oracle.swd.jre/bin/i386/native_threads/jre

posted @ 2008-02-21 20:33 华梦行 阅读(121) | 评论 (0)编辑 收藏
 1 在web。xml中添加
  <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>
    <init-param>
      <param-name>debug</param-name>
      <param-value>3</param-value>
    </init-param>
    <init-param>
      <param-name>detail</param-name>
      <param-value>3</param-value>
    </init-param>

在客户端文件中添加
OutService._path = 'http://192.168.1.120:8080/justchat/dwr';
DWREngine.setMethod(DWREngine.ScriptTag);
posted @ 2008-02-21 19:37 华梦行 阅读(631) | 评论 (0)编辑 收藏

                          
Linux 9 安装过程。
首先在bios中的启动顺序改为从cd-rom 启动,同时修改相关的io-device。设置为auto
格式化选择自动分区。
安装过程中版本选择选择服务器版本。
4.root的用户密码默认为:123456
完成安装。

二..jdk安装
1.到java官方网站去下载linux版本的jdk 1.5(prm)
2.运行相应的jdk rpm 安装文件,自动安装到/usr/java/jdk1.5.0_14   目录下面
3设置类路径:
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC
export JAVA_HOME=/usr/java/jdk1.5.0_14
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH:$HOMR/bin
在 /etc/profile  添加上面的代码即可
重起计算机运行javac即可完成测试: 如果出现javac相关的信息则说明安装成功。
二。openfire的安装以及部署
到openfire官方网站上去下载最新的openfire
关于openfire  的部署以及启动.自动安装到opt/openfire目录下面 相应的启动文件为
/opt/openfire/bin/openfire.sh
 将oracle9驱动classses12.jar复制到 /opt/openfire/lib目录下面,同时还需要修改配置文件/opt/openfire/conf/openfire.xml  

 如果是oracle则需要将classses12.jar复制到 /opt/openfire/lib目录下面,同时还需要修改配置文

件/opt/openfire/conf/openfire.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
   This file stores bootstrap properties needed by Openfire.
   Property names must be in the format: "prop.name.is.blah=value"
   That will be stored as:
       <prop>
           <name>
               <is>
                   <blah>value</blah>
               </is>
           </name>
       </prop>
   Most properties are stored in the Openfire database. A
 property viewer and editor is included in the admin console.
-->
<!-- root element, all properties must be under this element -->
<jive>
 <adminConsole>
   <!-- Disable either port by setting the value to -1 -->
   <port>9090</port>
   <securePort>9091</securePort>
 </adminConsole>
 <admin>
   <!-- Use this section to define users that will have admin privileges. Below,
         you will find two ways to specify which users are admins. Admins will
         have access to the admin console (only local users) and may have also access
         to other functionalities like ad-hoc commands. -->
   <!-- By default, only the user with the username "admin" can login
        to the admin console. Alternatively, you can specify a comma-delimitted
        list usernames that should be authorized to login to the admin console
        by setting the <authorizedUsernames> field below. -->
   <!-- <authorizedUsernames></authorizedUsernames> -->
   <!-- Comma-delimitted list of bare JIDs. The JIDs may belong to local
        or remote users. -->
   <!-- <authorizedJIDs></authorizedJIDs> -->
 </admin>
 <locale>zh_CN</locale>
 <!-- Network settings. By default, Openfire will bind to all network interfaces.
     Alternatively, you can specify a specific network interfaces that the server
     will listen on. For example, 127.0.0.1. This setting is generally only useful
      on multi-homed servers. -->
 <!--
   <network>
       <interface></interface>
   </network>
   -->
 <connectionProvider>
   <className>org.jivesoftware.database.DefaultConnectionProvider</className>
 </connectionProvider>
 <database>
   <defaultProvider>
     <driver>oracle.jdbc.driver.OracleDriver</driver>
     <serverURL>jdbc:oracle:thin:@192.168.1.2:1521:tlink</serverURL>
     <username>openfire</username>
     <password>openfire</password>
     <minConnections>5</minConnections>
     <maxConnections>15</maxConnections>
     <connectionTimeout>1.0</connectionTimeout>
   </defaultProvider>
 </database>
 <setup>true</setup>
</jive>


    Oracle9i 在Linux9上的安装过程


添加安装过程中需要用到的用户和组,这当中会用到二个用户一个是root,一个是oracle
#groupadd oinstall
#groupadd dba
#useradd –g oinstall –G dba oracle
#passwd oracle
 (二)新建安装目录
#mkdir –p /data/oracle9/product/9.2.0
#chown –R oracle.oinstall /data/oracle9
#mkdir /var/opt/oracle
#chown oracle.dba /var/opt/oracle
#chmod 755 /var/opt/oracle
(三)为了一开机系统就能自动帮你设好这些参数,
也可改动 /etc/sysctl.conf 这个文件,加入以下的语句:
kernel.shmmax = 8589934590
kernel.shmmni = 4096
kernel.shmall = 2097152
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000

注意:如果你的共享内存不够大的话,在安装的过程中会提示ORA-27123错误,到时候你只要把/proc/sys/kernel/shmmax的值调大就

可以了到于多大就看你的了

(六) oracle对文件的要求:编辑文件:
/etc/security/limits.conf 加入以下语句:
oracle    soft    nofile    65536
oracle    hard    nofile   65536
oracle    soft    nproc    16384
oracle    hard    nproc    16384

设置oracle的环境
vi ~/.bash_profile
export LD_ASSUME_KERNEL=2.4.10
export ORACLE_BASE=/data/oracle9
export ORACLE_HOME=/data/oracle9/product/9.2.0
export ORACLE_SID=ora9i
export ORACLE_TERM=xterm
#export NLS_LANG=AMERICAN
export ORACLE_OWNER=oracle
export THREADS_FLAG=native
#export LANG=en_US
export ORA_NLS33=$OROCLE_HOME/ocommon/nls/admin/data
export LD_LIBRARY_PAHT=/data/oracle9/product/9.2.0/lib:/lib:/usr /lib:/usr/local/lib
export PAHT=/data/oracle9/product/9.2.0/bin:$PATH
export PATH=$PATH:$ORACLE_HOME/bin


#su – oracle
$ vi ~/.bash_profile export LD_ASSUME_KERNEL=2.4.1
#export DISPLAY=”192.168.9.205:0.0” (127.0.0.1:0.0)
export ORACLE_BASE=/data/oracle9 export ORACLE_HOME=/data/oracle9/product/9.2.0
export ORACLE_SID=ora9i (数据库全局变量名)
export ORACLE_TERM=xterm (xterm窗口模式 vt100 终端调试模式)
export NLS_LANG=AMERICAN (设置语言AMERICAN英文)
export ORACLE_OWNER=oracle
export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
export THREADS_FLAG=native
export LD_LIBRARY_PATH=/data/oracle9/product/9.2.0/lib:/lib:/usr /lib:/usr/local/lib export

PATH=/data/oracle9/product/9.2/bin:$PATH export PATH=$PATH:$ORACLE_HOME/bin

然后注销再重新登录就可以,oracle 的环境就应该生效了 (要用英文环境)
安装oracle :
ship_9204_linux_disk1.cpio.gz
ship_9204_linux_disk2.cpio.gz
ship_9204_linux_disk3.cpio.gz
用zcat ship_9204_linux_disk1.cpio.gz|cpio -idmv
zcat ship_9204_linux_disk2.cpio.gz|cpio -idmv
zcat ship_9204_linux_disk3.cpio.gz|cpio -idmv
生成三个文件夹Disk1,Disk2,Disk3;
你也可以用(我用的是这个)
cpio -idmv < ship_9204_linux_disk1.cpio
cpio -idmv < ship_9204_linux_disk2.cpio
cpio -idmv < ship_9204_linux_disk3.cpio
在当前目录上会产生三个目录:
Disk1,Disk2,Disk3
#cd Disk1
#./runInstaller 出现图形安装界面。
按照提示完成安装即可。
安装过程中可能遇到的问题
1.遇到乱码时首先运行 export LANG=en_US
2.创见一个指向的链接:
ln -s /data/oracle9/product/9.2.0/oracle.swd.jre/bin/i386/native_threads/java

/data/oracle9/product/9.2.0/oracle.swd.jre/bin/i386/native_threads/jre
配置监听器服务命名还有目录服务 net config assistent
 /data/oracle9/product/9.2.0/bin/netca
启动oracle监听器.
/data/oracle9/product/9.2.0/bin/lsnrctl start TLINK
配置启动oracle服务器
 /data/oracle9/product/9.2.0/bin/dbca
在gui模式下启动oracle

linux 常见命令:
neat  =====redhat-config-network 配置网络
redhat-config-users 配置用户
 rpm -Uvv openfire.rpm --force   强制更新软件
rpm -ql package 列出该软件的所有文件所在的目录     | less  分页显示结果
rpm -qa 列出所有已安装的包
rpm -qi package 列出包信息
 /etc/rc.d/init.d/httpd start
启动 apache:
/etc/rc.d/init.d/httpd stop
关闭apache
  关于ssh 因为在linux下是内置的服务,所以只要启动服务即可。让在window下用ssh的客户端即可进行操作

 
 

posted @ 2008-02-18 11:48 华梦行 阅读(574) | 评论 (0)编辑 收藏
Apache
Apache软件包的组成
Apache服务器的启动
Apache服务器的配置
Apache服务器的用户认证
用户web目录
虚拟主机
1.Apache简介
        WWW(World Wide Web)
        HTTP(HyperText Transfer Protocol)
        交互式访问
        模块化
2.Apache软件包的组成
        /etc/httpd/conf/*
                主配置文件位置
        /etc/rc.d/init.d/httpd
                启动脚本
        /home/httpd/html
                html文档的主目录
        /home/httpd/html/manual/*
                html格式的帮助文档
        /home/httpd/icons/*
                用在html网页中的图标文件
        /usr/sbin/*
                -/usr/sbin/htpasswd
                        建立和更新apache用户的程序
                -/usr/sbin/httpd
                        http服务器程序
        /var/log/httpd/*
                日志文件
3.Apache服务器的启动       
        /etc/rc.d/init.d/httpd start(reload/restart/stop)
         使其自动运行
        ntsysv
4.Apache服务器的配置
        1.配置文件
                httpd.conf srm.conf access.conf
        2.httpd.conf
                ServerType standlone/inetd
                服务器的运行方式
                Port 80
                在standlone方式下监听的端口号
                User nobody
                进程运行的属主
                Group nobody
                进程运行的属组
                ServerAdmin admin@localhost
                管理员信箱
                ServerRoot "/home/httpd/"
                服务器文件位置
                ServerName httpserver
                服务器名称
                Timeout 300
                设置服务器和客户端的连接超时时间
                MaxClient 300
                允许同时连接的客户数
                ProxyRequests on
                允许充当proxy
                DocumentRoot "/home/httpd/html"
                提供服务器文档服务的根目录
                UserDir public_html
                服务器上用户自己主页所在目录
                DirectoryIndex index.html
                目录索引文件
                AccessFileName .htaccess
                在每个目录中包含访问控制信息的文件名
                Alias /icons/ "/home/user/icons/"
                为不在DocumentRoot之下的文档建立别名
                &lt;VirtualHost&gt;&lt;/VirtualHost&gt;
                &lt;Directory&gt;&lt;/Directory&gt;
        3.目录访问权限控制
                ----
                通过修改httpd.conf文件中的Directory项来设置
                Ex:
                &lt;Directory "/home/httpd/html/aa"&gt;
                        Options Indexes
                        AllowOverride None
                        order allow,deny
                        allow from all
                &lt;/Directory&gt;
                Options指令
                        --控制一个目录的访问特性
                        -None:
                        -All:
                        -ExecCGI:可以执行cgi脚本
                          -Indexes:访问一个无索引文件的目录时,返回一个文件                          列表
                AllowOverride指令
                        --".htaccess"文件中哪些设置允许覆盖先前的设置
                        -None:不读取.htaccess
                        -Limit:覆盖控制主机访问的指令(allow,deny)
                        -AuthConfig:允许覆盖跟认证有关指令                        (AuthType,AuthName)
                order指令
                        控制处理allow和deny指令的顺序
                        Ex:
                        order allow,deny
                        deny from all
                        allow from host11
                allow指令
                        对于一个目录来说,allow指令设置允许哪些主机访问
                        -all:所有主机
                        -域名:eloo.com
                        -一个完整IP:192.168.0.1
                        -网络号码/子网掩码:192.168.0.0/255.255.255.0
                        -网络号码/nnn:192.168.0.0/24
                deny指令
                        对于一个目录来说,allow指令设置禁止哪些主机访问
                        -all:所有主机
                        -域名:eloo.com
                        -一个完整IP:192.168.0.1
                        -网络号码/子网掩码:192.168.0.0/255.255.255.0
                        -网络号码/nnn:192.168.0.0/24
                         
5.Apache服务器的用户认证
                功能:只有合法的帐号名和密码才能访问到指定目录的内容
                1.建立用户数据库
                  格式:lpeng:BQ5DFS3%#$%
                        一般放在DocumentRoot以外的地方
                        #htpasswd -bc /etc/httpd/users user1 1234
                2.使用用户数据库
                        在要保护的目录中建立".htaccess"文件
                        Ex:
                        AuthName "会员区"
                        AuthType Basic
                        AuthUserFile /etc/httpd/users
                        require valid-user(requrie user &lt;username1&gt
                  注意:也可以建立一个用户组文件,然后在这里指定用户组
                        vi /etc/httpd/groups
                        teacher:jacky lpeng
                        Ex:
                        AuthName "会员区"
                        AuthType Basic
                        AuthGroupFile /etc/httpd/users
                        require group &lt;group1&gt;
                另一种情况:
                        Ex:
                        AuthName "会员区"
                        AuthType Basic
                        AuthGroupFile /etc/httpd/users
                        require group &lt;group1&gt;
                        Allow from
                        Deny from
                        satisfy all //同时使用两种,都满足才可
                        satisfy any        //符合一种即可

        使用php+mysql数据库来实现用户认证
       
6.用户Web目录
        Apache允许主机上的用户使用特定的目录存放用户自己的主页
        http://hostname/~username/
        一种方法
        UserDir public_html
        注意:此目录必须位于用户主目录下
        另种方法
        UserDir /home/httpd/*/httpd
7.虚拟主机
基于名字的虚拟主机
        &lt;VirtualHost 192.168.103.11&gt;
           ServerAdmin webmaster@host.some_domain.com
           DocumentRoot /home/eloo/a
           ServerName a.eloo.com
           ErrorLog /home/eloo/logs/host.some_domain.com-error_log
           CustomLog /home/eloo/logs/host.some_domain.com-access_log common
       &lt;/VirtualHost&gt;

       
实验:
        1.建立/home/httpd/htmlapachetest目录,并对其进行权限限制,使用户aa可以访问
        2.设置自己服务器上的个人主页空间
        3.设置本机域名mydomain.com
                主目录为/home/httpd/html
        再添加一别名为username.mydomain.com
                使其访问/home/username/html目录下的内容
posted @ 2008-02-18 10:50 华梦行 阅读(152) | 评论 (0)编辑 收藏
wget -q -O - https://rhn.redhat.com/help/new-cert.sh | /bin/bash
posted @ 2008-01-31 14:03 华梦行 阅读(178) | 评论 (0)编辑 收藏
<?xml version="1.0"?>
<!-- http://www.aeroflash.org/crossdomain.xml -->
<cross-domain-policy>
   <allow-access-from domain="192.168.1.120" />
   <allow-access-from domain="ser.wei.com" />
   <allow-access-from domain="www.myjust.com" />
   <allow-access-from domain="192.168.1.200" />
   <allow-access-from domain="192.168.1.110" />
   <allow-access-from domain="192.168.1.109" />
   <allow-access-from domain="192.168.1.2" />
</cross-domain-policy>
posted @ 2008-01-30 16:44 华梦行 阅读(196) | 评论 (0)编辑 收藏
Linux各个挂载点介绍
 
 

/bin              存放最常用的命令,此目录下的命令所有用户都有执行的权限
 

/boot             Linux系统引导目录,此目录保存系统启动时的内核文件和内核映像文件及启动时所需的其它文件
 
/dev              设备文件,保存所有的硬件设备文件,如硬盘设备文件,软驱、光驱设备文件等等
 
/etc              存放各种服务的配置文件,相当于Windows 2000的winnt目录
 
/home             各用宿主目录,相当于Windows 2000的“我的文档”
 
/lib              该目录用来存放系统动态链接共享库,几乎所用的应该程序都会用到该目录下的共享库
 
/mnt              挂载目录,用来临时挂载别的文件系统或者别的硬件设备(如光驱、软驱)
 
/proc             此目录信息是在内存中由系统自行产生的,存储了一些当前的进程ID号和CPU、内存的映射等
 
/sbin             系统管理员命令存放目录
 
/usr              最大的目录,用户的很多应该程序和文件都存放在此目录下
 
/usr/X1186        X-Windows目录,存放一些X-Windows的配置文件
 
/usr/include      系统头文件,存储一些C语言的头文件
 
/usr/src          Linux内核源代码,Linux系统所安装的内核源代码都保存在此
 
/usr/bin          对/bin目录的一些补充
 
/usr/sbin         对/sbin目录的一些补充
 
/var              大多数的日志存储目录和ftp,www服务的匿名访问目录
                  的根,在Linux工作一段时间后,此目录会比较大,应即时对此目录进行删除

/misc             autofs服务的目
 
/opt              用于存储第三方软件的目录
 
/tmp              临时文件的目录,用来存放不同程序执行时产生的临时文件
 
/lost+found       该目录在大多数情况下都是空的,但当实然停电或者非正常关机后,有些文件临时存入在此
 
/root             管理员的根目录,一般只有管理员才可以访问此目录
posted @ 2008-01-30 15:52 华梦行 阅读(562) | 评论 (0)编辑 收藏
标题: 急救:硬盘下安装red hat linux 9.0,提示未找到任何驱动!

Device Auto Ok
posted @ 2008-01-30 15:45 华梦行 阅读(442) | 评论 (0)编辑 收藏
../j_acegi_logout
_acegi_logout 映射是在哪里定义的呢? 各位大侠请不吝赐教
posted @ 2008-01-28 19:37 华梦行 阅读(506) | 评论 (2)编辑 收藏

项目管理是50 年代后期发展起来的一种计划管理方法,作为一门新兴的管理科学,正日益引起项目建设者的广泛重视,它是一种运用系统科学的原理对工程建设项目进行计划、组织和控制的系统管理方法。随着信息时代的到来,项目管理被广泛地应用各个行业和领域的项目中,并发挥着越来越重要的作用。

    但具体到信息技术类型的企业,有关的统计数据显示项目管理实施的效果并不理想。1997 年Garden Research Group 的调查结果显示:在美国,即使借助项目管理,90% 的IT 项目仍然不能在规定的时间和预算内完成。在国内,失败的IT项目也屡见不鲜。在项目管理理论发展的较为成熟的今天,会出现这样的局面至少说明在项目管理理论的实践运用中出现了一些问题。目前,国内的各行各业都开始了大规模的信息化建设,对于这些行业应用软件开发的项目,又该如何通过项目管理来保证项目的顺利推进呢?
    按照美国项目管理协会( PMI)的项目管理论,对项目的管理可以按照启动、规划、执行、控制和收尾这五个过程组来进行,关注的知识领域包括项目范围、进度、成本、质量、人力资源、沟通、风险、采购以及项目的整体管理。但是该项目管理理论是一个框架性的知识体系,且其针对的项目不仅仅是软件开发项目,而且针对项目的规模和大小,项目管理团队应该按照项目的特点对其建议的过程进行取舍,并辅以通用的一些管理和沟通技巧,以下,笔者结合自身的一些行业软件开发项目的管理经验,谈一下在行业应用软件开发中的项目管理的需要特别注意的地方和一些体会。
一、了解行业知识 -站在用户的角度考虑问题
对于大多行业软件项目来说,技术已不是项目成功的瓶颈。面对不同行业各具特色的行业知识,行业软件的开发决非技术可以解决问题的,要想成功地推进项目,就必须转变技术为先的观点,而是要站在用户的角度,看看用户需要的是什么。在行业软件开发中经常碰到的问题是用户后期的需求变更,首先,在项目前期,项目经理应该熟悉行业的背景,包括该行的相关政策、法规;客户信息化的现状、与上级、下级以及同级单位或者其他相关单位之间的业务关系等,为项目做一个明确的定位和边界划分;其次,在需求调研阶段,要学习以行业语言而不是计算机语言和客户对话。如在和客户进行需求调研的时候,如果不能对用户的业务背景、业务流程等知识有一些初步认识,是很难和用户做到深入的沟通的。如果调研的双方不能以相同的“语言”进行交流,又怎么能够真正了解业务的细节呢?对于一些特别复杂的业务,建议需求人员采取实习的方式,和具体的业务人员一同办理,观察业务的细节和工作人员的工作量消耗在什么地方,通过深入的学习和认真思考,将业务知识转化为信息流程。通过这样的工作,可以比较好地把握项目的范围,即使后期有一些变更,也基本能够进行控制;第三,在系统的功能设计和开发阶段,必须以用户的体验和以能够真正减轻用户的工作负担为出发点,而不是一味的考虑技术的先进性。即使系统采用的技术很先进,但如果信息化的结果不能真正减轻用户的工作负担,甚至加重用户的工作量,这样的系统用户肯定是不愿意用的。一些项目经理认为这样做会增加项目的成本,拖延项目的进度。但是如果在项目交付时才发现没有系统不满足需求、或者为适应实际的业务操作需要做大的变动,这种结果对项目的影响则是更为致命的。行业应用软件,应该是行业在先,软件在后,因此一个合格的项目经理,必须首先要理解这个软件的业务应用,并且有意识地在项目组中培养技术和行业相结合的人才,以提高项目组的业务能力。这样才能真正把握好业务需求,掌握业务模型并进行正确的项目开发。
    用户需求变更是所有项目团队都会遇到的问题,特别是有些行业的标准不规范或者不健全,使得在项目建设的过程中需求变化不断。事实上,需求变化是项目的常态,现代的项目管理理论认为对于变更应该采取更加主动地方式进行管理。要认识到项目的需求是在一个螺旋的过程中反复修改并不断完善的,需求分析本身就是为了协调开发方与客户之间对项目的认识。无论实现计划得多么周密,随着双方对项目认知的不断深化实践,项目的变更是不可避免的。在上一节的提到的方法有助于减少项目后期的需求变更,项目管理人员也可以采取一些更为主动的方法来管理需求变更。首先,要定期与用户交流系统的情况,例如以原型设计的方式与用户确认需求。很多用户虽然是行业专家,但他们并不清楚心目中的信息系统是以何种方式呈现的。这就需要项目开发人员尽早采取原型设计的方式来引导并确认需求。通过界面设计工具快速地设计出界面原型,使得用户看到具体的“实物”,这样可以使得用户更容易表达其真实的想法。在项目开发过程中,也应该定期将完成的功能以演示或者试用的方式与用户交流,听取用户对界面和功能设计方面的意见,及早发现可能出现的意见分歧,以免在项目后期才发现重大的偏差。不少项目组提交需求报告后就埋头进行系统的设计和开发,等到项目完成后才将系统提交给客户试用,结果造成用户对项目评价不高,或者系统完全不能适合用户当前的需求,甚至会因此影响双方的关系,结果给项目造成难以挽回的损失。其次,对已经发生的变更要认真的面对。记录用户提出的变更需求,并以书面的方式进行记录存档,并以集体决议的方式分析变更可能对项目造成的影响,并做出是否变更的决定,如果有可能的话尽可能邀请客户的项目负责人参与会议过程。根据对项目的影响程度,双方确定变更的内容对加以实施。总之,本着双方协商解决问题的态度以规范的流程处理项目中的变更,大部分的问题都是可以顺利解决的。

三、主动地沟通 -以团队精神做项目

    现在项目管理理论非常强调沟通能力对项目管理的重要性,良好的沟通能力是一名优秀的项目经理最重要的能力之一。随着软件规模的发展,以往凭着个人英雄主义的手工作坊形式越来越不适应当前软件项目的开发。在行业应用软件的开发中,通常我们是以一个团队的形式来完成一项任务,在这种群体的活动中沟通是无法避免的。项目经理大约上70%的时间用在各种形式的沟通上。开会、谈判、谈话、做报告是最常见的沟通形式,撰写报告实际上是一种书面沟通的方式,对外各种拜访、约见也都是沟通的表现形式。因此项目经理必须掌握有效的沟通技巧。许多项目经理是由技术人员转型发展而来的,往往以技术的观点看待问题,认为沟通只是浪费时间,又或者因为性格内向腼腆而不愿与客户沟通,这必然会对项目造成影响。因此项目经理要转变观念,积极有效的与客户沟通,解决项目可能存在的问题。在项目推进的过程中还要特别注意和项目组成员之间的沟通。项目常见的效率低下的问题,往往是有了问题后,大家没有沟通或不懂得沟通所引起的。另外,项目执行力差、领导力不强的问题,归根到底,都与沟通欠缺有直接的关系。以项目经理和项目组成员之间的关系为例,项目经理不仅仅应该关注组员个人的工作和绩效、职业规划等职业要素,还应该了解员工的想法、思想动态、日常管理中的问题和员工的意见、抱怨等等非职业要素。这看似与员工的业绩以及项目无关,但在实践过程中往往成为影响员工工作态度和项目结果的关键因素。在面临巨大、忙碌的项目压力时,项目组成员常常产生各种抱怨、动摇,这些都是正常的现象,项目经理应该特别注重员工的生活和思想动态,积极沟通,对出现的问题积极予以协助。通过有效沟通,可以提高项目成员的归属感,加速项目成员之间得磨合,打造一支有战斗力的项目团队。
    项目管理方法没有孰优孰劣,关键是根据项目的具体情况和外部环境的特点选择最适合的方法。以科学的项目管理理论为指导并在项目认真实践和探索,并不断吸取教训加以总结,就是项目管理的成功之道。
posted @ 2008-01-25 18:00 华梦行 阅读(96) | 评论 (0)编辑 收藏
/**********************
 * 用户-产品-订单模块
 **********************/

/*
    表名称: CUSTOMER(客户信息表)
    ID       (客户编号)
    NAME     (姓名)
    LOGINID  (登陆ID)
    PASSWD   (密码)
    EMAIL    (EMAIL)
    ADDRESS  (地址)
    STATUS   (状态)
*/
create table customer (
    id int not null identity,
    name varchar(80) not null,
    loginid varchar(20) not null,
    passwd varchar(255) not null,
    email varchar(80) null,
    address varchar(80) null,
    status varchar(20)  null,
    constraint pk_customer primary key (id)
);

/*
	表名称: CATEGORY(产品类别表)
	ID    (类别编码)
	NAME  (类别名)
	DESCN (描述)
	Primary Key: PK_CATEGORY PRIMARY KEY(ID)
*/
create table category (
	id int not null identity,
	name varchar(80) not null,
	descn varchar(255) null,
	constraint pk_category primary key (id)
);

/*
	表名称: PRODUCT(产品表)
	ID             (产品编码)
	CATEGORY_ID    (类别ID)
        NAME           (产品名称)
	DESCN          (描述)
	INVENTORY      (存货)
	UNITPRICE      (单价)
	STATUS         (状态)
	ATTR1          (自定义属性1)
	ATTR2          (自定义属性2)
	ATTR3          (自定义属性3)
	ATTR4          (自定义属性4)
	TYPE           (类型)
        CREATETIME     (创建的日期)
        CREATE_USER_ID (创建的操作员)
        MODIFYTIME     (最后一次修改的日期)
        MODIFY_USER_ID (最后一次修改的操作员)
	*/
create table product (
    id int not null identity,
    category_id int not null,
    name varchar(80) not null,
    descn varchar(255) null,
    inventory int null,
    unitprice decimal(10,2) null,
    status varchar(20) null,
    attr1 varchar(255) null,
    attr2 varchar(255) null,
    attr3 varchar(255) null,
    attr4 varchar(255) null,
    type varchar(20) default 'product',
    createtime date null,
    create_user_id int null,
    modifytime date null,
    modify_user_id int null,
    constraint pk_product primary key (id),
    constraint fk_product_1 foreign key (category_id)
    references category (id),
    constraint fk_product_2 foreign key (create_user_id)
    references users (id),
    constraint fk_product_3 foreign key (modify_user_id)
    references users (id)
);

/*
	表名称: ORDERS(订单信息表)
	ID             (订单编码)
	CUSTOMER_ID    (用户编码)
	ORDERDATE      (下订日期)
	TOTALPRICE     (总费用)
	ORIGINALPRICE   (原价格)
	APPLYRULES     (所使用的促销规则)
	REGION         (送货地区)
	SHIPADDR       (发货地址)
	SHIPDATE       (发货日期)
	STATUS         (订单状态)
*/
create table orders (
      id int not null identity,
      customer_id int not null,
      orderdate date not null,
      totalprice decimal(10,2) not null,
      originalprice decimal(10,2),
      applyRules varchar(255) ,
      region varchar(255),
      shipaddr varchar(80) ,
      shipdate date ,
      status varchar(2) default '1',
      constraint pk_orders primary key (id),
      constraint FK_ORDERS_1 foreign key (CUSTOMER_ID) REFERENCES CUSTOMER(ID)

);

/*
	表名称: ORDER_ITEM(订单货物表)
	ORDER_ID       (订单编码)
	LINENUM        (订单行号)
	PRODUCT_ID     (产品编码)
	QUANTITY       (数量)
	UNITPRICE      (单价)
*/
create table order_item (
      order_id int not null,
      linenum int not null,
      product_id int not null,
      quantity int not null,
      unitprice decimal(10,2) not null,
      constraint pk_orderitem primary key (order_id, linenum),
      constraint FK_ITEM_1 foreign key (ORDER_ID) REFERENCES orders(ID),
      constraint FK_ITEM_2 foreign key (PRODUCT_ID) REFERENCES PRODUCT(ID)
);

/****************************
 * 管理员及安全模块
 ****************************/

/*
	表名称: log4j_log(日志信息)
	ID             (序号)
	LOGINID        (登陆ID)
	PRIORITY       (级别)
	LOGDATE        (时间)
	CLASS          (类名)
	METHOD         (方法名)
	MSG            (信息)
*/
create table log4j_log(
      id int not null identity,
      loginid varchar(20) not null,
      priority varchar(10) not null,
      logdate varchar(21) not null,
      class   varchar(255) not null,
      method varchar(100) null,
      msg varchar(255) null,
      constraint pk_log4j_msg primary key (id)
);


/*
  表名称:change_history(领域对象修改记录)
*/
create table change_history(
    id int not null identity,
    entitytype varchar(20) not null,
    entityid   int not null,
    changeColumns varchar(255) null,
    constraint pk_product primary key (id)
);
/*
	表名称: users(用户)
	loginid 登陆ID
	passwd 密码
	name   用户名
	email  邮箱
	region 管理地区
	status 状态
	descn  用户描述
*/
create table users(
      id int not null identity,
      loginid varchar(20) not null,
      passwd varchar(255) not null,
      name varchar(80) not null,
      email varchar(255),
      region varchar(255),
      status VARCHAR(2) default 1,
      descn varchar(255) null,
      constraint pk_users primary key (id)
);

/*
	表名称: roles(角色)
	name 角色名称
	descn 角色描述
*/
create table roles(
      id int not null identity,
      name varchar(80) not null,
      descn varchar(255) null,
      constraint pk_roles primary key (id)
);

/*
  表名称:  user_role(用户角色表)
  user_id 用户ID
  role_id 角色ID
*/
create table user_role
(
  user_id int not null,
  role_id int not null,
  constraint pk_user_role primary key (user_id,role_id),
  constraint fk_user_role_1 foreign key (user_id) REFERENCES users(ID),
  constraint fk_user_role_2 foreign key (role_id) REFERENCES roles(ID)
);

/*
  表名称: permissions  (权限)
  name    权限名称
  descn   描述
  operation 操作
  status 状态
*/
create table permissions
(
  id            int not null identity,
  name          varchar(80) not null,
  descn         varchar(255) null,
  operation     varchar(80) null,
  status VARCHAR(2) default '1',
  constraint pk_permissons primary key (id)
);

/*
  表名称: role_permis(角色权限)
  role_id 角色ID
  permis_id 权限ID
*/
create table role_permis
(
  role_id int not null,
  permis_id int not null,
  constraint pk_role_permis primary key (role_id,permis_id),
  constraint fk_role_role_permis_1 foreign key (role_id) REFERENCES roles(ID),
  constraint fk_role_role_permis_2 foreign key (permis_id) REFERENCES permissions(ID)
);

/*
  表名称: resources  (资源)
  name  资源名称(模块名称)
  res_type 资源类型
  res_string 资源串
  descn  资源描述
*/
create table resources
(
  id            int not null identity,
  name          varchar(80) not null,
  res_type varchar(20) not null,
  res_string varchar(255) not null,
  descn         varchar(255) null,
  constraint pk_resources primary key (id)
);

/*
  表名称: permis_resc(权限资源)
  resource_id   资源ID
  operation_id  操作ID

*/
create table permis_resc
(
  permis_id  int not null,
  resc_id   int not null,
  constraint pk_permis_resc primary key (permis_id,resc_id),
  constraint fk_role_permis_resc_1 foreign key (resc_id) REFERENCES resources(ID),
  constraint fk_role_permis_resc_2 foreign key (permis_id) REFERENCES permissions(ID)
);

/*
  表名称: acl_object_identity(保护的ACLDomain对象列表)
  object_identity   受保护的ACL对象的标识符,一般是ClassName + ID
  parent_object  该对象关联的父对象
  acl_class  Acegi用来描述该类的Class,一般用来表示Mark等信息
*/
create table acl_object_identity (
  id            int not null identity,
  object_identity varchar(250) not null,
  parent_object integer,
  acl_class varchar(250) NOT NULL,
  constraint unique_object_identity unique(object_identity), 
  foreign key (parent_object) REFERENCES acl_object_identity(id)
);

/*
  表名称: permis_resc(ACL授权列表)
  acl_object_identity   对应acl_object_identity表的id,表示一个Acl保护的对象。
  recipient  用户名或角色名
  mask  所授权限
*/
create table acl_permission (
  id            int not null identity,
  acl_object_identity integer not null,
  recipient varchar(100) NOT NULL,
  mask integer not null,
  constraint unique_recipient unique(acl_object_identity, recipient),
  foreign key (acl_object_identity) REFERENCES acl_object_identity(id)
);
posted @ 2008-01-21 20:19 华梦行 阅读(201) | 评论 (0)编辑 收藏
ljava -classpath hsqldb.jar org.hsqldb.util.DatabaseManagerSwing
java -classpath hsqldb.jar org.hsqldb.Server -database.0 acl -dbname.0 acl
posted @ 2008-01-21 20:00 华梦行 阅读(127) | 评论 (0)编辑 收藏
private void bbslogin(String name,String pwd) {
  WebContext context = WebContextFactory.get();
  Cookie[] cookie1 = context.getHttpServletRequest().getCookies();
  if (cookie1 == null) {
   Cookie cookie = new Cookie("bbsUser", name);
   Cookie cookpwd=new Cookie("bbsPwd",pwd);
   cookie.setMaxAge(60*60*2);
   cookpwd.setMaxAge(60*60*2);
   cookpwd.setPath("/");
   cookie.setPath("/");
   context.getHttpServletResponse().addCookie(cookie);
  } else {
   for (int i = 0; i < cookie1.length; i++) {
    String vname = cookie1[i].getName();
    String value = cookie1[i].getValue();
    if (!vname.equals("bbsUser")) {
     Cookie cookie = new Cookie("bbsUser", name);
     Cookie cookpwd=new Cookie("bbsPwd",pwd);
     cookie.setMaxAge(60*60*2);
     cookpwd.setMaxAge(60*60*2);
     cookie.setPath("/");
     cookpwd.setPath("/");
     context.getHttpServletResponse().addCookie(cookie);
    }
   }
  }
 }
posted @ 2008-01-21 15:32 华梦行 阅读(155) | 评论 (0)编辑 收藏
<link rel=”icon” href=”/dir/favicon.ico” mce_href=”/dir/favicon.ico” type=”image/x-icon”>
<link rel=”shortcut icon” href=”/dir/favicon.ico” mce_href=”/dir/favicon.ico” type=”image/x-icon”>
posted @ 2008-01-19 15:40 华梦行 阅读(156) | 评论 (0)编辑 收藏
网上没有找到比较合适的,自己看了看,然后放到项目中实验的一下。
很多人都认为比DBCP优秀。

<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
      <property name="driverClass">
        <value>${jdbc.driverClassName}</value>
      </property>
      <property name="jdbcUrl">
        <value>${jdbc.url}</value>
      </property>
      <property name="user">
       <value>${jdbc.username}</value>
      </property>
      <property name="password">
       <value>${jdbc.password}</value>
      </property>
      <property name="initialPoolSize"><value>10</value></property>
      <property name="minPoolSize"><value>5</value></property>
      <property name="maxPoolSize"><value>30</value></property>
      <property name="acquireIncrement"><value>5</value></property>
      <property name="maxIdleTime"><value>10</value></property>
      <property name="maxStatements"><value>0</value></property>
    </bean>

以下几个参数是使用的基本配置参数:
initialPoolSize:
Number of Connections a pool will try to acquire upon startup. Should be between minPoolSize and maxPoolSize
连接池初始化时获取的链接数,介于minPoolSize和maxPoolSize之间

minPoolSize:
Minimum number of Connections a pool will maintain at any given time.
最小链接数

maxPoolSize:
Maximum number of Connections a pool will maintain at any given time.
最大连接数

acquireIncrement:
Determines how many connections at a time c3p0 will try to acquire when the pool is exhausted.
在当前连接数耗尽的时候,一次获取的新的连接数

maxIdleTime:
Seconds a Connection can remain pooled but unused before being discarded. Zero means idle connections never expire.
最大空闲的时间,单位是秒,无用的链接再过时后会被回收
posted @ 2008-01-18 19:47 华梦行 阅读(238) | 评论 (0)编辑 收藏
ALTER TABLE aUTHORITIES ADD constraint fk_authorities_users foreign key(username) references users(username)
posted @ 2008-01-15 12:12 华梦行 阅读(98) | 评论 (0)编辑 收藏
     摘要: 当前位置: 首页 >> 应用软件 >> 网络相关 >> Acegi安全系统详解   Acegi安全系统详解 作者:      来源:http://blog.csdn.ne...  阅读全文
posted @ 2008-01-14 20:19 华梦行 阅读(285) | 评论 (0)编辑 收藏
CREATE UNIQUE INDEX IX_mucgroupuser ON mucgroupuser(roomname,username)
在 sqlserver2000中你创建的一些约束都可以在查询分析器中直接看到
posted @ 2008-01-14 16:41 华梦行 阅读(167) | 评论 (0)编辑 收藏

解决webwork utf-8 乱码问题
起因:使用webwork+spring开发,出现提交数据乱码。

1,首先尝试修改webwork配制文件webwork.properties
webwork.locale=zh_CN
webwork.i18n.encoding=UTF-8
没有解决问题
2,再次尝试加入filter
 <filter>
  <filter-name>SetCharacterEncoding</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>UTF-8</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>SetCharacterEncoding</filter-name>
  <url-pattern>*.jsp</url-pattern>
 </filter-mapping>
 <filter-mapping>
  <filter-name>SetCharacterEncoding</filter-name>
  <url-pattern>*.action</url-pattern>
 </filter-mapping>
还是没有解决问题。
3,尝试更改提交方式 ,页面上加上  method="post"
问题解决。但是新问题出现,url中出现的中文依然是乱码
更改tomcat server.xml文件,在<Connector port="8080" >中加入URIEncoding="utf-8"问题解决,
但有更好的一种解决方案。就是用useBodyEncodingForURI="true"代替URIEncoding="utf-8"
这样tomcat会根据页面的编码去处理

posted @ 2008-01-13 14:49 华梦行 阅读(356) | 评论 (0)编辑 收藏
SELECT TOP 5 * FROM im_dh WHERE NOT EXISTS(SELECT * FROM (SELECT TOP 10 PID FROM  im_dh order by dhdt desc ) T  WHERE T.PID=im_dh.PID) order by dhdt desc

ibatis 中用$来设置动态参数
top  $start$ 

posted @ 2008-01-08 18:47 华梦行 阅读(921) | 评论 (0)编辑 收藏
 
添加如下代码:
out.clear();
out = pageContext.pushBody();
posted @ 2007-11-05 14:43 华梦行 阅读(410) | 评论 (0)编辑 收藏

     从网站上看到了有人提起这个框架——Guice,google名下的产物——一个彼Spring快的DI容器,兴趣使然,马上到http://code.google.com/p/google-guice/上去看了看,发现居然是Bob Lee这位大仙的杰作,还犹豫什么,download下来试试!

     恩,从哪里试起呢?还是老规矩,碰到新的东西就来验证我们经典的例子——Hello World!

     这个东西说是DI,居然没有.xml或者.properties文件,老天它用的是该死的Annotation,很好,要是大家也想尝试的话统统5.0或者以上的干活。安装好环境,开始动手!可是从哪里开始呢?既然说是DI容器,那好,我们先把我们的程序准备好,然后再看它把各个需要的东西怎么Inject。

     借鉴一下Spring开发手册里的例子吧,稍微改改(无聊的人不要骂这个程序,因为它太简单,我都想骂!)。既然是要打印,我们先来一个打印的服务接口:

 

public   interface  PrintService
{
    
public   void  print(String str);
}

 

很好,再来一个它的实现:

 

public   class  PrintServiceImpl  implements  PrintService
{

    
public   void  print(String str)
    {
        System.out.print(str);
    }

}

 

然后呢?一个打印客户Client:

 

public   class  Client
{
    
private  String str = " Hello world " ;
    
private  PrintService service;
     void  printString()
    {
        service.print(str);
    }

}

 

看到了么?这次Inject的不是那个该死的字符串“Hello World”,而是该死的打印服务!好了,Client和我们的打印服务是分开的,我不知道Guice会怎么把打印服务在Client需要的时候Inject进来。不管怎么做,一个test是应该有的:

 

import  junit.framework.TestCase;

public   class  testClient  extends  TestCase
{

    
public   void  testPrintString()
    {
        Client client
= new  Client();
        client.printString();
    }

}

 

好了,试试看,应该是红色的条子。废话,Client在这里根本不知道该死的打印服务在哪里。那么寻找打印服务就是Guice的事情了。

     让我们看看Guice是怎么进行Inject的。我们想要Client在使用的时候找到打印服务,那么我们应该在Client需要的时候将其Inject进去,这样的话我们需要写一个类似于setter的东西来建造一个Inject点,那么我们在Client里添加些东西:

 

import com.google.inject.Inject;
public   class  Client
{
    
private  String str = " Hello world " ;
    
private  PrintService service;
    @Inject
     void  injectPrintService(PrintService service)
    {
        
this .service = service;
    }

    
void  printString()
    {
        service.print(str);
    }

}

 

我们写入了一个injectPrintService方法,这个方法可以充当Inject点,然后我们在这个方法上面来一个Annotation——@Inject”,这就是告诉Guice应该在哪里Inject我们需要的打印服务。

     好了,我们下面要做的就是把PrintService和我们的实现动态的绑定起来(接口编程,好主意)。在Guice里,我们需要实现一个叫做Module的接口,Guice将一个binder传递给你的Module,然后你的Module将接口和它的实现绑定起来。让我们来试一下:

 

import  com.google.inject.Binder;
import  com.google.inject.Module;

public   class  MyModule  implements  Module
{

    
public   void  configure(Binder binder)
    {
        binder.bind(PrintService.
class ).to(PrintServiceImpl. class );
    }

}

 

在我们需要打印服务的时候,Guice会自动创建一个PrintServiceImpl的实例给我们。OK,接下来就是如何注入的问题了,我们需要在test中实现:

 

import  junit.framework.TestCase;
import  com.google.inject. * ;

public   class  testClient  extends  TestCase
{

    
public   void  testPrintString()
    {
        MyModule mo
= new  MyModule();
        Injector in
= Guice.createInjector(mo);
        Client client
= new  Client();
        in.injectMembers(client);
        client.printString();
    }

}

 

完了!一个全新的Hello world将要被打印出来了。

     Guice的工作流程是这样的:

首先将自己创建的Module传给Guice.createInjector(),Guice会为你的Module创建一个binder,你的Module利用这个binder来实现各种绑定,然后在Guice会创建一个Injector出来,我们就可以利用这个Injector来Inject我们的服务了。

   Guice将DI这个概念完完全全的诠释了出来,使我们在编写的应用的时候不必去考虑具体的实现在哪里,Guice会为你动态的绑定并且Inject的。很好使的框架,很有意思,以后继续关注!!

posted @ 2007-11-03 16:59 华梦行 阅读(110) | 评论 (0)编辑 收藏
 FileOutputStream fos = new FileOutputStream(logfile.toString(), false);
            logger = new PrintStream(fos, true);
            logger.println("Arale started at " + new java.util.Date());
posted @ 2007-10-31 16:53 华梦行 阅读(159) | 评论 (0)编辑 收藏
public class ssss {
   
    /** Creates a new instance of ssss */
    public ssss() {
    }
    public static void main(String s[]) throws IOException{
 //       java.net.URL  m=new java.net.URL("http://www.baidu.com/index.html");
   //     HttpURLConnection sst=(HttpURLConnection) m.openConnection();
//           DataInputStream in = new DataInputStream(connection.getInputStream());
  //          DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
      DataInputStream  tttt= new   DataInputStream((InputStream)new FileInputStream("c://ffffff.java.bak"));
  //      DataInputStream tttt=new DataInputStream(sst.getInputStream());
        DataOutputStream out = new DataOutputStream(new FileOutputStream("D://ffffff.java.bak"));
        byte[] buffer = new byte[4096];
        int count=0;
        while ((count = tttt.read(buffer))>0){
            out.write(buffer,0,count);
        }
        out.close();
        tttt.close();
    }
posted @ 2007-10-31 16:32 华梦行 阅读(186) | 评论 (0)编辑 收藏
http://www.java2s.com
http//www.dxiaoshuo.com
http://www.mdianying.com
posted @ 2007-10-26 16:51 华梦行 阅读(203) | 评论 (0)编辑 收藏

1.表名要以模块简称为前缀, 如:Bse_, Crm_, Sys_, Scm_, OA_, Mrp_, Ftm_等,后面部分与字段名称都尽量使用有意义的英文单词,第一个字母要大写,单词之间直接连接,不需要连接符号;

2.每个表必须要有主键,而且对经常使用的字段建立索引,除了必要的字段,尽可能设置字段允许为空而且不需要缺省值;

3.主键规则:对于经常增删的数据表,主键字段建议为varchar(36),用GUID生成,其它表原则上以性能为参考来建立主键,但要考虑可移植性,并发性与易初始化;主键本身在业务逻辑上不体现,不具有实际意义;

4.避免使用复合主键,只比较一个字段比比较多个字段快很多;

5.除了必要的冗余数据外,尽量避免冗余数据的出现,容易保证数据的一致性;

6.完全符合建立聚集索引要求:“既不能绝大多数都相同,又不能只有极少数相同”的规则;

7.用聚合索引比用不是聚合索引的主键速度快;

8.用聚合索引比用一般的主键作order by时速度快;

9.使用聚合索引内的字段,搜索时间会按数据占整个数据表的百分比成比例减少;

10.索引有助于提高检索性能,但过多或不当的索引也会导致系统低效,过多的索引甚至会导致索引碎片;

11.Like条件中,通配符%在字符串的开头使得索引无法使用;

12.OR条件,会引起全表扫描;

13.不推荐使用以下条件语句:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE;

14.IN 的作用相当与OR;

15.尽量少用NOT;

16.exists 和 in 的执行效率是一样的;

17.用函数charindex()和前面加通配符%的LIKE执行效率一样;

18.union在通常情况下比用or的效率要高的多,但如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多;

19.字段提取要按照“需多少、提多少”的原则,避免“select *”;

20.count(*)不比count(主键)慢,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总速度就越慢;

21.order by按聚集索引列排序效率最高;

22.高效的TOP,提高性能;

23.聚集索引有两个最大的优势:1、以最快的速度缩小查询范围;2、以最快的速度进行字段排序;

24.一定要将聚集索引建立在:1、您最频繁使用的、用以缩小查询范围的字段上;2、您最频繁使用的、需要排序的字段上;

25. 由于改变一个表的内容,将会引起索引的变化。频繁的insert,update,delete语句将导致系统花费较大的代价进行索引更新,引起整体性能的下降。一般来讲,在对查询性能的要求高于对数据维护性能要求时,应该尽量使用索引,否则,就要慎重考虑一下付出的代价;

26. 不同类型的索引效能是不一样的,应尽可能先使用效能高的,比如:数字类型的索引查找效率高于字符串类型,定长字符串char,nchar的索引效率高于变长字符串varchar,nvarchar的索引;

27. 有嵌套查询时,尽可能在内层过滤掉数据;

28. 多表关联查询时,需注意表顺序,并尽可能早的过滤掉数据,只将必须的数据带到后续的操作中去;

29. 任何对列的操作都导致全表扫描,如数据库函数、计算表达式等,查询时应尽可能将操作移至等号的某一边;

30. 存储过程如果有返回结果集的话, 就不能通过返回一个状态值来进行逻辑判断,否则会导致执行两次存储过程,影响性能;

31. Where条件中如果存在以下情况,则索引无效,严重影响性能: 索引列不要使用函数; 索引列不要使用NOT; 索引列不要用NULL; 不要对索引列进行计算;

posted @ 2007-10-26 15:34 华梦行 阅读(215) | 评论 (0)编辑 收藏

1. JSP页面的编码标准: UTF-8;

2. 有调用request对象的页面加上: <%request.setCharacterEncoding("UTF-8");%>;

3. 有调用response对象的页面加上: <%response.setCharacterEncoding("UTF-8");%>;

4. sendRedirect的调用需对中文等多字节参数进行编码: URLEncoder.encode(argname,"UTF-8");

5. 不要在页面中调用以下函数: out.close();

6. 不要在页面中调用以下函数: response.getOutputStream(),应该使用out对象,或者使用Servlet;

7. 页面文件转换为UTF-8文件的方法: 先用记事本打开,另存为UTF-8字符集, 加入编码UTF-8字符集, 然后再用NB IDE打开即可;

8. 不要调用标记为废弃的函数;

9. 所有可以点击查看内容的文字, 使用类: LinkText; 如: <span class="LinkText" ...

10. 取记录集显示时,循环中不能再进行数据库连接操作, 用Left Join或存储过程替换;

11. 程序文件目录与文件名称,命名一定要统一,采用JAVA的命名规则,用英文且大小写分开,同样功能的页面命名保持统一, 以便维护;

posted @ 2007-10-26 15:30 华梦行 阅读(237) | 评论 (0)编辑 收藏

1. 每个文件的头部注释: 版权说明、版本号、生成日期、作者、内容、功能、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明;

2. 函数头部应进行注释:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)、作者或修改人等;

3. 对变量的定义和分支语句(条件分支、循环语句等)必须编写注释;

4. 自己特有的命名风格,要自始至终保持一致,不可来回变化;

5. 类命名标准: 由两个或以上的相近意义的英文单词组成,首字母大写;

6. 一个类里面只能实现一个单据或一个功能的不同操作方面,尽可能减少类之间的耦合性;

7. 一些通用功能,都分类封装成不同的实用操作类;

8. 对以前的对象或函数重构或重命名时, 必须由修改人搜索以前的所有调用并替换,同时通知其它人以后使用新的调用;

9. 注释格式 /** * Setting to true will enable the display of debug information. * * @param d A boolean. * @return An Email. * @throws EmailException * @version Version * @author Author * @since 1.0 */

10. 类包规范: path.crm(itm,system,basic,oa,wms,mrp,scm).entity(manager),按模块分开类,同时实体类与操作类分开,映射文件跟实体类同目录;path.util下为实用类;Servlet映射为二级目录,目前为/path/system;

11. 页面不允许RS对象引用,全部用List或HashMap来实现;

12. 参数传递尽可能使用实体类, 没有实体类的使用HashMap;

13. 方法重载时, 可替换的不能使用重载;

14. 严格按照代码缩进格式进行代码书写,包括各种操作与分隔符号两边的空格;

15. 模糊搜索关键字,可以输入如"ab,abc"以逗号分隔的多个关键字进行搜索;

16. 变量命名规则: 数据类型简写+首字母大写的变量英文名称, 如果是全局变量加上小写g, 如: gszLimitString, gnModuleFlag, gnPageSize;

17. 程序中,SQL语句不能包含方括号, SQL语句中的表别名不能加AS,用空格代替;

18. SQL字符串,不能直接拼接字符串变量,用SET方法实现变量赋值,避免非法字符串变量引起安全问题;

19. 必须随时关闭所用的ResultSet,Statement对象,最好用finally实现,避免错误时没有关闭的问题;

20. 附件管理: 文件大小统一用text.formatFileSize()进行格式化;查看与下载链接用SPAN标签;

21. 其它详细的请参见公司的“软件编程规范检查”;

posted @ 2007-10-26 15:29 华梦行 阅读(147) | 评论 (0)编辑 收藏

1. 有"+"操作的字符串, 使用StringBuffer代替String;

2. 生成对象时,分配合理的空间和大小,如StringBuffer,Vector的初始化大小;

3. 优化循环体,避免在循环中生成同一个变量或调用同一个函数(参数变量也一样);

4. 尽量在使用时才创建该对象; 应该尽量重复使用一个对象,而不是声明新的同类对象;

5. 尽量使用局部变量; 尽量使用静态变量,从而使他所有的实例都共享这个变量;

6. 尽量减少方法的调用, 可事先判断, 同时用变量替换;

7. 尽量使用Java系统API,如复制大量数据时,使用System.arraycopy();

8. 尽可能使用带有Buffer的类代替没有Buffer的类;

9. 不用保存太多的信息在HttpSession中, 同时注意清除Session;

10. 大型数据量处理或批处理数据记录,尽量使用直接访问数据库的方法,用SQL直接存取数据;

11. 在生产环境下,禁止servlet和jsp的自动重载;

12. 插入下述“显式”计时代码,对程序进行评测:

long start = System.currentTimeMillis(); // 要计时的运算代码放在这儿,返回的时间以千分之一秒(1毫秒)为单位 long time = System.currentTimeMillis() - start;

13. 常用运算时间单位: 运算 示例 标准时间本地赋值 i=n; 1.0 实例赋值 this.i=n; 1.2 int增值 i++; 1.5 byte增值 b++; 2.0 short增值 s++; 2.0 float增值 f++; 2.0 double增值 d++; 2.0 空循环 while(true) n++; 2.0 三元表达式 (x<0) ?-x : x 2.2 算术调用 Math.abs(x); 2.5 数组赋值 a[0] = n; 2.7 long增值 l++; 3.5 方法调用 funct(); 5.9 throw或catch异常 try{ throw e; }或catch(e){} 320 同步方法调用 synchMehod(); 570 新建对象 new Object(); 980 新建数组 new int[10]; 3100

posted @ 2007-10-26 15:27 华梦行 阅读(265) | 评论 (0)编辑 收藏
多线程编程——基础篇 (二)

时间:2006-08-16
作者:axman
浏览次数: 3723
本文关键字:Java多线程线程线程对象单线程go deep into java
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章

  在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念。

[线程的并发与并行]

  在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent)。而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel)

  在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储如并发和并行这类术语,但我以我的经验能通俗地告诉大家它是怎么一回事,如果您看到我说的一些"标准"文档上说的不一样,只要意思一致,那您就不要挑刺了。

[JAVA线程对象]

  现在我们来开始考察JAVA中线程对象。

  在JAVA中,要开始一个线程,有两种方式。一是直接调用Thread实例的start()方法,二是
将Runable实例传给一个Thread实例然后调用它的start()方法。

  在前面已经说过,线程对象和线程是两个完全不同的概念。这里我们再次深入一下,生成一个线程的实例,并不代表启动了线程。而启动线程是说在某个线程对象上启动了该实例对应的线程,当该线程结束后,并不会就立即消失。

  对于从很多书籍上可以看到的基础知识我就不用多说了。既然是基础知识,我也着重于从普通文档上读不到的内容。所以本节我重点要说的是两种线程对象产生线程方式的区别。

class MyThread extends Thread{
  public int x = 0;
  
  public void run(){
    
    for(int i=0;i<100;i++){
      try{
        Thread.sleep(10);
      }catch(Exception e){}
      System.out.println(x++);
      
    }
  }
}

  如果我们生成MyThread的一个实例,然后调用它的start()方法,那么就产生了这个实例对应的线程:

public class Test {
  public static void main(String[] args) throws Exception{
    MyThread mt = new MyThread();
    mt.start();
  }
}

  不用说,最终会打印出0到99,现在我们稍微玩一点花样:

public class Test {
  public static void main(String[] args) throws Exception{
    MyThread mt = new MyThread();
    mt.start();
    System.out.println(101);
  }
}

  也不用说,在基础篇(一)中我们知道由于单CPU的原因,一般会先打印101,然后打印0到99。不过我们可以控制线程让它按我们的意思来运行:

public class Test {
  public static void main(String[] args) throws Exception{
    MyThread mt = new MyThread();
    mt.start();
    mt.join();
    System.out.println(101);
  }
}

  好了,我们终于看到,mt实例对应的线程(假如我有时说mt线程请你不要怪我,不过我尽量不这么说)。在运行完成后,主线程才打印101。因为我们让当前线程(这里是主线程)等待mt线程的运行结束。"在线程对象a上调用join()方法,就是让当前正在执行的线程等待线程对象a对应的线程运行完成后才继续运行。" 请大家一定要深刻理解并熟记这句话,而我这里引出这个知识点的目的是为了让你继续看下面的例子:

public class Test {
  public static void main(String[] args) throws Exception{
    MyThread mt = new MyThread();
    mt.start();
    mt.join();
    Thread.sleep(3000);
    mt.start();
  }
}

  当线程对象mt运行完成后,我们让主线程休息一下,然后我们再次在这个线程对象上启动线程。结果我们看到:

  Exception in thread "main" java.lang.IllegalThreadStateException

  也就是这种线程对象一时运行一次完成后,它就再也不能运行第二次了。我们可以看一下它有具体实现:

    public synchronized void start() {
        if (started)
            throw new IllegalThreadStateException();
        started = true;
        group.add(this);
        start0();
    }

  一个Thread的实例一旦调用start()方法,这个实例的started标记就标记为true,事实中不管这个线程后来有没有执行到底,只要调用了一次start()就再也没有机会运行了,这意味着:

[通过Thread实例的start(),一个Thread的实例只能产生一个线程]

  那么如果要在一个实例上产生多个线程(也就是我们常说的线程池),我们应该如何做呢?这就是Runnable接口给我们带来的伟大的功能。

class R implements Runnable{
  private int x = 0;
  public void run(){

    for(int i=0;i<100;i++){
      try{
        Thread.sleep(10);
      }catch(Exception e){}
      System.out.println(x++);

    }
  }
}

  
正如它的名字一样,Runnable的实例是可运行的,但它自己并不能直接运行,它需要被Thread对象来包装才行运行:

public class Test {
  public static void main(String[] args) throws Exception{
    new Thread(new R()).start();
  }
}

  当然这个结果和mt.start()没有什么区别。但如果我们把一个Runnable实例给Thread对象多次包装,我们就可以看到它们实际是在同一实例上启动线程:

public class Test {
  public static void main(String[] args) throws Exception{
    R r = new R();
    for(int i=0;i<10;i++)
      new Thread(r).start();
  }
}

  x是实例对象,但结果是x被加到了999,说明这10个线程是在同一个r对象上运行的。请大家注意,因为这个例子是在单CPU上运行的,所以没有对多个线程同时操作共同的对象进行同步。这里是为了说明的方便而简化了同步,而真正的环境中你无法预知程序会在什么环境下运行,所以一定要考虑同步。

  到这里我们做一个完整的例子来说明线程产生的方式不同而生成的线程的区别:

package debug;

import java.io.*;
import java.lang.Thread;


class MyThread extends Thread{
  public int x = 0;

  public void run(){
    System.out.println(++x);
  }
}

class R implements Runnable{
  private int x = 0;
  public void run(){
    System.out.println(++x);
  }
}

public class Test {
  public static void main(String[] args) throws Exception{
    
    for(int i=0;i<10;i++){
      Thread t = new MyThread();
      t.start();
    }
    Thread.sleep(10000);//让上面的线程运行完成
    R r = new R();
    for(int i=0;i<10;i++){
      Thread t = new Thread(r);
      t.start();
    }
  }
}

  上面10个线程对象产生的10个线程运行时打印了10次1。下面10个线程对象产生的10个线程运行时打印了1到10。我们把下面的10个线程称为同一实例(Runnable实例)的多个线程

  下节我们将研究线程对象方法,还是那句话,一般文档中可以读到的内容我不会介绍太多
请大家自己了解。

转载自dev2dev网友axman的go deep into java专栏。

个人自述

一个男人.
一个写程序的男人.
一个写程序并正在从程序中寻找快乐的男人.
一个写程序并正在从程序中寻找快乐并把快乐传递给大家的男人.

一个书生.
一个寂寞的书生.
一个寂寞的梅香竹影下敲声写韵的书生.
一个寂寞的梅香竹影下敲声写韵晨钟暮鼓中逸气扬剑的书生.

那个男人是位书生。没有人知道他的姓名,居无定所,行无定踪,亦耕变读,或渔或樵。
所以有人叫他樵夫(Axman),有人叫他渔郎(fisher)。

posted @ 2007-10-22 11:25 华梦行 阅读(235) | 评论 (0)编辑 收藏
多线程编程——基础篇 (一)

时间:2006-08-08
作者:axman
浏览次数: 5279
本文关键字:Java多线程线程线程对象单线程go deep into java
文章工具
推荐给朋友 推荐给朋友
打印文章 打印文章

  [写在前面]

  随着计算机技术的发展,编程模型也越来越复杂多样化。但多线程编程模型是目前计算机系统架构的最终模型。随着CPU主频的不断攀升,X86架构的硬件已经成为瓶,在这种架构的CPU主频最高为4G。事实上目前3.6G主频的CPU已经接近了顶峰。

  如果不能从根本上更新当前CPU的架构(在很长一段时间内还不太可能),那么继续提高CPU性能的方法就是超线程CPU模式。那么,作业系统、应用程序要发挥CPU的最大性能,就是要改变到以多线程编程模型为主的并行处理系统和并发式应用程序。

  所以,掌握多线程编程模型,不仅是目前提高应用性能的手段,更是下一代编程模型的核心思想。多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。从根本上说,这就是多线程编程的最终目的。

  [第一需要弄清的问题]

  如同程序和进程的区别,要掌握多线程编程,第一要弄清的问题是:线程对象和线程的区别

  线程对象是可以产生线程的对象。比如在java平台中Thread对象,Runnable对象。线程,是指正在执行的一个指点令序列。在java平台上是指从一个线程对象的start()开始,运行run方法体中的那一段相对独立的过程。

  鉴于作者的水平,无法用更确切的词汇来描述它们的定义。但这两个有本质区别的概念请初学者细细体会,随着介绍的深入和例程分析的增加,就会慢慢明白它们所代表的真实含义。

  天下难事必始于易,天下大事必始于细。

  让我们先从最简单的"单线程"来入手:(1)带引号说明只是相对而言的单线程,(2)基于java。

    class BeginClass{
        public static void main(String[] args){
            for(int i=0;i<100;i++)
                System.out.println("Hello,World!");
        }
    }

  如果我们成功编译了该java文件,然后在命令行上敲入:

  java BeginClass

  现在发生了什么呢?每一个java程序员,从他开始学习java的第一分钟里都会接触到这个问

  题,但是,你知道它到底发生发什么?

  JVM进程被启动,在同一个JVM进程中,有且只有一个进程,就是它自己。然后在这个JVM环境中,所有程序的运行都是以线程来运行。JVM最先会产生一个主线程,由它来运行指定程序的入口点。在这个程序中,就是主线程从main方法开始运行。当main方法结束后,主线程运行完成。JVM进程也随之退出。

  我们看到的是一个主线程在运行main方法,这样的只有一个线程执行程序逻辑的流程我们称

  之为单线程。这是JVM提供给我们的单线程环境,事实上,JVM底层还至少有垃圾回收这样的后台线程以及其它非java线程,但这些线程对我们而言不可访问,我们只认为它是单线程的。

  主线程是JVM自己启动的,在这里它不是从线程对象产生的。在这个线程中,它运行了main方法这个指令序列。理解它,但它没有更多可以研究的内容。

  [接触多线程]

    class MyThread extends Thread{
        public void run(){
            System.out.println("Thread say:Hello,World!");
        }
    }

    public class MoreThreads{
        public static void main(String[] args){
            new MyThread();
            new MyThread().start();
            System.out.println("Main say:Hello,World");
        }
    }

  执行这个程序,main方法第一行产生了一个线程对象,但并没有线程启动。

  main方法第二行产生了一个线程对象,并启动了一个线程。

  main方法第三行,产生并启动一个线程后,主线程自己也继续执行其它语句。

  我们先不研究Thread对象的具体内容,稍微来回想一下上面的两个概念,线程对象线程。在JAVA中,线程对象是JVM产生的一个普通的Object子类。而线程是CPU分配给这个对象的一个运行过程。我们说的这个线程在干什么,不是说一个线程对象在干什么,而是这个运行过程在干什么。如果一时想不明白,不要急,但你要记得它们不是一回事就行了。

  累了吧?为不么不继续了?

  基于这种风格来介绍多线程,并不是每个人都喜欢和接受的,如果你不喜欢,正好不浪费你的时间了,而如果你接受的话,那就看下一节吧。

  转载自dev2dev网友axman的go deep into java专栏

个人自述

一个男人.
一个写程序的男人.
一个写程序并正在从程序中寻找快乐的男人.
一个写程序并正在从程序中寻找快乐并把快乐传递给大家的男人.

一个书生.
一个寂寞的书生.
一个寂寞的梅香竹影下敲声写韵的书生.
一个寂寞的梅香竹影下敲声写韵晨钟暮鼓中逸气扬剑的书生.

那个男人是位书生。没有人知道他的姓名,居无定所,行无定踪,亦耕变读,或渔或樵。
所以有人叫他樵夫(Axman),有人叫他渔郎(fisher)。

posted @ 2007-10-22 11:17 华梦行 阅读(248) | 评论 (0)编辑 收藏

多线程设计要点

板桥里人 http://www.jdon.com 2002/01/10

 

1 .多线程中有主内存和工作内存之分, 在JVM中,有一个主内存,专门负责所有线程共享数据;而每个线程都有他自己私有的工作内存, 主内存和工作内存分贝在JVM的stack区和heap区。

2. 线程的状态有'Ready', 'Running', 'Sleeping', 'Blocked', 和 'Waiting'几个状态,
'Ready' 表示线程正在等待CPU分配允许运行的时间。

3. 线程运行次序并不是按照我们创建他们时的顺序来运行的,CPU处理线程的顺序是不确定的,如果需要确定,那么必须手工介入,使用setPriority()方法设置优先级。

4. 我们无从知道一个线程什么时候运行,两个或多个线程在访问同一个资源时,需要synchronized

5. 每个线程会注册自己,实际某处存在着对它的引用,因此,垃圾回收机制对它就“束手无策”了。

6. Daemon线程区别一般线程之处是:主程序一旦结束,Daemon线程就会结束。

7. 一个对象中的所有synchronized方法都共享一把锁,这把锁能够防止多个方法对通用内存同时进行的写操作。synchronized static方法可在一个类范围内被相互间锁定起来。

8. 对于访问某个关键共享资源的所有方法,都必须把它们设为synchronized,否则就不能正常工作。

9. 假设已知一个方法不会造成冲突,最明智的方法是不要使用synchronized,能提高些性能。

10 . 如果一个"同步"方法修改了一个变量,而我们的方法要用到这个变量(可能是只读),最好将自己的这个方法也设为 synchronized。

11. synchronized不能继承, 父类的方法是synchronized,那么其子类重载方法中就不会继承“同步”。

12. 线程堵塞Blocked有几个原因造成:

(1)线程在等候一些IO操作
(2)线程试图调用另外一个对象的“同步”方法,但那个对象处于锁定状态,暂时无法使用。

13. 原子型操作(atomic), 对原始型变量(primitive)的操作是原子型的atomic. 意味着这些操作是线程安全的, 但是大部分情况下,我们并不能正确使用,来看看 i = i + 1 , i是int型,属于原始型变量:

(1)从主内存中读取i值到本地内存.
(2)将值从本地内存装载到线程工作拷贝中.
(3)装载变量1.
(4)将i 加 1.
(5)将结果给变量i.
(6)将i保存到线程本地工作拷贝中.
(7)写回主内存.

注意原子型操作只限于第1步到第2步的读取以及第6到第7步的写, i的值还是可能被同时执行i=i+1的多线程中断打扰(在第4步)。

double 和long 变量是非原子型的(non-atomic)。数组是object 非原子型。

14. 由于13条的原因,我们解决办法是:

class xxx extends Thread{

//i会被经常修改
private int i;

public synchronized int read(){ return i;}

public synchronized void update(){ i = i + 1;}

..........

}

15. Volatile变量, volatile变量表示保证它必须是与主内存保持一致,它实际是"变量的同步", 也就是说对于volatile变量的操作是原子型的,如用在long 或 double变量前。

16. 使用yield()会自动放弃CPU,有时比sleep更能提升性能。

17. sleep()和wait()的区别是:wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步的方法或代码块内。

18. 通过制造缩小同步范围,尽可能的实现代码块同步,wait(毫秒数)可在指定的毫秒数可退出wait;对于wait()需要被notisfy()或notifyAll()踢醒。

19. 构造两个线程之间实时通信的方法分几步:
(1). 创建一个PipedWriter和一个PipedReader和它们之间的管道;
PipedReader in = new PipedReader(new PipedWriter())
(2). 在需要发送信息的线程开始之前,将外部的PipedWriter导向给其内部的Writer实例out
(3). 在需要接受信息的线程开始之前,将外部的PipedReader导向给其内部的Reader实例in
(4). 这样放入out的所有东西度可从in中提取出来。

20. synchronized带来的问题除性能有所下降外,最大的缺点是会带来死锁DeadLock,只有通过谨慎设计来防止死锁,其他毫无办法,这也是线程难以驯服的一个原因。不要再使用stop() suspend() resume()和destory()方法

21. 在大量线程被堵塞时,最高优先级的线程先运行。但是不表示低级别线程不会运行,运行概率小而已。

22. 线程组的主要优点是:使用单个命令可完成对整个线程组的操作。很少需要用到线程组。

23. 从以下几个方面提升多线程的性能:

检查所有可能Block的地方,尽可能的多的使用sleep或yield()以及wait();

尽可能延长sleep(毫秒数)的时间;

运行的线程不用超过100个,不能太多;

不同平台linux或windows以及不同JVM运行性能差别很大。

24. 推荐几篇相关英文文章:

posted @ 2007-10-22 10:21 华梦行 阅读(231) | 评论 (1)编辑 收藏
 名称 Java语言编码规范(Java Code Conventions)
 译者 晨光(Morning)
 简介 本文档讲述了Java语言的编码规范,较之陈世忠先生《c++编码规范》的浩繁详尽,此文当属短小精悍了。而其中所列之各项条款,从编码风格,到注意事项,不单只Java,对于其他语言,也都很有借鉴意义。因为简短,所以易记,大家不妨将此作为handbook,常备案头,逐一对验。
 声明 如需复制、传播,请附上本声明,谢谢。
原文出处:http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html,
译文出处:http://morningspace.51.net/,moyingzz@etang.com

 目录

1 介绍 2 文件名 3 文件组织 4 缩进排版 5 注释 6 声明 7 语句 8 空白 9 命名规范
10 编程惯例 11 代码范例

1 介绍(Introduction)

1.1 为什么要有编码规范(Why Have Code Conventions)

编码规范对于程序员而言尤为重要,有以下几个原因:

- 一个软件的生命周期中,80%的花费在于维护
- 几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护
- 编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码
- 如果你将源码作为产品发布,就需要确任它是否被很好的打包并且清晰无误,一如你已构建的其它任何产品

为了执行规范,每个软件开发人员必须一致遵守编码规范。每个人。

1.2 版权声明(Acknowledgments)

本文档反映的是Sun MicroSystems公司,Java语言规范中的编码标准部分。主要贡献者包括:Peter King,Patrick Naughton,Mike DeMoney,Jonni Kanerva,Kathy Walrath以及Scott Hommel。

本文档现由Scott Hommel维护,有关评论意见请发至shommel@eng.sun.com

2 文件名(File Names)

这部分列出了常用的文件名及其后缀。

2.1 文件后缀(File Suffixes)

Java程序使用下列文件后缀:

文件类别 文件后缀
Java源文件 .java
Java字节码文件 .class

2.2 常用文件名(Common File Names)

常用的文件名包括:

文件名 用途
GNUmakefile makefiles的首选文件名。我们采用gnumake来创建(build)软件。
README 概述特定目录下所含内容的文件的首选文件名

3 文件组织(File Organization)

一个文件由被空行分割而成的段落以及标识每个段落的可选注释共同组成。超过2000行的程序难以阅读,应该尽量避免。"Java源文件范例"提供了一个布局合理的Java程序范例。

3.1 Java源文件(Java Source Files)

每个Java源文件都包含一个单一的公共类或接口。若私有类和接口与一个公共类相关联,可以将它们和公共类放入同一个源文件。公共类必须是这个文件中的第一个类或接口。

Java源文件还遵循以下规则:

- 开头注释(参见"开头注释")
- 包和引入语句(参见"包和引入语句")
- 类和接口声明(参见"类和接口声明")

3.1.1 开头注释(Beginning Comments)

所有的源文件都应该在开头有一个C语言风格的注释,其中列出类名、版本信息、日期和版权声明:

  /*
   * Classname
   *
   * Version information
   *
   * Date
   *
   * Copyright notice
   */
	  

3.1.2 包和引入语句(Package and Import Statements)

在多数Java源文件中,第一个非注释行是包语句。在它之后可以跟引入语句。例如:

  package java.awt;

  import java.awt.peer.CanvasPeer;
	  

3.1.3 类和接口声明(Class and Interface Declarations)

下表描述了类和接口声明的各个部分以及它们出现的先后次序。参见"Java源文件范例"中一个包含注释的例子。

  类/接口声明的各部分 注解
1 类/接口文档注释(/**……*/) 该注释中所需包含的信息,参见"文档注释"
2 类或接口的声明  
3 类/接口实现的注释(/*……*/)如果有必要的话 该注释应包含任何有关整个类或接口的信息,而这些信息又不适合作为类/接口文档注释。
4 类的(静态)变量 首先是类的公共变量,随后是保护变量,再后是包一级别的变量(没有访问修饰符,access modifier),最后是私有变量。
5 实例变量 首先是公共级别的,随后是保护级别的,再后是包一级别的(没有访问修饰符),最后是私有级别的。
6 构造器  
7 方法 这些方法应该按功能,而非作用域或访问权限,分组。例如,一个私有的类方法可以置于两个公有的实例方法之间。其目的是为了更便于阅读和理解代码。

4 缩进排版(Indentation)

4个空格常被作为缩进排版的一个单位。缩进的确切解释并未详细指定(空格 vs. 制表符)。一个制表符等于8个空格(而非4个)。

4.1 行长度(Line Length)

尽量避免一行的长度超过80个字符,因为很多终端和工具不能很好处理之。

注意:用于文档中的例子应该使用更短的行长,长度一般不超过70个字符。

4.2 换行(Wrapping Lines)

当一个表达式无法容纳在一行内时,可以依据如下一般规则断开之:

- 在一个逗号后面断开
- 在一个操作符前面断开
- 宁可选择较高级别(higher-level)的断开,而非较低级别(lower-level)的断开
- 新的一行应该与上一行同一级别表达式的开头处对齐
- 如果以上规则导致你的代码混乱或者使你的代码都堆挤在右边,那就代之以缩进8个空格。

以下是断开方法调用的一些例子:

  someMethod(longExpression1, longExpression2, longExpression3, 
                   longExpression4, longExpression5);

  var = someMethod1(longExpression1, 
                            someMethod2(longExpression2, 
                                               longExpression3));
	  

以下是两个断开算术表达式的例子。前者更好,因为断开处位于括号表达式的外边,这是个较高级别的断开。

  longName1 = longName2 * (longName3 + longName4 - longName5)
                     + 4 * longname6; //PREFFER

  longName1 = longName2 * (longName3 + longName4 
                                         - longName5) + 4 * longname6; //AVOID
	  

以下是两个缩进方法声明的例子。前者是常规情形。后者若使用常规的缩进方式将会使第二行和第三行移得很靠右,所以代之以缩进8个空格

  //CONVENTIONAL INDENTATION
  someMethod(int anArg, Object anotherArg, String yetAnotherArg, 
                    Object andStillAnother) {
    ...
  }

  //INDENT 8 SPACES TO AVOID VERY DEEP INDENTS
  private static synchronized horkingLongMethodName(int anArg,
          Object anotherArg, String yetAnotherArg,
          Object andStillAnother) {
    ...
  }
	  

if语句的换行通常使用8个空格的规则,因为常规缩进(4个空格)会使语句体看起来比较费劲。比如:

  //DON’T USE THIS INDENTATION
  if ((condition1 && condition2)
      || (condition3 && condition4)
      ||!(condition5 && condition6)) { //BAD WRAPS
      doSomethingAboutIt();             //MAKE THIS LINE EASY TO MISS
  }

  //USE THIS INDENTATION INSTEAD
  if ((condition1 && condition2)
          || (condition3 && condition4)
          ||!(condition5 && condition6)) {
      doSomethingAboutIt();
  }

  //OR USE THIS
  if ((condition1 && condition2) || (condition3 && condition4)
          ||!(condition5 && condition6)) {
      doSomethingAboutIt();
  }
	  

这里有三种可行的方法用于处理三元运算表达式:

  alpha = (aLongBooleanExpression) ? beta : gamma;

  alpha = (aLongBooleanExpression) ? beta
                                   : gamma;

  alpha = (aLongBooleanExpression)
          ? beta
          : gamma;
	  

5 注释(Comments)

Java程序有两类注释:实现注释(implementation comments)和文档注释(document comments)。实现注释是那些在C++中见过的,使用/*...*/和//界定的注释。文档注释(被称为"doc comments")是Java独有的,并由/**...*/界定。文档注释可以通过javadoc工具转换成HTML文件。

实现注释用以注释代码或者实现细节。文档注释从实现自由(implementation-free)的角度描述代码的规范。它可以被那些手头没有源码的开发人员读懂。

注释应被用来给出代码的总括,并提供代码自身没有提供的附加信息。注释应该仅包含与阅读和理解程序有关的信息。例如,相应的包如何被建立或位于哪个目录下之类的信息不应包括在注释中。

在注释里,对设计决策中重要的或者不是显而易见的地方进行说明是可以的,但应避免提供代码中己清晰表达出来的重复信息。多余的的注释很容易过时。通常应避免那些代码更新就可能过时的注释。

注意:频繁的注释有时反映出代码的低质量。当你觉得被迫要加注释的时候,考虑一下重写代码使其更清晰。

注释不应写在用星号或其他字符画出来的大框里。注释不应包括诸如制表符和回退符之类的特殊字符。

5.1 实现注释的格式(Implementation Comment Formats)

程序可以有4种实现注释的风格:块(block)、单行(single-line)、尾端(trailing)和行末(end-of-line)。

5.1.1 块注释(Block Comments)

块注释通常用于提供对文件,方法,数据结构和算法的描述。块注释被置于每个文件的开始处以及每个方法之前。它们也可以被用于其他地方,比如方法内部。在功能和方法内部的块注释应该和它们所描述的代码具有一样的缩进格式。

块注释之首应该有一个空行,用于把块注释和代码分割开来,比如:

  /*
   * Here is a block comment.
   */
	  

块注释可以以/*-开头,这样indent(1)就可以将之识别为一个代码块的开始,而不会重排它。

  /*-
    * Here is a block comment with some very special
    * formatting that I want indent(1) to ignore.
    *
    *    one
    *        two
    *            three
    */
	  

注意:如果你不使用indent(1),就不必在代码中使用/*-,或为他人可能对你的代码运行indent(1)作让步。

参见"文档注释"

5.1.2 单行注释(Single-Line Comments)

短注释可以显示在一行内,并与其后的代码具有一样的缩进层级。如果一个注释不能在一行内写完,就该采用块注释(参见"块注释")。单行注释之前应该有一个空行。以下是一个Java代码中单行注释的例子:

  if (condition) {

    /* Handle the condition. */
    ...
  }
	  

5.1.3 尾端注释(Trailing Comments)

极短的注释可以与它们所要描述的代码位于同一行,但是应该有足够的空白来分开代码和注释。若有多个短注释出现于大段代码中,它们应该具有相同的缩进。

以下是一个Java代码中尾端注释的例子:

  if (a == 2) {
      return TRUE;              /* special case */
  } else {
      return isPrime(a);         /* works only for odd a */
  }
	  

5.1.4 行末注释(End-Of-Line Comments)

注释界定符"//",可以注释掉整行或者一行中的一部分。它一般不用于连续多行的注释文本;然而,它可以用来注释掉连续多行的代码段。以下是所有三种风格的例子:

  if (foo > 1) {

      // Do a double-flip.
      ...
  }
  else {
      return false;          // Explain why here.
  }

  //if (bar > 1) {
  //
  //    // Do a triple-flip.
  //    ...
  //}
  //else {
  //    return false;
  //}
	  

5.2 文档注释(Documentation Comments)

注意:此处描述的注释格式之范例,参见"Java源文件范例"

若想了解更多,参见"How to Write Doc Comments for Javadoc",其中包含了有关文档注释标记的信息(@return, @param, @see):

http://java.sun.com/javadoc/writingdoccomments/index.html

若想了解更多有关文档注释和javadoc的详细资料,参见javadoc的主页:

http://java.sun.com/javadoc/index.html

文档注释描述Java的类、接口、构造器,方法,以及字段(field)。每个文档注释都会被置于注释定界符/**...*/之中,一个注释对应一个类、接口或成员。该注释应位于声明之前:

  /**
    * The Example class provides ...
    */
  public class Example { ...
	  

注意顶层(top-level)的类和接口是不缩进的,而其成员是缩进的。描述类和接口的文档注释的第一行(/**)不需缩进;随后的文档注释每行都缩进1格(使星号纵向对齐)。成员,包括构造函数在内,其文档注释的第一行缩进4格,随后每行都缩进5格。

若你想给出有关类、接口、变量或方法的信息,而这些信息又不适合写在文档中,则可使用实现块注释(见5.1.1)或紧跟在声明后面的单行注释(见5.1.2)。例如,有关一个类实现的细节,应放入紧跟在类声明后面的实现块注释中,而不是放在文档注释中。

文档注释不能放在一个方法或构造器的定义块中,因为Java会将位于文档注释之后的第一个声明与其相关联。

6 声明(Declarations)

6.1 每行声明变量的数量(Number Per Line)

推荐一行一个声明,因为这样以利于写注释。亦即,

  int level;  // indentation level
  int size;   // size of table
	  

要优于,

int level, size;

不要将不同类型变量的声明放在同一行,例如:

  int foo,  fooarray[];   //WRONG!
	  

注意:上面的例子中,在类型和标识符之间放了一个空格,另一种被允许的替代方式是使用制表符:

  int		level;         // indentation level
  int		size;          // size of table
  Object	currentEntry;  // currently selected table entry
	  

6.2 初始化(Initialization)

尽量在声明局部变量的同时初始化。唯一不这么做的理由是变量的初始值依赖于某些先前发生的计算。

6.3 布局(Placement)

只在代码块的开始处声明变量。(一个块是指任何被包含在大括号"{"和"}"中间的代码。)不要在首次用到该变量时才声明之。这会把注意力不集中的程序员搞糊涂,同时会妨碍代码在该作用域内的可移植性。

  void myMethod() {
      int int1 = 0;         // beginning of method block

      if (condition) {
          int int2 = 0;     // beginning of "if" block
          ...
      }
  }
	  

该规则的一个例外是for循环的索引变量

  for (int i = 0; i < maxLoops; i++) { ... }
	  

避免声明的局部变量覆盖上一级声明的变量。例如,不要在内部代码块中声明相同的变量名:

  int count;
  ...
  myMethod() {
      if (condition) {
          int count = 0;     // AVOID!
          ...
      }
      ...
  }
	  

6.4 类和接口的声明(Class and Interface Declarations)

当编写类和接口是,应该遵守以下格式规则:

- 在方法名与其参数列表之前的左括号"("间不要有空格
- 左大括号"{"位于声明语句同行的末尾
- 右大括号"}"另起一行,与相应的声明语句对齐,除非是一个空语句,"}"应紧跟在"{"之后

  class Sample extends Object {
      int ivar1;
      int ivar2;

      Sample(int i, int j) {
          ivar1 = i;
          ivar2 = j;
      }

      int emptyMethod() {}

      ...
  }
	  
- 方法与方法之间以空行分隔

7 语句(Statements)

7.1 简单语句(Simple Statements)

每行至多包含一条语句,例如:

  argv++;       // Correct
  argc--;       // Correct
  argv++; argc--;       // AVOID!
	  

7.2 复合语句(Compound Statements)

复合语句是包含在大括号中的语句序列,形如"{ 语句 }"。例如下面各段。

- 被括其中的语句应该较之复合语句缩进一个层次
- 左大括号"{"应位于复合语句起始行的行尾;右大括号"}"应另起一行并与复合语句首行对齐。
- 大括号可以被用于所有语句,包括单个语句,只要这些语句是诸如if-else或for控制结构的一部分。这样便于添加语句而无需担心由于忘了加括号而引入bug。

7.3 返回语句(return Statements)

一个带返回值的return语句不使用小括号"()",除非它们以某种方式使返回值更为显见。例如:

  return;

  return myDisk.size();

  return (size ? size : defaultSize);
	  

7.4 if,if-else,if else-if else语句(if, if-else, if else-if else Statements)

if-else语句应该具有如下格式:

  if (condition) {
      statements;
  }

  if (condition) {
      statements;
  } else {
      statements;
  }

  if (condition) {
      statements;
  } else if (condition) {
      statements;
  } else{
      statements;
  }
	  

注意:if语句总是用"{"和"}"括起来,避免使用如下容易引起错误的格式:

  if (condition) //AVOID! THIS OMITS THE BRACES {}!
      statement;
	  

7.5 for语句(for Statements)

一个for语句应该具有如下格式:

  for (initialization; condition; update) {
      statements;
  }
	  

一个空的for语句(所有工作都在初始化,条件判断,更新子句中完成)应该具有如下格式:

  for (initialization; condition; update);
	  

当在for语句的初始化或更新子句中使用逗号时,避免因使用三个以上变量,而导致复杂度提高。若需要,可以在for循环之前(为初始化子句)或for循环末尾(为更新子句)使用单独的语句。

7.6 while语句(while Statements)

一个while语句应该具有如下格式

  while (condition) {
      statements;
  }
	  

一个空的while语句应该具有如下格式:

  while (condition);
	  

7.7 do-while语句(do-while Statements)

一个do-while语句应该具有如下格式:

  do {
      statements;
  } while (condition);
	  

7.8 switch语句(switch Statements)

一个switch语句应该具有如下格式:

  switch (condition) {
  case ABC:
      statements;
      /* falls through */
  case DEF:
      statements;
      break;

  case XYZ:
      statements;
      break;

  default:
      statements;
      break;
  }
	  

每当一个case顺着往下执行时(因为没有break语句),通常应在break语句的位置添加注释。上面的示例代码中就包含注释/* falls through */。

7.9 try-catch语句(try-catch Statements)

一个try-catch语句应该具有如下格式:

  try {
      statements;
  } catch (ExceptionClass e) {
      statements;
  }
	  

一个try-catch语句后面也可能跟着一个finally语句,不论try代码块是否顺利执行完,它都会被执行。

  try {
      statements;
  } catch (ExceptionClass e) {
      statements;
  } finally {
      statements;
  }
	  

8 空白(White Space)

8.1 空行(Blank Lines)

空行将逻辑相关的代码段分隔开,以提高可读性。

下列情况应该总是使用两个空行:

- 一个源文件的两个片段(section)之间
- 类声明和接口声明之间

下列情况应该总是使用一个空行:

- 两个方法之间
- 方法内的局部变量和方法的第一条语句之间
- 块注释(参见"5.1.1")或单行注释(参见"5.1.2")之前
- 一个方法内的两个逻辑段之间,用以提高可读性

8.2 空格(Blank Spaces)

下列情况应该使用空格:

- 一个紧跟着括号的关键字应该被空格分开,例如:

  while (true) {
      ...
  }
	  
注意:空格不应该置于方法名与其左括号之间。这将有助于区分关键字和方法调用。
- 空白应该位于参数列表中逗号的后面
- 所有的二元运算符,除了".",应该使用空格将之与操作数分开。一元操作符和操作数之间不因该加空格,比如:负号("-")、自增("++")和自减("--")。例如:
    a += c + d;
    a = (a + b) / (c * d);

    while (d++ = s++) {
        n++;
    }
    printSize("size is " + foo + "\n");
	  
- for语句中的表达式应该被空格分开,例如:
    for (expr1; expr2; expr3)
	  
- 强制转型后应该跟一个空格,例如:
    myMethod((byte) aNum, (Object) x);
    myMethod((int) (cp + 5), ((int) (i + 3)) + 1);
	  

9 命名规范(Naming Conventions)

命名规范使程序更易读,从而更易于理解。它们也可以提供一些有关标识符功能的信息,以助于理解代码,例如,不论它是一个常量,包,还是类。

标识符类型命名规则例子
包(Packages)一个唯一包名的前缀总是全部小写的ASCII字母并且是一个顶级域名,通常是com,edu,gov,mil,net,org,或1981年ISO 3166标准所指定的标识国家的英文双字符代码。包名的后续部分根据不同机构各自内部的命名规范而不尽相同。这类命名规范可能以特定目录名的组成来区分部门(department),项目(project),机器(machine),或注册名(login names)。com.sun.eng
com.apple.quicktime.v2
edu.cmu.cs.bovik.cheese
类(Classes)命名规则:类名是个一名词,采用大小写混合的方式,每个单词的首字母大写。尽量使你的类名简洁而富于描述。使用完整单词,避免缩写词(除非该缩写词被更广泛使用,像URL,HTML)class Raster;
class ImageSprite;
接口(Interfaces)命名规则:大小写规则与类名相似interface RasterDelegate;
interface Storing;
方法(Methods)方法名是一个动词,采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。run();
runFast();
getBackground();
变量(Variables)除了变量名外,所有实例,包括类,类常量,均采用大小写混合的方式,第一个单词的首字母小写,其后单词的首字母大写。变量名不应以下划线或美元符号开头,尽管这在语法上是允许的。
变量名应简短且富于描述。变量名的选用应该易于记忆,即,能够指出其用途。尽量避免单个字符的变量名,除非是一次性的临时变量。临时变量通常被取名为i,j,k,m和n,它们一般用于整型;c,d,e,它们一般用于字符型。
char c;
int i;
float myWidth;
实例变量(Instance Variables)大小写规则和变量名相似,除了前面需要一个下划线int _employeeId;
String _name;
Customer _customer;
常量(Constants)类常量和ANSI常量的声明,应该全部大写,单词间用下划线隔开。(尽量避免ANSI常量,容易引起错误)static final int MIN_WIDTH = 4;
static final int MAX_WIDTH = 999;
static final int GET_THE_CPU = 1;

10 编程惯例(Programming Practices)

10.1 提供对实例以及类变量的访问控制(Providing Access to Instance and Class Variables)

若没有足够理由,不要把实例或类变量声明为公有。通常,实例变量无需显式的设置(set)和获取(gotten),通常这作为方法调用的边缘效应 (side effect)而产生。

一个具有公有实例变量的恰当例子,是类仅作为数据结构,没有行为。亦即,若你要使用一个结构(struct)而非一个类(如果java支持结构的话),那么把类的实例变量声明为公有是合适的。

10.2 引用类变量和类方法(Referring to Class Variables and Methods)

避免用一个对象访问一个类的静态变量和方法。应该用类名替代。例如:

  classMethod();             //OK
  AClass.classMethod();      //OK
  anObject.classMethod();    //AVOID!
	  

10.3 常量(Constants)

位于for循环中作为计数器值的数字常量,除了-1,0和1之外,不应被直接写入代码。

10.4 变量赋值(Variable Assignments)

避免在一个语句中给多个变量赋相同的值。它很难读懂。例如:

  fooBar.fChar = barFoo.lchar = 'c'; // AVOID!
	  

不要将赋值运算符用在容易与相等关系运算符混淆的地方。例如:

  if (c++ = d++) {        // AVOID! (Java disallows)
      ...
  }
	  

应该写成

  if ((c++ = d++) != 0) {
    ...
  }
	  

不要使用内嵌(embedded)赋值运算符试图提高运行时的效率,这是编译器的工作。例如:

  d = (a = b + c) + r;        // AVOID!
	  

应该写成

  a = b + c;
  d = a + r;
	  

10.5 其它惯例(Miscellaneous Practices)

10.5.1 圆括号(Parentheses)

一般而言,在含有多种运算符的表达式中使用圆括号来避免运算符优先级问题,是个好方法。即使运算符的优先级对你而言可能很清楚,但对其他人未必如此。你不能假设别的程序员和你一样清楚运算符的优先级。

  if (a == b && c == d)     // AVOID!
  if ((a == b) && (c == d))  // RIGHT
	  

10.5.2 返回值(Returning Values)

设法让你的程序结构符合目的。例如:

  if (booleanExpression) {
      return true;
  } else {
      return false;
  }
	  

应该代之以如下方法:

  return booleanExpression;
	  

类似地:

  if (condition) {
      return x;
  }
  return y;
	  

应该写做:

  return (condition ? x : y);
	  

10.5.3 条件运算符"?"前的表达式(Expressions before '?' in the Conditional Operator)

如果一个包含二元运算符的表达式出现在三元运算符" ? : "的"?"之前,那么应该给表达式添上一对圆括号。例如:

  (x >= 0) ? x : -x;
	  

10.5.4 特殊注释(Special Comments)

在注释中使用XXX来标识某些未实现(bogus)的但可以工作(works)的内容。用FIXME来标识某些假的和错误的内容。

11 代码范例(Code Examples)

11.1 Java源文件范例(Java Source File Example)

下面的例子,展示了如何合理布局一个包含单一公共类的Java源程序。接口的布局与其相似。更多信息参见"类和接口声明"以及"文挡注释"。

/*
 * @(#)Blah.java        1.82 99/03/18
 *
 * Copyright (c) 1994-1999 Sun Microsystems, Inc.
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 */


package java.blah;

import java.blah.blahdy.BlahBlah;

/**
 * Class description goes here.
 *
 * @version 	1.82 18 Mar 1999
 * @author 	Firstname Lastname
 */
public class Blah extends SomeClass {
    /* A class implementation comment can go here. */

    /** classVar1 documentation comment */
    public static int classVar1;

    /**
     * classVar2 documentation comment that happens to be
     * more than one line long
     */
    private static Object classVar2;

    /** instanceVar1 documentation comment */
    public Object instanceVar1;

    /** instanceVar2 documentation comment */
    protected int instanceVar2;

    /** instanceVar3 documentation comment */
    private Object[] instanceVar3;

    /**
     * ...constructor Blah documentation comment...
     */
    public Blah() {
        // ...implementation goes here...
    }

    /**
     * ...method doSomething documentation comment...
     */
    public void doSomething() {
        // ...implementation goes here...
    }

    /**
     * ...method doSomethingElse documentation comment...
     * @param someParam description
     */
    public void doSomethingElse(Object someParam) {
        // ...implementation goes here...
    }
}
	  
posted @ 2007-10-15 11:21 华梦行 阅读(130) | 评论 (0)编辑 收藏
世界上并没有成为高手的捷径,但一些基本原则是可以遵循的。  

1、扎实的基础  


  数据结构、离散数学、编译原理,这些是所有计算机科学的基础,如果不掌握它们,很难写出高水平的程序。程序人人都会写,但当你发现写到一定程度很难再提高的时候,就应该想想是不是要回过头来学学这些最基本的理论。不要一开始就去学OOP,即使你再精通OOP,遇到一些基本算法的时候可能也会束手无策。因此多读一些计算机基础理论方面的书籍是非常有必要的。  


2、丰富的想像力  


  不要拘泥于固定的思维方式,遇到问题的时候要多想几种解决问题的方案,试试别人从没想过的方法。丰富的想像力是建立在丰富的知识的基础上,除计算机以外,多涉猎其他的学科,比如天文、物理、数学等等。开阔的思维对程序员来说很重要。  


3、最简单的是最好的  


  这也许是所有科学都遵循的一条准则,复杂的质能转换原理在爱因斯坦眼里不过是一个简单得不能再简单的公式:E=mc2。简单的方法更容易被人理解,更容易实现,也更容易维护。遇到问题时要优先考虑最简单的方案,只有简单方案不能满足要求时再考虑复杂的方案。  


4、不钻牛角尖  


  当你遇到障碍的时候,不妨暂时远离电脑,看看窗外的风景,听听轻音乐,和朋友聊聊天。当我遇到难题的时候会去玩游戏,当负责游戏的那部分大脑细胞极度亢奋的时候,负责编程的那部分大脑细胞就得到了充分的休息。当重新开始工作的时候,我会发现那些难题现在竟然可以迎刃而解。  


  5、对答案的渴求  


  人类自然科学的发展史就是一个渴求得到答案的过程,即使只能知道答案的一小部分也值得我们去付出。只要你坚定信念,一定要找到问题的答案,你才会付出精力去探索,即使最后没有得到答案,在过程中你也会学到很多东西。  


  6、多与别人交流  


  三人行必有我师,也许在一次和别人不经意的谈话中,就可以迸出灵感的火花。多上上网,看看别人对同一问题的看法,会给你很大的启发。  


  7、良好的编程风格  


  注意养成良好的习惯,代码的缩进编排,变量的命名规则要始终保持一致。大家都知道如何排除代码中错误,却往往忽视了对注释的排错。注释是程序的一个重要组成部分,它可以使你的代码更容易理解,而如果代码已经清楚地表达了你的思想,就不必再加注释了,如果注释和代码不一致,那就更加糟糕。  


  8、韧性和毅力  


  这也许是“高手”和一般程序员最大的区别。高手们并不是天才,他们是在无数个日日夜夜中磨炼出来的。成功能给我们带来无比的喜悦,但过程却是无比的枯燥乏味。你不妨做个测试,找个10000以内的素数表,把它们全都抄下来,然后再检查三遍,如果能够不间断地完成这一工作,你就可以满足这一条。
posted @ 2007-10-15 11:09 华梦行 阅读(98) | 评论 (0)编辑 收藏
select S_10994_1_SYS_MODELTYPE.nextval,a.typeid,'SYS','Mail_Forward','邮件转发模板','Mail Forward Model' from
bse_organization a where not exists (select orgtypeid from SYS_MODELTYPE b where b.orgtypeid=a.typeid and modelcode ='Mail_Forward')
--

select S_10994_1_SYS_MODELTYPE.nextval,typeid,'SYS','Mail_Forward','邮件转发模板','Mail Forward Model' from
bse_organization where typeid not in (
select orgtypeid from SYS_MODELTYPE where modelcode='Mail_Forward'
)

请注意not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的BUG:


请看下面的例子:
create table t1 (c1 number,c2 number);
create table t2 (c1 number,c2 number);

insert into t1 values (1,2);
insert into t1 values (1,3);
insert into t2 values (1,2);
insert into t2 values (1,null);

select * from t1 where c2 not in (select c2 from t2);
no rows found
select * from t1 where not exists (select 1 from t2 where t1.c2=t2.c2);
c1 c2
1 3

正如所看到的,not in 出现了不期望的结果集,存在逻辑错误。如果看一下上述两个select语句的执行计划,也会不同。后者使用了hash_aj。
因此,请尽量不要使用not in(它会调用子查询),而尽量使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录,正如上面例子所示。
除非子查询字段有非空限制,这时可以使用not in ,并且也可以通过提示让它使用hasg_aj或merge_aj连接。

posted @ 2007-10-11 16:51 华梦行 阅读(182) | 评论 (0)编辑 收藏

public class PlatContextListener implements ServletContextListener{
    private Timer timer = null;
    /** 应用程序的根目录 */
    private static String contextPath = null;
   
    /** Creates a new instance of PlatContextListener */
    public PlatContextListener() {
    }

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext sc = sce.getServletContext();
        contextPath = sc.getRealPath("").replace("\\", "/");
       
        int nInterval=24*60*60*1000;
       
        timer = new Timer(true);
       
        //每天零晨3点执行清理工作
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY,3);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        Date time = calendar.getTime();
   
        timer.scheduleAtFixedRate(new PlatTimerClearTask(), time,nInterval);
       

    }

    public void contextDestroyed(ServletContextEvent sce) {
        timer.cancel();
    }
   
    public static String getContextPath() {
        return contextPath;
    }
   
}

posted @ 2007-10-11 14:50 华梦行 阅读(160) | 评论 (0)编辑 收藏

在 IE6 中,可以很方便地利用 img 的 src 属性,实现本地图片预览,然而在 IE7 中,这种办法却行不通。需要用 AlphaImageLoader


AlphaImageLoader

说明:

在对象容器边界内,在对象的背景和内容之间显示一张图片。并提供对此图片的剪切和改变尺寸的操作。如果载入的是PNG(Portable Network Graphics)格式,则0%-100%的透明度也被提供。

语法:

filter : progid:DXImageTransform.Microsoft.AlphaImageLoader ( enabled=bEnabled , sizingMethod=sSize , src=sURL )

enabled:可选项。布尔值(Boolean)。设置或检索滤镜是否激活。
true:默认值。滤镜激活。
false:滤镜被禁止。

sizingMethod:可选项。字符串(String)。设置或检索滤镜作用的对象的图片在对象容器边界内的显示方式。
crop:剪切图片以适应对象尺寸。
image:默认值。增大或减小对象的尺寸边界以适应图片的尺寸。
scale:缩放图片以适应对象的尺寸边界。

src:必选项。字符串(String)。使用绝对或相对 url 地址指定背景图像。假如忽略此参数,滤镜将不会作用。


具体操作:

  1. 为预览区域(比如要在某个 div 中预览)添加样式:filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);。
  2. 为 AlphaImageLoader 设置 src 属性。

 

示例代码:

<? xml version="1.0" encoding="gb2312" ?>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html  xmlns ="http://www.w3.org/1999/xhtml" >

< head >
< meta  http-equiv ="Content-Type"  content ="text/html; charset=gb2312"   />
< title > 本地图片预览代码(支持 IE6、IE7) </ title >
< style  type ="text/css" >
#newPreview
{
    filter
: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale) ;
}

</ style >
< script  type ="text/javascript"  language ="javascript" >
<!--
function  PreviewImg(imgFile)
{
    
// 原来的预览代码,不支持 IE7。
     var  oldPreview  =  document.getElementById( " oldPreview " );
    oldPreview.innerHTML 
=   " <img src=\ " file:\\\\ "  + imgFile.value +  " \ "  width=\ " 80 \ "  height=\ " 60 \ "  /> " ;
    
    
// 新的预览代码,支持 IE6、IE7。
     var  newPreview  =  document.getElementById( " newPreview " );
    newPreview.filters.item(
" DXImageTransform.Microsoft.AlphaImageLoader " ).src  =  imgFile.value;
    newPreview.style.width 
=   " 80px " ;
    newPreview.style.height 
=   " 60px " ;
}

-->
</ script >
</ head >

< body >

< p > 说明:以下针对的是互联网情况,如果您在本地作测试,比如输入的地址是:http://127.0.0.1/,则可以看到全部预览。 </ p >

< hr  />

< p > 如果您使用的是 IE6,则可以看到以下预览;如果您使用的是 IE7,则看不到以下预览。 </ p >
< div  id ="oldPreview" ></ div >

< hr  />

< p > 不论您使用的是 IE6 还是 IE7,均可以看到以下预览。 </ p >
< div  id ="newPreview" ></ div >

< hr  />

< p > 请选择一个图片进行预览: < input  type ="file"  size ="20"  onchange ="javascript:PreviewImg(this);"   /></ p >

</ body >

</ html >
posted @ 2007-09-29 13:16 华梦行 阅读(2703) | 评论 (4)编辑 收藏
<!--#include file = conn.asp -->
posted @ 2007-09-25 14:55 华梦行 阅读(112) | 评论 (0)编辑 收藏
Oracle  查询如果  a.typeName=a.typeName  查出所有的a.typeName  不为null的记录。这点一定要注意null问题
posted @ 2007-09-14 18:19 华梦行 阅读(120) | 评论 (0)编辑 收藏

异常控制

  Author: 江南白衣

1.业务异常类

      1.所以业务异常类派生于BusinessException基类。

      2.原则上,要进行相同处理的异常分为一类,用ERROR_CODE标识不同。

      3.出错信息统一写在errors.properties,以ERROR_CODE为主键,支持i18N,由基类提供默认的getMessage()函数。

      参考BussinessException.java和OrderException.java。

2.Servlet规范里的异常控制

 2.1按error-code统一定义错误页面

<error-page>
  <error-code>404</error-code>
  <location>/404.jsp</location>
</error-page>
<error-page>
  <error-code>500</error-code>
  <location>/error.jsp</location>
</error-page>

2.2按异常类型定义单独错误页面

<error-page>
  <exception-type>org.sprngside.bookstore.UserNotFound</exception-type>
  <location>/userNotFound.jsp</location>
</error-page>

2.3 在JSP里单独定义错误页面

<@ errorPage="error.jsp">

3.Spring MVC里的异常控制

   spring-mvc可在xxx-serverlet.xml里定义default和 按Excepiton类型影射的错误页面, 和Servlet规范比,主要作了Spring特色的JSP路径转向和日志记录.参见bookstore-servlet.xml

  <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="/error.jsp"/>
        <property name="exceptionMappings">
            <props>
                <prop key="org.springside.framework.base.BusinessException">/businessError.jsp</prop>
            </props>
        </property>
    </bean>

4. error.jsp的处理

         error.jsp会同时处理jsp,servlet,和spring抛过来的异常

         其中jsp的异常在exception 变量中.

         servlet的异常在(Exception)request.getAttribute("javax.servlet.error.exception")

         spring的异常在(Exception) request.getAttribute("exception")

         使用 (String) request.getAttribute("javax.servlet.error.request_uri")获得 request_uri
         使用 logger.error(exception.getMessage(), exception); 记录整个异常栈

posted @ 2007-09-13 11:23 华梦行 阅读(1826) | 评论 (0)编辑 收藏
http://www.cnpack.org/upgrade/cvstracnt/CVSTracNT_1.2.1_20060112.exe
posted @ 2007-09-12 18:22 华梦行 阅读(102) | 评论 (0)编辑 收藏
Class FilterChainProxy
java.lang.Objectextended by org.acegisecurity.util.FilterChainProxy
All Implemented Interfaces:
Filter, InitializingBean, ApplicationContextAware

public class FilterChainProxy
extends Object
implements Filter, InitializingBean, ApplicationContextAware

Delegates Filter requests to a list of Spring-managed beans.

通过一系列的由spring托管的beans ,代理过滤请求。
FilterChainProxy 通过在web.xml中定义的FilterToBeanProxy 被加载,FilterChainProxy 将会通过init(FilterConfig), destroy() and doFilter(ServletRequest, ServletResponse, FilterChain)调用,调用每一个在其中定义的过滤器。

The FilterChainProxy is loaded via a standard FilterToBeanProxy declaration in web.xml. FilterChainProxy will then pass init(FilterConfig), destroy() and doFilter(ServletRequest, ServletResponse, FilterChain) invocations through to each Filter defined against FilterChainProxy.

 
    FilterChainProxy  是通过一个标准的FilterInvocationDefinitionSource 来实现配置的,每个可能的FilterChainProxy应该服务的URI模式都必须进入
            第一个搭配的URI模式将会被用来定义处理请求的所有的过滤器,就是说只适配第一组过滤器,后面的其他过滤器将无效。
FilterChainProxy
is configured using a standard FilterInvocationDefinitionSource. Each possible URI pattern that FilterChainProxy should service must be entered. The first matching URI pattern located by FilterInvocationDefinitionSource for a given request will be used to define all of the Filters that apply to that request. NB: This means you must put most specific URI patterns at the top of the list, and ensure all Filters that should apply for a given URI pattern are entered against the respective entry. The FilterChainProxy will not iterate the remainder of the URI patterns to locate additional Filters. The FilterInvocationDefinitionSource described the applicable URI pattern to fire the filter chain, followed by a list of configuration attributes. Each configuration attribute's ConfigAttribute.getAttribute() corresponds to a bean name that is available from the application context.

FilterChainProxy respects normal handling of Filters that elect not to call Filter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain), in that the remainder of the origial or FilterChainProxy-declared filter chain will not be called.

It is particularly noted the Filter lifecycle mismatch between the servlet container and IoC container. As per FilterToBeanProxy JavaDocs, we recommend you allow the IoC container to manage lifecycle instead of the servlet container. By default the FilterToBeanProxy will never call this class' init(FilterConfig) and destroy() methods, meaning each of the filters defined against FilterInvocationDefinitionSource will not be called. If you do need your filters to be initialized and destroyed, please set the lifecycle initialization parameter against the FilterToBeanProxy to specify servlet container lifecycle management.

If a filter name of TOKEN_NONE is used, this allows specification of a filter pattern which should never cause any filters to fire.

posted @ 2007-09-12 16:20 华梦行 阅读(1928) | 评论 (0)编辑 收藏

四 Acegi ACL使用 

4.1 基本概念

      在google中搜索'acl'会找到很多相关的介绍,而且涉及的范围也特别广泛。ACL是(Access Control List)的缩写,顾名思义,ACL是‘访问控制列表’的意思。通俗点说,ACL保存了所有用户或角色对资源的访问权限。最典型的ACL实现是流行操作系统(window, unix)的文件访问控制系统,精确定义了某个用户或角色对某个特定文件的读、写、执行等权限,更通俗的例子是可以定义某个管理员只能管一部分的订单,而另一个管理员只能管另一部分的。

4.2 Acegi ACL配置

Acegi好早就实现了ACL(好像是0.5),但是使用起来确实有点麻烦,所以用的不是太广泛。这里简单的说明一下使用方法,希望有更多的朋友来试试。

首先要理解Acegi里面Voter的概念,ACL正是在一个Voter上扩展起来的。现来看一下AclVoter的配置。

     < bean  id ="aclBeanReadVoter"  class ="org.acegisecurity.vote.BasicAclEntryVoter" >
        
< property  name ="processConfigAttribute" >
            
< value > ACL_READ </ value >
        
</ property >
        
< property  name ="processDomainObjectClass" >
            
< value > org.springside.modules.security.acl.domain.AclDomainAware </ value >
        
</ property >
        
< property  name ="aclManager" >
            
< ref  local ="aclManager" />
        
</ property >
        
< property  name ="requirePermission" >
            
< list >
                
< ref  local ="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" />
                
< ref  local ="org.acegisecurity.acl.basic.SimpleAclEntry.READ" />
            
</ list >
        
</ property >
    
</ bean >
  1. ACL_READ指的是这个Voter对哪些SecurityConfig起作用,我们可以把ACL_READ配置在想要拦截的Method上。比方说我们要拦截readOrder这个方法,以实现ACL控制,可以这样配置。
    orderManager.readOrder=ACL_READ
  2. processDomainObjectClass指出哪些DomainObject是要进行ACL校验的。
  3. aclManager是一个比较重要的概念,主要负责在权限列表中根据用户和DomainObject取得acl列表。
  4. requirePermission指出要进行这个操作必须具备的acl权限,比方说read操作就必须有ADMINISTRATION或READ两个权限。

其实整个过程看下来比较清晰,下面来看一下AclManager如何配置。

     <!--  ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS =========  -->

    
< bean  id ="aclManager"  class ="org.acegisecurity.acl.AclProviderManager" >
        
< property  name ="providers" >
            
< list >
                
< ref  local ="basicAclProvider" />
            
</ list >
        
</ property >
    
</ bean >

    
< bean  id ="basicAclProvider"  class ="org.acegisecurity.acl.basic.BasicAclProvider" >
        
< property  name ="basicAclDao" >
            
< ref  local ="basicAclExtendedDao" />
        
</ property >
    
</ bean >

    
< bean  id ="basicAclExtendedDao"  class ="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl" >
        
< property  name ="dataSource" >
            
< ref  bean ="dataSource" />
        
</ property >
    
</ bean >


很明显ACLManager继承了Acegi的一贯风格,Provider可以提供多种取得ACL访问列表的途径,默认的是用basicAclProvider在数据库中取得。既然提到了数据库,那我们就来看一下Acegi默认提供的ACL在数据库里的保存表结构:

CREATE   TABLE  acl_object_identity (
id 
IDENTITY   NOT   NULL ,
object_identity VARCHAR_IGNORECASE(
250 NOT   NULL ,
parent_object 
INTEGER ,
acl_class VARCHAR_IGNORECASE(
250 NOT   NULL ,
CONSTRAINT  unique_object_identity  UNIQUE (object_identity),
FOREIGN   KEY  (parent_object)  REFERENCES  acl_object_identity(id)
);
CREATE   TABLE  acl_permission (
id 
IDENTITY   NOT   NULL ,
acl_object_identity 
INTEGER   NOT   NULL ,
recipient VARCHAR_IGNORECASE(
100 NOT   NULL ,
mask 
INTEGER   NOT   NULL ,
CONSTRAINT  unique_recipient  UNIQUE (acl_object_identity, recipient),
FOREIGN   KEY  (acl_object_identity)  REFERENCES  acl_object_identity(id)
);
  1. acl_object_identity表存放了所有受保护的domainObject的信息。其中object_identity字段保存了domainObject的class和id,默认的保存格式是:domainClass:domainObjectId。
  2. acl_permission 就是ACL权限列表了,recipient 是用户或角色信息,mask表示了这个用户或角色对这个domainObject的访问权限。注意这些信息的保存格式都是可以根据自己的需要改变的。

这样读取和删除的时候Acegi就能很好的完成拦截工作,但是读取一个List的时候,如何才能把该用户不能操作的domainObject剔除掉呢?这就需要afterInvocationManager来完成这个工作。下面来看下配置:

     <!--  ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS ===========  -->

    
< bean  id ="afterInvocationManager"  class ="org.acegisecurity.afterinvocation.AfterInvocationProviderManager" >
        
< property  name ="providers" >
            
< list >
                
< ref  local ="afterAclCollectionRead" />
            
</ list >
        
</ property >
    
</ bean >
    
<!--  Processes AFTER_ACL_COLLECTION_READ configuration settings  -->
    
< bean  id ="afterAclCollectionRead"  class ="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider" >
        
< property  name ="aclManager" >
            
< ref  local ="aclManager" />
        
</ property >
        
< property  name ="requirePermission" >
            
< list >
                
< ref  local ="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" />
                
< ref  local ="org.acegisecurity.acl.basic.SimpleAclEntry.READ" />
            
</ list >
        
</ property >
    
</ bean >


afterAclCollectionRead会在拦截的方法执行结束的时候执行。主要的作用就是在返回的List中挨个检查domainObject的操作权限,然后根据requirePermission来剔除不符合的domainObject。

4.3 使用RuleEngine设置的ACL规则

在SpringSide里使用了RuleEngine来设置ACL规则,具体规则见
bookstore-sample\resources\rules\drl

posted @ 2007-09-12 14:46 华梦行 阅读(284) | 评论 (0)编辑 收藏

五 FAQ 

5.1 FAQ

  1. Q:   能否脱离Spring框架来使用Acegi?
    A:  虽然Acegi 没有要求必须使用Spring Framework,但事实上Acegi很大程度上利用了Spring的IOC和AOP,很难脱离Spring的单独使用。
  2. Q:  Acegi有对xfire的支持吗?
    A: 有,详见http://jira.codehaus.org/browse/XFIRE-389
  3. Q: 为何无论怎么设置都返回到登陆页面无法成功登陆?
    A:  检查登陆页面或登陆失败页面是否只有ROLE_ANONYMOUS权限

5.2 Acegi 补习班

要了解Acegi,首先要了解以下几个重要概念:

  1. Authentication
    Authentication对象包含了principal, credentials 和 authorities(authorities要赋予给principal的),同时也可以包含一些附加的认证请求信息,如TCP/IP地址和Session id等。
  2. SecurityContextHolder
    SecurityContextHolder包含ThreadLocal私有属性用于存取SecurityContext, SecurityContext包含Authentication私有属性, 看以下一段程序


    public void getSecurityContextInformations() {
      SecurityContext sc = SecurityContextHolder.getContext();
      Authentication auth = sc.getAuthentication();
      Object principal = auth.getPrincipal();
      if (principal instanceof UserDetails) {
       //用户密码
       String password = ((UserDetails) principal).getPassword();
       //用户名称
       String username = ((UserDetails) principal).getUsername();
       //用户权限
       GrantedAuthority[] authorities = ((UserDetails) principal).getAuthorities();
       for (int i = 0; i < authorities.length; i++) {
        String authority = authorities[i].getAuthority();
       }
      }
      Object details = auth.getDetails();
      if (details instanceof WebAuthenticationDetails) {
       //用户session id
       String SessionId = ((WebAuthenticationDetails) details).getSessionId();
      }
     }
  3. AuthenticationManager
    通过Providers验证在当前 ContextHolder中的Authentication对象是否合法。
  4. AccessDecissionManager
    经过投票机制来审批是否批准操作
  5. RunAsManager
    当执行某个操作时,RunAsManager可选择性地替换Authentication对象
  6. Interceptors
    拦截器(如FilterSecurityInterceptor,JoinPoint,MethodSecurityInterceptor等)用于协调授权,认证等操作
posted @ 2007-09-12 14:46 华梦行 阅读(145) | 评论 (0)编辑 收藏

三 Acegi安全系统扩展 

      相信side对Acegi的扩展会给你耳目一新的感觉,提供完整的扩展功能,管理界面,中文注释和靠近企业的安全策略。side只对Acegi不符合企业应用需要的功能进行扩展,尽量不改动其余部分来实现全套权限管理功能,以求能更好地适应Acegi升级。

3.1 基于角色的权限控制(RBAC)

    Acegi 自带的 sample 表设计很简单: users表{username,password,enabled} authorities表{username,authority},这样简单的设计无法适应复杂的权限需求,故SpringSide选用RBAC模型对权限控制数据库表进行扩展。 RBAC引入了ROLE的概念,使User(用户)和Permission(权限)分离,一个用户拥有多个角色,一个角色拥有有多个相应的权限,从而减少了权限管理的复杂度,可更灵活地支持安全策略。

    同时,我们也引入了resource(资源)的概念,一个资源对应多个权限,资源分为ACL,URL,和FUNTION三种。注意,URL和FUNTION的权限命名需要以AUTH_开头才会有资格参加投票, 同样的ACL权限命名需要ACL_开头。


3.2 管理和使用EhCache

3.2.1 设立缓存

在SpringSide里的 Acegi 扩展使用 EhCache 就作为一种缓存解决方案,以缓存用户和资源的信息和相对应的权限信息。

首先需要一个在classpath的ehcache.xml 文件,用于配置EhCache。

				
						
								<ehcache>
        <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="0"
            timeToLiveSeconds="0"
            diskPersistent="false"
           diskExpiryThreadIntervalSeconds= "120"/>
    <!-- acegi cache-->
    <cache name="userCache"
           maxElementsInMemory="10000"
           eternal="true"
          overflowToDisk= "true"/>
    <!-- acegi cache-->
    <cache name="resourceCache"
           maxElementsInMemory="10000"
           eternal="true"
           overflowToDisk="true"/>
</ehcache>

     maxElementsInMemory设定了允许在Cache中存放的数据数目,eternal设定Cache是否会过期,overflowToDisk设定内存不足的时候缓存到硬盘,timeToIdleSeconds和timeToLiveSeconds设定缓存游离时间和生存时间,diskExpiryThreadIntervalSeconds设定缓存在硬盘上的生存时间,注意当eternal="true"时,timeToIdleSeconds,timeToLiveSeconds和diskExpiryThreadIntervalSeconds都是无效的。

<defaultCache>是除制定的Cache外其余所有Cache的设置,针对Acegi 的情况, 专门设置了userCache和resourceCache,都设为永不过期。在applicationContext-acegi-security.xml中相应的调用是

				
				
				<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value=" userCache"/>
    </bean>
    <bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" autowire="byName">
        <property name="cache" ref="userCacheBackend"/>
    </bean>
    <bean id="resourceCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value=" resourceCache"/>
    </bean>
    <bean id="resourceCache" class="org.springside.modules.security.service.acegi.cache.ResourceCache" autowire="byName">
        <property name="cache" ref="resourceCacheBackend"/>
    </bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>

"cacheName" 就是设定在ehcache.xml 中相应Cache的名称。

userCache使用的是Acegi 的EhCacheBasedUserCache(实现了UserCache接口), resourceCache是SpringSide的扩展类

				public interface UserCache   {
				
						
    public UserDetails getUserFromCache (String username);

    public void putUserInCache (UserDetails user);

    public void removeUserFromCache (String username);
}
				public class ResourceCache   {
    public ResourceDetails getAuthorityFromCache (String resString) {...    }
    public void putAuthorityInCache (ResourceDetails resourceDetails) {...  }
 
   public void removeAuthorityFromCache (String resString) {... }
    public List getUrlResStrings() {... }
    public List getFunctions() {.. }
}

UserCache 就是通过EhCache对UserDetails 进行缓存管理, 而ResourceCache 是对ResourceDetails 类进行缓存管理

				public interface UserDetails   extends Serializable {
    public boolean isAccountNonExpired();
    public boolean isAccountNonLocked();

    public GrantedAuthority[] getAuthorities();

    public boolean isCredentialsNonExpired();

    public boolean isEnabled();

    public String getPassword();

    public String getUsername();
}
				public interface ResourceDetails   extends Serializable {
				
						
    public String getResString();

    public String getResType();

    public GrantedAuthority[] getAuthorities();
}

UserDetails 包含用户信息和相应的权限,ResourceDetails 包含资源信息和相应的权限。

				public interface GrantedAuthority     {
    public String getAuthority ();
}

     GrantedAuthority 就是权限信息,在Acegi 的 sample 里GrantedAuthority 的信息如ROLE_USER, ROLE_SUPERVISOR, ACL_CONTACT_DELETE, ACL_CONTACT_ADMIN等等,网上也有很多例子把角色作为GrantedAuthority ,但事实上看看ACL 就知道, Acegi本身根本就没有角色这个概念,GrantedAuthority 包含的信息应该是权限,对于非ACL的权限用 AUTH_ 开头更为合理, 如SpringSide里的 AUTH_ADMIN_LOGIN, AUTH_BOOK_MANAGE 等等。

3.2.2 管理缓存

     使用AcegiCacheManager对userCache和resourceCache进行统一缓存管理。当在后台对用户信息进行修改或赋权的时候, 在更新数据库同时就会调用acegiCacheManager相应方法, 从数据库中读取数据并替换cache中相应部分,使cache与数据库同步。

				public class AcegiCacheManager extends BaseService {
    private ResourceCache resourceCache ;
    private UserCache userCache ;
    /**
     * 修改User时更改userCache
     */

    public void modifyUserInCache (User user, String orgUsername) {...    }
    /**
     * 修改Resource时更改resourceCache
     */

    public void modifyResourceInCache (Resource resource, String orgResourcename) {...    }
    /**
     * 修改权限时同时修改userCache和resourceCache
     */

    public void modifyPermiInCache (Permission permi, String orgPerminame) {...  }
    /**
     * User授予角色时更改userCache
     */
    public void authRoleInCache (User user) {...    }
    /**
     * Role授予权限时更改userCache和resourceCache
     */

    public void authPermissionInCache (Role role) {...  }
    /**
     * Permissioni授予资源时更改resourceCache
     */

    public void authResourceInCache (Permission permi) {...  }
    /**
     * 初始化userCache
     */

    public void initUserCache () {...  }
    /**
     * 初始化resourceCache
     */

    public void initResourceCache () {... }
    /**
     * 获取所有的url资源
     */

    public List getUrlResStrings () {...  }
    /**
     * 获取所有的Funtion资源
     */

    public List getFunctions () {...  }
    /**
     * 根据资源串获取资源
     */

    public ResourceDetails getAuthorityFromCache (String resString) {...  }
  
 ......


}

 

3.3 资源权限定义扩展

     Acegi给出的sample里,资源权限对照关系是配置在xml中的,试想一下如果你的企业安全应用有500个用户,100个角色权限的时候,维护这个xml将是个繁重无比的工作,如何动态更改用户权限更是个头痛的问题。

   <bean id="contactManagerSecurity" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
      <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
      <property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
      <property name="objectDefinitionSource">
         <value>
            sample.contact.ContactManager.create=ROLE_USER
            sample.contact.ContactManager.getAllRecipients=ROLE_USER
            sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ
            sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ
            sample.contact.ContactManager.delete=ACL_CONTACT_DELETE
            sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN
            sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN
         </value>
      </property>
   </bean>
  <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
      <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
      <property name="objectDefinitionSource">
         <value>
       CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
       PATTERN_TYPE_APACHE_ANT
       /index.jsp=ROLE_ANONYMOUS,ROLE_USER
       /hello.htm=ROLE_ANONYMOUS,ROLE_USER
       /logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
       /switchuser.jsp=ROLE_SUPERVISOR
       /j_acegi_switch_user=ROLE_SUPERVISOR
       /acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER
     /**=ROLE_USER
         </value>
      </property>
   </bean>

 对如此不Pragmatic的做法,SpringSide进行了扩展, 让Acegi 能动态读取数据库中的权限资源关系。

3.3.1 Aop Invocation Authorization

    <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource" ref="methodDefinitionSource"/>
    </bean>
    <bean id="methodDefinitionSource" class="org.springside.security.service.acegi.DBMethodDefinitionSource">
        <property name="acegiCacheManager" ref="acegiCacheManager"/>
    </bean>

     研究下Aceig的源码,ObjectDefinitionSource的实际作用是返回一个ConfigAttributeDefinition对象,而Acegi Sample 的方式是用MethodDefinitionSourceEditor把xml中的文本Function资源权限对应关系信息加载到MethodDefinitionMap ( MethodDefinitionSource 的实现类 )中, 再组成ConfigAttributeDefinition,而我们的扩展目标是从缓存中读取信息来组成ConfigAttributeDefinition。

     MethodSecurityInterceptor是通过调用AbstractMethodDefinitionSource的lookupAttributes(method)方法获取ConfigAttributeDefinition。所以我们需要实现自己的ObjectDefinitionSource,继承AbstractMethodDefinitionSource并实现其lookupAttributes方法,从缓存中读取资源权限对应关系组成并返回ConfigAttributeDefinition即可。SpringSide中的DBMethodDefinitionSource类的部分实现如下 :

public class DBMethodDefinitionSource extendsAbstractMethodDefinitionSource {
......
    protected ConfigAttributeDefinitionlookupAttributes(Method mi) {
        Assert.notNull(mi, "lookupAttrubutes in the DBMethodDefinitionSource is null");
        String methodString = mi.getDeclaringClass().getName() + "." + mi.getName();
        if (!acegiCacheManager.isCacheInitialized()) {
            //初始化Cache
            acegiCacheManager.initResourceCache();
        }
        //获取所有的function
        List methodStrings = acegiCacheManager.getFunctions();
        Set auths = new HashSet();
        //取权限的合集
        for (Iterator iter = methodStrings.iterator(); iter.hasNext();) {
            String mappedName = (String) iter.next();
            if (methodString.equals(mappedName)
                    || isMatch(methodString, mappedName)) {
                ResourceDetails resourceDetails = acegiCacheManager.getAuthorityFromCache(mappedName);
                if (resourceDetails == null) {
                    break;
                }
                GrantedAuthority[] authorities = resourceDetails.getAuthorities();
                if (authorities == null || authorities.length == 0) {
                    break;
                }
                auths.addAll(Arrays.asList(authorities));
            }
        }
        if (auths.size() == 0)
            return null;
        ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
        String authoritiesStr = " ";
        for (Iterator iter = auths.iterator(); iter.hasNext();) {
            GrantedAuthority authority = (GrantedAuthority) iter.next();
            authoritiesStr += authority.getAuthority() + ",";
        }
        String authStr = authoritiesStr.substring(0, authoritiesStr.length() - 1);
        configAttrEditor.setAsText(authStr);
       //组装并返回ConfigAttributeDefinition
        return (ConfigAttributeDefinition) configAttrEditor.getValue();
    }
    ......
}

要注意几点的是:
1) 初始化Cache是比较浪费资源的,所以SpringSide中除第一次访问外的Cache的更新是针对性更新。

2) 因为method采用了匹配方式(详见 isMatch() 方法) , 即对于*Book和save*这两个资源来说,只要当前访问方法是Book结尾或以save开头都算匹配得上,所以应该取这些能匹配上的资源的相对应的权限的合集。

3) 使用ConfigAttributeEditor 能更方便地组装ConfigAttributeDefinition。

3.3.2 Filter Invocation Authorization

    <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource" ref="filterDefinitionSource"/>
    </bean>

    <bean id="filterDefinitionSource" class="org.springside.security.service.acegi.DBFilterInvocationDefinitionSource">
        <property name="convertUrlToLowercaseBeforeComparison" value="true"/>
        <property name="useAntPath" value="true"/>
        <property name="acegiCacheManager" ref="acegiCacheManager"/>
    </bean>

     PathBasedFilterInvocationDefinitionMap和RegExpBasedFilterInvocationDefinitionMap都是 FilterInvocationDefinitionSource的实现类,当PATTERN_TYPE_APACHE_ANT字符串匹配上时时,FilterInvocationDefinitionSourceEditor 选用PathBasedFilterInvocationDefinitionMap 把xml中的文本URL资源权限对应关系信息加载。

     FilterSecurityInterceptor通过FilterInvocationDefinitionSource的lookupAttributes(url)方法获取ConfigAttributeDefinition。 所以,我们可以通过继承FilterInvocationDefinitionSource的抽象类AbstractFilterInvocationDefinitionSource,并实现其lookupAttributes方法,从缓存中读取URL资源权限对应关系即可。SpringSide的DBFilterInvocationDefinitionSource类部分实现如下:

public class DBFilterInvocationDefinitionSource extends AbstractFilterInvocationDefinitionSource {

......
    public ConfigAttributeDefinition lookupAttributes(String url) {
        if (!acegiCacheManager.isCacheInitialized()) {
            acegiCacheManager.initResourceCache();
        }

        if (isUseAntPath()) {
            // Strip anything after a question mark symbol, as per SEC-161.
            int firstQuestionMarkIndex = url.lastIndexOf("?");
            if (firstQuestionMarkIndex != -1) {
                url = url.substring(0, firstQuestionMarkIndex);
            }
        }
        List urls = acegiCacheManager.getUrlResStrings();
        //URL资源倒叙排序
        Collections.sort(urls);
        Collections.reverse(urls);
//是否先全部转为小写再比较
        if (convertUrlToLowercaseBeforeComparison) {
            url = url.toLowerCase();
        }
        GrantedAuthority[] authorities = new GrantedAuthority[0];
        for (Iterator iterator = urls.iterator(); iterator.hasNext();) {
            String resString = (String) iterator.next();
            boolean matched = false;
//可选择使用AntPath和Perl5两种不同匹配模式
            if (isUseAntPath()) {
                matched = pathMatcher.match(resString, url);
            } else {
                Pattern compiledPattern;
                Perl5Compiler compiler = new Perl5Compiler();
                try {
                    compiledPattern = compiler.compile(resString,
                            Perl5Compiler.READ_ONLY_MASK);
                } catch (MalformedPatternException mpe) {
                    throw new IllegalArgumentException(
                            "Malformed regular expression: " + resString);
                }
                matched = matcher.matches(url, compiledPattern);
            }
            if (matched) {
                ResourceDetails rd = acegiCacheManager.getAuthorityFromCache(resString);
                authorities = rd.getAuthorities();
                break;
            }
        }
        if (authorities.length > 0) {
            String authoritiesStr = " ";
            for (int i = 0; i < authorities.length; i++) {
                authoritiesStr += authorities[i].getAuthority() + ",";
            }
            String authStr = authoritiesStr.substring(0, authoritiesStr
                    .length() - 1);
            ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
            configAttrEditor.setAsText(authStr);
            return (ConfigAttributeDefinition) configAttrEditor.getValue();
        }
        return null;
    }

......
 }

继承AbstractFilterInvocationDefinitionSource注意几点:
1)  需要先把获取回来的URL资源按倒序派序,以达到 a/b/c/d.* 在 a/.* 之前的效果(详见 Acegi sample 的applicationContext-acegi-security.xml 中的filterInvocationInterceptor的注释),为的是更具体的URL可以先匹配上,而获取具体URL的权限,如a/b/c/d.*权限AUTH_a, AUTH_b 才可查看,  a/.* 需要权限AUTH_a 才可查看,则如果当前用户只拥有权限AUTH_b,则他只可以查看a/b/c/d.jsp 而不能察看a/d.jsp。

2) 基于上面的原因,故第一次匹配上的就是当前所需权限,而不是取权限的合集。

3) 可以选用AntPath 或 Perl5 的资源匹配方式,感觉AntPath匹配方式基本足够。

4) Filter 权限控制比较适合于较粗颗粒度的权限,如设定某个模块下的页面是否能访问等,对于具体某个操作如增删修改,是否能执行,用Method  Invocation 会更佳些,所以注意两个方面一起控制效果更好

 

3.4 授权操作

     RBAC模型中有不少多对多的关系,这些关系都能以一个中间表的形式来存放,而Hibernate中可以不建这中间表对应的hbm.xml , 以资源与权限的配置为例,如下:

<hibernate-mapping package="org.springside.modules.security.domain">
    <class name="Permission" table="PERMISSIONS" dynamic-insert="true" dynamic-update="true">
        <cache usage="nonstrict-read-write"/>
        <id name="id" column="ID">
            <generator class="native"/>
        </id>
        <property name="name" column="NAME" not-null="true"/>
        <property name="descn" column="DESCN"/>
        <property name="operation" column="OPERATION"/>
        <property name="status" column="STATUS"/>
        <set name="roles" table="ROLE_PERMIS" lazy="true" inverse="true" cascade="save-update" batch-size="5">
            <key>
                <column name="PERMIS_ID" not-null="true"/>
            </key>
            <many-to-many class="Role" column="ROLE_ID" outer-join="auto"/>
        </set>
        <set name="resources" table="PERMIS_RESC" lazy="true" inverse="false" cascade="save-update" batch-size="5">
            <key>
                <column name="PERMIS_ID" not-null="true"/>
            </key>
            <many-to-many class="Resource" column="RESC_ID"/>
        </set>
    </class>
</hibernate-mapping>
<hibernate-mapping package="org.springside.modules.security.domain">
    <class name="Resource" table="RESOURCES" dynamic-insert="true" dynamic-update="true">
        <cache usage="nonstrict-read-write"/>
        <id name="id" column="ID">
            <generator class="native"/>
        </id>
        <property name="name" column="NAME" not-null="true"/>
        <property name="resType" column="RES_TYPE" not-null="true"/>
        <property name="resString" column="RES_STRING" not-null="true"/>
        <property name="descn" column="DESCN"/>
        <set name="permissions" table="PERMIS_RESC" lazy="true" inverse="true" cascade="save-update" batch-size="5">
            <key>
                <column name="RESC_ID" not-null="true"/>
            </key>
            <many-to-many class="Permission" column="PERMIS_ID" outer-join="auto"/>
        </set>
    </class>
</hibernate-mapping>

配置时注意几点:

1) 因为是分配某个权限的资源,所以权限是主控方,把inverse设为false,资源是被控方inverse设为true

2) cascade是"save-update",千万别配成delete

3) 只需要 permission.getResources().add(resource), permission.getResources()..remove(resource) 即可很方便地完成授权和取消授权操作

posted @ 2007-09-12 14:44 华梦行 阅读(228) | 评论 (0)编辑 收藏

二 Acegi安全系统的配置 

      Acegi 的配置看起来非常复杂,但事实上在实际项目的安全应用中我们并不需要那么多功能,清楚的了解Acegi配置中各项的功能,有助于我们灵活的运用Acegi于实践中。

2.1 在Web.xml中的配置

1)  FilterToBeanProxy
  Acegi通过实现了Filter接口的FilterToBeanProxy提供一种特殊的使用Servlet Filter的方式,它委托Spring中的Bean -- FilterChainProxy来完成过滤功能,这好处是简化了web.xml的配置,并且充分利用了Spring IOC的优势。FilterChainProxy包含了处理认证过程的filter列表,每个filter都有各自的功能。

    <filter>
        <filter-name>Acegi Filter Chain Proxy</filter-name>
        <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
        <init-param>
            <param-name>targetClass</param-name>
            <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
        </init-param>
    </filter>

2) filter-mapping
  <filter-mapping>限定了FilterToBeanProxy的URL匹配模式,只有*.do和*.jsp和/j_acegi_security_check 的请求才会受到权限控制,对javascript,css等不限制。

   <filter-mapping>
      <filter-name>Acegi Filter Chain Proxy</filter-name>
      <url-pattern>*.do</url-pattern>
    </filter-mapping>
   
    <filter-mapping>
      <filter-name>Acegi Filter Chain Proxy</filter-name>
      <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
   
    <filter-mapping>
      <filter-name>Acegi Filter Chain Proxy</filter-name>
      <url-pattern>/j_acegi_security_check</url-pattern>
</filter-mapping>

3) HttpSessionEventPublisher
  <listener>的HttpSessionEventPublisher用于发布HttpSessionApplicationEvents和HttpSessionDestroyedEvent事件给spring的applicationcontext。

    <listener>
        <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
    </listener>


2.2 在applicationContext-acegi-security.xml中

2.2.1 FILTER CHAIN

  FilterChainProxy会按顺序来调用这些filter,使这些filter能享用Spring ioc的功能, CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON定义了url比较前先转为小写, PATTERN_TYPE_APACHE_ANT定义了使用Apache ant的匹配模式

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
               /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,
basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,
exceptionTranslationFilter,filterInvocationInterceptor
            </value>
        </property>
    </bean>

2.2.2 基础认证

1) authenticationManager
  起到认证管理的作用,它将验证的功能委托给多个Provider,并通过遍历Providers, 以保证获取不同来源的身份认证,若某个Provider能成功确认当前用户的身份,authenticate()方法会返回一个完整的包含用户授权信息的Authentication对象,否则会抛出一个AuthenticationException。
Acegi提供了不同的AuthenticationProvider的实现,如:
        DaoAuthenticationProvider 从数据库中读取用户信息验证身份
        AnonymousAuthenticationProvider 匿名用户身份认证
        RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证
        AuthByAdapterProvider 使用容器的适配器验证身份
        CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆
        JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份
        RemoteAuthenticationProvider 根据远程服务验证用户身份
        RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证
        X509AuthenticationProvider 从X509认证中获取用户信息验证身份
        TestingAuthenticationProvider 单元测试时使用

        每个认证者会对自己指定的证明信息进行认证,如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref local="daoAuthenticationProvider"/>
                <ref local="anonymousAuthenticationProvider"/>
                <ref local="rememberMeAuthenticationProvider"/>
            </list>
        </property>
</bean>


2) daoAuthenticationProvider
  进行简单的基于数据库的身份验证。DaoAuthenticationProvider获取数据库中的账号密码并进行匹配,若成功则在通过用户身份的同时返回一个包含授权信息的Authentication对象,否则身份验证失败,抛出一个AuthenticatiionException。

    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="jdbcDaoImpl"/>
        <property name="userCache" ref="userCache"/>
        <property name="passwordEncoder" ref="passwordEncoder"/>
   </bean>


3) passwordEncoder
  使用加密器对用户输入的明文进行加密。Acegi提供了三种加密器:
PlaintextPasswordEncoder—默认,不加密,返回明文.
ShaPasswordEncoder—哈希算法(SHA)加密
Md5PasswordEncoder—消息摘要(MD5)加密

<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder"/>


4) jdbcDaoImpl
  用于在数据中获取用户信息。 acegi提供了用户及授权的表结构,但是您也可以自己来实现。通过usersByUsernameQuery这个SQL得到你的(用户ID,密码,状态信息);通过authoritiesByUsernameQuery这个SQL得到你的(用户ID,授权信息)

 
<bean id="jdbcDaoImpl" 
class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
        <property name="dataSource" ref="dataSource"/>
        <property name="usersByUsernameQuery">
            <value>select loginid,passwd,1 from users where loginid = ?</value>
        </property>
        <property name="authoritiesByUsernameQuery">
            <value>select u.loginid,p.name from users u,roles r,permissions p,user_role ur,role_permis rp where u.id=ur.user_id and r.id=ur.role_id and p.id=rp.permis_id and
                r.id=rp.role_id and p.status='1' and u.loginid=?</value>
        </property>
</bean>

5) userCache &  resourceCache
  缓存用户和资源相对应的权限信息。每当请求一个受保护资源时,daoAuthenticationProvider就会被调用以获取用户授权信息。如果每次都从数据库获取的话,那代价很高,对于不常改变的用户和资源信息来说,最好是把相关授权信息缓存起来。(详见 2.6.3 资源权限定义扩展 )
userCache提供了两种实现: NullUserCache和EhCacheBasedUserCache, NullUserCache实际上就是不进行任何缓存,EhCacheBasedUserCache是使用Ehcache来实现缓功能。

    <bean id="userCacheBackend" 
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value="userCache"/>
    </bean>
    <bean id="userCache" class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache" autowire="byName">
        <property name="cache" ref="userCacheBackend"/>
    </bean>
    <bean id="resourceCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="cacheName" value="resourceCache"/>
    </bean>
    <bean id="resourceCache" class="org.springside.modules.security.service.acegi.cache.ResourceCache" autowire="byName">
        <property name="cache" ref="resourceCacheBackend"/>
    </bean>


6) basicProcessingFilter
  用于处理HTTP头的认证信息,如从Spring远程协议(如Hessian和Burlap)或普通的浏览器如IE,Navigator的HTTP头中获取用户信息,将他们转交给通过authenticationManager属性装配的认证管理器。如果认证成功,会将一个Authentication对象放到会话中,否则,如果认证失败,会将控制转交给认证入口点(通过authenticationEntryPoint属性装配)

    <bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationEntryPoint" ref="basicProcessingFilterEntryPoint"/>
    </bean>

7) basicProcessingFilterEntryPoint
  通过向浏览器发送一个HTTP401(未授权)消息,提示用户登录。
处理基于HTTP的授权过程, 在当验证过程出现异常后的"去向",通常实现转向、在response里加入error信息等功能。

 <bean 
id="basicProcessingFilterEntryPoint" 
class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
        <property name="realmName" value="SpringSide Realm"/>
</bean>

8) authenticationProcessingFilterEntryPoint
  当抛出AccessDeniedException时,将用户重定向到登录界面。属性loginFormUrl配置了一个登录表单的URL,当需要用户登录时,authenticationProcessingFilterEntryPoint会将用户重定向到该URL

 
<bean id="authenticationProcessingFilterEntryPoint" 
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
        <property name="loginFormUrl">
            <value>/security/login.jsp</value>
        </property>
        <property name="forceHttps" value="false"/>
</bean>

2.2.3 HTTP安全请求

1) httpSessionContextIntegrationFilter
  每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象,在request完后, 又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用,使之能跨越多个请求。

<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"></bean>
    <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
</bean>


2) httpRequestAccessDecisionManager
  经过投票机制来决定是否可以访问某一资源(URL或方法)。allowIfAllAbstainDecisions为false时如果有一个或以上的decisionVoters投票通过,则授权通过。可选的决策机制有ConsensusBased和UnanimousBased

    <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
            </list>
        </property>
    </bean>


3) roleVoter
   必须是以rolePrefix设定的value开头的权限才能进行投票,如AUTH_ , ROLE_

    <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
        <property name="rolePrefix" value="AUTH_"/>
   </bean>

4)exceptionTranslationFilter
  异常转换过滤器,主要是处理AccessDeniedException和AuthenticationException,将给每个异常找到合适的"去向" 

   <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>
    </bean>

5) authenticationProcessingFilter
  和servlet spec差不多,处理登陆请求.当身份验证成功时,AuthenticationProcessingFilter会在会话中放置一个Authentication对象,并且重定向到登录成功页面
         authenticationFailureUrl定义登陆失败时转向的页面
         defaultTargetUrl定义登陆成功时转向的页面
         filterProcessesUrl定义登陆请求的页面
         rememberMeServices用于在验证成功后添加cookie信息

    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationFailureUrl">
            <value>/security/login.jsp?login_error=1</value>
        </property>
        <property name="defaultTargetUrl">
            <value>/admin/index.jsp</value>
        </property>
        <property name="filterProcessesUrl">
            <value>/j_acegi_security_check</value>
        </property>
        <property name="rememberMeServices" ref="rememberMeServices"/>
    </bean>

6) filterInvocationInterceptor
  在执行转向url前检查objectDefinitionSource中设定的用户权限信息。首先,objectDefinitionSource中定义了访问URL需要的属性信息(这里的属性信息仅仅是标志,告诉accessDecisionManager要用哪些voter来投票)。然后,authenticationManager掉用自己的provider来对用户的认证信息进行校验。最后,有投票者根据用户持有认证和访问url需要的属性,调用自己的voter来投票,决定是否允许访问。

    <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource" ref="filterDefinitionSource"/>
    </bean>


7) filterDefinitionSource (详见 2.6.3 资源权限定义扩展)
  自定义DBFilterInvocationDefinitionSource从数据库和cache中读取保护资源及其需要的访问权限信息 

<bean id="filterDefinitionSource" class="org.springside.modules.security.service.acegi.DBFilterInvocationDefinitionSource">
        <property name="convertUrlToLowercaseBeforeComparison" value="true"/>
        <property name="useAntPath" value="true"/>
        <property name="acegiCacheManager" ref="acegiCacheManager"/>
</bean>

2.2.4 方法调用安全控制

(详见 2.6.3 资源权限定义扩展)

1) methodSecurityInterceptor
  在执行方法前进行拦截,检查用户权限信息
2) methodDefinitionSource
  自定义MethodDefinitionSource从cache中读取权限

   <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource" ref="methodDefinitionSource"/>
    </bean>
    <bean id="methodDefinitionSource" class="org.springside.modules.security.service.acegi.DBMethodDefinitionSource">
        <property name="acegiCacheManager" ref="acegiCacheManager"/>
    </bean>

2.3 Jcaptcha验证码

采用 http://jcaptcha.sourceforge.net 作为通用的验证码方案,请参考SpringSide中的例子,或网上的:
http://www.coachthrasher.com/page/blog?entry=jcaptcha_with_appfuse

差沙在此过程中又发现acegi logout filter的错误,进行了修正。

另外它默认提供的图片比较难认,我们custom了一个美观一点的版本。

posted @ 2007-09-12 14:43 华梦行 阅读(130) | 评论 (0)编辑 收藏

一 Acegi安全系统介绍 

    Author: cac 差沙

    Acegi是Spring Framework 下最成熟的安全系统,它提供了强大灵活的企业级安全服务,如完善的认证和授权机制,Http资源访问控制,Method 调用访问控制,Access Control List (ACL) 基于对象实例的访问控制,Yale Central Authentication Service (CAS) 耶鲁单点登陆,X509 认证,当前所有流行容器的认证适配器,Channel Security频道安全管理等功能。

1.1 网站资源

官方网站      http://acegisecurity.sourceforge.net
论坛            http://forum.springframework.org/forumdisplay.php?f=33
Jira              http://opensource.atlassian.com/projects/spring/browse/SEC

1.2 多方面的安全控制粒度

  1. URL 资源访问控制
     http://apps:8080/index.htm -> for public
     http://apps:8080/user.htm -> for authorized user
  2. 方法调用访问控制
    public void getData() -> all user
    public void modifyData() -> supervisor only
  3. 对象实例保护
    order.getValue() < $100 -> all user
    order.getValue() > $100 -> supervisor only

1.3 非入侵式安全架构

  1. 基于Servlet Filter和Spring aop,  使商业逻辑和安全逻辑分开,结构更清晰
  2. 使用Spring 来代理对象,能方便地保护方法调用

1.4 其它安全架构

    Acegi只是安全框架之一,其实还存在其它优秀的安全框架可供选择:

posted @ 2007-09-12 14:42 华梦行 阅读(187) | 评论 (0)编辑 收藏
http://wiki.springside.org.cn/display/springside/Acegi+Reference


http://www.springside.org.cn/docs/reference/Acegi2.htm

http://www.springside.org.cn/docs/reference/Acegi3.htm


http://www.springside.org.cn/docs/reference/Acegi4.htm
http://www.springside.org.cn/docs/reference/Acegi5.htm
http://www.springside.org.cn/docs/reference/Acegi6.htm
posted @ 2007-09-12 14:39 华梦行 阅读(158) | 评论 (0)编辑 收藏

package org.springframework.samples;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.generic.GenericBeanFactoryAccessor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowCountCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.StatementCallback;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.samples.petclinic.Person;

/**
 *
 * @author worldheart
 *
 */
public class MainTestForJdbcTemplate {

 private static final Log log = LogFactory.getLog(MainTestForJdbcTemplate.class);
 
 public static void main(String[] args) {  
  ListableBeanFactory cbf = new ClassPathXmlApplicationContext("ac1.xml");  
  GenericBeanFactoryAccessor gbfa = new GenericBeanFactoryAccessor(cbf);
  
  JdbcTemplate jt = gbfa.getBean("jdbcTemplate");
  
  jt.execute(new ConnectionCallback(){
   public Object doInConnection(Connection con) throws SQLException, DataAccessException {
    System.out.println(con.getMetaData().getDriverName());
    return null;
   }
  });
  
  List nameList = (List)jt.execute(new StatementCallback(){
   public Object doInStatement(Statement stmt) throws SQLException, DataAccessException {
    System.out.println(stmt.getConnection().getMetaData().getDatabaseProductVersion());
    List<String> nameList = new ArrayList<String>();
    ResultSet rs = null;
    try{
     rs = stmt.executeQuery("select name from types");
     while(rs.next()){
      nameList.add(rs.getString("name"));
     }
    }finally{
     JdbcUtils.closeResultSet(rs);
    }
    return nameList;
   }
  });
  System.out.println(nameList);
  
  List perList = (List)jt.query("select * from vets",
    new ResultSetExtractor(){
      public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
       List<Person> personList = new ArrayList<Person>();
       while(rs.next()){
        Person per = new Person();
        per.setId(rs.getInt("id"));
        per.setFirstName(rs.getString("first_name"));
        per.setLastName(rs.getString("last_name"));
        personList.add(per);
       }
       return personList;
    }
  });
  for(Iterator iterator = perList.iterator(); iterator.hasNext();){
   Person person = (Person)iterator.next();
   System.out.println(person.getId() + "," + person.getFirstName() + "," + person.getLastName());
  }

  final List<Person> pSonList = new ArrayList<Person>();
  jt.query("select * from vets", new RowCallbackHandler(){
   public void processRow(ResultSet rs) throws SQLException {
    Person per = new Person();
    per.setId(rs.getInt("id"));
    per.setFirstName(rs.getString("first_name"));
    per.setLastName(rs.getString("last_name"));
    pSonList.add(per);
   }
  });
  for(Person pSon: pSonList){
   System.out.println(pSon.getId() + "," + pSon.getFirstName() + "," + pSon.getLastName());
  }
  
  RowCountCallbackHandler rcch = new RowCountCallbackHandler();
  jt.query("select * from vets", rcch);
  for(String colName: rcch.getColumnNames())
   System.out.println(colName);
  for(int colType: rcch.getColumnTypes())
   System.out.println(colType);
  System.out.println(rcch.getColumnCount());
  System.out.println(rcch.getRowCount());
  
  List vetsList = (List)jt.query("select * from vets",
    new RowMapper(){
     public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
      Person pers = new Person();
      pers.setId(rs.getInt("id"));
      pers.setFirstName(rs.getString("first_name"));
      pers.setLastName(rs.getString("last_name"));
      return pers;
     }
  });
  System.out.println(vetsList);
  
  ColumnMapRowMapper cmrw = new ColumnMapRowMapper();
  List vList = (List)jt.query("select * from vets", cmrw);
  System.out.println(vList);
  
  System.out.println(jt.queryForInt("select count(*) from vets where id = ?",
    new Object[]{3}));
      
  jt.execute("update owners set address = 'GuangZhou' where telephone = ?",
    new PreparedStatementCallback(){
     public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
      ps.setString(1, "16068008");
      ps.addBatch();
      ps.setString(1, "6085555487");
      ps.addBatch();
      return ps.executeBatch();
     }
  });
  
  System.out.println(jt.query("select address from owners where first_name = ? and last_name = ?",
    new PreparedStatementSetter(){
     public void setValues(PreparedStatement ps) throws SQLException {
      ps.setString(1, "Jeff");
      ps.setString(2, "Black");
     }
    },
    new RowMapper(){
     public Object mapRow(ResultSet rs, int rowNum) throws SQLException {      
      return rs.getString("address");
     }
    }));
  
  System.out.println(jt.execute(
    new PreparedStatementCreator(){
     public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
      return con.prepareStatement("select address from owners");
     }
    },
    new PreparedStatementCallback(){
     public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
      List<String> list = new ArrayList<String>();
      ResultSet rs = null;
      try{
       rs = ps.executeQuery();
       while(rs.next()){
        list.add(rs.getString("address"));
       }
      }finally{
       JdbcUtils.closeResultSet(rs);
      }
      return list;
     }
    }));
  
 }

}

posted @ 2007-09-11 11:22 华梦行 阅读(292) | 评论 (0)编辑 收藏
public class BindStatus
extends Object
		

Simple adapter to expose the bind status of a field or object. Set as a variable both by the JSP bind tag and Velocity/FreeMarker macros.

  简单的适配器获取域或者是对象绑定状态, 同样适用于模板。
Obviously, object status representations (i.e. errors at the object level rather than the field level) do not have an expression and a value but only error codes and messages. For simplicity's sake and to be able to use the same tags and macros, the same status class is used for both scenarios.
显然,对象的状态表示(例如错误是对象级的而不是域级别的)没有表达式或者值,而是只有错误码和消息

Method Summary
 int doEndTag ()
           
 void doFinally ()
           
protected  int doStartTagInternal ()
          Called by doStartTag to perform the actual work.
 PropertyEditor getEditor ()
          Retrieve the PropertyEditor for the property that this tag is currently bound to.
 Errors getErrors ()
          Retrieve the Errors instance that this tag is currently bound to.
 String getPath ()
          Return the path that this tag applies to.
 String getProperty ()
          Retrieve the property that this tag is currently bound to, or null if bound to an object rather than a specific property.
 boolean isIgnoreNestedPath ()
          Return whether to ignore a nested path, if any.
 void setIgnoreNestedPath (boolean ignoreNestedPath)
          Set whether to ignore a nested path, if any.
 void setPath (String path)
          Set the path that this tag should apply.
posted @ 2007-09-11 11:00 华梦行 阅读(245) | 评论 (0)编辑 收藏

1 TagSupport与BodyTagSupport的区别

 TagSupport与BodyTagSupport的区别主要是标签处理类是否需要与标签体交互,如果不需要交互的就用TagSupport,否则如果不需要交互就用BodyTagSupport。

     交互就是标签处理类是否要读取标签体的内容和改变标签体返回的内容。

    用TagSupport实现的标签,都可以用BodyTagSupport来实现,因为BodyTagSupport继承了TagSupport。

 2 doStartTag(),doEndTag()

   doStartTag()方法是遇到标签开始时会呼叫的方法,其合法的返回值是EVAL_BODY_INCLUDE与SKIP_BODY,前者表示将显示标签间的文字,后者表示不显示标签间的文字;doEndTag()方法是在遇到标签结束时呼叫的方法,其合法的返回值是EVAL_PAGE与 SKIP_PAGE,前者表示处理完标签后继续执行以下的JSP网页,后者是表示不处理接下来的JSP网页

    doAfterBody(),这个方法是在显示完标签间文字之后呼叫的,其返回值有EVAL_BODY_AGAIN与SKIP_BODY,前者会再显示一次标签间的文字,后者则继续执行标签处理的下一步。

   预定的处理顺序是:doStartTag()返回SKIP_BODY,doAfterBodyTag()返回SKIP_BODY,doEndTag()返回EVAL_PAGE.

  如果继承了TagSupport之后,如果没有改写任何的方法,标签处理的执行顺序是:

   doStartTag() ->不显示文字 ->doEndTag()->执行接下来的网页

  如果您改写了doStartTag(),则必须指定返回值,如果指定了EVAL_BODY_INCLUDE,则执行顺序是

   doStartTag()->显示文字->doAfterBodyTag()->doEndTag()->执行下面的网页

 

下面這個程式簡單的示範如何使用自訂標籤來對網頁內容作一些保護:

    * GuardTag.java

package onlyfun.caterpillar; 

 

import java.io.*; 

import javax.servlet.jsp.*; 

import javax.servlet.jsp.tagext.*; 

 

public class GuardTag extends TagSupport { 

    public int doStartTag() throws JspException { 

        String valid = 

            pageContext.getRequest().getParameter("valid"); 

 

        // 如果flag設定為key,就顯示本體文字內容 

        if(valid.equals("valid_user")) { 

            return EVAL_BODY_INCLUDE; 

        } 

 

        return SKIP_BODY; 

    } 




同樣的,程式編譯完之後,放置在WEB-INF/classes/之下,然後編譯.tld檔案,如下:

    * guardtag.tld

<?xml version="1.0" encoding="UTF-8" ?> 

 

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" 

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

                        web-jsptaglibrary_2_0.xsd" 

    version="2.0"> 

    

    <description>Tag Demo</description> 

    <tlib-version>1.0</tlib-version> 

    <jsp-version>2.0</jsp-version> 

    <short-name>TagDemo</short-name> 

    <uri>/TagDemo</uri> 


    <tag> 

        <description>Cuard BodyText</description> 

        <name>guard</name> 

        <tag-class>onlyfun.caterpillar.GuardTag</tag-class> 

        <body-content>JSP</body-content> 

    </tag> 


</taglib> 


在<body-content>中設定的是JSP,這表示如果本體中包括JSP網頁的內容,將會被編譯執行,接下來您可以在web.xml中定義uri與.tld的名稱對應關係,方法與前一個主題相同,這邊就不重複說明了,然後撰寫一個測試的JSP網頁:

    * test.jsp

<%@taglib prefix="caterpillar" 

           uri="http://caterpillar.onlyfun.net/"%> 

<html> 

<body> 

    這個網頁包括受保護的內容OOOXXXX。。。。。。<p> 

    <caterpillar:guard> 

        ${ param.user }, 您好,幸運密碼是 oooxxx ! 

    </caterpillar:guard> 

</body> 

</html> 


為了要能看到幸運密碼,您必須在請求中包括guard參數,假設請求是:
http://localhost:8080/myjsp/test.jsp?valid=valid_user&user=Justin


這樣就可以看到幸運密碼了:
<html>

<body>

    這個網頁包括受包護的內容OOOXXXX。。。。。。<p>

   

        Justin, 您好,幸運密碼是: oooxxx !

   

</body>
</html>

posted @ 2007-09-11 10:09 华梦行 阅读(718) | 评论 (1)编辑 收藏

 public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

    JspFactory _jspxFactory = null;
    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;
    PageContext _jspx_page_context = null;


    try {
      _jspxFactory = JspFactory.getDefaultFactory();
      response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
         null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\n");
      out.write("\n");
      out.write("\n");
      out.write("\n");
      out.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n");
      out.write("   \"http://www.w3.org/TR/html4/loose.dtd\">\n");
      out.write("\n");
      out.write("<html>\n");
      out.write("    <head>\n");
      out.write("        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
      out.write("        <title>JSP Page</title>\n");
      out.write("    </head>\n");
      out.write("    <body>\n");
      out.write("\n");
      out.write("    <h1>JSP Page</h1>\n");
      out.write("\n");
      out.write("    \n");
      out.write("    </body>\n");
      out.write("</html>\n");
    } catch (Throwable t) {
      if (!(t instanceof SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          out.clearBuffer();
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
      }
    } finally {
      if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }

posted @ 2007-09-10 17:00 华梦行 阅读(297) | 评论 (0)编辑 收藏
JSP的运行内幕

文章作者:
责任编辑: 录入时间:2004-11-1 18:26:13 来源:第七频道
频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意. 

经常有朋友问起,JSP和Servlet之间有什么区别,两者之间又有什么联系?其实Servlet技术的出现时间很早,是当时为了Java的服务器端应用而开发的。大家都知道Applet是应用小程序,Servlet就是服务器端小程序了。但在Microsoft公司的ASP技术出现后,使用Servlet进行响应输出时一行行的输出语句就显得非常笨拙,对于复杂布局或者显示页面更是如此。JSP就是为了满足这种需求在Servlet技术之上开发的。可见,JSP和Servlet之间有着内在的血缘关系,在学习JSP时,如果能够抓住这种联系,就能更深刻地理解JSP的运行机理,达到事半功倍的效果。

本文将通过对一个JSP运行过程的剖析,深入JSP运行的内幕,并从全新的视角阐述一些JSP中的技术要点。

HelloWorld.jsp

我们以Tomcat 4.1.17服务器为例,来看看最简单的HelloWorld.jsp是怎么运行的。

代码清单1:HelloWorld.jsp

HelloWorld.jsp
<%
 String message = "Hello World!";
%>
<%=message%>


  这个文件非常简单,仅仅定义了一个String的变量,并且输出。把这个文件放到Tomcat的webapps\ROOT\目录下,启动Tomcat,在浏览器中访问http://localhost:8080/HelloWorld.jsp,浏览器中的输出为“HelloWorld!”

  让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的HelloWorld_jsp.java,这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件:

  代码清单2:HelloWorld_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class HelloWorld_jsp extends HttpJspBase {
 ......
public void _jspService(HttpServletRequest request, 
HttpServletResponse response)throws java.io.IOException, ServletException
 {
  JspFactory _jspxFactory = null;
  javax.servlet.jsp.PageContext pageContext = null;
  HttpSession session = null;
  ServletContext application = null;
  ServletConfig config = null;
  JspWriter out = null;
  Object page = this;
  JspWriter _jspx_out = null;

  try {
   _jspxFactory = JspFactory.getDefaultFactory();
   response.setContentType("text/html;charset=ISO-8859-1");
   pageContext = _jspxFactory.getPageContext(this, request, 
response,null, true, 8192, true); application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; String message = "Hello World!"; out.print(message); } catch (Throwable t) { out = _jspx_out; if (out != null && out.getBufferSize() != 0) out.clearBuffer(); if (pageContext != null) pageContext.handlePageException(t); } finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext); } } }


  从上面可以看出,HelloWorld.jsp在运行时首先解析成一个Java类HelloWorld_jsp.java,该类继承于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase实现了HttpServlet接口。可见,JSP在运行前首先将编译为一个Servlet,这就是理解JSP技术的关键。

  我们还知道JSP页面中内置了几个对象,如pageContext、application、config、page、session、out等,你可能会奇怪,为什么在JSP中的代码片断中可以直接使用这些内置对象。观察_jspService()方法,实际上这几个内置对象就是在这里定义的。在对JSP文件中的代码片断进行解析之前,先对这几个内置对象进行初始化。

  首先,调用JspFactory的getDefaultFactory()方法获取容器实现(本文中指Tomcat 4.1.17)的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法set/getDefaultFactory()。set方法由JSP容器(Tomcat)实例化该页面Servlet(即HelloWorld_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。

  然后,调用这个JspFactoryImpl的getPageContext()方法,填充一个PageContext返回,并赋给内置变量pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码,这里不再赘述。该页面Servlet的环境设置完毕,开始对页面进行解析。HelloWorld.jsp页面仅仅定义了一个String变量,然后直接输出。解析后的代码如下:

  代码清单3:JSP页面解析后的代码片断

String message = "Hello World!";
out.print(message);


  定制标签的解析过程

  在一个中大型的Web应用中,通常使用JSP定制标签来封装页面显示逻辑。剖析容器对定制标签的解析过程,对我们深入理解定制标签的运行机理非常有帮助。下面我们以Struts1.1b中附带的struts-example应用的主页运行为例加以说明。

  包含定制标签的index.jsp

  Struts1.1b的下载地址是http://jakarta.apache.org/struts/index.html。将下载的包解压,在webapps目录下可以找到struts-example.war。将该War包拷贝到Tomcat的webapps目录下,Tomcat会自动安装此应用包。在浏览器中通过http://localhost:8080/struts-example访问struts-example应用,将显示应用的首页(见图1)。



  图一 应用的首页

  代码清单4:index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html:html locale="true">
<head>
<title><bean:message key="index.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
…… 
</body>
</html:html>


  我们仅以index.jsp中的<bean:message/>标签的解析为例进行分析,看容器是怎样把这个自定义标签解析成HTML输出的。上面代码省略了页面的其它显示部分。首先,查看上面浏览器中页面的源文件:

<html lang="zh">
<head>
<title>MailReader Demonstration Application (Struts 1.0)</title>
</head>
<body bgcolor="white">
……
</body>
</html>


  可见,容器已经把<bean:message key="index.title"/>替换成一个字串,显示为页面的标题。

  解析过程

  那么,JSP容器是怎样完成解析的呢?查看在工作目录jakarta-tomcat-4.1.17\work\Standalone\localhost\struts-example下解析后的index_jsp.java文件:

  代码清单5:index_jsp.java

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class index_jsp extends HttpJspBase {
 //为所有的定制标签定义处理器池类的引用
 private org.apache.jasper.runtime.TagHandlerPool ;
 _jspx_tagPool_bean_message_key;
 ……
 //页面类构造方法
 public index_jsp() {
  _jspx_tagPool_bean_message_key =
  new org.apache.jasper.runtime.TagHandlerPool();
   ……
 }

 public void _jspService(HttpServletRequest request,
   HttpServletResponse response) 
   throws java.io.IOException, ServletException {
  ……
  _jspxFactory = JspFactory.getDefaultFactory();
  response.setContentType("text/html;charset=UTF-8");
  pageContext = _jspxFactory.getPageContext(this,
    request, response,null, true, 8192, true);
  application = pageContext.getServletContext();
  config = pageContext.getServletConfig();
  session = pageContext.getSession();
  out = pageContext.getOut();
  _jspx_out = out;
  ……
  if (_jspx_meth_html_html_0(pageContext))
  return;
  ……
 }
 //页面在处理退出时释放所有定制标签的属性
 public void _jspDestroy() {
  _jspx_tagPool_bean_message_key.release();
  ……
 }
}


  生成的index_jsp.java继承于org.apache. jasper.runtime.HttpJspBase。研究这个文件为我们了解定制标签的运行机理提供了途径。

  从上面可以看出,Tomcat在解析一个JSP页面时,首先为每一个定制标签定义并实例化了一个TagHandlerPool对象。页面的处理方法覆盖父类的_ jspService()方法,_jspService方法首先初始化环境,为内置对象赋值。由于index.jsp页面整体由一个<html:html/>标签包裹,Tomcat对每一个标签都产生一个私有方法加以实现。<html:html/>标签的处理方法是_jspx_meth_html_html_0()。这个方法的命名规范大家也可以从这里看出,就是“_jspx_meth + 标签的前缀 + 标签名 + 该标签在JSP页面同类标签中出现的序号”。其它标签都被包含在该标签中,所以其它标签在_jspx_meth_html_html_0()方法中进行解析。具体的代码实现请参见赛迪网http://linux.ccidnet.com期刊浏览2003年第6期。

  在_jspx_meth_html_html_0()方法中,首先从_jspx_tagPool_html_html_locale池中得到一个org.apache.struts.taglib.html.HtmlTag的实例,然后设置这个tag实例的页面上下文及上级标签,由于html:html标签是页面的最顶层标签,所以它的parent是null。然后对该标签的内容进行解析。HTML代码直接输出,下面主要看看<html:html></html:html>标签之间包含的<bean:message key="index.title"/>标签的解析。对bean:message标签的解析类似于html:html,Tomcat也将其放入一个单独的方法_jspx_meth_bean_message_0()中进行。

  bean:message标签的解析

  代码清单7:_jspx_meth_bean_message_0()方法片断

//对message定制标签的处理方法
private boolean _jspx_meth_bean_message_0(
javax.servlet.jsp.tagext.Tag _jspx_th_html_html_0, 
javax.servlet.jsp.PageContext pageContext) throws Throwable {
 JspWriter out = pageContext.getOut();
 /* ----  bean:message ---- */
 org.apache.struts.taglib.bean.MessageTag
 _jspx_th_bean_message_0 =
 (org.apache.struts.taglib.bean.MessageTag) 
 _jspx_tagPool_bean_message_key.get(
 org.apache.struts.taglib.bean.MessageTag.class);
 _jspx_th_bean_message_0.setPageContext(pageContext);
 _jspx_th_bean_message_0.setParent(_jspx_th_html_html_0);
 _jspx_th_bean_message_0.setKey("index.title");
 int _jspx_eval_bean_message_0 = _jspx_th_bean_message_0.doStartTag();
 if (_jspx_th_bean_message_0.doEndTag()== javax.servlet.jsp.
tagext.Tag.SKIP_PAGE) return true; _jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0); return false; }


  同样,对html:bean也需要从池中得到一个标签类的实例,然后设置环境。这里不再赘述。我们只专注对MessageTag定制标签类特殊的处理部分。定制标签类的开发不在本文讨论范围之内。在index.jsp中定义了一个bean:message标签,并设置了一个属性:<bean:message key="index.title"/>。Tomcat在解析时,调用MessageTag对象的key属性设置方法setKey(),将该属性置入。然后调用MessageTag的doStartTag()和doEndTag()方法,完成解析。如果doEndTag()方法的返回值为javax.servlet.jsp.tagext.Tag. SKIP_PAGE,表明已经完成解析,返回true,Tomcat将立即停止剩余页面代码的执行,并返回。否则把该MessageTag的实例放回池中。

  标签类对象实例的池化

  为了提高运行效率,Tomcat对所有的定制标签类进行了池化,池化工作由org.apache.jasper. runtime.TagHandlerPool类完成。TagHandlerPool类主要有两个方法,代码如下:

  代码清单8:TagHandlerPool.java

public class TagHandlerPool {
 private static final int MAX_POOL_SIZE = 5;
 private Tag[] handlers;
 public synchronized Tag get(Class handlerClass) throws JspException {……}
 public synchronized void reuse(Tag handler) {……}
}


  TagHandlerPool简单地实现了对标签类的池化,其中MAX_POOL_SIZE是池的初始大小,handlers是一个Tag的数组,存储标签类的实例。get(Class handlerClass)得到一个指定标签类的实例,如果池中没有可用实例,则新实例化一个。reuse(Tag handler)把handler对象放回池中。

  至此,我们对JSP在容器中的运行过程已经了然于胸了。虽然每种JSP容器的解析结果会有差异,但其中的原理都雷同。对于编写JSP应用,我们并不需要干涉容器中的运行过程,但如果你对整个底层的运行机制比较熟悉,就能对JSP/Servlet技术有更深的认识。
posted @ 2007-09-10 16:53 华梦行 阅读(192) | 评论 (0)编辑 收藏
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
  jt.query("select * from vets", rcch);
  for(String colName: rcch.getColumnNames())
   System.out.println(colName);
  for(int colType: rcch.getColumnTypes())
   System.out.println(colType);
  System.out.println(rcch.getColumnCount());
  System.out.println(rcch.getRowCount());
posted @ 2007-09-10 11:35 华梦行 阅读(1022) | 评论 (0)编辑 收藏
for(Person pSon: pSonList){
   System.out.println(pSon.getId() + "," + pSon.getFirstName() + "," + pSon.getLastName());
  }
posted @ 2007-09-10 11:31 华梦行 阅读(113) | 评论 (0)编辑 收藏
     摘要: /** * Copyright: Copyright (c) 2005-2005 * Company: JavaResearch(http://www.javaresearch.org) ...  阅读全文
posted @ 2007-09-10 11:24 华梦行 阅读(2382) | 评论 (0)编辑 收藏
  1. /**


  2. * Copyright: Copyright (c) 2005-2005
  3. * Company: JavaResearch(http://www.javaresearch.org)
  4. */
  5. package org.javaresearch.jerch;



  6. import java.sql.PreparedStatement;
  7. import java.sql.SQLException;

  8. /**
  9. * 批量更新时设置PreparedStatement的值的接口定义。
  10. * 最后更新日期:2005年3月25日
  11. * @author cherami
  12. */
  13. public interface BatchPreparedStatementSetter {
  14.   /**
  15.    * 得到批次的总次数。
  16.    * @return 批次的总次数
  17.    */
  18.   publicint getBatchSize();

  19.   /**
  20.    * 设置第i次的值。
  21.    * 请注意它是针对每一次设置值的,
  22.    * 如果所有的值不是保存在一个List类型的可以通过索引访问的集合中,
  23.    * 那么这个方法的实现中可能需要使用switch或者if语句进行判断。
  24.    * 你可以考虑使用PreparedStatementSetter一次性设置全部的批次。
  25.    * @param ps PreparedStatement
  26.    * @param i 执行批次
  27.    * @throws SQLException
  28.    */
  29.   publicvoid setValues(PreparedStatement ps, int i) throwsSQLException;
  30. }
posted @ 2007-09-10 11:21 华梦行 阅读(1086) | 评论 (0)编辑 收藏

所谓的回调就是在执行statement A过程中,用到了statement B,那么先保存以前的执行信息,此时statement B 可以使用Statement A 的内容,然后再执行 Statement B, Statement B执行完毕后,返回的结果,可以被Statement A 利用,然后继续执行statementA。这就是传说中回调

posted @ 2007-09-10 11:16 华梦行 阅读(178) | 评论 (0)编辑 收藏
jt.execute("update owners set address = 'GuangZhou' where telephone = ?",
    new PreparedStatementCallback(){
     public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
      ps.setString(1, "16068008");
      ps.addBatch();
      ps.setString(1, "6085555487");
      ps.addBatch();
      return ps.executeBatch();
     }
  });
  1. /**


  2. * Copyright: Copyright (c) 2005-2005
  3. * Company: JavaResearch(http://www.javaresearch.org)
  4. */
  5. package org.javaresearch.jerch;

  6. import java.sql.PreparedStatement;
  7. import java.sql.SQLException;

  8. /**
  9. * PreparedStatement回调接口定义。
  10. * 最后更新日期:2005年3月28日
  11. * @author cherami
  12. */
  13. publicinterfacePreparedStatementCallback {
  14.   /**
  15.    * 定义PreparedStatement中的执行内容。
  16.    * 执行前PreparedStatement的参数等内容都已经设置好了。
  17.    * @param stmt PreparedStatement
  18.    * @return 执行的结果
  19.    * @throws SQLException
  20.    */
  21.   publicObject doInPreparedStatement(PreparedStatement stmt) throwsSQLException;
  22. }
posted @ 2007-09-10 11:10 华梦行 阅读(4319) | 评论 (0)编辑 收藏
  1. /**
  2. * Copyright: Copyright (c) 2005-2005
  3. * Company: JavaResearch(http://www.javaresearch.org)
  4. */
  5. package org.javaresearch.jerch;

  6. import java.sql.ResultSet;
  7. import java.sql.SQLException;

  8. /**
  9. * 提取ResultSet中的全部数据的接口定义。
  10. * 最后更新日期:2005年3月28日
  11. * @author cherami
  12. */
  13. public interface ResultSetExtractor {
  14.   /**
  15.    * 提取ResultSet中的全部数据。
  16.    * @param rs ResultSet
  17.    * @return ResultSet中的全部数据
  18.    * @throws SQLException
  19.    */
  20.   publicObject extractSet(ResultSet rs) throwsSQLException;
  21. }

List perList = (List)jt.query("select * from vets",
    new ResultSetExtractor(){
      public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
       List<Person> personList = new ArrayList<Person>();
       while(rs.next()){
        Person per = new Person();
        per.setId(rs.getInt("id"));
        per.setFirstName(rs.getString("first_name"));
        per.setLastName(rs.getString("last_name"));
        personList.add(per);
       }
       return personList;
    }
  });

posted @ 2007-09-10 11:05 华梦行 阅读(307) | 评论 (0)编辑 收藏
  1. public interface Mappable {


  2.   /**
  3.    * 得到字段对应的填充方法的方法名。
  4.    * @param fieldName 数据库表的字段名
  5.    * @return 进行填充的方法名。
  6.    */
  7.   publicString getMapMethod(String fieldName);
  8.   /**
  9.    * 得到字段对应的填充方法的参数类型。
  10.    * 数据库返回的值的类型和Java中的可能不是匹配的,或者JavaBean中自己定义为原始类型了,因此需要指定。
  11.    * @param fieldName 数据库表的字段名
  12.    * @param dbType 数据库返回的类型常量定义
  13.    * @return 进行填充的方法的参数的类型
  14.    */
  15.   publicClass getMethodParameterType(String fieldName,int dbType);
  16. }
posted @ 2007-09-10 11:00 华梦行 阅读(153) | 评论 (0)编辑 收藏
  1. /**


  2. * Copyright: Copyright (c) 2005-2005
  3. * Company: JavaResearch(http://www.javaresearch.org)
  4. */
  5. package org.javaresearch.jerch;

  6. import java.sql.PreparedStatement;
  7. import java.sql.SQLException;

  8. /**
  9. * 设置PreparedStatement的参数的接口定义。
  10. * 最后更新日期:2005年3月28日
  11. * @author cherami
  12. */
  13. public interface PreparedStatementSetter {
  14.   /**
  15.    * 设置PreparedStatement所需的全部参数。
  16.    * @param ps PreparedStatement
  17.    * @throws SQLException
  18.    */
  19.   publicvoid setValues(PreparedStatement ps)  throwsSQLException;
  20. }
  21. jt.query("select address from owners where first_name = ? and last_name = ?",
        new PreparedStatementSetter(){
         public void setValues(PreparedStatement ps) throws SQLException {
          ps.setString(1, "Jeff");
          ps.setString(2, "Black");
         }
        },
        new RowMapper(){
         public Object mapRow(ResultSet rs, int rowNum) throws SQLException {      
          return rs.getString("address");
         }
        }));
posted @ 2007-09-10 10:54 华梦行 阅读(4020) | 评论 (0)编辑 收藏
  1. /**


  2. * Copyright: Copyright (c) 2005-2005
  3. * Company: JavaResearch(http://www.javaresearch.org)
  4. */
  5. package org.javaresearch.jerch;

  6. import java.sql.Connection;
  7. import java.sql.PreparedStatement;
  8. import java.sql.SQLException;

  9. /**
  10. * 创建PreparedStatement的接口定义。
  11. * 最后更新日期:2005年3月28日
  12. * @author cherami
  13. */
  14. public interface PreparedStatementCreator {
  15.   /**
  16.    * 从数据库连接中创建一个PreparedStatement。
  17.    * @param con 数据库连接
  18.    * @return 创建好的PreparedStatement
  19.    * @throws SQLException
  20.    */
  21.   publicPreparedStatement createPreparedStatement(Connection con) throwsSQLException;
  22. }
  23. 使用实例:
  24. jt  jdbctemplate:
      System.out.println(jt.execute(
        new PreparedStatementCreator(){
         public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
          return con.prepareStatement("select address from owners");
         }
        },
        new PreparedStatementCallback(){
         public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
          List<String> list = new ArrayList<String>();
          ResultSet rs = null;
          try{
           rs = ps.executeQuery();
           while(rs.next()){
            list.add(rs.getString("address"));
           }
          }finally{
           JdbcUtils.closeResultSet(rs);
          }
          return list;
         }
        }));
posted @ 2007-09-10 10:38 华梦行 阅读(4163) | 评论 (0)编辑 收藏

使用 Commons-attributes-compiler一定要注意其中 在Meta-Info中的数据,因此,要注意他的版本

posted @ 2007-09-07 13:53 华梦行 阅读(140) | 评论 (0)编辑 收藏

文章: 49
积分: 89
来自: 浙江杭州

       时间: 2007-02-09 14:38    关键字:   Spring spring        

1、使用JdbcTemplate的execute()方法执行SQL语句

代码
  1. jdbcTemplate.execute( "CREATE TABLE USER (user_id integer, name varchar(100))" );  

2、如果是UPDATE或INSERT,可以用update()方法。
代码
  1. jdbcTemplate.update("INSERT INTO USER VALUES('"  
  2.            + user.getId() + "', '"  
  3.            + user.getName() + "', '"  
  4.            + user.getSex() + "', '"  
  5.            + user.getAge() + "')");   

3、带参数的更新
代码
  1. jdbcTemplate.update("UPDATE USER SET name = ? WHERE user_id = ?"new Object[] {name, id});  

代码
  1. jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)"new Object[] {user.getId(), user.getName(), user.getSex(), user.getAge()});   

4、使用JdbcTemplate进行查询时,使用queryForXXX()等方法
代码
  1. int count = jdbcTemplate.queryForInt("SELECT COUNT(*) FROM USER");  

代码
  1. String name = (String) jdbcTemplate.queryForObject("SELECT name FROM USER WHERE user_id = ?"new Object[] {id}, java.lang.String.class);  

代码
  1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");  

代码
  1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");   
  2. Iterator it = rows.iterator();   
  3. while(it.hasNext()) {   
  4.     Map userMap = (Map) it.next();   
  5.     System.out.print(userMap.get("user_id") + "\t");   
  6.     System.out.print(userMap.get("name") + "\t");   
  7.     System.out.print(userMap.get("sex") + "\t");   
  8.     System.out.println(userMap.get("age") + "\t");   
  9. }   

JdbcTemplate将我们使用的JDBC的流程封装起来,包括了异常的捕捉、SQL的执行、查询结果的转换等等。spring大量使用Template Method模式来封装固定流程的动作,XXXTemplate等类别都是基于这种方式的实现。
除了大量使用Template Method来封装一些底层的操作细节,spring也大量使用callback方式类回调相关类别的方法以提供JDBC相关类别的功能,使传统的JDBC的使用者也能清楚了解spring所提供的相关封装类别方法的使用。

JDBC的PreparedStatement

代码
  1. final String id = user.getId();   
  2. final String name = user.getName();   
  3. final String sex = user.getSex() + "";   
  4. final int age = user.getAge();   
  5.   
  6. jdbcTemplate.update("INSERT INTO USER VALUES(?, ?, ?, ?)",   
  7.                      new PreparedStatementSetter() {   
  8.                          public void setValues(PreparedStatement ps) throws SQLException {   
  9.                              ps.setString(1, id);   
  10.                              ps.setString(2, name);             
  11.                              ps.setString(3, sex);   
  12.                              ps.setInt(4, age);   
  13.                          }   
  14.                      });   
  15.   

代码
  1. final User user = new User();   
  2. jdbcTemplate.query("SELECT * FROM USER WHERE user_id = ?",   
  3.                     new Object[] {id},   
  4.                     new RowCallbackHandler() {   
  5.                         public void processRow(ResultSet rs) throws SQLException {   
  6.                             user.setId(rs.getString("user_id"));   
  7.                             user.setName(rs.getString("name"));   
  8.                             user.setSex(rs.getString("sex").charAt(0));   
  9.                             user.setAge(rs.getInt("age"));   
  10.                         }   
  11.                     });   
  12.   

代码
  1. class UserRowMapper implements RowMapper {   
  2.     public Object mapRow(ResultSet rs, int index) throws SQLException {   
  3.         User user = new User();   
  4.   
  5.         user.setId(rs.getString("user_id"));   
  6.         user.setName(rs.getString("name"));   
  7.         user.setSex(rs.getString("sex").charAt(0));   
  8.         user.setAge(rs.getInt("age"));   
  9.   
  10.         return user;   
  11.     }   
  12. }   
  13.   
  14. public List findAllByRowMapperResultReader() {   
  15.     String sql = "SELECT * FROM USER";   
  16.     return jdbcTemplate.query(sql, new RowMapperResultReader(new UserRowMapper()));   
  17. }   
  18.   

在getUser(id)里面使用UserRowMapper

代码
  1. public User getUser(final String id) throws DataAccessException {   
  2.     String sql = "SELECT * FROM USER WHERE user_id=?";   
  3.     final Object[] params = new Object[] { id };   
  4.     List list = jdbcTemplate.query(sql, params, new RowMapperResultReader(new UserRowMapper()));   
  5.   
  6.     return (User) list.get(0);   
  7. }   

网上收集
org.springframework.jdbc.core.PreparedStatementCreator 返回预编译SQL 不能于Object[]一起用

代码
  1. public PreparedStatement createPreparedStatement(Connection con) throws SQLException {   
  2.  return con.prepareStatement(sql);   
  3. }   

1.增删改
org.springframework.jdbc.core.JdbcTemplate 类(必须指定数据源dataSource)
代码
  1. template.update("insert into web_person values(?,?,?)",Object[]);   


代码
  1. template.update("insert into web_person values(?,?,?)",new PreparedStatementSetter(){ 匿名内部类 只能访问外部最终局部变量   
  2.   
  3.  public void setValues(PreparedStatement ps) throws SQLException {   
  4.   ps.setInt(index++,3);   
  5. });   

org.springframework.jdbc.core.PreparedStatementSetter 接口 处理预编译SQL
代码
  1. public void setValues(PreparedStatement ps) throws SQLException {   
  2.  ps.setInt(index++,3);   
  3. }   

2.查询JdbcTemplate.query(String,[Object[]/PreparedStatementSetter],RowMapper/RowCallbackHandler)
org.springframework.jdbc.core.RowMapper 记录映射接口 处理结果集
代码
  1. public Object mapRow(ResultSet rs, int arg1) throws SQLException {   int表当前行数   
  2.   person.setId(rs.getInt("id"));   
  3. }   
  4. List template.query("select * from web_person where id=?",Object[],RowMapper);   

org.springframework.jdbc.core.RowCallbackHandler 记录回调管理器接口 处理结果集
代码
  1. template.query("select * from web_person where id=?",Object[],new RowCallbackHandler(){   
  2.  public void processRow(ResultSet rs) throws SQLException {   
  3.   person.setId(rs.getInt("id"));   
  4. });   
posted @ 2007-09-06 18:04 华梦行 阅读(155) | 评论 (0)编辑 收藏
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
  <property name="username" value="sa" />
  <property name="password" value="" />
  <property name="url" value="jdbc:hsqldb:hsql://localhost:9001" />
 </bean>
 
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource"></property>
 </bean>

ListableBeanFactory cbf = new ClassPathXmlApplicationContext("ac1.xml");
  JdbcTemplate jt = (JdbcTemplate) cbf.getBean("jdbcTemplate");  
  List rsList = jt.queryForList("select * from pets");
  //////////////////// 首先取得list
  for(Iterator iterator = rsList.iterator();iterator.hasNext() ;){
//////////////////////////////将所有的list迭代出来
   System.out.println(iterator.next());
  }  
  1. List rows = jdbcTemplate.queryForList("SELECT * FROM USER");   
  2. Iterator it = rows.iterator();   
  3. while(it.hasNext()) {   
  4.     Map userMap = (Map) it.next();   
  5.     System.out.print(userMap.get("user_id") + "\t");   
  6.     System.out.print(userMap.get("name") + "\t");   
  7.     System.out.print(userMap.get("sex") + "\t");   
  8.     System.out.println(userMap.get("age") + "\t");   
  9. }
posted @ 2007-09-06 17:50 华梦行 阅读(431) | 评论 (0)编辑 收藏
select  getdate()  返回当前时间

Oracle      所有的日期函数都没有()
select Sysdate from dual
2007-9-6 11:27:25

 select sessiontimezone,current_timestamp from dual;
 +08:00

   2007-9-6 11:27:25.234000 +08:00

 select sessiontimezone,current_timestamp  ,current_date ,sysdate from dual;
posted @ 2007-09-06 11:36 华梦行 阅读(199) | 评论 (0)编辑 收藏

昨天在论坛看到一篇讨论嵌入式数据库HSQLDB(http://www.javaeye.com/topic/79802)的帖子,想到自己曾经读过部分它的源码,有一种对某些技术豁然开朗的感觉。所以,也希望和朋友们一起分享,大家有什么好的感受,不如也分享一下吧。下面是我对那个帖子的冗余回复,我觉得有必要专门发一篇帖子重复一下:

说点题外话,建议大家读读HSQLDB的源码,特别是jdbc driver(org/hsqldb/jdbc包)那部分,写得清晰易懂。读了它的部分源码,我自认为对下面一些问题理解深入了:
1、JDBC规范和JDBC实现的关系:怎么自己去设计一个规范,一种架构?我是否自己可以为某种数据设计jdbc driver,如何设计?想想php里面各数据库的函数库各自为政对程序移植性的影响,就知道jdbc规范有多么重要了。

2、JDBC协议:JDBC是基于socket之上的,数据包格式(org.hsqldb.Result)(mysql数据包格式公开了)?那么JMS数据包呢?其实,这也可以延伸到分布式协议的设计原理,如RMI、SOAP。其实,这些数据包格式和JSON、YAML这些message格式没有本质的区别,只不过应用范围不一样。任何分布式协议,肯定有一种message格式。

3、JDBC over HTTP:这样我们对RMI over IIOP, soap over HTTP, http tunnel原理有更深入的理解。

4、什么是long connection(jdbc的socket),什么是short connection(http),具体怎么实现?
3和4这些在HSQLDB的org.hsqldb.HTTPClientConnection类里有实现。

5、Java客户端和服务器端的通讯实现:jdbc driver就可以认为是一个java客户端类库。那么JMS client呢?还有,像mysql有各种语言的driver,原理是什么。

6、sql这种command、描述型语言究竟在数据库里面是个什么地位:sql是怎么传入jdbc driver,最终和database交互的?我们是否可以设计出另外一种command,形成一种行业标准,它在服务器和客户端怎么实现的。

以上我的表达可能有些晦涩,我只想表达一点:大家有兴趣就多读读经典的源码,扩展一下自己的设计思路。可能很多人象我一样,总有忙不完的项目,那么抽几个小时就够了,不必深入。
有很多技术我们理解总是很模糊,当你深入到内部,忽然发现原来就这么回事。我们总觉得IoC很神秘,其实最简单的IoC容器,也许一个HashMap就够了。


引用的http://www.javaeye.com/topic/80532

posted @ 2007-09-06 10:21 华梦行 阅读(663) | 评论 (0)编辑 收藏
//通过MessageSourceResolvable接口获得message_zh_CN.properties中的消息
  MessageSourceResolvable msr = new DefaultMessageSourceResolvable(new String[]{"welcome"},
    new Object[]{"默认MessageSourceResolvable实现"});
  System.out.println(aac.getMessage(msr, Locale.CHINA));

 

posted @ 2007-09-05 16:43 华梦行 阅读(442) | 评论 (0)编辑 收藏
  Sql 语法规则
@intCount  INT Output  ,
@chvKeywords            VARCHAR(100),            --关键字
 @dtmdatelowerlimit               DATETIME ,
@dtmdateupperlimit              DATETIME ,
@bitViewPersonalLimit  BIT,  --浏览个人

ORACLE 语法规则
chvOrgTypeID  IN VARCHAR2  DEFAULT NULL,
chCreatorName  IN VARCHAR2  DEFAULT NULL,
tempCount    in out          integer,---输入输出
posted @ 2007-09-03 16:48 华梦行 阅读(181) | 评论 (0)编辑 收藏

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS OFF
GO

 

ALTER             PROCEDURE spITM_CheckPaperList(
@intCount  INT Output  ,
@chvKeywords            VARCHAR(100),            --关键字
@chvinterunittypeid             varchar(100),
 @dtmdatelowerlimit               DATETIME ,
@dtmdateupperlimit              DATETIME ,
@isspecialbuy             int,
@checkresultid            int,
  @intAudit                         INT,                                --审批状态
@chvEmployeeTypeID VARCHAR(100) ,  --职员id
@bitViewPersonalLimit  BIT,  --浏览个人
@bitViewDepartmentLimit BIT,  --浏览部门
@bitEmployeeIsManager  BIT,  --浏览全部
   @chvOrgTypeID            VARCHAR(100), 
@intPageSize  INT  ,
@intPageNo  INT  
)
AS
--权限控制条件开始
DECLARE @chvEmployeeDepartment  VARCHAR(36)
DECLARE @bitEmployeeIsAdmin  BIT
SELECT @chvEmployeeDepartment = '000'

IF EXISTS(SELECT TypeID FROM CRM_Employee WHERE TypeID = @chvEmployeeTypeID)
 AND
 EXISTS(SELECT Count(*) FROM CRM_LoginUser WHERE InnerObject = 'Employee' AND InnerObjectTypeID = @chvEmployeeTypeID)
BEGIN
 --SELECT @chvEmployeeDepartment = [Department] FROM [CRM_Employee] WHERE [TypeID] = @chvEmployeeTypeID
 SELECT @bitEmployeeIsAdmin = IsAdmin FROM CRM_LoginUser WHERE InnerObject = 'Employee' AND InnerObjectTypeID = @chvEmployeeTypeID
 --deal  empty 2007/1/22
 SELECT @chvEmployeeDepartment = case @chvEmployeeDepartment when ' ' then  '000' else  @chvEmployeeDepartment end
END
ELSE
BEGIN
 SELECT * FROM ITM_CheckPaper  WHERE TypeID = '0' --返回一个空的记录集
 RETURN
END
--权限控制条件结束--
select a.*  ,b.Name VendorName,  ww.Name CheckPaperName,
w.Name CreatorName
  INTO #ITM_CheckPaperListPageTable
   from ITM_CheckPaper as  a 
             left JOIN CRM_Employee w      ON a.CreatorTypeID = w.TypeID
       left join CRM_Employee ww on a.CHECKERTYPEID=ww.Typeid
  LEFT JOIN scm_Vendor b ON a.VendorTypeID = b.TypeID
WHERE
 a.OrgTypeID = @chvOrgTypeID and
(
 a.SERIALNUMBER     like '%'+@chvKeywords+'%' or
 a.ContractNo                 like '%'+@chvKeywords+'%' or
b.Name                 like '%'+@chvKeywords+'%' or
 a.CheckSite     like '%'+@chvKeywords+'%'
)
--and
--a.AuditFlag = case @intAudit
  ---                        when 0 then a.AuditFlag
  --                       else @intAudit
  --                    end
--权限控制条件开始--
AND
(
 @bitViewDepartmentLimit = 1
 AND
 (
 ISNULL(w.[Department],'001') LIKE ISNULL(@chvEmployeeDepartment,'not the same') + '%'
 OR
 ISNULL(w.[Department2],'001') LIKE ISNULL(@chvEmployeeDepartment,'not the same') + '%'
 OR
 ISNULL(w.[Department3],'001') LIKE  ISNULL(@chvEmployeeDepartment,'not the same') + '%'
 )
 OR
 a.[CreatorTypeID] = @chvEmployeeTypeID  AND  @bitViewPersonalLimit = 1
 OR
 @bitEmployeeIsAdmin = 1
 OR
 @bitEmployeeIsManager = 1
 OR
 a.[EmployeeRange] LIKE '%' +@chvEmployeeTypeID +'%'
)
--权限控制条件结束--
--Order by a.CreateDate desc
---------------判断是否取记录数
if @intCount = 1
Begin
 SELECT @intCount=Count(0)
 FROM #ITM_CheckPaperListPageTable;
End
--------------------------取记录数完成
DECLARE @chvSql  VARCHAR(1000)
--处理大于总页数时的请求页数
DECLARE @intPageCount INT
SELECT @intPageCount = (@intCount + @intPageSize-1) / @intPageSize;
IF @intPageNo > 1 AND @intPageNo > @intPageCount
 SELECT @intPageNo = @intPageCount
ELSE IF @intPageNo > @intPageCount
 SELECT @intPageNo = 1
--处理大于总页数时的请求页数结束
Select @chvSql = 'SELECT TOP ' + Str(@intPageSize) + '  *  ' +
' FROM #ITM_CheckPaperListPageTable a ' +
' WHERE a.TypeID not in ' +
' (select top ' + Str((@intPageNo - 1) * @intPageSize) + ' TypeID from #ITM_CheckPaperListPageTable )'
Exec(@chvSql)
Drop Table #ITM_CheckPaperListPageTable

 

 

 

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

 

posted @ 2007-09-03 14:39 华梦行 阅读(192) | 评论 (0)编辑 收藏
http://www.mediafire.com/index.php
posted @ 2007-08-31 13:56 华梦行 阅读(84) | 评论 (0)编辑 收藏

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<!--
  - DispatcherServlet application context for the Countries web tier.
  -->
<beans>

 <!-- ========================= MAPPING DEFINITIONS ========================= -->

 <!--
  - Explicit view mappings in bundle instead of default InternalResourceViewResolver.
   - Fetches the view mappings from localized "views_xx" classpath files, i.e.
   - "/WEB-INF/classes/views-countries.properties" or "/WEB-INF/classes/views-countries_fr.properties".
   -
   - Symbolic view names returned by controllers will be resolved in the respective
   - properties file, allowing for arbitrary mappings between names and resources.
   -
   - We use the "defaultParentView" property. All views defined will by default inherit
  - the properties defined in the "modelView" view.
   -->
 <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
  <property name="basename" value="views-countries"/>
  <property name="defaultParentView" value="modelView"/>
 </bean>

 <!--
  - We specify here that Locale and theme are stored in cookies.
   - They could be stored in a Session. Default resolvers don't allow changing them on the fly.
  -->
 <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>

 <bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver">
  <property name="defaultThemeName" value="spring"/>
 </bean>

 <!--
        路径映射
  - Explicit URL handler mapping instead of default BeanNameUrlHandlerMapping.
  -->
 <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="interceptors">
   <list>
    <ref bean="localeChangeInterceptor"/>
    <ref bean="themeChangeInterceptor"/>
   </list>
  </property>
  <property name="mappings">
   <props><--  当请求发送过来时,自动交给相应的控制器,让控制器来处理相应的逻辑和渲染相应的视图  -->
    <prop key="/home.htm">countriesController</prop>
    <prop key="/config.htm">countriesController</prop>
    <prop key="/copy.htm">countriesController</prop>
    <prop key="/main/home.htm">countriesController</prop>
    <prop key="/main/detail.htm">countriesController</prop>
    <prop key="/main/countries.xls">countriesController</prop>
    <prop key="/main/countries.pdf">countriesController</prop>
    <prop key="/notfound.htm">errorsController</prop>
   </props>
  </property>
 </bean>


 <!-- ========================= CONTROLLER DEFINITIONS ========================= -->

 <!--
  - Interceptors will pre-handle any request in this servlet, no matter which controller
  - is mapped for a request.
  -
  - We use two built-in interceptors to detect user locale or theme change requests.
  - The third interceptor is specific to this Demo. It allows views to easily be aware
  - about the configuration detected. Precisely to know if a copy data to database can be
  - proposed to the user.
 -->
 <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>

 <bean id="themeChangeInterceptor" class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>

 <!-- General use multi-action controller for errors -->
 <bean id="errorsController" class="org.springframework.samples.countries.web.ErrorsController">
  <property name="methodNameResolver">
   <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
    <property name="mappings">
     <props>
      <prop key="/notfound.htm">handleHttp404</prop>
     </props>
    </property>
   </bean>
  </property>
 </bean>

 <!-- Application specific multi-action controller    由于好多页面调用同一个控制器,因此要区分不同的页面,以调用继承multi-action 的不同的方法
         而这个任务就交给MethodNameResulver来解决-->
 <bean id="countriesController" class="org.springframework.samples.countries.web.CountriesController">
  <property name="methodNameResolver">
   <bean class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
    <property name="mappings">
     <props>
      <prop key="/home.htm">handleHome</prop>
      <prop key="/config.htm">handleConfig</prop>
      <prop key="/copy.htm">handleCopy</prop>
      <prop key="/main/home.htm">handleMain</prop>
      <prop key="/main/detail.htm">handleDetail</prop>
      <prop key="/main/countries.xls">handleExcel</prop>
      <prop key="/main/countries.pdf">handlePdf</prop>
     </props>
    </property>
   </bean>
  </property>
  <property name="countryService" ref="countryService"/>
 </bean>

</beans>

posted @ 2007-08-30 18:34 华梦行 阅读(479) | 评论 (0)编辑 收藏
数组只有length属性

Locale.getAvailableLocales().length
posted @ 2007-08-30 18:18 华梦行 阅读(198) | 评论 (0)编辑 收藏
Spring提供了MethodNameResolver的三种方式:

1 : ParameterMethodNameResolver,这个可以根据请求的参数来确定一个需要调用的方法。
例如,http://www.sf.net/index.view?testParam=testIt,这个请求会调用名称为testIt的处理方法。

2 : InternalPathMethodNameResolver,这个可以根据请求的路径名称来调用相应的方法。
例如,http://www.sf.net/testing.view,这个请求会调用testing方法。

3 : PropertiesMethodNameResolver,这个可以根据一个URLs 映射列表来调用相应的方法。
例如,如果定义了/index/welcome.html=doIt,那么当请求为/index/welcome.html时,会调用doIt方法。在定义URLs时可以使用通配符。/**/welcom?.html
posted @ 2007-08-30 15:21 华梦行 阅读(1936) | 评论 (0)编辑 收藏

13.3. 控制器

控制器的概念是MVC设计模式的一部分(确切地说,是MVC中的C)。应用程序的行为通常被定义为服务接口,而控制器使得用户可以访问应用所提供的服务。控制器解析用户输入,并将其转换成合理的模型数据,从而可以进一步由视图展示给用户。Spring以一种抽象的方式实现了控制器概念,这样使得不同类型的控制器可以被创建。Spring本身包含表单控制器、命令控制器、向导型控制器等多种多样的控制器。

Spring控制器架构的基础是org.springframework.mvc.Controller接口,其代码如下:

public interface Controller {

    /**
     * Process the request and return a ModelAndView object which the DispatcherServlet
     * will render.
     */
    ModelAndView handleRequest(
        HttpServletRequest request,
        HttpServletResponse response) throws Exception;

}

你可以发现Controller接口仅仅声明了一个方法,它负责处理请求并返回合适的模型和视图。Spring MVC实现的基础就是这三个概念:Mdel、View(ModelAndView)以及 Controller。虽然Controller接口是完全抽象的,但Spring也提供了许多你可能会用到的控制器。Controller接口仅仅定义了每个控制器都必须提供的基本功能:处理请求并返回一个模型和一个视图。

13.3.1. AbstractControllerWebContentGenerator

为了提供一套基础设施,所有的Spring控制器都继承了 AbstractControllerAbstractController 提供了诸如缓存支持和mimetype设置这样的功能。

表 13.3. AbstractController提供的功能

功能 描述
supportedMethods 指定这个控制器应该接受什么样的请求方法。通常它被设置成同时支持GET和POST,但是你可以选择你想支持的方法。如果控制器不支持请求发送的方法,客户端会得到通知(通常是抛出一个ServletException)。
requiresSession 指定这个控制器是否需要HTTP session才能正常工作。如果控制器在没有session的情况下接收到请求,客户端会因为抛出ServletException而得到通知。
synchronizeSession 指定controller是否同步用户的HTTP session。
cacheSeconds 指定controller通知客户端对数据内容缓存的秒数,一般为大于零的整数。默认值为-1,即不缓存。
useExpiresHeader 指定Controller在响应请求时是否兼容HTTP 1.0 Expires header。缺省值为true
useCacheHeader 指定Controller在相应请求时是否兼容HTTP 1.1 Cache-Control header。默认值为true

当从AbstractController继承时,需要实现handleRequestInternal(HttpServletRequest, HttpServletResponse)抽象方法,该方法将用来实现自己的逻辑,并返回一个ModelAndView对象。下面这个简单的例子演示了如何从AbstractController继承以及如何在applicationContext.xml中进行配置

package samples;

public class SampleController extends AbstractController {

    public ModelAndView handleRequestInternal(
        HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        ModelAndView mav = new ModelAndView("hello");
        mav.addObject("message", "Hello World!");
        return mav;        
    }
}
<bean id="sampleController" class="samples.SampleController">
    <property name="cacheSeconds" value="120"/>
</bean>

该controller返回的ModelAndView使用了硬编码的视图名(尽管这样做不好),并通知客户端将响应数据缓存2分钟。除了通过以上方式创建和配置controller之外,还需要配置handler mapping(请参考第 13.4 节 “处理器映射(handler mapping)”),这样该controller就可以工作了。

13.3.2. 其它的简单控制器

尽管可以继承AbstractController来实现自己的控制器,不过Spring提供的众多控制器减轻了我们开发简单MVC应用时的负担。ParameterizableViewController基本上和上面例子中的一样,不同的是,你可以在applicationContext.xml配置中指定返回视图名从而避免了在Java代码中的硬编码。

UrlFilenameViewController会检查URL,获取文件请求的文件名,并把它作为视图名加以使用。。例如,http://www.springframework.org/index.html对应的视图文件名是index

13.3.3. MultiActionController

MultiActionController将多个行为(action)合并在一个控制器里,这样可以把相关功能组合在一起。MultiActionController位于org.springframework.web.mvc.multiaction包中,它通过将请求映射到正确的方法名来调用方法。当在一个控制器存在大量公共的行为,但是有多个调用入口时,使用MultiActionController就特别方便。

表 13.4. MultiActionController提供的功能

功能 描述
delegate MultiActionController有两种使用方式。第一种是你继承MultiActionController,并在子类中指定由MethodNameResolver解析的方法(这种情况下不需要这个delegate参数)。第二种是你定义一个代理对象,由它提供MethodNameResolver解析出来的方法(这种情况下,你必须使用这个配置参数定义代理对象)。
methodNameResolver MultiActionController需要一种策略,使其可以通过解析请求信息来获得要调用的方法。这个解析策略由MethodNameResolver这个接口定义的。这个参数允许你实现MethodNameResolver接口,然后在控制器中使用你的策略。

MultiActionController所支持的方法需要符合下列格式:

								
										// anyMeaningfulName can be replaced by any methodname
								
public [ModelAndView | Map | void] anyMeaningfulName(HttpServletRequest, HttpServletResponse [, Exception | AnyObject]);

注意:在此不允许方法重载,因为MultiActionController无法分辨出重载(overloading)了的方法。此外,你可以定义exception handler来处理方法中抛出的异常。

Exception 参数是可选的,它可以是任何异常,只要它是java.lang.Exceptionjava.lang.RuntimeException的子类。AnyObject参数也是可选的,它可以是任何对象。HTTP Request中的参数会存在这个对象中,以便使用。

下面几个例子示范了MultiActionController正确的方法定义。

标准格式(跟Controller接口定义的一样)。

public ModelAndView doRequest(HttpServletRequest, HttpServletResponse)

下面这个方法支持Login参数, 这个参数中包含从请求中抽取出来的信息。

public ModelAndView doLogin(HttpServletRequest, HttpServletResponse, Login)

下面这个方法可以处理Exception

public ModelAndView processException(HttpServletRequest, HttpServletResponse, IllegalArgumentException)

下面这个方法不返回任何数值。 (请参考后面的章节 第 13.11 节 “惯例优先原则(convention over configuration)”)

public void goHome(HttpServletRequest, HttpServletResponse)

This signature has a Map return type (see the section entitled 第 13.11 节 “惯例优先原则(convention over configuration)” below).

下面这个方法返回一个Map。 (请参考后面的章节第 13.11 节 “惯例优先原则(convention over configuration)”)

public Map doRequest(HttpServletRequest, HttpServletResponse)

MethodNameResolver负责从请求中解析出需要调用的方法名称。下面是Spring中内置的三个MethodNameResolver 实现。

  • ParameterMethodNameResolver - 解析请求参数,并将它作为方法名。(对应http://www.sf.net/index.view?testParam=testIt的请求,会调用 testIt(HttpServletRequest,HttpServletResponse)方法)。使用paramName配置参数,可以设定要检查的参数。

  • InternalPathMethodNameResolver -从路径中获取文件名作为方法名 (http://www.sf.net/testing.view的请求会调用testing(HttpServletRequest,HttpServletResponse)方法。

  • PropertiesMethodNameResolver - 使用用户自定义的属性对象,将请求的URL映射到方法名。当属性中包含/index/welcome.html=doIt时,发到/index/welcome.html 的请求会调用doIt(HttpServletRequest, HttpServletResponse)这个方法。 这个方法名解析器可以和PathMatcher一起工作,比如上边那个URL写成/**/welcom?.html也是可以的。

我们来看一组例子。首先是一个使用ParameterMethodNameResolver和代理(delegate)属性的例子,它接受包含参数名"method"的请求,调用方法retrieveIndex

<bean id="paramResolver" class="org....mvc.multiaction.ParameterMethodNameResolver">
  <property name="paramName" value="method"/>
</bean>

<bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
  <property name="methodNameResolver" ref="paramResolver"/>
  <property name="delegate" ref="sampleDelegate"/>
</bean>

<bean id="sampleDelegate" class="samples.SampleDelegate"/>

## together with

public class SampleDelegate {

    public ModelAndView retrieveIndex(HttpServletRequest req, HttpServletResponse resp) {

        return new ModelAndView("index", "date", new Long(System.currentTimeMillis()));
    }
}

当使用上面的代理对象时,我们也可以使用PropertiesMethodNameRseolver来匹配一组URL,将它们映射到我们定义的方法上:

<bean id="propsResolver" class="org....mvc.multiaction.PropertiesMethodNameResolver">
  <property name="mappings">
    <value>
        /index/welcome.html=retrieveIndex
        /**/notwelcome.html=retrieveIndex
        /*/user?.html=retrieveIndex
    </value>
  </property>
</bean>

<bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
    <property name="methodNameResolver" ref="propsResolver"/>
    <property name="delegate" ref="sampleDelegate"/>
</bean>

13.3.4. 命令控制器

Spring的CommandController是Spring MVC的重要部分。命令控制器提供了一种和数据对象交互的方式,并动态地将来自HttpServletRequest的参数绑定到你指定的数据对象上。它的功能和Struts中的ActionForm有点像,不过在Spring中,你不需要实现任何接口来实现数据绑定。首先,让我们看一下有哪些可以使用的命令控制器:

  • AbstractCommandController --你可以使用该抽象命令控制器来创建自己的命令控制器,它能够将请求参数绑定到你指定的命令对象。这个类并不提供任何表单功能,但是它提供验证功能,并且让你在子类中去实现如何处理由请求参数产生的命令对象。

  • AbstractFormController--一个支持表单提交的抽象控制器类。使用这个控制器,你可以定义表单,并使用从控制器获取的数据对象构建表单。当用户输入表单内容,AbstractFormController将用户输入的内容绑定到命令对象,验证表单内容,并将该对象交给控制器,完成相应的操作。它支持的功能有防止重复提交、表单验证以及一般的表单处理流程。子类需要实现自己的方法来指定采用哪个视图来显示输入表单,哪个视图显示表单正确提交后的结果。如果你需要表单,但不想在应用上下文中指定显示给用户的视图,就使用这个控制器。

  • SimpleFormController --这是一个form cotnroller,当需要根据命令对象来创建相应的form的时候,该类可以提供更多的支持。你可以为其指定一个命令对象,显示表单的视图名,当表单提交成功后显示给用户的视图名等等。

  • AbstractWizardFormController --这是一个抽象类,继承这个类需要实现validatePage()processFinish()processCancel() 方法。

    你有可能也需要写一个构造器,它至少需要调用setPages()setCommandName()方法。setPages()的参数是一个String数组,这个数组包含了组成向导的视图名。setCommandName()的参数是一个String,该参数将用来在视图中调用你的命令对象。

    AbstractFormController的实现一样, 你需要使用命令对象(其实就是一个JavaBean, 这个bean中包含了表单的信息)。你有两个选择:在构造函数中调用setCommandClass()方法(参数是命令对象的类名),或者实现formBackingObject()方法。

    AbstractWizardFormController 有几个你可以复写(override)的方法。最有用的一个是referenceData(..)。这个方法允许你把模型数据以Map的格式传递给视图;getTargetPage() 允许你动态地更改向导的页面顺序,或者直接跳过某些页面;onBindAndValidate() 允许你复写内置的绑定和验证流程。

    最后,我们有必要提一下setAllowDirtyBack()setAllowDirtyForward()两个方法。 你可以在getTargetPage()中调用这两个方法,这两个方法将决定在当前页面验证失败时,是否允许向导前移或后退。

    AbstractWizardFormController的更详细内容请参考JavaDoc。在Spring附带的例子jPetStore中,有一个关于向导实现的例子: org.springframework.samples.jpetstore.web.spring.OrderFormController

posted @ 2007-08-30 12:32 华梦行 阅读(2325) | 评论 (0)编辑 收藏
jar -cvf test.war *

即可在当前目录下得到test.war
随后可以把test.war上传到服务器


在server.xml添加

<Context path="" docBase="PEP" debug="0" reloadable="false">
    <ResourceLink global="jdbc/PathPlat" name="jdbc/PathPlat" type="javax.sql.DataSource"/>
   </Context>

将这段代码中的
<Context path="/manager" docBase="manager" debug="0" privileged="true"/>
拷贝一下并修改:path="" 为war路径,docBase=""为你的war的文件名。
 使用不带任何的 jar 命令我们可以看到 jar 命令的用法如下:

  jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...

  其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一个,它们分别表示:

   -c 创建新的 JAR 文件包

   -t 列出 JAR 文件包的内容列表

   -x 展开 JAR 文件包的指定文件或者所有文件

   -u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)

     [vfm0M] 中的选项可以任选,也可以不选,它们是 jar 命令的选项参数

   -v 生成详细报告并打印到标准输出

   -f 指定 JAR 文件名,通常这个参数是必须的

   -m 指定需要包含的 MANIFEST 清单文件

   -0 只存储,不压缩,这样产生的 JAR 文件包会比不用该参数产生的体积大,但速度更快

   -M 不产生所有项的清单(MANIFEST〕文件,此参数会忽略 -m 参数

     [jar-文件] 即需要生成、查看、更新或者解开的 JAR 文件包,它是 -f 参数的附属参数

     [manifest-文件] 即 MANIFEST 清单文件,它是 -m 参数的附属参数

     [-C 目录] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令转该目录下再执行不带 -C 参数的 jar 命令,它只能在创建和更新 JAR 文件包的时候可用。  

posted @ 2007-08-30 11:12 华梦行 阅读(178) | 评论 (0)编辑 收藏
jtds jdbc驱动
posted @ 2007-08-30 10:19 华梦行 阅读(184) | 评论 (0)编辑 收藏
视图解析器

就象和Spring集成的其他表现层技术一样,对于JSP页面你需要一个视图解析器来解析。最常用的JSP视图解析器是InternalResourceViewResolverResourceBundleViewResolver。它们被定义在WebApplicationContext里:

# The ResourceBundleViewResolver:
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
    <property name="basename"><value>views</value></property>
</bean>

# And a sample properties file is uses (views.properties in WEB-INF/classes):
welcome.class=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp

productList.class=org.springframework.web.servlet.view.JstlView
productList.url=/WEB-INF/jsp/productlist.jsp

你可以看到ResourceBundleViewResolver需要一个属性文件来把视图名称映射到 1)类和 2) URL。 通过ResolverBundleViewResolver,你可以用一个解析器来解析两种类型的视图。

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
    <property name="prefix"><value>/WEB-INF/jsp/</value></property>
    <property name="suffix"><value>.jsp</value></property>
</bean>

InternalResourceBundleViewResolver可以配置成使用JSP页面。作为好的实现方式,强烈推荐你将JSP文件放在WEB-INF下的一个目录中,这样客户端就不会直接访问到它们。

posted @ 2007-08-30 10:01 华梦行 阅读(644) | 评论 (0)编辑 收藏
     摘要: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsd:schema xmlns="http://www.springframework.org/schema/beans"  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  targetNamespace="http:...  阅读全文
posted @ 2007-08-30 09:24 华梦行 阅读(2769) | 评论 (0)编辑 收藏
2007-07-18 Spring的事务通知   

关键字: Spring       

Spring 2.0版本支持扩展XML配置,着实兴奋了一下,在我看来,Spring作为目前最流行的框架,不能扩展用户自定义的配置,实在是Spring的一个很不爽的地方,<bean />的方式用起来比较通用,起码到目前为止符合大部分人的使用习惯,并且能完成Spring所有的配置操作,但是对于第三方的提供商或则会经常扩展Spring功能的开发者来说,使用<bean />这样的配置方式或许不是他们最想要的,他们需要使组件的配置更加直观、易阅读、易扩展……试想使用下面的配置方式

代码
  1. <mytag:datasource id= "datasource"     
  2.        databaseType= "oracle"     
  3.        ip= "192.168.1.110"     
  4.        port= "1521"     
  5.        databaseName= "myDB"   
  6.        userName= "admin"   
  7.        password= "password"   
  8.        />   
  9.   
  10. <mytag:ehCache id= "ehcache"     
  11.        cache= "true"     
  12.        maxElements= "100000"     
  13.        timeToIdleSeconds= "120"     
  14.        timeToLiveSeconds= "120"   
  15.        overflowToDisk= "true"   
  16.        />   

上面的代码中配置了两个组件,datasource和cache组件,相比普通的bean&propertiy方式,很显然,这种配置方式更直观,更易读,更重要的是,如果作为组件发布,使用者也可以很方便快捷的开始使用,而不需要关心组件的任何实现细节。

扩展XML配置大致需要一下几个步骤
1、创建一个需要扩展的组件
2、定义一个xsd文件描述组件内容
3、创建一个文件,实现BeanDefinitionParser接口,用来解析xsd文件中的定义和组件定义
4、创建一个Handler文件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器
5、编写spring.handlers和spring.schemas文件

提供一个简单的例子,来说明如何去扩展一个Spring配置,需求如下:使用自定义标签定义一个简单的bean,这个bean有一个或多个属性,标签定义完成后,可以在其他项目中用自定义标签来定义该bean。

首先,创建一个需要扩展的组件,在这里只是一个简单的bean,而且这个bean只有一个属性age.
One.java

代码
  1. package com.mysite.tag;   
  2.   
  3. public class One {   
  4.     private String age;   
  5.        
  6.     public One(){   
  7.            
  8.     }   
  9.   
  10.     public String getAge() {   
  11.         return age;   
  12.     }   
  13.   
  14.     public void setAge(String age) {   
  15.         this.age = age;   
  16.     }   
  17. }   

然后,建立一个xsd文件,来描述这个bean
mytag.xsd

代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <xsd:schema xmlns="http://www.mysite.org/schema/mytag"  
  3.         xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  4.         xmlns:beans="http://www.springframework.org/schema/beans"  
  5.         targetNamespace="http://www.mysite.org/schema/mytag"  
  6.         elementFormDefault="qualified"  
  7.         attributeFormDefault="unqualified">  
  8.        
  9.     <xsd:import namespace="http://www.springframework.org/schema/beans"/>  
  10.        
  11.     <xsd:element name="one">  
  12.         <xsd:complexType>  
  13.             <xsd:complexContent>  
  14.                 <xsd:extension base="beans:identifiedType">  
  15.                     <xsd:attribute name="age" type="xsd:string" default="99999"/>  
  16.                 </xsd:extension>  
  17.             </xsd:complexContent>  
  18.         </xsd:complexType>  
  19.     </xsd:element>  
  20. </xsd:schema>  

在上面的xsd文件描述了一个新的targetNamespace,并在这个空间中定义了一个name为one的element,one有一个age属性,类型为string,默认值为99999.xsd文件是xml DTD的替代者,使用XML Schema语言进行编写,这里对xsd schema不做太多解释,有兴趣可以参考相关的资料。

创建一个Java文件,该文件实现了BeanDefinitionParser接口,用来解析xsd文件中的定义并注册到组件中。
MyBeanDefinitionParser.java

代码
  1. package com.mysite.tag;   
  2.   
  3. import org.springframework.beans.factory.config.BeanDefinition;   
  4. import org.springframework.beans.factory.config.BeanDefinitionHolder;   
  5. import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;   
  6. import org.springframework.beans.factory.support.RootBeanDefinition;   
  7. import org.springframework.beans.factory.xml.BeanDefinitionParser;   
  8. import org.springframework.beans.factory.xml.ParserContext;   
  9. import org.w3c.dom.Element;   
  10.   
  11. public class MyBeanDefinitionParser implements BeanDefinitionParser{   
  12.     public BeanDefinition parse(Element arg0, ParserContext arg1) {   
  13.         RootBeanDefinition def = new RootBeanDefinition();   
  14.                 //设置Bean Class   
  15.         def.setBeanClass(One.class);   
  16.            
  17.                 //注册ID属性   
  18.         String id = arg0.getAttribute("id");   
  19.         BeanDefinitionHolder idHolder= new BeanDefinitionHolder(def,id);   
  20.         BeanDefinitionReaderUtils.registerBeanDefinition(idHolder, arg1.getRegistry());   
  21.            
  22.                 //注册age属性   
  23.         String age = arg0.getAttribute("age");   
  24.         BeanDefinitionHolder ageHolder= new BeanDefinitionHolder(def,age);   
  25.         BeanDefinitionReaderUtils.registerBeanDefinition(ageHolder, arg1.getRegistry());   
  26.         def.getPropertyValues().addPropertyValue("age", age);   
  27.            
  28.         return def;   
  29.     }   
  30. }   
  31.   

上面的代码仅仅实现了一个方法public BeanDefinition parse(Element arg0, ParserContext arg1),设置相关的Bean Class,解析了对应的xsd文件,并将解析的内容注册到上下文中,同时返回一个BeanDefinition对象(BeanDefinition是Spring的bean定义,提供了bean部分的操作方法,如isSingleton()、isLazyInit()等)。

注意,id属性是一个默认的属性,可以不在xsd文件中描述,但是需要注册它,否则将无法通过getBean方法获取标签定义的bean,也无法被其他bean引用。
另外,下面代码是给bean的属性赋值,这个是不可缺少的,否则在使用标签定义时将无法获取bean属性的值。

代码
  1. def.getPropertyValues().addPropertyValue("age", age);   

然后为组件编写一个Handler文件,扩展自NamespaceHandlerSupport,它的作用是将组件注册到Spring容器
MyNameSpaceHandler.java

代码
  1. package com.mysite.tag;   
  2.   
  3. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;   
  4.   
  5. public class MyNameSpaceHandler extends NamespaceHandlerSupport {   
  6.   
  7.     public void init() {   
  8.          registerBeanDefinitionParser("one",new MyBeanDefinitionParser());   
  9.     }   
  10. }   

实际执行的过程只有一句代码,注册了一个名字为one的扩展配置,包含了MyBeanDefinitionParser所parser相关xsd的内容。

到了这里,一个Spring扩展标签已经完成,但是我们目前还没办法使用它,Spring没那么聪明,它无法知道我们在什么地方定义了哪些扩展标签,这些标签将被谁解析,这个过程要我们通过一些文件来告知Spring知道,它们就是spring.handlers和spring.schemas,它们放在META-INF目录中,Spring.jar的META-INF目录中也有同名的文件,它们的文件内容基本上是相似的,而Spring在执行过程中,如果发现其他jar文件的META-INF文件夹中包含有这两个文件,Spring将会合并它们。
spring.schemas

代码
  1. http\://www.mysite.org/schema/mytag.xsd=com/mysite/tag/mytag.xsd   

spring.handlers

代码
  1. http\://www.mysite.org/schema/mytag=com.mysite.tag.MyNameSpaceHandler   

spring.schemas将告诉Spring配置文件知道,如果在配置中引用http://www.mysite.org/schema/mytag.xsd,它应该去什么地方找相应的xsd文件。
而spring.handlers文件将告诉Spring,应该使用哪个Handler注册扩展标签。

现在为止,一个完整的xml扩展标签全部完成,做一个小应用测试一下。
将整个项目打包成jar文件(别忘记META-INF内的两个文件),然后新建一个项目,引用刚才打包的jar文件,并引用Spring相关文件。
需要注意,自定义xml扩展配置只有xsd方式的引用才可以使用.
application.xml

代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xmlns:tag="http://www.mysite.org/schema/mytag"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.     http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
  7.     http://www.mysite.org/schema/mytag   
  8.     http://www.mysite.org/schema/mytag.xsd">  
  9.   
  10.     <tag:one id="oneBean" age="99"/>  
  11. </beans>  

在xml文件引用上可以看到,配置了一个名字为tag的名称空间,目标为http://www.mysite.org/schema/mytag命名空间,这个目标名称空间必须是存在于项目的引用中的(mytag.xsd中所定义的).
代码
  1. <tag:one id="oneBean" age="99"/>   

上面定义了一个id为oneBean的组件,使用了“one”扩展标签,也就是我们在handler中所注册的,组件age属性的值为99。

Main.java

代码
  1. package com.test;   
  2.   
  3. import org.springframework.context.ApplicationContext;   
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  5.   
  6. import com.mysite.tag.One;   
  7.   
  8. public class Main {   
  9.   
  10.     public static void main(String[] args) {   
  11.         ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");   
  12.         One tag = (One) ctx.getBean("oneBean");   
  13.         System.out.println("oneBean age is "+tag.getAge());   
  14.     }   
  15. }   

运行测试程序,结果如下
代码
  1. oneBean age is 99  

Spring的xml扩展是一个非常有用的特性,在Spring2.0的版本中也提供了一些新的标签使用,如<aop>,<tx>等,但就目前来讲受大家关注程度并不高,我想大部分使用Spring的开发人员都在使用Spring开发企业应用,而Spring所提供的<bean />定义的方式对于开发人员来说已经能够满足需要,但是如果看的更远一些,在Spring以后的发展过程中,xml扩展应该会成为spring的核心特性之一,或许到时大家会习惯这样的方式来编写Spring配置文件吧

代码
  1. <XXCompany:XXXModule id="">   
  2. ...   
  3. ...   

最后更新:2007-07-18 16:03
15:42  |   永久链接  |   浏览 (481)  |   评论 (2)  |    收藏  |   进入论坛  |  
评论    共 2 条 发表评论
baallee     2007-07-18 15:53

代码
  1. <? xml   version = "1.0"   encoding = "UTF-8" ?>     
  2. < beans   xmlns = "http://www.springframework.org/schema/beans"        
  3. xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"        
  4. xmlns:p = "http://www.springframework.org/schema/p"        
  5. xsi:schemaLocation ="http://www.springframework.org/schema/beans           
  6. http://www.springframework.org/schema/beans/spring-beans.xsd" >      
  7. < bean   class = "com.interface21.spring2.ioc.Person"         
  8. p:name = "Tony"        
  9. p:age = "53"         
  10. p:house-ref = "number10"   />       
  11. < bean   class = "com.interface21.spring2.ioc.House"         
  12. id = "number10"        
  13. p:name = "10 Downing Street" />      
  14. </ beans >   

对于简单的应用可以用p标签就好了。
自定意扩展应该用在更多的高级应用上

posted @ 2007-08-29 15:08 华梦行 阅读(259) | 评论 (0)编辑 收藏
spring中dispatcherservlet的运行机制

dispatcherservlet是spring的web框架(以下简称springweb)中的核心servlet."spring的web框架——象其它web框架一样——是一个请求驱动的web框架,其设计围绕一个能将请求分发到控制器的servlet,它也提供其它功能帮助web应用开发。"----《spring framework 开发参考手册(中文版)》而在springweb框架中这个servlet就是org.springframework.web.servlet.dispatcherservlet。这个servlet的继承关系如下图所示:springweb首先将传统的httpservlet抽象类包装成了bean;frameworkservlet抽象出了web框架中的servlets的一些基本行为,比如对application context的访问;dispatcherservlet的主要工作就是将一个request分发到一个合适的处理器上,并将处理返回的modelandview绘制出来返回给客户端。

dispatcherservlet作为一个servlet那他一定有两个主要的方法:init()和doservice()。

一 init()初始化。dispatcherservlet继承体系中init()方法的实现位于httpservletbean中,httpservletbean首先调用initbeanwrapper(),初始化beanwrapper,然后调用抽象方法initservletbean(),这个方法的实现位于他的子类frameworkservlet中;framewordservlet中的initservletbean()方法将调用initwebapplicationcontext(),初始化webapplicationcontext,然后同样调用他的抽象方法initframeworkservlet(),而这个抽象方法的实现位于最终的dispatcherservlet中;dispatcherservlet中的initframeworkservet()将依次初始化multipar(用作文件上传)解析器、本地化信息解析器、主题解析器处理器映射等等内容。所以dispatcherservlet的初始化顺序为init();initbeanwrapper();

initservletbeaninitwebapplicationcontext()

initframework();initmultipartresolver();initlocaleresolver();initthemeresolver();inithandlermappings();inithandleradapters();inithandlerexceptionresolvers();initviewresolvers();

二 doservice()处理请求。dispatcherservlet中无论是通过post方式还是get方式提交的request,最终都会交由doservice()处理。doservice()中的处理逻辑大致分以下六个步骤:1.if(request是multipart,即文件上传) 则将request解析并包装成multiparthttpservletrequest2.mappedhandler = gethandler(request)根据request得到相应的处理器3.调用注册的所有拦截器的prehandle方法4.调用处理器    handleradapter ha = new gethandleradapter(mappedhandler.gethandler());    modelandview mv = ha.handle(req, res, mappedhandler.gethandler())//这里使用了adapter模式5.调用注册的所有拦截器的posthandle方法6.绘制mv

也许spring不像struts、hibernate那样是使用最为广泛的,但他是全面的、轻量级的、足够灵活的、容易替换、容易扩展的。springweb是springframework中的一个部分,而dispatcherservlet又是springweb中的一小部分,要弄懂spring以及他背后的设计思想,对我等菜鸟而言,还是有很长一段路要走的。但愿在新的一条路出现之前,我们已经走遍了这条路。路漫漫其修远兮,吾将上下而求索。继续研究ing...to be continue...

posted @ 2007-08-29 12:25 华梦行 阅读(693) | 评论 (0)编辑 收藏
select * from v$version

Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
posted @ 2007-08-29 11:33 华梦行 阅读(585) | 评论 (0)编辑 收藏

<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

<c:redirect url="home.htm"/>
<c:redirect url="b.jsp">
<c:param name="data" value="jsp_passdata中文傳值"></c:param>
</c:redirect>

他们两个作用相似
<jsp:forward page="/utils/errorReporter.jsp"/>

<jsp:forward page="/test4.jsp">
<jsp:param name="name" value="powerman"/>
<jsp:param name="address" value=" 北京西大街188号"/>
</jsp:forward>

<fmt:requestEncoding value="big5"/>
posted @ 2007-08-29 10:53 华梦行 阅读(216) | 评论 (0)编辑 收藏
关键字: Spring   mvc ioc     

请求的分发

请求首先到达DispatcherServlet,应用服务器会根据Web应用中web.xml文件定义的url映射将相应的请求分发到DispatcherServlet中

请求的处理

DispatcherServlet会查找相应的HandlerMapping接口的实现类,调用其中的方法:HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception,该方法会返回一个HandlerExecutionChain。返回的HandlerExecutionChain中包含了零个或者是多个Interceptor和一个处理请求的Handler。DispatcherServlet会调用Interceptor中的preHandle() 方法。然后处理Handler,这个Handler相当于Struts中Action,在SpringMVC中默认的实现是Controller接口,是具体处理请求的代码所驻留的地方。事实上HandlerExecutionChain中的getHandler()返回的是一个Object类型。DispatcherServlet不会直接调用getHandler()返回对象中的方法,DispatcherServlet会查找相应的HandlerAdapter,然后具体通过HandlerAdapter来调用getHandler()返回的handler对象中的方法。就是说我们可以实现自己的HandlerAdapter然后通过IoC注入到DispatcherServlet中,从而可以实现一套自定义的控制器。随后DispatcherServlet会调用Interceptor中的postHandle()方法。

视图的处理

DispatcherServlet会期望Hander返回一个ModelAndView,DispatcherServlet会根据所返回的ModelAndView对象所包含的信息进行视图的渲染。起具体出来流程如下:

首先DispatcherServlet会根据LocaleResolver来识别请求中的Locale,开发人员可以自己实现LocaleResolver接口,然后通过IoC注入到DispatcherServlet中,然后DispatcherServlet会判断ModelAndView中是否已经包含了接口View的具体实现,如果包含了,则直接调用View中的方法render(Map model, HttpServletRequest request, HttpServletResponse response)。如果不包含,则说明该ModelAndView只是包含了View的名称引用,DispatcherServlet会调用ViewResolver中的resolveViewName(String viewName, Locale locale)来解析其真正的视图。该方法会返回一个View的具体实现。

视图的渲染

Spring支持多种视图技术,其中比较常用的包括有Jstl视图,Veloctiy视图,FreeMarker视图等。对Jstl视图的渲染Spring是通过JstlView这个类具体实现的。事实上其最终的渲染是交给容器来做的,Spring只是通过RequestDispatcher实现了服务器内部请求的Forward。而对于模板视图,如Veloctiy和FreeMarker等,Spring会初始化其相应的模板引擎,由模板引擎生成最终的Html页面然后在合并到Response的输出流中。

异常的处理

如果在Hander中处理请求是抛出异常,DispatcherServlet会查找HandlerExceptionResolver接口的具体实现,该接口定义了一个方法:

ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex),实现类需要实现该方法以便对异常进行处理,最后该方法需要返回一个ModelAndView。

SpringMVC的一些总结
灵活的Interceptor,通过Interceptor我们可以在一个请求处理前和请求处理完成之后做相应的操作,通过Interceptor机制,我们可以做authentication, logging, and filtering等。
良好的表单支持,在SpringMVC的Controller继承体系结构中,其具体的子类对表单(Form)提供了良好的支持。能够很好的支持单个表单的显示、修改、提交操作。同时也提供了表单的分步提交。
可定制的数据绑定(Data Binding)。
多视图技术的支持,SpringMVC同时支持Jstl, Velocity 等多中视图技术,但是这同时也会引出一个问题,因为各种视图技术都有自己的一套方法来处理国际化,例如Jstl和Velocity处理国际化的方式就很不相同。因此在多个视图技术并存的应用中,国际化也是一个需要注意的问题。
其Handler(控制器)作为Bean定义在Spring容器中,因此能享受容器带来的服务。
Handler(控制器)具有良好的可测试性。

posted @ 2007-08-29 10:23 华梦行 阅读(2950) | 评论 (0)编辑 收藏
public abstract class HttpServletBean
extends HttpServlet
		

Simple extension of HttpServlet which treats its config parameters (init-param entries within the servlet tag in web.xml) as bean properties.

HttpServlet的简单扩展用来处理 (init-param)in the web.xml
A handy superclass for any type of servlet. Type conversion of config parameters is automatic, with the corresponding setter method getting invoked with the converted value. It is also possible for subclasses to specify required properties. Parameters without matching bean property setter will simply be ignored.

This servlet leaves request handling to subclasses, inheriting the default behavior of HttpServlet (doGet, doPost, etc).

This generic servlet base class has no dependency on the Spring ApplicationContext concept. Simple servlets usually don't load their own context but rather access service beans from the Spring root application context, accessible via the filter's ServletContext (see WebApplicationContextUtils).

The FrameworkServlet class is a more specific servlet base class which loads its own application context. FrameworkServlet serves as direct base class of Spring's full-fledged DispatcherServlet.

public abstract class FrameworkServlet
extends HttpServletBean
implements ApplicationListener
		

Base servlet for Spring's web framework. Provides integration with a Spring application context, in a JavaBean-based overall solution.

spring web Framework的基础 servlet  ,提供在以javabean为基础的整体解决方案已完成与spring应用上下文的集成
This class offers the following functionality:
1.管理一个servlet一个网络应用上下文实例,这个servlet的配置由servlet命名空间里的bean来决定
2.根据请求处理发布事件,是否请求成功的被处理了

  • Manages a WebApplicationContext instance per servlet. The servlet's configuration is determined by beans in the servlet's namespace.
  • Publishes events on request processing, whether or not a request is successfully handled.

Subclasses must implement doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) to handle requests. Because this extends HttpServletBean rather than HttpServlet directly, bean properties are automatically mapped onto it. Subclasses can override initFrameworkServlet() for custom initialization.

因为它继承自httpservletBean 所以bean的属性已经被自动的装配了,子类可以通过覆盖initFrameworkServlet来定制初始化bean

Detects a "contextClass" parameter at the servlet init-param level, falling back to the default context class, XmlWebApplicationContext, if not found. Note that, with the default FrameworkServlet, a custom context class needs to implement the ConfigurableWebApplicationContext SPI.

Passes a "contextConfigLocation" servlet init-param to the context instance, parsing it into potentially multiple file paths which can be separated by any number of commas and spaces, like "test-servlet.xml, myServlet.xml". If not explicitly specified, the context implementation is supposed to build a default location from the namespace of the servlet.

Note: In case of multiple config locations, later bean definitions will override ones defined in earlier loaded files, at least when using Spring's default ApplicationContext implementation. This can be leveraged to deliberately override certain bean definitions via an extra XML file.

The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location with XmlWebApplicationContext). The namespace can also be set explicitly via the "namespace" servlet init-param.

posted @ 2007-08-29 10:13 华梦行 阅读(673) | 评论 (0)编辑 收藏
HeidiSQL
posted @ 2007-08-28 15:54 华梦行 阅读(121) | 评论 (0)编辑 收藏
				
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="cleanup"/>

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
posted @ 2007-08-28 14:28 华梦行 阅读(168) | 评论 (0)编辑 收藏
Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:
BeanFactory的实现应该尽可能支持标准的bean生命周期,以下是所以的方法的顺序的依次列表
1. BeanNameAware's   setBeanName
2. BeanClassLoaderAware's  setBeanClassLoader
3. BeanFactoryAware's   setBeanFactory
4. ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
5. ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
6. MessageSourceAware's setMessageSource (only applicable when running in an application context)
7. ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
8. ServletContextAware's setServletContext (only applicable when running in a web application context)
9. postProcessBeforeInitialization methods of BeanPostProcessors
10. InitializingBean's afterPropertiesSet
11. a custom init-method definition
12. postProcessAfterInitialization methods of BeanPostProcessors
 当关闭一个bean的时候
On shutdown of a bean factory, the following lifecycle methods apply:
1. DisposableBean's destroy
2. a custom destroy-method definition

Method Summary
 booleancontainsBean(String name)
          Does this bean factory contain a bean with the given name?
 String[]getAliases(String name)
          Return the aliases for the given bean name, if any.
 ObjectgetBean(String name)
          Return an instance, which may be shared or independent, of the specified bean.
 ObjectgetBean(String name, Class requiredType)
          Return an instance, which may be shared or independent, of the specified bean.
 ClassgetType(String name)
          Determine the type of the bean with the given name.
 booleanisPrototype(String name)
          Is this bean a prototype?
 booleanisSingleton(String name)
          Is this bean a shared singleton?
 booleanisTypeMatch(String name, Class targetType)
          Check whether the bean with the given name matches the specified type.
 
posted @ 2007-08-28 14:09 华梦行 阅读(562) | 评论 (0)编辑 收藏
public interface Lifecycle
		

Interface defining methods for start/stop lifecycle control. The typical use case for this is to control asynchronous processing.

Can be implemented by both components (typically a Spring bean defined in a Spring BeanFactory) and containers (typically a Spring ApplicationContext). Containers will propagate start/stop signals to all components that apply.

Can be used for direct invocations or for management operations via JMX. In the latter case, the MBeanExporter will typically be defined with an InterfaceBasedMBeanInfoAssembler, restricting the visibility of activity-controlled components to the Lifecycle interface.

Since:
2.0
Author:
Juergen Hoeller
See Also:
ConfigurableApplicationContext , AbstractMessageListenerContainer, SchedulerFactoryBean

Method Summary
 boolean isRunning ()
          Check whether this component is currently running.
 void start ()
          Start this component.
 void stop ()
          Stop this component.
 
posted @ 2007-08-28 13:49 华梦行 阅读(150) | 评论 (0)编辑 收藏
Spring中Bean的生命周期
    在传统的Java应用中,Bean的生命周期非常简单。Java的关键词new用来实例化Bean(或许他是非序列化的)。这样就够用了。相反,Bean的生命周期在Spring容器中更加细致。理解Spring Bean的生命周期非常重要,因为你或许要利用Spring提供的机会来订制Bean的创建过程。


1. 容器寻找Bean的定义信息并且将其实例化。
2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。
3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用。
6.如果Bean指定了init-method方法,它将被调用。
7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。
    到这个时候,Bean已经可以被应用系统使用了,并且将被保留在Bean Factory中知道它不再需要。有两种方法可以把它从Bean Factory中删除掉。
1.如果Bean实现了DisposableBean接口,destory()方法被调用。
2.如果指定了订制的销毁方法,就调用这个方法。
    Bean在Spring应用上下文的生命周期与在Bean工厂中的生命周期只有一点不同,唯一不同的是,如果Bean实现了ApplicationContextAwre接口,setApplicationContext()方法被调用。

posted @ 2007-08-28 12:56 华梦行 阅读(1845) | 评论 (0)编辑 收藏
INSTR方法的格式为
INSTR(源字符串, 目标字符串, 起始位置, 匹配序号)

////匹配序号是从左边开始数起,而不管其实位置的正负。
///当起始位置为负数时,从右边数起来计算返回的结果
select  instr(' ',' ',1,1)返回的值为空

例如:INSTR('CORPORATE FLOOR','OR', 3, 2)中,源字符串为'CORPORATE FLOOR', 目标字符串为'OR',起始位置为3,取第2个匹配项的位置。

默认查找顺序为从左到右。当起始位置为负数的时候,从右边开始查找。

所以SELECT INSTR('CORPORATE FLOOR', 'OR', -1, 1) "Instring" FROM DUAL的显示结果是

Instring
——————
14
posted @ 2007-08-28 12:24 华梦行 阅读(332) | 评论 (0)编辑 收藏
 ApplicationContext ctx = new ClassPathXmlApplicationContext("knight.xml");
posted @ 2007-08-28 09:58 华梦行 阅读(1323) | 评论 (0)编辑 收藏

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%5p] %d{HH:mm:ss} %c{1} - %m%n

log4j.rootLogger=WARN, stdout

log4j.category.com.springinaction=DEBUG
log4j.category.org.springframework=WARN

posted @ 2007-08-27 17:29 华梦行 阅读(283) | 评论 (0)编辑 收藏

package com.springinaction.chapter01.knight;

import java.lang.reflect.Method;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;


public class MinstrelAdvice implements MethodBeforeAdvice {
  public void before(Method method, Object[] args, Object target)
      throws Throwable {

    Knight knight = (Knight) target;
   
    Logger song = Logger.getLogger(target.getClass());
   
    song.debug("Brave " + knight.getName() + " did " + method.getName());
  }
}

package com.springinaction.chapter01.knight;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
public class KnightApp {
  private static final org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger
      .getLogger(KnightApp.class);
 
  public static void main(String[] args) throws Exception {
    LOGGER.debug("Running KnightApp");
    ApplicationContext m;
    BeanFactory factory =
        new XmlBeanFactory(new FileSystemResource("knight.xml"));

///有XmlBeanFactory来负责具体的实现     knight.xml必须要保存在项目的总目录下面
Knight knight =
        (Knight) factory.getBean("knight");

    knight.embarkOnQuest();
    System.out.println("ok");
    LOGGER.debug("KnightApp Finished");
  }
}

posted @ 2007-08-27 16:11 华梦行 阅读(547) | 评论 (0)编辑 收藏

 Spring中ApplicationContext加载机制。
          加载器目前有两种选择:ContextLoaderListener和ContextLoaderServlet。
         这两者在功能上完全等同,只是一个是基于Servlet2.3版本中新引入的Listener接口实现,而另一个基于Servlet接口实现。开发中可根据目标Web容器的实际情况进行选择。

配置非常简单,在web.xml中增加:
<listener>
  <listener-class>
       org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>
或:
<servlet>
    <servlet-name>context</servlet-name>
    <servlet-class>
       org.springframework.web.context.ContextLoaderServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet> 
 
          通过以上配置,Web容器会自动加载/WEB-INF/applicationContext.xml初始化
ApplicationContext实例,如果需要指定配置文件位置,可通过context-param加以指定:
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>

        配置完成之后,即可通过
 WebApplicationContextUtils.getWebApplicationContext方法在Web应用中获取ApplicationContext引用。

如:ApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext();
    LoginAction action=(LoginAction)ctx.getBean("action");

posted @ 2007-08-27 16:03 华梦行 阅读(172) | 评论 (0)编辑 收藏

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

///////在spring里所有的bean都是具体的实现,所谓的装配bean就是装配一个具体的实现
<beans>
  <bean id="quest"
      class="com.springinaction.chapter01.knight.HolyGrailQuest"/>
/////转配一个实现类,用来实现一个接口

  <bean id="knightTarget"
      class="com.springinaction.chapter01.knight.KnightOfTheRoundTable">
    <constructor-arg>
      <value>Bedivere</value>
    </constructor-arg>
    <property name="quest">
////这里是装备一个这个类的属性
      <ref bean="quest"/>
    </property>
  </bean>
 
  <bean id="minstrel"
      class="com.springinaction.chapter01.knight.MinstrelAdvice"/>
     
  <bean id="knight"
      class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
      <list>
        <value>com.springinaction.chapter01.knight.Knight</value>
      </list>
    </property>
    <property name="interceptorNames">
      <list>
        <value>minstrel</value>
      </list>
    </property>
    <property name="target"><ref bean="knightTarget"/></property>
  </bean>
 
</beans>
在spring 里所有的类都要实现接口与具体实现的分离  iGoHome.java   iGoHomeImp.java  这两个类来具体完成

posted @ 2007-08-27 16:02 华梦行 阅读(199) | 评论 (0)编辑 收藏
List cat =sess.createCriteria(Cat.class).add(Restrictions.like("name","F%").addOrder(Order.asc("name")).addOrder(Order.desc("age")).setMaxResult(20).list();

posted @ 2007-08-24 18:10 华梦行 阅读(419) | 评论 (0)编辑 收藏
  <id        name="id"        type="java.lang.Integer"        column="ID">
            <generator class="native">        
                <param name="sequence">S_10924_1_BSE_BENEFICIARY</param>
            </generator>
    </id>
posted @ 2007-08-24 17:06 华梦行 阅读(164) | 评论 (0)编辑 收藏
JTS Java Transaction Service 是 J2EE 架构的关键元素。它与 JTA Java Transaction API 结合在一起,使我们能够构建对于各种系统和网络故障都非常健壮的分布式应用程序。事务是可靠应用程序的基本构建块 —— 如果没有事务的支持,编写可靠的分布式应用程序将是非常困难的。幸运的是,JTS 执行的大部分工作对于程序员都是透明的;J2EE 容器使事务划分和资源征用对程序员来说几乎是不可见的。这个由三个部分组成的系列文章的第一期讲述了一些基础知识,包括什么是事务,以及事务对于构建可靠的分布式应用程序来说至关重要的原因。

如果您阅读过任何有关 J2EE 的介绍性文章或者书籍,那么就会发现,只有一小部分资料是专门针对 Java Transaction Service(JTS)或 Java Transaction API(JTA)的。这并不是因为 JTS 是 J2EE 中不重要的部分或者可选部分 —— 恰恰相反。JTS 受到的关注之所以会比 EJB 技术少,是因为它为应用程序提供的服务非常透明 —— 很多开发人员甚至没有注意到在他们的应用程序中事务在哪里开始和结束。在某种意义上,JTS 的默默无闻恰恰是它的成功:因为它非常有效地隐藏了事务管理的很多细节,因此,我们没有听说过或者谈论过很多关于它的内容。但是,您可能想了解它在幕后都为您执行什么功能。

毫不夸张地说,没有事务就不能编写可靠的分布式应用程序。事务允许采用某种控制方式修改应用程序的持久性状态,以便使应用程序对于各种各样的系统故障(包括系统崩溃、网络故障、电源故障甚至自然灾害)更加健壮。事务是构建容错、高可靠性以及高可用性应用程序所需的基本构建块之一。

posted @ 2007-08-24 16:34 华梦行 阅读(881) | 评论 (0)编辑 收藏
  <Resource
            name="jdbc/PathPlat"
            auth="Container"
            type="javax.sql.DataSource"
            password="f"
            driverClassName="oracle.jdbc.driver.OracleDriver"
            maxIdle="50"
            maxWait="5000"
            username="t"
            url="jdbc:oracle:thin:@192.168.0.1:1521:www"
            removeAbandoned="true"
            removeAbandonedTimeout="60"
            maxActive="100"/>

Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/PathCrm" reloadable="true">
  <ResourceLink global="jdbc/PathPlat" name="jdbc/PathPlat" type="javax.sql.DataSource"/>
</Context>
 
<property  name="connection.datasource">java:comp/env/jdbc/PathPlat</property> 

private String dbName ="java:comp/env/jdbc/SavingsAccountDB";

java:comp/env是组件的JNDI上下文的名字(实际上这个上下文也作为一种资源来处理了,资源查找的过程可以是这样:jndictxt = ctxt.lookup(“java:comp/env”)然后用这个jndictxt来查找资源,ref = jndictxt.lookup("jdbc/SavingsAccountDB")。)jdbc/SavingsAccountDB是资源引用的JNDI名(The jdbc/SavingsAccountDB string is the JNDI name for the resource reference,这句话可能意味着资源引用实际上也跟资源一样处理成一种JNDI绑定对象了,但是实际上应该不是这样,因为在部署描述符中它是引用名元素。因为译者也不是高手,所以这里的具体实现细节有待读者自己研究了:)所以JDBC的DataSource对象的JNDI名就存储在java:comp/env/jdbc的上下文子对象中。(组件运行环境的上下文层次需要进一步了解)

5. 在Type列中选择javax.sql.DataSource。前面说过它是数据库连接工厂

posted @ 2007-08-24 15:35 华梦行 阅读(100) | 评论 (0)编辑 收藏
set 元素里不能有重复
posted @ 2007-08-24 14:22 华梦行 阅读(135) | 评论 (0)编辑 收藏
   Connection conn = HibernateUtil.getSession().connection();
posted @ 2007-08-24 11:43 华梦行 阅读(61) | 评论 (0)编辑 收藏

select userenv('language') from dual

Oracle/PLSQL: UserEnv Function


In Oracle/PLSQL, the userenv function can be used to retrieve information about the current Oracle session. Although this function still exists in Oracle for backwards compatibility, it is recommended that you use the sys_context function instead.

The syntax for the userenv function is:

userenv( parameter )

parameter is the value to return from the current Oracle session. The possible values are:

Parameter Explanation
CLIENT_INFO Returns user session information stored using the DBMS_APPLICATION_INFO package
ENTRYID Available auditing entry identifier
INSTANCE The identifier number of the current instance
ISDBA Returns TRUE if the user has DBA privileges. Otherwise, it will return FALSE.
LANG The ISO abbreviation for the language
LANGUAGE The language, territory, and character of the session. In the following format:
     language_territory.characterset
SESSIONID The identifier of the auditing session
TERMINAL The OS identifier of the current session

For example:

userenv('ENTRYID') would return FALSE
userenv('LANGUAGE') would return 'AMERICAN_AMERICA.WE8DEC'
posted @ 2007-08-24 11:31 华梦行 阅读(1201) | 评论 (0)编辑 收藏
     摘要: javaScript技巧集合 事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放 event.srcElement.setCapture();  eve...  阅读全文
posted @ 2007-08-24 11:13 华梦行 阅读(272) | 评论 (0)编辑 收藏
关键字:   hibernate    

Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。其区别在于:

  1. 如果未能发现符合条件的记录,get方法返回null,而load方法会抛出一个ObjectNotFoundException。
  2. Load方法可返回实体的代理类实例,而get方法永远直接返回实体类。
  3. load方法可以充分利用内部缓存和二级缓存中的现有数据,而get方法则仅仅在内部缓存中进行数据查找,如没有发现对应数据,将越过二级缓存,直接调用SQL完成数据读取。

Session在加载实体对象时,将经过的过程:

  1. 首先,Hibernate中维持了两级缓存。第一级缓存由Session实例维护,其中保持了Session当前所有关联实体的数据,也称为内部缓存。而第二级缓存则存在于SessionFactory层次,由当前所有由本SessionFactory构造的Session实例共享。出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。
  2. 之后,Session会在当前“NonExists”记录中进行查找,如果“NonExists”记录中存在同样的查询条件,则返回null。“NonExists”记录了当前Session实例在之前所有查询操作中,未能查询到有效数据的查询条件(相当于一个查询黑名单列表)。如此一来,如果Session中一个无效的查询条件重复出现,即可迅速作出判断,从而获得最佳的性能表现。
  3. 对于load方法而言,如果内部缓存中未发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。
  4. 如在缓存中未发现有效数据,则发起数据库查询操作(Select SQL),如经过查询未发现对应记录,则将此次查询的信息在“NonExists”中加以记录,并返回null。
  5. 根据映射配置和Select SQL得到的ResultSet,创建对应的数据对象。
  6. 将其数据对象纳入当前Session实体管理容器(一级缓存)。
  7. 执行Interceptor.onLoad方法(如果有对应的Interceptor)。
  8. 将数据对象纳入二级缓存。
  9. 如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。
  10. 返回数据对象。
posted @ 2007-08-24 08:42 华梦行 阅读(86) | 评论 (0)编辑 收藏
public ITM_BuyContract getBuyContractById(String id) {
        ITM_BuyContract bc = null;
        Session session = HibernateUtil.getSession();
        bc = (ITM_BuyContract) session.get(ITM_BuyContract.class,id);
        return bc;
    }
posted @ 2007-08-23 15:39 华梦行 阅读(92) | 评论 (0)编辑 收藏

做webservice 尽量将具体的实现写在javabean里,这样可以减少客户网站和webservice的耦合,就是说你修改了具体的实现之后,客户网站并不需要重新部署,从而提高开发效率提高

posted @ 2007-08-23 14:56 华梦行 阅读(97) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2007-08-23 09:15 华梦行 阅读(17) | 评论 (0)编辑 收藏
function strLen(str) {
    if (!str) return 0;
    var len = 0;
    var pattern = /[\u4E00-\u9FA5]|[\uFE30-\uFFA0]/;
    for (var i = 0, j = str.length; i < j; i++) {
        if (pattern.test(str.charAt(i))) {
            len += 2;
        } else {
            len++;
        }
    }
    return len;
}
posted @ 2007-08-22 13:38 华梦行 阅读(158) | 评论 (0)编辑 收藏

/*
 * ViewUploadFile.java
 *
 * Created on 2006年2月4日, 上午1:29
 */

package path.system.manager;

import java.io.*;
import java.net.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;
import org.hibernate.Session;
import system.entity.CRM_UploadFile;
import.FileStorageService;

public class ViewUploadFile extends HttpServlet {
    private FileInputStream isFile = null;
   
    /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

        String szCoObject=request.getParameter("CoObject");
        String szID=request.getParameter("ID");
        String szMode = request.getParameter("Mode");
       
        //清空缓冲
        response.reset();
       
        OutputStream osOut = response.getOutputStream();
       
        if(szID == null || szID.equals("") || szID.equals("0"))
        {  
            byte[] cFileData = this.getNoDate (szCoObject);
           
            this.isFile.read(cFileData);
            osOut.write(cFileData);
        }
        else
        {
            Session ssSession = HibernateUtil.getSession();
            CRM_UploadFile csUpload;

            csUpload = (CRM_UploadFile)ssSession.load(CRM_UploadFile.class,Integer.valueOf(szID));

            String szFileName =csUpload.getFileName();
            if (szFileName==null) szFileName = "";
            String szRightName = new String( szFileName.getBytes(), "ISO8859_1" );      //中文文件名处理
            String szFileSize = csUpload.getFileSize().toString();
            String urlFileName = csUpload.getUrlFileName();
///输出到网页
            if ("0".equals(szFileSize)) {
                byte[] cFileData = this.getNoDate(szCoObject);
                this.isFile.read(cFileData);
                osOut.write(cFileData);
            } else {
                if(szMode.equals("Download")) {
                        response.setContentType("application/x-msdownload;");           //下载类型
                        response.setHeader("Content-Disposition","attachment; filename=" + szRightName);
                } else {
                        response.setContentType(csUpload.getContentType());
                        response.setHeader("Content-Disposition","filename=" + szRightName);
                }
                response.setHeader("content-length", szFileSize);
                //java.sql.Blob blob = csUpload.getBinaryData();
                File file = new File(FileStorageService.getRootPath() + urlFileName);
                if (!file.exists())
                    return;
               
                InputStream bis = new BufferedInputStream(new FileInputStream(file));
                byte[] buffer = new byte[2048];
                for (int i = bis.read(buffer); i > 0; i = bis.read(buffer))
                    osOut.write(buffer, 0, i);
                bis.close();
                   
            }
        }
       
        //防止超时
        //response.setStatus( response.SC_OK );
        response.flushBuffer();
    }
   
    private byte[] getNoDate (String szCoObject) throws IOException{
        String szFileName="";
        if(szCoObject.equals("Employee"))
            szFileName = getServletContext().getRealPath("/images/Employee/NoPhoto.gif");
        else
            szFileName = getServletContext().getRealPath("/images/Commodity/NoPhoto.gif");
        this.isFile= new FileInputStream(szFileName);

        int nSize = this.isFile.available();
        byte[] cFileData = new byte[nSize];
        return cFileData;
    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
   
    /** Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        processRequest(request, response);
    }
   
    /** Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }
    // </editor-fold>
}

posted @ 2007-08-21 13:24 华梦行 阅读(108) | 评论 (0)编辑 收藏
public final int read(byte[] b)
               throws IOException
从所包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾 (end of file) 或抛出异常之前,此方法将一直阻塞。

如果 b 为 null,则抛出 NullPointerException。如果 b 的长度为零,则不读取字节并返回 0;否则试图读取至少一个字节。如果因为该流在文件末尾而无字节可用,则返回值 -1;否则至少读取一个字节并将其存储到 b 中。

将读取的第一个字节存储到元素 b[0] 中,将下一个字节存储到 b[1] 中,依此类推。读取的字节数至多等于 b 的长度。设 k 为实际读取的字节数;这些字节将存储在从 b[0]b[k-1] 的元素中,b[k]b[b.length-1] 的元素不受影响。

如果因为文件末尾以外的其他原因而无法读取第一个字节,则抛出 IOException。尤其在输入流已关闭的情况下,将抛出 IOException

read(b) 方法与以下方法的效果相同:

 read(b, 0, b.length) 
posted @ 2007-08-21 12:43 华梦行 阅读(8177) | 评论 (0)编辑 收藏

import java.io.*;
import java.net.*;
public class Test {
    public boolean saveUrlAs(String photoUrl, String fileName) {
        //此方法只能用于HTTP协议
        try {
            URL url = new URL(photoUrl);
            HttpURLConnection connection = (HttpURLConnection) url.
                    openConnection();
            DataInputStream in = new DataInputStream(connection.getInputStream());
            DataOutputStream out = new DataOutputStream(new FileOutputStream(fileName));
            byte[] buffer = new byte[4096];
            int count = 0;
            while ((count = in.read(buffer)) > 0) {
                out.write(buffer, 0, count);
            }
            out.close();
            in.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }
   
    public String getDocumentAt(String urlString) {
        //此方法兼容HTTP和FTP协议
        StringBuffer document = new StringBuffer();
        try {
            URL url = new URL(urlString);
            URLConnection conn = url.openConnection();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                document.append(line + "\n");
            }
            reader.close();
        }catch (MalformedURLException e) {
            System.out.println("Unable to connect to URL: " + urlString);
        }catch (IOException e) {
            System.out.println("IOException when connecting to URL: " +
                    urlString);
        }
        return document.toString();
    }
   
    public static void main(String[] args) throws IOException {
        Test test = new Test();
        String photoUrl = "http://www.cjsdn.net/index.html";
        String fileName = photoUrl.substring(photoUrl.lastIndexOf("/"));
        String filePath = "c:";
        boolean flag = test.saveUrlAs(photoUrl, filePath + fileName);
        System.out.println("Run ok!\nGet URL file " + flag);
    }
}


 

posted @ 2007-08-21 11:30 华梦行 阅读(915) | 评论 (0)编辑 收藏

import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
/*
 * hello.java
 *
 * Created on 2007年8月3日, 上午11:15
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 *
 * @author ljl
 */
public class hello {
   
    /** Creates a new instance of hello */
    public hello() {
    }
    public static void main(String s[]) throws Exception{
        String sss="Sogood";
       // System.out.print(sss.substring(0,4));
        ReadURL("http://java.ok6.org/logo.jpg");
    }
    public static void ReadURL(String URLName) throws Exception // 如果发生异常则向上抛出
    {
        int HttpResult; // 服务器返回的状态
        URL url =new URL(URLName); // 创建URL
       
        URLConnection urlconn = url.openConnection(); // 试图连接并取得返回状态码
        urlconn.connect();
        HttpURLConnection httpconn =(HttpURLConnection)urlconn;
        HttpResult = httpconn.getResponseCode();
        System.out.println(HttpResult);
        if(HttpResult != HttpURLConnection.HTTP_OK) // 不等于HTTP_OK说明连接不成功
           System.out.print("fail");
        else {
            int filesize = urlconn.getContentLength(); // 取数据长度
            System.out.println(filesize);
            InputStreamReader isReader = new InputStreamReader(urlconn.getInputStream());
            char[] buffer = new char[2048]; // 创建存放输入流的缓冲
            int num = 0; // 读入的字节数
            while(num>-1) {
                num = isReader.read(buffer); // 读入到缓冲区
                if(num < 0) break; // 已经读完
                System.out.print("suc");
              System.out.println(new String(buffer,0,num)); // 显示出来
            }
            isReader.close();//关闭输入流
        }
    }
   
   
}

posted @ 2007-08-21 10:38 华梦行 阅读(979) | 评论 (0)编辑 收藏

404:服务器找不到指定的资源,请求的网页不存在(譬如浏览器请求的网页被删除或者移位,但不排除日后该链接有效的可能性);32C站长资讯
410:请求的网页不存在(注意:410表示永久性,而404表示临时性);32C站长资讯
200:服务器成功返回请求的网页;32C站长资讯
301:网址永久性重定向32C站长资讯
302:网址临时性重定向

posted @ 2007-08-21 10:31 华梦行 阅读(220) | 评论 (0)编辑 收藏
试一试修改server.xml文件,路径在:
server\default\deploy\jbossweb-tomcat55.sar

在host标签中增加
<Context cookies="true" crossContext="true" path="/test" docBase="z:\test" />



请问一下,我们在tomcat中的server.xml中每设置一个<Context...../>比如:
<Context path="/oa" docBase="oa" debug="4" reloadable="true" crossContext="true"> </Context>
相应的工程中的.java文件修改了,可以自动重新加载。。。
其他工程修改就不行,,又要再加一条相应的语句,,不知道有没有其他的方法只要设置一下,就会侦听所有的工程,,,任何一个工程修改,,都可以自动重新加载。。。谢谢。。
我用的是myeclipse+eclipse+tomcat

posted @ 2007-08-21 09:48 华梦行 阅读(439) | 评论 (0)编辑 收藏
Singleton 模式主要作用是保证在 Java 应用程序中,一个类 Class 只有一个实例存在。

  一般 Singleton 模式通常有几种种形式:

  第一种形式:定义一个类,它的构造函数为 private 的,它有一个 static private 的该类变量,在类初始化时实例话,通过一个 public getInstance 方法获取对它的引用 , 继而调用其中的方法。

public class Singleton {

   private Singleton(){}

   // 在自己内部定义自己一个实例,是不是很奇怪?

   // 注意这是 private 只供内部调用

   private static Singleton instance = new Singleton();

   // 这里提供了一个供外部访问本 class 的静态方法,可以直接访问  

   public static Singleton getInstance() {

     return instance;   

   }

}

 

  第二种形式:

public class Singleton {

   private static Singleton instance = null;

   public static synchronized Singleton getInstance() {

   // 这个方法比上面有所改进,不用每次都进行生成对象,只是第一次     

   // 使用时生成实例,提高了效率!

   if (instance==null)

     instance new Singleton();

return instance;    }

}

posted @ 2007-08-20 14:01 华梦行 阅读(562) | 评论 (0)编辑 收藏
swtich 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String ?

   switch expr1 )中, expr1 是一个整数表达式。因此传递给 switch case 语句的参数应该是 int short char 或者 byte long,string 都不能作用于 swtich

posted @ 2007-08-20 13:52 华梦行 阅读(3299) | 评论 (0)编辑 收藏
try {} 里有一个 return 语句,那么紧跟在这个 try 后的 finally {} 里的 code 会不会被执行,什么时候被执行,在 return 前还是后 ?

  会执行,在 return 前执行。

posted @ 2007-08-20 13:45 华梦行 阅读(183) | 评论 (0)编辑 收藏
Overload Override 的区别。 Overloaded 的方法是否可以改变返回值的类型 ?

  方法的重写 Overriding 和重载 Overloading Java 多态性的不同表现。重写 Overriding 是父类与子类之间多态性的一种表现,重载 Overloading 是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding) 。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载 (Overloading) Overloaded 的方法是可以改变返回值的类型

posted @ 2007-08-20 13:40 华梦行 阅读(234) | 评论 (0)编辑 收藏
数组有没有 length() 这个方法 ? String 有没有 length() 这个方法?

  数组没有 length() 这个方法,有 length 的属性。

   String 有有 length() 这个方法。

posted @ 2007-08-20 13:39 华梦行 阅读(1937) | 评论 (0)编辑 收藏
sleep:在睡觉,要睡够了你才叫得醒
wait:在等你叫它
TOP
回复人:Polarislee(北极星)(灌水是我无言的抗议)  一星(中级)  信誉:110      2005-3-1 13:35:27  得分:20

sleep是Thread类的静态方法。sleep的作用是让线程休眠制定的时间,在时间到达时恢复,也就是说sleep将在接到时间到达事件事恢复线程执行,例如:

try{
System.out.println("I'm going to bed");
Thread.sleep(1000);
System.out.println("I wake up");
}
catch(IntrruptedException e) {
}


wait是Object的方法,也就是说可以对任意一个对象调用wait方法,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify方法才会重新激活调用者,例如:


//Thread 1

try{
obj.wait();//suspend thread until obj.notify() is called
}
catch(InterrputedException e) {
}
posted @ 2007-08-20 13:23 华梦行 阅读(540) | 评论 (0)编辑 收藏

16 Collection Collections 的区别。

   Collections 是个 java.util 下的类,它包含有各种有关集合操作的静态方法。

   Collection 是个 java.util 下的接口,它是各种集合结构的父接口。

posted @ 2007-08-20 13:17 华梦行 阅读(151) | 评论 (0)编辑 收藏

ArrayList和Vector的区别,HashMap和Hashtable的区别 
答:就ArrayList与Vector主要从二方面来说. 
一.同步性:Vector是线程安全的,也就是说是同步的,而ArrayList是线程序不安全的,不是同步的 
二.数据增长:当需要增长时,Vector默认增长为原来一培,而ArrayList却是原来的一半 
就HashMap与HashTable主要从三方面来说。 
一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 
二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 
三.值:只有HashMap可以让你将空值作为一个表的条目的key或value 

  

都属于
Map 接口的类,实现了将惟一键映射到特定的值上。

 

   HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。

   Hashtable 类似于 HashMap ,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。

posted @ 2007-08-20 13:13 华梦行 阅读(251) | 评论 (0)编辑 收藏
Stack.  用来在ram中存放数据的地方 This   lives   in   the   general   RAM   (random-access   memory)   area,   but    has   direct   support   from   the   processor   via   its   stack   pointer.   The   stack   pointer   is   moved   down   to   create   new   memory   and   moved   up   to   release   that   memory.   This   is   an   extremely   fast   and   efficient   way   to   allocate   storage,   second   only   to   registers.   The   Java   compiler   must   know,   while   it   is   creating   the   program,   the   exact   size   and   lifetime   of   all   the   data   that   is   stored   on   the   stack,   because   it   must   generate   the   code   to   move   the   stack   pointer   up   and   down.   This   constraint   places   limits   on   the   flexibility   of   your   programs,   so   while   some   Java   storage   exists   on   the   stack   ?in   particular,   object   handles   ?Java   objects   are   not   placed   on   the   stack.    
   
  Heap.   This   is   a   general-purpose   pool   of   memory   (also   in   the   RAM   area)   where   all   Java   objects   live.   The   nice   thing   about   the   heap   is   that,   unlike   the   stack,   the   compiler   doesn't   need   to   know   how   much   storage   it   needs   to   allocate   from   the   heap   or   how   long   that   storage   must   stay   on   the   heap.   Thus,   there's   a   great   deal   of   flexibility   in   using   storage   on   the   heap.   Whenever   you   need   to   create   an   object,   you   simply   write   the   code   to   create   it   using   new   and   the   storage   is   allocated   on   the   heap   when   that   code   is   executed.   And   of   course   there's   a   price   you   pay   for   this   flexibility:   it   takes   more   time   to   allocate   heap   storage.  
. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char。存在于栈中。另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中.
posted @ 2007-08-20 13:08 华梦行 阅读(163) | 评论 (0)编辑 收藏

Boolean.parseBoolean("Strrrr");   false
只有String 在忽略大小写的情况小“true”才会返回true

posted @ 2007-08-20 10:18 华梦行 阅读(503) | 评论 (0)编辑 收藏
String strSource=request.getHeader("Referer")
posted @ 2007-08-17 10:29 华梦行 阅读(72) | 评论 (0)编辑 收藏
     strReturn= sql.replaceAll("(&)|(\\^)|(')|(/)|(;)|(:)|(_)|(%)|(\")|(\n)|(\\*)|(\\+)|(\\[)|(\\])|(\\})|(\\{)|(\\n)|(\\|)","");

 public static String dealSql(String sql){
        String strReturn="";
        if (sql==null)
            strReturn="";
        else{
            try{
        strReturn= sql.replaceAll("(&)|(\\^)|(')|(/)|(;)|(:)|(_)|(%)|(\")|(\n)|(\\*)|(\\+)|(\\[)|(\\])|(\\})|(\\{)|(\\n)|(\\|)","");
            }catch(Exception e){
                System.out.println(e.toString());
                strReturn="";
            }
        }
        return strReturn;
    }
posted @ 2007-08-16 18:10 华梦行 阅读(109) | 评论 (0)编辑 收藏
ws

/*
 * PathWsInterUnit.java
 *
 * Created on 2007年8月16日, 下午12:52
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package path.ws.interUnit;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;


import path.crm.entity.CRM_Interunit;
import path.crm.manager.InterUnitManager;

/**
 *
 * @author ljl
 */
@WebService()
public class PathWsInterUnit {
    /**
     * Web service operation  客户新增
     * @param pwsStrWebSiteID   网站id
     * @param pwsStrInterUnitName   客户名称
     * @param pwsStrTel       电话
     * @param pwsStrMobile   手机
     * @param pwsStrFax   传真
     * @param pwsStrCorpName   公司名称
     * @param pwsStrEmail   公司邮件
     * @param pwsStrMemo   详细信息
     * @return   "success" : 添加成功     userexisted: "用户已存在" emailexisted: 该邮件已经被使用过了  fail: 添加失败
     */
    @WebMethod
    public String pathWsInterUnitAdd(@WebParam(name = "pwsStrWebSiteID") String pwsStrWebSiteID, @WebParam(name = "pwsStrInterUnitName") String pwsStrInterUnitName, @WebParam(name = "pwsStrTel") String pwsStrTel, @WebParam(name = "pwsStrMobile") String pwsStrMobile, @WebParam(name = "pwsStrFax") String pwsStrFax, @WebParam(name = "pwsStrCorpName") String pwsStrCorpName, @WebParam(name = "pwsStrEmail") String pwsStrEmail, @WebParam(name = "pwsStrMemo") String pwsStrMemo) {
 String strReturn;
  InterUnitManager  im=new InterUnitManager();
  //检查用户时候存在
 if ("existed".equals(im.chkIfExistRcd(pwsStrInterUnitName,"InterUnitName")))
      return  "userexisted";
  if ("existed".equals(im.chkIfExistRcd(pwsStrInterUnitName,"InterUnitName")))
   return  "emailexisted";
 //检查邮件是否存在
        try{
        CRM_Interunit ci=new CRM_Interunit();
        ci.setSerialNumber(pwsStrInterUnitName);
        ci.setOrgTypeId("pathwebserviceorgnization");
        ci.setCreatorTypeId(pwsStrWebSiteID);
        ci.setName(pwsStrCorpName);
        ci.setTelephone(pwsStrTel);
        ci.setFax(pwsStrFax);
        ci.setEmail(pwsStrEmail);
        ci.setDescription(pwsStrMemo);
      return im.insertInterunitWs(ci);
        }catch(Exception e){
            System.out.println(e.toString());
            return "fail";
        }
    }

    /**
     * Web service operation   是否存在的服务  直接调用javabean
     * @param pwsStrWebSiteId  网站id 
     * @param pwsStrChkName
     * @param pwsStrChkModule   模块名   InterUnitName:检验客户是否存在   InterUnitEmail:邮件是否被注册过
     * @return   不存在:notExisted   存在:existed     异常:"fail
     */
    @WebMethod
    public String pathWsCheckUserExist(@WebParam(name = "pwsStrWebSiteId") String pwsStrWebSiteId, @WebParam(name = "pwsStrChkName") String pwsStrChkName, @WebParam(name = "pwsStrChkModule") String pwsStrChkModule) {
        // TODO implement operation
        return  new InterUnitManager().chkIfExistRcd(pwsStrChkName,pwsStrChkModule);
    }
   
}

posted @ 2007-08-16 14:19 华梦行 阅读(102) | 评论 (0)编辑 收藏

Server.xml  : 
<GlobalNamingResources>
        <!-- Test entry for demonstration purposes -->
        <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
        <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users -->
        <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
     <!--  
        <Resource
            auth="Container"
            name="jdbc/PathPlat"
            type="javax.sql.DataSource"
            password=""
            driverClassName="net.sourceforge.jtds.jdbc.Driver"
            maxIdle="50"
            maxWait="5000"
            username="sa"
            url="jdbc:jtds:sqlserver://192.168.0.155:1433/pathplat;tds=8.0;lastupdatecount=true"
            removeAbandoned="true"
            removeAbandonedTimeout="60"
            maxActive="100"/>    -->
          
        <Resource
            name="jdbc/PathPlat"
            auth="Container"
            type="javax.sql.DataSource"
            password=""
            driverClassName="oracle.jdbc.driver.OracleDriver"
            maxIdle="50"
            maxWait="5000"
            username="tep"
            url="jdbc:oracle:thin:@192.168.0.166:1521:w"
            removeAbandoned="true"
            removeAbandonedTimeout="60"
            maxActive="100"/>
      
    </GlobalNamingResources>
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/PathCrm" reloadable="true">
  <ResourceLink global="jdbc/PathPlat" name="jdbc/PathPlat" type="javax.sql.DataSource"/>
</Context>
hibernate.cfg.xml:
<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property  name="connection.datasource">java:comp/env/jdbc/PathPlat</property> 

        <!-- SQL dialect -->
        <!--<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>-->
        <property name="dialect">org.hibernate.dialect.OracleDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">false</property>

 <mapping resource="/wms/entity/WmsAdjustStoreCmdt.hbm.xml"/>
        <mapping resource="/wms/entity/WmsStorage.hbm.xml"/>
  
    </session-factory>

</hibernate-configuration>

posted @ 2007-08-15 10:44 华梦行 阅读(148) | 评论 (0)编辑 收藏
竖排格式:Portrait  横排格式:landscape
posted @ 2007-08-14 19:18 华梦行 阅读(147) | 评论 (0)编辑 收藏
 If dtmDateLowerLimit is not null and dtmDateUpperLimit is not null then
    temps := temps ||' AND DATEDIFF(''d'', to_date('''||to_char(dtmDateLowerLimit,'yyyy-mm-dd ')|| ' 00:00:00'||''',''yyyy-mm-dd HH24:mi:ss''), a.SendTime) >= 0 AND DATEDIFF(''d'', a.SendTime, to_date('''||to_char(dtmDateUpperLimit,'yyyy-mm-dd')|| ' 23:59:59'||''',''yyyy-mm-dd HH24:mi:ss'')) >= 0 ' ;
  End If; 
posted @ 2007-08-13 11:14 华梦行 阅读(83) | 评论 (0)编辑 收藏
document.getElementById("ffff").readOnly=true;
 readOnly  O必须大写
posted @ 2007-08-10 14:20 华梦行 阅读(123) | 评论 (0)编辑 收藏

  Session session = HibernateUtil.getSession();
            Criteria crit = session.createCriteria(entityClass);
            crit.add(Restrictions.eq("orgTypeId", orgId)); 
            crit.add(Restrictions.eq("StructID", strTypeid));
            List entities = crit.list();
            populate(sheet, entities);

  Hibernate 条件查询

/*
 * ExportManager.java
 *
 * Created on 2006年7月30日, 下午2:40
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package path.system.manager;

import java.io.*;
import java.util.List;
import java.util.Date;
import java.sql.Timestamp;
import java.lang.reflect.*;
import java.math.BigDecimal;

import jxl.*;
import jxl.write.*;
import org.hibernate.Session;
import org.hibernate.Query;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;

import path.system.manager.HibernateUtil;
import path.util.DoNumber;

/**
 *
 * @author zhaoming
 */
public class ExportManager {
   
    private Class entityClass;
    private Field[] fields;
    private Class[] fieldTypes;
   
    private static WritableCellFormat integerFormat = new WritableCellFormat(NumberFormats.INTEGER);
    private static WritableCellFormat floatFormat = new WritableCellFormat(new NumberFormat("#.####"));
    private static WritableCellFormat dateFormat = new WritableCellFormat(new DateFormat("yyyy-MM-dd"));
   
    public ExportManager() {
    }
   
    /**
     * 输出excel
     * @param is 原始excel模版输入流
     * @param os 目的输出流,这里是ServletOutputStream
     */
    public void exportExcel(InputStream is, OutputStream os, String orgId) {
        WritableWorkbook wb = null;
        try {
            wb = Workbook.createWorkbook(os, Workbook.getWorkbook(is));
            WritableSheet sheet = wb.getSheet(0);
            init(sheet);
            Session session = HibernateUtil.getSession();
            Criteria crit = session.createCriteria(entityClass);
            crit.add(Restrictions.eq("orgTypeId", orgId));
            List entities = crit.list();
            populate(sheet, entities);
            wb.write();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { wb.close(); } catch (Exception e) {}
        }
    }
    public void exportExcelCd(InputStream is, OutputStream os, String orgId, String strTypeid) {
        WritableWorkbook wb = null;
        try {
            wb = Workbook.createWorkbook(os, Workbook.getWorkbook(is));
            WritableSheet sheet = wb.getSheet(0);
            init(sheet);
            Session session = HibernateUtil.getSession();
            Criteria crit = session.createCriteria(entityClass);
            crit.add(Restrictions.eq("orgTypeId", orgId)); 
            crit.add(Restrictions.eq("StructID", strTypeid));
            List entities = crit.list();
            populate(sheet, entities);
            wb.write();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { wb.close(); } catch (Exception e) {}
        }
    }
   
    private void init(WritableSheet sheet) throws Exception {
        entityClass = Class.forName(sheet.getCell(0, 0).getContents().trim());
        Cell[] fieldNames = sheet.getRow(1);
        int len = fieldNames.length;
        fields = new Field[len];
        fieldTypes = new Class[len];
        for (int i = 0; i < len; i++) {
            fields[i] = entityClass.getDeclaredField(fieldNames[i].getContents().trim());
            fieldTypes[i] = fields[i].getType();
        }
    }
   
    private void populate(WritableSheet sheet, List entities) throws Exception {
        for (int i = 0; i < entities.size(); i++) {
            Object entity = entities.get(i);
            for (int j = 0; j < fields.length; j++) {
                fields[j].setAccessible(true);
                WritableCell cell = getCell(i + 3, j, fields[j].get(entity));
                sheet.addCell(cell);
            }
        }
    }
   
    private WritableCell getCell(int row, int col, Object value) {
        if (fieldTypes[col] == String.class)
            return new Label(col, row, (String) value);
        if (fieldTypes[col] == long.class || fieldTypes[col] == Long.class)
            return new jxl.write.Number(col, row, value == null ? 0 : ((Long) value).longValue(), integerFormat);
        if (fieldTypes[col] == int.class || fieldTypes[col] == Integer.class)
            return new jxl.write.Number(col, row, value == null ? 0 : ((Integer) value).intValue(), integerFormat);
        if (fieldTypes[col] == double.class || fieldTypes[col] == Double.class)
            return new jxl.write.Number(col, row, value == null ? 0 : ((Double) value).doubleValue(), floatFormat);
        if (fieldTypes[col] == float.class || fieldTypes[col] == Float.class)
            return new jxl.write.Number(col, row, value == null ? 0 : ((Float) value).floatValue(), floatFormat);
        if (fieldTypes[col] == BigDecimal.class)
            return new jxl.write.Number(col, row, value == null ? 0 : ((BigDecimal) value).doubleValue(), floatFormat);
        if (fieldTypes[col] == Timestamp.class || fieldTypes[col] == Date.class)
            return new jxl.write.DateTime(col, row, value == null ? new Date() : (Date) value, dateFormat);
        return null;
    }
   
}

posted @ 2007-08-10 14:18 华梦行 阅读(232) | 评论 (0)编辑 收藏
var oOpener = dialogArguments ;
      
 oOpener.szOldPassword = document.all.OldPassword.value ;
 oOpener.szNewPassword = document.all.NewPassword.value ;
 oOpener.bIsEditPwd = true ;

openDialog('UserModifyPwd.jsp?TimeID=' + Math.random(),window,300,180) ;
 if (bIsEditPwd == true){
  document.Form1.OldPassword.value = szOldPassword ;
  document.Form1.NewPassword.value = szNewPassword ;
  top.topFrame.saveURL('../Configure/UserConfigure.jsp?AutoShow=Yes&TimeID=' + Math.random()) ;
  document.Form1.submit() ;
 }
posted @ 2007-08-01 16:26 华梦行 阅读(582) | 评论 (0)编辑 收藏
select * from col , user_tab_cols  
posted @ 2007-07-31 11:39 华梦行 阅读(88) | 评论 (0)编辑 收藏

D:\aa>keytool -genkey -v -alias JoeUserKey -keyalg RSA
输入keystore密码:  huamengxing
您的名字与姓氏是什么?
  [Unknown]:  Joe usr
您的组织单位名称是什么?
  [Unknown]:  security
您的组织名称是什么?
  [Unknown]:  commmm,Inc
您所在的城市或区域名称是什么?
  [Unknown]:  fsdfs
您所在的州或省份名称是什么?
  [Unknown]:  fsdfsd
该单位的两字母国家代码是什么
  [Unknown]:  cn
CN=Joe usr, OU=security, O="commmm,Inc", L=fsdfs, ST=fsdfsd, C=cn 正确吗?
  [否]:  y

创建1,024比特RSA键值对及针对CN=Joe usr, OU=security, O="commmm,Inc", L=fsdfs, ST
=fsdfsd, C=cn的自我签署的认证 (MD5WithRSA)
        :
输入<JoeUserKey>的主密码
        (如果和 keystore 密码相同,按回车):
[正在存储 C:\Documents and Settings\ljl\.keystore]

D:\aa>keytool -list -v -genkey -alias JooUserKey
输入keystore密码:  huamengxing
您的名字与姓氏是什么?
  [Unknown]:  Joe usr
您的组织单位名称是什么?
  [Unknown]:  security
您的组织名称是什么?
  [Unknown]:  commmm,Inc
您所在的城市或区域名称是什么?
  [Unknown]:  fadfs
您所在的州或省份名称是什么?
  [Unknown]:  fsdfsd
该单位的两字母国家代码是什么
  [Unknown]:  cn
CN=Joe usr, OU=security, O="commmm,Inc", L=fadfs, ST=fsdfsd, C=cn 正确吗?
  [否]:  y

创建1,024比特DSA键值对及针对CN=Joe usr, OU=security, O="commmm,Inc", L=fadfs, ST
=fsdfsd, C=cn的自我签署的认证 (SHA1WithDSA)
        :
输入<JooUserKey>的主密码
        (如果和 keystore 密码相同,按回车):
[正在存储 C:\Documents and Settings\ljl\.keystore]

D:\aa>keytool -list -v  -alias JooUserKey
输入keystore密码:  huamengxing
别名名称: JooUserKey
创建日期: 2007-7-30
输入类型:KeyEntry
认证链长度: 1
认证 [1]:
Owner: CN=Joe usr, OU=security, O="commmm,Inc", L=fadfs, ST=fsdfsd, C=cn
发照者: CN=Joe usr, OU=security, O="commmm,Inc", L=fadfs, ST=fsdfsd, C=cn
序号: 46ad82e0
有效期间: Mon Jul 30 14:19:12 CST 2007 至: Sun Oct 28 14:19:12 CST 2007
认证指纹:
         MD5:  88:F5:21:21:2C:65:03:84:60:12:65:55:39:D3:A0:1E
         SHA1: 37:B6:87:9F:C4:EA:E4:50:9A:F4:00:B3:41:58:C8:F0:10:5E:44:8E

D:\aa>
 D:\>keytool.exe -genkey -alias Tomcat -keyalg RSA -storepass bigsecret -keypass bigsecret -dname "cn=localhost"

  执行完该命令后,就会在HOME目录下生成一个.keystore文件。下面是各种切换命令的含义:

  · genkey:告诉keytool应用程序生成新的公钥/私钥对。
  · alias:用于引用密钥的名称。记住,.keystore文件可包含多个密钥。
  · Keyalg:使用RSA算法生成公钥/私钥对。
  · Storepass:访问.keystore文件所需的口令。
  · Keypass:管理密钥所需的口令。
  · dname:该值非常重要。.我使用了localhost,因为该示例被设计为本地运行。如果一个Web应用程序被注册为http://www.myserver.com,那么该值就必须是www.myserver.com。如果名称不匹配,证书就会自动被拒绝。
  一旦keytool应用程序创建了一个新的公钥/私钥对,它就自动自签名该密钥。我们刚刚生成了自己的自签名证书,它可用于HTTPS通信。只需提取出自签名公钥。后面我将展示如何做。

posted @ 2007-07-30 14:24 华梦行 阅读(1281) | 评论 (0)编辑 收藏

public void close()
    {
        try
        {
             if(rs!=null) rs.close();
             if(st!=null) st.close();
             if(cn!=null) cn.close();
        }
        catch(SQLException _ex)
        {
            try
            {
                if(rs != null)   rs.close();
            }
            catch(SQLException _ex2)
            {
                try
                {
                    if(st != null) st.close();
                }
                catch(SQLException _ex3) {
                }
                try
                {
                    if(cn != null) cn.close();
                }
                catch(SQLException _ex3) {
                }
            }

            try
            {
                if(st != null)  st.close();
            }
            catch(SQLException _ex2)
            {
                try
                {
                    if(cn != null) cn.close();
                }
                catch(SQLException _ex3) {
                }
            }
            try
            {
                if(cn != null)   cn.close();
            }
            catch(SQLException _ex2) {
            }
        }
        finally
        {
          try
          {
           // if(rs!=null) rs.close();
            if(st!=null) st.close();
            if(cn!=null) cn.close();
          }
          catch(Exception e)
          {
            //System.out.println(e.toString());
          }
        }

    }

posted @ 2007-07-27 13:56 华梦行 阅读(92) | 评论 (0)编辑 收藏

select NVL(b.Name, ' ') AS spec, ' ' as packs,
'' as Quant,
'' as Price,

 NVL(a.feeamount,0) as amount, ' ' as cpbh,' ' as cpname, ' ' as jidw
from ITM_Documentfee a  left join
sys_datadictionary b on b.id=a.feeid    

union
select
NVL(b.Spec, ' ') AS spec,
NVL(b.field1,' ') as packs,
case Quant
 when 0 then
  ' '
 when null then
  ' '
 else
   to_char(Quant) 
end as Quant
,
case Price
 when 0 then
  ' '
 when null then
  ' '
 else
   to_char(Price) 
end as Price
,
  NVL(b.Amount, 0) AS amount,
c.SerialNumber as cpbh,NVL(c.EnName, ' ') AS cpname,
NVL(t.Symbol, ' ') AS jidw
from ITM_SalesCommodity b
left join CRM_Commodity c ON c.TypeID = b.CommodityTypeID
LEFT OUTER JOIN      BSE_MeasureStyle t ON b.QuantUnitID = t.ID


select ISNULL(b.Name, ' ') AS spec, ' ' as packs,
'' as Quant,
'' as Price,

 isnull(a.feeamount,0) as amount, ' ' as cpbh,' ' as cpname, ' ' as jidw
from ITM_Documentfee a  left join
sys_datadictionary b on b.id=a.feeid    

union
select
ISNULL(b.Spec, ' ') AS spec,
isnull(b.field1,' ') as packs,
Quant =
case
 when Quant>0 then
  CAST( Quant AS varchar(20))
 else ''
end
,
Price =
case
 when Price>0 then
  CAST( Price AS varchar(20))
 else ''
end
,
  ISNULL(b.Amount, 0) AS amount,
c.SerialNumber as cpbh,ISNULL(c.EnName, ' ') AS cpname,
ISNULL(t.Symbol, ' ') AS jidw
from ITM_SalesCommodity b
left join CRM_Commodity c ON c.TypeID = b.CommodityTypeID
LEFT OUTER JOIN      BSE_MeasureStyle t ON b.QuantUnitID = t.ID

posted @ 2007-07-27 13:44 华梦行 阅读(96) | 评论 (0)编辑 收藏

using System;
using System.Data;
using System.Data.SqlClient;

namespace com.hua..li
{
 /// <summary>
 /// 数据库操作
 /// </summary>
 public class pathDB:pathPage
 {

  override protected void OnInit(EventArgs e)
  {
   pathInit();
   base.OnInit(e);
  }

  protected void pathInit()
  {
   this.ConnectDb();
  }

  protected void ConnectDb()
  {
   if(doh == null)
   {
    System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(System.Configuration.ConfigurationSettings.AppSettings["connString"]);
    doh = new com.path.SqlDbOperHandler(conn);
   }
  }
 }
}
using System;

namespace com.hua.li
 {
  /// <summary>
  /// 表示数据库连接类型。
  /// </summary>
  public enum DatabaseType:byte{SqlServer,OleDb};
  /// <summary>
  /// DbOperHandler 的摘要说明。
  /// </summary>
  public abstract class DbOperHandler
  {
   /// <summary>
   /// 析构函数,释放申请的资源。
   /// </summary>
   ~DbOperHandler()
   {
    conn.Close();
   }
   /// <summary>
   /// 表示数据库连接的类型,目前支持SqlServer和OLEDB
   /// </summary>
   protected DatabaseType dbType=DatabaseType.OleDb;
   /// <summary>
   /// 返回当前使用的数据库连接对象。
   /// </summary>
   /// <returns></returns>
   public System.Data.IDbConnection GetConnection()
   {
    return conn;
   }
   /// <summary>
   /// 条件表达式,用于在数据库操作时筛选记录,通常用于仅需指定表名称和某列名称的操作,如GetValue(),Delete()等,支持查询参数,由AddConditionParameters指定。。
   /// </summary>
   public string ConditionExpress=string.Empty;
   /// <summary>
   /// 当前的SQL语句。
   /// </summary>
   public string SqlCmd=string.Empty;
   /// <summary>
   /// 当前操作所涉及的数据表名称。
   /// </summary>
   protected string tableName=string.Empty;
   /// <summary>
   /// 当前操作所设计的字段名称。
   /// </summary>
   protected string fieldName=string.Empty;
   /// <summary>
   /// 当前所使用的数据库连接。
   /// </summary>
   protected System.Data.IDbConnection conn;
   /// <summary>
   /// 当前所使用的命令对象。
   /// </summary>
   protected System.Data.IDbCommand cmd;
   /// <summary>
   /// 当前所使用的数据库适配器。
   /// </summary>
   protected System.Data.IDbDataAdapter da;

  
   /// <summary>
   /// 用于存储字段/值配对。
   /// </summary>
   protected System.Collections.ArrayList alFieldItems=new System.Collections.ArrayList(10);
   /// <summary>
   /// 用于存储SQL语句中的查询参数。
   /// </summary>
   protected System.Collections.ArrayList alSqlCmdParameters=new System.Collections.ArrayList(5);
   /// <summary>
   /// 用于存储条件表达式中的查询参数。
   /// </summary>
   protected System.Collections.ArrayList alConditionParameters=new System.Collections.ArrayList(5);
   /// <summary>
   /// 重值该对象,使之恢复到构造时的状态。
   /// </summary>
   public void Reset()
   {
    this.alFieldItems.Clear();
    this.alSqlCmdParameters.Clear();
    this.alConditionParameters.Clear();
    this.ConditionExpress=string.Empty;
    this.SqlCmd=string.Empty;
    this.cmd.Parameters.Clear();
    this.cmd.CommandText=string.Empty;
   }
   /// <summary>
   /// 添加一个字段/值对到数组中。
   /// </summary>
   /// <param name="_fieldName">字段名称。</param>
   /// <param name="_fieldValue">字段值。</param>
   public void AddFieldItem(string _fieldName,object _fieldValue)
   {

    for(int i=0;i<this.alFieldItems.Count;i++)
    {
     if(((DbKeyItem)this.alFieldItems[i]).fieldName==_fieldName)
     {
      throw new ArgumentException("The field name has existed!");
     }
    }
    this.alFieldItems.Add(new DbKeyItem(_fieldName,_fieldValue));
   }
   /// <summary>
   /// 添加条件表达式中的查询参数到数组中。注意:当数据库连接为SqlServer时,参数名称必须和SQL语句匹配。其它则只需保持添加顺序一致,名称无需匹配。
   /// </summary>
   /// <param name="_conditionName">条件名称。</param>
   /// <param name="_conditionValue">条件值。</param>
   public void AddConditionParameter(string _conditionName,object _conditionValue)
   {
    for(int i=0;i<this.alConditionParameters.Count;i++)
    {
     if(((DbKeyItem)this.alConditionParameters[i]).fieldName==_conditionName)
     {
      throw new ArgumentException("The condition name has existed!");
     }
    }
    this.alConditionParameters.Add(new DbKeyItem(_conditionName,_conditionValue));
   }

   /// <summary>
   /// 添加SQL语句中的查询参数到数组中。注意:当数据库连接为SqlServer时,参数名称必须和SQL语句匹配。其它则只需保持添加顺序一致,名称无需匹配。
   /// </summary>
   /// <param name="_paraName">参数名称。</param>
   /// <param name="_paraValue">参数值。</param>
   public void AddSqlCmdParameters(string _paraName,object _paraValue)
   {
    for(int i=0;i<this.alSqlCmdParameters.Count;i++)
    {
     if(((DbKeyItem)this.alSqlCmdParameters[i]).fieldName==_paraName)
     {
      throw new ArgumentException("The sqlcmd parameter name has existed!");
     }
    }
    this.alSqlCmdParameters.Add(new DbKeyItem(_paraName,_paraValue));
   }

   public bool Exist(string tableName)
   {
    return this.GetValue(tableName,"count(*)").ToString()!="0";
   }
   /// <summary>
   /// 抽象函数。用于产生Command对象所需的参数。
   /// </summary>
   protected abstract void GenParameters();
   /// <summary>
   /// 根据当前alFieldItem数组中存储的字段/值向指定表中添加一条数据。在该表无触发器的情况下返回添加数据所获得的自动增长id值。
   /// </summary>
   /// <param name="_tableName">要插入数据的表名称。</param>
   /// <returns>返回本数据连接上产生的最后一个自动增长id值。</returns>
   public int Insert(string _tableName)
   {
   
    this.tableName=_tableName;
    this.fieldName=string.Empty;
    this.SqlCmd="insert into "+this.tableName+"(";
    string tempValues=" values(";
    for(int i=0;i<this.alFieldItems.Count-1;i++)
    {
     this.SqlCmd+=((DbKeyItem)alFieldItems[i]).fieldName;
     this.SqlCmd+=",";

     tempValues+="@para";
     tempValues+=i.ToString();

     tempValues+=",";
    }
    this.SqlCmd+=((DbKeyItem)alFieldItems[alFieldItems.Count-1]).fieldName;
    this.SqlCmd+=") ";

    tempValues+="@para";
    tempValues+=(alFieldItems.Count-1).ToString();

    tempValues+=")";
    this.SqlCmd+=tempValues;
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    cmd.ExecuteNonQuery();
    cmd.CommandText="select @@identity as id";
    int autoId=Convert.ToInt32(cmd.ExecuteScalar());
    return autoId;
   }

   /// <summary>
   /// 根据当前alFieldItem数组中存储的字段/值和条件表达式所指定的条件来更新数据库中的记录,返回所影响的行数。
   /// </summary>
   /// <param name="_tableName">要更新的数据表名称。</param>
   /// <returns>返回此次操作所影响的数据行数。</returns>
   public int Update(string _tableName)
   {
    this.tableName=_tableName;
    this.fieldName=string.Empty;
    this.SqlCmd="update "+this.tableName+" set ";
    for(int i=0;i<this.alFieldItems.Count-1;i++)
    {
     this.SqlCmd+=((DbKeyItem)alFieldItems[i]).fieldName;
     this.SqlCmd+="=";

     this.SqlCmd+="@para";
     this.SqlCmd+=i.ToString();

     this.SqlCmd+=",";
    }
    this.SqlCmd+=((DbKeyItem)alFieldItems[alFieldItems.Count-1]).fieldName;
    this.SqlCmd+="=";

    this.SqlCmd+="@para";
    this.SqlCmd+=(alFieldItems.Count-1).ToString();


    if(this.ConditionExpress!=string.Empty)
    {
     this.SqlCmd=this.SqlCmd+" where "+this.ConditionExpress;
    }
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    int effectedLines=this.cmd.ExecuteNonQuery();
    return effectedLines;
   }

   /// <summary>
   /// 执行SqlCmd中的SQL语句,参数由AddSqlCmdParameters指定,与ConditionExpress无关。
   /// </summary>
   /// <returns>返回此次操作所影响的数据行数。</returns>
   public int ExecuteSqlNonQuery()
   {
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    return cmd.ExecuteNonQuery();
   }
   /// <summary>
   /// 获取指定表,指定列,指定条件的第一个符合条件的值。
   /// </summary>
   /// <param name="_tableName">表名称。</param>
   /// <param name="_fieldName">字段名称。</param>
   /// <returns>获取的值。如果为空则返回null。</returns>
   public object GetValue(string _tableName,string _fieldName)
   {
    this.tableName=_tableName;
    this.fieldName=_fieldName;
    this.SqlCmd="select "+this.fieldName+" from "+this.tableName;
    if(this.ConditionExpress!=string.Empty)
    {
     this.SqlCmd=this.SqlCmd+" where "+this.ConditionExpress;
    }
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    return cmd.ExecuteScalar();
   }
   /// <summary>
   /// 根据当前指定的SqlCmd获取DataTable。如果ConditionExpress不为空则会将其清空,所以条件表达式需要包含在SqlCmd中。
   /// </summary>
   /// <returns>返回查询结果DataTable。</returns>
   public System.Data.DataTable GetDataTable()
   {
    System.Data.DataSet ds=this.GetDataSet();
    return ds.Tables[0];
   }
   /// <summary>
   /// 根据当前指定的SqlCmd获取DataSet。如果ConditionExpress不为空则会将其清空,所以条件表达式需要包含在SqlCmd中。
   /// </summary>
   /// <returns>返回查询结果DataSet。</returns>
   public System.Data.DataSet GetDataSet()
   {
    this.alConditionParameters.Clear();
    this.ConditionExpress=string.Empty;
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    System.Data.DataSet ds=new System.Data.DataSet();
    this.da.SelectCommand=this.cmd;
    this.da.Fill(ds);
    return ds;
   }
   /// <summary>
   /// 对指定表,指定字段执行加一计数,返回计数后的值。条件由ConditionExpress指定。
   /// </summary>
   /// <param name="_tableName">表名称。</param>
   /// <param name="_fieldName">字段名称。</param>
   /// <returns>返回计数后的值。</returns>
   public int Count(string _tableName,string _fieldName)
   {
    this.tableName=_tableName;
    this.fieldName=_fieldName;
    int count=Convert.ToInt32(this.GetValue(this.tableName,this.fieldName));
    count++;
    this.cmd.Parameters.Clear();
    this.cmd.CommandText=string.Empty;
    this.AddFieldItem(_fieldName,count);
    this.Update(this.tableName);
    return count;
   }

   /// <summary>
   /// 对指定表,指定字段执行减一计数,返回计数后的值。条件由ConditionExpress指定。
   /// </summary>
   /// <param name="_tableName">表名称。</param>
   /// <param name="_fieldName">字段名称。</param>
   /// <returns>返回计数后的值。</returns>
   public int Substract(string _tableName,string _fieldName)
   {
    this.tableName=_tableName;
    this.fieldName=_fieldName;
    int count=Convert.ToInt32(this.GetValue(this.tableName,this.fieldName));
    if(count>0)count--;
    this.cmd.Parameters.Clear();
    this.cmd.CommandText=string.Empty;
    this.AddFieldItem(_fieldName,count);
    this.Update(this.tableName);
    return count;
   }

   /// <summary>
   /// 根据ConditionExpress指定的条件在指定表中删除记录。返回删除的记录数。
   /// </summary>
   /// <param name="_tableName">指定的表名称。</param>
   /// <returns>返回删除的记录数。</returns>
   public int Delete(string _tableName)
   {
    this.tableName=_tableName;
    this.SqlCmd="delete from "+this.tableName;
    if(this.ConditionExpress!=string.Empty)
    {
     this.SqlCmd=this.SqlCmd+" where "+this.ConditionExpress;
    }
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    return cmd.ExecuteNonQuery();
   }
            /// <summary>
            /// 函数sendMsg需要 __Receive接受者 如果是系统则为 admin 否则为手机号码
            /// </summary>
            /// <param name="_PHONE">手机号码</param>
            /// <param name="_KeyWorld">关键字</param>
            /// <param name="_INFO">信息的基本内容</param>
            /// <param name="_Receive">接受者</param>
            /// <returns></returns>
            public bool SendMsg(string _PHONE, string _KeyWorld, string _INFO, string _Receive)
            {
                bool SendOk;
                if (_PHONE != null || _KeyWorld != null)
                {
                    this.Reset();
                    this.AddFieldItem("PHONE", _PHONE);
                    this.AddFieldItem("KeyWorld", _KeyWorld);
                    this.AddFieldItem("INFO", _INFO);
                    this.AddFieldItem("Receive", _Receive);
                    this.Insert("smsRawRecv").ToString();
                    SendOk = true;
                }
                else
                {
                    SendOk = false;
                   
                }
                return SendOk;
            }
            /// <summary>
            ///
            /// </summary>
            /// <param name="_PHONE"></param>
            /// <param name="_KeyWorld"></param>
            /// <param name="_INFO"></param>
            /// <param name="_Receive"></param>
            /// <returns></returns>
             //public bool Received(string _PHONE, string _KeyWorld, string _INFO, string _Receive)
             //{
             //    bool Received, SendOk;
             //    if (SendOk)
             //    {
             //        if (_PHONE != null || _KeyWorld != null)
             //        {
             //            this.Reset();
             //            this.AddFieldItem("PHONE", _PHONE);
             //            this.AddFieldItem("KeyWorld", _KeyWorld);
             //            this.AddFieldItem("INFO", _INFO);
             //            this.AddFieldItem("Receive", _Receive);
             //            this.Insert("smsSended").ToString();
             //            Received = true;
             //        }
             //        else
             //        {
             //            Received = false;
             //        }
             //    }
             //    else
             //    {
             //        Received = false;
             //    }
             //}
   /// <summary>
   /// 审核函数。将指定表,指定字段的值进行翻转,如:1->0或0->1。条件由ConditionExpress指定。
   /// </summary>
   /// <param name="_tableName">表名称。</param>
   /// <param name="_fieldName">字段名称。</param>
   /// <returns>返回影响的行数。</returns>
   public int Audit(string _tableName,string _fieldName)
   {
    this.tableName=_tableName;
    this.fieldName=_fieldName;
    this.SqlCmd="update "+this.tableName+" set "+this.fieldName+"=1-"+this.fieldName;
    if(this.ConditionExpress!=string.Empty)
    {
     this.SqlCmd=this.SqlCmd+" where "+this.ConditionExpress;
    }
    this.cmd.CommandText=this.SqlCmd;
    this.GenParameters();
    return cmd.ExecuteNonQuery();
   }

   /// <summary>
   /// 释放资源
   /// </summary>
   public void Dispose()
   {
    conn.Close();
   }
  
  }

  /// <summary>
  /// 数据表中的字段属性,包括字段名,字段值。
  /// 常用于保存要提交的数据。
  /// </summary>
  public class DbKeyItem
  {
   /// <summary>
   /// 构造函数。
   /// </summary>
   /// <param name="_fieldName">字段名称。</param>
   /// <param name="_fieldValue">字段值。</param>
   public DbKeyItem(string _fieldName,object _fieldValue)
   {
    this.fieldName=_fieldName;
    this.fieldValue=_fieldValue.ToString();
   }
   /// <summary>
   /// 字段名称。
   /// </summary>
   public string fieldName;
   /// <summary>
   /// 字段值。
   /// </summary>
   public string fieldValue;
  }
 }

posted @ 2007-07-27 11:09 华梦行 阅读(333) | 评论 (0)编辑 收藏
用了这么久的PHP,今天才知道原来PHP对函数名、类名大小写不敏感。我一直都以为是跟变量名一样大小写敏感的。爆汗一下!!!,今天才发现PHP原来对函数名类名大小写不敏感

NULL 类型只有一个值,就是大小写敏感的关键字 NULL
posted @ 2007-07-25 16:10 华梦行 阅读(279) | 评论 (0)编辑 收藏
端口冲突问题,开机后便宣布某个端口归某个应用程序所有
posted @ 2007-07-25 15:55 华梦行 阅读(92) | 评论 (0)编辑 收藏

1下载 apatche http server,下php 安装程序, 
2. 设置环境变量, class pass  php安装路径
3. 设置apatche的根路径 doc_root ="C:\Program Files\Apache Software Foundation\Apache2.2\htdocs"

posted @ 2007-07-25 15:54 华梦行 阅读(97) | 评论 (0)编辑 收藏

----------厚厚发表于 2006年06月27日

网络上很多关于JAVA对Oracle中BLOB、CLOB类型字段的操作说明,有的不够全面,有的不够准确,甚至有的简直就是胡说八道。最近的项目正巧用到了这方面的知识,在这里做个总结。
环境:
Database: Oracle 9i
App Server: BEA Weblogic 8.14
表结构:
CREATE TABLE TESTBLOB (ID Int, NAME Varchar2(20), BLOBATTR Blob)
CREATE TABLE TESTBLOB (ID Int, NAME Varchar2(20), CLOBATTR Clob)
JAVA可以通过JDBC,也可以通过JNDI访问并操作数据库,这两种方式的具体操作存在着一些差异,由于通过App Server的数据库连接池JNDI获得的数据库连接提供的java.sql.Blob和java.sql.Clob实现类与JDBC方式提供的不同,因此在入库操作的时候需要分别对待;出库操作没有这种差异,因此不用单独对待。

一、BLOB操作
1、入库
(1)JDBC方式
//通过JDBC获得数据库连接
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象empty_blob()
st.executeUpdate("insert into TESTBLOB (ID, NAME, BLOBATTR) values (1, "thename", empty_blob())");
//锁定数据行进行更新,注意“for update”语句
ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1 for update");
if (rs.next())
{
//得到java.sql.Blob对象后强制转换为oracle.sql.BLOB
oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBATTR");
OutputStream outStream = blob.getBinaryOutputStream();
//data是传入的byte数组,定义:byte[] data
outStream.write(data, 0, data.length);
}
outStream.flush();
outStream.close();
con.commit();
con.close();
(2)JNDI方式
//通过JNDI获得数据库连接
Context context = new InitialContext();
ds = (DataSource) context.lookup("ORA_JNDI");
Connection con = ds.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象empty_blob()
st.executeUpdate("insert into TESTBLOB (ID, NAME, BLOBATTR) values (1, "thename", empty_blob())");
//锁定数据行进行更新,注意“for update”语句
ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1 for update");
if (rs.next())
{
//得到java.sql.Blob对象后强制转换为weblogic.jdbc.vendor.oracle.OracleThinBlob(不同的App Server对应的可能会不同)
weblogic.jdbc.vendor.oracle.OracleThinBlob blob = (weblogic.jdbc.vendor.oracle.OracleThinBlob) rs.getBlob("BLOBATTR");
OutputStream outStream = blob.getBinaryOutputStream();
//data是传入的byte数组,定义:byte[] data
outStream.write(data, 0, data.length);
}
outStream.flush();
outStream.close();
con.commit();
con.close();
2、出库
//获得数据库连接
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//不需要“for update”
ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1");
if (rs.next())
{
java.sql.Blob blob = rs.getBlob("BLOBATTR");
InputStream inStream = blob.getBinaryStream();
//data是读出并需要返回的数据,类型是byte[]
data = new byte[input.available()];
inStream.read(data);
inStream.close();
}
inStream.close();
con.commit();
con.close();
二、CLOB操作
1、入库
(1)JDBC方式
//通过JDBC获得数据库连接
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象empty_clob()
st.executeUpdate("insert into TESTCLOB (ID, NAME, CLOBATTR) values (1, "thename", empty_clob())");
//锁定数据行进行更新,注意“for update”语句
ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1 for update");
if (rs.next())
{
//得到java.sql.Clob对象后强制转换为oracle.sql.CLOB
oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBATTR");
Writer outStream = clob.getCharacterOutputStream();
//data是传入的字符串,定义:String data
char[] c = data.toCharArray();
outStream.write(c, 0, c.length);
}
outStream.flush();
outStream.close();
con.commit();
con.close();
(2)JNDI方式
//通过JNDI获得数据库连接
Context context = new InitialContext();
ds = (DataSource) context.lookup("ORA_JNDI");
Connection con = ds.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象empty_clob()
st.executeUpdate("insert into TESTCLOB (ID, NAME, CLOBATTR) values (1, "thename", empty_clob())");
//锁定数据行进行更新,注意“for update”语句
ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1 for update");
if (rs.next())
{
//得到java.sql.Clob对象后强制转换为weblogic.jdbc.vendor.oracle.OracleThinClob(不同的App Server对应的可能会不同)
weblogic.jdbc.vendor.oracle.OracleThinClob clob = (weblogic.jdbc.vendor.oracle.OracleThinClob) rs.getClob("CLOBATTR");
Writer outStream = clob.getCharacterOutputStream();
//data是传入的字符串,定义:String data
char[] c = data.toCharArray();
outStream.write(c, 0, c.length);
}
outStream.flush();
outStream.close();
con.commit();
con.close();
2、出库
//获得数据库连接
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//不需要“for update”
ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1");
if (rs.next())
{
java.sql.Clob clob = rs.getClob("CLOBATTR");
Reader inStream = clob.getCharacterStream();
char[] c = new char[(int) clob.length()];
inStream.read(c);
//data是读出并需要返回的数据,类型是String
data = new String(c);
inStream.close();
}
inStream.close();
con.commit();
con.close();
需要注意的地方:
1、java.sql.Blob、oracle.sql.BLOB、weblogic.jdbc.vendor.oracle.OracleThinBlob几种类型的区别
2、java.sql.Clob、oracle.sql.CLOB、weblogic.jdbc.vendor.oracle.OracleThinClob几种类型的区别

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=839235


posted @ 2007-07-24 16:43 华梦行 阅读(664) | 评论 (0)编辑 收藏
netbeans 用户下的 debug*.property文件里
posted @ 2007-07-23 18:27 华梦行 阅读(131) | 评论 (0)编辑 收藏

<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<html>
    <script language="javascript">


//test function with post method
function RequestByPost(value)
{
var data;
data = '<?xml version="1.0" encoding="utf-8"?>';
data = data + '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">';
data = data + '<soapenv:Body>';
data = data + '<ns1:getUser xmlns:ns1="http://ss/">';
data = data + '<Name>'+"ffff"+'</Name>';
data = data + '</ns1:getUser>';
data = data + '</soapenv:Body>';
data = data + '</soapenv:Envelope>';

var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
var URL="http://localhost:8080/myPj/SayHelloTo?wsdl";
xmlhttp.Open("POST",URL, false);
xmlhttp.SetRequestHeader ("Content-Type","text/xml; charset=UTF-8");
xmlhttp.SetRequestHeader ("SOAPAction","http://ss/SayHelloTo");
alert(data);
xmlhttp.Send(data);
alert( xmlhttp.responseText);
document.getElementById('mm').value=xmlhttp.responseText;
}

    </script>
    <title>
        Call webservice with javascript and xmlhttp.
    </title>
    <body>
       
        <div id="mm">
        <input type="button" value="CallWebserviceByGet" onClick="RequestByGet(null)">
        <input type="button" value="CallWebserviceByPost" onClick="RequestByPost('Zach')">
        <input id="mm" type="text"/>
    </body>
</html>

 

posted @ 2007-07-17 16:18 华梦行 阅读(156) | 评论 (0)编辑 收藏
res://msxml.dll/defaultss.xsl
posted @ 2007-07-13 08:24 华梦行 阅读(102) | 评论 (0)编辑 收藏
Result:
hello null
<?xml version="1.0" ?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://ss/"><soapenv:Body><ns1:sayHelloResponse><return>hello null</return></ns1:sayHelloResponse></soapenv:Body></soapenv:Envelope>
posted @ 2007-07-06 13:10 华梦行 阅读(99) | 评论 (0)编辑 收藏

nodeType 属性

KingCMS官方网站 Microsoft 2006-1-31 21:18:32
作 用
辨识节点的DOM 型态。  
基本语法
numNodeType = xmlDocNode.nodeType ;
 
说 明

此属性只读且传回一个数值。

有效的数值符合以下的型别:
1-ELEMENT
2-ATTRIBUTE
3-TEXT
4-CDATA
5-ENTITY REFERENCE
6-ENTITY
7-PI (processing instruction)
8-COMMENT
9-DOCUMENT
10-DOCUMENT TYPE
11-DOCUMENT FRAGMENT
12-NOTATION
 
 
范 例
numNodeType = xmlDoc.documentElement.nodeType;
alert(numNodeType);
posted @ 2007-07-06 12:58 华梦行 阅读(126) | 评论 (0)编辑 收藏
type:表示所有的数据类型
Message: 指明被调用的函数的参数
Port:    指明服务的具体内容,包括输入输出
Binding:  服务所绑定的协议

addTwo Method invocation



Method parameter(s)

TypeValue
int55
int676

Method returned

int : "731"

SOAP Request


<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header/>
    <S:Body>
        <ns2:addTwo xmlns:ns2="http://my/">
            <mm>55</mm>
            <gg>676</gg>
        </ns2:addTwo>
    </S:Body>
</S:Envelope>

SOAP Response


<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:addTwoResponse xmlns:ns2="http://my/">
            <return>731</return>
        </ns2:addTwoResponse>
    </S:Body>
</S:Envelope>


<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.2-hudson-112-M1. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.2-hudson-112-M1. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://my/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://my/" name="firstService">
<types>
<xsd:schema>
<xsd:import namespace="http://my/" schemaLocation="http://localhost:8080/ssServ/firstService?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="usrLogin">
<part name="parameters" element="tns:usrLogin"></part>
</message>
<message name="usrLoginResponse">
<part name="parameters" element="tns:usrLoginResponse"></part>
</message>
<message name="addTwo">
<part name="parameters" element="tns:addTwo"></part>
</message>
<message name="addTwoResponse">
<part name="parameters" element="tns:addTwoResponse"></part>
</message>
<message name="userLogin">
<part name="parameters" element="tns:userLogin"></part>
</message>
<message name="userLoginResponse">
<part name="parameters" element="tns:userLoginResponse"></part>
</message>
<portType name="first">
<operation name="usrLogin">
<input message="tns:usrLogin"></input>
<output message="tns:usrLoginResponse"></output>
</operation>
<operation name="addTwo">
<input message="tns:addTwo"></input>
<output message="tns:addTwoResponse"></output>
</operation>
<operation name="userLogin">
<input message="tns:userLogin"></input>
<output message="tns:userLoginResponse"></output>
</operation>
</portType>
<binding name="firstPortBinding" type="tns:first">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding>
<operation name="usrLogin">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
<operation name="addTwo">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
<operation name="userLogin">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
</binding>
<service name="firstService">
<port name="firstPort" binding="tns:firstPortBinding">
<soap:address location="http://localhost:8080/ssServ/firstService"></soap:address>
</port>
</service>
</definitions>

从本质上说:客户端发一个请求即SOAP 请求头,到指定的web service地址wsdl,然后经过webservice的处理之后,返回一个 SOAP 相应, 然后再在客户端解析他们
posted @ 2007-07-05 18:27 华梦行 阅读(165) | 评论 (0)编辑 收藏

程序员每天该做的事
1、总结自己一天任务的完成情况

最好的方式是写工作日志,把自己今天完成了什么事情,遇见了什么问题都记录下来,日后翻看好处多多

2、考虑自己明天应该做的主要工作

把明天要做的事情列出来,并按照优先级排列,第二天应该把自己效率最高的时间分配给最重要的工作

3、考虑自己一天工作中失误的地方,并想出避免下一次再犯的方法

出错不要紧,最重要的是不要重复犯相同的错误,那是愚蠢

4、考虑自己一天工作完成的质量和效率能否还能提高

一天只提高1%,365天你的效率就能提高多少倍你知道吗? (1+0.01)^365 = 37 倍

posted @ 2007-07-05 11:33 华梦行 阅读(123) | 评论 (0)编辑 收藏

function hel(){
 alert("good");

Event.observe(document, 'mousedown', hel.bindAsEventListener());


  Browser: {
    IE:     !!(window.attachEvent && !window.opera), //判断是不是IE  转换为boolean
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
  },

posted @ 2007-07-03 11:13 华梦行 阅读(146) | 评论 (0)编辑 收藏

AnnotationProcessor      Annotation 处理的接口,实现类是DefaltAnnotationProcessor :

protected static void lookupFieldResource (javax.naming.Context context, java.lang.Object instance, java.lang.reflect.Field field, java.lang.String name)
          Inject resources in specified field.
protected static void lookupMethodResource (javax.naming.Context context, java.lang.Object instance, java.lang.reflect.Method method, java.lang.String name)
          Inject resources in specified method.
 void postConstruct (java.lang.Object instance)
          Call postConstruct method on the specified instance.
 void preDestroy (java.lang.Object instance)
          Call preDestroy method on the specified instance.
 void processAnnotations (java.lang.Object instance)
          Inject resources in specified instance


public class DefaultAnnotationProcessor implements AnnotationProcessor {
   
    protected javax.naming.Context context = null;
   
    public DefaultAnnotationProcessor(javax.naming.Context context) {
        this.context = context;
    }


    /**
     * Call postConstruct method on the specified instance.
     */
    public void postConstruct(Object instance)
        throws IllegalAccessException, InvocationTargetException {
       
        Method[] methods = instance.getClass().getDeclaredMethods();
        Method postConstruct = null;
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].isAnnotationPresent(PostConstruct.class)) {
                if ((postConstruct != null)
                        || (methods[i].getParameterTypes().length != 0)
                        || (Modifier.isStatic(methods[i].getModifiers()))
                        || (methods[i].getExceptionTypes().length > 0)
                        || (!methods[i].getReturnType().getName().equals("void"))) {
                    throw new IllegalArgumentException("Invalid PostConstruct annotation");
                }
                postConstruct = methods[i];
            }
        }

        // At the end the postconstruct annotated
        // method is invoked
        if (postConstruct != null) {
            boolean accessibility = postConstruct.isAccessible();
            postConstruct.setAccessible(true);
            postConstruct.invoke(instance);
            postConstruct.setAccessible(accessibility);
        }
       
    }
   
   
    /**
     * Call preDestroy method on the specified instance.
     */
    public void preDestroy(Object instance)
        throws IllegalAccessException, InvocationTargetException {
       
        Method[] methods = instance.getClass().getDeclaredMethods();
        Method preDestroy = null;
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].isAnnotationPresent(PreDestroy.class)) {
                if ((preDestroy != null)
                        || (methods[i].getParameterTypes().length != 0)
                        || (Modifier.isStatic(methods[i].getModifiers()))
                        || (methods[i].getExceptionTypes().length > 0)
                        || (!methods[i].getReturnType().getName().equals("void"))) {
                    throw new IllegalArgumentException("Invalid PreDestroy annotation");
                }
                preDestroy = methods[i];
            }
        }

        // At the end the postconstruct annotated
        // method is invoked
        if (preDestroy != null) {
            boolean accessibility = preDestroy.isAccessible();
            preDestroy.setAccessible(true);
            preDestroy.invoke(instance);
            preDestroy.setAccessible(accessibility);
        }
       
    }
   
   
    /**
     * Inject resources in specified instance.
     */
    public void processAnnotations(Object instance)
        throws IllegalAccessException, InvocationTargetException, NamingException {
       
        if (context == null) {
            // No resource injection
            return;
        }
       
        // Initialize fields annotations
        Field[] fields = instance.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].isAnnotationPresent(Resource.class)) {
                Resource annotation = (Resource) fields[i].getAnnotation(Resource.class);
                lookupFieldResource(context, instance, fields[i], annotation.name());
            }
            if (fields[i].isAnnotationPresent(EJB.class)) {
                EJB annotation = (EJB) fields[i].getAnnotation(EJB.class);
                lookupFieldResource(context, instance, fields[i], annotation.name());
            }
            if (fields[i].isAnnotationPresent(WebServiceRef.class)) {
                WebServiceRef annotation =
                    (WebServiceRef) fields[i].getAnnotation(WebServiceRef.class);
                lookupFieldResource(context, instance, fields[i], annotation.name());
            }
            if (fields[i].isAnnotationPresent(PersistenceContext.class)) {
                PersistenceContext annotation =
                    (PersistenceContext) fields[i].getAnnotation(PersistenceContext.class);
                lookupFieldResource(context, instance, fields[i], annotation.name());
            }
            if (fields[i].isAnnotationPresent(PersistenceUnit.class)) {
                PersistenceUnit annotation =
                    (PersistenceUnit) fields[i].getAnnotation(PersistenceUnit.class);
                lookupFieldResource(context, instance, fields[i], annotation.name());
            }
        }
       
        // Initialize methods annotations
        Method[] methods = instance.getClass().getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].isAnnotationPresent(Resource.class)) {
                Resource annotation = (Resource) methods[i].getAnnotation(Resource.class);
                lookupMethodResource(context, instance, methods[i], annotation.name());
            }
            if (methods[i].isAnnotationPresent(EJB.class)) {
                EJB annotation = (EJB) methods[i].getAnnotation(EJB.class);
                lookupMethodResource(context, instance, methods[i], annotation.name());
            }
            if (methods[i].isAnnotationPresent(WebServiceRef.class)) {
                WebServiceRef annotation =
                    (WebServiceRef) methods[i].getAnnotation(WebServiceRef.class);
                lookupMethodResource(context, instance, methods[i], annotation.name());
            }
            if (methods[i].isAnnotationPresent(PersistenceContext.class)) {
                PersistenceContext annotation =
                    (PersistenceContext) methods[i].getAnnotation(PersistenceContext.class);
                lookupMethodResource(context, instance, methods[i], annotation.name());
            }
            if (methods[i].isAnnotationPresent(PersistenceUnit.class)) {
                PersistenceUnit annotation =
                    (PersistenceUnit) methods[i].getAnnotation(PersistenceUnit.class);
                lookupMethodResource(context, instance, methods[i], annotation.name());
            }
        }

    }
   
   
    /**
     * Inject resources in specified field.
     */
    protected static void lookupFieldResource(javax.naming.Context context,
            Object instance, Field field, String name)
        throws NamingException, IllegalAccessException {
   
        Object lookedupResource = null;
        boolean accessibility = false;
       
        if ((name != null) &&
                (name.length() > 0)) {
            lookedupResource = context.lookup(name);
        } else {
            lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName());
        }
       
        accessibility = field.isAccessible();
        field.setAccessible(true);
        field.set(instance, lookedupResource);
        field.setAccessible(accessibility);
    }


    /**
     * Inject resources in specified method.
     */
    protected static void lookupMethodResource(javax.naming.Context context,
            Object instance, Method method, String name)
        throws NamingException, IllegalAccessException, InvocationTargetException {
       
        if (!method.getName().startsWith("set")
                || method.getParameterTypes().length != 1
                || !method.getReturnType().getName().equals("void")) {
            throw new IllegalArgumentException("Invalid method resource injection annotation");
        }
       
        Object lookedupResource = null;
        boolean accessibility = false;
       
        if ((name != null) &&
                (name.length() > 0)) {
            lookedupResource = context.lookup(name);
        } else {
            lookedupResource =
                context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3));
        }
       
        accessibility = method.isAccessible();
        method.setAccessible(true);
        method.invoke(instance, lookedupResource);
        method.setAccessible(accessibility);
    }
   

}

posted @ 2007-06-28 15:26 华梦行 阅读(662) | 评论 (0)编辑 收藏
http://webfx.eae.net/
posted @ 2007-06-28 12:54 华梦行 阅读(117) | 评论 (0)编辑 收藏

  import java.lang.reflect.*;
public class RunTest {
    public static void main(String[] args) throws Exception {
       
        int passed = 0, failed = 0;
        for (Method m : Class.forName("Foo").getMethods()) {
            if (m.isAnnotationPresent(Test.class)) {
                try {
                    m.invoke(null);
                   
                    passed++;
                } catch (Throwable ex) {
                    System.out.printf("Test %s failed: %s %n", m, ex.getCause());
                    failed++;
                }
            }
        }
        System.out.printf("Passed: %d, Failed %d%n", passed, failed);
    }
}

public class Foo {
    @Test public static void m1() {
    System.out.println("m1 SUcsessful");
    }
    public static void m2() { }
    @Test public static void m3() {
        System.out.println("m3 Fails");
        throw new RuntimeException("Boom");
    }
    public static void m4() { }
    @Test public static void m5() { }
    public static void m6() { }
    @Test public static void m7() {
        throw new RuntimeException("Crash");        }
   
    public static void m8() { }
}


import java.lang.annotation.*;
/*
 * Test.java
 *
 * Created on 2007年6月28日, 上午8:52
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

/**
 *
 * @author ljl
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
   
   
   
}

posted @ 2007-06-28 09:24 华梦行 阅读(297) | 评论 (0)编辑 收藏