Java Bean 对象和XML之间的转化和 Socket 通讯

         最近项目中涉及到好多系统的交互,  我们是微服务boot项目,手机银行,个人网银是传统的MVC项目,通讯协议是TCP + 10位 定长XML报文。 所以我们需要把我们的Http协议 + JSON转化成为 TCP + XML 请求对方系统。

      网上搜索了好多方法,都不太好用,总结下自己测试的方法。亲测可用。

      一, 工具类1 如下 :

import de.odysseus.staxon.json.JsonXMLConfig;
import de.odysseus.staxon.json.JsonXMLConfigBuilder;
import de.odysseus.staxon.json.JsonXMLInputFactory;
import de.odysseus.staxon.json.JsonXMLOutputFactory;
import de.odysseus.staxon.xml.util.PrettyXMLEventWriter;
import org.springframework.stereotype.Component;
import javax.xml.stream.*;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * <pre>
 * </pre>
 * @author dcits.xupfb
 * @version dcits.xupfb 初始创建
 */
@Component
public class JsonAndXmlUtils {
    /**
     * xml转化为JSON
     * @param xmlString  xmlString
     * @return  String
     */
    public static String XmlToJson(String xmlString) {
        StringReader  input = new StringReader(xmlString);
        StringWriter  output = new StringWriter();
        JsonXMLConfig config  = new JsonXMLConfigBuilder().autoArray(true).autoPrimitive(true).prettyPrint(true).build();
        try {
            XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(input);
            XMLEventWriter writer = new JsonXMLOutputFactory(config ).createXMLEventWriter(output);
            writer.add(reader);
            reader.close();
            writer.close();
        } catch (XMLStreamException e) {
            e.printStackTrace();
        }finally {
            try {
                output.close();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return output.toString();
    }

    /**
     * json转XML
     *
     * @param jsonString  jsonString
     * @return String
     */
    public static String JsonToXml(String jsonString){
        StringReader input = new StringReader(jsonString);
        StringWriter output = new StringWriter();
        JsonXMLConfig config = new JsonXMLConfigBuilder().multiplePI(false).repairingNamespaces(false).build();
        try {
            XMLEventReader reader = new JsonXMLInputFactory(config).createXMLEventReader(input);
            XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(output);
            writer = new PrettyXMLEventWriter(writer);
            writer.add(reader);
            reader.close();
            writer.close();
        } catch (XMLStreamException e) {
            e.printStackTrace();
        }finally {
            try {
                output.close();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // remove <?xml version="1.0" encoding="UTF-8"?>
        if (output.toString().length() >= 38) {
            return output.toString().substring(39);
        }
        return output.toString();
    }

    private static Pattern  pattern = Pattern.compile("\\s*|\t|\r|\n");
    /**
     * 去掉xml中的换行和空格
     *
     * @param jsonString
     * @return
     */
    public static String JsonToXmlReplaceBlank(String jsonString) {
        String str = JsonAndXmlUtils.JsonToXml(jsonString);
        String dest = "";
        if (str != null) {
            Matcher m = pattern.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }
}

    二, 工具类2 如下 :

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
/**
 * <pre>
 * 类功能:TODO
 * </pre>
 * @author xupfb 2020-06-11
 * @desc: TODO
 * @modify xupfb 2020-06-11 初始创建
 */
@XmlRootElement
public class JaXmlUtil {
    /**
     * JavaBean转换成xml
     * @param obj
     * @return
     */
    public static String convertToXml(Object obj) {
        try {
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            //注意jdk版本
            XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
            XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(baos, (String) marshaller.getProperty(Marshaller.JAXB_ENCODING));
            xmlStreamWriter.writeStartDocument(
            (String) marshaller.getProperty(Marshaller.JAXB_ENCODING), "1.0");
            marshaller.marshal(obj, xmlStreamWriter);
            xmlStreamWriter.writeEndDocument();
            xmlStreamWriter.close();
            return new String(baos.toString("GBK"));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * xml转换成JavaBean
     *
     * @param xml
     * @param c
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T converyToJavaBean(String xml, Class<T> c) {
        T t = null;
        try {

            JAXBContext jaxbContext = JAXBContext.newInstance(c);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            t = (T) unmarshaller.unmarshal(new StringReader(xml));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

 

  三, JavaBean 实体类如下 :

import lombok.Data;
import lombok.NoArgsConstructor;
import javax.xml.bind.annotation.*;
/**
 * <pre>
 * 类功能: JavaBean 和 XML  需要转换的类
 * </pre>
 * @author xupfb 2020-06-11
 * @desc: TODO
 * @modify xupfb 2020-06-11 初始创建
 */
@Data
//表示使用这个类中的 private非静态字段作为XML的序列化的属性或者元素,对应属性要使用get、set方法
@XmlAccessorType(XmlAccessType.FIELD)
//xml格式数据的显示的顺序名字要和定义变量的一样,而不是@XmlElement中的name
@XmlRootElement(name="Message")
public class XmlAndJavaAdapterDto {

    @XmlElement(name="Body",required=true)
    private Body body;
    @XmlElement(name="Head",required=true)
    private Head head;
    //表示使用这个类中的 private非静态字段作为XML的序列化的属性或者元素,对应属性要使用get、set方法
    @XmlAccessorType(XmlAccessType.FIELD)
//xml格式数据的显示的顺序名字要和定义变量的一样,而不是@XmlElement中的name
    @XmlType(propOrder={"transactionId","bankId","tellerId"})
    @Data
    @NoArgsConstructor
    public static class Head{
        /**
         * 定义xml中显示的数据
         */
        @XmlElement(name="TransactionId",required=true)
        private  String transactionId;
        @XmlElement(name="_BankId",required=true)
        private String bankId;

        @XmlElement(name="_TellerId",required=true)
        private String tellerId;
    }
    //表示使用这个类中的 private非静态字段作为XML的序列化的属性或者元素,对应属性要使用get、set方法
    @XmlAccessorType(XmlAccessType.FIELD)
//xml格式数据的显示的顺序名字要和定义变量的一样,而不是@XmlElement中的name
    @XmlType(propOrder={"code","name","age"})
    @Data
    public static class Body {
        /**
         * 定义xml中显示的数据
         */
        @XmlElement(name="Code",required=true)
        private  String code;
        @XmlElement(name="Name",required=true)
        private String name;

        @XmlElement(name="Age",required=true)
        private String age;
    }
}

 四, JavaBean 配合 工具类2 测试用例 如下 :

 

import com.dcits.branch.cloud.base.dao.entity.XmlAndJavaAdapterDto;
import com.dcits.branch.cloud.base.utils.JaXmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
 * <pre>
 * 类功能:TODO
 * </pre>
 * @author xupfb 2020-06-04
 * @desc: TODO
 * @modify xupfb 2020-06-04 初始创建
 */
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class XmlToBeanTest {
    @Test
    public void objectToXml(){
        XmlAndJavaAdapterDto.Head head = new XmlAndJavaAdapterDto.Head();
        head.setBankId("张三");
        head.setTellerId("00012");
        head.setTransactionId("0330012");
        
        XmlAndJavaAdapterDto.Body dd  = new XmlAndJavaAdapterDto.Body();
        dd.setAge("12");
        dd.setCode("q35352");
        dd.setName("mynah886");

        XmlAndJavaAdapterDto xmlAndJavaAdapterDto = new XmlAndJavaAdapterDto();
        xmlAndJavaAdapterDto.setBody(dd);
        xmlAndJavaAdapterDto.setHead(head);

        String xml = JaXmlUtil.convertToXml(xmlAndJavaAdapterDto);
        log.debug("111----------------------------------");
        log.debug(xml);

        XmlAndJavaAdapterDto xmlAndJavaAdapterDto2 = JaXmlUtil.converyToJavaBean(xml, XmlAndJavaAdapterDto.class);
        log.debug("222----------------------------------");
        log.debug(xmlAndJavaAdapterDto2.toString());

    }

 四, XML报文  配合 工具类1 模拟 JavaBean和 XML转化 通讯 Socket  测试用例 如下 :

       需要注意:Socket测试需要先启动- 服务端,再启动 客户端  测试。 顺序不对会报错。

 

4.1 测试1,  客户端启动  发送XML报文测试。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class TestSocketClient {
    @Autowired
    private WebSocketServiceClient webSocketServiceClient;
    /**
     * 先启动服务端, 完成后 启动客户端
     */
    @Test
    public void socketTest(){
        log.debug("---- 客户端开启工作 ----");
        //客户端发送xml,假数据
        String xml = "<?xml version='1.0' encoding='GBK'?><Message><Body><Code>q35352</Code><Name>mynah886</Name><Age>12</Age></Body><Head><TransactionId>0330012</TransactionId><_BankId>&#x5f20;&#x4e09;</_BankId><_TellerId>00012</_TellerId></Head></Message>";
        // 调用客户端
        webSocketServiceClient.runSocketClient(xml);
    }
}

 

4.2 测试2,  服务端启动  接受 XML报文测试。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
 *先开启服务端, 后开启客户端
 */
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class TestSocketService {
    @Autowired
    WebSocketService webSocketService;
    /**
     * 先启动服务端,完成后启动客户端
     */
    @Test
    public void Sockets(){
        log.debug("----------服务端开启----------");
        //服务端收到xml后转为json后回复
        webSocketService.runSocketService();
    }
}

 

4.3   服务端代码  监听模拟端口号, 接受 XML报文测试,返回响应。

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.net.ServerSocket;
import java.net.Socket;
/**
 *  socket  工具类 服务端
 */
@Slf4j
@Component
public class WebSocketService {
    // 监听端口
    private static final int PORT = 7777;
        @SneakyThrows
        public  void runSocketService(){
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            //1.建立服务器的socket,并设定一个监听的端口 PORT
            serverSocket = new ServerSocket(PORT);
            //进行循环监听,获取消息的操作放在一个大循环里
            while (true) {
                try {
                    //2.建立跟客户端的连接
                    socket = serverSocket.accept();
                } catch (Exception e) {
                    log.debug("建立与客户端的连接出现异常");
                }
                WebSocketThread webSocketThread = new WebSocketThread(socket);
                webSocketThread.start();
            }
        } catch (Exception e) {
            log.debug("端口号被占用");
        } finally {
            serverSocket.close();
        }
    }
}

4.3 多线程处理类。返回响应。

 

import com.dcits.branch.cloud.base.dao.entity.XmlAndJavaAdapterDto;
import com.dcits.branch.cloud.base.utils.JaXmlUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.net.Socket;
/**
 * socket 工具类 服务端 ---- 多线程
 */
@Slf4j
public class WebSocketThread extends Thread {
    private Socket socket;
    InputStream inputStream;
    OutputStream outputStream;
    public WebSocketThread(Socket socket) {  this.socket = socket; }

    @Override
    public void run() {
        try {
            while (true) {
                //接受客户端的消息并打印
                log.debug("socket" + socket);
                //3.获取输入流
                inputStream = socket.getInputStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
                //获取输出流
                outputStream = socket.getOutputStream();
                PrintWriter pw = new PrintWriter(outputStream);
                //4.读取用户输入信息
                String info = null;
                StringBuffer b = new StringBuffer();
                while ( ( info = br.readLine() ) != null  ) {
                    b.append(info);
                }
                log.debug("服务端收到消息xml---------- {}", b.toString());
                //将xml转为Json
                //给客户一个响应
                //String reply = JsonAndXmlUtils.XmlToJson(b.toString());
                XmlAndJavaAdapterDto xmlAndJavaAdapterDto2 =
                        JaXmlUtil.converyToJavaBean(b.toString(), XmlAndJavaAdapterDto.class);
                pw.write(xmlAndJavaAdapterDto2.toString());
                //pw.write(reply);
                pw.flush();
                //5.关闭资源
                pw.close();
                outputStream.close();
                br.close();
                inputStream.close();
                socket.close();
            }
        } catch (IOException e) {
            log.debug("客户端主动断开了");
        }
        //操作结束,关闭socket
        try {
            socket.close();
        } catch (IOException e) {
            log.debug("关闭连接出现异常");
        }
    }
}

4.4   客户端代码  监听模拟端口号,处理服务的返回的数据 

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.*;
import java.net.Socket;
/**
 * socket  工具类 客户端
 */
@Slf4j
@Service
public class WebSocketServiceClient {

    public void runSocketClient(String info) {
        try {
            final String HOST="192.168.43.216";
            //1.创建一个客户端的连接
            Socket socket = null;
            socket = new Socket(HOST,7777);
            //2.得到socket读写流
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            //输入流
            InputStream in = socket.getInputStream();
            BufferedReader  br = new BufferedReader(new InputStreamReader(in));
            //3.利用流程按照一定操作,对socket进行读写操作
            //将xml发送给服务端
            pw.write(info);
            pw.flush();
            socket.shutdownOutput();
            //接受服务器的相应
            String buf = null;
            StringBuffer  reply = new StringBuffer(256);
            while(!((buf = br.readLine() ) == null)){
                reply.append(buf);
            }
            log.debug("第一次发送后接收到服务端消息,xml转为Json后: {}", reply.toString());
            //4.关闭资源
            br.close();
            in.close();
            pw.close();
            os.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值