在Spring启动应用程序中添加HttpRequest拦截器的正确方法是什么?我想要做的是为每个http请求记录请求和响应。
Spring启动文档根本不涉及此主题。 (http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/)
我找到了一些关于如何对旧版本的spring执行相同操作的Web示例,但这些示例与applicationcontext.xml一起使用。请帮忙。
答案 0 :(得分:126)
由于您使用的是Spring Boot,我认为您更愿意尽可能依赖Spring的自动配置。要添加其他自定义配置(如拦截器),只需提供WebMvcConfigurerAdapter
的配置或bean。
以下是配置类的示例:
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Autowired
HandlerInterceptor yourInjectedInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(...)
...
registry.addInterceptor(getYourInterceptor());
registry.addInterceptor(yourInjectedInterceptor);
// next two should be avoid -- tightly coupled and not very testable
registry.addInterceptor(new YourInterceptor());
registry.addInterceptor(new HandlerInterceptor() {
...
});
}
}
注意如果要保留Spring Boots auto configuration for mvc,请不要使用@EnableWebMvc对其进行注释。
答案 1 :(得分:57)
WebMvcConfigurerAdapter
将被弃用。从Javadoc:
@deprecated从5.0 {@link WebMvcConfigurer}有默认方法(制作 可以通过Java 8基线实现,并且可以直接实现而无需此适配器
如上所述,您应该做的是实施WebMvcConfigurer
并覆盖addInterceptors
方法。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyCustomInterceptor());
}
}
答案 2 :(得分:23)
要将拦截器添加到弹簧启动应用程序,请执行以下操作
创建拦截器类
public class MyCustomInterceptor implements HandlerInterceptor{
//unimplemented methods comes here. Define the following method so that it
//will handle the request before it is passed to the controller.
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response){
//your custom logic here.
return true;
}
}
定义配置类
@Configuration
public class MyConfig extends WebMvcConfigurerAdapter{
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
}
}
多数民众赞成。现在,您的所有请求都将通过MyCustomInterceptor的preHandle()方法中定义的逻辑。
答案 3 :(得分:9)
我有同样的问题,即WebMvcConfigurerAdapter已被弃用。当我搜索示例时,我几乎找不到任何实现的代码。这是一段工作代码。
创建一个扩展HandlerInterceptorAdapter
的类import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import me.rajnarayanan.datatest.DataTestApplication;
@Component
public class EmployeeInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(DataTestApplication.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
String x = request.getMethod();
logger.info(x + "intercepted");
return true;
}
}
然后实现WebMvcConfigurer接口
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import me.rajnarayanan.datatest.interceptor.EmployeeInterceptor;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
EmployeeInterceptor employeeInterceptor ;
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(employeeInterceptor).addPathPatterns("/employee");
}
}
答案 4 :(得分:7)
您也可以考虑使用开源SpringSandwich库,它允许您直接在Spring Boot控制器中注释哪些拦截器可以应用,就像您为url路由注释一样。
这样,SpringSandwich的方法和类注释很容易在重构中幸存下来,并且很清楚在哪里应用了什么。 (披露:我是作者)。
答案 5 :(得分:2)
由于对此的所有响应都使用了现已弃用的抽象WebMvcConfigurer适配器而不是WebMvcInterface适配器(已由@sebdooe指出),因此,这是一个带有Interceptor的SpringBoot(2.1.4)应用程序的最小工作示例:
Minimal.java:
@SpringBootApplication
public class Minimal
{
public static void main(String[] args)
{
SpringApplication.run(Minimal.class, args);
}
}
MinimalController.java:
@RestController
@RequestMapping("/")
public class Controller
{
@GetMapping("/")
@ResponseBody
public ResponseEntity<String> getMinimal()
{
System.out.println("MINIMAL: GETMINIMAL()");
return new ResponseEntity<String>("returnstring", HttpStatus.OK);
}
}
Config.java:
@Configuration
public class Config implements WebMvcConfigurer
{
//@Autowired
//MinimalInterceptor minimalInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(new MinimalInterceptor());
}
}
MinimalInterceptor.java:
public class MinimalInterceptor extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle(HttpServletRequest requestServlet, HttpServletResponse responseServlet, Object handler) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR PREHANDLE CALLED");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR POSTHANDLE CALLED");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception
{
System.out.println("MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED");
}
}
按广告宣传
输出将为您提供以下信息:
> Task :Minimal.main()
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.4.RELEASE)
2019-04-29 11:53:47.560 INFO 4593 --- [ main] io.minimal.Minimal : Starting Minimal on y with PID 4593 (/x/y/z/spring-minimal/build/classes/java/main started by x in /x/y/z/spring-minimal)
2019-04-29 11:53:47.563 INFO 4593 --- [ main] io.minimal.Minimal : No active profile set, falling back to default profiles: default
2019-04-29 11:53:48.745 INFO 4593 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-04-29 11:53:48.780 INFO 4593 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-04-29 11:53:48.781 INFO 4593 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-04-29 11:53:48.892 INFO 4593 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-29 11:53:48.893 INFO 4593 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1269 ms
2019-04-29 11:53:49.130 INFO 4593 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-29 11:53:49.375 INFO 4593 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-29 11:53:49.380 INFO 4593 --- [ main] io.minimal.Minimal : Started Minimal in 2.525 seconds (JVM running for 2.9)
2019-04-29 11:54:01.267 INFO 4593 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-29 11:54:01.267 INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-04-29 11:54:01.286 INFO 4593 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 19 ms
MINIMAL: INTERCEPTOR PREHANDLE CALLED
MINIMAL: GETMINIMAL()
MINIMAL: INTERCEPTOR POSTHANDLE CALLED
MINIMAL: INTERCEPTOR AFTERCOMPLETION CALLED
答案 6 :(得分:1)
我在这个站点上找到了一个很好的教程,介绍了如何使用注释将请求拦截器添加到特定控制器:
https://programmer.group/how-do-spring-boot-2.x-add-interceptors.html
我知道这个问题是如何向所有请求添加拦截器,这已经得到了回答。我正在搜索使用注释将请求拦截器添加到特定控制器的解决方案,但在 stackoverflow 中找不到解决方案。决定将此内容添加到此问题而不是提出新问题。
定义注解 NeedLogin.class
package com.example.helloSpringBoot.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedLogin {
}
然后定义inceptor类
package com.example.helloSpringBoot.config;
import com.example.helloSpringBoot.annotation.NeedLogin;
import com.example.helloSpringBoot.util.WxUserInfoContext;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Logon interceptor
*
* @Author: Java Fragment
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
//This method is executed before accessing the interface. We only need to write the business logic to verify the login status here to verify the login status before the user calls the specified interface.
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
NeedLogin needLogin = ((HandlerMethod) handler).getMethodAnnotation(NeedLogin.class);
if (null == needLogin) {
needLogin = ((HandlerMethod) handler).getMethod().getDeclaringClass()
.getAnnotation(NeedLogin.class);
}
// Check login if you have login validation annotations
if (null != needLogin) {
WxUserInfoContext curUserContext = (WxUserInfoContext) request.getSession()
.getAttribute("curUserContext");
//If session No, not logged in.
if (null == curUserContext) {
response.setCharacterEncoding("UTF-8");
response.getWriter().write("Not logged in!");
return false;
}
}
}
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
然后将inceptor添加到WebConfig中
package com.example.helloSpringBoot.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* WebConfig
*
* @Author: Java Fragment
*
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// Custom interceptor, add intercept path and exclude intercept path
registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
}
}
最后你可以使用新的注解@NeedLogin 自由使用新的拦截器
package com.example.helloSpringBoot.controller;
import com.example.helloSpringBoot.annotation.NeedLogin;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
/**
* Testing does not require login
*
*
*/
@RequestMapping("/testNoLogin")
public String testNoLogin (){
return "The call is successful, this interface does not need login validation!-Java Broken read!";
}
/**
* Testing requires login
*
*
*/
@NeedLogin
@RequestMapping("/testNeedLogin")
public String testNeedLogin (){
return "testNeedLogin!";
}
}
答案 7 :(得分:0)
下面是一个实现,我用它来拦截每个HTTP请求,然后再将其返回。通过此实现,我还可以在一个点上随请求传递任何标头值。
public class HttpInterceptor implements ClientHttpRequestInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution
) throws IOException {
HttpHeaders headers = request.getHeaders();
headers.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
traceRequest(request, body);
ClientHttpResponse response = execution.execute(request, body);
traceResponse(response);
return response;
}
private void traceRequest(HttpRequest request, byte[] body) throws IOException {
logger.info("===========================Request begin======================================");
logger.info("URI : {}", request.getURI());
logger.info("Method : {}", request.getMethod());
logger.info("Headers : {}", request.getHeaders() );
logger.info("Request body: {}", new String(body, StandardCharsets.UTF_8));
logger.info("==========================Request end=========================================");
}
private void traceResponse(ClientHttpResponse response) throws IOException {
logger.info("============================Response begin====================================");
logger.info("Status code : {}", response.getStatusCode());
logger.info("Status text : {}", response.getStatusText());
logger.info("Headers : {}", response.getHeaders());
logger.info("=======================Response end===========================================");
}}
下面是Rest模板Bean
@Bean
public RestTemplate restTemplate(HttpClient httpClient)
{
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate= new RestTemplate(requestFactory);
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors))
{
interceptors = new ArrayList<>();
}
interceptors.add(new HttpInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}