Как можно сопоставить пользовательские / dunami c запросы к данному контроллеру на основе поиска в репозитории?
Вариант использования - это функция, подобная CMS, в веб-платформе, где определенные шаблоны URL («страницы»), хранящиеся в БД, должны обрабатываться отдельным контроллером PageController.java
. Эти шаблоны не обязательно известны во время компиляции, и их также можно добавлять и изменять во время развертывания приложения (таким образом, оно не может управляться аннотациями).
Я пытался сопоставить контроллер с " ** "(см. ниже), но это не сработало по двум причинам: во-первых, все другие запросы были разрешены с использованием того же метода контроллера (я надеялся, что он будет использовать" ** "в качестве запасного варианта и сначала попробует другие), и он также заканчивал тем, что разрешал все запросы к моим статическим файлам / файлам активов на этот контроллер (что приводило к нежелательным 404 ответам).
@Controller
public class PageController {
@Inject
private PageService pageService;
@RequestMapping(value = "**", method = RequestMethod.GET)
public String getPage(Model model, HttpServletRequest request, @CurrentUser User user) {
String path = request.getRequestURI();
Page page = this.pageService.getByPath(path, user);
if (page == null) {
throw new NotFoundException();
}
model.addAttribute("page", page);
return "web/page";
}
}
Временное решение / модификация вышеуказанного метода до сих пор сопоставить предварительно определенные URL-префиксы с этим контроллером (например, /page/**
, /info/**
, /news/**
et c), но это не элегантное решение, которое добавляет произвольные ограничения к системе, которые я сейчас пытаюсь устранить ,
В настоящее время я использую Spring Boot 2.0. В дополнение к наивному отображению в **
в обычном @Controller
классе (с использованием @RequestMapping
-аннотации) я также попытался настроить SimpleUrlHandlerMapping
следующим образом:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Inject
private PageDao pageDao;
@Bean
public PageController pageController() {
return new PageController();
}
@Bean
public SimpleUrlHandlerMapping pageUrlHandlerMapping() {
SimpleUrlHandlerMapping pageUrlHandlerMapping = new SimpleUrlHandlerMapping();
PageController pageController = this.pageController();
Map<String, Object> urlMap = this.pageDao.findAll().stream()
.map(Page::getNormalizedSlug)
.collect(Collectors.toMap(Function.identity(),
slug -> pageController, (existing, duplicate) -> existing));
pageUrlHandlerMapping.setUrlMap(urlMap);
pageUrlHandlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE); // <- Cannot be LOWEST_PRECEDENCE for some reason...
return pageUrlHandlerMapping;
}
}
public class PageController implements Controller {
@Inject
private PageService pageService;
@Inject
private DmaWebControllerAdvice controllerAdvice;
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
User user = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof User) {
user = (User) principal;
}
String path = request.getRequestURI();
Page page = this.pageService.getByPath(path, user);
if (page == null) {
throw new NotFoundException();
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("web/page");
modelAndView.addObject("page", page);
controllerAdvice.globalModelAttributes(modelAndView.getModel(), null);
return modelAndView;
}
}
Этот подход технически работает, но список страниц каким-то образом придется перезагружать в SimpleUrlHandlerMapping при каждом изменении одной из страниц (я не совсем уверен, как это сделать). Это также возможно перезаписывает некоторую конфигурацию Spring Boot по умолчанию, которую я в идеале хотел бы сохранить. Он также имеет некоторые недостатки по сравнению с разрешением контроллеров с использованием @Controller
и @RequesMapping
, поскольку в настоящее время я внедряю определенные данные во все представления, разрешенные таким образом (в основном данные модели, используемые в общем дизайне сайта, такие как меню, быстрые ссылки и т. 1029 *). В вышеупомянутой попытке мне пришлось установить их с помощью отдельного вызова на controllerAdvice-globalModelAttributes()
.
. То, что я ищу, - это решение, в котором мой репозиторий запрашивается для потенциальных совпадений страниц во время выполнения, и если это так. действительный, тогда запрос будет обработан соответствующим контроллером страниц. Является ли пользовательская реализация HandlerMapping способом сделать это? И если нет, то как мне решить эту проблему? И если сделать отдельное HandlerMapping для страниц, как мне добавить / зарегистрировать это в моей конфигурации без перезаписи по умолчанию, предоставляемой Spring?