仮想マシンへのMongoDBのインストールについては、「CentOS7へのMongoDB4のインストール」を参照してください。
私が使用しているIDEはSTS4で、自分の習慣に合わせて選択できます。
重要なのは、pom.xmlを追加することです。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
application.propertiesを追加します。
spring.data.mongodb.uri=mongodb://用户名:密码@IP:PORT/数据库
エンティティクラス
@Document(collection = "test_goods")
publicclass GoodsEntity implements Serializable {
privatestaticfinallongserialVersionUID = -805486477824888750L;
@Id
private String id;
private String goodsName;
privatelongcategoryId;
privateintgoodsStatus;
private String labels;
//省略get、set方法
}
他に何も説明されていません。一目で理解できます。ここでは、idフィールドに注意する必要があります。
上記の構成と注釈@Idを使用すると、新しいドキュメントを作成するときに追加の設定は不要であり、以下に示すような主キーが自動的に生成されます。
これは、12バイトのBSONタイプの文字列である「_id」という名前のObjectIdタイプの主キーです。
4バイトはUNIXタイムスタンプ、3バイトはMongoDBサーバー、2バイトはIDを生成するプロセス、3バイトは乱数です。
これの利点は、配布に適していることです。また、idにはタイムスタンプが含まれているため、当然、作成時刻が含まれます。合格できます
ObjectId id = new ObjectId(entity.getId());
System.out.println(id.getDate());
作成時間を取得します。
もちろん、従来のDBの補足としてMongoDBを使用する場合でも、システム内のMongoDBのDBにIDを保存する場合は、idフィールドの注釈を削除し、処理時にIDフィールドを設定します。
ダオ
@Component
publicclass GoodsDao {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 新建
*
* @param entity
* @return
*/
public GoodsEntity add(GoodsEntity entity) {
returnmongoTemplate.save(entity);
}
/**
* 根据ID修改
*
* @param entity
* @return
*/
public UpdateResult upd(GoodsEntity entity) {
Query query = new Query(Criteria.where("id").is(entity.getId()));
Update update = new Update().set("goodsName", entity.getGoodsName()).set("categoryId", entity.getCategoryId())
.set("goodsStatus", entity.getGoodsStatus()).set("labels", entity.getLabels());
returnmongoTemplate.updateFirst(query, update, GoodsEntity.class);
}
/**
* 根据ID删除
*
* @param id
* @return
*/
public DeleteResult delById(longid) {
Query query = new Query(Criteria.where("id").is(id));
returnmongoTemplate.remove(query, GoodsEntity.class);
}
/**
* 根据主键获取详情
*
* @param id
* @return
*/
public GoodsEntity getById(longid) {
Query query = new Query(Criteria.where("id").is(id));
GoodsEntity entity = mongoTemplate.findOne(query, GoodsEntity.class);
returnentity;
}
/**
* 列出所有记录
*
* @return
*/
public List<GoodsEntity> listAll() {
List<GoodsEntity> entities = mongoTemplate.find(new Query(), GoodsEntity.class);
returnentities;
}
/**
* 根据某字段使用正则表达式模糊查询,且分页、ID倒序
*
* @param label
* @param pageNumber
* @param pageSize
* @return
*/
public List<GoodsEntity> queryPageByLabel(String label, intpageNumber, intpageSize) {
// 完全匹配
// Pattern pattern = Pattern.compile("^" + label + "$",
// Pattern.CASE_INSENSITIVE);
// 右匹配
// Pattern pattern = Pattern.compile("^.*\"+label+\"$",
// Pattern.CASE_INSENSITIVE);
// 左匹配
// Pattern pattern = Pattern.compile("^\"+label+\".*$",
// Pattern.CASE_INSENSITIVE);
// 模糊匹配
Pattern pattern = Pattern.compile("^.*" + MongoDBUtils.escapeExprSpecialWord(label) + ".*$",
Pattern.CASE_INSENSITIVE);
Query query = new Query(Criteria.where("labels").regex(pattern));
// ID倒序
query.with(new Sort(Sort.Direction.DESC, "id"));
// 分页
PageRequest pageableRequest = PageRequest.of(pageNumber, pageSize);
query.with(pageableRequest);
returnmongoTemplate.find(query, GoodsEntity.class);
}
/**
* 多查询条件,分页,ID倒序
*
* @param entity
* @param pageNumber
* @param pageSize
* @return
*/
public List<GoodsEntity> queryPage(GoodsEntity entity, intpageNumber, intpageSize) {
Criteria criteria = new Criteria();
if (!StringUtils.isEmpty(entity.getGoodsName())) {
Pattern pattern = Pattern.compile("^.*" + entity.getGoodsName() + ".*$", Pattern.CASE_INSENSITIVE);
criteria.and("goodsName").regex(pattern);
}
if (!StringUtils.isEmpty(entity.getLabels())) {
Pattern pattern = Pattern.compile("^.*" + entity.getLabels() + ".*$", Pattern.CASE_INSENSITIVE);
criteria.and("labels").regex(pattern);
}
if (entity.getCategoryId() > 0) {
criteria.and("categoryId").is(entity.getCategoryId());
}
if (entity.getGoodsStatus() > 0) {
criteria.and("goodsStatus").is(entity.getGoodsStatus());
}
Query query = new Query(criteria);
// 分页&ID倒序
PageRequest pageableRequest = PageRequest.of(pageNumber, pageSize, Sort.Direction.DESC, "id");
query.with(pageableRequest);
returnmongoTemplate.find(query, GoodsEntity.class);
}
}
個人的には、ほとんどの要件は基本的にカバーされていると感じており、コードについては詳しく説明しません。
ここで重要なのは、今回はObjectIdを使用しなかったが、DBのIDを使用したため、ここでのエンティティのIDは長いことです。
テスト
@RunWith(SpringRunner.class)
@SpringBootTest
publicclass GoodsDaoTest {
@Autowired
private GoodsDao goodsDao;
@Test
publicvoid add() {
GoodsEntity entity = new GoodsEntity();
entity.setId(3); // 如果使用ObjectId,就不需要额外处理ID字段了。
entity.setCategoryId(5);
entity.setGoodsName("测试商品E");
entity.setGoodsStatus(1);
entity.setLabels("a,b,c,*,d");
GoodsEntity newEntity = goodsDao.add(entity);
JsonFormaterUtil.printFromObj(newEntity);
}
@Test
publicvoid upd() {
GoodsEntity entity = goodsDao.getById(1);
entity.setLabels("a,b,c,d");
JsonFormaterUtil.printFromObj(goodsDao.upd(entity));
}
@Test
publicvoid del() {
JsonFormaterUtil.printFromObj(goodsDao.delById(3));
}
@Test
publicvoid getById() {
JsonFormaterUtil.printFromObj(goodsDao.getById(1));
}
@Test
publicvoid listAll() {
JsonFormaterUtil.printFromObj(goodsDao.listAll());
}
@Test
publicvoid queryByLabel() {
JsonFormaterUtil.printFromObj(goodsDao.queryPageByLabel("*", 0, 2));
}
@Test
publicvoid queryPage() {
GoodsEntity entity = new GoodsEntity();
// entity.setCategoryId(5);
entity.setGoodsName("测试商品");
// entity.setGoodsStatus(1);
// entity.setLabels("a,b,c");
JsonFormaterUtil.printFromObj(goodsDao.queryPage(entity, 0, 10));
}
}
言うことは何もありません。
ログ構成
私は個人的にコンソールでDB操作のステートメントを印刷するのが好きなので、ログ構成が変更されました。
SpringBootはlogbackを使用します。resourcesディレクトリに次の内容のlogback.xmlファイルを作成します。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储绝对路径-->
<property name="LOG_HOME" value="d:/" />
<!-- 控制台输出 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} : %n%msg%n
</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/mongodbdemo.log.%d{yyyy-MM-dd}.log
</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} :
%msg%n
</pattern>
</encoder>
<!--日志文件最大的大小 -->
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="ERROR">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<!-- MongoDB日志输出 -->
<logger
name="org.springframework.data.mongodb.core.MongoTemplate"
level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
</configuration>
重要な点は、MongoDBログ出力を構成することです。ここで、nameはログ出力クラスであり、レベルは、次のように、実行されたステートメントを出力するようにデバッグするように設定されます。
find using query: { "goodsName" : { "$regex" : "^.*测试商品.*$", "$options" : "i" } } fields: Document{{}} for class: class org.leo.mongodb.demo.entity.GoodsEntity in collection: test_goods
また、additivity = "false"は、追加しないと、上記のログがコンソールに2回出力されるためです。
正規表現を通じて照会し、いくつかの特殊文字の必要性をエスケープするためにどの、遭遇されるコードは以下の通りである(*、など?)。:
publicclass MongoDBUtils {
privatestaticfinal String[] fbsArr = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" };
/**
* regex对输入特殊字符转义
*
* @param keyword
* @return
*/
publicstatic String escapeExprSpecialWord(String keyword) {
if (!StringUtils.isEmpty(keyword)) {
for (String key : fbsArr) {
if (keyword.contains(key)) {
keyword = keyword.replace(key, "\\" + key);
}
}
}
returnkeyword;
}
}
インデックス:
db.getCollection("test_goods").createIndex({ "categoryId": 1 }, { "name": "idx_goods_categoryid" })
categoryIdのインデックスを作成します。ここで、{"categoryId":1}の1は昇順の作成を表し、-1は降順を表します。
次のように複合インデックスを作成します。
db.getCollection("test_goods").createIndex({ "categoryId": 1, "goodsStatus": -1 })
一意のインデックスを次のように設定します。
db.getCollection("test_goods").createIndex({ "categoryId": 1}, { "unique": true })