Краткое изложение положения синтаксического анализа параметров запроса в веб-главе учебного пособия SpringBoot Series

Spring Boot

Как правило, при разработке веб-приложений, если предоставляется интерфейс http, наиболее распространенным методом http-запроса является GET/POST.Мы знаем, что существенное различие между двумя методами запроса заключается в том, что параметры запроса GET находятся в URL-адресе, а почтовый запрос не может быть в URL-адресе; тогда как веб-приложение, созданное SpringBoot, может анализировать инициированные параметры HTTP-запроса?

Ниже мы обобщим несколько распространенных жестов разбора параметров запроса GET с примерами.

оригинал:190824-Получить сводку по анализу параметров запроса в веб-главе учебника по серии SpringBoot

I. Строительство окружающей среды

Прежде всего, необходимо собрать веб-приложение для продолжения последующих тестов.Сборка веб-приложения с помощью SpringBoot — относительно простая задача;

Создайте проект maven, файл pom выглядит следующим образом

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7</version>
    <relativePath/> <!-- lookup parent from update -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

Добавить класс запуска проектаApplication.cass

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

В примере разбора параметра демо-запроса мы используем команду curl терминала для инициации http-запроса (основная причина в том, что загружать скриншоты слишком хлопотно, либо текстовый вывод терминала удобнее; недостаток в том, что это не очень понятно)

II. Разбор параметра запроса GET

Далее мы официально вступаем в очаровательную главу анализа параметров и представим некоторые распространенные случаи (не говоря уже о том, что включены все варианты использования).

Все перечисленные ниже методы помещены вParamGetRestв этом контроллере

@RestController
@RequestMapping(path = "get")
public class ParamGetRest {
}

1. HttpServletRequest

Использовать напрямуюHttpServletRequestЧтобы получить параметры запроса, это относительно примитивный, но наиболее гибкий способ его использования.

Обычное использование жестов заключается в том, что один из параметров запроса методаHttpServletRequest, мы проходимServletRequest#getParameter(参数名)Чтобы получить определенные параметры запроса, ниже демонстрируется случай возврата всех параметров запроса.

@GetMapping(path = "req")
public String requestParam(HttpServletRequest httpRequest) {
    Map<String, String[]> ans = httpRequest.getParameterMap();
    return JSON.toJSONString(ans);
}

Протестируйте случай, обратите внимание, что когда в параметре запроса curl есть китайский язык, выполняется кодирование URL (эта проблема будет объяснена позже)

  ~ curl 'http://127.0.0.1:8080/get/req?name=yihuihiu&age=19'
{"name":["yihuihiu"],"age":["19"]}%                                                                                                                                         ~ curl 'http://127.0.0.1:8080/get/req?name=%E4%B8%80%E7%81%B0%E7%81%B0&age=19'
{"name":["一灰灰"],"age":["19"]}%

Используйте HttpServletRequest для получения параметров запроса, есть еще один вариант использования, не для получения экземпляра запроса путем передачи параметров, а для использованияRequestContextHolder; Одним из преимуществ этого является то, что если мы хотим написать АОП, когда мы перехватываем GET-запросы и выводим параметры запроса, мы можем обрабатывать их следующим образом.

@GetMapping(path = "req2")
public String requestParam2() {
    HttpServletRequest request =
            ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
    String name = request.getParameter("name");
    return "param Name=" + name;
}

прецедент

  ~ curl 'http://127.0.0.1:8080/get/req2?name=%E4%B8%80%E7%81%B0%E7%81%B0&age=19'
param Name=一灰灰%

2. Параметры метода

Этот метод синтаксического анализа довольно мощный. Параметр GET и параметр метода отображаются в соответствии с именем параметра. С сенсорной точки зрения это похоже на прямой вызов.

@GetMapping(path = "arg")
public String argParam(String name, Integer age) {
    return "name: " + name + " age: " + age;
}

В ответ на приведенные выше методы наши тесты естественно разделятся на следующие типы, посмотрим что получится

  • Всего два параметра, определение было
  • Отсутствие параметра запроса
  • Еще один параметр запроса
  • Типы параметров несовместимы
# 参数解析正常
  ~ curl 'http://127.0.0.1:8080/get/arg?name=%E4%B8%80%E7%81%B0%E7%81%B0&age=19'
name: 一灰灰 age: 19%
# 缺少一个参数时,为null
  ~ curl 'http://127.0.0.1:8080/get/arg?name=%E4%B8%80%E7%81%B0%E7%81%B0'
name: 一灰灰 age: null% 
# 多了一个参数,无法被解析
  ~ curl 'http://127.0.0.1:8080/get/arg?name=%E4%B8%80%E7%81%B0%E7%81%B0&age=19&id=10'
name: 一灰灰 age: 19%                                                              
# 类型不一致,500 
  ~ curl 'http://127.0.0.1:8080/get/arg?name=%E4%B8%80%E7%81%B0%E7%81%B0&age=haha' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 01:45:14 GMT
Connection: close

Как видно из фактического случая выше, при использовании параметров метода для анализа параметров GET фактический эффект таков:

  • Параметры метода и параметры GET связаны сигнатурой параметра
  • Тип параметра метода, который должен соответствовать полученному типу параметра GET.
  • Когда параметр метода не является базовым типом, если не пройдено никакого параметра, он нуль; (то есть, если это базовый тип, он не может быть преобразован в NULL, а исключение брошено)
  • Фактические параметры GET могут быть больше, чем параметры, определенные методом.

Далее приведите пример разбора параметра массива

@GetMapping(path = "arg2")
public String argParam2(String[] names, int size) {
    return "name: " + (names != null ? Arrays.asList(names) : "null") + " size: " + size;
}

Тестовый пример следующий: при передаче массива значения параметров разделяются запятыми, для базовых типов параметры должны передаваться обязательно, иначе парсинг будет аномальным.

  ~ curl 'http://127.0.0.1:8080/get/arg2?name=yihui,erhui&size=2'
name: null size: 2%                                                                                                                                                         ~ curl 'http://127.0.0.1:8080/get/arg2?name=yihui,erhui' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 01:53:30 GMT
Connection: close

3. Аннотация RequestParam

Этот метод похож на предыдущий, но более гибкий.Для начала рассмотрим аннотации.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
  // 指定请求参数名
	String value() default "";
	// 指定请求参数名
	String name() default "";
	// true表示发起请求时这个参数必须存在
	boolean required() default true;
	String defaultValue() default ValueConstants.DEFAULT_NONE;
}

Есть два параметра, на которые следует обратить внимание: один — это имя, указывающее, какая связь этого параметра с параметром GET; required указывает, является ли этот параметр необязательным.

Вот простой способ использовать его

@GetMapping(path = "ano")
public String anoParam(@RequestParam(name = "name") String uname,
        @RequestParam(name = "age", required = false) Integer age,
        @RequestParam(name = "uids", required = false) Integer[] uids) {
    return "name: " + uname + " age: " + age + " uids: " + (uids != null ? Arrays.asList(uids) : "null");
}

Тест выглядит следующим образом:

# 三个参数全在
  ~ curl 'http://localhost:8080/get/ano?name=%E4%B8%80%E7%81%B0%E7%81%B0blog&age=18&uids=1,3,4'
name: 一灰灰blog age: 18 uids: [1, 3, 4]%
# age不传
  ~ curl 'http://localhost:8080/get/ano?name=%E4%B8%80%E7%81%B0%E7%81%B0blog&uids=1,3,4'
name: 一灰灰blog age: null uids: [1, 3, 4]% 
# 必选参数name不传时
  ~ curl 'http://localhost:8080/get/ano?uids=1,3,4' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 13:09:07 GMT
Connection: close

использоватьRequestParamаннотация, если указаноname/value, этот параметр связывается с указанным параметром GETGET, если не указан, то связывается согласно сигнатуре параметра

Ниже приведены еще два интересных варианта использования: один — синтаксический анализ параметров перечисления, другой — сопоставление параметров размещения, а третий — синтаксический анализ параметров массива.

public enum TYPE {
    A, B, C;
}

@GetMapping(path = "enum")
public String enumParam(TYPE type) {
    return type.name();
}

@GetMapping(path = "enum2")
public String enumParam2(@RequestParam TYPE type) {
    return type.name();
}

@GetMapping(path = "mapper")
public String mapperParam(@RequestParam Map<String, Object> params) {
    return params.toString();
}

// 注意下面这个写法,无法正常获取请求参数,这里用来对比列出
@GetMapping(path = "mapper2")
public String mapperParam2(Map<String, Object> params) {
    return params.toString();
}


@GetMapping(path = "ano1")
public String anoParam1(@RequestParam(name = "names") List<String> names) {
    return "name: " + names;
}

// 注意下面这个写法无法正常解析数组
@GetMapping(path = "arg3")
public String anoParam2(List<String> names) {
    return "names: " + names;
}

Тестовый случай выглядит следующим образом

  ~ curl 'http://localhost:8080/get/enum?type=A'
A%
  ~ curl 'http://localhost:8080/get/enum2?type=A'
A%
  ~ curl 'http://localhost:8080/get/mapper?type=A&age=3'
{type=A, age=3}%
  ~ curl 'http://localhost:8080/get/mapper2?type=A&age=3'
{}%
  ~ curl 'http://localhost:8080/get/ano1?names=yi,hui,ha'
name: [yi, hui, ha]%
  ~ curl 'http://localhost:8080/get/arg3?names=yi,hui,ha' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 13:50:55 GMT
Connection: close

Из результатов теста:

  • Когда Get отображается на перечисление, согласноenum.valueOf()к примеру
  • Если вы хотите использовать карту для размещения всех переданных параметров, вам необходимо добавить аннотации@RequestParam
  • Если параметр имеет тип List, необходимо добавить аннотацию@RequestParam; иначе используйте массив для получения

4. PathVariable

Разбираем параметры из запрошенного URL-пути, метод использования мало чем отличается от предыдущего.

@GetMapping(path = "url/{name}/{index}")
public String urlParam(@PathVariable(name = "name") String name,
        @PathVariable(name = "index", required = false) Integer index) {
    return "name: " + name + " index: " + index;
}

Вышеупомянутое является общим использованием, мы разрабатываем случай с несколькими вопросами

  • Что, если есть только имя, но нет индекса?
  • За ним есть имя, индекс и путь, что происходит?
  ~ curl http://127.0.0.1:8080/get/url/yihhuihui/1
name: yihhuihui index: 1%

  ~ curl 'http://127.0.0.1:8080/get/url/yihhuihui' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 13:27:08 GMT
Connection: close

  ~ curl 'http://127.0.0.1:8080/get/url/yihhuihui/1/test' -i
HTTP/1.1 500
Content-Length: 0
Date: Sat, 24 Aug 2019 13:27:12 GMT
Connection: close

При получении параметров из пути к URL-адресу предъявляются относительно строгие требования, обратите внимание на использование


5. POJO

Я лично часто использую такие случаи, особенно в экосистеме на основе SpringCloud, можно сказать, что использование Feign для вызова сторонних микросервисов очень удобно; давайте посмотрим на положение использования этого метода.

Сначала определите POJO

@Data
public class BaseReqDO implements Serializable {
    private static final long serialVersionUID = 8706843673978981262L;

    private String name;

    private Integer age;

    private List<Integer> uIds;
}

предоставить услугу

@GetMapping(path = "bean")
public String beanParam(BaseReqDO req) {
    return req.toString();
}

В POJO определены три параметра. Когда мы снова проверим, посмотрим, нужны ли эти параметры.

# GET传参与POJO中成员名进行关联
  ~ curl 'http://127.0.0.1:8080/get/bean?name=yihuihui&age=18&uIds=1,3,4'
BaseReqDO(name=yihuihui, age=18, uIds=[1, 3, 4])%
# 没有传参的属性为null;因此如果POJO中成员为基本类型,则参数必传
  ~ curl 'http://127.0.0.1:8080/get/bean?name=yihuihui&age=18'
BaseReqDO(name=yihuihui, age=18, uIds=null)%

II. Другое

0. Проект

1. серый блог

Это не так хорошо, как письмо. Вышеупомянутое содержание чисто из семьи. Из-за ограниченных личных способностей неизбежно будут упущения и ошибки. Если вы обнаружите ошибки или у вас есть лучшие предложения, вы можете критиковать и поправьте их.

Ниже представлен серый личный блог, в котором записываются все посты в блоге по учебе и работе, приглашаю всех посетить

  • One Grey BlogПерсональный блогblog.hhui.top
  • Серый блог - специальный весенний блогspring.hhui.top

一灰灰blog