关于Post请求查询,前端传来的字符串前后有空格的处理
1. 问题起因:
最近办公室在对项目系统进行统一的测试,测试出了一些查询的问题,我们这写的index页面的分页查询接口,如果是index页面展示的字段单表可以满足,就直接用mybatis plus的分页查询,但是呢,凡是都有例外,因为做的是公司用的oa系统,关联的地方很多,比如组织机构啊,项目啊,合同啊,单位啊,之类的……总之有很是单表查询满足不了的,因此,就产生了今天的问题,前端的入参,不标准怎么办?冷不丁的给你冒出个前后空格,导致查询结果不对,用户就反馈,为什么这个查不出来啊,我都是复制的,想想就头疼。
2. 初步想法
因为最开始对这个系统功能不熟悉,加之比较急,就没有考虑这个问题,具体是前端做,还是后端做,其实:我感觉,必须是前端自己做,哈哈哈!一开始呢,第一时间肯定就是想到trim方法嘛。
就是用下面这种改法:
这是控制器方法,一个例子而已。
@PostMapping("/getIndexPageData")
public R getIndexPageData(@RequestBody SubProblemIndexReqDTO reqDTO,
@RequestHeader String token) {
log.info(LogConstant.CALL_INTERFACE,"/security/statistical/getIndexPageData");
return securityCheckService.getIndexPageData(reqDTO,token);
}
这是入参类的结构
/** * index页请求DTO * @author: 一位大帅哥 * @date: 2022/10/12 10:32 * @description: TODO */ @Data @EqualsAndHashCode(callSuper = true) @Trim // 就是我们今天要说的注解 public class SubProblemIndexReqDTO extends PageReqDTO { /** * 区域 */ private String area; /** * 流程编号 */ private String flowCode; /** * 项目名称 */ private String projectName; /** * 合同名称 */ private String contractName; /** * 监理单位名称 */ private String companyNameJl; /** * 施工单位名称 */ private String companyNameSg; /** * 检查类型 */ private String checkType; /** * 回复率起始值 */ private Double responseRateBegin; /** * 回复率结束值 */ private Double responseRateEnd; /** * 整改率起始值 */ private Double rectificationRateBegin; /** * 整改率结束值 */ private Double rectificationRateEnd; /** * 闭合率起始值 */ private Double closingRateBegin; /** * 闭合率结束值 */ private Double closingRateEnd; /** * 检查日期 --> 起始值 */ private Date checkDateBegin; /** * 检查日期 --> 结束值 */ private Date checkDateEnd; }
顺便给大家说一下利用Post请求做分页,把查询参数放到类中的,定义一个抽象的ReqDTO,把查询的公共参数放到里面,直接继承着用,感觉大家应该都能想到。下面是我用的ReqDTO
/** * <p>请求公共属性抽象类</p> * * @author gaoming * @Date 2022/9/6 11:43 */ @Data public abstract class PageReqDTO { /** * 页大小 , 默认值 10 */ private Integer pageSize = 10; /** * 当前页 , 默认值 1 */ private Integer pageNum = 1; /** * 流程状态 */ private Integer processStatus; /** * 项目ids */ private List<String> projectIds; /** * 项目组织结构id */ private String organizationId; }
一开始想的就是在service方法中,把要用到的String属性判断不为空,就进行trim操作
if (StrUtil.isNotBlank(reqDTO.getArea())) { reqDTO.setArea(reqDTO.getArea().trim()); }
但是这样做就太多了,有的入参类String属性有一二十个,那要是这样改,人不得改崩了啊!所以果断放弃,因此,就要从别的方面入手,第一时间想到用注解形式,只要定义一个注解,放到类或者类的属性上面,不就可以了吗?
3. 正文开始
看了这么久,终于等到正文了!
-
定义一个自定义注解Trim
/** * @author GmDsg * @date 2023/5/15 9:29 * @description 去除String字段前后空格 */ @Target({ElementType.FIELD, ElementType.TYPE}) // 注解可作用在类或者类属性 @Retention(RetentionPolicy.RUNTIME) // 运行时生效 public @interface Trim { }
-
定义一个切面类
/** * @author GmDsg * @date 2023/5/15 9:30 * @description Trim切面 */ @Aspect @Component @Slf4j public class TrimAop { /** * 切入点:任意包路径下controller包下的任意Controller类的公共方法 * <p切入点根据自己的需求,做不同的操作,不规定死/p> */ @Pointcut("execution(public * *..controller.*Controller.*(..))") public void pointCut() { } /** * 前置操作 * @param joinPoint 连接点 * @throws Throwable 抛出异常 */ @Before("pointCut()") public void before(JoinPoint joinPoint) throws Throwable { // 获取入参 Object[] args = joinPoint.getArgs(); for (int i = 0; i < args.length; i++) { Object arg = args[i]; if (arg == null) { continue; } // 获取该入参类是否有Trim注解 Class<?> argClass = arg.getClass(); Trim annotation = argClass.getAnnotation(Trim.class); // 获取该入参类所有属性 Field[] fields = argClass.getDeclaredFields(); if (annotation == null) { // 类上没有Trim注解 for (Field field : fields) { // 获取类中属性是否有Trim注解 Trim fieldAnnotation = field.getAnnotation(Trim.class); if (fieldAnnotation == null || !field.getType().equals(String.class)) { continue; } // 该属性有注解并且也是String类型 // 设置私有属性可访问 field.setAccessible(true); // 获取属性值 Object value = field.get(arg); if (value != null) { // 执行trim操作,并重新为该属性赋值 field.set(arg, ((String) value).trim()); } } } else { // 入参类上存在Trim注解 for (Field field : fields) { // 遍历所有属性值并筛选是String类型的字段 if (!field.getType().equals(String.class)) { continue; } // 设置私有属性可访问 field.setAccessible(true); // 获取属性值 Object value = field.get(arg); if (value != null) { // 执行trim操作,并重新为该属性赋值 field.set(arg, ((String) value).trim()); } } } // 为当前类赋值处理完的类,实现去除空格效果 args[i] = arg; } } }
-
浅浅的解释一下
使用@Before注解获取前置操作的所有入参,也就是这一句
// 获取入参 Object[] args = joinPoint.getArgs();
会获取控制器方法的所有入参:就会获取reqDTO,token
@PostMapping("/getIndexPageData") public R getIndexPageData(@RequestBody SubProblemIndexReqDTO reqDTO, @RequestHeader String token) { log.info(LogConstant.CALL_INTERFACE,"/security/statistical/getIndexPageData"); return securityCheckService.getIndexPageData(reqDTO,token); }
遍历获取到的Object,反射获取Object的class,调用class的getAnnotation(Trim.class)方法
// 获取类中属性是否有Trim注解 Trim annotation = argClass.getAnnotation(Trim.class);
如果这个annotation不为空,则说明该类上有Trim注解,对于类上面有Trim注解的,会对所有String类型并且不为null的属性进行去除
前后空格操作。
所以就要获取类中所有的属性
// 获取该入参类所有属性 Field[] fields = argClass.getDeclaredFields();
遍历fields,挨个判断Field是否是String类型并且不为空,如果满足,则为该Field设置去除前后空格的值,具体操作如下。
// 入参类上存在Trim注解 for (Field field : fields) { // 遍历所有属性值并筛选是String类型的字段 if (!field.getType().equals(String.class)) { continue; } // 设置私有属性可访问 field.setAccessible(true); // 获取属性值 Object value = field.get(arg); if (value != null) { // 执行trim操作,并重新为该属性赋值 field.set(arg, ((String) value).trim()); } }
然后类上面没有Trim注解的呢,我们还要再对fields进行遍历,因为我们的注解当时定义是作用在类上或者属性上的,因此类上面没有还要对属性进行判断,这个属性有没有Trim注解,有这个注解它是不是String类型的,话不多说,上代码。
// 类上没有Trim注解 for (Field field : fields) { // 获取类中属性是否有Trim注解 Trim fieldAnnotation = field.getAnnotation(Trim.class); if (fieldAnnotation == null || !field.getType().equals(String.class)) { continue; } // 该属性有注解并且也是String类型 // 设置私有属性可访问 field.setAccessible(true); // 获取属性值 Object value = field.get(arg); if (value != null) { // 执行trim操作,并重新为该属性赋值 field.set(arg, ((String) value).trim()); } }
其实这个没啥讲的,取属性上的注解,看属性上有没有这个注解,如果有,还要判断这个属性是不是String类型的,如果都满足,则对这个Field做trim操作
4. 测试
我们找到一个接口,随便测试一下
-
先在入参类上面加Trim注解
-
然后我们故意给String属性写空格,然后查询
-
后台打印日志,已经把前后空格去掉了
-
然后我们再试试不在类上写注解,只在指定字段写注解
给指定属性加注解:待会测试中,只有projectName 和 companyNameSg有值,都带空格
这是入参,然后直接点查询
后台日志:
可以看到,projectName 和 companyNameSg都加了空格,因为projectName加了Trim注解,所以去掉了空格,反之,companyNameSg没加注解,没有去掉空格,导致查询为空!
结果:
5. 最后
最后还是要说一下,利用切面类,是很好用,但是,启动项目时,spring也会加载切面,如果切面写的范围过大,会导致启动速度变慢,也可能导致方法查询不准确,所以大家用的时候,要写好这个切入点。以上就是我这次给大家分享的‘干货’,因为我也是小菜鸟一枚,写博客也只是记录一下,大家有什么好的建议或者文章中有一些写的不对不准确的地方,欢迎大家指正。最后祝在看文章的您,能在这卷到飞起的java大环境中,成长为一个超级大大大大大……神!