我正在编写一个简单的代理应用程序,并希望映射的网址将由我的控制器处理,但其他网址(包括错误)可以转发到另一个不同的地址。所以我使用Filter
而不是HandlerInterceptorAdapter
如果找不到resourece则无法调用,因为某些" resourece路径处理程序"处理它。
期望
http://localhost:8090/upload.html
> Filter
> http://localhost:8092/upload.html
http://localhost:8090/files/upload
> Controller
> http://localhost:8092/files/upload
不会
http://localhost:8090/upload.html
> Filter
> http://localhost:8092/upload.html
http://localhost:8090/files/upload
> Controller
> http://localhost:8092/files/upload
或者
http://localhost:8090/upload.html
> Interceptor
> http://localhost:8090/error
未找到
http://localhost:8090/files/upload
> Filter
> http://localhost:8092/files/upload
演示
我在Filter
的子类中设置了WebMvcConfigurerAdapter
。
@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
}
}
}
}
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";
}
}
答案 0 :(得分:0)
阅读Spring mvc autowire RequestMappingHandlerMapping或Get destination controller from a HttpServletRequest
以下代码有效:
@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
}
}
}
}