成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為啥前端給到的參數(shù)又不對,該如何傳遞呢?

開發(fā) 前端
最常見的一種傳輸參數(shù)的方式,URL 查詢參數(shù)是指附加在 URL 后面的以鍵值對形式傳遞的參數(shù),通常用于 GET 請求中向服務(wù)器傳遞簡單的數(shù)據(jù)。 ?

在Spring Boot開發(fā)過程中,前端與后端之間的傳參是一個核心且常見的問題。本文將詳細探討前端如何向后端傳遞參數(shù)、后端如何接收參數(shù)、接收參數(shù)的原理,以及在實際開發(fā)中如何進行合理的配置與設(shè)置,確保參數(shù)能夠正確、安全地傳輸和處理。

六種常見的方式

URL 查詢參數(shù)

最常見的一種傳輸參數(shù)的方式,URL 查詢參數(shù)是指附加在 URL 后面的以鍵值對形式傳遞的參數(shù),通常用于 GET 請求中向服務(wù)器傳遞簡單的數(shù)據(jù)。  

// 前端
axios.get('/api/users', {
  params: {
    name: 'John',
    age: 30
  }
});
// 后端
@GetMapping("/users")
public ResponseEntity<?> getUser(@RequestParam("name") String name,
                                 @RequestParam("age") Integer age) {
    // 處理業(yè)務(wù)邏輯
    return ResponseEntity.ok("User: " + name + ", age: " + age);
}

注意:我們可以去省略這個@RequestParam 注解,使用這個注解的好處就是可以設(shè)置參數(shù)的默認值defaultValue。

路徑參數(shù)

直接將參數(shù)嵌入到 URL 路徑當中的一種傳遞方式,對于后端而言需要指定特殊的標識符和注解才能使用。

// 前端
axios.get('/api/users/123');
// 后端
@GetMapping("/users/{id}")
public ResponseEntity<?> getUserById(@PathVariable("id") Long id) {
    // 根據(jù) id 查詢用戶
    return ResponseEntity.ok("User ID: " + id);
}

請求體參數(shù)

主要用于 POST、PUT 等請求,常傳遞 JSON 數(shù)據(jù)或表單數(shù)據(jù)。  

// 前端
axios.post('/api/users', {
  name: 'John',
  age: 30
});
// 后端
@PostMapping("/users")
public ResponseEntity<?> createUser(@RequestBody User user) {
    // user 對象由 JSON 數(shù)據(jù)自動反序列化而來
    return ResponseEntity.ok("User created: " + user.getName());
}

注意:請求頭需要設(shè)置  Content-Type: application/json,主要用于解析 JSON 數(shù)據(jù) 。

表單數(shù)據(jù)參數(shù)

 表單數(shù)據(jù)指的是通過 HTML 表單或 application/x-www-form-urlencoded 方式提交的參數(shù),主要用于 POST、PUT 請求。后端通常使用 @RequestParam 或 @ModelAttribute 來解析。

// 前端
let formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('username', 'John');


axios.post('/api/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  }
});
// 后端
// 普通表單接收方式
@PostMapping("/users/form")
public ResponseEntity<?> createUserForm(@ModelAttribute User user) {
    return ResponseEntity.ok("User created via form: " + user.getName());
}
// 涉及文件上傳表單接收方式
@PostMapping("/upload")
public ResponseEntity<?> handleFileUpload(@RequestPart("file") MultipartFile file,
                                          @RequestParam("username") String username) {
    // 處理文件上傳和其他參數(shù)
    return ResponseEntity.ok("File uploaded by: " + username);
}

post 方式只有一個屬性

@PostMapping("/string")
public ResponseEntity<?> receiveString(@RequestParam("text") String text) {
    return ResponseEntity.ok("Received: " + text);
}


axios.post('/string', 'text=Hello%20World', {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})


@PostMapping("/string")
public ResponseEntity<?> receiveString(@RequestBody String text) {
    return ResponseEntity.ok("Received: " + text);
}


axios.post('/string', 'Hello World', {
  headers: {
    'Content-Type': 'text/plain'
  }
})

注意:@RequestParam 方式(不可也可以,但是加上更清晰可讀)下可直接放在 Url 后面,@RequestBody 方式下使用 json 格式傳遞 。

圖片圖片

post 請求傳遞數(shù)組

@PostMapping("/list")
public ResponseEntity<?> receiveList(@RequestBody List<String> list) {
    return ResponseEntity.ok("Received: " + list);
}


axios.post('/list', ["apple", "banana", "cherry"], {
    headers: { 'Content-Type': 'application/json' }
})


@PostMapping("/list")
public ResponseEntity<?> receiveList(@RequestParam List<String> list) {
    return ResponseEntity.ok("Received: " + list);
}
axios.post('/list', null, { params: { list: ["apple", "banana", "cherry"] } })
.then(response => console.log(response.data))
.catch(error => console.error(error));
http://localhost:8080/list?list=apple&list=banana&list=cherry

圖片圖片

圖片圖片

原理分析

圖片圖片

RequestParamMethodArgumentResolver 類

在 Spring MVC 中,@RequestParam 參數(shù)的解析由 RequestParamMethodArgumentResolver 負責(zé)。它是 HandlerMethodArgumentResolver 的實現(xiàn)類之一,專門用于解析 @RequestParam 注解的參數(shù)。  

// 判斷是否由該類進行解析
public boolean supportsParameter(MethodParameter parameter) {
    if (parameter.hasParameterAnnotation(RequestParam.class)) {
        if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
            RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
            return (requestParam != null && StringUtils.hasText(requestParam.name()));
        }
        else {
            return true;
        }
    }
    else {
        if (parameter.hasParameterAnnotation(RequestPart.class)) {
            return false;
        }
        parameter = parameter.nestedIfOptional();
        if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
            return true;
        }
        else if (this.useDefaultResolution) {
            return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
        }
        else {
            return false;
        }
    }
}


// 具體解析邏輯
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {


    NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
    MethodParameter nestedParameter = parameter.nestedIfOptional();


    Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
    if (resolvedName == null) {
        throw new IllegalArgumentException(
                "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
    }


    Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
    if (arg == null) {
        if (namedValueInfo.defaultValue != null) {
            arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
        }
        else if (namedValueInfo.required && !nestedParameter.isOptional()) {
            handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
        }
        arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
    }
    else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
        arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
    }


    if (binderFactory != null) {
        WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
        try {
            arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
        }
        catch (ConversionNotSupportedException ex) {
            throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                    namedValueInfo.name, parameter, ex.getCause());
        }
        catch (TypeMismatchException ex) {
            throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                    namedValueInfo.name, parameter, ex.getCause());
        }
        // Check for null value after conversion of incoming argument value
        if (arg == null && namedValueInfo.defaultValue == null &&
                namedValueInfo.required && !nestedParameter.isOptional()) {
            handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
        }
    }


    handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);


    return arg;
}


protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);


    if (servletRequest != null) {
        Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
        if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
            return mpArg;
        }
    }


    Object arg = null;
    MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
    if (multipartRequest != null) {
        List<MultipartFile> files = multipartRequest.getFiles(name);
        if (!files.isEmpty()) {
            arg = (files.size() == 1 ? files.get(0) : files);
        }
    }
    if (arg == null) {
        String[] paramValues = request.getParameterValues(name);
        if (paramValues != null) {
            arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
        }
    }
    return arg;
}

解析條件:首先調(diào)用supportsParameter 方法判斷是否需要該類進行解析,判斷邏輯參數(shù)上存在@RequestParam 注解或者未標@RequestParam注解,但是 useDefaultResolutinotallow=true 也會嘗試解析。

解析邏輯:調(diào)用該類父類AbstractNamedValueMethodArgumentResolver 的resolveArgument 方法解析參數(shù)。

關(guān)鍵點:該類的resolveName 方法是從request.getParameter()獲取參數(shù)值。

PathVariableMethodArgumentResolver 類

@PathVariable 注解的解析由 PathVariableMethodArgumentResolver 負責(zé),它的解析邏輯與 @RequestParam 類似,但它解析的是 路徑參數(shù),而非查詢參數(shù)。

public boolean supportsParameter(MethodParameter parameter) {
    if (!parameter.hasParameterAnnotation(PathVariable.class)) {
        return false;
    }
    if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
        PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
        return (pathVariable != null && StringUtils.hasText(pathVariable.value()));
    }
    return true;
}

解析條件:首先調(diào)用supportsParameter 方法判斷是否需要該類進行解析,判斷邏輯參數(shù)上存在@PathVariable 注解。

解析邏輯:與前面@RequestParam的一致。

關(guān)鍵點:該類的resolveName 方法是從 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE  獲取參數(shù)值。

RequestResponseBodyMethodProcessor 類

該類是用來 處理 @RequestBody 和 @ResponseBody注解的,它主要用于解析請求體(@RequestBody)和返回值(@ResponseBody),并完成 JSON/XML 的序列化和反序列化。    

public boolean supportsParameter(MethodParameter parameter) {
    return parameter.hasParameterAnnotation(RequestBody.class);
}


@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {


    parameter = parameter.nestedIfOptional();
    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    String name = Conventions.getVariableNameForParameter(parameter);


    if (binderFactory != null) {
        WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
        if (arg != null) {
            validateIfApplicable(binder, parameter);
            if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
            }
        }
        if (mavContainer != null) {
            mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
        }
    }


    return adaptArgumentIfNecessary(arg, parameter);
}

解析條件:首先調(diào)用supportsParameter 方法判斷是否需要該類進行解析,判斷邏輯是存在@RequestBody 注解。

解析邏輯:直接自身的resolveArgument 方法,通過readWithMessageConverters 方法進行請求體轉(zhuǎn)換,獲取參數(shù)名稱,進行數(shù)據(jù)綁定和校驗,適配參數(shù)。

拓展分析

如果內(nèi)置的參數(shù)綁定方式無法滿足特定的要求,我們可以通過自定義 HandlerMethodArgumentResolver  來實現(xiàn)獨特的參數(shù)方式,這樣可以做到更加的安全可靠,需要將自定義解析器加入鏈條當中。

public class CustomArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 根據(jù)條件判斷是否支持該參數(shù)解析
        return parameter.hasParameterAnnotation(MyCustomAnnotation.class);
    }


    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        // 自定義解析邏輯
        return ...;
    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new CustomArgumentResolver());
    }
}

具體的實現(xiàn)邏輯可以根據(jù)需求去添加,該方式適合于復(fù)雜的數(shù)據(jù)轉(zhuǎn)換和自定義注解綁定邏輯,相對于統(tǒng)一的傳參方式更加隱秘安全。

責(zé)任編輯:武曉燕 來源: java從零到壹
相關(guān)推薦

2017-12-05 08:53:20

Golang參數(shù)傳遞

2010-06-04 10:46:18

同事上司

2023-01-05 08:12:11

分層應(yīng)用代碼

2025-02-12 10:51:51

2024-02-26 08:52:20

Python傳遞函數(shù)參數(shù)參數(shù)傳遞類型

2020-05-22 18:16:57

數(shù)據(jù)泄露網(wǎng)絡(luò)安全互聯(lián)網(wǎng)

2023-07-29 22:11:58

Spring容器Component

2023-04-10 15:14:03

2015-11-09 10:29:05

設(shè)計師前端

2020-12-23 07:56:40

前端UICSS

2021-02-24 14:01:13

微服務(wù)開發(fā)框架

2009-06-09 21:54:26

傳遞參數(shù)JavaScript

2025-03-06 08:45:03

2021-05-20 10:11:51

固態(tài)硬盤碎片系統(tǒng)

2015-05-15 17:29:13

.Netxp系統(tǒng)如何解決

2018-07-27 17:28:37

人工智能機器學(xué)習(xí)AI

2023-11-03 08:18:59

PostgresMySQL

2024-09-19 20:59:49

2009-07-30 13:07:49

ASP.NET中的三層

2020-01-08 15:31:41

MybatisHibernateJPA
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 精品久久久久久亚洲综合网站 | 国产精品久久久久久238 | 韩国主播午夜大尺度福利 | 中文二区 | 中文字幕在线一区二区三区 | 国产一区91精品张津瑜 | 日韩中文字幕在线观看 | 婷婷综合激情 | 欧美v日韩v| 99re热精品视频| 少妇性l交大片免费一 | 欧美一区二区三区在线观看视频 | 永久网站| 日韩在线观看中文字幕 | 日韩不卡在线 | 精品一区二区三区在线观看国产 | 国产日韩视频 | 欧美精品一区二区三区四区五区 | 午夜手机在线 | 日韩中文一区二区三区 | 国产人成精品一区二区三 | 中文字幕亚洲视频 | 午夜精品在线 | 色婷婷综合久久久中字幕精品久久 | 99久久中文字幕三级久久日本 | 在线播放第一页 | 在线亚洲欧美 | 日韩综合在线 | 欧美日韩久久久 | 特级毛片 | 黄色网址在线免费播放 | 狠狠干网 | 99久久亚洲 | 日韩精品在线观看一区二区三区 | 国产一区精品 | 国产精品99久久久久久动医院 | 精品国产精品三级精品av网址 | 久久久久久91 | 午夜播放器在线观看 | 国产福利在线小视频 | 国产精品一区二区久久 |