iBase4J项目笔记
目录:
1 数据库密码加密
3 web层概述
4 后端CRUD
4.1 READ
4.2 UPDATE
4.3 CREATE
4.4 DELETE
1 数据库密码加密
iBase4J项目的service层中数据库配置文件中数据库的连接密码必须是经过加密过后的,如何获取加密方法
1.1 加密类是 org.ibase4j.core.util.PropertiesUtil
2 Service层
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<T extends BaseModel> implements ApplicationContextAware { protected Logger logger = LogManager.getLogger(getClass()); @Autowired protected BaseMapper<T> 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; } }
技巧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<T> query(Map<String, Object> params) { Page<Long> 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; }
技巧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对象封装了查询到的数据信息,以及一些分页查询参数
3 Web层
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<T extends BaseProvider> 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); } }
技巧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); } }
4 后端CRUD
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; } }
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<Test> { @Autowired private SysUserThirdpartyMapper thirdpartyMapper; @Autowired private SysDicService sysDicService; @Autowired private SysDeptService sysDeptService; @Autowired private SysAuthorizeService sysAuthorizeService; // public Page<SysUser> query(Map<String, Object> params) { // System.out.println("测试服务层"); // Map<String, String> userTypeMap = sysDicService.queryDicByType("USERTYPE"); // Page<SysUser> pageInfo = super.query(params); // for (SysUser userBean : pageInfo.getRecords()) { // if (userBean.getUserType() != null) { // userBean.setUserTypeText(userTypeMap.get(userBean.getUserType())); // } // List<String> 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<Test> pageInfo = new Page<Test>(); Page<Test> pageInfo = super.query(params); return pageInfo; } }
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<Test> { List<Long> selectIdPage(@Param("cm") Map<String, Object> params); }
4.1.5 在service层中创建一个名为 TestMapper.xml 文件
这个自定义的XML文件主要是和Mapper接口配合使用实现数据库的CRUD操作的
详情请参见mybatis先关的技术文档
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.ibase4j.mapper.TestMapper"> <!-- 查询列表--> <select id="selectIdPage" resultType="java.lang.Long"> SELECT id_ FROM test_user ORDER BY id_ DESC </select> </mapper>
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<ISysProvider> { @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); } }
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
5 facade层概述
facade中主要编写的是实体类,每一个实体类都和数据库中表有着严格的对应关系;每个实体类类都继承自BaseModel,在BaseModel中定义了一些通用的属性,例如:id、enable、remark等等
坑01:由于所有的实体类都继承自BaseModel类,所以在创建数据库时BaseModel中的属性必须有相应的字段与其对应,否则在启动service层时会报错:XXX字段不存在