MongoDB学习(五) Spring Data整合MongoDB

官网:https://projects.spring.io/spring-data-mongodb/

也可参考:https://www.cnblogs.com/wihainan/p/7064829.html

一、整合基础

spring集成的一些nosql或者sql数据库,都习惯用xxxxTemplate。一般看到xxxxTemplate,我们就可以认为是spring集成的。要和原生的使用方式区分开来。讨论spring提供的mongodb的整合封装。

我们可以在Mongodb中存储数亿级别的这种数据而不影响效率。提醒一下:Mongodb不适合按照多条件查询,我们一般用id值来做查询。多条件查询时需要建索引,而且容易把库查死。

MongoDB可以不用创建库和集合,只要在applicationContext.xml中指定即可

1、Maven的pom.xml

    <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.3.9.RELEASE</spring.version>
		<!-- log4j日志文件管理包版本 -->
		<slf4j.version>1.6.6</slf4j.version>
		<log4j.version>1.2.12</log4j.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mongodb</groupId>
			<artifactId>mongo-java-driver</artifactId>
			<version>3.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-mongodb</artifactId>
			<version>1.7.1.RELEASE</version>
		</dependency>
		<!-- 日志文件管理包 -->
		<!-- log start -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>${log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<!-- log end -->

	</dependencies>


2、整合步骤的关键:applicationContext.xml

        其中红色部分完全可以不写,具体的作用下回解答

<?xml version="1.0" encoding="UTF-8"?>    
<beans xmlns="http://www.springframework.org/schema/beans"    
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
    xmlns:context="http://www.springframework.org/schema/context"    
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd    
        http://www.springframework.org/schema/data/mongo         
        http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd     
        http://www.springframework.org/schema/context    
        http://www.springframework.org/schema/context/spring-context-4.0.xsd">    
    
    <context:component-scan base-package="com.wqc" />    
    
    <mongo:mongo host="127.0.0.1" port="27017" />    
    
    <!-- mongo的工厂,通过它来取得mongo实例,dbname为mongodb的数据库名,没有的话会自动创建 -->    
    <mongo:db-factory dbname="test_mongodb" mongo-ref="mongo" />    
    
    <!-- mongodb的主要操作对象,所有对mongodb的增删改查的操作都是通过它完成 -->    
    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">    
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />    
    </bean>    
    
    <!-- 映射转换器,扫描back-package目录下的文件,根据注释,把它们作为mongodb的一个collection的映射 -->    
    <mongo:mapping-converter base-package="com.wqc.model" />    
    
    <!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 -->    
    <mongo:repositories base-package="com.wqc.dao.impl" />    
    
    <context:annotation-config />    
    
</beans>

二、接下来就是CRUD封装的底层DAO接口及其实现类

1、DAO 接口:

package com.wqc.dao;

import java.io.File;
import java.util.List;
import java.util.Map;

import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.mongodb.gridfs.GridFSDBFile;
import com.wqc.dao.model.Page;

/**
 * @ClassName: BaseDaoI
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author: 
 * @date: 2018年5月29日 下午2:37:47
 */
public interface BaseDaoI<T> {

	void _test();

	void createCollection(T object);

	List<T> findList(Query query);
	
	List<T> findList(int skip, int limit);

	T findOneByItems(Map<String, Object> params);
	
	List<T> findByItems(Map<String, Object> params);

	List<T> findListByPageAndItems(int skip, int rows, Map<String, Object> params);
	
	// 分页查询  
    Page<T> findPage(Page<T> page,Query query);

	void insert(T t);

	void update(Query query, Update update);
	
	void update(String id, Map<String, Object> params, T t);
	
    long count(Query query);

	long count(Map<String, Object> params);

	void deleteById(String id);

	void saveFile(File file, String fileUrl);

	GridFSDBFile retrieveFileOne(String filename);
}

2、DAO 实现:

import java.io.File;  
import java.io.IOException;  
import java.lang.reflect.ParameterizedType;  
import java.util.List;  
import java.util.Map;  
import java.util.Set;  
  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.data.domain.Sort;  
import org.springframework.data.domain.Sort.Direction;  
import org.springframework.data.domain.Sort.Order;  
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.Repository;

import com.mongodb.DB;  
import com.mongodb.gridfs.GridFS;  
import com.mongodb.gridfs.GridFSDBFile;  
import com.mongodb.gridfs.GridFSInputFile;
import com.wqc.dao.BaseDaoI;
import com.wqc.dao.model.Page;
import com.wqc.util.ReflectionUtils;

/**   
 * @ClassName: BaseDaoImpl   
 * @Description: TODO(这里用一句话描述这个类的作用)   
 * @author: 
 * @date: 2018年5月29日 下午2:38:23    
 */


@Repository  
public class BaseDaoImpl<T> implements BaseDaoI<T> {  
      
    public static final Logger LOGGER = LoggerFactory.getLogger(BaseDaoImpl.class);  
      
    public static final String FILEURL="imgRespository";
  
    @Autowired  
    private MongoTemplate mongoTemplate;  
      
    private Class<?> clz;  
      
    public Class<?> getClz() {
    	LOGGER.info("getClz()");
        if(clz==null) { 
        	LOGGER.info("初始化:getClz()");
            //获取泛型的Class对象  
            clz = ((Class<?>)  
                    (((ParameterizedType)(this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]));  
        }  
        return clz;  
    }  
    public BaseDaoImpl() {  
          LOGGER.info("BaseDaoImpl()");
    }  
  
    @Override  
    public void _test() {  
        Set<String> colls = this.mongoTemplate.getCollectionNames();  
        for (String coll : colls) {  
        	LOGGER.info("CollectionName=" + coll);  
        }  
        DB db = this.mongoTemplate.getDb();  
        LOGGER.info("db=" + db.toString());  
    }  
  
    @Override  
    public void createCollection(T object) {
    	LOGGER.info("createCollection_000");
        if (!this.mongoTemplate.collectionExists(getClz())) {
            this.mongoTemplate.createCollection(getClz());  
        } 
          
    }  
  
    @Override  
    public List<T> findList(Query query) {  
        return mongoTemplate.find(query, this.getEntityClass());  
    }
    
    @Override  
    public List<T> findList(int skip, int limit) {  
        Query query = new Query();  
        query.with(new Sort(new Order(Direction.ASC, "_id")));  
        query.skip(skip).limit(limit);  
        return (List<T>)this.mongoTemplate.find(query, getClz());  
    }  
  
    @Override  
    public T findOneByItems(Map<String, Object> params) {  
        Query query = new Query();  
        if ((params != null) && (!(params.isEmpty()))) {  
              for (String key : params.keySet()) {  
                  query.addCriteria(new Criteria(key).is(params.get(key)));  
              }  
         }  
        return (T)mongoTemplate.findOne(query, getClz());  
    }  
    
    @Override  
    public List<T> findByItems(Map<String, Object> params) {  
        Query query = new Query();  
        if ((params != null) && (!(params.isEmpty()))) {  
              for (String key : params.keySet()) {  
                  query.addCriteria(new Criteria(key).is(params.get(key)));  
              }  
            }  
        return (List<T>)this.mongoTemplate.find(query, getClz());  
    }  
  
    @Override  
    public List<T> findListByPageAndItems(int skip, int rows,  
            Map<String, Object> params) {  
        Query query = new Query();  
        if ((params != null) && (!(params.isEmpty()))) {  
              for (String key : params.keySet()) {  
                  query.addCriteria(new Criteria(key).is(params.get(key)));  
              }  
         }  
        query.skip(skip).limit(rows);  
        return (List<T>)this.mongoTemplate.find(query, getClz());  
    }  
    
    @Override
	public Page<T> findPage(Page<T> page, Query query) {
		int count = (int)this.count(query);  
        page.setTotalCount(count);  
        int pageSize = page.getPageSize();  
        query.skip(page.getStartIndex()).limit(pageSize);  
        List<T> rows = this.findList(query);  
        page.setRows(rows);  
        return page;
	}
  
    @Override  
    public void insert(T t) {  
        this.mongoTemplate.insert(t);  
    }  
  
    @Override  
    public long count(Query query){  
        return mongoTemplate.count(query, this.getEntityClass());  
    } 
  
    @Override  
    public long count(Map<String, Object> params) {  
        Query query = new Query();  
        if ((params != null) && (!(params.isEmpty()))) {  
              for (String key : params.keySet()) {  
                  query.addCriteria(new Criteria(key).is(params.get(key)));  
              }  
            }  
        return (long)mongoTemplate.find(query, getClz()).size();  
    }  
  
    @Override  
    public void update(Query query, Update update) {  
        mongoTemplate.findAndModify(query, update, this.getEntityClass());  
    }
    
    @Override  
    public void update(String id, Map<String, Object> params,T t) {  
        Query query = new Query();  
        query.addCriteria(new Criteria("_id").is(id));  
        Update update = new Update();  
        if ((params != null) && (!(params.isEmpty()))) {  
              for (String key : params.keySet()) {  
                  update.set(key, params.get(key));  
              }  
         }  
        this.mongoTemplate.updateFirst(query, update,getClz());  
    }  
    @Override  
    public void deleteById(String id) {  
        mongoTemplate.remove(new Query(Criteria.where("_id").is(id)), getClz());  
    }  
      
      
    @Override  
    public void saveFile(File file, String fileUrl) {  
          try {    
                DB db = mongoTemplate.getDb();    
                GridFS fs = new GridFS(db, FILEURL);    
                GridFSInputFile inputFile = fs.createFile(file);    
                inputFile.setFilename(fileUrl);    
                inputFile.setContentType(fileUrl.substring(fileUrl.lastIndexOf(".")));    
                inputFile.save();    
            } catch (IOException e) {    
                e.printStackTrace();    
            }   
    }  
      
    @Override  
    public GridFSDBFile retrieveFileOne(String filename) {  
         try {    
                DB db = mongoTemplate.getDb();    
                // 获取fs的根节点    
                GridFS gridFS = new GridFS(db, FILEURL);    
                GridFSDBFile dbfile = gridFS.findOne(filename);    
                if (dbfile != null) {    
                    return dbfile;    
                }    
            } catch (Exception e) {    
                e.printStackTrace();    
            }    
            return null;   
    }
    
	private Class<T> getEntityClass(){  
        return ReflectionUtils.getSuperClassGenricType(getClass());  
    }
	
}

3、DAO分页参数

public class Page<T> implements Serializable {

	/**
	 * @Fields serialVersionUID: TODO(用一句话描述这个变量表示什么)
	 */
	private static final long serialVersionUID = -8896679359677548079L;
	public static final int DEFAULT_PAGE_MAXSIZE = 1000;
	public static final int DEFAULT_PAGE_SIZE = 10;
	public static final int DEFAULT_CURRENT_PAGE = 1;
	
	private int startIndex;
	/**
	 * 每页显示个数
	 */
	private int pageSize;
	/**
	 * 当前页数
	 */
	private int currentPage;
	/**
	 * 总页数
	 */
	private int totalPage;
	/**
	 * 总记录数
	 */
	private int totalCount;
	/**
	 * 结果列表
	 */
	private List<T> rows;

	public int getStartIndex() {
		return (getCurrentPage()-1)*getPageSize();
	}

	public int getPageSize() {
		if (pageSize < 1) {
			this.setPageSize(DEFAULT_PAGE_SIZE);
		}
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		if (pageSize > DEFAULT_PAGE_MAXSIZE) {
			setPageSize(DEFAULT_PAGE_SIZE);
		}else {
			this.pageSize = pageSize;
		}
	}

	public int getCurrentPage() {
		if (currentPage < 1) {
			setCurrentPage(DEFAULT_CURRENT_PAGE);
		}
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}

	/**
	 * 设置结果 及总页数
	 * 
	 * @param list
	 */
	public void build(List<T> rows) {
		this.setRows(rows);
		int count = this.getTotalCount();
		int divisor = count / this.getPageSize();
		int remainder = count % this.getPageSize();
		this.setTotalPage(remainder == 0 ? divisor == 0 ? 1 : divisor : divisor + 1);
	}

	public List<T> getRows() {
		return rows;
	}

	public void setRows(List<T> rows) {
		this.rows = rows;
	}
}

三、业务类及其DAO接口与实现

1、业务类:

Staff:

@Document(collection = "staff")
public class Staff {
	
	@Id
	private String id;

	/**
	 * 姓名
	 */
	private String name;

	/**
	 * 邮箱
	 */
	private String[] email;

	/**
	 * 出身日期
	 */
	private Date birthday;

	/**
	 * 部门名称
	 */
	private String department;

	/**
	 * 毕业学校
	 */
	private String school;

	/**
	 * 现居地
	 */
	private String location;

	/**
	 * 年龄
	 */
	private int age;

	/**
	 * 员工评论
	 */
	private List<Comment> comments;

	public String getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String[] getEmail() {
		return email;
	}

	public void setEmail(String[] email) {
		this.email = email;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getDepartment() {
		return department;
	}

	public void setDepartment(String department) {
		this.department = department;
	}

	public String getSchool() {
		return school;
	}

	public void setSchool(String school) {
		this.school = school;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public List<Comment> getComments() {
		return comments;
	}

	public void setComments(List<Comment> comments) {
		this.comments = comments;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Staff [id=" + id + ", name=" + name + ", email=" + Arrays.toString(email) + ", birthday=" + birthday
				+ ", department=" + department + ", school=" + school + ", location=" + location + ", age=" + age
				+ ", comments=" + comments + "]";
	}

Comment.java:

@Document
public class Comment {

	@Id
	private String id;

	/**
	 * 评论内容
	 */
	private String content;

	/**
	 * 评论日期
	 */
	private Date conDate;

	public Comment() {

	}

	public Comment(String content, Date conDate) {
		this.content = content;
		this.conDate = conDate;
	}

	public String getId() {
		return id;
	}

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

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Date getConDate() {
		return conDate;
	}

	public void setConDate(Date conDate) {
		this.conDate = conDate;
	}
}

2、业务DAO接口与实现:

接口:

import org.springframework.transaction.annotation.Transactional;

import com.wqc.model.Staff;

/**   
 * @ClassName: StaffDaoI   
 * @Description: TODO(这里用一句话描述这个类的作用)   
 * @author: 
 * @date: 2018年5月29日 下午2:36:47    
 */


@Transactional
public interface StaffDaoI extends BaseDaoI<Staff> {  
  
}

实现:

import org.springframework.stereotype.Repository;

import com.wqc.dao.StaffDaoI;
import com.wqc.model.Staff;

/**   
 * @ClassName: StaffDaoImpl   
 * @Description: TODO(这里用一句话描述这个类的作用)   
 * @author: 
 * @date: 2018年5月29日 下午2:40:57    
 */

@Repository  
public class StaffDaoImpl extends BaseDaoImpl<Staff> implements StaffDaoI{  
  
}

四、测试用例:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.mongodb.gridfs.GridFSDBFile;
import com.wqc.dao.StaffDaoI;
import com.wqc.dao.impl.BaseDaoImpl;
import com.wqc.dao.model.Page;
import com.wqc.model.Comment;
import com.wqc.model.Staff;

/**   
 * @ClassName: TestMongoDb   
 * @Description: TODO(这里用一句话描述这个类的作用)   
 * @author: wuqichun 
 * @date: 2018年5月29日 下午2:35:28    
 */

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })  
public class TestMongoDb {  
  
	 public static final Logger LOGGER = LoggerFactory.getLogger(TestMongoDb.class);
	 
    @Autowired  
    public StaffDaoI staffDao;  
  
    /** 
     * 在数据库test_mongodb中创建一个collection集合staff 
     */  
    @Test  
    public void test1() {
        Staff staff = new Staff();
        staffDao.createCollection(staff);  
    }  
      
    /** 
     * 保存一条数据 
     */  
    @Test  
    public void test2() {  
        Staff staff = new Staff();  
        staff.setName("chenjunfeng");  
        staff.setAge(35);  
        staff.setDepartment("1-4-4");  
        staff.setLocation("sanshanjie");  
        staff.setBirthday(new Date());  
        staff.setId("000111");  
        staff.setSchool("nanjingdaxue");  
        Comment comment=new Comment();  
        comment.setConDate(new Date());  
        comment.setContent("good leader");  
        Comment comment1=new Comment();  
        comment.setConDate(new Date());  
        comment.setContent("a very good leader");  
        List<Comment> comments=new ArrayList<Comment>();  
        comments.add(comment);  
        comments.add(comment1);  
        staff.setComments(comments);  
        staff.setEmail(new String[]{"cjf@123.com","smile@163.com"});  
        staffDao.insert(staff);  
    }  
      
    /** 
     * 根据检索条件返回检索个数 
     */  
    @Test  
    public void test3() {  
        Map<String,Object> params=new HashMap<String, Object>();  
        params.put("age", 35);  
        System.out.println(staffDao.count(params));  
    }  
      
    /** 
     * 根据条件返回数据的集合 
     */  
    @Test  
    public void test5() {  
        Map<String,Object> params=new HashMap<String, Object>();  
        params.put("age", 35);  
        System.out.println(staffDao.findByItems(params).get(0).toString());  
    }  
      
    /** 
     * 存储图片 
     */  
    @Test  
    public void test6() {  
         File file=new File("D:\\cloud.jpg");  
         String fileUrl="cloud.jpg";  
         staffDao.saveFile(file, fileUrl);  
    }  
      
    /** 
     *  取出图片 
     * @throws IOException 
     */  
    @Test  
    public void test7() throws IOException {  
         String fileUrl="cloud.jpg";  
         GridFSDBFile file=staffDao.retrieveFileOne(fileUrl);  
         System.out.println(file.getId());  
         System.out.println(file.getContentType());  
         System.out.println(file.getChunkSize());  
         file.writeTo(new File("E:\\cloud.jpg"));  
    }  
    
    //循环插入数据
    @Test  
    public void test8() {  
    	for (int i = 10; i < 500; i++) {
    		Staff staff = new Staff();  
            staff.setName("chenjunfeng");  
            staff.setAge(35);  
            staff.setDepartment("1-4-4");  
            staff.setLocation("sanshanjie");  
            staff.setBirthday(new Date());  
            staff.setId(""+1000+i);  
            staff.setSchool("nanjingdaxue");  
            Comment comment=new Comment();  
            comment.setConDate(new Date());  
            comment.setContent("good leader");  
            Comment comment1=new Comment();  
            comment.setConDate(new Date());  
            comment.setContent("a very good leader");  
            List<Comment> comments=new ArrayList<Comment>();  
            comments.add(comment);  
            comments.add(comment1);  
            staff.setComments(comments);  
            staff.setEmail(new String[]{"cjf@123.com","smile@163.com"});  
            staffDao.insert(staff);  
		}
    } 
    
    //分页查询
    @Test
    public void test9() throws Exception {
    	Query query = new Query();
    	query.addCriteria(new Criteria("age").is(35));
    	Page page = new Page();
    	page.setCurrentPage(2);
    	page.setPageSize(10);
    	Page<Staff> pageList = staffDao.findPage(page, query);
    	for (Staff staff : pageList.getRows()) {
			System.out.println(staff);
		}
    }
      
}

五、工具类:

ReflectionUtils.java:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.util.Assert;
import org.springframework.util.StringUtils;

/**
 * @ClassName: ReflectionUtils
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author: wuqichun
 * @date: 2018年5月29日 下午12:34:14
 */
public class ReflectionUtils {

	private static Logger LOGGER = LoggerFactory.getLogger(ReflectionUtils.class);

	/**
	 * 调用Getter方法.
	 */
	public static Object invokeGetterMethod(Object obj, String propertyName) {
		String getterMethodName = "get" + StringUtils.capitalize(propertyName);
		return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});
	}

	/**
	 * 调用Setter方法.使用value的Class来查找Setter方法.
	 */
	public static void invokeSetterMethod(Object obj, String propertyName, Object value) {
		invokeSetterMethod(obj, propertyName, value, null);
	}

	/**
	 * 调用Setter方法.
	 * 
	 * @param propertyType
	 *            用于查找Setter方法,为空时使用value的Class替代.
	 */
	public static void invokeSetterMethod(Object obj, String propertyName, Object value, Class<?> propertyType) {
		Class<?> type = propertyType != null ? propertyType : value.getClass();
		String setterMethodName = "set" + StringUtils.capitalize(propertyName);
		invokeMethod(obj, setterMethodName, new Class[] { type }, new Object[] { value });
	}

	/**
	 * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
	 */
	public static Object getFieldValue(final Object obj, final String fieldName) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
		}

		Object result = null;
		try {
			result = field.get(obj);
		} catch (IllegalAccessException e) {
			LOGGER.error("不可能抛出的异常{}", e.getMessage());
		}
		return result;
	}

	/**
	 * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
	 */
	public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
		}

		try {
			field.set(obj, value);
		} catch (IllegalAccessException e) {
			LOGGER.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
	 * 
	 * 如向上转型到Object仍无法找到, 返回null.
	 */
	public static Field getAccessibleField(final Object obj, final String fieldName) {
		Assert.notNull(obj, "object不能为空");
		Assert.hasText(fieldName, "fieldName");
		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				Field field = superClass.getDeclaredField(fieldName);
				field.setAccessible(true);
				return field;
			} catch (NoSuchFieldException e) {// NOSONAR
				// Field不在当前类定义,继续向上转型
			}
		}
		return null;
	}

	/**
	 * 直接调用对象方法, 无视private/protected修饰符. 用于一次性调用的情况.
	 */
	public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
			final Object[] args) {
		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
		if (method == null) {
			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]");
		}

		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 如向上转型到Object仍无法找到, 返回null.
	 * 
	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object...
	 * args)
	 */
	public static Method getAccessibleMethod(final Object obj, final String methodName,
			final Class<?>... parameterTypes) {
		Assert.notNull(obj, "object不能为空");

		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				Method method = superClass.getDeclaredMethod(methodName, parameterTypes);

				method.setAccessible(true);

				return method;

			} catch (NoSuchMethodException e) {// NOSONAR
				// Method不在当前类定义,继续向上转型
			}
		}
		return null;
	}

	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. eg. public UserDao
	 * extends HibernateDao<User>
	 * 
	 * @param clazz
	 *            The class to introspect
	 * @return the first generic declaration, or Object.class if cannot be
	 *         determined
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static <T> Class<T> getSuperClassGenricType(final Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class.
	 * 
	 * 如public UserDao extends HibernateDao<User,Long>
	 * 
	 * @param clazz
	 *            clazz The class to introspect
	 * @param index
	 *            the Index of the generic ddeclaration,start from 0.
	 * @return the index generic declaration, or Object.class if cannot be
	 *         determined
	 */
	@SuppressWarnings("rawtypes")
	public static Class getSuperClassGenricType(final Class clazz, final int index) {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			LOGGER.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			LOGGER.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
					+ params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			LOGGER.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}

		return (Class) params[index];
	}

	/**
	 * 将反射时的checked exception转换为unchecked exception.
	 */
	public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {
		if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
				|| e instanceof NoSuchMethodException) {
			return new IllegalArgumentException("Reflection Exception.", e);
		} else if (e instanceof InvocationTargetException) {
			return new RuntimeException("Reflection Exception.", ((InvocationTargetException) e).getTargetException());
		} else if (e instanceof RuntimeException) {
			return (RuntimeException) e;
		}
		return new RuntimeException("Unexpected Checked Exception.", e);
	}

	/*
	 * 
	 */

	/**
	 * 根据对象获得mongodb Update语句 除id字段以外,所有被赋值的字段都会成为修改项
	 */
	public static Update getUpdateObj(final Object obj) {
		if (obj == null)
			return null;
		Field[] fields = obj.getClass().getDeclaredFields();
		Update update = null;
		boolean isFirst = true;
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				Object value = field.get(obj);
				if (value != null) {
					if ("id".equals(field.getName().toLowerCase())
							|| "serialversionuid".equals(field.getName().toLowerCase()))
						continue;
					if (isFirst) {
						update = Update.update(field.getName(), value);
						isFirst = false;
					} else {
						update = update.set(field.getName(), value);
					}
				}

			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		return update;
	}

	/**
	 * 根据对象获得mongodb Query语句
	 * 
	 * 1.时间范围查询:在时间字段前增加begin或end,为这两个字段分别赋值 例:private Date createDate; 开始时间
	 * private Date beginCreateDate; 结束时间 private Date endCreateDate;
	 * 分析后结果:where createDate >= beginCreateDate and createDate <
	 * beginCreateDate
	 * 
	 * 2.排序 定义并赋值VO中 orderBy 字段,以英文“,”分割多个排序,以空格分隔排序方向 asc可不写 例:private String
	 * orderBy; orderBy="createDate desc,sendDate asc,id" 分析结构:order by
	 * createDate desc,sendDate asc,id asc
	 * 
	 * 3.固定值搜索 定义并赋值VO中的任意字段,搜索时会把以赋值的字段当作为搜索条件
	 */
	public static Query getQueryObj(final Object obj) {
		if (obj == null)
			return null;
		Field[] fields = obj.getClass().getDeclaredFields();
		// Sort sort=new Sort(new Order(Direction.DESC,"createDate"));
		Query query = new Query();
		// 存放日期范围或者确定日期
		Map<String, Criteria> dateMap = new HashMap<String, Criteria>();
		String sortStr = null;
		for (Field field : fields) {
			field.setAccessible(true);
			try {
				Object value = field.get(obj);
				if (value != null) {
					if ("serialversionuid".equals(field.getName().toLowerCase())) {
						continue;
					}
					if ("orderby".equals(field.getName().toLowerCase())) {
						sortStr = String.valueOf(value);
						continue;
					}
					// 如果是日期类型
					if (field.getType().getSimpleName().equals("Date")) {
						if (field.getName().toLowerCase().startsWith("begin")) {
							String beginName = field.getName().substring(5);
							if (beginName.isEmpty()) {
								dateMap.put("begin", Criteria.where("begin").is(value));
							} else {
								beginName = StringUtil.toLowerCaseFirstOne(beginName);
								Criteria criteria = dateMap.get(beginName) == null
										? Criteria.where(beginName).gte(value) : dateMap.get(beginName).gte(value);
								dateMap.put(beginName, criteria);
							}
							continue;
						}
						if (field.getName().toLowerCase().startsWith("end")) {
							String endName = field.getName().substring(3);
							if (endName.isEmpty()) {
								dateMap.put("end", Criteria.where("end").is(value));
							} else {
								endName = StringUtil.toLowerCaseFirstOne(endName);
								Criteria criteria = dateMap.get(endName) == null ? Criteria.where(endName).lt(value)
										: dateMap.get(endName).lt(value);
								dateMap.put(endName, criteria);
							}
							continue;
						}
						dateMap.put(field.getName(), Criteria.where(field.getName()).is(value));
						continue;
					}
					query.addCriteria(Criteria.where(field.getName()).is(value));
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		// 日期类型查询条件
		for (String key : dateMap.keySet()) {
			if (dateMap.get(key) != null) {
				query.addCriteria(dateMap.get(key));
			}
		}
		// 排序
		if (sortStr != null && !sortStr.trim().isEmpty()) {
			Sort sort = null;
			String[] strs = sortStr.split(",");
			for (String str : strs) {
				str = str.trim();
				if (str.isEmpty()) {
					continue;
				}
				int i = str.indexOf(" ");
				if (i < 0) {
					if (sort == null) {
						sort = new Sort(Direction.ASC, str);
					} else {
						sort = sort.and(new Sort(Direction.ASC, str));
					}
				} else {
					String name = str.substring(0, i);
					String dire = str.substring(i + 1).trim();
					Sort sn = null;
					if ("desc".equals(dire.toLowerCase())) {
						sn = new Sort(Direction.DESC, name);
					} else {
						sn = new Sort(Direction.ASC, name);
					}
					if (sort == null) {
						sort = sn;
					} else {
						sort = sort.and(sn);
					}
				}
			}
			if (sort != null) {
				query.with(sort);
			}
		}
		return query;
	}

	public static void main(String[] a) {
		
	}
}

StringUtils:

public class StringUtil {

	//首字母转小写  
    public static String toLowerCaseFirstOne(String s)  
    {  
        if(Character.isLowerCase(s.charAt(0)))  
            return s;  
        else  
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();  
    }  
    //首字母转大写  
    public static String toUpperCaseFirstOne(String s)  
    {  
        if(Character.isUpperCase(s.charAt(0)))  
            return s;  
        else  
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();  
    } 
}

六、工程结构图


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值