Jeebase是GitHub上一个比较棒的工程,里面许多东西值得我去学习,这只是其中我很想借鉴的几个点。
- 可以借鉴的工程结构:
- BaseDao.java
public interface BaseDao<T> {
/***
* 获取单条数据
* @param id
* @return 实体对象
*/
T get(String id);
/***
* 获取单条数据
* @param entity 实体对象
* @return 实体对象
*/
T get(T entity);
/***
* 查询数据列表,如果需要分页,请设置分页对象,如:entity.setPage(new Page<T>());
* @param entity 实体对象
* @return 实体对象列表
*/
List<T> getList(T entity);
/***
* 插入数据
* @param entity 要插入的实体对象
* @return
*/
int insert(T entity);
/***
* 更新数据
* @param entity 要更新的实体对象
* @return
*/
int update(T entity);
/***
* 删除数据(一般为逻辑删除,更新del_flag字段为1)[并不是真的删除]
* @param entity 要删除的实体
* @return
*/
int delete(T entity);
}
借鉴:
- 使用泛型建立一个基础Interface BaseDao。里面有基本的增删改查方法:其中查询有三种,按主键查询,按条件查询(T entity),按条件查询列表(查询数据列表,如果需要分页,请设置分页对象,如:entity.setPage(new Page());)
- 删除数据(一般为逻辑删除,更新del_flag字段为1)[并不是真的删除]
BaseService.java
package cn.support.base;
/**
* Created by Ww on 2017/10/12.
*/
import cn.support.web.Page;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Service 基础接口
*/
@Transactional(readOnly = true)
public abstract class BaseService<D extends BaseDao<T>, T extends BaseModel<T>> {
/***
* 持久层对象
*/
@Autowired
protected D dao;
/***
* 获取单条数据
* @param id 主键
* @return
*/
public T get(String id) {
return dao.get(id);
}
/***
*
* @param entity
* @return
*/
public T get(T entity) {
return dao.get(entity);
}
/**
* 查询列表数据
* @param entity 实体对象
* @return 查询出的数据列表
*/
public List<T> getList(T entity) {
return dao.getList(entity);
}
/***
* 查询分页数据
* @param page 分页对象
* @param entity 实体对象
* @return 分页对象(包含查询出的数据列表)
*/
public Page<T> getPage(Page<T> page, T entity) {
entity.setPage(page);
page.setList(dao.getList(entity));
return page;
}
/***
* 保存数据(插入或更新)
* @param entity 要保存或更新的实体
*/
@Transactional(readOnly = false)
public void save(T entity) {
if (StringUtils.isEmpty(entity.getId())) {
entity.preInsert();
dao.insert(entity);
} else {
entity.preUpdate();
dao.update(entity);
}
}
@Transactional(readOnly = false)
public void delete(T entity) {
dao.delete(entity);
}
}
借鉴:
- 事物设成只读(@Transactional(readOnly = true))
- 设置两个泛型(public abstract class BaseService
package cn.support.base;
import cn.support.web.Page;
import java.io.Serializable;
import java.sql.Time;
import java.util.Date;
import java.util.UUID;
/**
* Created by Ww on 2017/10/12.
*/
public abstract class BaseModel<T> implements Serializable {
protected String id;//实体编号
// protected User createBy;//创建者
protected Date createTime; // 创建日期
// protected User updateBy;//更新者
protected Date updateTime; // 更新日期
protected String remarks; // 备注
protected String delStatus; // 删除标记(0:正常;1:删除;2:审核)
public static final String NORMAL = "0";//正常数据
public static final String DELETE = "1";//已删除数据
public static final String AUDIT = "2";//待审核数据
/***
* 当前实体分页对象
*/
protected Page<T> page;
public BaseModel() {
this.delStatus = NORMAL;
}
public BaseModel(String id) {
this.id = id;
this.delStatus = NORMAL;
}
/***
* 插入之前执行此方法
*/
public void preInsert() {
this.setId(UUID.randomUUID().toString().replaceAll("-",""));
this.createTime = new Date();
this.updateTime = createTime;
// User user = ShiroUtils.getCurrentUser();
// if(user != null){
// this.createBy = new User(user.getId());
// this.updateBy = new User(user.getId());
// }else {
// this.createBy = new User("0");
// this.updateBy = new User("0");
// }
};
/***
* 更新前执行此方法
*/
public void preUpdate() {
this.updateTime = new Date();
// User user = ShiroUtils.getCurrentUser();
// if(user != null){
// this.updateBy = new User(user.getId());
// }else {
// this.updateBy = new User("0");
// }
};
public Page<T> getPage() {
return page;
}
public void setPage(Page<T> page) {
this.page = page;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getRemarks() {
return remarks;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
public String getDelStatus() {
return delStatus;
}
public void setDelStatus(String delStatus) {
this.delStatus = delStatus;
}
}
借鉴:
- 都有实体编号,创建者,更新者等。
- 以前UUID都是一句一句的写,现在放到BaseModel中只需要在插入前执行一下preInsert()就可以了。更新同理。
Page.java
package cn.support.web;
import com.doubleview.jeebase.support.config.Constant;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* 分页支持类
*/
public class Page<T> {
private static String pageNoParam = "pageNo";//当前页面请求参数
private static String pageSizeParam = "pageSize";//当前页面大小请求参数
private static String orderByParam = "orderByParam";//当前页面排序请求参数
private int pageNo = 1; // 当前页码
private int pageSize = Integer.valueOf(Constant.getConfig("page.pageSize")); // 页面大小
private long totalSize;// 总记录数
private int first;// 首页索引
private int last;// 尾页索引
private boolean firstPage;//是否是第一页
private boolean lastPage;//是否是最后一页
private List<T> list = new ArrayList();
private String orderBy = ""; // 标准查询有效
/**
* 默认构造器
*/
public Page() {
this(1 , Integer.valueOf(Constant.getConfig("page.pageSize")));
}
/**
*分页构造函数 ,默认第一页
* @param request
*/
public Page(HttpServletRequest request){
this(request,Integer.valueOf(Constant.getConfig("page.pageSize")));
}
/**
* 分页构造函数
* @param request
* @param defaultPageSize
*/
public Page(HttpServletRequest request, int defaultPageSize){
String pageNo = request.getParameter(pageNoParam);
String pageSize = request.getParameter(pageSizeParam);
String orderBy = request.getParameter(orderByParam);
this.pageNo = StringUtils.isNotBlank(pageNo) ? Integer.parseInt(pageNo) : 1;
this.pageSize = StringUtils.isNotBlank(pageSize) ? Integer.parseInt(pageSize): defaultPageSize;
this.orderBy = orderBy;
}
/**
* 构造方法
* @param pageNo 当前页码
* @param pageSize 分页大小
*/
public Page(int pageNo, int pageSize) {
this(pageNo, pageSize, 0);
}
/**
* 构造方法
* @param pageNo 当前页码
* @param pageSize 分页大小
* @param totalSize 数据条数
*/
public Page(int pageNo, int pageSize, long totalSize) {
this.pageNo = pageNo;
this.pageSize = pageSize;
this.totalSize = totalSize;
}
/**
* 初始化参数
*/
public void initialize(){
//设置首页和尾页
this.first = 1;
this.last = (int)(totalSize / (this.pageSize < 1 ? 20 : this.pageSize));
if (this.totalSize % this.pageSize != 0 || this.last == 0) {
this.last++;
}
if (this.last < this.first) {
this.last = this.first;
}
//设置当前页
if (this.pageNo <= 1) {
this.pageNo = this.first;
this.firstPage=true;
}
if (this.pageNo >= this.last) {
this.pageNo = this.last;
this.lastPage=true;
}
}
/**
* 默认输出当前分页标签
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("<ul class=\"pagination\">");
sb.append("<li class=\"page-first \"><a href=\"javascript:void(0)\" data-pageNo=\""+this.getFirst()+"\">«</a></li>");
sb.append("<li class=\"page-pre \"><a href=\"javascript:void(0)\" data-pageNo=\""+this.getPrev()+"\">‹</a></li>");
int pageNo = this.getPageNo();
if(pageNo <=3){
for(int i = 1; i< pageNo ;i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\""+i+"\">"+i+"</a></li>");
}
sb.append("<li class=\"page-number active\"><a href=\"javascript:void(0)\" data-pageNo=\"" + pageNo + "\">"+pageNo+"</a></li>");
int lastPage = this.getTotalPage() > 5 ? 5: this.getTotalPage();
for(int i = pageNo + 1; i <= lastPage;i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\"" + i + "\">"+i+"</a></li>");
}
}else if(this.getTotalPage() - pageNo <= 2){
int firstPage = this.getTotalPage() - 4;
for(int i = firstPage; i< pageNo ; i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\"" + i + "\">"+i+"</a></li>");
}
sb.append("<li class=\"page-number active\"><a href=\"javascript:void(0)\" data-pageNo=\"" + pageNo+ "\">"+pageNo+"</a></li>");
for(int i = pageNo + 1; i <= this.getTotalPage();i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\"" + i + "\">"+i+"</a></li>");
}
}else {
int firstPage = this.getPageNo() - 2;
for(int i = firstPage; i < pageNo;i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\"" + i + "\">"+i+"</a></li>");
}
sb.append("<li class=\"page-number active\"><a href=\"javascript:void(0)\" data-pageNo=\"" + pageNo + "\">"+pageNo+"</a></li>");
for(int i = pageNo + 1; i < pageNo + 3 ; i++){
sb.append("<li class=\"page-number\"><a href=\"javascript:void(0)\" data-pageNo=\"" + i + "\">"+i+"</a></li>");
}
}
sb.append(" <li class=\"page-next\"><a href=\"javascript:void(0)\" data-pageNo=\"" + this.getNext()+ "\">›</a></li>");
sb.append("<li class=\"page-last\"><a href=\"javascript:void(0)\" data-pageNo=\"" + this.getLast() + "\">»</a></li>");
sb.append(String.format("<li class=\"pagination-info\"><a>当前%s到%s条,共%s条</a></li></ul>" ,this.getFirstResult() + 1, this.getLastResult() , this.getTotalSize()));
return sb.toString();
}
/**
* 获取分页HTML代码
* @return
*/
public String getHtml(){
return toString();
}
/**
* 获取设置总数
* @return
*/
public long getTotalSize(){
return totalSize;
}
/**
* 设置数据总数
* @param totalSize
*/
public void setTotalSize(long totalSize) {
this.totalSize = totalSize;
if (pageSize >= totalSize){
pageNo = 1;
}
}
/**
* 获取当前页码
* @return
*/
public int getPageNo() {
return pageNo;
}
/**
* 设置当前页码
* @param pageNo
*/
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
/**
* 获取页面大小
* @return
*/
public int getPageSize() {
return pageSize;
}
/**
* 设置页面大小,最大为100条
* @param pageSize
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize <= 0 ? 10 : pageSize > 100 ? 100 : pageSize;
}
/**
* 首页索引
* @return
*/
public int getFirst() {
return first;
}
/**
* 尾页索引
* @return
*/
public int getLast() {
return last;
}
/**
* 获取页面总数
* @return getLast();
*/
public int getTotalPage() {
return getLast();
}
/**
* 是否为第一页
* @return
*/
public boolean isFirstPage() {
return firstPage;
}
/**
* 是否为最后一页
* @return
*/
public boolean isLastPage() {
return lastPage;
}
/**
* 上一页索引值
* @return
*/
public int getPrev() {
if (isFirstPage()) {
return pageNo;
} else {
return pageNo - 1;
}
}
/**
* 下一页索引值
* @return
*/
public int getNext() {
if (isLastPage()) {
return pageNo;
} else {
return pageNo + 1;
}
}
/**
* 得到起始条数
* @return
*/
public int getFirstResult(){
int firstResult = (getPageNo() - 1) * getPageSize();
if (firstResult >= getTotalSize()) {
firstResult = 0;
}
return firstResult;
}
/**
* 得到结尾条数
* @return
*/
public int getLastResult(){
int lastResult = getFirstResult() + getPageSize() -1;
if(lastResult > getTotalSize()){
return Long.valueOf(getTotalSize()).intValue();
}
return lastResult;
}
/**
* 获取本页数据对象列表
* @return List<T>
*/
public List<T> getList() {
return list;
}
/**
* 设置本页数据对象列表
* @param list
*/
public Page<T> setList(List<T> list) {
this.list = list;
initialize();
return this;
}
/**
* 获取查询排序字符串
* @return
*/
public String getOrderBy() {
// SQL过滤,防止注入
String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"
+ "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
if (sqlPattern.matcher(orderBy).find()) {
return "";
}
return orderBy;
}
/**
* 设置查询排序,标准查询有效
*/
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
}
- 借鉴:
- Constant.getConfig(“page.pageSize”);这样都从配置文件里读取。
- 通过泛型,Page里有一个List可以存放对应类型变量的类的List。
- BaseModel中也有一个Page,使用来分页的。
- Constant.java——扩大可配置性。
package com.doubleview.jeebase.support.config;
import com.google.common.collect.Maps;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
/**
* 全局常量类
*/
public class Constant {
private static Logger logger = LoggerFactory.getLogger(Constant.class);
private static Properties props;
private static String defaultLoadProperties = "jeebase.properties";//默认加载配置文件
/**
* 静态加载配置文件
*/
static{
props = new Properties();
InputStream is = null;
try {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(defaultLoadProperties);
props.load(is);
} catch (IOException ex) {
logger.warn("Could not load jeebase.properties {}" , ex.getMessage());
} finally {
IOUtils.closeQuietly(is);
}
}
/**
* 保存全局属性值(缓存)
*/
private static Map<String, String> map = Maps.newHashMap();
/**
* 显示/隐藏
*/
public static final String SHOW = "1";
public static final String HIDE = "0";
/**
* 是/否
*/
public static final String YES = "1";
public static final String NO = "0";
/**
* 对/错
*/
public static final String TRUE = "true";
public static final String FALSE = "false";
/**
* 树形结构跟级id
*/
public static final String rootId = "0";
public static final String defaultCharset = "UTF-8";//默认编码
/**
* 获取配置属性
* @param key
* @return
*/
public static String getConfig(String key) {
String value = map.get(key);
if (value == null){
value = props.getProperty(key);
map.put(key, value != null ? value : StringUtils.EMPTY);
}
return value;
}
/**
* 获取管理端路径
* @return
*/
public static String getAdminPath() {
return getConfig("adminPath");
}
/**
* 获取前端路径
* @return
*/
public static String getFrontPath() {
return getConfig("frontPath");
}
/**
* 获取静态资源路径
* @return
*/
public static String getStaticPath(){
return getConfig("staticPath");
}
/**
* 获取产品名称
* @return
*/
public static String getProductName(){
return getConfig("productName");
}
/**
* 获取URL后缀
* @return
*/
public static String getUrlSuffix() {
return getConfig("urlSuffix");
}
public static Integer getInt(String key) {
return getInt(key, null);
}
public static Integer getInt(String key, Integer defaultValue) {
String value = getConfig(key);
if (value != null)
return Integer.parseInt(value.trim());
return defaultValue;
}
public static Long getLong(String key) {
return getLong(key, null);
}
public static Long getLong(String key, Long defaultValue) {
String value = getConfig(key);
if (value != null)
return Long.parseLong(value.trim());
return defaultValue;
}
public static Boolean getBoolean(String key) {
return getBoolean(key, null);
}
public static Boolean getBoolean(String key, Boolean defaultValue) {
String value = getConfig(key);
if (value != null) {
value = value.toLowerCase().trim();
if ("true".equals(value))
return true;
else if ("false".equals(value))
return false;
throw new RuntimeException("The value can not parse to Boolean : "
+ value);
}
return defaultValue;
}
}
借鉴:
- IOUtils.closeQuietly(is);的安静关闭(忽略null和异常)流。
- Maps.newHashMap();来自com.google.common.collect包。
- private static Map< String, String> map = Maps.newHashMap();缓存导入的key-value。
如下代码片:
public static String getConfig(String key) { String value = map.get(key); if (value == null){ value = props.getProperty(key); map.put(key, value != null ? value : StringUtils.EMPTY); } return value; }
实现了缓存的效果。
- 还有就是一些常用的key有专门的方法。