我已经阅读了许多关于将 HttpServletRequest 传递给方面的不同帖子。但他们都不适合我。这里要解决的用例是将方面应用于服务实现类而不是控制器类并获取请求级别的详细信息。
我创建了一个方面来对自定义注释应用建议,该注释将放置到我需要在其中获取请求 (HttpServletRequest) 的服务类。
我尝试过的几种方法:
您方面中的 Autowire HttpServletRequest 需要为此注册一个 bean,这将失败并给出 IllegalStateException,因为 httpservletrequest 是一个作用域请求 bean
使用RequestContextHolder.getRequestAttributes()获取httpservletrequest会导致null
将切入点与Before suggest一起使用(如下所示)不会让方面工作
@Before("@annotation(com.company.services.annotations.EnableAuth) && args( request, ..)")
public void doBefore(final JoinPoint joinPoint, HttpServletRequest request) throws IOException {
}
我们如何将 HttpServletRequest 注入到服务层?
下面是我的代码:
自定义注释
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface EnableAuth {
}
方面
@Component
@Aspect
public class AccessAdvice {
@Autowired
private AccessTokenSecretConfig accessTokenSecretConfig;
public static final String ACCESS_TOKEN_HEADER = "accessToken";
@Pointcut("@annotation(com.company.services.annotations.EnableAuth)")
public void invokeAnnotation() {}
@Before("invokeAnnotation()")
public void doBefore(final JoinPoint joinPoint) throws IOException {
ServletRequestAttributes t = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest req = t.getRequest();
final String accessToken = req.getHeader(ACCESS_TOKEN_HEADER);
return;
}
}
}
xml配置
<bean id="adminService"
class="com.company.services.impl.AdminServicesImpl" />
<bean id="accessTokenSecretConfig" class="com.company.services.config.AccessTokenSecretConfig"/>
<bean id = "accessAdvice" class = "com.company.services.filters.AccessAdvice"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>
管理控制器
@Path("/v1/admin")
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
public interface AdminController {
@GET
@Path("/check/status")
Response checkStatus(
@BeanParam RequestContextWrapper contextWrapper);
}
管理服务
public class AdminServicesImpl implements AdminController {
@EnableAuth
@Override
public Response checkStatus(RequestContextWrapper contextWrapper) {
return Response.ok().entity("Hello !!").build();
}
}
使用 Spring 注解代替您当前使用的注解怎么样?
package de.scrum_master.spring.q78880567;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface EnableAuth {}
package de.scrum_master.spring.q78880567;
public class RequestContextWrapper {
// Dummy class to make the application compile and run
}
package de.scrum_master.spring.q78880567;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/v1/admin")
public interface AdminController {
@GetMapping("/check/status")
ResponseEntity<?> checkStatus(RequestContextWrapper contextWrapper);
}
package de.scrum_master.spring.q78880567;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AdminControllerImpl implements AdminController {
@EnableAuth
@Override
public ResponseEntity<?> checkStatus(RequestContextWrapper contextWrapper) {
return ResponseEntity.ok().body("my response body");
}
}
package de.scrum_master.spring.q78880567;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component
@Aspect
public class AccessAspect {
// @Autowired
// private AccessTokenSecretConfig accessTokenSecretConfig;
public static final String ACCESS_TOKEN_HEADER = "accessToken";
@Pointcut("@annotation(EnableAuth)")
public void invokeAnnotation() {}
@Before("invokeAnnotation()")
public void doBefore(final JoinPoint joinPoint) {
System.out.println(joinPoint);
ServletRequestAttributes t = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest req = t.getRequest();
System.out.println(req);
final String accessToken = req.getHeader(ACCESS_TOKEN_HEADER);
}
}
package de.scrum_master.spring.q78880567;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
doStuff(appContext);
}
}
private static void doStuff(ConfigurableApplicationContext appContext) {
try {
HttpEntity<String> entity = new HttpEntity<>("my request body");
RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange("http://localhost:8080/v1/admin/check/status", HttpMethod.GET, entity, String.class);
}
catch (RestClientException ignored) {}
}
}
这将记录类似以下内容:
...
execution(ResponseEntity de.scrum_master.spring.q78880567.AdminControllerImpl.checkStatus(RequestContextWrapper))
org.apache.catalina.connector.RequestFacade@16c10558
...