Spring调用Controller某个方法前,先执行Controller中另一个方法

需求

与多个第三方集成,要求每家第三方都需要实现某些接口。
为了验证第三方接口,在程序中有一个Controller类。通过内部调用第三方接口的类,完成验证第三方接口是否实现。
但是,每家的BaseUrl不一样。所以,为了使用方便,我们需要根据请求入参,进行单独处理。且又不想在每个接口方法中去手动调用该处理方法,嫌烦

  • 举例
    • 通过公共方法,来获取BaseUrl,但是每个方法都需要调用该方法。
    • 需求:能不能统一自动完成调用,这样就无需在每个方法中执行该方法。
@RestController
@RequestMapping(value = "checkThirdApi")
@Slf4j
public class AiController {
	// 调用第三方接口的实现类
    @Resource
    private ThirdApp thirdApp;
    
    @Resource
    private HttpServletRequest request;

    private String baseUrl;

    /**
    * 通用方法,每次请求,都会根据请求头的appCode参数
    * 来获取对应第三方App的CallBackUrl地址
    */
    public void settingBaseUrl() {
        String appCode = request.getHeader("appCode");
        try {
            // 根据appCode,获取配置的CallBackURL
            this.baseUrl = configService.getCallBackUrl(appcode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 调用第三方接口,查询当前第三方应用的名称
     */
    @PostMapping(value = "getName")
    public String getThirdName(@RequestBody ParamsVo params) {
    	// 每个Controller接口方法,都需要执行这行代码
		settingBaseUrl();
		
    	// thirdApp在调用时,需要设置 当前第三发APP的请求url,即:baseUrl
        return thirdApp.getThirdName(baseUrl, params);
    }

	// Controller接口中每个方法,都需要执行settingBaseUrl()方法
	@GetMapping(value = "getInfoById")
	public Info getInfoById(String id) {
		settingBaseUrl();
		...
	}

解决思路

使用拦截器(Interceptor)

  • 使用拦截器(Interceptor)来在执行Controller方法之前进行拦截。拦截器可以用于在请求到达Controller之前执行一些特定的逻辑,比如验证用户权限、记录日志等。

使用过滤器(Filter)

  • 过滤器是Servlet规范中的一种组件,它可以在请求到达Servlet之前或响应返回客户端之前对请求和响应进行预处理和后处理。在Spring中,我们可以通过实现javax.servlet.Filter接口来创建自定义的过滤器,然后在Spring配置中注册这个过滤器,从而实现在执行Controller方法前进行一次拦截。

实现RequestBodyAdvice接口

  • 实现RequestBodyAdvice接口后,重写对应方法,此时就可以增强Controller类中的所有被@RequestBody注解的方法

使用自定义切面(Aspect)

  • 切面是Spring框架中的一个重要概念,它可以用来定义横切关注点(cross-cutting concerns),比如日志记录、性能监控、事务管理等。通过定义切面,我们可以在程序的不同位置插入通用的逻辑,而不需要修改原有的代码。

使用@ModelAttribute的注解

  • 它可以用于在执行Controller方法前进行一次拦截。虽然它的主要作用是将方法的返回值绑定到Model中,但是它也可以用于执行一些逻辑,比如数据预处理、权限验证等。

以上解决思路对比

  • 由于是针对某一个具体的Controller类,不需要对其他Controller类进行处理,故考虑耦合性,不使用拦截器过滤器来实现
  • 使用RequestBodyAdvice接口来实现,有局限性,只能增强Controller类中被@RequestBody注解修饰的方法
  • 使用自定义切面方案,其实**@ModelAttribute注解**其原理也是切面,故已经能够满足需求,无需自己实现切面
  • 综上:选择**@ModelAttribute注解**方案

实现

@RestController
@RequestMapping(value = "checkThirdApi")
@Slf4j
public class AiController {
	// 调用第三方接口的实现类
    @Resource
    private ThirdApp thirdApp;
    
    @Resource
    private HttpServletRequest request;

    private String baseUrl;

    // 直接使用@ModelAttribute注解
    // 此时:当前Controller类中的所有方法,都会在执行前,执行该方法
    // 就无需单独在每个方法里进行调用
    @ModelAttribute
    public void settingBaseUrl() {
        String appCode = request.getHeader("appCode");
        try {
            // 根据appCode,获取配置的CallBackURL
            this.baseUrl = configService.getCallBackUrl(appcode);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 调用第三方接口,查询当前第三方应用的名称
     */
    @PostMapping(value = "getName")
    public String getThirdName(@RequestBody ParamsVo params) {
    	// thirdApp在调用时,需要设置 当前第三发APP的请求url,即:baseUrl
        return thirdApp.getThirdName(baseUrl, params);
    }

	// 无需单独调用settingBaseUrl()方法,直接处理逻辑
	@GetMapping(value = "getInfoById")
	public Info getInfoById(String id) {
		// settingBaseUrl();
		...
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值