【问题标题】:Spring Boot - Database based request mappingSpring Boot - 基于数据库的请求映射
【发布时间】:2023-04-07 16:21:02
【问题描述】:

使用 Spring Boot 2 我想创建一个基于数据库的请求映射。我的意思是,我不想在控制器上使用数百个 @RequestMapping 注释,而是将映射存储在数据库表中。 每个控制器都实现了一个带有执行方法的接口,所以我只需在数据库中搜索相关的控制器并在其上调用执行方法。

目前我有一个CustomController 和一个@RequestMapping("*"),这个控制器找到真正的控制器并调用执行方法。它有效,但不是一个好的解决方案。例如,在拦截器级别,处理程序对象是CustomController,而不是真正的控制器。

也许我应该像这样使用SimpleUrlHandlerMapping

@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
    SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();

    Map<String, Object> urlMap = new HashMap<>();
    urlMap.put("/dashboard", __???__);
    simpleUrlHandlerMapping.setUrlMap(urlMap);

    return simpleUrlHandlerMapping;
}

但在这种情况下,我不知道如何填充urlMap 中的bean 值。例如在“/dashboard”的情况下如何放置DashboardController.execute()

也许有更好的解决方案?

更新 1

我创建了一个像这样的SimpleUrlHandlerMapping

@Configuration
public class SimpleUrlHandlerMappingConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        Map<String, Object> urlMap = new HashMap<>();

        String path = "/dashboard";
        String controllerName = "dashboardController";

        Object myController = context.getBean(controllerName);

        urlMap.put(path, myController);
        simpleUrlHandlerMapping.setUrlMap(urlMap);

        return simpleUrlHandlerMapping;
    }

}

还有一个CustomHandlerAdapter

@Configuration
public class CustomHandlerAdapter implements HandlerAdapter {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public boolean supports(Object handler) {
        logger.debug("Test handler: " + handler);
        if (handler instanceof PageController) {
            return true;
        }
        return false;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("Custom handle");
        ModelAndView mv = new ModelAndView();
        String viewName = ((PageController)handler).execute2(request, response);
        mv.setViewName(viewName);
        return mv;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }
}   

但根据日志,SimpleUrlHandlerMapping 似乎无法正常工作:

- DispatcherServlet with name 'dispatcherServlet' processing GET request for [/dashboard]
- Looking up handler method for path /dashboard
- Did not find handler method for [/dashboard]
- Matching patterns for request [/dashboard] are [/**]
- URI Template variables for request [/dashboard] are {}
- Mapping [/dashboard] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@4bc6044e]]] and 1 interceptor
- Test handler: ResourceHttpRequestHandler [locations=[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@4bc6044e]]
- Last-Modified value for [/dashboard] is: -1   

更新 2

感谢@M. Deinum 我已经更新了我的代码并有了一个可行的解决方案。 请注意,@EnableWebMvc 是引入的,以后可能会导致其他副作用。

SimpleUrlHandlerMappingConfig:

@Configuration()
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleUrlHandlerMappingConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        Map<String, Object> urlMap = new HashMap<>();

        String path = "/dashboard";
        String controllerName = "dashboardController";

        Object myController = context.getBean(controllerName);

        urlMap.put(path, myController);
        simpleUrlHandlerMapping.setUrlMap(urlMap);

        return simpleUrlHandlerMapping;
    }

}

CustomHandlerAdapter:

@Component
public class CustomHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        if (handler instanceof PageController) {
            return true;
        }
        return false;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ModelAndView mv = new ModelAndView();
        String viewName = ((PageController)handler).execute2(request, response);
        mv.setViewName(viewName);
        return mv;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }
}   

还有 WebConfig:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/style/**")
                .addResourceLocations("classpath:" + "/static/style/");
        registry.addResourceHandler("/js/**")
                .addResourceLocations("classpath:" + "/static/js/");

    }
}   

【问题讨论】:

  • 创建一个自定义的HandlerAdapter,它知道如何处理您的自定义接口(即调用execute 方法)。对于映射,请创建自定义 HandlerMapping 或简单地使用数据库中的数据填充 SimpleUrlHandlerMapping。尽管如此,您仍需要为您的班级定制一个 HandlerAdapter
  • @M.Deinum 谢谢,我已经尝试过你的建议,但我似乎仍然遗漏了一些东西,正如你在我更新的帖子中看到的那样。
  • 您的CustomHandlerAdapter 不应该是@Configuration,而应该是@Component 或只是您配置中的常规@Bean。您还想在SimpleUrlHandlerMapping 上设置order,您可能希望使用最高顺序Ordered.HIGHEST_PRECEDENCE。否则它将在其他处理程序映射之后执行。
  • 如果我将@EnableWebMvc 注释添加到我的WebConfig 类,则基本概念有效,但在这种情况下,提供静态内容的服务停止工作。
  • 我已经为我的WebConfig 添加了一个resourceHandlers,现在它可以与@EnableWebMvc 一起正常工作,但是我不知道@EnableWebMvc 会导致什么其他副作用。

标签: spring spring-mvc spring-boot


【解决方案1】:

如果我理解正确,您想摆脱简单的操作(get/post/put/delete)——而那些只调用存储库中的保存/查找/删除方法。 如果是这种情况,我建议使用Spring Data REST

【讨论】:

    【解决方案2】:

    我在这里发布了最终解决方案(感谢 M. Deinum),也许可以帮助其他人。

    所以我只使用SimpleUrlHandlerMapping 创建了一个HandlerMapping

    @Configuration()
    public class SimpleUrlHandlerMappingConfig {
    
        @Autowired
        private ApplicationContext context;
    
        @Bean
        public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
            SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
            Map<String, Object> urlMap = new HashMap<>();
    
            String path = "/dashboard";
            String controllerName = "dashboardController";
    
            Object myController = context.getBean(controllerName);
    
            urlMap.put(path, myController);
            simpleUrlHandlerMapping.setUrlMap(urlMap);
    
            simpleUrlHandlerMapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
    
            return simpleUrlHandlerMapping;
        }
    
    }
    

    还有一个自定义的HandlerAdapter

    @Component
    public class CustomHandlerAdapter implements HandlerAdapter {
    
        @Override
        public boolean supports(Object handler) {
            if (handler instanceof PageController) {
                return true;
            }
            return false;
        }
    
        @Override
        public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            ModelAndView mv = new ModelAndView();
            String viewName = ((PageController)handler).execute2(request, response);
            mv.setViewName(viewName);
            return mv;
        }
    
        @Override
        public long getLastModified(HttpServletRequest request, Object handler) {
            return -1;
        }
    }
    

    请注意,此示例仅演示了没有正确错误处理和实际数据库访问的概念。

    【讨论】:

      猜你喜欢
      • 2019-11-25
      • 2022-01-12
      • 2016-01-04
      • 1970-01-01
      • 2019-05-12
      • 2019-02-03
      • 2019-11-13
      • 2020-04-19
      • 2018-03-18
      相关资源
      最近更新 更多