使用 RSA 非对称加密保证数据不被篡改 java 例子代码

摘要:
(不加密原始数据的原因是原始数据太大,加密和解密速度太慢,非对称加密也不是很慢。摘要函数中存在雪崩效应,原始文本的任何更改都会导致摘要发生剧烈变化。)注意:因为使用了json排序。因此,这可能是由于不同的数据类型导致签名验证失败。注2:该方法侧重于数据不被篡改,而不是确保数据不被泄露。如果需要确保数据不泄漏,则应使用对方的公钥对请求和响应数据进行加密,对方应在收到请求后使用自己的私钥进行解密。

原理: 对原始数据 生成有序的json 字符串,然后取 摘要,然后 对摘要 进项 分对称加密。( 不对原数据加密是应为 原数据太大,加解密速度太慢,非对称加密都不 挺慢的。在摘要函数具有雪崩效应 ,原文发生点点的改变都会引起 摘要的剧烈变化 )

注意事项:因为使用的 对json 排序。而不是 传统的 from 表单方式。虽然 让请求响应都支持了json 变得统一,但是,这里又一个明显的容易缺陷。json 的 value 中 字符串带有 引号,数字类型没有引号。所以 这可能 应为 数据类型不一样造成验签失败。所以应该 全部使用 字符串。如果都有 引号就没有这种问题了。

备注:这个适用于 2个 系统之间 的数据交流。2 系统之间的数据交流最明显的特点就是 没有登录, 请求是无状态的,只能 通过请求参数来识别 请求是否合法。 这个 方式安全的 大前提 是自己的私钥 永远只有自己知道。

备注2: 这种方式侧重是数据不被篡改,而不是 保证数据不被泄露。 如果需要保证数据不被泄露 ,那么 发送请求和响应数据 的时候应该使用对方的公钥加密,对方收到请求以后使用自己的私钥解密。而且 加密的 原文 应该是整个 原始字符串,而不是 原文的摘要。

 目录结构:

使用 RSA 非对称加密保证数据不被篡改 java 例子代码第1张

RSAUtils.java: 生成公私玥,加密解密 的工具类

package com.sbl.ebuygou.trading.biz.sign;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
 
public class RSAUtils {
 
    public static final String CHARSET = "UTF-8";
    public static final String RSA_ALGORITHM = "RSA";
 
 
    public static Map<String, String> createKeys(int keySize){
        //为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try{
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        }catch(NoSuchAlgorithmException e){
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }
 
        //初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        //生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
        //得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<String, String>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);
 
        return keyPairMap;
    }
 
    /**
     * 得到公钥
     * @param publicKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }
 
    /**
     * 得到私钥
     * @param privateKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }
 
    /**
     * 公钥加密
     * @param data
     * @param publicKey
     * @return
     */
    public static String publicEncrypt(String data, RSAPublicKey publicKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        }catch(Exception e){
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }
 
    /**
     * 私钥解密
     * @param data
     * @param privateKey
     * @return
     */
 
    public static String privateDecrypt(String data, RSAPrivateKey privateKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }
 
    /**
     * 私钥加密
     * @param data
     * @param privateKey
     * @return
     */
 
    public static String privateEncrypt(String data, RSAPrivateKey privateKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
        }catch(Exception e){
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }
 
    /**
     * 公钥解密
     * @param data
     * @param publicKey
     * @return
     */
 
    public static String publicDecrypt(String data, RSAPublicKey publicKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }
 
    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
        int maxBlock = 0;
        if(opmode == Cipher.DECRYPT_MODE){
            maxBlock = keySize / 8;
        }else{
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try{
            while(datas.length > offSet){
                if(datas.length-offSet > maxBlock){
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                }else{
                    buff = cipher.doFinal(datas, offSet, datas.length-offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        }catch(Exception e){
            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }
 
}

  

SignUtil.java : 签名和核心 工具类

package com.sbl.ebuygou.trading.biz.sign;

import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;

import org.apache.commons.codec.digest.DigestUtils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sbl.ebuygou.trading.biz.sign.pram.QueryOrderReq;

/**
 * 签名工具
 * 
 * @author ZHANGYUKUN
 *
 */
public class SignUtil {

	/**
	 * 生成签名
	 * 
	 * @param sortData
	 *            原始加密字符串
	 * @param privateKeyStr
	 *            私钥字符串
	 * @return 加密后的 对象
	 */
	public static <T extends SignParam> T getSignObject(T signParam, String privateKeyStr) {
		String sign = getSign(signParam, privateKeyStr);
		signParam.setSign(sign);

		return signParam;
	}

	/**
	 * 生成签名
	 * 
	 * @param sortData
	 *            原始加密字符串
	 * @param privateKeyStr
	 *            私钥字符串
	 * @return 加密后的 sign字符串
	 */
	public static <T extends SignParam> String getSign(T signParam, String privateKeyStr) {
		String sortData = getSortData(signParam);

		RSAPrivateKey privateKey = null;
		try {
			privateKey = RSAUtils.getPrivateKey(privateKeyStr);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
			e.printStackTrace();
		}

		String sortDataMd5 = DigestUtils.md5Hex(sortData);

		return RSAUtils.privateEncrypt(sortDataMd5, privateKey);
	}

	/**
	 * 核对签名
	 * 
	 * @param resultStr
	 *            带有 sign 的json 字符串
	 * @param publicKeyStr
	 *            公钥字符串
	 * @return
	 */
	public static <T extends SignParam > boolean checkSign(String resultStr,String publicKeyStr , TypeReference< T >  typeReference) {
		Content content = SignUtil.getSortData(resultStr,  typeReference );
		return checkSign(content.getSortData(), content.getSign(),publicKeyStr);
	}

	/**
	 * 核对签名
	 * 
	 * @param sortData
	 *            原始加密字符串
	 * @param sige
	 *            签名字符串
	 * @param publicKeyStr
	 *            公钥字符串
	 * 
	 * @return true 验签成功 ,false 验签失败
	 */
	public static boolean checkSign(String sortData, String sige, String publicKeyStr) {
		RSAPublicKey publicKey = null;
		try {
			publicKey = RSAUtils.getPublicKey(publicKeyStr);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
			e.printStackTrace();
		}
		String data = null;
		try {
			data = RSAUtils.publicDecrypt(sige, publicKey);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

		String sortDataMd5 = DigestUtils.md5Hex(sortData);
		if (data.equals(sortDataMd5)) {
			return true;
		}
		return false;
	}

	/**
	 * 得到排序的 用于签名的 原始 json 字符串
	 * 
	 * @param signParam
	 *            可以签名的对象
	 * @return 排序了的 原始 加密字符串
	 */
	public static <T extends SignParam> String getSortData(T signParam) {
		signParam.setSign(null);
		return JSONObject.toJSONString(signParam, SerializerFeature.SortField);
	}

	/**
	 * 得到排序的 用于签名的 原始 json 字符串
	 * 
	 * @param resultStr
	 *            带有 签名的 原始字符串
	 * @return Content 里面带有 原始签名字符串 和签名
	 */
	public static <T extends SignParam> Content getSortData(String resultStr, TypeReference<T> typeReference) {
		T signResult = JSONObject.parseObject(resultStr, typeReference);

		String sign = signResult.getSign();
		signResult.setSign(null);
		String sortData = getSortData(signResult);

		Content content = new Content();
		content.setSign(sign);
		content.setSortData(sortData);

		return content;
	}

}

  

Content.java:  存放 原始签名 json 字符串和 签名 的 辅助类

package com.sbl.ebuygou.trading.biz.sign;

public class Content {
	
	/**
	 * 签名
	 */
	private String sign;
	
	/**
	 * 原始的 签名 json 字符串
	 */
	private String sortData;
	
	public String getSign() {
		return sign;
	}
	public void setSign(String sign) {
		this.sign = sign;
	}
	public String getSortData() {
		return sortData;
	}
	public void setSortData(String sortData) {
		this.sortData = sortData;
	}

}

  

RSAKey.java: 存放 公私玥的地方( 我这里省事就只用了一组公私玥,正常应该2 对 , 各自 持有自己的私钥,公钥 ,和对方的 公钥)

package com.sbl.ebuygou.trading.biz.sign;

public class RSAKey {

	public static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCWLw2S_98GLHAe3ZvVCh3rdJ36A0BHwLehAK5j1378peDDOdz1oIsHyprRsGvnXh9aWZAhKemIUkimK-WtbD4VVmOsfayoSL17c_CZIL7Yd6tfSBiobbXb4m-bt0wGZRzh0L7IMpwIukzmWcyo0BNGdEe6CLDb6gvc6IOwJ_JBuQIDAQAB";
	
	public static final String privateKey ="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJYvDZL_3wYscB7dm9UKHet0nfoDQEfAt6EArmPXfvyl4MM53PWgiwfKmtGwa-deH1pZkCEp6YhSSKYr5a1sPhVWY6x9rKhIvXtz8Jkgvth3q19IGKhttdvib5u3TAZlHOHQvsgynAi6TOZZzKjQE0Z0R7oIsNvqC9zog7An8kG5AgMBAAECgYADa0bP1etp5JEY4sqtavGLbrg5_OD1wTls_Or7cuh9L_mR-DtDjEgeAUrNA0sxlT75e5iAaMfcRqNIxS8RZ6lyIfhaRlzV2L0baBzL718INpHuc5_zqxX1aFIKScQylX4YAVGwk4AG6NU9rlzNd8wHqH9P7lFQdfsc_cd72CQE0QJBAM8o_hfIUxIHdfNFpvMTkZ9-xEHlDBOaQkjWMu7WCHQ1xiNMR1stSqHLItyG3vk4N3MISAyY9L270dy3E_hR9OsCQQC5l0sZ3L9TB6tibzo2xL39jeOCA7BrrFSThF81KRAujlCgHcKGV64po6YLmjxaX5z77xJOPSyc8YGgppVjH8rrAkEAq_6Q2BYOQk3HdC9EKVT59r49G6ibmjrdBbQxnXI-mp164BuYsu6rpCEP1KB1x90QzIT3rN3hdRXXa7Tk86q3-QJAWCZcLXSEC1PhO2fJJqpb80qpfN9ztDCuG0MMVZuja_l8ohCAjH6o4m4wN-KSN_qh_aeX8kFsJz8uare0zNgU8QJAEZroY4DiiFdIxIA2S5gKDcvZlkl6ePSZzMbPw35wVrE9NqqL7l3S1TfZ9PnAhU70S2IW0ZMM0DdiAX5-zb3t_A";

}

  

SignParam.java:定义的统一的可以签名的对象的抽象(请求对象和响应对象都应该继承这个类 )。

package com.sbl.ebuygou.trading.biz.sign;

/**
 * 带有签名的参数
 * @author ZHANGYUKUN
 *
 */
public abstract class SignParam {
	
	/**
	 * 签名
	 */
	private String sign;
	

	public String getSign() {
		return sign;
	}

	public void setSign(String sign) {
		this.sign = sign;
	}

}

  

上面5 个类是固定的。下面的类根据业务自由拓展.

QueryOrderReq.java : 查询订单请求参数( 不同 的 请求定义不通接请求参数 )

package com.sbl.ebuygou.trading.biz.sign.pram;

import com.sbl.ebuygou.trading.biz.sign.SignParam;

/**
 * 查询订单请求
 * @author ZHANGYUKUN
 *
 */
public class QueryOrderReq extends SignParam {
	
	/**
	 * 订单Id
	 */
	private String orderId;

	public String getOrderId() {
		return orderId;
	}

	public void setOrderId(String orderId) {
		this.orderId = orderId;
	}

	

}

  

SignResult.java:带有签名的 统一返回 ,请求 没有固定格式,为了拓展,返回 固定格式便于对方解析(  备注:请求是多变的,但是响应 都是类似的。 基本都是 有个状态,有个原因 ,有个数据  )。

package com.sbl.ebuygou.trading.biz.sign.pram;

import com.sbl.ebuygou.trading.biz.sign.RSAKey;
import com.sbl.ebuygou.trading.biz.sign.SignParam;
import com.sbl.ebuygou.trading.biz.sign.SignUtil;

/**
 * 签名的结果集
 * 
 * @author ZHANGYUKUN
 *
 * @param <T>
 */
public class SignResult<T> extends SignParam {

	/**
	 * 状态
	 */
	private Status status;
	
	/**
	 * 备注
	 */
	private String  mark;
	
	/**
	 * 数据
	 */
	private T data;


	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public String getMark() {
		return mark;
	}

	public void setMark(String mark) {
		this.mark = mark;
	}
	
	/**
	 * 得到一个成功的结果集
	 * 
	 * @param data 数据
	 * @param privateKeyStr 私钥字符串
	 * @return
	 */
	public static <T> SignResult<T> getSucceedInstance(T data, String privateKeyStr ) {
		SignResult<T> signResult = new SignResult<T>();
		signResult.setMark("成功");
		signResult.setStatus( Status.SUCCEE );
		signResult.setData(data);
		
		signResult = SignUtil.getSignObject(signResult, RSAKey.privateKey );
		
		return signResult;
	}
	
	
	

}

  

Status.java :统一的 响应状态

package com.sbl.ebuygou.trading.biz.sign.pram;

public enum Status {

	SUCCEE("成功"),FAILURE("失败"),OTHER("其他问题");

    private String mark;

    Status(String mark ) {
        this.mark = mark;
    }

    public String getMark() {
        return mark;
    }
}

  

测试类:OrderPublicController.java

package com.sbl.ebuygou.trading.biz.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.sbl.commons.exception.resolver.exception.ParameterErrorException;
import com.sbl.commons.util.BeanUtils;
import com.sbl.ebuygou.platform.api.api.SupplierServiceApi;
import com.sbl.ebuygou.platform.api.api.UserServiceApi;
import com.sbl.ebuygou.trading.biz.bean.in.QueryOrderItemIn;
import com.sbl.ebuygou.trading.biz.bean.out.OrderItemOut;
import com.sbl.ebuygou.trading.biz.bean.out.OrderOut;
import com.sbl.ebuygou.trading.biz.entity.Order;
import com.sbl.ebuygou.trading.biz.service.LogisticsService;
import com.sbl.ebuygou.trading.biz.service.OrderService;
import com.sbl.ebuygou.trading.biz.sign.RSAKey;
import com.sbl.ebuygou.trading.biz.sign.SignUtil;
import com.sbl.ebuygou.trading.biz.sign.pram.QueryOrderReq;
import com.sbl.ebuygou.trading.biz.sign.pram.SignResult;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 订单相关接口
 * 
 * @author ZHANGYUKUN
 *
 */

@Api(tags = "订单相关接口(三方调用)")
@RestController
@RequestMapping("public/order")
public class OrderPublicController {

	@Autowired
	OrderService orderService;

	@Autowired
	LogisticsService logisticsService;

	@Autowired
	SupplierServiceApi supplierServiceApi;

	@Autowired
	UserServiceApi userServiceApi;

	@ApiOperation("测试甲方接受乙方请求,然后验签,并且放回响应乙方签名数据")
	@GetMapping("queryOrderByIdWithOrderItem")
	public SignResult<OrderOut> queryByOrderId(@RequestBody QueryOrderReq queryOrderReq   ) {
		String  resultStr = JSONObject.toJSONString( queryOrderReq );
		
		if(  !SignUtil.checkSign( resultStr  ,RSAKey.publicKey ,new TypeReference< QueryOrderReq >() {} ) ) {
			throw new ParameterErrorException("验签失败");
		}
		
		
		//业务逻辑
		long orderId = Long.valueOf( queryOrderReq.getOrderId() );

		OrderOut orderOut = new OrderOut();
		Order order = orderService.queryOrderById( orderId );

		if (order == null) {
			return null;
		}

		BeanUtils.copyProperties(order, orderOut, true);

		// 关联子订单
		QueryOrderItemIn queryOrderItemIn = new QueryOrderItemIn();
		queryOrderItemIn.setOrderId( orderId );
		orderOut.setOrderItem(BeanUtils.copyToOutList(orderService.queryOrderItemByOrderId(queryOrderItemIn, order.getUserId()), OrderItemOut.class));
		
		
		
		
		return SignResult.getSucceedInstance(orderOut , RSAKey.privateKey  );
	}
	
	
	@ApiOperation("测试乙方验签")
	@GetMapping("checkSign")
	public boolean checkSign(String orderId) {
		SignResult<OrderOut> signResult = t1( orderId );
		
		String  resultStr = JSONObject.toJSONString( signResult );
		return SignUtil.checkSign( resultStr  , RSAKey.publicKey , new TypeReference< SignResult<OrderOut> >() {} );
	}
	
	@ApiOperation("测试乙方发送 签名数据给 甲方")
	@GetMapping("t1")
	public  SignResult<OrderOut> t1(String orderId ) {
		QueryOrderReq queryOrderReq = new QueryOrderReq();
		queryOrderReq.setOrderId(orderId);
		
		return queryByOrderId( SignUtil.getSignObject( queryOrderReq, RSAKey.privateKey ) );
	}
	
	
	




}

  

备注。SignResult<OrderOut> 里面的  OrderOut 我就不上传了。根据自己的业务定义就是了。

免责声明:文章转载自《使用 RSA 非对称加密保证数据不被篡改 java 例子代码》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WebService学习总结(四)——调用第三方提供的webService服务,使用cxf关于深度值的一些需要说明的点下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Ansi,UTF8,Unicode编码(续)

1.三种编码的回顾 Ansi字符串我们最熟悉,英文占一个字节,汉字2个字节,以一个\0结尾,常用于txt文本文件。 Unicode字符串,每个字符(汉字、英文字母)都占2个字节;在VC++的世界里,Microsoft比较鼓励使用Unicode,如wchar_t。 UTF8是Unicode一种压缩形式,英文A在unicode中表示为0x0041,英语中这种存...

DB2把整型转换成制定长度的字符串,前面补0

selecta.auto_id,right(digits(cast(auto_idasbigint)),18)fromT_BZ_DEMO_AREA_APPa; digits必须使用整型参数。 auto_id类型为:small integer :返回5位字符串。large integer :返回10位字符串。big integer :返回19位字符串。...

Matlab读取Excel的数据

matlab读取excel中的数据用的是xlsread()这个函数这句代码跟matlab菜单操作中的file中import再选择excel文件的效果是一样的手动导入的时候它会自动识别文件中有什么类型的数据,数字和字符串被分别读入到两个变量中。比如[A B] = xlsread('1.xmls'); A中存储了这个文件中的数字矩阵,B中存储了字符串矩阵,读取...

Delphi部分函数、命令、属性中文说明

Abort 函数 引起放弃的意外处理Abs 函数 绝对值函数AddExitProc 函数 将一过程添加到运行时库的结束过程表中Addr 函数 返回指定对象的地址AdjustLineBreaks 函数 将给定字符串的行分隔符调整为CR/LF序列Align 属性 使控件位于窗口某部分Alignment 属性 控件标签的文字位置AllocMem 函数 在堆栈上分...

Freemarker常用技巧(一)

1 截取字符串有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度<#if title.content?length lt 8>           <a href>${title.content?default("")}</a>      <#else>    ...

.NET 基础知识

.net程序基本编写、执行流程(c#)       1>编写c#代码,保存为.cs文件。       2>通过csc.exe程序来将.cs文件编译为.net程序集(.exe或.dll)。此时的exe或dll并不是机器码(cpu不可理解)。【>csc /out:c:a.exe c:program.cs】   C:WindowsMicroso...