[lottery] 03_业务处理-用户登录

Android 4.0

业务处理-用户登录
代码抽取,
抽取代码

步骤:
①、用户登录界面,输入好用户信息
②、点击登录按钮
③、生成用户登录 UserLoginElement请求的xml文件
④、发送请求xml给服务器
⑥、服务器响应一个xml
⑦、手机端对服务器响应的xml进行第一个校验
进行md5值校验:
timestamp(时间戳)+子代理商的密码(本地存储)+<body>......</body>(完整body内容)
⑧、将生成的md5和服务器返回的xml中的digest进行比对,
⑨、如果一样,那么就是发送给自己的,现在就进行body中内容的解析

1、未抽取前的用户登录模块:
package cn.zengfansheng.lottery.engine;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
 
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
 
import android.util.Xml;
import cn.zengfansheng.lottery.ConstantValue;
import cn.zengfansheng.lottery.domain.User;
import cn.zengfansheng.lottery.net.protocol.HttpClientAdapter;
import cn.zengfansheng.lottery.net.protocol.Message;
import cn.zengfansheng.lottery.net.protocol.element.UserLoginElement;
import cn.zengfansheng.lottery.util.DES;
 
/**
* 用户有关的业务服务
* @author hacket
*/

public class UserService {
 
    // 1、生成用户登陆请求(UserLoginElement)
    // 2、设置好用户名和密码
    // 3、Message.getXml(element)
    // 4、建立与服务连接的工具连接服务器传递当前的xml
    // 5、等待服务器回复
 
    public Message login(User user) {
 
        //TODO : 1、生成用户登陆请求(UserLoginElement)
        UserLoginElement userLoginElement = new UserLoginElement();
        userLoginElement.getActpassword().setTagValue(user.getPassword());
 
        //TODO : 2、设置好用户名和密码
        Message message = new Message();
        message.getHeader().getUsername().setTagValue(user.getUsername());
 
        //TODO : 3、Message.getXml(element)生成xml文件
        String userLoginXml = message.getXml(userLoginElement);
 
        //TODO : 4、建立与服务连接的工具连接服务器传递当前的xml
        if (StringUtils.isNotBlank(userLoginXml)) {
 
            HttpClientAdapter clientAdapter = new HttpClientAdapter();
            InputStream in = clientAdapter.sendPost(ConstantValue.URL_LOTTERY,userLoginXml);//TODO:这里为null?
 
            Message msg = new Message();// 用来保存第一次解析中的信息
            if (in!=null) {//服务器返回的xml流
 
                //TODO : 5、解析服务器回复数据(第一次解析)目的:解析出timestamp、body 和digest为下面的md5校验做准备
                XmlPullParser parser = Xml.newPullParser();
 
                try {
                    parser.setInput(in, "utf-8");
 
                    int eventType = parser.getEventType();
                    while (XmlPullParser.END_DOCUMENT != eventType) {
                        String name = "";
                        switch (eventType) {
                        case XmlPullParser.START_TAG:
                            name = parser.getName();
                            if ("timestamp".equalsIgnoreCase(name)) {// 时间戳
                                String timestamp = parser.nextText();
                                msg.getHeader().getTimestamp().setTagValue(timestamp);
                            }else if ("body".equalsIgnoreCase(name)) {//body中的内容
                                String body = parser.nextText();
                                msg.getBody().setFirstDecodeBodyInfo(body);
                            }else if ("digest".equalsIgnoreCase(name)) {//md5加密后的
                                String digest = parser.nextText();
                                msg.getHeader().getDigest().setTagValue(digest);
                            }
                            break;
                        case XmlPullParser.END_TAG:
                            break;
                        }
                        eventType = parser.next();
                    }
 
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
 
            // 6、验证MD5信息 (timestamp+子代理商的密钥+解密后全部body信息)
            DES des = new DES();//des.authcode("d8fPhfd9JkW99p8aqhtVIA==","ENCODE","0102030405060708")
 
            // 经过第一次解析后且经过des解密的body全部的内容(使用des的密码解密)
            String wholeBody =  "<body>"+des.authcode(msg.getBody().getFirstDecodeBodyInfo(),"ENCODE",ConstantValue.DES_PASSWORD)+"</body>";
 
            // 待加密md5值的字符串(服务器的时间戳+子代理商的密码+完全的body未加密信息)(使用子代理商的密码)
            String md5Info = msg.getHeader().getTimestamp().getTagValue().trim()+ ConstantValue.AGENTER_PASSWORD + wholeBody.trim();
 
            String md5Hex = DigestUtils.md5Hex(md5Info).trim();
            if (msg.getHeader().getDigest().getTagValue().trim().equals(md5Hex)) {// 验证通过
 
                // 7、解析body(第二次解析) oelement:errorcode、errormsg
                XmlPullParser parser = Xml.newPullParser();
                Message resultMsg = new Message();
                try {
                    parser.setInput(new StringReader(wholeBody));
 
                    int eventType = parser.getEventType();
                    while (XmlPullParser.END_DOCUMENT != eventType) {
                        String name = "";
                        switch (eventType) {
                        case XmlPullParser.START_TAG:
                            name = parser.getName();
                            if ("errorcode".equalsIgnoreCase(name)) {// 错误代码
                                int errorcode = Integer.parseInt(parser.nextText());
                                resultMsg.getBody().getOlement().setErrorcode(errorcode );
                            } else if ("errormsg".equalsIgnoreCase(name)) {// 具体错误信息
                                String errormsg = parser.nextText();
                                resultMsg.getBody().getOlement().setErrormsg(errormsg );
                            }
                            break;
                        case XmlPullParser.END_TAG:
                            break;
                        }
                        eventType = parser.next();
                    }
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return resultMsg;
            }
        }
        return null;
    }
}
二、进行抽取
将不变的抽取到一个抽象类中
具体的业务实现只需要继承该类,然后实现某个业务特有的方法
①抽象类BasicService.java 
package cn.zengfansheng.lottery.engine;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.codec.digest.DigestUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Xml;
import cn.zengfansheng.lottery.ConstantValue;
import cn.zengfansheng.lottery.domain.User;
import cn.zengfansheng.lottery.net.protocol.Element;
import cn.zengfansheng.lottery.net.protocol.HttpClientAdapter;
import cn.zengfansheng.lottery.net.protocol.Message;
import cn.zengfansheng.lottery.util.DES;
public abstract class BasicService {
    /**
     * TODO 返回Md5验证通过后的结果 (汇总)
     * @param user 用户
     * @param element 请求类型
     * @return md5验证通过后的Message 
     */
    public Message getResult(User user, Element element) {
        
        //获取xml文件
        String xml = getXml(user, element);
        
        //建立与服务连接的工具连接服务器传递当前的xml
        InputStream in = sendRequest(xml);
        
        //第一次解析,为验证md5做准备
        if (in!=null) {
            Message message = firstParser(in);
            if (message != null) {
                // 进行md5校验
                if (checkMd5(message)) {
                    return message;
                }
            }
        }
        return null;
    }
    
    
    // 3、生成xml文件
    /**
     * 生成xml文件
     * @param user 用户名
     * @param element 请求的类型
     * @return 返回生成用于和服务器进行通信的xml文件
     */
    protected String getXml(User user, Element element) {
        Message message = new Message();
        if (user != null) {
            message.getHeader().getUsername().setTagValue(user.getUsername());
        }
        return message.getXml(element);
    }
    // 4、建立与服务连接的工具连接服务器传递当前的xml
    /**
     * 和服务器通讯,并获得服务器返回的结果 
     * @param xml 和服务通讯的xml文件
     * @return InputStream
     */
    protected InputStream sendRequest(String xml) {
        
        HttpClientAdapter clientAdapter = new HttpClientAdapter();
        InputStream in = clientAdapter.sendPost(ConstantValue.URL_LOTTERY,xml); 
        return in;
    }
    
    /**
     * 5、第一次解析,为验证md5做准备
     * @param in 服务器返回的xml流对象
     * @return 
     */
    protected Message firstParser(InputStream in) {
        Message msg = new Message();// 用来保存第一次解析中的信息
        if (in!=null) {//服务器返回的xml
            
            //TODO : 5、解析服务器回复数据(第一次解析)目的:解析出timestamp、body 和digest为下面的md5校验做准备
            XmlPullParser parser = Xml.newPullParser();
            try {
                parser.setInput(in, "utf-8");
                int eventType = parser.getEventType();
                while (XmlPullParser.END_DOCUMENT != eventType) {
                    String name = "";
                    switch (eventType) {
                    case XmlPullParser.START_TAG:
                        name = parser.getName();
                        if ("timestamp".equalsIgnoreCase(name)) {// 时间戳
                            String timestamp = parser.nextText();
                            msg.getHeader().getTimestamp().setTagValue(timestamp);
                        }else if ("body".equalsIgnoreCase(name)) {//body中的内容
                            String body = parser.nextText();
                            msg.getBody().setFirstDecodeBodyInfo(body);
                        }else if ("digest".equalsIgnoreCase(name)) {//md5加密后的
                            String digest = parser.nextText();
                            msg.getHeader().getDigest().setTagValue(digest);
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        break;
                    }
                    eventType = parser.next();
                }
                return msg;
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    // 验证MD5信息 (timestamp+子代理商的密钥+解密后全部body信息)
    /**
     * 6、进行md5校验
     * @param msg 要校验的信息封装的message
     * @return 通过为true,反之没有通过
     */
    protected boolean checkMd5(Message msg) {
        DES des = new DES();//des.authcode("d8fPhfd9JkW99p8aqhtVIA==","ENCODE","0102030405060708")
        // 经过第一次解析后且经过des解密的body全部的内容(使用des的密码解密)
        String wholeBodyInfo =  "<body>"+des.authcode(msg.getBody().getFirstDecodeBodyInfo(),"ENCODE",ConstantValue.DES_PASSWORD)+"</body>";
        
        // 待加密md5值的字符串(服务器的时间戳+子代理商的密码+完全的body未加密信息)(使用子代理商的密码)
        String md5Info = msg.getHeader().getTimestamp().getTagValue().trim()+ ConstantValue.AGENTER_PASSWORD + wholeBodyInfo.trim();
        String md5Hex = DigestUtils.md5Hex(md5Info).trim();
        if (msg.getHeader().getDigest().getTagValue().trim().equals(md5Hex)) {
            
            msg.getBody().setEncodeBodyInfo(wholeBodyInfo);
            return true;
        }
        return false;
    }
}
②如用户登录具体实现业务类 UserService.java
package cn.zengfansheng.lottery.engine;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
 
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
 
import android.util.Xml;
import cn.zengfansheng.lottery.ConstantValue;
import cn.zengfansheng.lottery.domain.User;
import cn.zengfansheng.lottery.net.protocol.HttpClientAdapter;
import cn.zengfansheng.lottery.net.protocol.Message;
import cn.zengfansheng.lottery.net.protocol.element.UserLoginElement;
import cn.zengfansheng.lottery.util.DES;
 
/**
* 用户有关的业务服务
* @author hacket
*/

public class UserService extends BasicService{
 
 
    /**
     * 用户登录
     * @param user  用户的信息bean
     * @return  返回服务器给手机端的Message
     */

    public Message login(User user) {
 
        // TODO : 1、生成用户登陆请求(UserLoginElement)
        UserLoginElement userLoginElement = new UserLoginElement();
        userLoginElement.getActpassword().setTagValue(user.getPassword());
 
        // TODO : 2、3、4、5、6
        Message result = getResult(user, userLoginElement);
 
        // 7、解析body(第二次解析) oelement:errorcode、errormsg
        XmlPullParser parser = Xml.newPullParser();
        Message resultMsg = new Message();
        try {
            parser.setInput(new StringReader(result.getBody().getEncodeBodyInfo()));//完全的未desc加密的body内容
 
            int eventType = parser.getEventType();
            while (XmlPullParser.END_DOCUMENT != eventType) {
                String name = "";
                switch (eventType) {
                case XmlPullParser.START_TAG:
                    name = parser.getName();
                    if ("errorcode".equalsIgnoreCase(name)) {// 错误代码
                        int errorcode = Integer.parseInt(parser.nextText());
                        resultMsg.getBody().getOlement().setErrorcode(errorcode );
                    } else if ("errormsg".equalsIgnoreCase(name)) {// 具体错误信息
                        String errormsg = parser.nextText();
                        resultMsg.getBody().getOlement().setErrormsg(errormsg );
                    }
                    break;
                case XmlPullParser.END_TAG:
                    break;
                }
                eventType = parser.next();
            }
            return result;
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

问题:
相同的字符串,使用md5加密
windows下和android下加密后的结果不一致?