1. Обзор
Спецификация URI RFC 3986 определяет параметры пути URI как пары имя-значение. Матричные переменные — это термин, придуманный Spring, и альтернативная реализация для передачи и анализа параметров пути URI.
Поддержка матричных переменных стала доступна в Spring MVC 3.2 и предназначена для упрощения запросов с большим количеством параметров .
В этой статье мы покажем, как можно упростить сложные запросы GET, которые используют либо переменные, либо необязательные параметры пути внутри различных сегментов пути URI.
2. Конфигурация
Чтобы включить матричные переменные Spring MVC, начнем с конфигурации:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}
В противном случае они отключены по умолчанию.
3. Как использовать матричные переменные
Эти переменные могут появляться в любой части пути, и символ равенства ("=") используется для указания значений, а точка с запятой (';') - для разделения каждой матричной переменной. На одном и том же пути мы также можем повторять одно и то же имя переменной или разделять разные значения с помощью запятой (',').
В нашем примере есть контроллер, который предоставляет информацию о сотрудниках. У каждого сотрудника есть рабочая область, и мы можем искать по этому признаку. Для поиска можно использовать следующий запрос:
http://localhost:8080/spring-mvc-java-2/employeeArea/workingArea=rh,informatics,admin
или вот так:
http://localhost:8080/spring-mvc-java-2
/employeeArea/workingArea=rh;workingArea=informatics;workingArea=admin
Когда мы хотим сослаться на эти переменные в Spring MVC, мы должны использовать аннотацию @MatrixVariable
.
В наших примерах мы будем использовать класс Employee :
public class Employee {
private long id;
private String name;
private String contactNumber;
// standard setters and getters
}
А также класс Company :
public class Company {
private long id;
private String name;
// standard setters and getters
}
Эти два класса будут связывать параметры запроса.
4. Определение свойств матричных переменных
Мы можем указать обязательные свойства или свойства по умолчанию для переменной. В следующем примере требуется contactNumber
, поэтому он должен быть включен в наш путь, примерно так:
http://localhost:8080/spring-mvc-java-2/employeesContacts/contactNumber=223334411
Запрос будет обработан следующим методом:
@RequestMapping(value = "/employeesContacts/{contactNumber}",
method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<List<Employee>> getEmployeeByContactNumber(
@MatrixVariable(required = true) String contactNumber) {
List<Employee> employeesList = new ArrayList<Employee>();
...
return new ResponseEntity<List<Employee>>(employeesList, HttpStatus.OK);
}
В итоге мы получим всех сотрудников, у которых есть контактный номер 223334411
.
5. Параметр дополнения
Переменные матрицы могут дополнять переменные пути.
Например, мы ищем сотрудника по его/ее имени, но мы также можем включить начальные цифры его/ее контактного номера.
Запрос для этого поиска должен быть таким:
http://localhost:8080/spring-mvc-java-2/employees/John;beginContactNumber=22001
Запрос будет обработан следующим методом:
@RequestMapping(value = "/employees/{name}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<List<Employee>> getEmployeeByNameAndBeginContactNumber(
@PathVariable String name, @MatrixVariable String beginContactNumber) {
List<Employee> employeesList = new ArrayList<Employee>();
...
return new ResponseEntity<>(employeesList, HttpStatus.OK);
}
В итоге мы получим всех сотрудников, имеющих контактный номер 22001
или которых зовут Джон
.
6. Привязка всех переменных матрицы
Если по какой-то причине мы хотим получить все переменные, доступные на пути, мы можем привязать их к карте
:
http://localhost:8080/spring-mvc-java-2/employeeData/id=1;name=John;contactNumber=2200112334
Этот запрос будет обработан следующим методом:
@GetMapping("employeeData/{employee}")
@ResponseBody
public ResponseEntity<Map<String, String>> getEmployeeData(
@MatrixVariable Map<String, String> matrixVars) {
return new ResponseEntity<>(matrixVars, HttpStatus.OK);
}
Конечно, мы можем ограничить привязку к матричным переменным конкретной части пути. Например, если у нас есть такой запрос:
http://localhost:8080/spring-mvc-java-2/
companyEmployee/id=2;name=Xpto/employeeData/id=1;name=John;
contactNumber=2200112334
И мы хотим получить только все переменные, принадлежащие employeeData
; тогда мы должны использовать в качестве входного параметра это:
@RequestMapping(
value = "/companyEmployee/{company}/employeeData/{employee}",
method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Map<String, String>> getEmployeeDataFromCompany(
@MatrixVariable(pathVar = "employee") Map<String, String> matrixVars) {
...
}
7. Частичная привязка
Помимо простоты, еще одним преимуществом является гибкость, матричные переменные можно использовать множеством различных способов. Например, мы можем получить каждую переменную из каждого сегмента пути. Рассмотрим следующий запрос:
http://localhost:8080/spring-mvc-java-2/
companyData/id=2;name=Xpto/employeeData/id=1;name=John;
contactNumber=2200112334
Если мы хотим знать только имя матричной переменной сегмента
companyData ,
то мы должны использовать в качестве входного параметра следующее:
@MatrixVariable(value="name", pathVar="company") String name
8. Настройка брандмауэра
Если приложение использует Spring Security, то по умолчанию используется StrictHttpFirewall
. Это блокирует запросы, которые кажутся вредоносными, включая матричные переменные с разделителем точкой с запятой.
Мы можем настроить эту реализацию в конфигурации приложения и разрешить такие переменные, отклоняя другие, возможно, вредоносные запросы.
Однако таким образом мы можем открыть приложение для атак. Поэтому мы должны реализовать это только после тщательного анализа приложения и требований безопасности.
9. Заключение
В этой статье показаны некоторые из различных способов использования матричных переменных.
Очень важно понять, как этот новый инструмент может работать со слишком сложными запросами или помочь нам добавить дополнительные параметры для ограничения нашего поиска.
Реализацию всех этих примеров и фрагментов кода можно найти в проекте GitHub — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.