Spring+MyBatis纯注解零XML整合

释放双眼,带上耳机,听听看~!

不得不说,利用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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1package org.fhp.springmybatis.config;
2
3import org.springframework.core.annotation.Order;
4import org.springframework.web.WebApplicationInitializer;
5
6import javax.servlet.*;
7
8@Order(1)
9public class BasicWebInitializer implements WebApplicationInitializer {
10
11
12    @Override
13    public void onStartup(ServletContext servletContext) throws ServletException {
14//        servletContext.addFilter("filterName", AFilter.class).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/");
15//      servletContext.addListener(EventListener.class);
16//        servletContext.addServlet("servletName", AServlet.class);
17    }
18}
19

接下来需要进行Spring的Servlet配置。Spring提供了AbstractAnnotationConfigDispatcherServletInitializer类(也是WebApplicationInitializer的子类),实现之即可进行Spring的servlet配置。这里需要把加载顺序放在BasicWebInitializer之后。

清单2 配置Spring的WebApplicationInitializer


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1package org.fhp.springmybatis.config;
2
3import org.springframework.core.annotation.Order;
4import org.springframework.web.context.WebApplicationContext;
5import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
6import org.springframework.web.filter.CharacterEncodingFilter;
7import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
8
9import javax.servlet.Filter;
10
11@Order(3)
12public class SpringInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
13
14  //配置Spring根上下文配置类
15    @Override
16    protected Class<?>[] getRootConfigClasses() {
17        return new Class[] {SpringRootConfig.class};
18    }
19  
20      //配置Spring Web上下文配置类
21    @Override
22    protected Class<?>[] getServletConfigClasses() {
23        return new Class[] {SpringWebConfig.class};
24    }
25
26    //配置在什么路径下使用Spring的DispatcherServlet。等价于给DispatchServlet指定对应的url-mapping
27    @Override
28    protected String[] getServletMappings() {
29        return new String[] { "/" };
30    }
31
32    //配置与Spring相关的Filter。这里规定Spring MVC的编码为UTF-8。
33    @Override
34    protected Filter[] getServletFilters() {
35        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
36        characterEncodingFilter.setEncoding("UTF-8");
37        characterEncodingFilter.setForceEncoding(true);
38        return new Filter[] { characterEncodingFilter };
39    }
40}
41

这里Servlet的配置,等价于XML配置中的web.xml就完成了。下面开始Spring的ApplicationContext配置。

首先进行Web的上下文配置。进行Web的上下文配置需要继承WebMvcConfigurerAdapter类,同时配置类也要有@Configuration,@EnableWebMvc和@ComponentScan注解。这里配置一个对静态文件访问的支持,在WebMvcConfigurerAdapter可以看到其他的配置,这里就不多说了。

清单3 Spring Web ApplicationContext配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1package org.fhp.springmybatis.config;
2
3import org.springframework.context.annotation.ComponentScan;
4import org.springframework.context.annotation.Configuration;
5import org.springframework.web.servlet.config.annotation.EnableWebMvc;
6import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
7import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
8
9import java.util.List;
10
11@Configuration
12@EnableWebMvc
13@ComponentScan(basePackages = "org.fhp.springmybatis")
14public class SpringWebConfig extends WebMvcConfigurerAdapter {
15
16    @Override
17    public void addResourceHandlers(ResourceHandlerRegistry registry) {
18        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
19        registry.addResourceHandler("*.html").addResourceLocations("/");
20    }
21}
22

其次进行根上下文的配置。这里通过@Bean注解来取代XML中的<bean>标签。

清单4 Spring Root ApplicationContext配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1package org.fhp.springmybatis.config;
2
3
4import org.springframework.context.annotation.*;
5import org.springframework.transaction.annotation.EnableTransactionManagement;
6import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
7import org.springframework.core.io.ClassPathResource;
8
9
10@Configuration
11@ComponentScan(&quot;org.fhp.springmybatis&quot;)
12@EnableAspectJAutoProxy(proxyTargetClass=true)
13@EnableTransactionManagement
14@Import(DaoConfig.class)
15public class SpringRootConfig {
16
17    @Bean
18    public PropertyPlaceholderConfigurer getTestPpc() {
19        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
20        ppc.setLocations(new ClassPathResource(&quot;jdbc.properties&quot;));
21        return ppc;
22    }
23}
24

1
2
1其中jdbc.properties内容如下:
2

清单5 jdbc.properties配置


1
2
3
4
5
1jdbc.driverClass=com.mysql.jdbc.Driver
2jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test_mysql
3jdbc.user=root
4jdbc.password=root
5

1
2
1 然后是DAO层的上下文。
2

清单6 DAO上下文配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1package org.fhp.springmybatis.config;
2
3import org.apache.ibatis.session.SqlSessionFactory;
4import org.mybatis.spring.SqlSessionFactoryBean;
5import org.mybatis.spring.annotation.MapperScan;
6import org.springframework.beans.factory.annotation.Value;
7import org.springframework.context.annotation.Bean;
8import org.springframework.context.annotation.Configuration;
9import org.springframework.jdbc.datasource.DataSourceTransactionManager;
10import org.springframework.jdbc.datasource.DriverManagerDataSource;
11
12import javax.sql.DataSource;
13
14@Configuration
15@MapperScan(value=&quot;org.fhp.springmybatis.dao&quot;)
16public class DaoConfig {
17
18    @Value(&quot;${jdbc.driverClass}&quot;)
19    private String driverClass;
20
21    @Value(&quot;${jdbc.user}&quot;)
22    private String user;
23
24    @Value(&quot;${jdbc.password}&quot;)
25    private String password;
26
27    @Value(&quot;${jdbc.jdbcUrl}&quot;)
28    private String jdbcUrl;
29
30    @Bean
31    public DataSource dataSource() {
32        DriverManagerDataSource dataSource = new DriverManagerDataSource();
33        dataSource.setDriverClassName(driverClass);
34        dataSource.setUsername(user);
35        dataSource.setPassword(password);
36        dataSource.setUrl(jdbcUrl);
37        return dataSource;
38    }
39
40    @Bean
41    public DataSourceTransactionManager transactionManager() {
42        return new DataSourceTransactionManager(dataSource());
43    }
44
45    @Bean
46    public SqlSessionFactory sqlSessionFactory() throws Exception {
47        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
48        sessionFactory.setDataSource(dataSource());
49        return sessionFactory.getObject();
50    }
51}
52

1
2
1 至此Spring的配置完成。
2

现在,我们假设有如下实体类。

清单7 实体类定义


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1package org.fhp.springmybatis.entity;
2
3public class Person {
4   private long id;
5   private String name;
6   private String nick;
7  
8   public long getId() {
9       return id;
10  }
11  public void setId(long id) {
12      this.id = id;
13  }
14  public String getName() {
15      return name;
16  }
17  public void setName(String name) {
18      this.name = name;
19  }
20  public String getNick() {
21      return nick;
22  }
23  public void setNick(String nick) {
24      this.nick = nick;
25  }
26}
27

1
2
1 由于在清单6中@MapperScan规定了扫描Mapper的包为org.fhp.springmybatis.dao,因此我们只要将mapper配置类放在这个包下,MyBatis即可自动识别。
2

清单8 Mapper的配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1package org.fhp.springmybatis.dao;
2
3import java.util.List;
4
5import org.apache.ibatis.annotations.Delete;
6import org.apache.ibatis.annotations.Insert;
7import org.apache.ibatis.annotations.Param;
8import org.apache.ibatis.annotations.Result;
9import org.apache.ibatis.annotations.Results;
10import org.apache.ibatis.annotations.Select;
11import org.apache.ibatis.annotations.SelectProvider;
12import org.apache.ibatis.annotations.Update;
13import org.fhp.springmybatis.entity.Person;
14
15public interface PersonDao {
16 
17  @Insert(value=&quot;insert into t_person(name, nick) values (#{name}, #{nick})&quot;)
18  void add(Person person);
19 
20  @Delete(value=&quot;delete from t_person where id=#{id}&quot;)
21  void delete(long id);
22 
23  @Update(value=&quot;update t_person set name=#{name}, nick=#{nick} where id=#{id}&quot;)
24  void update(Person person);
25 
26  @Select(value=&quot;select * from t_person where id=#{id}&quot;)
27  Person select(long id);
28}
29

1
2
1 可以看到,通过@Insert,@Delete,@Update,@Select注解加SQL语句的配置,即可实现MyBatis对数据库的增删改查操作。
2

那么假如需要动态地生成SQL语句,该怎么办呢?答案是使用MyBatis提供的@InsertProvider,@DeleteProvider,@UpdateProvider,@SelectProvider注解,当然也是对应数据库的增删改查。这里以@SelectProvider为例。

首先定义一个Provider类。

清单9 Provider类


1
2
3
4
5
6
7
8
9
10
11
1public class PersonSqlProvider {
2   public String selectByNameAndNick(@Param(&quot;name&quot;) String name, @Param(&quot;nick&quot;) String nick) {
3       StringBuffer sb = new StringBuffer();
4       sb.append(&quot;select * from t_person where &quot;);
5       sb.append(&quot;name=#{name}&quot;);
6       sb.append(&quot; and &quot;);
7       sb.append(&quot;nick=#{nick}&quot;);
8       return sb.toString();
9   }
10}
11

然后就要有请我们的@SelectProvider出场了。

清单10 使用@SelectProvider


1
2
3
1@SelectProvider(type=PersonSqlProvider.class, method=&quot;selectByNameAndNick&quot;)
2List&lt;Person&gt; selectByNameAndNick(@Param(&quot;name&quot;) String name, @Param(&quot;nick&quot;) String nick);
3

当然,在本例当中即使不用Provider也是能够实现的,这里只是为了演示Provider的效果。我们可以看到,SQL语句由程序拼接,自然可以实现动态SQL中if条件判断以及SQL当中in语句等复杂语句的拼接,而且一定程度上比用XML更灵活。

综上,本文介绍了Spring与MyBatis整合的另一种思路——纯注解无XML的配置方法。随着越来越多的框架都逐渐采用注解进行配置,可以说无XML配置已经成为一种趋势。如果你已经用上了Spring 4,不妨尝试一下这样的方法,你一定会感到很满意的。

给TA打赏
共{{data.count}}人
人已打赏
安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

安全运维

设计模式的设计原则

2021-12-12 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索