mybatis字符#與字符$的區別

問題:使用in查詢查詢出一批數據,in查詢的參數是字符串拼接的。調試過程當中,把mybatis輸出的sql複製到navicat中,在控制檯將sql的參數也複製出來,替換到sql的字符 '?' 的位置,執行sql,能查詢到數據,可是java程序沒法查詢到數據。java

  緣由:由於mybatis的參數佔位符以#字符開頭的參數,在處理過程當中會自動給參數加引號,及一些字符過濾處理(例如防止sql注入等等)sql

  解決方式:  in查詢的參數佔位符換成字符$開頭,由於mybatis在處理 $ 開頭的參數佔位符時候不會給參數加引號及其餘額外處理(例如sql注入字符過濾),使用的是參數原值。apache

 

mybatis 參數查詢修改前片斷
AND a.source in (#{source})

mybatis 參數查詢修改後片斷
AND a.source in (${source})

    其餘: 由於mybatis的參數佔位符以#字符開頭的參數,在處理過程當中會自動給參數加引號,那麼是加單引號仍是雙引號呢?安全

    實際上mybatis對這個#開頭的參數參數進行了參數化處理,防止注入。mybatis

     若是參數拼接 top_news','net_music','knowledge_sns','wb ,若是#開頭參數處理是單純加單引號,那麼sql條件語句若是變成以下這樣,是能夠查詢到數據的,可是結果是沒有查詢到數據,說明,時間拼接的數據不是以下的結果,結果是#開頭的參數不是單純的加單引號處理app

AND a.source in ('top_news','net_music','knowledge_sns','wb')   

 

若是參數拼接使用雙引號拼接以下 top_news","net_music","knowledge_sns","wb ,若是#開頭參數處理是單純加雙引號,那麼sql條件語句若是變成以下這樣,是能夠查詢到數據的,可是結果是沒有查詢到數據,說明,實際拼接的數據不是以下的結果,結果是#開頭的參數不是單純的加雙引號處理post

AND a.source in ("top_news","net_music","knowledge_sns","wb") 

至於#開頭的參數到底怎麼處理的,既不是單純加單引號也不是單純加雙引號,具體作了哪些處理,請閱讀源碼。反正mybatis進行in查詢時,參數是拼接好的字符串的時候,參數佔位符使用$,而不使用#,在使用$作參數佔位符時候,給參數賦值前確保代碼裏作了防注入處理或者已知的代碼是安全的不存在sql注入的,能夠直接使用$做爲參數佔位符。ui

 

  mybatis xml 文件(修改前),in查詢參數使用佔位符使用字符#url

複製代碼
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.thinkgem.jeesite.modules.backend.dao.ChannelDao">
<sql id="channelColumns">
   a.id AS "id",
   a.name AS "name",
   a.source AS "source",
   a.url AS "url",
   a.create_by AS "createBy.id",
   a.update_by AS "updateBy.id",
   a.update_date AS "updateDate",
   a.create_date AS "createDate",
   a.remarks AS "remarks",
   a.del_flag AS "delFlag"
</sql>

<sql id="channelJoins">
</sql>

<select id="findList" resultType="Channel">
   SELECT 
      <include refid="channelColumns"/>
   FROM mkt_channel a
   <include refid="channelJoins"/>
   <where>
      a.del_flag = #{DEL_FLAG_NORMAL}
      <if test="source != null and source!=''">
         AND a.source in (#{source})
      </if>

      <if test="createBy != null">
         AND  a.create_by = #{createBy.id}
      </if>

   </where>
   <choose>
      <when test="page !=null and page.orderBy != null and page.orderBy != ''">
         ORDER BY ${page.orderBy}
      </when>
      <otherwise>
         ORDER BY a.update_date DESC
      </otherwise>
   </choose>
</select>
</mapper>
複製代碼

ChannelController.javaspa

複製代碼
@Controller
@RequestMapping(value = "${a}/backend/channel")
public class ChannelController extends BaseController {

    @Autowired
    private ChannelService channelService;

    @Autowired
    private SystemService systemService;

    @RequiresPermissions("backend:channel:view")
    @RequestMapping(value = {"list", ""})
    public String list(Channel channel, HttpServletRequest request, HttpServletResponse response, Model model) {
        
        String sourceName= request.getParameter("sourceName");
        String srcStr = null;
        boolean srcFindDo = false;
        if(StringUtils.isNotEmpty(sourceName)) {
            Map<String, Object> findedChannelMap = SourceUtils.getInstance().searchSourceList(sourceName);
            srcStr = (String) findedChannelMap.get("srcStr");
            srcFindDo = true;
        }


        String createBy = request.getParameter("createBy");
        channel.setCreateBy(null);
        createBy = XssFilter.getInstance().cleanXssChars(createBy);
        if(StringUtils.isNotEmpty(createBy)) {
            User user = systemService.getUserById(createBy);
            if(null != user) {
                channel.setCreateBy(user);
            }
        }

        Page<Channel> page = new Page<>();

        if(srcFindDo && StringUtils.isEmpty(srcStr)){
            page.setList(new ArrayList<>());
            page.setPageNo(0);
            page.setPageSize(0);
            page.setCount(0);
            page.setMessage("沒有找到數據");
        }
        else {
            channel.setUtmSource(labelStr);
            page = channelService.findPage(new Page<Channel>(request, response), channel);
        }

        model.addAttribute("page", page);
        return "modules/backend/channelList";
    }
}
複製代碼

 

SourceUtils.java

複製代碼
package com.thinkgem.jeesite.common.utils;

import com.thinkgem.jeesite.modules.backend.entity.ChannelSource;
import com.thinkgem.jeesite.modules.sys.entity.Dict;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;

public class SourceUtils {

    private Logger logger = LogManager.getLogger(SourceUtils.class);

    private ChannelSourceFacade channelSourceFacade;

    private static SourceUtils instance;

    private SourceUtils() {
        channelSourceFacade = SpringContextHolder.getBean(ChannelSourceFacade.class);
    }

    public static SourceUtils getInstance() {
        if (null == instance) {
            instance = new SourceUtils();
        }
        return instance;
    }


    /**
     * 獲取全部的來源列表
     * @return
     */
    public List<ChannelSource> getAllSource() {
        List<ChannelSource> dataList = new ArrayList<>();
        Response<List<ChannelSource>> response = channelSourceFacade.getChannelSourceList();
        dataList = response.getData(); 
        return dataList;
    }


    /**
     * 根據來源名稱模糊查找渠道
     * @return
     */
    public Map<String,Object> searchChannelList(String label,String desc,String code) {
        Map<String,Object> dictMap = new HashMap<>();
        String labelStr = "";
         List<ChannelSource> findedList = new ArrayList<>();
        List<ChannelSource> srcList = getAllChannelDict();
        if(null != srcList && srcList.size() > 0) {
            for (ChannelSource item : srcList) {
                if (dictMap.containsKey(item.getLabel())) {
                    continue;
                }
                if(channelMatch(name,item)) {
                    findedList.add(item);
                    srcStr = String.format("%s'%s',",srcStr,item.getLabel());
                }
            }
        }
        if(srcStr.length() > 1) {
            //移除最後一個逗號和2個引號
            srcStr = srcStr.substring(0, srcStr.length() - 1);
        }
        dictMap.put("srcStr",srcStr);
        dictMap.put("findedList",findedList);
        return dictMap;
    }

    private boolean channelMatch(String sourceName,Dict item) {
        boolean result = true;
        name = null == name ? "" : name;
        if (StringUtils.isNotEmpty(name)) {
            if (dict.getDescription().indexOf(desc) == -1) {
                result = false;
                return result;
            }
        }
        return result;
    }

}



複製代碼
相關文章
相關標籤/搜索