使用Spring Boot和Spring Data MongoDB开发搜索应用程序

总结

我们将使用Spring Boot和Spring Data MongoDB来开发一个可以进行简单搜索的Web应用程序。

环境

    • Windows7 (64bit)

 

    • Java 1.8.0_60

 

    • Spring-Boot 1.2.5

Spring-Data-MongoDB 1.6.3

MongoDB 2.4.14

请参考

我参考了下面的网站。

    Spring Data MongoDB – Reference Documentation

完成的图像

customers.png
customer_details.png

GitHub可以用于存储、分享和协作开发各种类型的代码和项目。

源代码位于rubytomato/sbdm-example。

预先准备

Spring Data MongoDB支持的MongoDB版本如下表所示。

根据这个表格,我们选择了2.4.14版本作为本次使用的MongoDB版本。

Spring Data MongoDB 支持

Spring-Data-MongoDB VersionSupport MongoDB Versionreference1.6.3Spring MongoDB support requires MongoDB 1.4 or higherMongoDB support1.7.2Spring MongoDB support requires MongoDB 2.6 or higherMongoDB support1.8.0 RC1Spring MongoDB support requires MongoDB 2.6 or higherMongoDB support

准备MongoDB

省略 MongoDB 的安装步骤的说明。

创建数据库、账户

数据库名称:mongovwdb
用户名/密码:mongovwuser / mongovwpass

> use mongovwdb

添加用户。

> db.addUser({user:"mongovwuser", pwd:"mongovwpass", roles: [ "userAdmin" ]})

我会确认是否可以进行认证。

> db.auth("mongovwuser","mongovwpass")
1

样本数据集

我借用了MySQLTutorial上公开的样本数据集来处理这个应用程序中的数据。

收藏品列表

namedescriptioncustomers顧客order_details注文明細orders注文payments支払いproduct_lines製品種別products製品

数据示例

顾客

> db.customers.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd8549f4b"),
        "_class" : "com.example.sbdm.domain.Customers",
        "customerNumber" : NumberLong(103),
        "customerName" : "Atelier graphique",
        "contactLastName" : "Schmitt",
        "contactFirstName" : "Carine",
        "phone" : "40.32.2555",
        "addressLine1" : "54, rue Royale",
        "city" : "Nantes",
        "postalCode" : "44000",
        "country" : "France",
        "salesRepEmployeeNumber" : NumberLong(1370),
        "creditLimit" : "21000"
}

订单详情

> db.order_details.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd8549fc5"),
        "_class" : "com.example.sbdm.domain.OrderDetails",
        "orderNumber" : NumberLong(10100),
        "productCode" : "S18_1749",
        "quantityOrdered" : NumberLong(30),
        "priceEach" : "136",
        "orderLineNumber" : 3
}

1. 订购
2. 下单
3. 订货

> db.orders.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd854ab79"),
        "_class" : "com.example.sbdm.domain.Orders",
        "orderNumber" : NumberLong(10100),
        "orderDate" : ISODate("2011-01-05T15:00:00Z"),
        "requiredDate" : ISODate("2011-01-12T15:00:00Z"),
        "shippedDate" : ISODate("2011-01-09T15:00:00Z"),
        "status" : "Shipped",
        "customerNumber" : NumberLong(363)
}

付款

> db.payments.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd854acbf"),
        "_class" : "com.example.sbdm.domain.Payments",
        "customerNumber" : NumberLong(103),
        "checkNumber" : "HQ336336",
        "paymentDate" : ISODate("2012-10-18T15:00:00Z"),
        "amount" : "6066.78"
}

产品系列

> db.product_lines.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd854add0"),
        "_class" : "com.example.sbdm.domain.ProductLines",
        "productLine" : "Classic Cars",
        "textDescription" : "Attention car enthusiasts: Make yo ...省略..."
}

产品

> db.products.findOne()
{
        "_id" : ObjectId("55df620d67cdfe3cd854add7"),
        "_class" : "com.example.sbdm.domain.Products",
        "productCode" : "S10_1678",
        "productName" : "1969 Harley Davidson Ultimate Chopper",
        "productLine" : "Motorcycles",
        "productScale" : "1:10",
        "productVendor" : "Min Lin Diecast",
        "productDescription" : "This replica features working kickstand, ...省略...",
        "quantityInStock" : 7933,
        "buyPrice" : "48.81",
        "MSRP" : "95.7"
}

创建应用程序

生成项目的模板。

项目名称:sbdm示例

使用Maven创建应用程序的草稿。

> mvn archetype:generate -DgroupId=com.example.sbdm -DartifactId=sbdm-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
> cd sbdm-example
> mvn eclipse:eclipse

将Eclipse中导入

    • メニューバーの”File” -> “Import…” -> “Maven” -> “Existing Maven Projects”を選択します。

 

    プロジェクトのディレクトリを選択し、”Finish”ボタンをクリックします。

编辑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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example.sbdm</groupId>
  <artifactId>sbdm-example</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>sbdm-example</name>
  <url>http://maven.apache.org</url>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

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

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>
    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.4</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <version>1.2.5.RELEASE</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <verbose>true</verbose>
          <source>${java.version}</source>
          <target>${java.version}</target>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>versions-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

创建资源文件夹

在src/main下创建一个称为resources的文件夹,用于存放设置文件和模板文件等。

完成后将应用到项目中。

    • “Build Path” -> “Configure Build Path” -> “Java Buld Path” -> “Source”タブを選択する。

 

    “Add Folder”ボタンをクリック -> 作成した”resources”フォルダにチェックを入れる。

创建application.yml文件

在src/main/resources文件夹中创建application.yml文件。

# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server:
  port: 9000

spring:
# THYMELEAF (ThymeleafAutoConfiguration)
  thymeleaf:
    enabled: true
    cache: false
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
  messages:
    basename: messages
    cache-seconds: -1
    encoding: UTF-8
# MONGODB (MongoProperties)
  data:
    mongodb:
      host: localhost
      port: 27017
      uri: mongodb://localhost/mongovwdb # connection URL
      database: mongovwdb
#      authentication-database: mongovwdb
#      grid-fs-database:
      username: mongovwuser
      password: mongovwpass
      repositories:
        enabled: true  # if spring data repository support is enabled

# ENDPOINTS (AbstractEndpoint subclasses)
endpoints:
  enabled: true

创建logback.xml文件

在src/main/resources文件夹内创建logback.xml文件。
设置日志输出文件夹为”D:/logs”。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

  <property name="LOG_DIR" value="D:/logs" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>
  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${LOG_DIR}/sbdm-example.log</file>
     <encoder>
       <charset>UTF-8</charset>
       <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] - %msg %n</pattern>
     </encoder>
  </appender>

  <logger name="com.example" level="DEBUG" />

  <logger name="org.hibernate" level="ERROR"/>
  <logger name="org.springframework" level="INFO"/>
  <logger name="org.thymeleaf" level="INFO"/>
  <logger name="org.eclipse.jetty" level="INFO"/>
  <logger name="org.apache.http" level="INFO"/>
  <root>
    <appender-ref ref="STDOUT" />
    <appender-ref ref="FILE" />
  </root>
</configuration>

建设

在这个时间点上进行构建以进行操作验证。

> mvn package

如果构建成功,则执行生成的jar文件。
如果在命令提示符下显示“Hello World!”,则表示成功。

> cd target
> java -jar sbdm-example-1.0-SNAPSHOT.jar
Hello World!

应用程序开发

由于全部源代码都放在文章中会使文章的大小变得很大,所以我们只会发布关键部分的代码。

应用程序

我們將創建一個作為終點的類。
由於已經存在一個名為App.java的樣例文件,我們將按照下面的方式進行修改。

package com.example.sbdm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.example.sbdm.viewhelper.MyDialect;

@SpringBootApplication
public class App {

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

  //THYMELEAF Utility Object
  @Bean
  MyDialect myDialect(){
    return new MyDialect();
  }

}

MongoDB配置

可以创建一个继承自AbstractMongoConfiguration类的类来配置MongoDB。

package com.example.sbdm;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
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.data.repository.query.QueryLookupStrategy;

import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.WriteConcern;

@Configuration
@EnableMongoRepositories(
  basePackages = "com.example.sbdm.repository",
  queryLookupStrategy = QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND
)
public class MongodbConfig extends AbstractMongoConfiguration {

  @Override
  @Bean
  public Mongo mongo() throws Exception {
    Mongo mongo = new MongoClient("localhost", 27017);
    mongo.setWriteConcern(WriteConcern.SAFE);
    return mongo;
  }

  @Override
  @Bean
  public MongoDbFactory mongoDbFactory() throws Exception {
    return new SimpleMongoDbFactory(mongo(), getDatabaseName(), getUserCredentials());
    //return new SimpleMongoDbFactory(mongo(), getDatabaseName());
  }

  @Override
  @Bean
  public MongoTemplate mongoTemplate() throws Exception {
    MongoTemplate template = new MongoTemplate(mongoDbFactory());
    template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
    return template;
  }

  @Value("${spring.data.mongodb.database}")
  private String databasename;

  @Override
  protected String getDatabaseName() {
    return databasename;
  }

  @Override
  protected String getMappingBasePackage() {
    return "com.example.sbdm.domain";
  }

  @Value("${spring.data.mongodb.username}")
  private String username;
  @Value("${spring.data.mongodb.password}")
  private String password;

  @Override
  protected UserCredentials getUserCredentials() {
    UserCredentials userCredentials = new UserCredentials(username, password);
    return userCredentials;
  }

}

领域

包: com.example.sbdm.domain

我会为MongoDB的集合创建一个对应的领域类。

顾客

package com.example.sbdm.domain;

import java.math.BigDecimal;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
import org.springframework.data.mongodb.core.index.IndexDirection;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

@Document(collection = CollectionNames.Customers)
@CompoundIndexes({
  @CompoundIndex(
    name = "idx1_customers",
    def = "{'contactLastName' : 1, 'contactFirstName' : 1}"
  )
})
public class Customers {

  public Customers() {
  }

  @PersistenceConstructor
  public Customers(Long customerNumber, String customerName) {
    this.customerNumber = customerNumber;
    this.customerName = customerName;
  }

  @Id
  private String id;

  @Indexed(name = "pk_customers", direction = IndexDirection.DESCENDING, unique = true)
  @Field("customerNumber")
  private Long customerNumber;

  private String customerName;

  @Field("contactLastName")
  private String contactLastName;

  @Field("contactFirstName")
  private String contactFirstName;

  private String phone;

  private String addressLine1;

  private String addressLine2;

  private String city;

  private String state;

  private String postalCode;

  private String country;

  private Long salesRepEmployeeNumber;

  private BigDecimal creditLimit;

  //...getter/setterは省略します...
}

中国人介词「点」。

使用注释来定义MongoDB集合/文档之间的关系。

@Idアノテーションでドキュメントの_idフィールドをマッピングします。

@Documentアノテーションでコレクション名を定義します。

@Indexedアノテーションや@CompoundIndexアノテーションでインデックスを定義します。

@Fieldアノテーションでドキュメントのフィールドをマッピングします。

仓库

包名:com.example.sbdm.repository

创建继承MongoRepository接口的每个集合的repository接口。

顾客存储库 kù)

package com.example.sbdm.repository;

import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import com.example.sbdm.domain.Customers;

public interface CustomersRepository extends MongoRepository<Customers, String> {

  public static final String FIND =
   "{$or:[" +
   "{'customerName': {$regex: '?0', $options: 'i'}}," +
   "{'contactFirstName': {$regex: '?0', $options: 'i'}}," +
   "{'contactLastName': {$regex: '?0', $options: 'i'}}" +
   "]}";

  Customers findByCustomerNumber(Long customerNumber);

  Iterable<Customers> findByCustomerNameLike(String customerName, Sort sort);

  Long countByCustomerNameLike(String keyword);

  @Query(value = FIND, count = true)
  Long searchCount(String keyword);

  @Query(value = FIND)
  PageImpl<Customers> search(String keyword, Pageable page);
}

点数

    • このrepositoryインターフェースには@Repositoryアノテーションを付けません。付けるとアプリケーション起動時にエラーが発生します。

MongoRepositoryインターフェースを継承することで基本的なメソッド(findやcount,save,delete)が使用できるようになります。
任意の条件で検索をおこないたい場合は命名ルールに基づいて独自メソッドを定義します。
任意のクエリーを発行したい場合は@Queryアノテーションを使用して実行するクエリーを指定することができます。

关于定义独立方法

您可以遵循命名规则,通过指定的方法名称来执行任何查询。有关规则的详细解释可在Query methods中找到。

比如下面的方法定义将会在customers集合中搜索具有与参数值相同的customerNumber字段的文档。(注意,由于该字段是唯一的,所以只能保证检索到一条文档。)

Customers findByCustomerNumber(Long customerNumber);

如果在方法名中加入”Like”,则进行like搜索。

Iterable<Customers> findByCustomerNameLike(String customerName, Sort sort);

计数的方法是使用countBy进行加法。

Long countByCustomerNameLike(String keyword);

如果您想要将多个字段作为搜索条件,可以添加And和Or。

OrderDetails findByOrderNumberAndProductCode(Long orderNumber, String prodctCode);

如果使用@Query注释,可以直接指定要执行的查询。顺便提一下,在这个例子中还添加了Pageable接口作为参数,但在这种情况下,返回类型将是PageImpl类(如果不添加的话,将是ArrayList类)。

@Query(value = FIND)
PageImpl<Customers> search(String keyword, Pageable page);

当将count = true添加到查询中时,将对查询结果进行计数。

@Query(value = FIND, count = true)
Long searchCount(String keyword);

服务 (fú wù)

包名:com.example.sbdm.service

创建一个定义了执行文档操作的基本方法的接口。

服务接口

package com.example.sbdm.service;


public interface IService<T> extends Pagination {

  /**
   * コレクションのドキュメントの件数
   */
  public long count();

  /**
   * ドキュメントIDで検索
   */
  public T findById(String id);

  /**
   * 条件なしでドキュメントを検索
   */
  public Iterable<T> findAll(int page, int size, String sortColumn);

  /**
   * ドキュメントのプライマリーキーで検索
   */
  public T findByPk(Object...keys);

  /**
   * 名称のlike検索
   */
  public Iterable<T> findByNameLike(String name, String sortColumn);

  /**
   * 検索ワードに一致するドキュメントの件数
   */
  public long searchCount(String keyword);

  /**
   * 検索ワードに一致するドキュメントを検索
   */
  public Iterable<T> search(String keyword, int page, int size, String sortColumn);

  public T save(T model);

  public Iterable<T> save(Iterable<T> model);

  public void delete(String id);

  public void delete(Iterable<T> model);
}

摘要服务

我们将创建一个实现IService接口的服务类基类,用于每个集合。

在这个AbstractService类中,定义了一些相似功能的方法,但它们的区别如下所示。

IServiceインターフェースのメソッドの実装では、上記で説明したrepositoryを使用します。

AbstractServiceクラスで定義するメソッドは、MongoTemplateとQueryを使用するメソッドを使用します。

package com.example.sbdm.service;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.MongoRepository;

import com.example.sbdm.utils.MongoService;

public abstract class AbstractService<T> implements IService<T> {
  private static Logger logger = LoggerFactory.getLogger(AbstractService.class);

  @Autowired
  private MongoTemplate template;

  /* *
   * repositoryを使用する方法
   * 
   * */

  @Override
  public long count() {
    return getRepository().count();
  }

  @Override
  public T findById(String id) {
    return getRepository().findOne(id);
  }

  @Override
  public Iterable<T> findAll(int page, int size, String sort) {
    Pageable pager = new PageRequest(currentPage(page), size, Direction.ASC, sort);
    Iterable<T> result = getRepository().findAll(pager);
    return result;
  }

  @Override
  public T save(T model) {
    return getRepository().save(model);
  }

  @Override
  public Iterable<T> save(Iterable<T> model) {
    return getRepository().save(model);
  }

  @Override
  public void delete(String id) {
    getRepository().delete(id);
  }

  @Override
  public void delete(Iterable<T> model) {
    getRepository().delete(model);
  }

  abstract protected MongoRepository<T, String> getRepository();


  /* *
   * templateとqueryを使用する方法
   * 
   * */

  protected long doCount(Query query, Class<T> clazz) {
    return template.count(query, clazz);
  }

  protected T doFindOne(Query query, Class<T> clazz) {
    return template.findOne(query, clazz);
  }

  protected List<T> doFind(Query query, Class<T> clazz) {
    return template.find(query, clazz);
  }

  protected List<T> doFindAll(Class<T> clazz) {
    return template.findAll(clazz);
  }

  protected Criteria makeCriteriaById(String id) {
    return Criteria.where("id").is(id);
  }

  protected Criteria makeCriteriaRegex(Criteria criteria, String field, String param) {
    if (criteria == null) {
      criteria = Criteria.where(field).regex(param,"i");
    } else {
      criteria.and(field).regex(param,"i");
    }
    return criteria;
  }

  protected Criteria makeCriteria(Criteria criteria, String field, Object param) {
    if (criteria == null) {
      criteria = Criteria.where(field).is(param);
    } else {
      criteria.and(field).is(param);
    }
    return criteria;
  }

  protected Criteria makeWhere(String name) {
    return Criteria.where(name);
  }

  protected Criteria makeWhere(String name, Object param) {
    return Criteria.where(name).is(param);
  }

  protected Query makeQuery(Criteria criteria) {
    Query query;
    if (criteria != null) {
      query = new Query(criteria);
    } else {
      query = new Query();
    }
    return query;
  }

  protected int calcSkipNum(int page, int size) {
    return (page - 1) * size;
  }

  abstract protected long count(T searchCondition);
  abstract protected List<T> search(int page, int size, Sort sort, T searchCondition);
  abstract protected Criteria makeCriteriaByPk(T model);
  abstract protected Criteria makeCriteria(T model);
  abstract protected Update makeAllUpdate(T model);
}

积分

在处理文档的方法中,有两种选择:一种是使用Repository接口,另一种是使用MongoTemplate和Query。这两种方法都能实现相同的功能,但是使用Repository可以减少代码的实现量。

    • Repositoryを使用する方法: シンプルなクエリーであればメソッド定義だけで済み、コードの記述やクエリーを意識する必要がありません。

 

    MongoTemplateとQueryを使用する方法: プログラムでクエリーを組み立てることができます。

无论哪种方法,都可以直接执行查询。

具体化的Service类

包: com.example.sbdm.service.impl

顾客服务

package com.example.sbdm.service.impl;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Service;

import com.example.sbdm.domain.Customers;
import com.example.sbdm.repository.CustomersRepository;
import com.example.sbdm.service.AbstractService;

@Service
public class CustomersService extends AbstractService<Customers> {
  private static Logger logger = LoggerFactory.getLogger(CustomersService.class);

  @Autowired
  private CustomersRepository customersRepository;

  @Override
  protected MongoRepository<Customers, String> getRepository() {
    return customersRepository;
  }

  @Override
  public Customers findByPk(Object...keys) {
    return customersRepository.findByCustomerNumber((Long)keys[0]);
  }

  @Override
  public Iterable<Customers> findByNameLike(String customerName, String sortColumn) {
    Sort sort = new Sort(sortColumn);
    return customersRepository.findByCustomerNameLike(customerName, sort);
  }

  @Override
  public long searchCount(String keyword) {
    return customersRepository.searchCount(keyword);
  }

  @Override
  public Iterable<Customers> search(String keyword, int page, int size, String sortColumn) {
    Pageable pager = new PageRequest(currentPage(page), size, Direction.ASC, sortColumn);
    return customersRepository.search(keyword, pager);
  }

  @Override
  public long count(Customers searchCondition) {
    Criteria criteria = makeCriteria(searchCondition);
    Query query = makeQuery(criteria);
    return doCount(query, Customers.class);
  }

  @Override
  public List<Customers> search(int page, int size, Sort sort, Customers searchCondition) {
    Criteria criteria = makeCriteria(searchCondition);
    Query query= makeQuery(criteria);
    query.skip(calcSkipNum(page, size)).limit(size);
    if (sort != null) {
      query.with(sort);
    }
    return doFind(query, Customers.class);
  }

  @Override
  protected Criteria makeCriteriaByPk(Customers model) {
    return Criteria.where("customerNumber").is(model.getCustomerNumber());
  }

  @Override
  protected Criteria makeCriteria(Customers model) {
    Criteria criteria = null;
    if (model.getCustomerNumber() != null && model.getCustomerNumber() > 0L) {
      criteria = makeCriteria(criteria, "customerNumber", model.getCustomerNumber());
    }
    if (StringUtils.isNotEmpty(model.getCustomerName())) {
      criteria = makeCriteria(criteria, "customerName", model.getCustomerName());
    }
    if (StringUtils.isNotEmpty(model.getPhone())) {
      criteria = makeCriteria(criteria, "phone", model.getPhone());
    }
    if (StringUtils.isNotEmpty(model.getCity())) {
      criteria = makeCriteria(criteria, "city", model.getCity());
    }
    if (StringUtils.isNotEmpty(model.getCountry())) {
      criteria = makeCriteria(criteria, "country", model.getCountry());
    }
    if (StringUtils.isNotEmpty(model.getState())) {
      criteria = makeCriteria(criteria, "state", model.getState());
    }
    if (StringUtils.isNotEmpty(model.getPostalCode())) {
      criteria = makeCriteria(criteria, "postalCode", model.getPostalCode());
    }
    return criteria;
  }

  @Override
  protected Update makeAllUpdate(Customers model) {
    Update update = new Update();
    update.set("customerName", model.getCustomerName());
    update.set("contactLastName", model.getContactLastName());
    update.set("contactFirstName", model.getContactFirstName());
    update.set("phone", model.getPhone());
    update.set("addressLine1", model.getAddressLine1());
    update.set("addressLine2",model.getAddressLine2());
    update.set("city", model.getCity());
    update.set("state", model.getState());
    update.set("postalCode", model.getPostalCode());
    update.set("country", model.getCountry());
    update.set("salesRepEmployeeNumber", model.getSalesRepEmployeeNumber());
    update.set("creditLimit", model.getCreditLimit());
    return update;
  }

}

控制器

包: com.example.sbdm.web

顾客控制器

package com.example.sbdm.web;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.sbdm.domain.Customers;
import com.example.sbdm.domain.Orders;
import com.example.sbdm.service.impl.CustomersService;
import com.example.sbdm.service.impl.OrdersService;
import com.example.sbdm.utils.JsonLoader;

@Controller
@RequestMapping(value = "/customers")
public class CustomersController extends BaseController {
  private static Logger logger = LoggerFactory.getLogger(CustomersController.class);

  private static final int PAGE_SIZE = 10;

  @Autowired
  private CustomersService customersService;

  @Autowired
  private OrdersService ordersService;

  @RequestMapping(method = RequestMethod.GET)
  public String _index(Model model) {
    return index(1, null, model);
  }

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public String index(Model model) {
    return index(1, null, model);
  }

  @RequestMapping(value = "/{pageNo}", method = RequestMethod.GET)
  public String index(
      @PathVariable Integer pageNo,
      @RequestParam String keyword,
      Model model) {
    logger.debug("CustomersController:[index] Passing through...");

    int totalCount = 0;
    Iterable<Customers> result;

    if (StringUtils.isNotEmpty(keyword)) {
      result = customersService.search(keyword, pageNo, PAGE_SIZE, "customerName");
      totalCount = (int)customersService.searchCount(keyword);
    } else {
      result = customersService.findAll(pageNo, PAGE_SIZE, "customerNumber");
      totalCount = (int)customersService.count();
    }

    model.addAttribute("keyword", keyword);
    model.addAttribute("result", result);

    addPageAttr(customersService.calcPage(totalCount, pageNo, PAGE_SIZE), model);

    return "Customers/index";
  }

  @RequestMapping(value = "/detail/{id}", method = RequestMethod.GET)
  public String detail(
      @PathVariable String id,
      Model model) {
    logger.debug("CustomersController:[detail] Passing through...");

    Customers customer =  customersService.findById(id);

    String json = "{}";
    if (customer != null) {
      json = JsonLoader.toJson(customer);
    }

    Iterable<Orders> orderList = ordersService.findByCustomerNumber(customer.getCustomerNumber());

    model.addAttribute("customer", customer);
    model.addAttribute("orderList", orderList);
    model.addAttribute("json", json);

    return "Customers/detail";
  }

  @RequestMapping(value = "/search", method = RequestMethod.GET)
  public String search(
      @RequestParam(required = false) String country,
      @RequestParam(required = false) String city,
      @RequestParam(required = false) String state,
      @RequestParam(required = false) String postalcode,
      Model model) {
    logger.debug("CustomersController:[search] Passing through...");

    int pageNo = 1;

    Customers searchCondition = new Customers();
    if (StringUtils.isNotEmpty(country)) {
      searchCondition.setCountry(country);
    }
    if (StringUtils.isNotEmpty(city)) {
      searchCondition.setCity(city);
    }
    if (StringUtils.isNotEmpty(state)) {
      searchCondition.setState(state);
    }
    if (StringUtils.isNotEmpty(postalcode)) {
      searchCondition.setPostalCode(postalcode);
    }

    List<Customers> result = customersService.search(pageNo, PAGE_SIZE, null, searchCondition);

    int totalCount = (int)customersService.count(searchCondition);

    model.addAttribute("result", result);

    addPageAttr(customersService.calcPage(totalCount, pageNo, PAGE_SIZE), model);

    return "Customers/index";
  }

}

searchアクションの呼び出しは、ブラウザのアドレスバーに直接URLを入力して行います。実行結果は一覧ページに表示されます。

其他类别和模板
其他课程和模板
其他的班级和模板
其他的类和模板
其他的学科和模板

因为与MongoDB相关的重要部分被省略了,且文章变得过大,所以其他类和模板将不在此处提及。源代码全部在GitHub上公开。

执行

确保MongoDB已启动并运行以下命令。

> mvn spring-boot:run

如果应用程序启动后,访问下面的URL并显示页面,则表示成功。
然而,由于没有任何数据,因此应该显示如下图所示的页面。

empty.png

数据初始化

初始数据以json文件的形式进行管理(文件位于resources/data/init文件夹下)。

resources
 └─data
    └─init
        ├─Customers
        ├─OrderDetails
        ├─Orders
        ├─Payments
        ├─ProductLines
        └─Products

点击页面菜单中的”admin:init”,将会加载json文件并创建文档。
如果数据初始化成功,将显示如下图所示的结果页面。

init_result.png

当数据初始化完成后,您可以在每个页面上确认数据。

顾客名单

customers.png

订单清单

orders.png

产品列表

products.png

所有产品种类的清单

productlines.png

付款清单

payments.png
广告
将在 10 秒后关闭
bannerAds