×

配置Spring Boot集成MyBatis、通用Mapper、Quartz、PageHelper

96
木木不哭_4a70
2017.07.19 18:01* 字数 1770

首先感谢csdn大大的文章,blog.csdn.net/jrainbow/article/details/51980036,本文是在该博客基础下扩展。

1、Maven构建Spring Boot

1.1创建Maven 工程

使用spring-boot-starter-parent来构建Spring Boot项目是一个很好的方法,但很多项目本身就是依赖其它的父模块的,再或者spring-boot-starter-parent默认提供的那么多配置和功能我们用不到。引入spring-boot-starter-parent依赖及web依赖,编辑
pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ljy</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot</name>
    <packaging>jar</packaging>
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.3.RELEASE</version>
    </parent>
    <!-- Add typical dependencies for a web application -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>

1.2 启动入口

update project后,建立如下结构,并创建启动文件 Application.java

Paste_Image.png

Application.java

package com.ljy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

入口类Application带main方法,我们直接运行main方法就能启动Spring Boot项目了,这样极大程序地方便了我们调试程序和项目。

Application类说明自己是Spring Boot的入口类,那么需要加入@Configuration注解。

@EnableAutoConfiguration习惯放在主方法类Application上,当项目运行时,Spring容器去自动查找带特定注解的类,如:带@Entity、@Service等类。

@ComponentScan如果不带basePackage 属性的话,它会自动扫描以入口类所在的包为父节点下所有子包下的类。这也是Spring Boot会提议我们把Application类放于根包路径下。

如果我们的项目和Spring Boot建议的代码结构一样,Application类放在根包路径下。那么我们可以使用@SpringBootApplication来代替上。这里我们就用@SpringBootApplication。

最基础的springboot已经配置完毕。

1.3新建首页html

Paste_Image.png

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    This is my HTML page2. <br>
  </body>
</html>

试下是不是配置成功了。运行启动文件Application.java,访问http://localhost:8080/,默认端口8080,首页默认index.jsp、index.html。结果成功访问首页

Paste_Image.png

如果启动失败报错
java.lang.UnsupportedClassVersionError: javax/annotation/ManagedBean : Unsupported major.minor version 51.0
则需要指定jdk版本。

注意:默认配置的/**映射到/static(或/public ,/resources,/META-INF/resources)

当请求/index.html的时候,Spring MVC 会在/static/目录下面找到。

所以如果访问http://localhost:8080/static/index.html,那么上面配置的几个目录下面都没有/static目录,因此会找不到资源文件!

所以写静态资源位置的时候,不要带上映射的目录名(如/static/,/public/ ,/resources/,/META-INF/resources/)!

如果我按如下结构存放相同名称的图片,那么Spring Boot 读取图片的优先级是怎样的呢? 如下图:

这里写图片描述

当我们访问地址 http://localhost:8080/fengjing.jpg 的时候,显示哪张图片?这里博主可以直接告诉大家,优先级顺序为:META/resources > resources > static > public 如果我们想访问pic2.jpg,请求地址 http://localhost:8080/img/pic2.jpg


2.Spring Boot的Web项目实现

2.1 Application类支持Web应用

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}

入口类Application继承SpringBootServletInitializer并重写configure方法。运行主方法后,会将我们的web项目打包成war,并默认启动tomcat容器来运行我们的Web项目。

2.2服务器端口更改

spring会从classpath下的/config目录或者classpath的根目录查找application.properties或application.yml。两种配置特点自行查询。这里选择yml。

Paste_Image.png

application.yml

# Server settings  
server:  
    port: 80
    address: 127.0.0.1
# SPRING PROFILES  
spring:         
    # HTTP ENCODING  
    http:  
        encoding.charset: UTF-8  
        encoding.enable: true  
        encoding.force: true  

这里需要注意,yml配置文件是的值属性前面必须有一个空格,如果没有空格,Spring的解析器会忽略此配置项。

2.3Controller

Spring Boot应用中@RestController的Controller带有默认基于Jackson2的对象转JSON功能。如:

@RestController
public class MyController {

    @RequestMapping("/thing")
    public MyThing thing() {
            return new MyThing();
    }

}

如需跳转,
可以在application.yml设置前缀后缀

spring:  
          mvc:
                  view.prefix: /WEB-INF/jsp/
                  view.suffix: .jsp

跳转类如下:

@Controller
public class MyController {

    @RequestMapping("/thing")
    public String thing() {
            return “test”;
    }

}

2.4Spring Boot应用实现热部署

<!-- spring热部署 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>springloaded</artifactId>
        </dependency>

当系统通过 mvn spring-boot:run启动或者 右键application debug 启动java文件时,系统会监视classes文件,当有classes文件被改动时,系统会重新加载类文件,不用重启启动服务。

注:使用application run(非debug模式下),热部署功能会失效。

2.5打包成jar/war插件

放在project子节点

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

这时已经可以打成独立的jar包运行。

Paste_Image.png
Paste_Image.png

3.Spring Boot集成MyBatis

3.1加入基础依赖

mybatis:

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.0</version>
        </dependency>

mybatis-spring-boot-starter:

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

mysql:

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

3.2数据库配置

# SPRING PROFILES  
spring:         
    # DATASOURCE  
    datasource:  
        driverClass: com.mysql.jdbc.Driver  
        url: jdbc:mysql://127.0.0.1:3306/springboot?useUnicode=true&characterEncoding=utf-8  
        username: root  
        password: test 

3.3引入通用Mapper

引入依赖

        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.3.7</version>
        </dependency>

配置通用Mapper
MyBatisMapperScannerConfig.java

package com.ljy.common.configure;

import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

@Configuration
public class MyBatisMapperScannerConfig {
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.ljy.dao");//扫描该路径下的dao
        Properties properties = new Properties();
        properties.setProperty("mappers", "com.ljy.common.BaseDao");//通用dao
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }

}

其实MyBatisMapperScannerConfig 是一个MyBatis扫描Mapper接口扫描。

MapperScannerConfigurer根据指定的创建接口或注解创建映射器。我们这里映射了com.ljy.dao包下的接口。

使用MapperScannerConfigurer,没有必要去指定SqlSessionFactory或SqlSessionTemplate,因为MapperScannerConfigurer将会创建MapperFactoryBean,之后自动装配。但是,如果你使用了一个以上的DataSource(因此,也是多个的SqlSessionFactory),那么自动装配可能会失效。这种情况下,你可以使用sqlSessionFactory或sqlSessionTemplate属性来设置正确的工厂/模板。

注意的是网络上有些文章中在MapperScannerConfigurer之前还配置了 MyBatisConfig,因为MapperScannerConfigurer会创建MapperFactoryBean,所以我的项目中没有再配置MyBatisConfig。经使用没有出现任何问题。

3.4通用Mapper的使用(Dao层)

BaseDao.java

package com.ljy.common;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

public interface BaseDao<T> extends Mapper<T>,MySqlMapper<T>{

}

附上测试表sql

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `username` varchar(255) DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'test', '1');
INSERT INTO `user` VALUES ('2', 'user', '2');

表实体类:
User.java

package com.ljy.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

public class User implements Serializable {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private Integer state;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

}

*Dao:

package com.ljy.dao;

import com.ljy.common.BaseDao;
import com.ljy.entity.User;

public interface UserDao extends BaseDao<User>{

}

MyBatis的Dao与其它的ORM框架不一样的是,MyBatis的Dao其实就是Mapper,是一个接口,是通过MapperScannerConfigurer扫描后生成实现的,我们不需要再写Dao接口的实现。

3.5业务处理及事务(Service层)

*Service

package com.ljy.service;

public interface UserService {

}

*ServiceImpl

package com.ljy.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ljy.dao.UserDao;
import com.ljy.entity.User;
import com.ljy.service.UserService;
@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;
    public User getUser(int id) {
        return userDao.selectByPrimaryKey(id);
    }
}

Spring Boot集成MyBatis后,实现事物管理的方法很简单,只需要在业务方法前面加上@Transactional注解就可以了。

写个类看下成功没
Test.java

package com.ljy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.ljy.entity.User;
import com.ljy.service.UserService;

@RestController
public class Test {
    @Autowired
    private UserService userService;

    @RequestMapping("/test")
    public User test() {
        return userService.getUser(1);
    }
}

运行springboot后访问http://localhost/test,成功

Paste_Image.png

4.集成PageHelper

4.1依赖包

<dependency>  
    <groupId>com.github.pagehelper</groupId>  
    <artifactId>pagehelper</artifactId>  
    <version>4.1.0</version>  
</dependency>  

4.2配置类

MybatisConf.java

package com.ljy.common.configure;

import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.pagehelper.PageHelper;

/*  
 * 注册MyBatis分页插件PageHelper  
 */  
  
@Configuration  
public class MybatisConf {  
        @Bean  
        public PageHelper pageHelper() {  
           System.out.println("MyBatisConfiguration.pageHelper()");  
            PageHelper pageHelper = new PageHelper();  
            Properties p = new Properties();  
            p.setProperty("offsetAsPageNum", "true");  
            p.setProperty("rowBoundsWithCount", "true");  
            p.setProperty("reasonable", "true");  
            pageHelper.setProperties(p);  
            return pageHelper;  
        }  
}  

这时就可以使用PageHelp插件了,在controller中直接使用。
Test.java

package com.ljy.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ljy.dao.UserDao;
import com.ljy.entity.User;
import com.ljy.service.UserService;

@RestController
public class Test {
    @Autowired
    private UserService userService;
    @RequestMapping("/test")
    public PageInfo<User> test() {
         /*  
         * 第一个参数是第几页;第二个参数是每页显示条数。  
         */  
        PageHelper.startPage(1,1);  
        List<User> list=userService.getUsers();
        PageInfo<User> pageInfo=new PageInfo<User>(list);
        return pageInfo; 

    }
}

UserService .java

package com.ljy.service;

import java.util.List;
import com.ljy.entity.User;

public interface UserService {
    public User getUser(int id);
    public List<User> getUsers();
}

UserServiceImpl.java

package com.ljy.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ljy.dao.UserDao;
import com.ljy.entity.User;
import com.ljy.service.UserService;
@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;
    public User getUser(int id) {
        return userDao.selectByPrimaryKey(id);
    }
    @Override
    public List<User> getUsers() {
        // TODO Auto-generated method stub
        return userDao.selectAll();
    }
}
Paste_Image.png

4.3PageHelper实现原理

参考这篇文章http://blog.csdn.net/jaryle/article/details/52315565

原理:

pageHelper会使用ThreadLocal获取到同一线程中的变量信息,各个线程之间的Threadlocal不会相互干扰,也就是Thread1中的ThreadLocal1之后获取到Tread1中的变量的信息,不会获取到Thread2中的信息
所以在多线程环境下,各个Threadlocal之间相互隔离,可以实现,不同thread使用不同的数据源或不同的Thread中执行不同的SQL语句
所以,PageHelper利用这一点通过拦截器获取到同一线程中的预编译好的SQL语句之后将SQL语句包装成具有分页功能的SQL语句,并将其再次赋值给下一步操作,所以实际执行的SQL语句就是有了分页功能的SQL语句

5集成quartz

完全借鉴了文章http://www.jianshu.com/p/2f45eadca7f9,感谢简书作者。

5.1.依赖包引入

<dependency> 
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId> 
</dependency>
<dependency> 
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId> 
</dependency>
<dependency> 
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>

5.2.注册[pring-boot启动完成事件监听,用于启动job任务

SchedulerListener.java

package com.ljy.common.shcedule;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class SchedulerListener implements ApplicationListener<ContextRefreshedEvent> { 
    @Autowired
    public MyScheduler myScheduler;
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) { 
        try {
            myScheduler.scheduleJobs();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
     } 
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); 
        return schedulerFactoryBean; 
    }
}

5.3、job参数设置

MyScheduler.java

package com.ljy.common.shcedule;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

@Component
public class MyScheduler {
    @Autowired
    SchedulerFactoryBean schedulerFactoryBean;
    public void scheduleJobs() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        startJob1(scheduler); 
        startJob2(scheduler); 
    }
    private void startJob1(Scheduler scheduler) throws SchedulerException{
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob.class) .withIdentity("job1", "group1").build(); 
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?"); 
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") .withSchedule(scheduleBuilder).build(); 
        scheduler.scheduleJob(jobDetail,cronTrigger); 
    } 
    private void startJob2(Scheduler scheduler) throws SchedulerException{ 
        JobDetail jobDetail = JobBuilder.newJob(ScheduledJob2.class) .withIdentity("job2", "group1").build();
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?"); 
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group1") .withSchedule(scheduleBuilder).build(); 
        scheduler.scheduleJob(jobDetail,cronTrigger);
    }
}

5.4.实现各个任务job

package com.ljy.common.shcedule;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class ScheduledJob implements Job{

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        // TODO Auto-generated method stub
        System.out.println("1任务运行----------------------");
    }

}

接下来就是见证奇迹的时刻

Paste_Image.png

附上源码地址https://github.com/tianya1451/springboot

日记本
Web note ad 1