1. 程式人生 > >Spring+MyBatis純註解零XML整合(4)

Spring+MyBatis純註解零XML整合(4)

myba rtp ppi ddr 而且 進行 掃描 reat 多人

不得不說,利用XML作為配置文件是一個非常好的想法,它可以輕松地實現配置集中化,而且修改之後無需再次編譯。然而,由於大多數情況下開發者基本都會拿到程序的源碼,加之對於各種XML配置文件一般情況下也只有開發者會去動,可以說XML在一定程度上也相當於程序代碼,只是不用編譯而已。因此很多人並不是很喜歡XML這種東西。早在Spring 2.5之前就有很多人對滿天飛的XML配置叫苦不叠。從Spring 3開始,Java config開始出現,這一特性使得Spring能夠擺脫XML配置文件。但是大多數人仍然通過XML文件配置註解,這樣的用法並未完全擺脫XML。實際上,從這時候開始就完全可以通過Java Config而非XML來對Spring進行配置了。加上MyBatis也完全可以通過註解來配置mapper,因此對於不喜歡XML配置的讀者,這篇文章可以說是值得一看。本文以Spring 4為例介紹Spring與MyBatis純註解整合。

首先你需要:

  • 了解傳統的通過XML配置Spring+MyBatis的方法
  • Spring 4 + MyBatis 3
  • Servlet 3.0
  • Java 8
  • 20分鐘的時間

對於傳統的Web項目自然少不了web.xml。然而從Servlet 3.0開始,這個東西已經被WebApplicationInitializer取代。顧名思義,WebApplicationInitializer是對Web應用進行初始化的一個東東。不過WebApplicationInitializer是一個接口,所以你需要提供一個WebApplicationInitializer的實現類。當你把實現類寫好之後,Servlet 3.0可以自動發現它並對servlet進行初始化(當然也可以是多個實現類),可以說這個接口的實現類一定程度上等價於web.xml的配置。下面的WebApplicationInitializer實現類為Servlet的根配置,並指定該配置的加載順序為所有配置之前(由@Order註解控制,數值越小優先級越高)。本例中該配置為空,可通過清單1中的方式來配置Filter、Listener和Servlet。

清單1 配置根WebApplicationInitializer

package org.fhp.springmybatis.config;  
  
import org.springframework.core.annotation.Order;  
import org.springframework.web.WebApplicationInitializer;  
  
import javax.servlet.*;  
  
@Order(1)  
public class BasicWebInitializer implements WebApplicationInitializer {  
  
  
    @Override  
    
public void onStartup(ServletContext servletContext) throws ServletException { // servletContext.addFilter("filterName", AFilter.class).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/"); // servletContext.addListener(EventListener.class); // servletContext.addServlet("servletName", AServlet.class); } }
接下來需要進行Spring的Servlet配置。Spring提供了AbstractAnnotationConfigDispatcherServletInitializer類(也是WebApplicationInitializer的子類),實現之即可進行Spring的servlet配置。這裏需要把加載順序放在BasicWebInitializer之後。

清單2 配置Spring的WebApplicationInitializer

package org.fhp.springmybatis.config;  
  
import org.springframework.core.annotation.Order;  
import org.springframework.web.context.WebApplicationContext;  
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;  
import org.springframework.web.filter.CharacterEncodingFilter;  
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
  
import javax.servlet.Filter;  
  
@Order(3)  
public class SpringInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
  
    //配置Spring根上下文配置類  
    @Override  
    protected Class<?>[] getRootConfigClasses() {  
        return new Class[] {SpringRootConfig.class};  
    }  
    
    //配置Spring Web上下文配置類  
    @Override  
    protected Class<?>[] getServletConfigClasses() {  
        return new Class[] {SpringWebConfig.class};  
    }  
  
    //配置在什麽路徑下使用Spring的DispatcherServlet。等價於給DispatchServlet指定對應的url-mapping  
    @Override  
    protected String[] getServletMappings() {  
        return new String[] { "/" };  
    }  
  
    //配置與Spring相關的Filter。這裏規定Spring MVC的編碼為UTF-8。  
    @Override  
    protected Filter[] getServletFilters() {  
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();  
        characterEncodingFilter.setEncoding("UTF-8");  
        characterEncodingFilter.setForceEncoding(true);  
        return new Filter[] { characterEncodingFilter };  
    }  
}  

這裏Servlet的配置,等價於XML配置中的web.xml就完成了。下面開始Spring的ApplicationContext配置。

首先進行Web的上下文配置。進行Web的上下文配置需要繼承WebMvcConfigurerAdapter類,同時配置類也要有@Configuration,@EnableWebMvc和@ComponentScan註解。這裏配置一個對靜態文件訪問的支持,在WebMvcConfigurerAdapter可以看到其他的配置,這裏就不多說了。

清單3 Spring Web ApplicationContext配置

package org.fhp.springmybatis.config;  
  
import org.springframework.context.annotation.ComponentScan;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.web.servlet.config.annotation.EnableWebMvc;  
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;  
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
  
import java.util.List;  
  
@Configuration  
@EnableWebMvc  
@ComponentScan(basePackages = "org.fhp.springmybatis")  
public class SpringWebConfig extends WebMvcConfigurerAdapter {  
  
    @Override  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");  
        registry.addResourceHandler("*.html").addResourceLocations("/");  
    }  
}  

  

其次進行根上下文的配置。這裏通過@Bean註解來取代XML中的<bean>標簽。

清單4 Spring Root ApplicationContext配置

package org.fhp.springmybatis.config;  
  
  
import org.springframework.context.annotation.*;  
import org.springframework.transaction.annotation.EnableTransactionManagement;  
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;  
import org.springframework.core.io.ClassPathResource;  
  
  
@Configuration  
@ComponentScan("org.fhp.springmybatis")  
@EnableAspectJAutoProxy(proxyTargetClass=true)  
@EnableTransactionManagement  
@Import(DaoConfig.class)  
public class SpringRootConfig {  
  
    @Bean  
    public PropertyPlaceholderConfigurer getTestPpc() {  
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();  
        ppc.setLocations(new ClassPathResource("jdbc.properties"));  
        return ppc;  
    }  
}  

其中jdbc.properties內容如下:

清單5 jdbc.properties配置

jdbc.driverClass=com.mysql.jdbc.Driver  
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test_mysql  
jdbc.user=root  
jdbc.password=root  

然後是DAO層的上下文。

清單6 DAO上下文配置

package org.fhp.springmybatis.config;  
  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.mybatis.spring.SqlSessionFactoryBean;  
import org.mybatis.spring.annotation.MapperScan;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.jdbc.datasource.DataSourceTransactionManager;  
import org.springframework.jdbc.datasource.DriverManagerDataSource;  
  
import javax.sql.DataSource;  
  
@Configuration  
@MapperScan(value="org.fhp.springmybatis.dao")  
public class DaoConfig {  
  
    @Value("${jdbc.driverClass}")  
    private String driverClass;  
  
    @Value("${jdbc.user}")  
    private String user;  
  
    @Value("${jdbc.password}")  
    private String password;  
  
    @Value("${jdbc.jdbcUrl}")  
    private String jdbcUrl;  
  
    @Bean  
    public DataSource dataSource() {  
        DriverManagerDataSource dataSource = new DriverManagerDataSource();  
        dataSource.setDriverClassName(driverClass);  
        dataSource.setUsername(user);  
        dataSource.setPassword(password);  
        dataSource.setUrl(jdbcUrl);  
        return dataSource;  
    }  
  
    @Bean  
    public DataSourceTransactionManager transactionManager() {  
        return new DataSourceTransactionManager(dataSource());  
    }  
  
    @Bean  
    public SqlSessionFactory sqlSessionFactory() throws Exception {  
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();  
        sessionFactory.setDataSource(dataSource());  
        return sessionFactory.getObject();  
    }  
}  

至此Spring的配置完成。
現在,我們假設有如下實體類。



清單7 實體類定義

[java] view plain copy
package org.fhp.springmybatis.entity;  
  
public class Person {  
    private long id;  
    private String name;  
    private String nick;  
      
    public long getId() {  
        return id;  
    }  
    public void setId(long id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public String getNick() {  
        return nick;  
    }  
    public void setNick(String nick) {  
        this.nick = nick;  
    }  
}  

由於在清單6中@MapperScan規定了掃描Mapper的包為org.fhp.springmybatis.dao,因此我們只要將mapper配置類放在這個包下,MyBatis即可自動識別。

清單8 Mapper的配置

package org.fhp.springmybatis.dao;  
  
import java.util.List;  
  
import org.apache.ibatis.annotations.Delete;  
import org.apache.ibatis.annotations.Insert;  
import org.apache.ibatis.annotations.Param;  
import org.apache.ibatis.annotations.Result;  
import org.apache.ibatis.annotations.Results;  
import org.apache.ibatis.annotations.Select;  
import org.apache.ibatis.annotations.SelectProvider;  
import org.apache.ibatis.annotations.Update;  
import org.fhp.springmybatis.entity.Person;  
  
public interface PersonDao {  
      
    @Insert(value="insert into t_person(name, nick) values (#{name}, #{nick})")  
    void add(Person person);  
      
    @Delete(value="delete from t_person where id=#{id}")  
    void delete(long id);  
      
    @Update(value="update t_person set name=#{name}, nick=#{nick} where id=#{id}")  
    void update(Person person);  
      
    @Select(value="select * from t_person where id=#{id}")  
    Person select(long id);  
}  

可以看到,通過@Insert,@Delete,@Update,@Select註解加SQL語句的配置,即可實現MyBatis對數據庫的增刪改查操作。

那麽假如需要動態地生成SQL語句,該怎麽辦呢?答案是使用MyBatis提供的@InsertProvider,@DeleteProvider,@UpdateProvider,@SelectProvider註解,當然也是對應數據庫的增刪改查。這裏以@SelectProvider為例。

首先定義一個Provider類。

清單9 Provider類

public class PersonSqlProvider {  
    public String selectByNameAndNick(@Param("name") String name, @Param("nick") String nick) {  
        StringBuffer sb = new StringBuffer();  
        sb.append("select * from t_person where ");  
        sb.append("name=#{name}");  
        sb.append(" and ");  
        sb.append("nick=#{nick}");  
        return sb.toString();  
    }  
}  

然後就要有請我們的@SelectProvider出場了。

清單10 使用@SelectProvider

@SelectProvider(type=PersonSqlProvider.class, method="selectByNameAndNick")  
List<Person> selectByNameAndNick(@Param("name") String name, @Param("nick") String nick);  

當然,在本例當中即使不用Provider也是能夠實現的,這裏只是為了演示Provider的效果。我們可以看到,SQL語句由程序拼接,自然可以實現動態SQL中if條件判斷以及SQL當中in語句等復雜語句的拼接,而且一定程度上比用XML更靈活。

綜上,本文介紹了Spring與MyBatis整合的另一種思路——純註解無XML的配置方法。隨著越來越多的框架都逐漸采用註解進行配置,可以說無XML配置已經成為一種趨勢。如果你已經用上了Spring 4,不妨嘗試一下這樣的方法,你一定會感到很滿意的。

/**
 * 城市 DAO 接口類
 * Created by wanglu-jf on 17/6/27.
 * @Mapper 標誌接口為 MyBatis Mapper 接口
 * @Select 是 Select 操作語句
 * @Results 標誌結果集,以及與庫表字段的映射關系
 */
@Mapper
public interface CityDao {
    /**
     * 查詢城市信息
     */
    @Select(" SELECT * FROM city WHERE id = #{id}")
    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "provinceId", column = "province_id"),
            @Result(property = "cityName", column = "city_name"),
            @Result(property = "description", column = "description")
    })
    public City queryCityById(@Param("id") int id);
}

Spring+MyBatis純註解零XML整合(4)