问题描述
我有一个方案,Spring应用程序使用自定义ContentType和JSON负载接收HTTP请求。一部分有效载荷是服务定位器调用中使用的密钥。
有效载荷:
{ "service_id": "ServiceA" }
我想使用@RequestScope
的Spring @Bean
检查请求并返回/注入正确的服务。
类似的东西:
@Configuration
public class ServiceLocatorConfig {
@Bean
@RequestScope
public SomeService serviceByKey(WebRequest request,Map<String,SomeService> services) {
// This is where I need a hand -- how would I get the request body?
String serviceId = readServiceIdFromrequestBody(request);
return services[key];
}
}
到目前为止,我已经在@Bean
中收到请求,但是获得请求正文没有任何成功。我得到的最接近的结果是盲目尝试ContentCachingRequestWrapper
,但是在致电null
时我总是收到.getContentAsByteArray()
。听起来好像还需要表单编码的主体,因此自定义内容类型(在这种情况下无法修改)可能会带来更多麻烦。
Spring Bean如何检查HTTP请求?
解决方法
为了实现您需要的功能,您可以使用WebFilter
作为进入请求的拦截器,在到达services
之前,它可以访问json有效负载,并且您可以读取传入的参数并调用适当的组件以处理请求。
您的WebFilter
类将类似于该类(在本示例中,我们正在拦截对'/ rest / *'的请求:
import java.io.IOException;
import java.nio.charset.Charset;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
@WebFilter(urlPatterns = "/rest/*")
public class DoSomethingInterceptor implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
throws IOException,ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
//Parse the json from request
String jsonPayload = IOUtils.toString(request.getInputStream(),Charset.defaultCharset());
IncomingRequest jsonRequest = mapper.readValue(jsonPayload,IncomingRequest.class);
//Read the service parameter
String serviceClass = jsonRequest.getServiceClass();
//Map the incoming service to your service class
Class<MyService> myServiceClass = ServiceType.get(serviceClass);
//Get the bean from Spring context
DoSomething bean =
(DoSomething) WebApplicationContextUtils.
getRequiredWebApplicationContext(filterConfig.getServletContext()).
getBean(myServiceClass);
//Call the method in the service
String resultFromService = bean.doSomething();
//Finally you will copy the result from service to the http response
response.getOutputStream().write(resultFromService);
return;
}
}
也请记住在Spring上注册您的WebFilter,对于SpringBoot应用程序,可以像下面的示例中那样完成:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
@Bean
@Autowired
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new DoSomethingInterceptor());
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/rest/*");
filterRegistration.setUrlPatterns(urlPatterns);
return filterRegistration;
}