在春季强制将XML编组中的特殊字符转义

Sel*_*amy 5 java xml spring jaxb marshalling

我想在使用Spring Marshaller时强制转义特殊字符。当我使用下面的代码是完美的工作javax.xml.bind.Marshaller

书类

package com.odr.core.action;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "book")
public class Book {

    private String name;
    private String author;
    private String publisher;
    private String isbn;

    @XmlJavaTypeAdapter(value=CDATAAdapter.class)
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Book [name=" + name + ", author=" + author + ", publisher="
            + publisher + ", isbn=" + isbn + ", description=" + description
            + "]";
    }   
}
Run Code Online (Sandbox Code Playgroud)

XML对象

        writer = new BufferedWriter(new FileWriter(selectedFile));
        context = JAXBContext.newInstance(Book.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        m.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
                new CharacterEscapeHandler() {
                    @Override
                    public void escape(char[] ch, int start, int length,
                            boolean isAttVal, Writer writer)
                            throws IOException {
                        writer.write(ch, start, length);
                    }
                });
        m.marshal(book, writer);
Run Code Online (Sandbox Code Playgroud)

输出:

package com.odr.core.action;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "book")
public class Book {

    private String name;
    private String author;
    private String publisher;
    private String isbn;

    @XmlJavaTypeAdapter(value=CDATAAdapter.class)
    private String description;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Book [name=" + name + ", author=" + author + ", publisher="
            + publisher + ", isbn=" + isbn + ", description=" + description
            + "]";
    }   
}
Run Code Online (Sandbox Code Playgroud)

但是当我使用org.springframework.oxm.jaxb.Jaxb2Marshaller时,相同类型的代码不起作用,下面是代码

    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("jaxb.formatted.output", true);
    jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
    // com.sun.xml.bind.characterEscapeHandler
    // com.sun.xml.bind.marshaller.CharacterEscapeHandler
    map.put("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
            new CharacterEscapeHandler() {
                @Override
                public void escape(char[] ac, int i, int j, boolean flag,
                        Writer writer) throws IOException {
                    writer.write(ac, i, j);
                }
            });
    jaxb2Marshaller.setMarshallerProperties(map);

    org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
    FileOutputStream fos = null;
    // String fileNamePath = directory.getAbsolutePath() + "\\" + fileName;

    try {
        // fos = new FileOutputStream(fileNamePath);
        fos = new FileOutputStream(selectedFile);
        marshaller.marshal(book, new StreamResult(fos));

        // File f = new File(directory,fileName);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            fos.close();
        }
    }
Run Code Online (Sandbox Code Playgroud)

输出量

        writer = new BufferedWriter(new FileWriter(selectedFile));
        context = JAXBContext.newInstance(Book.class);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        m.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
                new CharacterEscapeHandler() {
                    @Override
                    public void escape(char[] ch, int start, int length,
                            boolean isAttVal, Writer writer)
                            throws IOException {
                        writer.write(ch, start, length);
                    }
                });
        m.marshal(book, writer);
Run Code Online (Sandbox Code Playgroud)

第一个片段未对特殊字符进行编码。但是,虽然我设置了属性,但是使用Spring的第二个片段确实进行了编码。我必须在项目中使用Spring才能不影响现有代码。有什么办法可以解决吗

Rhu*_*lus 3

好吧,我也遇到了同样的问题,我就是这样解决的。

首先要事。您应该创建两个 bean。一个用于 ,Jaxb2Marshaller另一个用于MarshallingHttpMessageConverter。我假设您想保留您的配置,所以我将使用您的代码。

创建Jaxb2Marshallerbean:

@Bean
public Jaxb2Marshaller getJaxb2Marshaller() {
    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("jaxb.formatted.output", true);
    jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
    map.put("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
            new CharacterEscapeHandler() {
                @Override
                public void escape(char[] ac, int i, int j, boolean flag,
                                   Writer writer) throws IOException {
                    writer.write(ac, i, j);
                }
            });
    jaxb2Marshaller.setMarshallerProperties(map);

    org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
    FileOutputStream fos = null;

    try {
        fos = new FileOutputStream(selectedFile);
        marshaller.marshal(book, new StreamResult(fos));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            fos.close();
        }
    }

    return jaxb2Marshaller;
}
Run Code Online (Sandbox Code Playgroud)

好吧,我使用的是Java 8,所以我将com.sun.xml.bind.marshaller.CharacterEscapeHandler更改为com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler,如上面所示。

创建MarshallingHttpMessageConverterbean:

@Bean
public MarshallingHttpMessageConverter getMarshallingHttpMessageConverter() {
    return new MarshallingHttpMessageConverter(getJaxb2Marshaller());
}
Run Code Online (Sandbox Code Playgroud)

您一定注意到我创建了自己的 HttpMessageConverter 来解决该问题。这是因为 Spring 使用它自己的转换器,Marshaller每次需要将实体或 DTO 转换为 XML 对象时都会创建一个新实例。所以,我认为下面的代码可以解决您的问题。希望对您有帮助。

import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

@Configuration
public class XmlParseConfig {
    @Bean
    public Jaxb2Marshaller getJaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("jaxb.formatted.output", true);
        jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
        map.put("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
                new CharacterEscapeHandler() {
                    @Override
                    public void escape(char[] ac, int i, int j, boolean flag,
                                       Writer writer) throws IOException {
                        writer.write(ac, i, j);
                    }
                });
        jaxb2Marshaller.setMarshallerProperties(map);

        org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream(selectedFile);
            marshaller.marshal(book, new StreamResult(fos));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                fos.close();
            }
        }

        return jaxb2Marshaller;
    }

    @Bean
    public MarshallingHttpMessageConverter getMarshallingHttpMessageConverter() {
        return new MarshallingHttpMessageConverter(getJaxb2Marshaller());
    }
}
Run Code Online (Sandbox Code Playgroud)