摘要:我们可以在处理每次请求的过程中,无需从Controller以及Service中的方法层层传值,只需要直接通过该局部变量取值即可。

本文分享自华为云社区《拦截器中巧用ThreadLocal规避层层传值》,作者:KevinQ。

Web开发中的一点麻烦事

最近,准确地说,是一直都有的一点麻烦事:函数层层传递。什么意思呢?比如说有个很常见的需求描述是:记录用户的某次操作明细。

以在Java的开源框架jfinal中,操作添加一个用户的接口为例,有:

public class XXController() {
public void addUser() {
// 获取操作人
Integer opUserId = Integer.parseInt(getHeader("opUserId"));
// 获取其他参数... service.addUser(...., opUserId);
renderAppMsg("添加用户成功");
}
}

为了记录用户添加的具体操作内容以及信息错误,这个记录用户操作的记录可能需要穿透好层方法。

public class XXService() {
public void addUser(String tel, String name, String password, Integer opUserId) {
checkTel(tel, opUserId); checkName(name, opUserId); checkPassword(password, opUserId);
} public void checkTel(String tel, Integer opUserId) {
check(tel, opUserId);
} publc void check(..., Integer opUserId) {
// ...
}
}

举得这个例子或许不是很恰当,但是相信大家可以理解这个麻烦点在哪里。

函数调用链中的每个方法并不是需要这个参数,而可能仅仅是为了向下个被调用的函数传递这个参数。

那么是否有方法帮助我们来不需要这样逐层传递,从而获取接口请求参数的方法呢。

思考

这有点类似与一个全局变量,但是这个变量对每次请求来说是变化的,那么是否有一种方式能够让我们来保存这样一种:针对每次请求的全局变量呢?

在最近学习Shiro的过程中,以及学习若依开源框架的过程中,我们发现其均使用到了一个强大的Java类:ThreadLocal。

shiro使用ThreadLocal是用来保存当前登录对象,若依框架中,其中所使用的分页插件PageUtil使用ThreadLocal保存请求参数中的pageNum与pageSize等分页参数。因此我们是不是也可以使用ThreadLocal来达到同样的目的。

在拦截器中使用ThreadLocal暂存请求参数

为此,我们来尝试一下,通过ThreadLocal保存请求参数,通过拦截器我们可以拦截每次请求,如下是实现方式:

package com.holdoa.core.interceptor;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation; import javax.servlet.http.HttpServletRequest; public class RequestPool implements Interceptor { public static ThreadLocal<HttpServletRequest> localRequest= new ThreadLocal<>(); @Override
public void intercept(Invocation inv) {
localRequest.set(inv.getController().getRequest());
inv.invoke();
localRequest.remove();
} public static HttpServletRequest getRequest() {
return localRequest.get();
}
}

我们通过ThreadLocal将整个请求暂存起来,当然,为了节约内存,也可以只保存使用频次高的通用参数,比如当前登录人的信息等等。

使用参数

使用时,只需要我们通过这个线程局部变量取值即可:

String para = RequestPool.localRequest.get().getParameter("username");

如此,我们便可以在处理每次请求的过程中,无需从Controller以及Service中的方法层层传值,只需要直接通过该局部变量取值即可。

点击关注,第一时间了解华为云新鲜技术~

最新文章

  1. Java中的垃圾回收
  2. 54. Android中adb常用命令及应用常用目录
  3. 帮助理解委托、匿名委托、Lambda表达式还有事件
  4. Oracle里SID、SERVICE_NAME
  5. Java IO流系统整理
  6. 大话数据结构(十一)java程序——串
  7. 获取本机外网ip和内网ip
  8. 关于 zend studio 中有些php 内置函数没有提示,或是有‘小黄色感叹号’
  9. PHP 用session与gd库实现简单验证码生成与验证的类
  10. (cljs/run-at (JSVM. :browser) &quot;搭建刚好可用的开发环境!&quot;)
  11. oracle运行速度与效率高的秘密
  12. 校验ISBN的方法
  13. T470p VS 2017 上运行 VS 2015 + Qt 5.6.2 + GLSL 400
  14. 华为mate10 UA
  15. j2ee课程设计—基于activiti的请休假系统
  16. 关于运行python脚本产生__pycache__
  17. Codeforces 1038 E - Maximum Matching
  18. eclipse gradle插件 org.gradle.tooling.GradleConnectionException: Could not install Gradle distribution from &#39;https://services.gradle.org/distributions/gradle-3.4-bin.zip&#39;.
  19. 金老师的经典著作《一个普通IT人的十年回顾》
  20. 【题解】 bzoj2115: [Wc2011] Xor (线性基+dfs)

热门文章

  1. 应用程序application和库工程library之间的切换
  2. .NET宝藏API之:OutputFormatter,格式化输出对象
  3. [AcWing 779] 最长公共字符串后缀
  4. Docker从入门到放弃(1) Docker简介与安装
  5. [题解] 51 nod 1340 地铁环线
  6. [题解] 序列(sequence)
  7. Java安全之SnakeYaml反序列化分析
  8. Blazor和Vue对比学习(基础1.3):属性和父子传值
  9. 什么叫做 SSO
  10. JavaScript中if语句优化和部分语法糖小技巧推荐