1. 程式人生 > >Spring-boot mongodb ID自增長註解實現 適用於JDK 1.7和JDK 1.8

Spring-boot mongodb ID自增長註解實現 適用於JDK 1.7和JDK 1.8

開發工具Idea ,JDK1.8

Entity類

SeqInfo.java

package com.gl.springbootdao.mongodb.entity;


import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field
; /** * 模擬序列類 * @author zxy * @date 2018年1月8日 */ @Getter @Setter @ToString @Document(collection = "sequence") public class SeqInfo { @Id private String id;// 主鍵 @Field private String collName;// 集合名稱 @Field private Long seqId;// 序列值 }
User.java
package com.gl.springbootdao.mongodb.entity;

import 
com.gl.springbootdao.mongodb.annotations.AutoValue; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; import java.io.Serializable; import lombok.Getter; import lombok.Setter; import
lombok.ToString; @Document(collection="user") @Getter @Setter @ToString public class User{ @Id @Field("_id") @AutoValue private long id; @Field("username") private String userName; @Field("password") private String passWord; public User() { super(); } public User(String userName, String passWord) { this.userName = userName; this.passWord =passWord; } /** * @CompoundIndex 複合索引,加複合索引後通過複合索引欄位查詢將大大提高速度。 @Document @CompoundIndexes({ @CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}") }) public class Person<T extends Address> { } 寫法如上,lastName和age將作為複合索引,數字引數指定索引的方向,1為正序,-1為倒序。方向對單鍵索引和隨機存不要緊,但如果你要執行分組和排序操作的時候,它就非常重要了。 @Transient 被該註解標註的,將不會被錄入到資料庫中。只作為普通的javaBean屬性。 */ }

自定義主鍵註解:

package com.gl.springbootdao.mongodb.annotations;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoValue {
}

自定義監聽器類

package com.gl.springbootdao.mongodb.listener;
import com.gl.springbootdao.mongodb.entity.SeqInfo;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
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.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;

import org.slf4j.Logger;

import com.gl.springbootdao.mongodb.annotations.AutoValue;

/**
 * 儲存文件監聽類<br>
 * 在儲存物件時,通過反射方式為其生成ID
 * @author zxy
 * @date 2018年1月8日
 */

/**@Component泛指元件,當元件不好歸類的時候,我們可以使用這個註解進行標註
 * @Document  把一個java類宣告為mongodb的文件,可以通過collection引數指定這個類對應的文件*/
@Component
public class SaveEventListener extends AbstractMongoEventListener<Object> {
    private final static Logger logger = LoggerFactory.getLogger(SaveEventListener.class);
    @Autowired
    private MongoTemplate mongo;

    /**
     * Captures {@link BeforeConvertEvent}.
     *
     * @param event never {@literal null}.
     * @since 1.8
     */
    @Override
    public void onBeforeConvert(BeforeConvertEvent<Object> event) {
        final Object source = event.getSource();
        if (source != null) {
            ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
                /** Perform an operation using the given field.
                 * @param field the field to operate on */
                @Override
                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                    ReflectionUtils.makeAccessible(field);
                    // 如果欄位添加了我們自定義的AutoValue註解
                    if (field.isAnnotationPresent(AutoValue.class) && field.get(source) instanceof Number
                            && field.getLong(source) == 0) {
                        // field.get(source) instanceof Number &&
                        // field.getLong(source)==0
                        // 判斷註解的欄位是否為number型別且值是否等於0.如果大於0說明有ID不需要生成ID
                        // 設定自增ID
                        field.set(source, getNextId(source.getClass().getSimpleName()));
                        logger.debug("集合的ID為======================="+ source);
                    }
                }
            });
        }
    }

    /**
     * @since 1.7
     */
    /*@Override
    public void onBeforeConvert(final Object source) {
        if (source != ) {
            ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
                public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                    ReflectionUtils.makeAccessible(field);
                    // 如果欄位添加了我們自定義的AutoIncKey註解
                    if (field.isAnnotationPresent(AutoIncKey.class)) {
                        // 設定自增ID
                        field.set(source, getNextId(source.getClass().getSimpleName()));
                    }
                }
            });
        }
    }*/

    /**
     * 獲取下一個自增ID
     *
     * @param collName
     *            集合(這裡用類名,就唯一性來說最好還是存放長類名)名稱
     * @return 序列值
     */
    private Long getNextId(String collName) {
        logger.debug("CollectionsName======================="+collName);
        Query query = new Query(Criteria.where("collName").is(collName));
        Update update = new Update();
        update.inc("seqId", 1);
        FindAndModifyOptions options = new FindAndModifyOptions();
        options.upsert(true);
        options.returnNew(true);
        SeqInfo seq = mongo.findAndModify(query, update, options, SeqInfo.class);
        logger.debug(collName+"集合的ID為======================="+seq.getSeqId());
        return seq.getSeqId();
    }
}

Dao類

package com.gl.springbootdao.mongodb.dao;

import com.gl.springbootdao.mongodb.entity.User;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface UserDao  extends MongoRepository<User,Long> {
    User findUserByUsername(String name);

    void saveUser(User user);

    void updateUser(User user);

    void deleteUserById(Long id);
}
Dao類實現類:

package com.gl.springbootdao.mongodb.dao.impl;

import com.gl.springbootdao.mongodb.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Component;


@Component
public class UserDaoImpl {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 建立物件
     * @param user
     */
    public void saveUser(User user) {
        mongoTemplate.save(user);
    }

    /**
     * 根據使用者名稱查詢物件
     * @param userName
     * @return
     */
    public User findUserByUsername(String userName) {
        Query query=new Query(Criteria.where("userName").is(userName));
        User user =  mongoTemplate.findOne(query , User.class);
        return user;
    }

    /**
     * 更新物件
     * @param user
     */
    public void updateUser(User user) {
        Query query=new Query(Criteria.where("id").is(user.getId()));
        Update update= new Update().set("userName", user.getUserName()).set("passWord", user.getPassWord());
        //更新查詢返回結果集的第一條
        mongoTemplate.updateFirst(query,update,User.class);
        //更新查詢返回結果集的所有
        // mongoTemplate.updateMulti(query,update,UserEntity.class);
    }

    /**
     * 刪除物件
     * @param id
     */
    public void deleteUserById(Long id) {
        Query query=new Query(Criteria.where("id").is(id));
        mongoTemplate.remove(query,User.class);
    }
}
測試類

package com.gl.springbootdao;

import com.gl.springbootdao.mongodb.dao.UserDao;
import com.gl.springbootdao.mongodb.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@RunWith(SpringRunner.class)// SpringJUnit支援,由此引入Spring-Test框架支援!
@SpringBootTest(classes = SpringbootDaoApplication.class)
@WebAppConfiguration
@TestPropertySource("classpath:application.properties")
public class mongodbTests {

   @Autowired(required=true)
   private UserDao userDao;

   @Autowired
   private MongoTemplate mongo;


/**mongodb基本操作*/
   @Autowired
   private MongoTemplate mongoTemplate;
   @Test
   public void testSaveUser() throws Exception {
      User user=new User();
      user.setId((long) 1111);
      user.setUserName("test2");
      user.setPassWord("123456");
      userDao.saveUser(user);
   }

   @Test
   public void findUserByUserName(){
      Query query=new Query(Criteria.where("id").is((long) 1111));
      User user =  mongoTemplate.findOne(query , User.class);
      System.out.println("user is "+user);
   }
   @Test
   public void updateUser(){
      User user=new User();
      user.setId((long) 1111);
      user.setUserName("test");
      user.setPassWord("111111");
      userDao.updateUser(user);
   }


   @Test
   public void save() {
      User user=new User();
      /*user.setId(SaveEventListener.getNextId(""));*/
      user.setUserName("2");
      user.setPassWord("123456");
//    userDao.saveUser(user);
      mongo.save(user);
      System.out.println("已生成ID:" + user.getId());
   }

   @Test
   public void deleteUserById(){
      userDao.deleteUserById((long) 1111);
   }

   @Test
   public void contextLoads() {
   }

}
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.gl</groupId>
   <artifactId>springboot-dao</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>springboot-dao</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.9.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.6</java.version>
   </properties>

   <dependencies>
      <!-- spring boot starter -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
         <exclusions>
            <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
         </exclusions>
      </dependency>
    
      <!-- web -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <!-- test -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
      <dependency>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>xml-maven-plugin</artifactId>
         <version>1.0</version>
      </dependency>
      <!--引入tomcat依賴,可以自定義啟動埠 -->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
      </dependency>
      <!-- mysql -->
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>
      <!--mongodb 多資料來源配置
      Lombok - 是一個可以通過簡單的註解形式來幫助我們簡化消除一些必須有但顯得很臃腫的Java程式碼的工具,通過使用對應的註解,
      可以在編譯原始碼的時候生成對應的方法。簡單試了以下這個工具還挺好玩的,加上註解我們就不用手動寫 getter\setter、構建方式類似的程式碼了。

      spring-boot-autoconfigure - 就是spring boot的自動化配置-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-mongodb</artifactId>
      </dependency>
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-autoconfigure</artifactId>
         <version>RELEASE</version>
      </dependency>
      <!-- mongodb driver -->
      <dependency>
         <groupId>org.mongodb</groupId>
         <artifactId>mongodb-driver</artifactId>
         <version>3.2.2</version>
      </dependency>
      <!--檢測JSON格式的響應資料-->
      <dependency>
         <groupId>com.jayway.jsonpath</groupId>
         <artifactId>json-path</artifactId>
      </dependency>
      <!--安裝外掛 lombok -->
      <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
      <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>1.16.10</version>
         <scope>provided</scope>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>


</project>
springboot配置檔案

application.properties

## 開發/測試/生產環境分別對應dev/test/prod,可以自由定義
spring.profiles.active=dev

##spring mvc
mvc.view.prefix= /views/
mvc.view.suffix= .jsp
application-dev.properties

##service
server.port=9082
server.session.timeout=10
server.tomcat.uri-encoding=UTF-8

## mongodb
spring.data.mongodb.uri=mongodb://test:[email protected]:27017/meetings