使用背景:如在多端开发时有时会共用同一套接口,但是需要对接口进行区分例访问多加一串url,并且不同端可能获取一些公用信息方式不一样,如pc是一个k值从redis拿取用户登录信息而手机端确实直接解析等等。
解决上述场景问题下列举例解决方案:
方案1:直接新建Controller加串url并继承原url(缺点是麻烦,虽然加url比较灵活但是一般情况下同一端的前边一段url是固定的),值得注意的点是,将子Controller下全部方法设置为切点时若访问未重写的父方法切面是不触发的,具体看下方测试。这里可以用拦截器解决不触发前置通知而无法赋值的问题。
方案2:整个过滤器对统一前缀进行过滤转发,并做一些操作。具体看下方。
首先创建一个Controller
@RestController
@RequestMapping(value="ceshi")
public class CeshiController {
@GetMapping(value = "ceshi")
public String ceshi() {
return "测试";
}
}
创建一个Controller继承上一个Controller
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
}
效果:
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
public String ceshi() {
return "测试11";
}
}
效果:
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
@GetMapping(value = "ceshi11")
public String ceshi() {
return "测试11";
}
}
效果:
访问/to/ceshi/ceshi时报404
访问/to/ceshi/ceshi11时得到重写后返回值
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
@GetMapping(value = "ceshi")
public String ceshi11() {
return "测试11";
}
}
效果:无法启动项目
创建一个切面,将继承Controller所有方法设置为切点
@Aspect
@Component
public class CeshiAspect {
@Pointcut("execution(* ceshi.Controller.Ceshi2Controller.*(..))")
public void demo() {}
@Before("demo()")
public void before(JoinPoint joinPoint){
System.out.println("--------触发前置通知---------");
}
}
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
}
效果:
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
public String ceshi() {
return "测试11";
}
}
效果:
@RestController
@RequestMapping(value="to/ceshi")
public class Ceshi2Controller extends CeshiController{
@GetMapping(value = "ceshi222")
public String ceshi() {
return "测试222";
}
}
效果:
补充:若不希望对方法进行重写,在访问接口时想要提前触发一些方法可使用拦截器。
1.一个原Controller
@RestController
@RequestMapping(value="ceshi")
public class CeshiController {
@GetMapping(value = "ceshi")
public String ceshi(HttpServletRequest request) {
String token = request.getHeader("token");
System.out.println(token);
return "测试";
}
}
2.过滤器工具
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CeshiFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//可能需要请求转发到新的地址
System.out.println("----------过滤----------");
System.out.println("原:"+req.getRequestURI());
System.out.println("新:"+req.getRequestURI().substring(3));
//转发到req.getRequestURI().substring(3)
request.getRequestDispatcher(req.getRequestURI().substring(3)).forward(request,response);
}
}
3.注册过滤器
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CeshiConfigurer implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean jwtFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new CeshiFilter());
registration.setName("CeshiFilter");
//过滤to开头的url
registration.addUrlPatterns("/to/*");
registration.setOrder(1);
return registration;
}
}
访问/to/ceshi/ceshi并设置头信息token为11111
结果:
使用OpenFeign或是Gateway访问接口会出现头信息丢失的情况:解决方法详见:解决方法