2015-05-15 11 views
5

Oggi stavo preparando un esempio utilizzando Spring Boot e utilizzando MyBatis per la comunicazione di accesso ai dati accanto a Spring-MyBatis. Ecco la configurazione del progetto in questione (usando Maven):Perché il file di interfaccia e il file di mappatura xml devono essere nello stesso pacchetto e avere lo stesso nome?

src/main/java 
- edu.home.ltmj.controller 
    + CategoryController.java 
- edu.home.ltmj.dao 
    + CategoryDao.java 
- edu.home.ltmj.domain 
    + Category.java 
src/main/resources 
- edu.home.ltmj.dao 
    + CategoryMapper.xml 

contenuti rilevanti del file:

CategoryDao.java:

package edu.home.ltmj.dao; 

public interface CategoryDao { 
    List<Category> getAllCategories(); 
} 

CategoryMapper.xml:

<mapper namespace="edu.home.ltmj.dao.CategoryDao"> 
    <resultMap id="categoryMap" 
     type="edu.home.ltmj.domain.Category"> 
     <id property="id" column="id" /> 
     <result property="name" column="name" /> 
    </resultMap> 
    <select id="getAllCategories" resultMap="categoryMap"> 
     SELECT id, nombre 
     FROM category 
    </select> 
</mapper> 

Quindi, inietto un'istanza di questo dao in un controller di richiesta (a scopo di test), in questo modo:

package edu.home.ltmj.controller; 

@RestController 
public class CategoryController { 
    @Autowired 
    private CategoryDao dao; 

    @RequestMapping(value="/category/all", 
     method=RequestMethod.GET, 
     produces=MediaType.APPLICATION_JSON_VALUE) 
    public List<Categoria> getAllCategories() { 
     return dao.getAllCategories(); 
    } 
} 

eseguo il mio progetto e testare l'esecuzione utilizzando curl localhost:8080/category/all e poi si aspettava di vedere i risultati in formato JSON, ma ho avuto questa eccezione invece:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): edu.home.ltmj.dao.CategoryDao.getAllCategories 
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:189) 
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:43) 
at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:58) 
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:51) 
at com.sun.proxy.$Proxy45.getAllCategories(Unknown Source) 
at edu.home.ltmj.controller.CategoryRestController.getAllCategories(CategoryRestController.java:27) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
(...) 

Non capisco la causa di questo. C'è un'interfaccia CategoryDao e ha il metodo corretto getAllCategories che corrisponde a <select id="getAllCategories">. Dopo un po 'di tempo con questo, ho cambiato il nome dell'interfaccia dao in CategoryMapper e aggiornato lo spazio dei nomi in CategoryMapper.xml. Dopo averlo fatto, funzionava normalmente. Inoltre, dopo aver avuto lo stesso nome per la classe e xml, ho spostato la classe dao e il mapper xml in diversi pacchetti (stil usando lo stesso nome per entrambi: CategoryMapper.), Aggiornato lo spazio dei nomi nel file xml e ottenuto la stessa eccezione , con il messaggio aggiornato per mostrare il nome del pacchetto dell'interfaccia dao. Ma poi di nuovo, ho spostato entrambi i file nello stesso pacchetto e tutto ha funzionato di nuovo.

Quindi, la mia domanda è: perché MyBatis ha bisogno che l'interfaccia e il file di mappatura xml abbiano lo stesso nome e si trovino nello stesso pacchetto? Si tratta di MyBatis o di un problema in Spring MyBatis?

risposta

5

Hai anche un file di configurazione MyBatis?

Se ricordo correttamente lo stesso nome dello stesso percorso per il file XML come l'interfaccia è quando si desidera avere una configurazione che funziona senza alcuna configurazione aggiuntiva.

Se si dispone dei mapper XML da qualche altra parte, è possibile specificare manualmente il percorso di classe dei file XML utilizzando un elemento <mappers> all'interno di MyBatis configuration.

Dal Injecting Mappers documentation:

Se l'UserMapper ha un corrispondente file di mapping XML MyBatis nella stessa posizione classpath come interfaccia mapper, sarà analizzata automaticamente dal MapperFactoryBean. Non è necessario specificare il mapper in un file di configurazione MyBatis a meno che i file XML del programma di definizione non si trovino in una diversa posizione del percorso di classe. Vedere la proprietà configLocation di SqlSessionFactoryBean per ulteriori informazioni.

Quindi provare questo:

  1. Creare un file mybatis-config.xml all'interno src/main/resources con questo in esso:

    <?xml version="1.0" encoding="UTF-8" ?> 
    <!DOCTYPE configuration 
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
        "http://mybatis.org/dtd/mybatis-3-config.dtd"> 
    <configuration> 
        <mappers> 
        <mapper resource="com/test/path/etc/etc/WhateverNameYouWant.xml"/> 
        </mappers> 
    </configuration> 
    

    Dove WhateverNameYouWant.xml contiene ciò che il vostro CategoryMapper.xml contenute.

  2. impostare la posizione del file di configurazione (configurazione di Java come di seguito o di semi di file applicationContext):

    @Bean 
    public SqlSessionFactoryBean sqlSessionFactory() throws Exception { 
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 
        // .... 
        sessionFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml")); 
        // .... 
        return sessionFactory; 
    } 
    
+0

Io uso '@ MapperScan' e indicare i pacchetti di base in cui MyBatis può scansione di tutti i mapper di per sé. Questa annotazione funziona come '' per analizzare automaticamente i file e quindi non usare ''. –

+0

@LuiggiMendoza: '@ MapperScan' cerca interfacce. Vedi la mia modifica alla risposta. – Bogdan

+0

Questo è interessante. Alla fine, è una cosa di MyBatis * l'intera separazione delle preoccupazioni tra l'interfaccia e il mappatore, mentre '@ MapperScan' aiuta nella raccolta automatica dei bean delle interfacce dao. Grazie per il link alla documentazione corretta e l'esempio. –

1

ho usato il seguente modo senza @MapperScan come segue:

1) Setup mybatis-config.xml come al punto 2 sopra

@Bean 
public SqlSessionFactoryBean sqlSessionFactory() throws Exception { 
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 
    // .... 
    sessionFactory.setConfigLocation(new ClassPathResource("mybatis-config.xml")); 
    // .... 
    return sessionFactory; 
} 

2) Installazione CategoryDao

@Bean 
public CategoryDao getCategoryDao() throws Exception{ 
    SqlSessionTemplate sessionTemplate = new SqlSessionTemplate(sqlSessionFactoryBean()); 
    return sessionTemplate.getMapper(CategoryDao.class); 
} 

3) Installazione all'interno mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE configuration 
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
     "http://mybatis.org/dtd/mybatis-3-config.dtd"> 

<configuration> 

    <settings> 
     <setting name="logImpl" value="COMMONS_LOGGING"/> 
    </settings> 

    <mappers> 

     <mapper class="CategoryMapper.xml"/> 
    </mappers> 

</configuration> 
Problemi correlati