Soru Spring MVC: JSON istek gövdesini seri hale getirmiyor


Bir Spring MVC projesi üzerinde çalışıyorum ve yapmam gereken görevlerden biri, bir POST isteğinde kullanıcı tarafından gönderilen bir JSON verisi dizisine sahip olmamı gerektiriyor. Spring'in Jackson'ı kullanarak nesneler için JSON'u seri hale getireceğini biliyorum, ancak aşağıdaki gibi bir şey denersem:

@RequestMapping(value = "/test", method = RequestMethod.POST)
public void doSomething(@RequestBody String json) {
    // do something
}

HTTP 400 Kötü İstek'i geri aldım ("İstemci tarafından gönderilen istek, sözdizimsel olarak yanlıştı.").

İstemci tarafından gönderilen ham JSON'u bir ip olarak nasıl alabilirim?


28
2018-05-09 16:57


Menşei


Sunucu günlüklerinde stacktrace nedir ve bu talebi nasıl yaptınız, JS kodunu da gönderin! AJAX kodunu gönder .. - NINCOMPOOP
@NoobUnChained - Bir REST API'sini test etmek için isteği kendim bir Chrome uzantısı üzerinden yapıyorum. Stacktrace çıkışı yok. @ alex23 - Açıkça bir dize olarak işlemesini nasıl söylerim? Her müşterinin bir gönderi göndereceğini garanti edemem Content-Type: application/text başlığı. - Ryan Morrison


Cevaplar:


Spring MVC, URL yoluna uyan bir istek eşlemesi bulduğunda, genellikle bu tür bir hatayı görürsünüz, ancak parametreler (veya başlıklar veya bir şey) işleyici yönteminin beklediğiyle uyuşmuyor.

@RequestBody ek açıklamasını kullanırsanız, Spring MVC'nin POST isteğinin tüm gövdesini bir nesneye eşlemeyi beklediğine inanıyorum. Sanırım vücudun sadece bir String değil, tam bir JSON nesnesi.

Eğer beklediğiniz JSON nesnesinin bir java modeliniz varsa, String parametresini bunun gibi bir doSomething bildiriminde değiştirebilirsiniz.

public void doSomething(@RequestBody MyObject myobj) {

JSON ile eşleşen bir Java nesnesiniz yoksa, bunu değiştirerek çalışmayı deneyebilirsiniz. String ile yazın Map<String, Object> ve bunun sizi çalışan bir çözüme daha yaklaştırıp yaklaştırmadığını görün.

Ayrıca, neden kötü bir istek olduğunu daha fazla bilgi almak için Spring MVC'de hata ayıklama günlüğünü açabilirsiniz.

Düzenle: Yorumlardaki gereksinimleriniz göz önünde bulundurulduğunda, HttpServletRequest'i yönteminize basitçe enjekte edebilir ve vücudu kendiniz okuyabilirsiniz.

public void doSomething(HttpServletRequest request) {
  String jsonBody = IOUtils.toString( request.getInputStream());
  // do stuff
}

48
2018-05-09 17:17



Haklısın - vücut tam bir JSON nesnesidir. Normalde onu bir Java nesnesine eşlerim, ancak nesne oluşturmadan önce ham JSON'u değiştirmem gerekiyor, bu yüzden ham JSON dizesine neden ihtiyacım var. - Ryan Morrison
Yorum yapmak için özür dilerim, ancak yukarıdaki yorumumu düzenleyemiyorum. İlkbaharda hata ayıklama kaydını etkinleştirdim ve bu özel durumla karşılaştım: org.codehaus.jackson.map.JsonMappingException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_ARRAY token - böylece seri hale getirme bölümünü nasıl atlayabilirim ve JSON verilerini bir ip olarak nasıl alabilirim? - Ryan Morrison
Bir dizge olarak isterseniz, onu bir String olarak göndermelisiniz. Sadece String'in JSON içeriği içerdiği için Spring MVC'ye söylemeniz gerektiği anlamına gelmez. @RequestBody kullanmayın ve json değerini bir formda normal bir istek param olarak gönderin. - digitaljoel
Bu, middleware ile bir REST API arayüzüne yöneliktir, middleware doğrudan JSON ile isteklerin gövdesi olarak yolları arayacaktır. Sorunları daha karmaşık hale getirmek için, uygulama yalnızca İçerik Türü değerlerini kabul eder application/json Bu nedenle her müşteri bu özel talebi düz metin olarak gönderebilse bile uygulama tarafından reddedilecektir (bunu değiştiremem). - Ryan Morrison
Bir geçici çözüm olarak, bir dize değerini ortaya koyan basit bir sınıf tanımlayabilirsiniz. Örneğin. class JsonValue { getValue(); } - Bart


Haritalamak için bazı denetleyici yöntemleri istediğimiz bir durum vardı. POST vücut Fasulyelerve sadece ham istediğimiz diğer yöntemler sicim. Bunu kullanarak gerçekleştirmek için @RequestBody  not, birden fazla mesaj dönüştürücüsünü yapılandırmanız gerekir.

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="useDefaultSuffixPattern" value="false"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jsonConverter" />
            <ref bean="marshallingConverter" />
            <ref bean="stringHttpMessageConverter" />
        </list>
    </property>
</bean>

<bean id="jsonConverter"
      class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="supportedMediaTypes" value="application/json" />
</bean>

<bean id="marshallingConverter"
      class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
    <constructor-arg ref="jaxb2Marshaller" />
    <property name="supportedMediaTypes" value="application/xml"/>
</bean>

<bean id="stringHttpMessageConverter"
      class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/plain"/>
</bean>

Ardından, çeşitli yöntemlere istekleri belirtmelidir "içerik türü"uygun bir değere sahip başlık. İstek gövdesinin bir JAXB fasulye, belirtin "application/xml"Ve istek gövdesinin olduğu yerler için sicim, kullan "text/plain".


6
2018-03-28 05:03





Kaçmayı deneyebilirsin @RequestBody tamamen ve bunun yerine istek gövdesini doğrudan InputStream/Reader ya da WebRequest/HttpServletRequest.


2
2017-12-06 01:33





Benim durumumda, json alan adlarını alıntılamadığı içindir. Bir örnek, bu kabul edilmez:

{ entity: "OneEntity"} 

ama bu bir evet:

{ "entity": "OneEntity"}

Nesne eşlemeyi bahar bağlamında nasıl yapılandırabildiğimi henüz anlamadım. Bir JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES olduğunu biliyorum, ancak nesne eşleştiricisi için bunu nasıl ayarlayacağımı bilmiyorum.


1
2018-02-26 12:27





İçerik türünüz "application / json" ise ve ilk mesajınızConvertor org.springframework.http.converter.StringHttpMessageConverter değilse, Spring düzgün çalışmayabilir. Benim durumumda şunu yaptım:

<mvc:annotation-driven>
		<mvc:message-converters>
			<ref bean="stringHttpMessageConverter" /><!-- 放在前面,对@RequestBody String json 提供支持 -->
			<ref bean="mappingJacksonHttpMessageConverter" />
		</mvc:message-converters>
	</mvc:annotation-driven>


	<!-- 消息转换器 -->
	<bean id="stringHttpMessageConverter"
		class="org.springframework.http.converter.StringHttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="text" />
					<constructor-arg index="1" value="plain" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="application" />
					<constructor-arg index="1" value="json" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
			</list>
		</property>
	</bean>

	<bean id="mappingJacksonHttpMessageConverter"
		class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
		<property name="supportedMediaTypes">
			<list>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="text" />
					<constructor-arg index="1" value="plain" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
				<bean class="org.springframework.http.MediaType">
					<constructor-arg index="0" value="application" />
					<constructor-arg index="1" value="json" />
					<constructor-arg index="2" value="UTF-8" />
				</bean>
			</list>
		</property>
		<!-- 设置时间格式, 有了这个就不用在pojo的属性上写了 -->
		<property name="objectMapper">
			<bean class="com.fasterxml.jackson.databind.ObjectMapper">
				<property name="dateFormat">
					<bean class="java.text.SimpleDateFormat">
						<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"></constructor-arg>
					</bean>
				</property>
			</bean>
		</property>
	</bean>


0
2018-05-12 10:47





İlkbahar sürümü güncellemesiyle benim için sadece bir "gerekli" idi. XXX yerine "XXX" ve her şey elinizde olduğu kadar iyi çalışıyor. İçerik Türü uygulaması / json


0
2017-09-06 16:13