iBase4J项目笔记
阅读原文时间:2023年07月16日阅读:1

  1 数据库密码加密

  2 service层概述

  3 web层概述

  4 后端CRUD

    4.1 READ

    4.2 UPDATE

    4.3 CREATE

    4.4 DELETE

  5 facade层概述

  iBase4J项目的service层中数据库配置文件中数据库的连接密码必须是经过加密过后的,如何获取加密方法

  1.1 加密类是 org.ibase4j.core.util.PropertiesUtil

end

  2.1 所有service层都继承于BaseService

package top.ibase4j.core.base;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;

import top.ibase4j.core.Constants;
import top.ibase4j.core.util.CacheUtil;
import top.ibase4j.core.util.DataUtil;
import top.ibase4j.core.util.ExceptionUtil;
import top.ibase4j.core.util.InstanceUtil;
import top.ibase4j.core.util.PropertiesUtil;

/**
* 业务逻辑层基类,继承基类后必须配置CacheConfig(cacheNames="")
*
* @author ShenHuaJie
* @version 2016年5月20日 下午3:19:19
*/
public abstract class BaseService implements ApplicationContextAware {
protected Logger logger = LogManager.getLogger(getClass());
@Autowired
protected BaseMapper mapper;

protected ApplicationContext applicationContext;

int maxThread = PropertiesUtil.getInt("db.reader.list.maxThread", 50);  
int threadSleep = PropertiesUtil.getInt("db.reader.list.threadWait", 5);  
ExecutorService executorService = Executors.newFixedThreadPool(maxThread);

/\*\*  
 \* 分页查询  
 \* @param params  
 \* @return  
 \*/  
@SuppressWarnings("unchecked")  
public static Page<Long> getPage(Map<String, Object> params) {  
    Integer current = 1;  
    Integer size = 10;  
    String orderBy = "id\_", sortAsc = null;  
    if (DataUtil.isNotEmpty(params.get("pageNumber"))) {  
        current = Integer.valueOf(params.get("pageNumber").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("pageIndex"))) {  
        current = Integer.valueOf(params.get("pageIndex").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("pageSize"))) {  
        size = Integer.valueOf(params.get("pageSize").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("limit"))) {  
        size = Integer.valueOf(params.get("limit").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("offset"))) {  
        current = Integer.valueOf(params.get("offset").toString()) / size + 1;  
    }  
    if (DataUtil.isNotEmpty(params.get("sort"))) {  
        orderBy = (String)params.get("sort");  
        params.remove("sort");  
    }  
    if (DataUtil.isNotEmpty(params.get("orderBy"))) {  
        orderBy = (String)params.get("orderBy");  
        params.remove("orderBy");  
    }  
    if (DataUtil.isNotEmpty(params.get("sortAsc"))) {  
        sortAsc = (String)params.get("sortAsc");  
        params.remove("sortAsc");  
    }  
    Object filter = params.get("filter");  
    if (filter != null) {  
        params.clear();  
        params.putAll(JSON.parseObject(filter.toString(), Map.class));  
    }  
    if (size == -1) {  
        Page<Long> page = new Page<Long>();  
        page.setOrderByField(orderBy);  
        page.setAsc("Y".equals(sortAsc));  
        return page;  
    }  
    Page<Long> page = new Page<Long>(current, size, orderBy);  
    page.setAsc("Y".equals(sortAsc));  
    return page;  
}

/\*\*  
 \* @param id  
 \* @param userId  
 \*/  
@Transactional  
public void del(Long id, Long userId) {  
    try {  
        T record = this.queryById(id);  
        record.setEnable(0);  
        record.setUpdateTime(new Date());  
        record.setUpdateBy(userId);  
        mapper.updateById(record);  
        try {  
            CacheUtil.getCache().set(getCacheKey(id), record);  
        } catch (Exception e) {  
            logger.error(Constants.Exception\_Head, e);  
        }  
    } catch (Exception e) {  
        throw new RuntimeException(e.getMessage(), e);  
    }  
}

/\*\*  
 \* @param id  
 \*/  
@Transactional  
public void delete(Long id) {  
    try {  
        mapper.deleteById(id);  
    } catch (Exception e) {  
        throw new RuntimeException(e.getMessage(), e);  
    }  
    try {  
        CacheUtil.getCache().del(getCacheKey(id));  
    } catch (Exception e) {  
        logger.error(Constants.Exception\_Head, e);  
    }  
}

/\*\*  
 \* @param t  
 \* @return  
 \*/  
@Transactional  
public Integer deleteByEntity(T t) {  
    Wrapper<T> wrapper = new EntityWrapper<T>(t);  
    return mapper.delete(wrapper);  
}

/\*\*  
 \* @param columnMap  
 \* @return  
 \*/  
@Transactional  
public Integer deleteByMap(Map<String, Object> columnMap) {  
    return mapper.deleteByMap(columnMap);  
}

/\*\*  
 \* 根据Id查询(默认类型T)  
 \* @param ids  
 \* @return  
 \*/  
public List<T> getList(final List<Long> ids) {  
    final List<T> list = InstanceUtil.newArrayList();  
    if (ids != null) {  
        for (int i = 0; i < ids.size(); i++) {  
            list.add(null);  
        }  
        final Map<Integer, Object> thread = InstanceUtil.newConcurrentHashMap();  
        for (int i = 0; i < ids.size(); i++) {  
            final int index = i;  
            executorService.execute(new Runnable() {  
                public void run() {  
                    try {  
                        list.set(index, queryById(ids.get(index)));  
                    } finally {  
                        thread.put(index, 0);  
                    }  
                }  
            });  
        }  
        while (thread.size() < list.size()) {  
            try {  
                Thread.sleep(threadSleep);  
            } catch (InterruptedException e) {  
                logger.error("", e);  
            }  
        }  
    }  
    return list;  
}

/\*\*  
 \* 根据Id查询(cls返回类型Class)  
 \* @param ids  
 \* @param cls  
 \* @return  
 \*/  
public <K> List<K> getList(final List<Long> ids, final Class<K> cls) {  
    final List<K> list = InstanceUtil.newArrayList();  
    if (ids != null) {  
        for (int i = 0; i < ids.size(); i++) {  
            list.add(null);  
        }  
        final Map<Integer, Object> thread = InstanceUtil.newConcurrentHashMap();  
        for (int i = 0; i < ids.size(); i++) {  
            final int index = i;  
            executorService.execute(new Runnable() {  
                public void run() {  
                    try {  
                        T t = queryById(ids.get(index));  
                        K k = InstanceUtil.to(t, cls);  
                        list.set(index, k);  
                    } finally {  
                        thread.put(index, 0);  
                    }  
                }  
            });  
        }  
        while (thread.size() < list.size()) {  
            try {  
                Thread.sleep(threadSleep);  
            } catch (InterruptedException e) {  
                logger.error("", e);  
            }  
        }  
    }  
    return list;  
}

/\*\*  
 \* 根据Id查询(默认类型T)  
 \* @param ids  
 \* @return  
 \*/  
public Page<Map<String, Object>> getPageMap(final Page<Long> ids) {  
    if (ids != null) {  
        Page<Map<String, Object>> page = new Page<Map<String, Object>>(ids.getCurrent(), ids.getSize());  
        page.setTotal(ids.getTotal());  
        final List<Map<String, Object>> records = InstanceUtil.newArrayList();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            records.add(null);  
        }  
        final Map<Integer, Object> thread = InstanceUtil.newConcurrentHashMap();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            final int index = i;  
            executorService.execute(new Runnable() {  
                public void run() {  
                    try {  
                        records.set(index, InstanceUtil.transBean2Map(queryById(ids.getRecords().get(index))));  
                    } finally {  
                        thread.put(index, 0);  
                    }  
                }  
            });  
        }  
        while (thread.size() < records.size()) {  
            try {  
                Thread.sleep(threadSleep);  
            } catch (InterruptedException e) {  
                logger.error("", e);  
            }  
        }  
        page.setRecords(records);  
        return page;  
    }  
    return new Page<Map<String, Object>>();  
}

/\*\*  
 \* @param params  
 \* @return  
 \*/  
public Page<T> query(Map<String, Object> params) {  
    Page<Long> page = getPage(params);  
    page.setRecords(mapper.selectIdPage(page, params));  
    return getPage(page);  
}

/\*\*  
 \* @param id  
 \* @return  
 \*/  
@Transactional  
public T queryById(Long id) {  
    return queryById(id, 1);  
}

/\*\*  
 \* @param params  
 \* @return  
 \*/  
public List<T> queryList(Map<String, Object> params) {  
    List<Long> ids = mapper.selectIdPage(params);  
    List<T> list = getList(ids);  
    return list;  
}

/\*\*  
 \* @param entity  
 \* @return  
 \*/  
public List<T> selectList(Wrapper<T> entity) {  
    return mapper.selectList(entity);  
}

/\*\*  
 \* @param entity  
 \* @return  
 \*/  
public T selectOne(T entity) {  
    return mapper.selectOne(entity);  
}

/\* (non-Javadoc)  
 \* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.  
 \* ApplicationContext) \*/  
public void setApplicationContext(ApplicationContext applicationContext) {  
    this.applicationContext = applicationContext;  
}

/\*\*  
 \* @param record  
 \* @return  
 \*/  
@SuppressWarnings("unchecked")  
@Transactional  
public T update(T record) {  
    try {  
        record.setUpdateTime(new Date());  
        if (record.getId() == null) {  
            record.setCreateTime(new Date());  
            mapper.insert(record);  
            try {  
                CacheUtil.getCache().set(getCacheKey(record.getId()), record);  
            } catch (Exception e) {  
                logger.error(Constants.Exception\_Head, e);  
            }  
        } else {  
            String lockKey = getLockKey("U" + record.getId());  
            if (CacheUtil.tryLock(lockKey)) {  
                try {  
                    T org = null;  
                    String key = getCacheKey(record.getId());  
                    try {  
                        org = (T)CacheUtil.getCache().get(key);  
                    } catch (Exception e) {  
                        logger.error(Constants.Exception\_Head, e);  
                    }  
                    if (org == null) {  
                        org = mapper.selectById(record.getId());  
                    }

                    T update = InstanceUtil.getDiff(org, record);  
                    update.setId(record.getId());  
                    mapper.updateById(update);  
                    record = mapper.selectById(record.getId());  
                    try {  
                        CacheUtil.getCache().set(key, record);  
                    } catch (Exception e) {  
                        logger.error(Constants.Exception\_Head, e);  
                    }  
                } finally {  
                    CacheUtil.unlock(lockKey);  
                }  
            } else {  
                throw new RuntimeException("数据不一致!请刷新页面重新编辑!");  
            }  
        }  
    } catch (DuplicateKeyException e) {  
        logger.error(Constants.Exception\_Head, e);  
        throw new RuntimeException("已经存在相同的配置.");  
    } catch (Exception e) {  
        logger.error(Constants.Exception\_Head, e);  
        throw new RuntimeException(ExceptionUtil.getStackTraceAsString(e));  
    }  
    return record;  
}

/\*\*  
 \* 获取缓存键值  
 \* @param id  
 \* @return  
 \*/  
protected String getCacheKey(Object id) {  
    String cacheName = getCacheKey();  
    return new StringBuilder(Constants.CACHE\_NAMESPACE).append(cacheName).append(":").append(id).toString();  
}

/\*\*  
 \* 获取缓存键值  
 \* @param id  
 \* @return  
 \*/  
protected String getLockKey(Object id) {  
    String cacheName = getCacheKey();  
    return new StringBuilder(Constants.CACHE\_NAMESPACE).append(cacheName).append(":LOCK:").append(id).toString();  
}

/\*\*  
 \* @param params  
 \* @param cls  
 \* @return  
 \*/  
protected <P> Page<P> query(Map<String, Object> params, Class<P> cls) {  
    Page<Long> page = getPage(params);  
    page.setRecords(mapper.selectIdPage(page, params));  
    return getPage(page, cls);  
}

/\*\*  
 \* @param millis  
 \*/  
protected void sleep(int millis) {  
    try {  
        Thread.sleep(RandomUtils.nextLong(10, millis));  
    } catch (InterruptedException e) {  
        logger.error("", e);  
    }  
}

/\*\*  
 \* @return  
 \*/  
private String getCacheKey() {  
    Class<?> cls = getClass();  
    String cacheName = Constants.cacheKeyMap.get(cls);  
    if (StringUtils.isBlank(cacheName)) {  
        CacheConfig cacheConfig = cls.getAnnotation(CacheConfig.class);  
        if (cacheConfig != null && ArrayUtils.isNotEmpty(cacheConfig.cacheNames())) {  
            cacheName = cacheConfig.cacheNames()\[0\];  
        } else {  
            cacheName = getClass().getName();  
        }  
        Constants.cacheKeyMap.put(cls, cacheName);  
    }  
    return cacheName;  
}

/\*\* 根据Id查询(默认类型T) \*/  
private Page<T> getPage(final Page<Long> ids) {  
    if (ids != null) {  
        Page<T> page = new Page<T>(ids.getCurrent(), ids.getSize());  
        page.setTotal(ids.getTotal());  
        final List<T> records = InstanceUtil.newArrayList();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            records.add(null);  
        }  
        final Map<Integer, Object> thread = InstanceUtil.newConcurrentHashMap();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            final int index = i;  
            executorService.execute(new Runnable() {  
                public void run() {  
                    try {  
                        records.set(index, queryById(ids.getRecords().get(index)));  
                    } finally {  
                        thread.put(index, 0);  
                    }  
                }  
            });  
        }  
        while (thread.size() < records.size()) {  
            try {  
                Thread.sleep(threadSleep);  
            } catch (InterruptedException e) {  
                logger.error("", e);  
            }  
        }  
        page.setRecords(records);  
        return page;  
    }  
    return new Page<T>();  
}

/\*\* 根据Id查询(cls返回类型Class) \*/  
private <K> Page<K> getPage(final Page<Long> ids, final Class<K> cls) {  
    if (ids != null) {  
        Page<K> page = new Page<K>(ids.getCurrent(), ids.getSize());  
        page.setTotal(ids.getTotal());  
        final List<K> records = InstanceUtil.newArrayList();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            records.add(null);  
        }  
        final Map<Integer, Object> thread = InstanceUtil.newConcurrentHashMap();  
        for (int i = 0; i < ids.getRecords().size(); i++) {  
            final int index = i;  
            executorService.execute(new Runnable() {  
                public void run() {  
                    try {  
                        T t = queryById(ids.getRecords().get(index));  
                        K k = InstanceUtil.to(t, cls);  
                        records.set(index, k);  
                    } finally {  
                        thread.put(index, 0);  
                    }  
                }  
            });  
        }  
        while (thread.size() < records.size()) {  
            try {  
                Thread.sleep(threadSleep);  
            } catch (InterruptedException e) {  
                logger.error("", e);  
            }  
        }  
        page.setRecords(records);  
        return page;  
    }  
    return new Page<K>();  
}

@SuppressWarnings("unchecked")  
private T queryById(Long id, int times) {  
    String key = getCacheKey(id);  
    T record = null;  
    try {  
        record = (T)CacheUtil.getCache().get(key);  
    } catch (Exception e) {  
        logger.error(Constants.Exception\_Head, e);  
    }  
    if (record == null) {  
        String lockKey = getLockKey(id);  
        if (CacheUtil.tryLock(lockKey)) {  
            try {  
                record = mapper.selectById(id);  
                try {  
                    CacheUtil.getCache().set(key, record);  
                } catch (Exception e) {  
                    logger.error(Constants.Exception\_Head, e);  
                }  
            } finally {  
                CacheUtil.unlock(lockKey);  
            }  
        } else {  
            if (times > 3) {  
                return mapper.selectById(id);  
            }  
            logger.debug(getClass().getSimpleName() + ":" + id + " retry queryById.");  
            sleep(20);  
            return queryById(id, times + 1);  
        }  
    }  
    return record;  
}  

}

BaseService

    技巧01:BaseService类实现了ApplicationContextAware后就可以通过ApplicationContext类型的成员变量去获取在spring容器中定义的其他bean了

protected ApplicationContext applicationContext;

      参考文档:点击前往

    技巧02:BaseService类提供了一些类的数据操作方法

  2.2 SysUserService类的query方法详解

    注意:仅仅解释如何获取数据,权限先关的暂时还未弄清楚,当更新

    

    2.2.1 调用父类的query方法

      技巧01:query方法是一个没有约束的查询方法,该方法的参数是和分页查询有关的,不涉及任何与条件查询相关的参数

/**
* @param params
* @return
*/
public Page query(Map params) {
Page page = getPage(params);
page.setRecords(mapper.selectIdPage(page, params));
return getPage(page);
}

      技巧02:从query方法的源代码中可以看出,query方法调用了BaseService类中的getPage方法

/\*\*  
 \* 分页查询  
 \* @param params  
 \* @return  
 \*/  
@SuppressWarnings("unchecked")  
public static Page<Long> getPage(Map<String, Object> params) {  
    Integer current = 1;  
    Integer size = 10;  
    String orderBy = "id\_", sortAsc = null;  
    if (DataUtil.isNotEmpty(params.get("pageNumber"))) {  
        current = Integer.valueOf(params.get("pageNumber").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("pageIndex"))) {  
        current = Integer.valueOf(params.get("pageIndex").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("pageSize"))) {  
        size = Integer.valueOf(params.get("pageSize").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("limit"))) {  
        size = Integer.valueOf(params.get("limit").toString());  
    }  
    if (DataUtil.isNotEmpty(params.get("offset"))) {  
        current = Integer.valueOf(params.get("offset").toString()) / size + 1;  
    }  
    if (DataUtil.isNotEmpty(params.get("sort"))) {  
        orderBy = (String)params.get("sort");  
        params.remove("sort");  
    }  
    if (DataUtil.isNotEmpty(params.get("orderBy"))) {  
        orderBy = (String)params.get("orderBy");  
        params.remove("orderBy");  
    }  
    if (DataUtil.isNotEmpty(params.get("sortAsc"))) {  
        sortAsc = (String)params.get("sortAsc");  
        params.remove("sortAsc");  
    }  
    Object filter = params.get("filter");  
    if (filter != null) {  
        params.clear();  
        params.putAll(JSON.parseObject(filter.toString(), Map.class));  
    }  
    if (size == -1) {  
        Page<Long> page = new Page<Long>();  
        page.setOrderByField(orderBy);  
        page.setAsc("Y".equals(sortAsc));  
        return page;  
    }  
    Page<Long> page = new Page<Long>(current, size, orderBy);  
    page.setAsc("Y".equals(sortAsc));  
    return page;  
}

getPage

      技巧03:getPage方法主要是查看query方法中的参数是否有和分页查询相关的参数,如果有就将这些参数封装成一个对象返回给query方法使用

      技巧04:mapper.selectIdPage(page, params)的作用是调用相应的mapper接口去获取数据

      技巧05:page.setRecords(mapper.selectIdPage(page, params));的作用是将获取到的数据封装到一个page对象中

      技巧06:getPage(page);的作用是对获取到的数据进一步进行封装,仅仅将需要查询的页码数据进行封装

    2.2.2 向web层返回一个Page对象

      技巧01:该Page对象封装了查询到的数据信息,以及一些分页查询参数

end

  3.1 所有的web层都会继承AbstractController

/**
*
*/
package top.ibase4j.core.base;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;

import com.baomidou.mybatisplus.plugins.Page;

/**
* 控制器基类
*
* @author ShenHuaJie
* @version 2016年5月20日 下午3:47:58
*/
public abstract class AbstractController extends BaseController {
protected final Logger logger = LogManager.getLogger(this.getClass());
@Autowired
protected T provider;

public abstract String getService();

public Object query(ModelMap modelMap, Map<String, Object> param) {  
    if (param.get("keyword") == null && param.get("search") != null) {  
        param.put("keyword", param.get("search"));  
    }  
    Parameter parameter = new Parameter(getService(), "query", param);  
    logger.info("{} execute query start...", parameter.getNo());  
    Page<?> list = provider.execute(parameter).getResultPage();  
    logger.info("{} execute query end.", parameter.getNo());  
    return setSuccessModelMap(modelMap, list);  
}

public Object queryList(ModelMap modelMap, Map<String, Object> param) {  
    Parameter parameter = new Parameter(getService(), "queryList", param);  
    logger.info("{} execute queryList start...", parameter.getNo());  
    List<?> list = provider.execute(parameter).getResultList();  
    logger.info("{} execute queryList end.", parameter.getNo());  
    return setSuccessModelMap(modelMap, list);  
}

public Object get(ModelMap modelMap, BaseModel param) {  
    Parameter parameter = new Parameter(getService(), "queryById", param.getId());  
    logger.info("{} execute queryById start...", parameter.getNo());  
    Object result = provider.execute(parameter).getResult();  
    logger.info("{} execute queryById end.", parameter.getNo());  
    return setSuccessModelMap(modelMap, result);  
}

public Object update(ModelMap modelMap, BaseModel param) {  
    Long userId = getCurrUser();  
    if (param.getId() == null) {  
        param.setCreateBy(userId);  
        param.setCreateTime(new Date());  
    }  
    param.setUpdateBy(userId);  
    param.setUpdateTime(new Date());  
    Parameter parameter = new Parameter(getService(), "update", param);  
    logger.info("{} execute update start...", parameter.getNo());  
    provider.execute(parameter);  
    logger.info("{} execute update end.", parameter.getNo());  
    return setSuccessModelMap(modelMap);  
}

public Object delete(ModelMap modelMap, BaseModel param) {  
    Parameter parameter = new Parameter(getService(), "delete", param.getId());  
    logger.info("{} execute delete start...", parameter.getNo());  
    provider.execute(parameter);  
    logger.info("{} execute delete end.", parameter.getNo());  
    return setSuccessModelMap(modelMap);  
}  

}

AbstractController

    技巧01:AbstractController中的BaseProvider对象通过excute方法去调用Service层相关方法,excute方法接收的是一个包含service名称、service中的方法名称、参数封装成的的Parameter对象;Page list = provider.execute(parameter).getResultPage()的作用是将从service层查询到的数据放到一个Page对象中;return setSuccessModelMap(modelMap, list)的作用是将数据进行封装并放回给前端

    技巧02:AbsstractController中的抽象方法getService是用来指定调用那个Service的,返回值是一个字符串;所有继承自AbsstractController的类都必须实现该方法,因为在调用Service层的时候回用到该方法,而且该方法在AbsstractController是一个抽象方法,所有的子类必须实现

  3.2 AbstractController还继承自BaseController接口

    该接口提供了最外层数据的封装方法

/**
*
*/
package top.ibase4j.core.base;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.plugins.Page;

import top.ibase4j.core.Constants;
import top.ibase4j.core.exception.BaseException;
import top.ibase4j.core.exception.IllegalParameterException;
import top.ibase4j.core.support.DateFormat;
import top.ibase4j.core.support.HttpCode;
import top.ibase4j.core.util.InstanceUtil;
import top.ibase4j.core.util.WebUtil;

/**
* 控制器基类
*
* @author ShenHuaJie
* @version 2016年5月20日 下午3:47:58
*/
public abstract class BaseController {
protected final Logger logger = LogManager.getLogger(this.getClass());

/\*\* 获取当前用户Id \*/  
protected Long getCurrUser() {  
    return WebUtil.getCurrentUser();  
}

@InitBinder  
protected void initBinder(WebDataBinder binder) {  
    binder.registerCustomEditor(Date.class, new CustomDateEditor(new DateFormat(), true));  
}

/\*\* 设置成功响应代码 \*/  
protected ResponseEntity<ModelMap> setSuccessModelMap(ModelMap modelMap) {  
    return setSuccessModelMap(modelMap, null);  
}

/\*\* 设置成功响应代码 \*/  
protected ResponseEntity<ModelMap> setSuccessModelMap(ModelMap modelMap, Object data) {  
    return setModelMap(modelMap, HttpCode.OK, data);  
}

/\*\* 设置响应代码 \*/  
protected ResponseEntity<ModelMap> setModelMap(ModelMap modelMap, HttpCode code) {  
    return setModelMap(modelMap, code, null);  
}

/\*\* 设置响应代码 \*/  
protected ResponseEntity<ModelMap> setModelMap(ModelMap modelMap, HttpCode code, Object data) {  
    Map<String, Object> map = InstanceUtil.newLinkedHashMap();  
    map.putAll(modelMap);  
    modelMap.clear();  
    for (Iterator<String> iterator = map.keySet().iterator(); iterator.hasNext();) {  
        String key = iterator.next();  
        if (!key.startsWith("org.springframework.validation.BindingResult") && !key.equals("void")) {  
            modelMap.put(key, map.get(key));  
        }  
    }  
    if (data != null) {  
        if (data instanceof Page) {  
            Page<?> page = (Page<?>)data;  
            modelMap.put("rows", page.getRecords());  
            modelMap.put("current", page.getCurrent());  
            modelMap.put("size", page.getSize());  
            modelMap.put("pages", page.getPages());  
            modelMap.put("total", page.getTotal());  
        } else if (data instanceof List<?>) {  
            modelMap.put("rows", data);  
            modelMap.put("total", ((List<?>)data).size());  
        } else {  
            modelMap.put("data", data);  
        }  
    }  
    modelMap.put("code", code.value().toString());  
    modelMap.put("msg", code.msg());  
    modelMap.put("timestamp", System.currentTimeMillis());  
    logger.info("RESPONSE : " + JSON.toJSONString(modelMap));  
    return ResponseEntity.ok(modelMap);  
}

/\*\* 异常处理 \*/  
@ExceptionHandler(Exception.class)  
public void exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception ex)  
    throws Exception {  
    logger.error(Constants.Exception\_Head, ex);  
    ModelMap modelMap = new ModelMap();  
    if (ex instanceof BaseException) {  
        ((BaseException)ex).handler(modelMap);  
    } else if (ex instanceof IllegalArgumentException) {  
        new IllegalParameterException(ex.getMessage()).handler(modelMap);  
    } else if (ex instanceof UnauthorizedException) {  
        modelMap.put("code", HttpCode.FORBIDDEN.value().toString());  
        modelMap.put("msg", StringUtils.defaultIfBlank(ex.getMessage(), HttpCode.FORBIDDEN.msg()));  
    } else {  
        modelMap.put("code", HttpCode.INTERNAL\_SERVER\_ERROR.value().toString());  
        String msg = StringUtils.defaultIfBlank(ex.getMessage(), HttpCode.INTERNAL\_SERVER\_ERROR.msg());  
        modelMap.put("msg", msg.length() > 100 ? "系统走神了,请稍候再试." : msg);  
    }  
    response.setContentType("application/json;charset=UTF-8");  
    modelMap.put("timestamp", System.currentTimeMillis());  
    logger.info("RESPONSE : " + JSON.toJSON(modelMap));  
    byte\[\] bytes = JSON.toJSONBytes(modelMap, SerializerFeature.DisableCircularReferenceDetect);  
    response.getOutputStream().write(bytes);  
}  

}

BaseController

end 

  4.1 READ

    4.1.1 在数据库中创建一个名为 test_user 表

      坑01:如果和数据库表对应的实体类继承了BaseModel类,那么在创建数据库表时就必须在数据表中添加和BaseModel中属性对应的字段,否则就会报错:XXX字段不存在

CREATE TABLE `NewTable` (
`id_` bigint(20) NOT NULL ,
`name` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`enable_` int(11) NOT NULL ,
`remark_` varchar(22) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`create_by` bigint(22) NULL DEFAULT NULL ,
`create_time` date NULL DEFAULT NULL ,
`update_by` bigint(20) NULL DEFAULT NULL ,
`update_time` date NULL DEFAULT NULL ,
`keyword` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`id_`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=COMPACT
;

    4.1.2 在facade层创建一个名为 Test.java 实体类

      技巧01:将每个实体类中公用的属性提取出来作为父类,在iBase4j中是将公用的属性提取出来放在了BaseModel中

      坑01:由于实体类继承了BaseModel,所以和实体类对应的数据库表必须有和BaseModel对应的字段,否则会报错:XXX字段不存在 

package org.ibase4j.model;

import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableName;

import top.ibase4j.core.base.BaseModel;

@TableName("test_user")
@SuppressWarnings("serial")
public class Test extends BaseModel {

@TableField("name")  
private String name;  
@TableField("phone")  
private String phone;

@TableField(exist = false)  
private String oldPassword;  
@TableField(exist = false)  
private String deptName;  
@TableField(exist = false)  
private String userTypeText;  
@TableField(exist = false)  
private String permission;

public String getOldPassword() {  
    return oldPassword;  
}  
public void setOldPassword(String oldPassword) {  
    this.oldPassword = oldPassword;  
}  
public String getDeptName() {  
    return deptName;  
}  
public void setDeptName(String deptName) {  
    this.deptName = deptName;  
}  
public String getUserTypeText() {  
    return userTypeText;  
}  
public void setUserTypeText(String userTypeText) {  
    this.userTypeText = userTypeText;  
}  
public String getPermission() {  
    return permission;  
}  
public void setPermission(String permission) {  
    this.permission = permission;  
}  
public String getName() {  
    return name;  
}  
public void setName(String name) {  
    this.name = name;  
}  
public String getPhone() {  
    return phone;  
}  
public void setPhone(String phone) {  
    this.phone = phone;  
}

}

Test.java

    4.1.3 在service层创建一个名为 TestService.java 服务类

      技巧01:在iBase4j中所有的服务类都继承了BaseService类,因为在BaseService类中基本的CRUD方法

      技巧02:在自定义的服务中定义一个查询方法,在这个查询方法中调用父类的query方法进行查询

      坑01:自定义服务类在继承BaseService服务类时需要制定泛型类型,这个泛型类型必须是facade中定义的实体类,即使是Object类型也会报错

package org.ibase4j.service;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.ibase4j.mapper.SysUserThirdpartyMapper;
import org.ibase4j.model.SysUser;
import org.ibase4j.model.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.plugins.Page;

import top.ibase4j.core.base.BaseService;

@Service
public class TestService extends BaseService {

@Autowired  
private SysUserThirdpartyMapper thirdpartyMapper;  
@Autowired  
private SysDicService sysDicService;  
@Autowired  
private SysDeptService sysDeptService;  
@Autowired  
private SysAuthorizeService sysAuthorizeService;

// public Page query(Map params) {
// System.out.println("测试服务层");
// Map userTypeMap = sysDicService.queryDicByType("USERTYPE");
// Page pageInfo = super.query(params);
// for (SysUser userBean : pageInfo.getRecords()) {
// if (userBean.getUserType() != null) {
// userBean.setUserTypeText(userTypeMap.get(userBean.getUserType()));
// }
// List permissions = sysAuthorizeService.queryUserPermission(userBean.getId());
// for (String permission : permissions) {
// if (StringUtils.isBlank(userBean.getPermission())) {
// userBean.setPermission(permission);
// } else {
// userBean.setPermission(userBean.getPermission() + ";" + permission);
// }
// }
// }
// return pageInfo;
// }

public Page<Test> query(Map<String, Object> params) {  

// Page pageInfo = new Page();
Page pageInfo = super.query(params);
return pageInfo;
}

}

TestService.java

    4.1.4 在service层中创建一个名为 TestMapper.java 接口

      这个接口就类似于springboot中的JPA接口,该接口和对应的XML文件配合来实现数据库的CRUD操作

      技巧01:自定义的DAO接口继承自BaseMapper接口,BaseMapper接口中定义了公用的分页查询

package org.ibase4j.mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;
import org.ibase4j.model.Test;

import top.ibase4j.core.base.BaseMapper;

public interface TestMapper extends BaseMapper {
List selectIdPage(@Param("cm") Map params);
}

TestMapper.java

    4.1.5 在service层中创建一个名为 TestMapper.xml 文件

      这个自定义的XML文件主要是和Mapper接口配合使用实现数据库的CRUD操作的

      详情请参见mybatis先关的技术文档



    4.1.6 在web层创建一个名为 TestController.java 控制类

      自定义的控制类必须继承AbstractController,因为在AbstractController类中封装了CRUD操作

      技巧01:继承AbstractController类后必须实现getService方法,该方法的返回值就是service层中对应的一个服务类的类名(PS:类名首字母小写后的结果)

      技巧02:在自定义的控制类中随便写一个方法,然后在该方法中调用的父类的query方法就可以实现数据查询操作了

package org.ibase4j.web;

import java.util.Map;

import org.ibase4j.provider.ISysProvider;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import top.ibase4j.core.base.AbstractController;

@RestController
@RequestMapping(value = "/test")
public class TestController extends AbstractController {
@Override
public String getService() {
// TODO Auto-generated method stub
return "testService";
}

@PutMapping(value = "/test01")  
public Object test01(ModelMap modelMap, @RequestBody Map<String, Object> param) {  
    System.out.println("测试控制层");  

// return "测试请求成功";
return super.query(modelMap, param);

}

}

TestController.java

    4.1.7 效果展示

      利用Postman或者Advanced REST client 模拟前端进行测试即可

      坑01:由于iBase4j后台默认使用的是分页查询,所以在请求中必须传入pageSize的值,例如:

        

      请求成功后的效果如下:

        

  4.2 UPDATE

    待更新……2018年3月21日09:21:09

  4.3 CREATE

    待更新……2018-3-21 09:21:21

  4.4 DELETE

    待更新……2018-3-21 09:21:29

end

  facade中主要编写的是实体类,每一个实体类都和数据库中表有着严格的对应关系;每个实体类类都继承自BaseModel,在BaseModel中定义了一些通用的属性,例如:id、enable、remark等等

  坑01:由于所有的实体类都继承自BaseModel类,所以在创建数据库时BaseModel中的属性必须有相应的字段与其对应,否则在启动service层时会报错:XXX字段不存在

end