Java微信二次开发(五)
消息加密
需要到入库:commons-io-2.4.jar,commons-codec-1.9.jar(在官网的Java微信加密demo下)
第一步:访问https://mp.weixin.qq.com/wiki,下载AES加密的示例代码

第二步:新建com.wtz.aes包,把实例代码中的8个AES加密类复制进去,将这些类的包名改为com.wtz.aes,导入库commons-codec-1.9.jar,选上面的Project下的Properties,点击Java Build Path,Libraries,Add Library,选Junit 4,Next,Finish,OK,AES加密导入完成
第三步:找到包com.wtz.util,新建类Parameter.java类,存放参数token,encodingAESKey(随机戳),corpId(AppID),这些在基本配置处可以得到
package com.wtz.util; /**
* @author wangtianze QQ:864620012
* @date 2017年4月21日 下午9:27:50
* <p>version:1.0</p>
* <p>description:参数api</p>
*/
public class Parameter {
//token
public static String token = "wangtianze";
//随机戳
public static String encodingAESKey = "X78dYU3MXpijKArRbiozTRq0jZZnjxxvuB4n8KJwRH1";
//应用AppID
public static String corpId = "wx9621c31e147dfdf9";
}
第四步:找到包com.wtz.util下的MessageUtil.java类,修改parseXml方法
package com.wtz.util; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import com.wtz.message.response.ImageMessage;
import com.wtz.message.response.MusicMessage;
import com.wtz.message.response.NewsMessage;
import com.wtz.message.response.TextMessage;
import com.wtz.message.response.VideoMessage;
import com.wtz.message.response.VoiceMessage; /**
* @author wangtianze QQ:864620012
* @date 2017年4月19日 下午3:29:58
* <p>version:1.0</p>
* <p>description:消息处理工具类</p>
*/
public class MessageUtil {
//请求消息类型:文本
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
//请求消息类型:图片
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
//请求消息类型:语音
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
//请求消息类型:视频
public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
//请求消息类型:地理位置
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
//请求消息类型:链接
public static final String REQ_MESSAGE_TYPE_LINK = "link";
//请求消息类型:事件推送
public static final String REQ_MESSAGE_TYPE_EVENT = "event"; //--------------------------------------------------------------- //事件类型:subscribe(订阅)
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
//事件类型:unsubscribe(取消订阅)
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
//事件类型:scan(用户已关注时的扫描带参数的二维码)
public static final String EVENT_TYPE_SCAN = "scan";
//事件类型:LOCATION(上报地理位置)
public static final String EVENT_TYPE_LOCATION = "LOCATION";
//事件类型:CLICK(自定义菜单)
public static final String EVENT_TYPE_CLICK = "CLICK"; //--------------------------------------------------------------- //响应消息类型:文本
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
//响应详细类型:图片
public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
//响应消息类型:语音
public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
//响应消息类型:视频
public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
//响应详细类型:音乐
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
//响应消息类型:图文
public static final String RESP_MESSAGE_TYPE_NEWS = "news"; //--------------------------------------------------------------- //-----------------------------------------老的,加密前---------------------------------------------
// //从流中解析出每个节点的内容
// public static Map<String,String> parseXml(HttpServletRequest request) throws IOException{
// Map<String,String> map = new HashMap<String,String>();
//
// //从输入流中获取流对象
// InputStream in = request.getInputStream();
//
// //构建SAX阅读器对象
// SAXReader reader = new SAXReader();
// try {
// //从流中获得文档对象
// Document doc = reader.read(in);
//
// //获得根节点
// Element root = doc.getRootElement();
//
// //获取根节点下的所有子节点
// List<Element> children = root.elements();
//
// for(Element e:children){
// //遍历每一个节点,并按照节点名--节点值放入map中
// map.put(e.getName(), e.getText());
// System.out.println("用户发送的消息XML解析为:" + e.getName() + e.getText());
// }
//
// //关闭流
// in.close();
// in = null;
// } catch (DocumentException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// return map;
// }
//-----------------------------------------新的,加密后--------------------------------------------
//从流中解析出每个节点的内容
public static Map<String,String> parseXml(String request) throws IOException{
Map<String,String> map = new HashMap<String,String>(); //从request中获取流对象
InputStream in = new ByteArrayInputStream(request.getBytes("UTF-8")); //构建SAX阅读器对象
SAXReader reader = new SAXReader();
try {
//从流中获得文档对象
Document doc = reader.read(in); //获得根节点
Element root = doc.getRootElement(); //获取根节点下的所有子节点
List<Element> children = root.elements(); for(Element e:children){
//遍历每一个节点,并按照节点名--节点值放入map中
map.put(e.getName(), e.getText());
System.out.println("用户发送的消息XML解析为:" + e.getName() + e.getText());
} //关闭流
in.close();
in = null;
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return map;
}
//---------------------------------------------------------------------------------------------- /**
* 用于扩展节点数据按照<ToUserName><![CDATA[toUser]]></ToUserName>,中间加了CDATA段
*/
private static XStream xstream = new XStream(new XppDriver(){
public HierarchicalStreamWriter createWriter(Writer out){
return new PrettyPrintWriter(out){
boolean cdata = true;
public void startNode(String name,Class clazz){
super.startNode(name,clazz);
} protected void writeText(QuickWriter writer,String text){
if(cdata){
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
}else{
writer.write(text);
}
}
};
}
}); /**
* 将文本消息对象转换成XML格式
* params:textMessage 文本消息对象
* return:xml
*/
public static String messageToXml(TextMessage textMessage){
xstream.alias("xml",textMessage.getClass());
return xstream.toXML(textMessage);
} /**
* 将图片消息对象转换成XML格式
* params:imageMessage
* return:xml
*/
public static String messageToXml(ImageMessage imageMessage){
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
} /**
* 将语音消息对象转换成XML格式
* params:voiceMessage
* return:xml
*/
public static String messageToXml(VoiceMessage voiceMessage){
xstream.alias("xml",voiceMessage.getClass());
return xstream.toXML(voiceMessage);
} /**
* 将视频消息对象转换成XML格式
* params:videoMessage
* return:xml
*/
public static String messageToXml(VideoMessage videoMessage){
xstream.alias("xml",videoMessage.getClass());
return xstream.toXML(videoMessage);
} /**
* 将音乐消息对象转换成XML格式
* params:musicMessage
* return:xml
*/
public static String messageToXml(MusicMessage musicMessage){
xstream.alias("xml",musicMessage.getClass());
return xstream.toXML(musicMessage);
} /**
* 将图文消息对象转换成XML格式
* params:newsMessage
* return:xml
*/
public static String messageToXml(NewsMessage newsMessage){
xstream.alias("xml",newsMessage.getClass());
return xstream.toXML(newsMessage);
}
}
第五步:找到包com.wtz.util下的ProcessService.java类,修改dealRequest方法
package com.wtz.util; import java.io.IOException;
import java.util.Date;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.wtz.dao.PostCodeDao;
import com.wtz.message.response.TextMessage; /**
* @author wangtianze QQ:864620012
* @date 2017年4月19日 下午8:04:14
* <p>version:1.0</p>
* <p>description:核心服务类</p>
*/
public class ProcessService {
//定义数据访问的dao
private static PostCodeDao dao = new PostCodeDao(); //-----------------------------------老的,加密前--------------------------------------------------
// public static String dealRequest(HttpServletRequest request){
// //XML格式的消息数据
// String respXml = "";
// //默认返回的文本消息内容
// String respContent = "未知的消息类型";
// //调用parseXml方法解析请求消息
// Map<String, String> requestMap;
// try {
// requestMap = MessageUtil.parseXml(request);
// //发送方账号
// String fromUserName = requestMap.get("FromUserName");
// //开发者微信号
// String toUserName = requestMap.get("ToUserName");
// //消息类型
// String MsgType = requestMap.get("MsgType");
// //消息内容
// String content = requestMap.get("Content");
//
// //回复文本消息
// TextMessage textMessage = new TextMessage();
// textMessage.setToUserName(fromUserName);
// textMessage.setFromUserName(toUserName);
// textMessage.setCreateTime(new Date().getTime());
// textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
//
// if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// if(content.equals("1")){
// respContent = "请按照格式输入地区名,例如输入 邮编:东城";
// }
// if(content.equals("2")){
// respContent = "请按照格式输入地区名,例如输入 区号:东城";
// }
// if(content.equals("?")){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// }
// if(content.startsWith("邮编:")){
// int pos = content.indexOf(":");
// String cityName = content.substring(pos + 1);
// respContent = dao.findPostCodeByCityName(cityName);
// System.out.println("邮编:respContent:" + respContent);
// }
// if(content.startsWith("区号:")){
// int pos = content.indexOf(":");
// String cityName = content.substring(pos + 1);
// respContent = dao.findTelCodeByCityName(cityName);
// System.out.println("区号:respContent:" + respContent);
// }
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){
// respContent = "您发送的是图片消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
// respContent = "您发送的是语音消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)){
// respContent = "您发送的是视频消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
// respContent = "您发送的是地理位置消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)){
// respContent = "您发送的是链接消息";
// }else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
// //事件类型
// String eventType = requestMap.get("Event");
// if(eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){
// respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){
// //TODO 取消订阅后用户不会再收到公众号发送的消息,因此不需要回复
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){
// //TODO 处理扫描带参数二维码事件
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)){
// //TODO 处理上报地理位置事件
// }else if(eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
// //TODO 处理菜单点击事件
// }
// }
// //设置文本消息的内容
// textMessage.setContent(respContent);
// //将文本消息对象转换成xml
// respXml = MessageUtil.messageToXml(textMessage);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// return respXml;
// } //----------------------------------------------新的,加密后---------------------------------------------
public static String dealRequest(String request){
//XML格式的消息数据
String respXml = "";
//默认返回的文本消息内容
String respContent = "未知的消息类型";
//调用parseXml方法解析请求消息
Map<String, String> requestMap;
try {
requestMap = MessageUtil.parseXml(request);
//发送方账号
String fromUserName = requestMap.get("FromUserName");
//开发者微信号
String toUserName = requestMap.get("ToUserName");
//消息类型
String MsgType = requestMap.get("MsgType");
//消息内容
String content = requestMap.get("Content"); //回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
if(content.equals("1")){
respContent = "请按照格式输入地区名,例如输入 邮编:东城";
}
if(content.equals("2")){
respContent = "请按照格式输入地区名,例如输入 区号:东城";
}
if(content.equals("?")){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
}
if(content.startsWith("邮编:")){
int pos = content.indexOf(":");
String cityName = content.substring(pos + 1);
respContent = dao.findPostCodeByCityName(cityName);
System.out.println("邮编:respContent:" + respContent);
}
if(content.startsWith("区号:")){
int pos = content.indexOf(":");
String cityName = content.substring(pos + 1);
respContent = dao.findTelCodeByCityName(cityName);
System.out.println("区号:respContent:" + respContent);
}
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)){
respContent = "您发送的是图片消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)){
respContent = "您发送的是语音消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VIDEO)){
respContent = "您发送的是视频消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)){
respContent = "您发送的是地理位置消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)){
respContent = "您发送的是链接消息";
}else if(MsgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)){
//事件类型
String eventType = requestMap.get("Event");
if(eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)){
respContent = "感谢您关注【王天泽的服务号】\n" + "微信号:wangtianze1\n" + "请回复序号:\n" + "1.查邮政编码\n" + "2.查电话区号\n" + "?.返回帮助菜单\n";
}else if(eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)){
//TODO 取消订阅后用户不会再收到公众号发送的消息,因此不需要回复
}else if(eventType.equals(MessageUtil.EVENT_TYPE_SCAN)){
//TODO 处理扫描带参数二维码事件
}else if(eventType.equals(MessageUtil.EVENT_TYPE_LOCATION)){
//TODO 处理上报地理位置事件
}else if(eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
//TODO 处理菜单点击事件
}
}
//设置文本消息的内容
textMessage.setContent(respContent);
//将文本消息对象转换成xml
respXml = MessageUtil.messageToXml(textMessage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} return respXml;
}
}
第六步:找到包com.wtz.service,修改LoginServlet.java类,修改doPost方法
package com.wtz.service; import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import com.wtz.aes.AesException;
import com.wtz.aes.WXBizMsgCrypt;
import com.wtz.util.MessageUtil;
import com.wtz.util.Parameter;
import com.wtz.util.ProcessService;
import com.wtz.util.ValidationUtil; /**
* @author wangtianze QQ:864620012
* @date 2017年4月17日 下午8:11:32
* <p>version:1.0</p>
* <p>description:微信请求验证类</p>
*/
public class LoginServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("get请求。。。。。。"); //1.获得微信签名的加密字符串
String signature = request.getParameter("signature"); //2.获得时间戳信息
String timestamp = request.getParameter("timestamp"); //3.获得随机数
String nonce = request.getParameter("nonce"); //4.获得随机字符串
String echostr = request.getParameter("echostr"); System.out.println("获得微信签名的加密字符串:"+signature);
System.out.println("获得时间戳信息:"+timestamp);
System.out.println("获得随机数:"+nonce);
System.out.println("获得随机字符串:"+echostr); PrintWriter out = response.getWriter(); //验证请求确认成功原样返回echostr参数内容,则接入生效,成为开发者成功,否则失败
if(ValidationUtil.checkSignature(signature, timestamp, nonce)){
out.print(echostr);
} out.close();
out = null;
} /**
* 接受微信服务器发过来的XML数据包(通过post请求发送过来的)
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//将请求响应的编码均设置为UTF-8,防止中文乱码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8"); //------------------------老的,不加密----------------------------
// //获取微信加密的签名字符串
// String signature = request.getParameter("signature");
//
// //获取时间戳
// String timestamp = request.getParameter("timestamp");
//
// //获取随机数
// String nonce = request.getParameter("nonce");
//
// PrintWriter out = response.getWriter();
//
// if(ValidationUtil.checkSignature(signature,timestamp,nonce)){
// String respXml = "";
// try {
// respXml = ProcessService.dealRequest(request);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// out.print(respXml);
// }
// out.close();
// out = null;
//---------------------------新的,加密---------------------------
//获取微信加密的签名字符串
String signature = request.getParameter("msg_signature"); //获取时间戳
String timestamp = request.getParameter("timestamp"); //获取随机数
String nonce = request.getParameter("nonce"); //从请求中读取整个post数据
InputStream inputStream = request.getInputStream(); //commons.io.jar方法,直接将流转成字符串
String Post = IOUtils.toString(inputStream,"UTF-8"); System.out.println("Post:" + Post); String Msg = "";
WXBizMsgCrypt wxcpt = null;
try {
wxcpt = new WXBizMsgCrypt(Parameter.token,Parameter.encodingAESKey,Parameter.corpId);
//解密消息
Msg = wxcpt.decryptMsg(signature,timestamp,nonce,Post);
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Msg打印结果
System.out.println("Msg打印结果:" + Msg); //调用核心业务类接收消息,处理消息
String respMessage = ProcessService.dealRequest(Msg); //respMessage打印结果
System.out.println("respMessage打印结果:" + respMessage); String encryptMsg = "";
try {
//加密回复消息
encryptMsg = wxcpt.encryptMsg(respMessage, timestamp, nonce);
System.out.println("encryptMsg:" + encryptMsg);
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //响应消息
PrintWriter out = response.getWriter();
out.print(encryptMsg);
out.close();
}
}
消息加密完成。
Java微信二次开发(五)的更多相关文章
- Java微信二次开发(一)
准备用Java做一个微信二次开发项目,把流程写在这里吧. 第一天,做微信请求验证 需要导入库:servlet-api.jar 第一步:新建包com.wtz.service,新建类LoginServle ...
- Java微信二次开发(七)
自定义菜单 第一步:新建包com.wtz.menu,新建类Button.java package com.wtz.menu; /** * @author wangtianze QQ:864620012 ...
- Java微信公众平台开发(五)--文本及图文消息回复的实现
转自:http://www.cuiyongzhi.com/post/43.html 上篇我们说到回复消息可以根据是否需要上传文件到微信服务器可划分为[普通消息]和[多媒体消息],这里我们来讲述普通消息 ...
- Java微信二次开发(十)
生成带参数的二维码以及长链接转短链接 第一步:找到包com.wtz.vo,新建类WeixinQRCode.java package com.wtz.vo; /** * @author wangtian ...
- Java微信二次开发(八)
高级接口,先做了两个(获取用户信息和获取关注者列表) 第一步:找到包com.wtz.vo,新建类UserInfo.java package com.wtz.vo; /** * @author wang ...
- Java微信二次开发(六)
Token定时获取 需要导入库:添加log4j(slf4j-api-1.5.10.jar,slf4j-log4j12-1.5.10.jar,log4j-1.2.15.jar,并且在src下添加log4 ...
- Java微信二次开发(三)
各种类型消息的封装 第一步:找到com.wtz.message.response包,新建类Image.java package com.wtz.message.response; /** * @aut ...
- Java微信二次开发(二)
第二天,做微信文本消息接口请求与发送 需要导入库:dom4j-1.6.1.jar,xstream-1.3.1.jar 第一步:新建包com.wtz.message.response,新建类BaseMe ...
- Java微信二次开发(九)
多媒体文件上传与下载 第一步:找到包com.wtz.vo,新建类WeixinMedia.java package com.wtz.vo; /** * @author wangtianze QQ:864 ...
随机推荐
- MP实战系列(二)之集成swagger
其实与spring+springmvc+mybatis集成swagger没什么区别,只是之前写的太不好了,所以这次决定详细写. 提到swagger不得不提rest,rest是一种架构风格,里面有对不同 ...
- PAT A1129 Recommendation System (25 分)——set,结构体重载小于号
Recommendation system predicts the preference that a user would give to an item. Now you are asked t ...
- AMD和CMD规范
1.名词解释AMD:Asynchronous Modules Definition异步模块定义,提供定义模块及异步加载该模块依赖的机制.CMD:Common Module Definition 通用模 ...
- Objective-C 类簇深入理解
类簇(class cluster),是一种基于抽象工厂的设计模式,广泛运用于系统的Foundation框架.顾名思义,即一坨类,这里指的是继承自同一父类的一组私有子类.这种实现既可以简化公共接口,又保 ...
- Caused by: java.lang.IllegalStateException: commit already called
出现的情况,当FragmentTransaction是全局变量时,fragment智能调用一次commint: 异常的意思:commint已经被调用过了. 所以不要重复调用它就好了.
- Javascript 对象复制
如果对象只是一个数据集,可采用json化再反json化的方式克隆一个对象,这个过程会丢失对象的方法.效率比较低. 可以采用如下递归的方式复制一个对象. function clone(target) { ...
- 3.《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——检查文件
上面我们已经学过如何创建及操作文件,现在我们再来学习检查内容.当文件太长以至于屏幕一页显示不完时,这显得尤其重要.特殊情形下,如我们在第2.1章节开始部分中使用cat命令将内容展示到屏幕上,但这对于长 ...
- 创建一个Scalar-valued Function函数来实现LastIndexOf
昨天有帮助网友解决的个字符串截取的问题,<截取字符串中最后一个中文词语(MS SQL)>http://www.cnblogs.com/insus/p/7883606.html 虽然实现了, ...
- QueryHelper
[1].[代码] QueryHelper.java 跳至 [1] package my.db; import java.io.Serializable; import java.math.BigInt ...
- jinja2模块使用教程
模板 要了解jinja2,那么需要先理解模板的概念.模板在Python的web开发中广泛使用,它能够有效的将业务逻辑和页面逻辑分开,使代码可读性增强.并且更加容易理解和维护. 模板简单来说就是一个其中 ...