使用@RequestBody傳遞多個(gè)不同對(duì)象方式
@RequestBody傳遞多個(gè)不同對(duì)象
如果使用spring mvc同客戶(hù)端通信,完全使用json數(shù)據(jù)格式,需要增加RequestBody注解,函數(shù)參數(shù)為自定義類(lèi)
@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public RetureResult test(@RequestBody User user){
return new ReturnResult();
}
}
這樣的話(huà),可以將接收到的json格式的數(shù)據(jù)轉(zhuǎn)換為指定的數(shù)據(jù)對(duì)象user。比如{name:"test"},name為User類(lèi)的屬性域。通過(guò)ResponseBody注解,可以返回json格式的數(shù)據(jù)。
有時(shí)接收json格式數(shù)據(jù)時(shí),我們可能需要將其轉(zhuǎn)換為多個(gè)對(duì)象。
以下方式是錯(cuò)誤的。原因是request的content-body是以流的形式進(jìn)行讀取的,讀取完一次后,便無(wú)法再次讀取了。
@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public RetureResult test(@RequestBody User user,@RequestBody Address address){
return new ReturnResult();
}
}
解決方案1
增加一個(gè)包裝類(lèi),將所需要類(lèi)寫(xiě)入,增加get,set方法
@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public RetureResult test(@RequestBody Param param){
User user=param.getUser();
Address address=param.getAddress();
return new ReturnResult();
}
}
class Param{
private User user;
private Address address;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
此時(shí)傳輸?shù)膉son數(shù)據(jù)格式變?yōu)閧user:{name:"test"},address:{location:"新華路"}}。
由于只是在TestController中增加一個(gè)包裝類(lèi),不會(huì)影響其他的類(lèi)以及已經(jīng)定義好的model類(lèi),因此可以非常方便的達(dá)到接收多個(gè)對(duì)象參數(shù)的目的。
解決方案2
將接收參數(shù)定義為Map<String, Object>,然后使用map轉(zhuǎn)object工具,轉(zhuǎn)換成需要的對(duì)象。
此時(shí),即使自定義的Param類(lèi)中的屬性即使比json數(shù)據(jù)中的屬性少了,也沒(méi)關(guān)系。
其中JSONUtils為自定義的工具類(lèi),可使用常見(jiàn)的fastjson等工具包包裝實(shí)現(xiàn)。
@Controller
public class TestController{
@RequestMapping("\test")
@ResponseBody
public Object test(@RequestBody Map<String, Object> models){
User user=JsonXMLUtils.map2object((Map<String, Object>)models.get("user"),User.class);
Address address=JsonXMLUtils.map2object((Map<String, Object>)models.get("address"),Address.class);
return models;
}
}
import com.alibaba.fastjson.JSON;
public class JsonXMLUtils {
public static String obj2json(Object obj) throws Exception {
return JSON.toJSONString(obj);
}
public static <T> T json2obj(String jsonStr, Class<T> clazz) throws Exception {
return JSON.parseObject(jsonStr, clazz);
}
public static <T> Map<String, Object> json2map(String jsonStr) throws Exception {
return JSON.parseObject(jsonStr, Map.class);
}
public static <T> T map2obj(Map<?, ?> map, Class<T> clazz) throws Exception {
return JSON.parseObject(JSON.toJSONString(map), clazz);
}
}
使用多個(gè)@RequestBody接收參數(shù)
原因
常規(guī)情況下,因?yàn)閞equest的body只能讀取一次,@RequestBody也只能解析一次,這就導(dǎo)致解析第二個(gè)的@RequestBody的時(shí)候stream已經(jīng)關(guān)閉了,無(wú)法再次讀取。
話(huà)不多說(shuō),上貨:
解決辦法:兩個(gè)類(lèi),直接copy即可
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {
private final String body;
/**
*
* @param request
*/
public BodyReaderRequestWrapper(HttpServletRequest request) throws IOException{
super(request);
StringBuilder sb = new StringBuilder();
InputStream ins = request.getInputStream();
BufferedReader isr = null;
try{
if(ins != null){
isr = new BufferedReader(new InputStreamReader(ins));
char[] charBuffer = new char[128];
int readCount = 0;
while((readCount = isr.read(charBuffer)) != -1){
sb.append(charBuffer,0,readCount);
}
}else{
sb.append("");
}
}catch (IOException e){
throw e;
}finally {
if(isr != null) {
isr.close();
}
}
sb.toString();
body = sb.toString();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayIns.read();
}
};
return servletIns;
}
}
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@WebFilter(filterName = "crownFilter", urlPatterns = "/*")
public class BodyReaderRequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper(request);
if(requestWrapper == null){
filterChain.doFilter(request,response);
}else {
filterChain.doFilter(requestWrapper,response);
}
}
@Override
public void destroy() {
}
}
使用:自行測(cè)試。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)和森林結(jié)構(gòu)工具類(lèi)實(shí)現(xiàn)
本文主要介紹了Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)和森林結(jié)構(gòu)工具類(lèi)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
在Java生產(chǎn)環(huán)境下進(jìn)行性能監(jiān)控與調(diào)優(yōu)的詳細(xì)過(guò)程
在Java生產(chǎn)環(huán)境下進(jìn)行性能監(jiān)控與調(diào)優(yōu)是一個(gè)復(fù)雜但重要的過(guò)程,它涉及到多個(gè)方面,包括代碼分析、JVM監(jiān)控、線(xiàn)程管理、垃圾收集優(yōu)化、內(nèi)存管理、數(shù)據(jù)庫(kù)交互等,下面我將提供一個(gè)詳細(xì)的概述和示例代碼,需要的朋友可以參考下2025-02-02
SpringBoot通過(guò)自定義注解實(shí)現(xiàn)配置類(lèi)的自動(dòng)注入的實(shí)現(xiàn)
本文主要介紹了SpringBoot通過(guò)自定義注解實(shí)現(xiàn)配置類(lèi)的自動(dòng)注入的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長(zhǎng)公共子序列及最長(zhǎng)公共子字符串示例
這篇文章主要介紹了Java基于動(dòng)態(tài)規(guī)劃法實(shí)現(xiàn)求最長(zhǎng)公共子序列及最長(zhǎng)公共子字符串,簡(jiǎn)單描述了動(dòng)態(tài)規(guī)劃法的概念、原理,并結(jié)合實(shí)例形式分析了Java使用動(dòng)態(tài)規(guī)劃法求最長(zhǎng)公共子序列以及最長(zhǎng)公共子字符串相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-08-08
Spring Cloud Ubuntu環(huán)境部署的步驟與注意事項(xiàng)
這篇文章主要給大家介紹了關(guān)于Spring Cloud Ubuntu環(huán)境部署的步驟與注意事項(xiàng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Cloud具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
JAVA將中文轉(zhuǎn)換為拼音簡(jiǎn)單實(shí)現(xiàn)方法
拼音轉(zhuǎn)換是中文處理的常見(jiàn)需求,TinyPinyin、HanLP、pinyin4j是常用的本地拼音轉(zhuǎn)換庫(kù),各有特點(diǎn),開(kāi)發(fā)者可根據(jù)具體需求選擇合適的拼音轉(zhuǎn)換工具,需要的朋友可以參考下2024-10-10
Java 中jasperReport實(shí)現(xiàn)動(dòng)態(tài)列打印的實(shí)現(xiàn)代碼
這篇文章主要介紹了Java 中jasperReport實(shí)現(xiàn)動(dòng)態(tài)列打印的實(shí)現(xiàn)代碼的相關(guān)資料,希望通過(guò)本文大家能掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09

