官网:https://projects.spring.io/spring-data-mongodb/
一、整合基础
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();
}
}
六、工程结构图