SpringBoot 集成SpringBatch 批处理框架

2023-10-26

SpringBatch 核心组件简介:

 1)JobRepository:用来注册Job容器,设置数据库相关属性。
 2)JobLauncher:用来启动Job的接口
 3)Job:我们要实际执行的任务,包含一个或多个
 4)Step:即步骤,包括:ItemReader->ItemProcessor->ItemWriter
 5)ItemReader:用来读取数据,做实体类与数据字段之间的映射。比如读取csv文件中的人员数据,之后对应实体AuthUser的字段做mapper
 6)ItemProcessor:用来处理数据的接口,同时可以做数据校验(设置校验器,使用JSR-303(hibernate-validator)注解)
 7)ItemWriter:用来输出数据的接口,设置数据库源。编写预处理SQL插入语句

使用说明:在自定义的SpringBatch配置对象中一一实列化七大组件,并且在程序入口开启@EnableBatchProcessing

package com.zzg.batch;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement
@MapperScan("com.zzg.batch.mapper")
public class Application extends SpringBootServletInitializer{

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
		System.out.println("============= SpringBoot gcxt-system-provider Service Start Success =============");

	}

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
		// 注意这里要指向原先用main方法执行的Application启动类
		return builder.sources(Application.class);
	}
}

SpringBatch 批处理流程图:

SpringBatch 实践

第一步:依赖核心jar文件:

<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.zzg</groupId>
	<artifactId>jreport</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.1.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<mybatis-spring-boot-starter.version>1.3.2</mybatis-spring-boot-starter.version>
		<mysql-connector-java.version>8.0.11</mysql-connector-java.version>
		<com.alibaba.druid.version>1.1.9</com.alibaba.druid.version>
		<commons-lang.version>2.6</commons-lang.version>
		<commons-codec.version>1.10</commons-codec.version>
		<commons-lang3.version>3.8.1</commons-lang3.version>
		<commons-net.version>3.6</commons-net.version>
		<commons-io.version>2.6</commons-io.version>
		<commons-collections.version>3.2.1</commons-collections.version>
		<common-fileupload.version>1.3.1</common-fileupload.version>
		<fastjson.version>1.2.48</fastjson.version>
		<jasperreports.version>6.10.0</jasperreports.version>
	</properties>


	<dependencies>
		<!-- SpringWeb模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!--springboot 集成测试框架 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>


		<!--lombok插件 -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>${lombok.version}</version>
			<scope>provided</scope>
		</dependency>


		<!-- mysql 连接 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>${mybatis-spring-boot-starter.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql-connector-java.version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>${com.alibaba.druid.version}</version>
		</dependency>
		<!-- 分页控件 -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>4.1.6</version>
		</dependency>

		<!--common-lang 常用工具包 -->
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>${commons-lang.version}</version>
		</dependency>
		<!--commons-lang3 工具包 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>${commons-lang3.version}</version>
		</dependency>

		<!--commons-codec 加密工具包 -->
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>${commons-codec.version}</version>
		</dependency>
		<!--commons-net 网络工具包 -->
		<dependency>
			<groupId>commons-net</groupId>
			<artifactId>commons-net</artifactId>
			<version>${commons-net.version}</version>
		</dependency>
		<!--common-io 工具包 -->
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>${commons-io.version}</version>
		</dependency>
		<!--common-collection 工具包 -->
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>${commons-collections.version}</version>
		</dependency>
		<!--common-fileupload 工具包 -->
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>${common-fileupload.version}</version>
		</dependency>

		<!-- Swagger2 -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.7.0</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.7.0</version>
		</dependency>

		<!-- fastjson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>${fastjson.version}</version>
		</dependency>

	    <!-- 集成springboot batch 批处理 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-batch</artifactId>
		</dependency>


	</dependencies>
	
</project>

第二步:application.properties 配置文件

# 指定服务端口
server.port=7090
# 指定服务 名称
# server.context-path=/jreport
#mybatis xml 文件配置
mybatis.mapper-locations=classpath*:mapper/batch/*Mapper.xml
mybatis.type-aliases-package=com.zzg.batch.domain
# MyBatis mysql8 配置
spring.datasource.url=jdbc:mysql://192.168.1.**:3306/boot-security?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
spring.datasource.username=**
spring.datasource.password=**
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Druid 配置
# 初始化时建立物理连接的个数
spring.datasource.druid.initial-size=5
# 最大连接池数量
spring.datasource.druid.max-active=30
# 最小连接池数量
spring.datasource.druid.min-idle=5
# 获取连接时最大等待时间,单位毫秒
spring.datasource.druid.max-wait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.druid.time-between-eviction-runs-millis=60000
# 连接保持空闲而不被驱逐的最小时间
spring.datasource.druid.min-evictable-idle-time-millis=300000
# 用来检测连接是否有效的sql,要求是一个查询语句
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
spring.datasource.druid.test-while-idle=true
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.druid.test-on-borrow=false
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.druid.test-on-return=false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
spring.datasource.druid.pool-prepared-statements=true
# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=50
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计
#spring.datasource.druid.filters=stat,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.druid.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# 合并多个DruidDataSource的监控数据
spring.datasource.druid.use-global-data-source-stat=true
# 配置sql 注入方式
spring.datasource.druid.filters=stat
# 日志文件配置
logging.config=classpath:logback.xml

# springboot 批处理配置
spring.batch.job.enabled=false
spring.batch.initialize-schema=always

第三步:配置类

package com.zzg.batch.config;

import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;
import com.zzg.batch.domain.AuthUser;
import com.zzg.batch.processor.CVSItemProcessor;
import com.zzg.batch.processor.listener.CSVJobListener;
import com.zzg.batch.processor.validator.BeanValidator;
/**
 * springboot batch 配置类
 * @author zzg
 *
 */
@Configuration
@EnableBatchProcessing // 开启批处理的支持
public class BatchConfig {
	
	@Autowired
	private DataSource dataSource;
	
	@Autowired
	private PlatformTransactionManager transactionManager;
	
	
	/**
     * ItemReader定义:读取文件数据+entirty映射
     * @return
     */
    @Bean
    public ItemReader<AuthUser> reader(){
        // 使用FlatFileItemReader去读cvs文件,一行即一条数据
        FlatFileItemReader<AuthUser> reader = new FlatFileItemReader<>();
        // 设置文件处在路径
        reader.setResource(new ClassPathResource("user.csv"));
        // entity与csv数据做映射
        reader.setLineMapper(new DefaultLineMapper<AuthUser>() {
            {
                setLineTokenizer(new DelimitedLineTokenizer() {
                    {
                        setNames(new String[]{"id", "password"});
                    }
                });
                setFieldSetMapper(new BeanWrapperFieldSetMapper<AuthUser>() {
                    {
                        setTargetType(AuthUser.class);
                    }
                });
            }
        });
        return reader;
    }
    
    /**
     * 注册ItemProcessor: 处理数据
     * @return
     */
    @Bean
    public ItemProcessor<AuthUser, AuthUser> processor(){
    	CVSItemProcessor cvsItemProcessor = new CVSItemProcessor();
    	cvsItemProcessor.setValidator(new BeanValidator<AuthUser>());
        return cvsItemProcessor;
    }
    
    /**
     * ItemWriter定义:指定datasource,设置批量插入sql语句,写入数据库
     * @param dataSource
     * @return
     */
    @Bean
    public ItemWriter<AuthUser> writer(){
        // 使用jdbcBcatchItemWrite写数据到数据库中
        JdbcBatchItemWriter<AuthUser> writer = new JdbcBatchItemWriter<>();
        // 设置有参数的sql语句
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<AuthUser>());
        String sql = "insert into auth_user (id, password)" + " values(:id, :password)";
        writer.setSql(sql);
        writer.setDataSource(dataSource);
        return writer;
    }
    
    /**
     * JobRepository定义:设置数据库,注册Job容器
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean
    public JobRepository cvsJobRepository() throws Exception{
        JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
        jobRepositoryFactoryBean.setDatabaseType("mysql");
        jobRepositoryFactoryBean.setTransactionManager(transactionManager);
        jobRepositoryFactoryBean.setDataSource(dataSource);
        return jobRepositoryFactoryBean.getObject();
    }
    
    /**
     * jobLauncher定义:
     * @param dataSource
     * @param transactionManager
     * @return
     * @throws Exception
     */
    @Bean
    public SimpleJobLauncher csvJobLauncher() throws Exception{
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        // 设置jobRepository
        jobLauncher.setJobRepository(cvsJobRepository());
        return jobLauncher;
    }
    
    /**
     * 定义job
     * @param jobs
     * @param step
     * @return
     */
    @Bean
    public Job importJob(JobBuilderFactory jobs, Step step){
        return jobs.get("importCsvJob")
                .incrementer(new RunIdIncrementer())
                .flow(step)
                .end()
                .listener(csvJobListener())
                .build();
    }

    /**
     * 注册job监听器
     * @return
     */
    @Bean
    public CSVJobListener csvJobListener(){
        return new CSVJobListener();
    }
    
    /**
     * step定义:步骤包括ItemReader->ItemProcessor->ItemWriter 即读取数据->处理校验数据->写入数据
     * @param stepBuilderFactory
     * @param reader
     * @param writer
     * @param processor
     * @return
     */
    @Bean
    public Step step(StepBuilderFactory stepBuilderFactory, ItemReader<AuthUser> reader,
                     ItemWriter<AuthUser> writer, ItemProcessor<AuthUser, AuthUser> processor){
        return stepBuilderFactory
                .get("step")
                .<AuthUser, AuthUser>chunk(65000) // Chunk的机制(即每次读取一条数据,再处理一条数据,累积到一定数量后再一次性交给writer进行写入操作)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }
}
package com.zzg.batch.config;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
/**
 * druid 监控配置
 * @author zzg
 *
 */
@Configuration
public class DruidConfig {
	 	@Bean
	    public ServletRegistrationBean druidServletRegistrationBean() {
	        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
	        servletRegistrationBean.setServlet(new StatViewServlet());
	        servletRegistrationBean.addUrlMappings("/druid/*");
	        servletRegistrationBean.addInitParameter("allow", "");
	        servletRegistrationBean.addInitParameter("deny", "");
	        servletRegistrationBean.addInitParameter("loginUsername", "admin");
	        servletRegistrationBean.addInitParameter("loginPassword", "admin");
	        return servletRegistrationBean;
	    }

	    /**
	     * 注册DruidFilter拦截
	     *
	     * @return
	     */
	    @Bean
	    public FilterRegistrationBean duridFilterRegistrationBean() {
	        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
	        filterRegistrationBean.setFilter(new WebStatFilter());
	        Map<String, String> initParams = new HashMap<String, String>();
	        //设置忽略请求
	        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
	        filterRegistrationBean.setInitParameters(initParams);
	        filterRegistrationBean.addUrlPatterns("/*");
	        return filterRegistrationBean;
	    }
}
package com.zzg.batch.config;

import java.util.Properties;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.pagehelper.PageHelper;

/**
 * mybatis 配置对象
 * @author zzg
 *
 */
@Configuration
public class MyBatisConfig {
	/**
	 * 分页对象实列化
	 * @return
	 */
	@Bean
	public PageHelper pageHelper() {
		PageHelper pageHelper = new PageHelper();
		Properties p = new Properties();
		p.setProperty("offsetAsPageNum", "true");
		p.setProperty("rowBoundsWithCount", "true");
		p.setProperty("reasonable", "true");
		p.setProperty("dialect", "mysql");
		pageHelper.setProperties(p);
		return pageHelper;
	}
}
package com.zzg.batch.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.swagger.annotations.ApiOperation;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
	@Bean
	public Docket buildDocket() {

		ParameterBuilder tokenPar = new ParameterBuilder();
		List<Parameter> pars = new ArrayList<Parameter>();
		tokenPar.name("X-CSRF-TOKEN").description("令牌").modelRef(new ModelRef("string")).parameterType("header")
				.required(false).build();
		pars.add(tokenPar.build());

		return new Docket(DocumentationType.SWAGGER_2).select()
				.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any())
				.build().globalOperationParameters(pars).apiInfo(buildApiInf());
	}

	private ApiInfo buildApiInf() {
		return new ApiInfoBuilder().title("****").termsOfServiceUrl("http://www.baidu.cn/")
				.description("API接口")
				.contact(new Contact("baidu", "http://www.baidu.cn/", "zhouzhiwengang@163.com"))
				.version("2.0").build();

	}
}

业务逻辑层代码:model、service、mapper层的相关代码:

package com.zzg.batch.domain;

import java.util.Date;

public class AuthUser {
    private Integer id;

    private String password;

    private Date lastLogin;

    private String isSuperuser;

    private String username;

    private String firstName;

    private String lastName;

    private String email;

    private String isStaff;

    private String isActive;

    private Date dateJoined;

    public Integer getId() {
        return id;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    public Date getLastLogin() {
        return lastLogin;
    }

    public void setLastLogin(Date lastLogin) {
        this.lastLogin = lastLogin;
    }

    public String getIsSuperuser() {
        return isSuperuser;
    }

    public void setIsSuperuser(String isSuperuser) {
        this.isSuperuser = isSuperuser;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName == null ? null : firstName.trim();
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName == null ? null : lastName.trim();
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email == null ? null : email.trim();
    }

    public String getIsStaff() {
        return isStaff;
    }

    public void setIsStaff(String isStaff) {
        this.isStaff = isStaff;
    }

    public String getIsActive() {
        return isActive;
    }

    public void setIsActive(String isActive) {
        this.isActive = isActive;
    }

    public Date getDateJoined() {
        return dateJoined;
    }

    public void setDateJoined(Date dateJoined) {
        this.dateJoined = dateJoined;
    }
}
package com.zzg.batch.mapper;

import java.util.List;
import java.util.Map;
import com.zzg.batch.domain.AuthUser;

public interface AuthUserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(AuthUser record);

    int insertSelective(AuthUser record);

    AuthUser selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(AuthUser record);

    int updateByPrimaryKey(AuthUser record);
    
    // 方法梳理
    List<AuthUser> selectAll(Map<String, Object> paramter);
}
package com.zzg.batch.service;

import java.util.List;
import java.util.Map;
import com.zzg.batch.domain.AuthUser;
import com.zzg.jreport.common.BaseService;
import com.zzg.jreport.common.page.PageData;
import com.zzg.jreport.common.page.PageParam;

public interface AuthUserService extends BaseService<AuthUser> {
	 // 方法梳理
    List<AuthUser> selectAll(Map<String, Object> paramter);
    
    PageData<AuthUser> selectAllPage(Map<String,Object> parame, PageParam rb);
    
    // 事务测试
    void transaction();

}
package com.zzg.batch.service.impl;

import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zzg.batch.domain.AuthUser;
import com.zzg.batch.mapper.AuthUserMapper;
import com.zzg.batch.service.AuthUserService;
import com.zzg.jreport.common.convert.SimpleTypeConverterUtil;
import com.zzg.jreport.common.page.PageData;
import com.zzg.jreport.common.page.PageParam;

@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
public class AuthUserServiceImpl implements AuthUserService {
	@Autowired
	private AuthUserMapper mapper;

	@Override
	public Long insert(AuthUser entity) {
		// TODO Auto-generated method stub
		Integer num = mapper.insertSelective(entity);
		return Long.valueOf(num);
	}

	@Override
	public void updateByPrimaryKeySelective(AuthUser entity) {
		// TODO Auto-generated method stub
		mapper.updateByPrimaryKeySelective(entity);
	}

	@Override
	public AuthUser selectByPrimaryKey(String sid) {
		// TODO Auto-generated method stub
		return mapper.selectByPrimaryKey(SimpleTypeConverterUtil.convertIfNecessary(sid, int.class));
	}

	@Override
	public void deleteByPrimaryKey(String sid) {
		// TODO Auto-generated method stub
		mapper.deleteByPrimaryKey(SimpleTypeConverterUtil.convertIfNecessary(sid, int.class));
	}

	@Override
	public List<AuthUser> selectAll(Map<String, Object> paramter) {
		// TODO Auto-generated method stub
		return mapper.selectAll(paramter);
	}

	@Override
	public PageData<AuthUser> selectAllPage(Map<String, Object> parame, PageParam rb) {
		// TODO Auto-generated method stub
		PageData<AuthUser> pageData = new PageData<AuthUser>();

		PageHelper.startPage(rb.getPageNo(), rb.getLimit());
		List<AuthUser> rs = mapper.selectAll(parame);

		PageInfo<AuthUser> pageInfo = new PageInfo<AuthUser>(rs);
		pageData.setData(pageInfo.getList());
		pageData.setPageNum(pageInfo.getPageNum());
		pageData.setPageSize(pageInfo.getPageSize());
		pageData.setTotalCount(pageInfo.getTotal());
		return pageData;
	}

	@Override
	public void transaction() {
		// TODO Auto-generated method stub
		AuthUser admin = new AuthUser();
		admin.setId(1);
		admin.setUsername("admin");
		mapper.updateByPrimaryKeySelective(admin);
		
		int a = 1 / 0;
		
		AuthUser superMan = new AuthUser();
		superMan.setId(2);
		superMan.setUsername("superMan");
		mapper.updateByPrimaryKeySelective(superMan);
		
		
	}

}
package com.zzg.batch.controller;

import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.zzg.batch.domain.AuthUser;
import com.zzg.batch.service.AuthUserService;
import com.zzg.jreport.common.controller.AbstractController;
import com.zzg.jreport.common.page.PageData;
import com.zzg.jreport.common.page.PageParam;
import com.zzg.jreport.response.JreportResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@Controller
@RequestMapping("/api/auth/user")
@Api(value = "用户Controlle", tags = "用户操作服务")
public class AuthUserController extends AbstractController {

	@Autowired
	private AuthUserService service;
	
	@ApiOperation(httpMethod = "POST", value = "用户对象保存")
	@RequestMapping(value = "/insert", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public JreportResponse insert(
			@RequestBody @ApiParam(name = "用户对象", value = "json格式对象", required = true) AuthUser entity) {
		Long engSid = service.insert(entity);
		return JreportResponse.ok(engSid);
		
	}
	
	@ApiOperation(httpMethod = "POST", value = "用户对象更新")
	@RequestMapping(value = "/update", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public JreportResponse update(
			@RequestBody @ApiParam(name = "用户对象", value = "json格式对象", required = true) AuthUser entity) {
		service.updateByPrimaryKeySelective(entity);
		return JreportResponse.ok();
	}
	
	@RequestMapping(value="/find", method={RequestMethod.POST}, produces = "application/json;charset=UTF-8")
	@ResponseBody
	@ApiOperation(httpMethod = "POST", value = "用户查询")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "id", value = "主键", required = false, dataType = "Integer", paramType = "query"),
		@ApiImplicitParam(name = "username", value = "用户名称", required = false, dataType = "String", paramType = "query"),
		@ApiImplicitParam(name = "email", value = "用户邮箱", required = false, dataType = "String", paramType = "query"),
		@ApiImplicitParam(name = "isStaff", value = "是否在职:1 在职、2:离职", required = false, dataType = "Integer", paramType = "query"),
		@ApiImplicitParam(name = "isActive", value = "激活状态:1 已激活、2:未激活", required = false, dataType = "Integer", paramType = "query")
	})
	public JreportResponse find(@RequestBody @ApiParam(name = "用户对象", value = "json格式对象", required = true) JSONObject entity) {
		Map<String, Object> param = JSONObject.toJavaObject(entity, Map.class);
		List<AuthUser> list = service.selectAll(param);
		return JreportResponse.ok(list);
	}
	
	
	@RequestMapping(value="/findByPage", method={RequestMethod.POST}, produces = "application/json;charset=UTF-8")
	@ResponseBody
	@ApiOperation(httpMethod = "POST", value = "用户分页查询")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "id", value = "主键", required = false, dataType = "Integer", paramType = "query"),
		@ApiImplicitParam(name = "username", value = "用户名称", required = false, dataType = "String", paramType = "query"),
		@ApiImplicitParam(name = "email", value = "用户邮箱", required = false, dataType = "String", paramType = "query"),
		@ApiImplicitParam(name = "isStaff", value = "是否在职:1 在职、2:离职", required = false, dataType = "Integer", paramType = "query"),
		@ApiImplicitParam(name = "isActive", value = "激活状态:1 已激活、2:未激活", required = false, dataType = "Integer", paramType = "query")
	})
	public JreportResponse findByPage(@RequestBody @ApiParam(name = "用户对象", value = "json格式对象", required = true) JSONObject entity) {

		Map<String, Object> param = JSONObject.toJavaObject(entity, Map.class);
		PageParam rb = super.initPageBounds(param);
		PageData<AuthUser> pageList = service.selectAllPage(param, rb);
		return JreportResponse.ok(pageList);
	}

	
	
	
}
package com.zzg.batch.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zzg.batch.processor.listener.CSVJobListener;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;


@Controller
@RequestMapping("/api/batch")
@Api(value = "批处理Controlle", tags = "批处理操作服务")
public class BatchController {
	// 日志服务处理
	private Logger logger = LoggerFactory.getLogger(BatchController.class);
	
	@Autowired
	private SimpleJobLauncher  launcher;
	@Autowired
	private Job job;
	
	@ApiOperation(httpMethod = "POST", value = "用户对象保存")
	@RequestMapping(value = "/init", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public void insert() {
		// 后置参数:使用JobParameters中绑定参数
		try{
			JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
					.toJobParameters();
			launcher.run(job, jobParameters);
			
		} catch(Exception e){
			e.printStackTrace();
			logger.error(e.getMessage());
		}
	}

}
package com.zzg.batch.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.zzg.batch.service.AuthUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Controller
@RequestMapping("/api/trans")
@Api(value = "事务处理Controlle", tags = "事务处理操作服务")
public class TransactionController {

	@Autowired
	private AuthUserService service;
	
	@ApiOperation(httpMethod = "POST", value = "事务功能测试")
	@RequestMapping(value = "/init", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public void init() {
		service.transaction();
	}

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzg.batch.mapper.AuthUserMapper">
	<resultMap id="BaseResultMap" type="com.zzg.batch.domain.AuthUser">
		<id column="id" jdbcType="INTEGER" property="id" />
		<result column="password" jdbcType="VARCHAR" property="password" />
		<result column="last_login" jdbcType="TIMESTAMP" property="lastLogin" />
		<result column="is_superuser" jdbcType="VARCHAR" property="isSuperuser" />
		<result column="username" jdbcType="VARCHAR" property="username" />
		<result column="first_name" jdbcType="VARCHAR" property="firstName" />
		<result column="last_name" jdbcType="VARCHAR" property="lastName" />
		<result column="email" jdbcType="VARCHAR" property="email" />
		<result column="is_staff" jdbcType="VARCHAR" property="isStaff" />
		<result column="is_active" jdbcType="VARCHAR" property="isActive" />
		<result column="date_joined" jdbcType="TIMESTAMP" property="dateJoined" />
	</resultMap>
	<sql id="Base_Column_List">
		id, password, last_login, is_superuser, username,
		first_name, last_name,
		email, is_staff,
		is_active, date_joined
	</sql>
	<sql id="condition">
		<if test="id != null">
			and id = #{id}
		</if>
		<if test="username != null and username != ''">
			and username = #{username}
		</if>
		<if test="email != null and email !=''">
			and email = #{email}
		</if>
		<if test="isStaff != null">
			and is_staff = #{isStaff}
		</if>
		<if test="isActive != null">
			and is_active = #{isActive}
		</if>
	</sql>
	<!-- 方法梳理 -->
	<select id="selectAll" parameterType="java.util.Map" resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from auth_user
		where 1 = 1
		<include refid="condition"></include>
	</select>

	<select id="selectByPrimaryKey" parameterType="java.lang.Integer"
		resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from auth_user
		where id = #{id,jdbcType=INTEGER}
	</select>
	<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
		delete from
		auth_user
		where id = #{id,jdbcType=INTEGER}
	</delete>
	<insert id="insert" parameterType="com.zzg.batch.domain.AuthUser">
		insert into auth_user (id,
		password, last_login,
		is_superuser, username, first_name,
		last_name,
		email, is_staff,
		is_active, date_joined)
		values (#{id,jdbcType=INTEGER},
		#{password,jdbcType=VARCHAR},
		#{lastLogin,jdbcType=TIMESTAMP},
		#{isSuperuser,jdbcType=VARCHAR}, #{username,jdbcType=VARCHAR},
		#{firstName,jdbcType=VARCHAR},
		#{lastName,jdbcType=VARCHAR},
		#{email,jdbcType=VARCHAR},
		#{isStaff,jdbcType=VARCHAR},
		#{isActive,jdbcType=VARCHAR}, #{dateJoined,jdbcType=TIMESTAMP})
	</insert>
	<insert id="insertSelective" parameterType="com.zzg.batch.domain.AuthUser">
		insert into auth_user
		<trim prefix="(" suffix=")" suffixOverrides=",">
			<if test="id != null">
				id,
			</if>
			<if test="password != null">
				password,
			</if>
			<if test="lastLogin != null">
				last_login,
			</if>
			<if test="isSuperuser != null">
				is_superuser,
			</if>
			<if test="username != null">
				username,
			</if>
			<if test="firstName != null">
				first_name,
			</if>
			<if test="lastName != null">
				last_name,
			</if>
			<if test="email != null">
				email,
			</if>
			<if test="isStaff != null">
				is_staff,
			</if>
			<if test="isActive != null">
				is_active,
			</if>
			<if test="dateJoined != null">
				date_joined,
			</if>
		</trim>
		<trim prefix="values (" suffix=")" suffixOverrides=",">
			<if test="id != null">
				#{id,jdbcType=INTEGER},
			</if>
			<if test="password != null">
				#{password,jdbcType=VARCHAR},
			</if>
			<if test="lastLogin != null">
				#{lastLogin,jdbcType=TIMESTAMP},
			</if>
			<if test="isSuperuser != null">
				#{isSuperuser,jdbcType=VARCHAR},
			</if>
			<if test="username != null">
				#{username,jdbcType=VARCHAR},
			</if>
			<if test="firstName != null">
				#{firstName,jdbcType=VARCHAR},
			</if>
			<if test="lastName != null">
				#{lastName,jdbcType=VARCHAR},
			</if>
			<if test="email != null">
				#{email,jdbcType=VARCHAR},
			</if>
			<if test="isStaff != null">
				#{isStaff,jdbcType=VARCHAR},
			</if>
			<if test="isActive != null">
				#{isActive,jdbcType=VARCHAR},
			</if>
			<if test="dateJoined != null">
				#{dateJoined,jdbcType=TIMESTAMP},
			</if>
		</trim>
	</insert>
	<update id="updateByPrimaryKeySelective" parameterType="com.zzg.batch.domain.AuthUser">
		update auth_user
		<set>
			<if test="password != null">
				password = #{password,jdbcType=VARCHAR},
			</if>
			<if test="lastLogin != null">
				last_login = #{lastLogin,jdbcType=TIMESTAMP},
			</if>
			<if test="isSuperuser != null">
				is_superuser = #{isSuperuser,jdbcType=VARCHAR},
			</if>
			<if test="username != null">
				username = #{username,jdbcType=VARCHAR},
			</if>
			<if test="firstName != null">
				first_name = #{firstName,jdbcType=VARCHAR},
			</if>
			<if test="lastName != null">
				last_name = #{lastName,jdbcType=VARCHAR},
			</if>
			<if test="email != null">
				email = #{email,jdbcType=VARCHAR},
			</if>
			<if test="isStaff != null">
				is_staff = #{isStaff,jdbcType=VARCHAR},
			</if>
			<if test="isActive != null">
				is_active = #{isActive,jdbcType=VARCHAR},
			</if>
			<if test="dateJoined != null">
				date_joined = #{dateJoined,jdbcType=TIMESTAMP},
			</if>
		</set>
		where id = #{id,jdbcType=INTEGER}
	</update>
	<update id="updateByPrimaryKey" parameterType="com.zzg.batch.domain.AuthUser">
		update auth_user
		set password = #{password,jdbcType=VARCHAR},
		last_login =
		#{lastLogin,jdbcType=TIMESTAMP},
		is_superuser =
		#{isSuperuser,jdbcType=VARCHAR},
		username = #{username,jdbcType=VARCHAR},
		first_name = #{firstName,jdbcType=VARCHAR},
		last_name =
		#{lastName,jdbcType=VARCHAR},
		email = #{email,jdbcType=VARCHAR},
		is_staff = #{isStaff,jdbcType=VARCHAR},
		is_active =
		#{isActive,jdbcType=VARCHAR},
		date_joined =
		#{dateJoined,jdbcType=TIMESTAMP}
		where id = #{id,jdbcType=INTEGER}
	</update>
</mapper>

SpringBatch批处理涉及:批处理类、批处理监听器、批处理校验器

package com.zzg.batch.processor;

import org.springframework.batch.item.validator.ValidatingItemProcessor;
import org.springframework.batch.item.validator.ValidationException;

import com.zzg.batch.domain.AuthUser;

public class CVSItemProcessor extends ValidatingItemProcessor<AuthUser> {
	
	// 局部常量
//	public static final String YES = "1";
//	public static final String NO = "2";

	@Override
	public AuthUser process(AuthUser item) throws ValidationException {
		// TODO Auto-generated method stub
		super.process(item);
//		if("是".equalsIgnoreCase(item.getIsSuperuser())){
//			item.setIsSuperuser(YES);
//		} else {
//			item.setIsSuperuser(NO);
//		}
//		
//		if("是".equalsIgnoreCase(item.getIsActive())){
//			item.setIsActive(YES);
//		} else {
//			item.setIsActive(NO);
//		}
//		
//		if("是".equalsIgnoreCase(item.getIsStaff())){
//			item.setIsStaff(YES);
//		} else {
//			item.setIsStaff(NO);
//		}
		return item;
	}
	
}
package com.zzg.batch.processor.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;

public class CSVJobListener implements JobExecutionListener {
	private Logger logger = LoggerFactory.getLogger(CSVJobListener.class);
	
	private long startTime;
    private long endTime;
	@Override
	public void afterJob(JobExecution arg0) {
		// TODO Auto-generated method stub
		 endTime = System.currentTimeMillis();
	     logger.info("job process end...");
	     logger.info("spend time: " + (endTime - startTime) + "ms");
	}

	@Override
	public void beforeJob(JobExecution arg0) {
		// TODO Auto-generated method stub
		 startTime = System.currentTimeMillis();
	     logger.info("job process start...");
	}

}
package com.zzg.batch.processor.validator;


import org.springframework.batch.item.validator.ValidationException;
import org.springframework.batch.item.validator.Validator;
import org.springframework.beans.factory.InitializingBean;

public class BeanValidator<T> implements Validator<T>, InitializingBean {


	@Override
	public void afterPropertiesSet() throws Exception {
	}

	@Override
	public void validate(T value) throws ValidationException {
	}

}

项目整体结构截图:

补全日志配置文件、数据库脚本和测试数据:

<?xml version="1.0" encoding="UTF-8"?> 
  
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->  
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->  
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->  
  
  
<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,
默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。   
    debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->  
<configuration scan="true" scanPeriod="60 seconds" debug="false">  
    <!-- 定义日志文件 输入位置 -->  
    <property name="log_dir" value="/logs/system-provider" />  
    <!-- 日志最大的历史 30天 -->  
    <property name="maxHistory" value="30"/>  
  
  
    <!-- ConsoleAppender 控制台输出日志 -->  
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
        <!-- 对日志进行格式化 -->  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- ERROR级别日志 -->  
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->  
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录WARN级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>ERROR</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--日志输出位置  可相对、和绝对路径 -->  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-error-log.log</fileNamePattern>  
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6,  
            则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
          
        <!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。   
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">     
          <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/.log.zip</fileNamePattern>     
          <minIndex>1</minIndex>     
          <maxIndex>3</maxIndex>     
        </rollingPolicy>   -->  
        <!-- 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动   
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">     
            <maxFileSize>5MB</maxFileSize>     
        </triggeringPolicy>   -->  
          
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- WARN级别日志 appender -->  
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录WARN级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>WARN</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-warn-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- INFO级别日志 appender -->  
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录INFO级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>INFO</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-info-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
      
      
    <!-- DEBUG级别日志 appender -->  
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>DEBUG</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/neo4j-debug-log.log  
            </fileNamePattern>  
            <maxHistory>${maxHistory}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>  
    
    <logger name="java.sql.PreparedStatement" value="DEBUG" />    
    <logger name="java.sql.Connection" value="DEBUG" />    
    <logger name="java.sql.Statement" value="DEBUG" />    
    <logger name="com.ibatis" value="DEBUG" />    
    <logger name="com.ibatis.common.jdbc.SimpleDataSource" value="DEBUG" />    
    <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/>    
    <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" value="DEBUG" />    
    <logger name="org.springframework.web" level="DEBUG"/>
    <logger name="com.zzg.jreport" level="DEBUG"/>
		
      
    <!-- root级别   DEBUG -->  
    <root level="ERROR">  
        <!-- 控制台输出 -->  
        <appender-ref ref="STDOUT" />  
        <!-- 文件输出 -->  
        <appender-ref ref="ERROR" />  
        <appender-ref ref="INFO" />  
        <appender-ref ref="WARN" />  
        <appender-ref ref="DEBUG" />  
    </root>  
</configuration>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot 集成SpringBatch 批处理框架 的相关文章

随机推荐

  • 【学习笔记】启动Nginx、查看nginx进程、查看nginx服务主进程的方式、Nginx服务可接受的信号、nginx帮助命令、Nginx平滑重启、Nginx服务器的升级

    1 启动nginx的方式 cd usr local nginx ls nginx c nginx conf 2 查看nginx的进程方式 root localhost nginx ps ef grep nginx root localhos
  • 103-----JS基础-----添加删除记录-删除

    一 代码 很简单 看一下即可
  • TensorFlow学习-anaconda的方式安装TensorFlow教程

    前置准备 首先在说到安装TensorFlow前 要安装好anaconda 这里引入一篇教程anaconda安装与使用 初学者另外也需要在官网安装对应的python包python官网 有这些前置准备后 就可以安装TensorFlow了 采用a
  • linux下ftp的使用命令

    1 登录ftp ftp 0 0 0 0 输入用户名和密码 登录成功 2 ftp帮助 help 显示本地可用命令 rhelp 显示远程终端可以使用的命令 3 切换目录 cd 切换远程终端的当前工作目录 lcd 切换本地的当前工作目录 pwd
  • Centos7离线安装依赖包

    Centos离线安装依赖包 文章目录 Centos离线安装依赖包 1 下载依赖包 1 1 使用yum install downloadonly下载安装包及其依赖 1 2使用yumdownloader下载安装包及其依赖 2 安装下载好的依赖包
  • vuex的基本用法(提炼公共文件import all vuex modules)

    1 第一步是你的package json中需要有 vuex 3 5 1 如果没有安装vuex 就先安装一下 2 在src下创建一个文件store store下创建一个文件modules index js 下面继续创建文件 最终的目录文件如下
  • Discourse搭建

    首先要链接上服务器 首先WINDOWS打开CMDER MAC的话打开Terminal 都是类似的 在窗口输入 ssh root ALIYUN IP 这里的ALIYUN IP是你的服务器的公网IP地址 举个例子 我的公网IP是47 88 12
  • Qt中执行多条shell语句

    在Qt中执行一个shell指令常用QProcess类来完成 常见的用法示例如下 QProcess process process start find opt name ts calibrate str是需要执行的命令 flag proce
  • python之weditor定位的使用

    1 driver text 书城 定位元素的方式 属性定位 2 driver text 书城 click 点击元素 3 driver resourceId click 点击搜素按钮 4 driver resourceId send keys
  • 我在支付宝花了 1 分钟,查到了对象的开房记录

    来源丨Hack https mp weixin qq com s 6fDFqBQMqUVdkJG Dg7iCw 在大数据时代下 不管你做什么都会留下蛛丝马迹 只要学会把各种软件运用到极致 捉奸简直轻而易举 今天就来给大家分享一下 什么叫大数
  • Python基础学习:numbers模块

    numbers 数字抽象基类 其源代码存储在 Lib numbers py numbers模块定义了数字抽象基类的层次结构 逐渐定义更多的操作 该模块中定义的任何类型都不能实例化 1 数字塔 class numbers Complex 数字
  • Python EasyNote 1

    描述 Python strip 方法用于移除字符串头尾指定的字符 默认为空格或换行符 或字符序列 注意 该方法只能删除开头或是结尾的字符 不能删除中间部分的字符 Python split 通过指定分隔符对字符串进行切片 如果参数 num 有
  • 05 CoCos Creator-native.log

    1 Compile failed 编译保存信息 查看报错文件 C Users Administrator CocosCreator logs native log Error Compile failed The log file path
  • 宏和函数

    此为C语言的基础 和Linux内核关系并不大 不过还是作为补充知识点介绍一下好了 宏非常频繁的用于执行简单的计算 比如在两个表达式中寻找其中较大的一个 define MAX a b a gt b a b 如果使用函数来实现的话就比较慢 宏的
  • Hololens2发布流程记录,含MRTK2导入,工程的安装

    记录一下HoloLens2发布流程 1 创建新工程 我这边用的是unity2019版本 2 下载MixedRealityFeatureTool exe 官网链接 https download microsoft com download 2
  • 住宅IP和机房IP的特征区别

    住宅IP是ISP 互联网服务提供商 或ADSL提供商分配给单个用户的实际住宅IP地址 由100 真实WIFI网络用户组成 住宅IP是真正的用户设备IP 与主流用户的宽带网络IP完全一致 与机房等IP相比 成功率更高 关闭概率更低 但维护稳定
  • 在spring引入log4j

    在spring中使用log4j 引入log4j软件包 配置log4j属性 加载log4j配置文件 默认加载 手动加载 使用logger 本文的整体代码结构是在已经引入spring基本应用的前提下 在spring配置文件中通过 Bean注解创
  • git---查看当前账户和切换账户

    查看当前用户名和邮箱 git config user name git config user email 修改用户名和邮箱 git config global user name Your username git config glob
  • GPT-Tools Cookbook by Eric

    1 账号申请和登录 1 1 OpenAI 账号注册 可以参考 2 ChatGPT 的注册与登录 来自 涛哥ChatGPT和Python变现圈 选择账号邮箱 我们在尝试过直接使用邮箱注册OpenAI账号 试验了两次 都没有成功 Note 第二
  • SpringBoot 集成SpringBatch 批处理框架

    SpringBatch 核心组件简介 1 JobRepository 用来注册Job容器 设置数据库相关属性 2 JobLauncher 用来启动Job的接口 3 Job 我们要实际执行的任务 包含一个或多个 4 Step 即步骤 包括 I