Spring Boot 在请求正文中使用Unicode码位发送特殊字符,不进行转换

2jcobegt  于 2023-04-06  发布在  Spring
关注(0)|答案(1)|浏览(449)

我正在开发一个KotlinSpringBoot应用程序。
我需要在请求中发送一个特殊字符(例如欧元符号)。如果我发送unicode代码点,那么它会被第三方系统正确解析和显示。
我可以用Postman工具做到这一点,但不能从我的应用程序中做到这一点。
Postman 示例:

{
    "comment": "The value is € 200 and \u20ac 300"
}

第三方系统输出:

{
    "comment": "The value is € 200 and \u20ac 300"
}

这里我们可以看到\u20ac从Postman正确发送到第三方系统。
我的应用程序代码:
控制器:

import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class TestRestController(
  private val restClient: RestClient
) {

  data class Data(
    val comment: String
  )

  @PostMapping("/data-test")
  fun dataTest(): ResponseEntity<String> {
    val euroSymbol = "\u20ac"
    val escapedEuroSymbol = "\\u20ac"

    val mockData = Data(
      comment = "The value is $euroSymbol 200 and $escapedEuroSymbol 300"
    )

    restClient.createRequest(mockData)

    return ResponseEntity.status(HttpStatus.OK).body("ok")
  }
}

其余客户端:

import org.springframework.cloud.openfeign.FeignClient
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import javax.validation.Valid

@FeignClient(
  value = "restClient",
  url = "https://envpqi8gjjxx8.x.pipedream.net/",
)
interface RestClient {
  @PostMapping(
    value = ["/test"],
    consumes = [MediaType.APPLICATION_JSON_VALUE]
  )
  fun createRequest(
    @RequestBody request: @Valid TestRestController.Data
  ): String?
}

我的对象Map器配置:

objectMapper.setTimeZone(TimeZone.getDefault())
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
objectMapper.registerModules(kotlinModule(), JavaTimeModule())

第三方系统输出:

{
    "comment": "The value is € 200 and \\u20ac 300"
}

现在,在mockData变量中,您可以看到我同时使用了\u20ac\\u20ac。第一个变量的值已损坏,第二个变量以\\u20ac的形式发送。我希望能够以纯文本的形式发送\u20ac,就像我使用Postman所做的那样。
如何做到这一点?

bfnvny8b

bfnvny8b1#

你可以使用Jackson的JsonGenerator writeRawValue来实现。
第一步:
dataTest()中,使用escapedEuroSymbol,而不是非转义变量。
步骤2-创建一个新的序列化器:

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import java.io.IOException

//use Unicode code points(like escapedEuroSymbol) for special characters in the string variable if using this Serializer on the variable
class StringWithSpecialCharacterSerializer : JsonSerializer<String?>() {
  @Throws(IOException::class)
  override fun serialize(value: String?, gen: JsonGenerator, serializers: SerializerProvider) {
    if (value != null) {
      val newString = "\"" + value + "\""
      val newStringEscapeNewLine = newString
                  .replace(System.lineSeparator(), "\\n")
                  .replace("\t", "\\t")
                  .replace("\b", "\\b")
      gen.writeRawValue(newStringEscapeNewLine)
    }
  }
}

Step 3-然后在你的数据类中,你可以在字符串字段上使用序列化器,这些字符串字段的值包含特殊字符,如欧元符号等(在使用这个序列化器时,总是使用转义的unicode代码点,而不是直接使用特殊字符):

data class Data(
    @JsonSerialize(using = StringWithSpecialCharacterSerializer::class)
    val comment: String
  )

相关问题