springData使用QueryDsl

参考资料
1:http://docs.spring.io/spring-data/jpa/docs/1.10.x/reference/pdf/spring-data-jpa-reference.pdf
2:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
经过多年,spring data jpa越来越完善,在版本迭代的过程中,会不断增加功能,今天看新的reference发现有Querydsl.然后搜索到上面的参考资料2
无论是JpaSpecificationExecutor,还是QueryDslPredicateExecutor,它俩都提供了使用Predicate(意义相同,都是构建where子句;类不同,javax.persistence.criteria.Predicate,com.querydsl.core.types.Predicate)去构建查询,使用比较方便.
关于两者的简单使用,上面的参考资料2有介绍.文末也有总结,从概括来看,我个人认为应倾向使用QueryDslPredicateExecutor,QueryDsl不仅适用于JPA repositories,还支持MongoDB.
下面是个例子
1.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>org.exam</groupId>
    <artifactId>testjava</artifactId>
    <version>1.0.0</version>
    <name>${project.artifactId}</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.version>4.2.5.RELEASE</spring.version>
        <spring-data.version>Hopper-SR1</spring-data.version>
        <querydsl.version>4.1.1</querydsl.version>
        <hibernate.version>5.1.0.Final</hibernate.version>
        <tomcat.version>8.0.32</tomcat.version>
        <logback.version>1.1.7</logback.version>
        <mysql.version>5.1.33</mysql.version>
        <junit.version>4.12</junit.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>${spring.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-releasetrain</artifactId>
                <version>${spring-data.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>maven-apt-plugin</artifactId>
                <version>1.0.4</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-mongodb</artifactId>
            <version>${querydsl.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>central</id>
            <name>Central Repository</name>
            <url>http://repo1.maven.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

2.Domain类

package org.exam.domain;

import org.springframework.data.mongodb.core.mapping.Document;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;

@Entity
@Document
public class Employee implements Serializable {
    @Id
    @Column(length = 38)
    private String id;
    @Column(length = 32)
    private String name;
    private long salary;
    private long departmentId;
    //setter和getter略
}

3.Repository类

package org.exam.repository.jpa;
import org.exam.domain.Employee;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Collection;
public interface JpaEmployeeRepository extends PagingAndSortingRepository<Employee,String>,QueryDslPredicateExecutor<Employee>{
    Collection<Employee> findByIdIn(Collection<String> ids);
}
package org.exam.repository.mongo;

import org.exam.domain.Employee;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.Collection;
public interface MongoEmployeeRepository extends PagingAndSortingRepository<Employee, String>, QueryDslPredicateExecutor<Employee> {
    Collection<Employee> findByIdIn(Collection<String> ids);
}

JPA有JpaRepository,MongoDB有MongoRepository,它俩都继承PagingAndSortingRepository
3.配置类

package org.exam.config;

import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.WriteResultChecking;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.Resource;
import java.net.UnknownHostException;
import java.util.Properties;

@Configuration
@PropertySource("classpath:config.properties")
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "org.exam.repository.jpa")
@EnableMongoRepositories(basePackages = "org.exam.repository.mongo")
public class AppConfig {
    @Resource
    private Environment env;

    @Bean(destroyMethod = "close")
    public DataSource dataSource() {
        DataSource dataSource = new DataSource();
        dataSource.setDriverClassName(env.getProperty("ds.driverClassName"));
        dataSource.setUrl(env.getProperty("ds.url"));
        dataSource.setUsername(env.getProperty("ds.username"));
        dataSource.setPassword(env.getProperty("ds.password"));
        dataSource.setInitialSize(env.getProperty("ds.initialSize", Integer.class));
        dataSource.setMinIdle(env.getProperty("ds.minIdle", Integer.class));
        dataSource.setMaxIdle(env.getProperty("ds.maxIdle", Integer.class));
        dataSource.setMaxActive(env.getProperty("ds.maxActive", Integer.class));
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabase(Database.valueOf(env.getProperty("jpa.database")));
        jpaVendorAdapter.setGenerateDdl(env.getProperty("jpa.generateDdl",Boolean.class));
        jpaVendorAdapter.setShowSql(env.getProperty("jpa.showSql",Boolean.class));
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource());
        emf.setPackagesToScan("org.exam.domain");
        emf.setJpaVendorAdapter(jpaVendorAdapter);
        Properties properties = new Properties();
        properties.setProperty("hibernate.default_schema", env.getProperty("jpa.defaultSchema"));
        emf.setJpaProperties(properties);
        return emf;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }

    @Bean
    public MongoDbFactory mongoDbFactory() throws UnknownHostException {
        return new SimpleMongoDbFactory(new MongoClient(env.getProperty("mongo.host"), env.getProperty("mongo.port", Integer.class)), env.getProperty("mongo.db"));
    }

    @Bean
    public MongoTemplate mongoTemplate() throws UnknownHostException {
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
        mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION);
        mongoTemplate.setWriteConcern(WriteConcern.NORMAL);
        return mongoTemplate;
    }
}

4.测试类

package org.exam.repository.jpa;

import org.exam.config.AppConfig;
import org.exam.domain.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {AppConfig.class})
@Transactional(transactionManager = "transactionManager")//Rollback默认为true
public class JpaEmployeeRepositoryTest {
    @Autowired
    private JpaEmployeeRepository jpaEmployeeRepository;

    @Test
    @Rollback(false)
    public void testSave() {
        for (int i = 0; i < 5; i++) {
            Employee employee = new Employee();
            employee.setId(UUID.randomUUID().toString());
            employee.setName("name");
            employee.setDepartmentId(1 + i);
            employee.setSalary(6800 + i);
            jpaEmployeeRepository.save(employee);
        }
    }

    @Test
    public void testFindAll() {
        Page<Employee> all = jpaEmployeeRepository.findAll(null, new PageRequest(0, 8));
        for (Employee employee : all) {
            System.out.println("employee = " + employee);
        }
    }
}
package org.exam.repository.mongo;
import com.mongodb.MongoClient;
import org.exam.config.AppConfig;
import org.exam.domain.Employee;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.geo.Circle;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import java.net.UnknownHostException;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {AppConfig.class})
public class MongoEmployeeRepositoryTest {
    @Autowired
    private MongoEmployeeRepository mongoEmployeeRepository;

    public static void main(String[] args) throws UnknownHostException {
        MongoTemplate template = new MongoTemplate(new MongoClient("127.0.0.1", 27017), "test");
        Circle circle = new Circle(-73.99171, 40.738868, 0.01);

        System.out.println();
    }

    @Test
    public void testFindAll() {
        Page<Employee> all = mongoEmployeeRepository.findAll(null, new PageRequest(0, 8));
        for (Employee employee : all) {
            System.out.println("employee = " + employee);
        }
    }
}

5.其它config.properties,logback.xml文件不太重要,篇幅关系就省略.
源码下载
http://download.csdn.net/detail/xiejx618/9528303

再了解一下比较大的需求,从几张表来取几个字段的数据,返回分页排序数据.
1.在AppConfig注册JPAQueryFactory Bean

@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
    return new JPAQueryFactory(new HQLTemplates(), entityManager);
}

2.建一个DTO(数据传输对象)

public class UserDTO {
    private String empName;
    private String deptName;
    private long salary;
    //setter,getter略
}

3.查询例子测试

private Page<UserDTO> findAll(String empName,Pageable pageable) {
    QEmployee qEmp = QEmployee.employee;
    QDepartment qDep = QDepartment.department;
    List<Predicate> criteria = new ArrayList<>();
    if (StringUtils.hasText(empName)){
        criteria.add(qEmp.name.eq(empName.trim()));
    }

    JPAQuery<?> query = jpaQueryFactory.from(qEmp).innerJoin(qDep).on(qEmp.deptId.eq(qDep.id)).where(criteria.toArray(new Predicate[criteria.size()]));
    long total = query.fetchCount();
    List<UserDTO> content;
    if (pageable == null || total > pageable.getOffset()) {
        Map<String, SimpleExpression<?>> map = new HashMap<>();
        map.put("deptName", qDep.name);
        map.put("empName", qEmp.name);
        map.put("salary", qEmp.salary);
        content = QuerydslUtils.applyPagination(pageable, query).select(Projections.bean(UserDTO.class, map)).fetch();
    } else {
        content = Collections.emptyList();
    }
    return new PageImpl<>(content, pageable, total);
}

@Test
public void test() {
    Pageable pageable = new PageRequest(0, 10, new QSort(new OrderSpecifier<>(Order.DESC, QEmployee.employee.salary), new OrderSpecifier<>(Order.ASC, QDepartment.department.name)));
    Page<UserDTO> page = findAll("name", pageable);
    for (UserDTO userDTO : page) {
        System.out.println("userDTO = " + userDTO);
    }
}

猜你喜欢

转载自blog.csdn.net/xiejx618/article/details/51480265