2017-08-09 2 views
0

Ich schreibe eine einfache Proxy-App, und möchte zugeordnete URL von meinem Controller behandelt werden, aber andere URL (enthält Fehler) kann an eine andere Adresse weitergeleitet werden. Also benutze ich Filter anstatt HandlerInterceptorAdapter, die nicht aufgerufen werden kann, wenn die resourece nicht gefunden wird, weil bestimmte "resourece path handler" es behandelt.Wie bekomme ich die HandlerMethod eine HttpServletRequest in einem Filter

Erwartung

http://localhost:8090/upload.html>Filter>http://localhost:8092/upload.html
http://localhost:8090/files/upload>Controller>http://localhost:8092/files/upload

Nicht

http://localhost:8090/upload.html>Filter>http://localhost:8092/upload.html
http://localhost:8090/files/upload>Controller>http://localhost:8092/files/upload

Oder

http://localhost:8090/upload.html>Interceptor>http://localhost:8090/error Nicht gefunden http://localhost:8090/files/upload>Filter>http://localhost:8092/files/upload

Demo

ich ein Filter in meiner Unterklasse von WebMvcConfigurerAdapter einrichten.

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Bean 
    private javax.servlet.Filter proxyFilter() { 
     return new OncePerRequestFilter() { 
      @Override 
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
       System.out.println("[doFilterInternal]isCommitted=" + response.isCommitted() + ", URI = " + request.getRequestURI()); 
       // if(!isRequestMappedInController(request, "my.pakcage")) 
       httpProxyForward(request, response); 
      } 
     }; 
    } 

// @Bean 
// private FilterRegistrationBean loggingFilterRegistration() { 
//  FilterRegistrationBean registration = new FilterRegistrationBean(proxyFilter()); 
//  registration.addUrlPatterns("/**"); 
//  return registration; 
// } 

    Override 
    public void addInterceptors(InterceptorRegistry registry) { 
     registry.addInterceptor(new HandlerInterceptorAdapter() { 
      @Override 
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
       // How I determine a controller has handled the request in my interceptor? 
       if (handler instanceof HandlerMethod) { 
        HandlerMethod handlerMethod = ((HandlerMethod) handler); 
        if (handlerMethod.getMethod().getDeclaringClass().getName().startsWith("nxtcasb.casbproxy")) { 
         System.out.println("[preHandle]dealt: request uri = " + request.getRequestURI() + ", HandlerMethod = " + ((HandlerMethod) handler).getMethod()); 
         return true; 
        } else { 
         System.out.println("[preHandle]isCommitted=" + response.isCommitted() + ", HandlerMethod = " + ((HandlerMethod) handler).getMethod()); 
        } 
       } 
       // act as an api-gateway 
       System.out.println("[preHandle]undealt: request uri = " + request.getRequestURI() + ", handler = " + handler); 

       //ModelAndView modelView = new ModelAndView("redirect: http://www.bing.com"); 
       //throw new ModelAndViewDefiningException(modelView); 
       httpProxyForward(request, response); 
       return false; 
      } 

      @Override 
      public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
       if (handler instanceof HandlerMethod) { 
        System.out.println("[postHandle]dealt: uri = " + request.getRequestURI() + ", handler = " + ((HandlerMethod) handler).getMethod()); 
       } else { 
        System.out.println("[postHandle]undealt uri = " + request.getRequestURI() + ", handler = " + handler); 
       } 
      } 
     }).addPathPatterns("/**", "/error"); 
    } 

    /** 
    * this is the same as <mvc:default-servlet-handler/> <!-- This tag allows for mapping the DispatcherServlet to "/" --> 
    * 
    * @param configurer 
    */ 
    @Override 
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
     configurer.enable(); 
    } 

    @Override 
    public void addResourceHandlers(ResourceHandlerRegistry registry) { 
     //registry.addResourceHandler("/**").addResourceLocations("classpath:/public"); 
    } 

    protected void httpProxyForward(HttpServletRequest request, HttpServletResponse response) { 
     HttpClient httpClient = CreateHttpClient(); 
     HttpUriRequest targetRequest = null; 
     HttpResponse targetResponse = null; 
     try { 
      targetRequest = createHttpUriRequest(request); 
      targetResponse = httpClient.execute(targetRequest); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      // make sure the entire entity was consumed, so the connection is released 
      if (targetResponse != null) { 
       EntityUtils.consumeQuietly(targetResponse.getEntity()); // @since 4.2 
       //Note: Don't need to close servlet outputStream: 
       // http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter 
      } 
     } 
    } 
} 

Die api url /files/upload:

@RestController 
@RequestMapping(value = "/files") 
public class FileUploadProxyController { 

    private static final Logger logger = LoggerFactory.getLogger(FileUploadProxyController.class); 

    @RequestMapping(value = "/upload", method = RequestMethod.POST) 
    public ResponseEntity upload(HttpServletResponse response, HttpServletRequest request) { 
     try { 
      MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; 
      Iterator<String> it = multipartRequest.getFileNames(); 
      MultipartFile multipart = multipartRequest.getFile(it.next()); 
      String fileName = multipart.getOriginalFilename(); 

      File dir = new File("files", "proxy-uploaded"); 
      dir.mkdirs(); 

      logger.debug("current dir = {}, uploaded dir = {}", System.getProperty("user.dir"), dir.getAbsolutePath()); 

      File file = new File(dir, fileName); 
      Files.copy(multipart.getInputStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); 
      //FileCopyUtils.copy(multipart.getInputStream()) 

//   byte[] bytes = multipart.getBytes(); 
//   BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream("upload" + fileName)); 
//   stream.write(bytes); 
//   stream.close(); 

      RestTemplate restTemplate = new RestTemplate(); 
      SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 
      //// if Spring version < 3.1, see https://jira.springsource.org/browse/SPR-7909 
      // requestFactory.setBufferRequestBody(false); 
      restTemplate.setRequestFactory(requestFactory); 

      String url = "http://localhost:8092/files/upload"; 

      // [resttemplate multipart post](https://jira.spring.io/browse/SPR-13571) 
      // [Spring RestTemplate - how to enable full debugging/logging of requests/responses?](https://stackoverflow.com/questions/7952154/spring-resttemplate-how-to-enable-full-debugging-logging-of-requests-responses?rq=1) 

      MultiValueMap<String, Object> param = new LinkedMultiValueMap<>(); 
      param.add("file", new FileSystemResource(file)); 
      param.add("param1", fileName); 
      param.add("param2", "Leo"); 

      HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String,Object>>(param); 
      ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); 

      //String string = restTemplate.postForObject(url, param, String.class); 

      //ResponseEntity e = restTemplate.exchange(url, HttpMethod.POST, 
      //  new HttpEntity<Resource>(new FileSystemResource(file)), String.class); 

      return responseEntity; 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return new ResponseEntity("Upload failed", HttpStatus.BAD_REQUEST); 
     } 
    } 

    @RequestMapping("/hello") 
    public String hello() { 
     return "hello word"; 
    } 
} 

Antwort

0

Afer Lesen Spring mvc autowire RequestMappingHandlerMapping oder Get destination controller from a HttpServletRequest

Der folgende Code funktioniert:

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    // https://stackoverflow.com/questions/129207/getting-spring-application-context 
    @Autowired 
    private org.springframework.context.ApplicationContext appContext; 

    private static final String MY_CONTROLLER_PACKAGE_NAME = "nxtcasb.casbproxy"; 

    @Bean 
    protected javax.servlet.Filter proxyFilter() { 
     return new OncePerRequestFilter() { 
      @Override 
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 
        throws ServletException, IOException { 

       HandlerMethod handlerMethod = null; 
       try { 
        RequestMappingHandlerMapping req2HandlerMapping = (RequestMappingHandlerMapping) appContext.getBean("requestMappingHandlerMapping"); 
        // Map<RequestMappingInfo, HandlerMethod> handlerMethods = req2HandlerMapping.getHandlerMethods(); 
        HandlerExecutionChain handlerExeChain = req2HandlerMapping.getHandler(request); 
        if (Objects.nonNull(handlerExeChain)) { 
         handlerMethod = (HandlerMethod) handlerExeChain.getHandler(); 
         if (handlerMethod.getBeanType().getName().startsWith(MY_CONTROLLER_PACKAGE_NAME)) { 
          filterChain.doFilter(request, response); 
          return; 
         } 
        } 
       } catch (Exception e) { 
        logger.warn("Lookup the handler method", e); 
       } finally { 
        logger.debug("URI = " + request.getRequestURI() + ", handlerMethod = " + handlerMethod); 
       } 

       httpProxyForward(request, response); 
      } 
     }; 
    } 

// @Bean 
// private FilterRegistrationBean loggingFilterRegistration() { 
//  FilterRegistrationBean registration = new FilterRegistrationBean(proxyFilter()); 
//  registration.addUrlPatterns("/**"); 
//  return registration; 
// } 

    /** 
    * this is the same as <mvc:default-servlet-handler/> <!-- This tag allows for mapping the DispatcherServlet to "/" --> 
    * 
    * @param configurer 
    */ 
    @Override 
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
     configurer.enable(); 
    } 

    @Override 
    public void addResourceHandlers(ResourceHandlerRegistry registry) { 
     //registry.addResourceHandler("/**").addResourceLocations("classpath:/public"); 
    } 

    protected void httpProxyForward(HttpServletRequest request, HttpServletResponse response) { 
     HttpClient httpClient = CreateHttpClient(); 
     HttpUriRequest targetRequest = null; 
     HttpResponse targetResponse = null; 
     try { 
      targetRequest = createHttpUriRequest(request); 
      targetResponse = httpClient.execute(targetRequest); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      // make sure the entire entity was consumed, so the connection is released 
      if (targetResponse != null) { 
       EntityUtils.consumeQuietly(targetResponse.getEntity()); // @since 4.2 
       //Note: Don't need to close servlet outputStream: 
       // http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter 
      } 
     } 
    } 
} 
Verwandte Themen