优秀是一种习惯!!!
Solo  当前访客:2 开始使用

AmethystFOB

记录精彩人生

序列化问题汇总

2023-11-29 10:15:04 amethystfob
0  评论    0  浏览

序列化问题汇总

一、用Java将svg图片转图片流返回前端

在Java中,你可以使用第三方库Batik来将SVG图片转换为图片流,并将其返回给前端。以下是一个示例代码:

import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class SVGConverter {
   public static void main(String[] args) {
       String svgContent = "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n" +
               "  <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"2\" fill=\"red\" />\n" +
               "</svg>";

       byte[] imageBytes = convertSvgToImage(svgContent, "png");

       // 将 imageBytes 返回给前端
   }

   public static byte[] convertSvgToImage(String svgContent, String format) {
       try {
           // 创建DOM实现和文档对象
           DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
           Document document = domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
           Element svgRoot = document.getDocumentElement();

           // 将SVG内容添加到文档对象
           InputStream inputStream = new ByteArrayInputStream(svgContent.getBytes());
           TransformerFactory.newInstance().newTransformer().transform(
                   new DOMSource(document),
                   new StreamResult(svgRoot));

           // 创建转码器
           PNGTranscoder transcoder = new PNGTranscoder();
           transcoder.addTranscodingHint(PNGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, 0.026458333f); // 设置像素到毫米的转换比例,可选

           // 设置输入和输出
           TranscoderInput input = new TranscoderInput(document);
           ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
           TranscoderOutput output = new TranscoderOutput(outputStream);

           // 执行转码
           transcoder.transcode(input, output);

           // 获取转码后的图片字节数组
           byte[] imageBytes = outputStream.toByteArray();

           return imageBytes;
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
}

在示例中,我们定义了一个convertSvgToImage方法,它接受SVG内容和目标格式作为参数,并返回转换后的图片字节数组。你可以将该方法嵌入到你的Spring Controller或Servlet中,并将得到的图片字节数组返回给前端。请注意,这里示范使用PNG格式进行转换,如果需要其他格式,请根据需要修改代码中的相关部分。

需要引入Batik的依赖包,在项目的pom.xml文件(如果是Maven项目)中添加以下依赖项:

<dependency>
   <groupId>org.apache.xmlgraphics</groupId>
   <artifactId>batik-transcoder</artifactId>
   <version>1.14</version>
</dependency>

以上代码仅提供了一种将SVG转换为图片流的方式,你可以根据需要进行修改和扩展。

二、在C:\shape\aaa.svg该路径下读取aaa.svg文件,将SVG图片转换为图片流,并将其返回给前端

import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class SVGConverter {
   public static void main(String[] args) {
       String filePath = "C:\\shape\\aaa.svg";

       byte[] imageBytes = convertSvgToImage(filePath, "png");

       // 将 imageBytes 返回给前端
   }

   public static byte[] convertSvgToImage(String filePath, String format) {
       try {
           // 读取SVG文件
           File svgFile = new File(filePath);
           InputStream inputStream = new FileInputStream(svgFile);

           // 创建DOM实现和文档对象
           DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
           Document document = domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
           Element svgRoot = document.getDocumentElement();

           // 将SVG文件内容添加到文档对象
           TransformerFactory.newInstance().newTransformer().transform(
                   new DOMSource(document),
                   new StreamResult(svgRoot));

           // 创建转码器
           PNGTranscoder transcoder = new PNGTranscoder();
           transcoder.addTranscodingHint(PNGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, 0.026458333f); // 设置像素到毫米的转换比例,可选

           // 设置输入和输出
           TranscoderInput input = new TranscoderInput(inputStream);
           ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
           TranscoderOutput output = new TranscoderOutput(outputStream);

           // 执行转码
           transcoder.transcode(input, output);

           // 获取转码后的图片字节数组
           byte[] imageBytes = outputStream.toByteArray();

           return imageBytes;
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
}

在这个示例代码中,我们创建了一个新的StreamResult实例用于输出转换结果,而不是将文档的根节点传递给它。

三、将C:\shape\aaa.svg该路径下读取aaa.svg文件,将SVG图片转换为二进制流,返回给前端,注意返回的不是图片,是文件流

好的,那么你可以根据以下示例代码将SVG图片转换为二进制文件流并返回给前端:

import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;


public class SVGConverter {
   public static void main(String[] args) {
       String filePath = "C:\\shape\\aaa.svg";

       byte[] fileBytes = convertSvgToBinary(filePath, "png");

       // 将 fileBytes 返回给前端,这里的fileBytes就是二进制文件流
   }

   public static byte[] convertSvgToBinary(String filePath, String format) {
       try {
           // 读取SVG文件
           File svgFile = new File(filePath);
           InputStream inputStream = new FileInputStream(svgFile);

           // 创建DOM实现和文档对象
           DOMImplementation domImpl = SVGDOMImplementation.getDOMImplementation();
           Document document = domImpl.createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
           Element svgRoot = document.getDocumentElement();

           // 将SVG文件内容添加到文档对象
           TransformerFactory.newInstance().newTransformer().transform(
                   new DOMSource(document),
                   new StreamResult(svgRoot));

           // 创建转码器
           PNGTranscoder transcoder = new PNGTranscoder();
           transcoder.addTranscodingHint(PNGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, 0.026458333f); // 设置像素到毫米的转换比例,可选

           // 设置输入和输出
           TranscoderInput input = new TranscoderInput(inputStream);
           ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
           TranscoderOutput output = new TranscoderOutput(outputStream);

           // 执行转码
           transcoder.transcode(input, output);

           // 获取转码后的二进制流
           byte[] fileBytes = outputStream.toByteArray();

           return fileBytes;
       } catch (Exception e) {
           e.printStackTrace();
           return null;
       }
   }
}

在这个示例代码中,我们使用ByteArrayOutputStream来接收PNG转码器的输出,并使用toByteArray()方法将它转换为字节数组返回给前端。请注意返回的是二进制文件流,而不是图片。你可以根据需要进行修改和扩展。

BufferedImage newBufferedImage = new BufferedImage(bufImg.getWidth(), bufImg.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufImg, 0, 0, Color.WHITE, null);

这两句作用:

这两句代码的作用是将给定的BufferedImage对象 bufImg 格式化为 RGB 类型的图像,并将其绘制在一个新创建的白色背景的 BufferedImage 对象中。

具体解释如下:

BufferedImage newBufferedImage = new BufferedImage(bufImg.getWidth(), bufImg.getHeight(), BufferedImage.TYPE_INT_RGB);

上述代码创建了一个新的 BufferedImage 对象 newBufferedImage,宽度和高度与原始图像 bufImg 相同,像素类型为 TYPE_INT_RGB。这意味着新创建的图像将使用 24 位 RGB 颜色空间进行表示。

newBufferedImage.createGraphics().drawImage(bufImg, 0, 0, Color.WHITE, null);

接下来,通过调用 createGraphics() 方法创建了一个 Graphics2D 对象,该对象用于在 newBufferedImage 上进行绘图操作。然后,使用 drawImage() 方法将原始图像 bufImg 绘制在 newBufferedImage 中,起始坐标为 (0, 0),背景颜色为白色 (Color.WHITE),最后一个参数 null 表示没有处理 ImageObserver 对象。

通过这两句代码,我们实现了将原始图像绘制到一个新的白色背景的 BufferedImage 对象中,以便满足特定的渲染要求或保存要求。

四、将C:\shape\aaa.svg该路径下aaa.svg文件,将该svg文件返回文件流给前端

你可以使用Java的IO流来读取该SVG文件并将其返回给前端。以下是一个简单示例代码:

import java.io.*;

@RestController
public class SVGController {
 @GetMapping(value = "/get_svg")
 public ResponseEntity<byte[]> getSVG() throws IOException {
   File file = new File("C:\\shape\\aaa.svg");
   InputStream in = new FileInputStream(file);
   byte[] bytes = new byte[in.available()];
   in.read(bytes);
   in.close();
   HttpHeaders headers = new HttpHeaders();
   headers.setContentDispositionFormData("attachment", file.getName());
   headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
   return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
 }
}

在上面的示例代码中,我们定义了一个名为getSVG的HTTP GET请求处理程序,并将响应实体设置为应用程序/octet-stream类型,这是一种通用的二进制数据类型。然后我们从文件中读取字节并返回响应实体。最后我们设置了Content-Disposition标头来指示浏览器将响应保存为文件。

五、java.lang.IllegalArgumentException: 代码点[31,449]处的Unicode字符[站]无法编码,因为它超出了允许的0到255范围。如何解决?

这个异常是由于SVG文件包含了超出ASCII字符范围的Unicode字符,而在转换为字节数组时发生了编码错误。要解决这个问题,你可以使用Java的ReaderWriter类来读取和写入文件内容,以避免编码问题。以下是修改后的示例代码:

import java.io.*;

@RestController
public class SVGController {
 @GetMapping(value = "/get_svg")
 public ResponseEntity<byte[]> getSVG() throws IOException {
   File file = new File("C:\\shape\\aaa.svg");
   Reader reader = new FileReader(file);
   StringWriter writer = new StringWriter();
   char[] buffer = new char[4096];
   int n;
   while ((n = reader.read(buffer)) != -1) {
     writer.write(buffer, 0, n);
   }
   reader.close();
   writer.close();
   byte[] bytes = writer.toString().getBytes();

   HttpHeaders headers = new HttpHeaders();
   headers.setContentDispositionFormData("attachment", file.getName());
   headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
   return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
 }
}

在上述示例代码中,我们使用ReaderWriter来代替InputStreamFileInputStream,并且将StringWriter用于缓存文件内容。通过这种方式,我们可以避免编码问题,并将SVG文件的内容作为字节数组返回给前端。请确保前端正确处理返回的字节数组以显示或保存SVG文件。

修改为采用base64进行编码:

如果你想将SVG文件内容使用Base64编码并返回给前端,你可以对修改后的示例代码进行以下调整:

import java.io.*;
import java.util.Base64;

@RestController
public class SVGController {
 @GetMapping(value = "/get_svg")
 public ResponseEntity<String> getSVG() throws IOException {
   File file = new File("C:\\shape\\aaa.svg");
   Reader reader = new FileReader(file);
   StringWriter writer = new StringWriter();
   char[] buffer = new char[4096];
   int n;
   while ((n = reader.read(buffer)) != -1) {
     writer.write(buffer, 0, n);
   }
   reader.close();
   writer.close();
   String svgContent = writer.toString();
   String encodedSVGContent = Base64.getEncoder().encodeToString(svgContent.getBytes());

   HttpHeaders headers = new HttpHeaders();
   headers.setContentType(MediaType.TEXT_PLAIN);
   return new ResponseEntity<>(encodedSVGContent, headers, HttpStatus.OK);
 }
}

在修改后的代码中,我们将byte[]类型的字节数组替换为String类型的Base64编码字符串。我们首先将SVG文件内容保存在String类型的变量svgContent中,并使用Base64类的getEncoder()方法对其进行Base64编码。然后,我们设置响应消息头的Content-Typetext/plain,并返回Base64编码的SVG内容作为String类型的响应实体。

请确保前端正确处理Base64编码的SVG内容以进行相应的解码和显示。

六、java中如何在@RequestBody 对象,和指定参数同时获取,类似@RequestBody QrCode request, @RequestParam(value = "startDate") String startDate, @RequestParam(value = "endDate") String endDate

在Java中,您可以同时使用@RequestBody@RequestParam来获取请求参数。您可以将参数分别注解在方法的参数上,并通过逗号分隔它们。

以下是一个示例:

@PostMapping("/example")
public void example(@RequestBody QrCode request,
                   @RequestParam(value = "startDate") String startDate,
                   @RequestParam(value = "endDate") String endDate) {
   // 处理逻辑
}

在上述示例中,@RequestBody QrCode request用于接收请求体中的JSON对象,并将其映射到QrCode类型的参数request中。同时,@RequestParam用于获取与指定名称匹配的查询参数值,分别注解在字符串参数startDateendDate上。

请根据您的实际需求进行相应的调整和处理。

上述获取参数错误!

非常抱歉,我之前的回答有误。在Spring MVC中,@RequestBody注解用于接收请求体中的JSON对象,而@RequestParam用于获取查询参数(query parameters)。它们不能同时用于同一个参数。

如果您需要同时获取请求体中的JSON对象和查询参数,可以使用一个包含多个字段的DTO(数据传输对象)来表示请求体和查询参数。

以下是一个示例:

public class QrCodeRequest {
   private QrCode qrCode;
   private String startDate;
   private String endDate;
   
   // Getters and Setters...
}

public class QrCode {
   private String qrCodeId;
   private String qrCodeValue;
   
   // Getters and Setters...
}

@PostMapping("/example")
public void example(@RequestBody QrCodeRequest request) {
   QrCode qrCode = request.getQrCode();
   String startDate = request.getStartDate();
   String endDate = request.getEndDate();
   
   // 处理逻辑
}

在上述示例中,新建了一个名为QrCodeRequest的DTO类,其中包含了一个QrCode对象和两个字符串字段作为查询参数。在example方法中,只需要接收一个QrCodeRequest对象作为参数,然后通过该对象获取请求体中的JSON对象和查询参数。

请求的JSON可以按照以下格式进行提交:

{
 "qrCode": {
   "qrCodeId": "123456",
   "qrCodeValue": "ABCDEF"
 },
 "startDate": "2023-01-01",
 "endDate": "2023-01-31"
}

发送POST请求到/example端点时,将上述JSON作为请求体发送,并使用QrCodeRequest对象来接收参数。然后可以通过request对象获取qrCodestartDateendDate的值。

是否可以实现同时接收HTTP请求的请求体参数和接收HTTP请求的URL查询参数?

正确的方式应该是使用@ModelAttribute注解来接收URL查询参数。@ModelAttribute注解用于将HTTP请求参数(包括URL查询参数)绑定到方法参数上。

下面是正确的示例代码:

@PostMapping("/example")
public void example(@RequestBody QrCode request,
                   @ModelAttribute DateRange dateRange) {
   String startDate = dateRange.getStartDate();
   String endDate = dateRange.getEndDate();
   // 处理逻辑
}

其中,DateRange是一个包含startDateendDate属性的自定义类,用于封装日期范围参数。@ModelAttribute注解会自动将URL查询参数映射到DateRange对象的对应属性上。

例如,在这个示例中,如果请求URL为/example?startDate=2023-11-01&endDate=2023-11-30,则dateRange对象的startDate属性值为2023-11-01endDate属性值为2023-11-30

希望这次回答能够帮助你解决问题。如果还有其他问题,请随时向我提问。


标题:序列化问题汇总
作者:amethystfob
地址:https://newmoon.top/articles/2023/11/28/1701163166542.html

欢迎各路大侠指点留痕:
, ,
TOP