Comment puis-je passer une liste entière à MyBatis XML, à utiliser dans une clause in dans ma requête MySQL?
J'utilise Java 7, MySQL 5.6 DB et MyBatis 3.0.4 avec des requêtes dans un fichier mapper-xml
.
Actuellement, je convertis cette liste d'entiers en chaîne et j'utilise la substitution de chaîne (opérateur ${}
) pour placer les valeurs dans la clause 'IN'. Cette méthode fonctionne normalement, mais rend le paramètre vulnérable à Injection.
J'ai essayé d'utiliser un élément <foreach>
, mais je ne suis pas en mesure de déterminer les attributs à spécifier.
Voici un exemple de code Java:
public List<Stripper> getStripperDetails(String club, List<Integer> stripperIds) {
Map<String, Object> input = new HashMap<>();
input.put("club", club);
input.put("stripperIds", stripperIds);
return stripClubMapper.getStripperDetails(input);
}
Mapper xml:
<select id="getStripperDetails" parameterType="Java.util.HashMap" resultMap="StripperMap">
SELECT STRIPPER_ID, STAGE_NAME, REAL_NAME, CLUB FROM EXOTIC_DANCERS WHERE CLUB = #{club} AND STRIPPER_ID IN
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{index}
</foreach>
</select>
Je ne suis pas en mesure de déterminer quels attributs spécifier pour l'élément <foreach>
- je continue à courir dans une exception NullPointerException pour la valeur située à # {index}.
Pouvez-vous m'aider à comprendre l'utilisation correcte de l'élément <foreach>
?
Modifier :
@ 10086,
Ci-dessous la trace de la pile:
org.mybatis.spring.MyBatisSystemException: nested exception is org.Apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: Java.lang.NullPointerException
### The error may involve com.stripclub.mapper.stripClubMapper.getStripperDetails-Inline
### The error occurred while setting parameters
### Cause: Java.lang.NullPointerException
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.Java:67) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.Java:345) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at com.Sun.proxy.$Proxy208.selectList(Unknown Source) ~[na:na]
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.Java:193) ~[mybatis-spring-1.0.0-RC3.jar:1.0.0-RC3]
at org.Apache.ibatis.binding.MapperMethod.executeForList(MapperMethod.Java:85) ~[mybatis-3.0.4.jar:3.0.4]
at org.Apache.ibatis.binding.MapperMethod.execute(MapperMethod.Java:65) ~[mybatis-3.0.4.jar:3.0.4]
at org.Apache.ibatis.binding.MapperProxy.invoke(MapperProxy.Java:38) ~[mybatis-3.0.4.jar:3.0.4]
at com.Sun.proxy.$Proxy209.getTransactionIds(Unknown Source) ~[na:na]
La valeur spécifiée par l'attribut item doit être utilisée à l'intérieur de la balise foreach, lorsqu'elle est utilisée avec des listes. Utilisez comme ci-dessous:
<foreach item="sId" collection="stripperIds" separator="," open="(" close=")">
#{sId}
</foreach>
L'attribut d'index n'est pas obligatoire lors de l'utilisation d'une liste. Reportez-vous à la section documentation de MyBatis pour plus d'informations ou consultez la DTD - http://mybatis.org/dtd/mybatis-3-mapper.dtd pour plus d'informations sur les paramètres:
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
<!ATTLIST foreach
collection CDATA #REQUIRED
item CDATA #IMPLIED
index CDATA #IMPLIED
open CDATA #IMPLIED
close CDATA #IMPLIED
separator CDATA #IMPLIED
>
Les listes d’objets sont également accessibles dans foreach comme ci-dessous. Vous utiliserez généralement ceci pour les instructions INSERT/UPDATE:
Échantillon de haricot:
public class StripperBean {
public StripperBean(int stripperID, String stripperName, String realName) {
this.stripperID = stripperID;
this.stripperName = stripperName;
this.realName = realName;
}
private int stripperID;
private String stripperName;
private String realName;
public int getStripperID() {
return stripperID;
}
public void setStripperID(int stripperID) {
this.stripperID = stripperID;
}
public String getStripperName() {
return stripperName;
}
public void setStripperName(String stripperName) {
this.stripperName = stripperName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
}
Dans votre implémentation:
Map<String, Object> input = new HashMap<>();
input.put("club", club);
List<StripperBean> strippers = new ArrayList<>();
strippers.add(new StripperBean(1,"Ashley", "Jean Grey"));
strippers.add(new StripperBean(2,"Candice","Diana Prince"));
strippers.add(new StripperBean(3,"Cristal","Lara Croft"));
input.put("strippers", strippers);
return stripClubMapper.saveStripperDetails(input);
Dans le mappeur xml:
<insert id="saveStripperDetails">
INSERT INTO EXOTIC_DANCERS (STRIPPER_ID, STAGE_NAME, REAL_NAME)
VALUES
<foreach item="stripper" collection="input" separator=",">
(#{stripper.stripperID},
#{stripper.stripperName},
#{stripper.realName})
</foreach>
</select>
Belle question BTW :)
Votre XML devrait être comme ça:
<foreach item="item" index="index" collection="stripperIds" open="(" separator="," close=")">
#{item}
</foreach>
Lors de l'utilisation d'une carte (ou d'une collection d'objets Map.Entry), index sera l'objet clé et l'élément sera l'objet valeur.
Vous pouvez référencer ici pour les détails. Vous aurez une solide compréhension des attributs.
Utiliser l'annotation devrait être plus facile
@Select({
"<script>", "select", " * ", "FROM TABLE",
"WHERE CONDITION IN " +
"<foreach item='item' index='index' collection='list' open='(' separator=',' close=')'> #{item} </foreach>" +
"</script>" })
@Results({ })
List<POJO> selectByKeys(@Param("list") List<String> ids);
votre entrée est une carte. vous devez donc résoudre stripperIds de l’entrée avant d’appeler directement stripperIds.