使用HttpServletResponse实现curl接口时控制台输出(续)

发布时间 2023-09-26 23:23:14作者: 飞鸟_Asuka

上一篇文章的问题

在上一篇文章 Spring Boot RestController接口如何输出到终端 中讨论了如何使用 HttpSerlvetResponse 写入输出流,使应急接口通过 curl 调用时可以在控制台输出信息,使运维人员知道命令执行情况。

但是上一篇文章的问题是,HttpServletResponse 是 Controller 的参数,这就使得如果要在其调用的 Service 方法中也要实现控制台输出,就必须让所有涉及到的 Service 方法都带上 HttpServletResponse 参数,这对业务的侵入实在太大,对于实际业务可能包含多个 Service、Component 之间的相互引用,改造成本是不可容忍的。

本文的解决思路

那么笔者就在想,如何构造一个全局的 HttpServletResponse 对象,使它能够在各个 Controller、Service、Component 之前传递呢?经过查阅资料发现,HttpServletResponse 对象本身是可以被 @Autowired@Resource 注解注入的!那么我们就可以构造一个带有自动注入的 HttpServletResponse 对象的 Component,然后在其他所有需要使用的地方去自动注入这个 Component 即可。

代码

代码实现如下:

@Component
public class WebUtil {
    @Resource
    private HttpServletResponse httpServletResponse;

    public void output(String message) {
        if (httpServletResponse == null) {
            return;
        }
        try {
            httpServletResponse.setContentType("text/plain;charset=utf-8");
            httpServletResponse.setCharacterEncoding("UTF-8");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println(message);
            writer.flush();
        } catch (Exception e) {
            return;
        }
    }
}

由于我们的目的只是为了实现控制台输出,所以如果该方法抛出异常(主要是 IOExceptionIllegalStatesException),那么直接返回即可。这个问题主要出在定时任务中,因为定时任务是不含 HttpServletResponse 对象的,如果在定时任务中调用该方法的时候会抛出 IllegalStatesException

在要使用该方法的类中使用自动注入,注入 WebUtil 类,然后使用它的对象(而不是这个类本身)的output方法即可。

@Service
@Slf4j
public class TestServiceImpl implements TestService {
    @Resource
    private WebUtil webUtil;

    @Override
    public boolean emergencyOperation() throws IOException {
        log.info("开始执行应急操作任务");
        webUtil.output( "开始执行应急操作任务");
        for (int i = 0; i < 20; i++) {
            webUtil.output( "完成第" + (i+1) + "批次");
            log.info("完成第 {} 批次", i+1);
            try {
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                log.warn("应急操作任务失败");
                webUtil.output( "应急操作任务失败");
                return false;
            }
        }
        log.info("完成应急操作任务");
        webUtil.output( "应急操作任务完成");
        return true;
    }
}

经过测试发现,curl调用接口可以实现控制台输出,定时任务也执行正常,没有预期外的异常产生。