当前位置:   article > 正文

Mybatis Plugin拦截器处理特殊字符串_mybatis 拦截器 处理 输入 %

mybatis 拦截器 处理 输入 %

        书接上回,在mybatis查询之前可手动调用公共方法,将特殊字符进行转义。commons-beanutils和反射解决查询%和_数据问题

      但是,这么做还是不够方便,因为每次我都要在查询前调用方法,如果我忘记调用了,那测试大神又得给版本不通过了,这不就完蛋了个锤子了吗!

        之前想的是用切面去做,但是发现切面方式不好,原因在于在切入获取参数时,存在不确定性,并且较难获取到其入参的实体类。为了满足测试大神的要求,于是尝试使用mybatis拦截器,拦截select方法的入参,对入参进行转义,并且对存在入参为实体类时,通过注解+反射的方式获取需要转义的字符。其中@Param传参的话是不需要定义注解的,注解的目的是在入参为实体类时进行转义。

        定义注解+反射工具类

定义注解@SpecChar

  1. /**
  2. * 特殊字符处理注解,主要用来解决测试大神提的%和_查询问题
  3. * 希望我司测试大神能满意
  4. * 希望我司测试大神增强自己的实力,不要只会体验
  5. * 真正的测试比开发要牛
  6. * 共勉!
  7. */
  8. @Target(ElementType.FIELD)
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Documented
  11. public @interface SpecChar {
  12. }

引入commons-beanutils包,建议引入1.9.3

  1. <dependency>
  2. <groupId>commons-beanutils</groupId>
  3. <artifactId>commons-beanutils</artifactId>
  4. <version>1.9.3</version>
  5. </dependency>

定义工具类setSpecChar(),将要转义的实体类传入此方法!

  1. /**
  2. * 处理特殊字符‘%’、‘_’
  3. * @param object
  4. * @return
  5. * @throws InvocationTargetException
  6. * @throws IllegalAccessException
  7. * @throws NoSuchMethodException
  8. */
  9. public static void setSpecChar(Object object) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
  10. if (object == null) {
  11. return ;
  12. }
  13. for (Field field : getAllFields(object)) {
  14. if (field.getAnnotation(SpecChar.class) != null) {
  15. String name = field.getName();
  16. Object value = PropertyUtils.getSimpleProperty(object, name);
  17. if (value != null) {
  18. String valueStr = (String) value;
  19. if (valueStr.contains("%")) {
  20. valueStr = valueStr.replaceAll("\\%","\\\\%");
  21. }
  22. if (valueStr.contains("_")) {
  23. valueStr = valueStr.replaceAll("\\_","\\\\_");
  24. }
  25. PropertyUtils.setProperty(object, name, valueStr);
  26. }
  27. }
  28. }
  29. }
  1. /**
  2. * 获取类的所有属性,包括父类
  3. *
  4. * @param object
  5. * @return
  6. */
  7. public static Field[] getAllFields(Object object) {
  8. Class<?> clazz = object.getClass();
  9. List<Field> fieldList = new ArrayList<>();
  10. while (clazz != null) {
  11. fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
  12. clazz = clazz.getSuperclass();
  13. }
  14. Field[] fields = new Field[fieldList.size()];
  15. fieldList.toArray(fields);
  16. return fields;
  17. }

定义dealSpecChar,将要转义的字符串传入此方法!

  1. public static String dealSpecChar(String valueStr) {
  2. if (valueStr.contains("%")) {
  3. valueStr = valueStr.replaceAll("\\%","\\\\%");
  4. }
  5. if (valueStr.contains("_")) {
  6. valueStr = valueStr.replaceAll("\\_","\\\\_");
  7. }
  8. return valueStr;
  9. }

定义MyBatis拦截器

 定义拦截器,在查询方法类型为Select时,将带有特殊字符的参数,进行转义。本案例中,也引入了update和insert方法,用于增强更新和创建时间,亦可进行参考。

  1. /**
  2. * mybatis拦截获取自动创建时间,并且查询时对特殊字符%、_进行转义
  3. * @author 椰子皮
  4. */
  5. @Slf4j
  6. @Component
  7. @Intercepts({
  8. @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
  9. RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
  10. @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class })
  11. })
  12. public class MybatisInterceptor implements Interceptor {
  13. @Override
  14. public Object intercept(Invocation invocation) throws Throwable {
  15. MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
  16. SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
  17. Object parameter = invocation.getArgs()[1];
  18. if (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) {
  19. if (parameter == null) {
  20. return invocation.proceed();
  21. }
  22. Field[] fields = ConvertUtils.getAllFields(parameter);
  23. for (Field field : fields) {
  24. try {
  25. if ("updateTime".equals(field.getName()) || "createTime".equals(field.getName())) {
  26. field.setAccessible(true);
  27. Object local_createDate = field.get(parameter);
  28. field.setAccessible(false);
  29. if (local_createDate == null || local_createDate.equals("")) {
  30. field.setAccessible(true);
  31. //ConvertUtils.getNowTime() 为获取当前时间,此处省略其实现方式
  32. field.set(parameter, ConvertUtils.getNowTime());
  33. field.setAccessible(false);
  34. }
  35. }
  36. } catch (Exception e) {
  37. log.error(e.getMessage(), e);
  38. }
  39. }
  40. }
  41. //如果是查询
  42. else if (SqlCommandType.SELECT == sqlCommandType){
  43. Object[] args = invocation.getArgs();
  44. if (parameter instanceof MapperMethod.ParamMap) {
  45. Map<Object, Object> paramMap = (Map) parameter;
  46. Iterator<Map.Entry<Object, Object>> it = paramMap.entrySet().iterator();
  47. //遍历map,并且将string类型的参数进行转义
  48. while (it.hasNext()) {
  49. Map.Entry<Object, Object> entry = it.next();
  50. Object objectKey = entry.getKey();
  51. if (objectKey instanceof String && entry.getValue() instanceof String) {
  52. if ((StringUtils.isNotBlank(sql) && sql.contains("LIKE")) ||
  53. (StringUtils.isNotBlank(sql) && sql.contains("like"))) {
  54. if (paramMap.containsKey("page") &&
  55. sql.contains("COUNT")) {
  56. String value = (String) entry.getValue();
  57. entry.setValue(ConvertUtils.dealSpecChar(value));
  58. }
  59. }
  60. } else if (objectKey instanceof String && ((String) objectKey).contains("param")){
  61. if (paramMap.containsKey("page") && sql.contains("COUNT")) {
  62. ConvertUtils.setSpecChar(entry.getValue());
  63. } else if (!paramMap.containsKey("page")) {
  64. ConvertUtils.setSpecChar(entry.getValue());
  65. }
  66. }
  67. }
  68. }
  69. }
  70. return invocation.proceed();
  71. }
  72. @Override
  73. public void setProperties(Properties properties) {
  74. System.out.println("...................");
  75. }

验证

根据测试大神的要求,当前按照设计思路已经编码完成,但是!咱不清楚到底能不能实现啊。还是得验证一下,测试大神的软件体验还是很重要的!

实践是检验真理的唯一标准!Just do it!

定义实体类TblCollectCamera(在需要搜索的字段cameraName设置定义好的注解@SpecChar)

  1. /**
  2. *
  3. * @TableName tbl_collect_camera
  4. */
  5. @TableName(value ="tbl_collect_camera")
  6. @Data
  7. public class TblCollectCamera implements Serializable {
  8. /**
  9. * 主键
  10. */
  11. @TableId(type = IdType.AUTO)
  12. private String id;
  13. /**
  14. *
  15. */
  16. private String collectId;
  17. /**
  18. *
  19. */
  20. @SpecChar
  21. private String cameraName;
  22. /**
  23. *
  24. */
  25. private String resCode;
  26. /**
  27. *
  28. */
  29. private String updateTime;
  30. @TableField(exist = false)
  31. private static final long serialVersionUID = 1L;
  32. }

编写DAO层TblCollectCameraMapper

  1. /**
  2. * @author 椰子皮
  3. * @description 针对表【tbl_collect_camera】的数据库操作Mapper
  4. * @createDate 2022-12-05 14:45:45
  5. * @Entity generator.domain.TblCollectCamera
  6. */
  7. public interface TblCollectCameraMapper extends BaseMapper<TblCollectCamera>{
  8. List<TblCollectCamera> getByCollectId(@Param("id") String id, @Param("cameraName") String cameraName);
  9. IPage<TblCollectCamera> getTblCollectCameraByPage(Page<TblCollectCamera> page, @Param("tblCollectCamera") TblCollectCamera tblCollectCamera);
  10. }

可以看到此处两个方法,入参分别为实体类TblCollectCamera和字段cameraName,按照mybatis拦截器中的代码,cameraName字段如果不加注解其实也是可以被转义的,注解的目的是在入参为实体类时进行转义

调用方法:

 其中入参cameraName为特殊字符%

打断点观察:

可以看到mybatis拦截器拦截到了入参为一实体类tblCollectCamera,入参为cameraName=%,根据我们的代码判断,此会进入 else判断,即会使用反射+注解方式将带有@SpecChar注解的字段的参数进行转义

  1. if (objectKey instanceof String && entry.getValue() instanceof String) {
  2. String value = (String) entry.getValue();
  3. entry.setValue(ConvertUtils.dealSpecChar(value));
  4. } else {
  5. ConvertUtils.setSpecChar(entry.getValue());
  6. }

继续断点往下走:

发现cameraName已经被转义了。查看查询结果:

发现不会查询到所有数据,验证OK。另外单个查询的话此处就不演示了,如果仅仅是@Param这种单个字段的查询模式,是不需要加注解就可以实现特殊字符串处理的。

最后

希望我司的测试能够会一些基本的sql和linux命令,别只当个体验官,那你离开了这个行业啥也不是。

最后感谢公司秦总的图片转发支持!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/173846
推荐阅读
相关标签
  

闽ICP备14008679号