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;
/**
 * 
 * 
* @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 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;
/**
 * 
 * 类功能:TODO
 * 
* @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 * @return */ @SuppressWarnings("unchecked") public static T converyToJavaBean(String xml, Class 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.*;
/**
 * 
 * 类功能: JavaBean 和 XML  需要转换的类
 * 
* @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;
/**
 * 
 * 类功能:TODO
 * 
* @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 = "q35352mynah886120330012<_BankId>张三<_TellerId>00012";
        // 调用客户端
        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();
        }
    }
}

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(MynahUtil)