此項目地址已在碼云上咖刃,地址:https://gitee.com/youxiaxiaomage/jfl-platform-parent
此項目主要使用了Druid
泳炉,MyBatis-Plus
,redis
嚎杨,dubbo
花鹅,shiro
,SpringMVC
枫浙,thymeleaf
刨肃,layUI
,Bootstrap
后臺管理系統(tǒng)箩帚,以及相應的restful
接口真友。
1.基類實體類(BaseModel)
@Data
public abstract class BaseModel implements Serializable
{
/**
* id
*/
@JsonSerialize(using=ToStringSerializer.class)
@TableId(value = "id", type = IdType.ID_WORKER)
private Long id;
/**
* 狀態(tài)
*/
@TableField("enable")
public Integer enable;
/**
* 備注
*/
@TableField("remark")
private String remark;
/**
* 創(chuàng)建人
*/
@TableField("create_by")
private Long createBy;
/**
* 創(chuàng)建時間
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
@TableField("create_time")
private Date createTime;
/**
* 更新時間
*/
@TableField("update_by")
private Long updateBy;
/**
* 更新時間
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
@TableField("update_time")
private Date updateTime;
/** 請求參數(shù) */
@TableField(exist=false)
private Map<String, Object> params;
}
此基類實體類主要是基于Mybatis-Plus
插件,表名定義紧帕,字段定義都使用了該方式盔然。其中,主鍵id
使用長整型是嗜,其長度為20位愈案,頁面展示時,精度會丟失鹅搪,因此該字段序列化為字符串返回站绪。
這些字段都是在定義表時,必須包含的字段丽柿,其中請求參數(shù)params
用于接收前端的參數(shù)恢准,非數(shù)據(jù)庫字段。
2.基類Mapper(BaseMapper)
public interface BaseMapper<T extends BaseModel> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T>
{
List<Long> selectIdPage(@Param("cm") T paramT);
List<Long> selectIdPage(@Param("cm") Map<String, Object> paramMap);
List<Long> selectIdPage(RowBounds paramRowBounds, @Param("cm") Map<String, Object> paramMap);
List<Long> selectIdPage(RowBounds paramRowBounds, @Param("cm") T paramT);
List<T> selectPage(RowBounds paramRowBounds, @Param("cm") Map<String, Object> paramMap);
Integer selectCount(@Param("cm") Map<String, Object> paramMap);
}
分頁重寫了mybatisplus
的BaseMapper
甫题,其中列出的方法需要在***Mapper.xml
中實現(xiàn)顷歌,具體參見對應的xml文件。
3.基類Service(BaseService)
public interface BaseService<T extends BaseModel> extends IService<T>
{
/**
* 修改
* @param record
* @param userId
* @return
* @throws BusinessException
* @throws ValidateException
* @see [類幔睬、類#方法眯漩、類#成員]
*/
@Transactional
T update(T record) throws BusinessException, ValidateException;
/**
* 邏輯刪除
* @param ids 刪除的id
* @param userId 用戶id
* @throws BusinessException
* @throws ValidateException
* @see [類、類#方法麻顶、類#成員]
*/
@Transactional
void del(List<Long> ids, Long userId) throws BusinessException, ValidateException;
/**
* 邏輯刪除單條
* @param id
* @param userId
* @throws BusinessException
* @throws ValidateException
* @see [類赦抖、類#方法、類#成員]
*/
@Transactional
void del(Long id, Long userId) throws BusinessException, ValidateException;
/**
* 物理刪除
* @param id
* @throws BusinessException
* @throws ValidateException
* @see [類辅肾、類#方法队萤、類#成員]
*/
@Transactional
void delete(Long id) throws BusinessException, ValidateException;
/**
* 物理刪除
* @param entity
* @return
* @throws BusinessException
* @throws ValidateException
* @see [類、類#方法矫钓、類#成員]
*/
@Transactional
Integer deleteByEntity(T entity) throws BusinessException, ValidateException;
/**
* 物理刪除
* @param columnMap
* @return
* @throws BusinessException
* @throws ValidateException
* @see [類要尔、類#方法舍杜、類#成員]
*/
@Transactional
Integer deleteByMap(Map<String, Object> columnMap) throws BusinessException, ValidateException;
...
}
此類中部分方法未列舉。
4.基類Service實現(xiàn)類(BaseServiceImpl)
public class BaseServiceImpl<T extends BaseModel, M extends BaseMapper<T>> extends ServiceImpl<BaseMapper<T>, T> implements BaseService<T>
{
/**
* logger 日志
*/
protected Logger logger = LoggerFactory.getLogger(getClass());
/**
* mapper
*/
@Autowired
protected M mapper;
@Transactional
@Override
public T update(T record) throws BusinessException, ValidateException
{
if (record.getId() != null)
{
record.setUpdateTime(new Date());
this.mapper.updateById(record);
}
else
{
record.setCreateTime(new Date());
record.setUpdateTime(new Date());
record.setUpdateBy(record.getCreateBy());
this.mapper.insert(record);
}
return this.mapper.selectById(record.getId());
}
/**
* 邏輯刪除
* @param ids
* @param userId
* @throws BusinessException
* @throws ValidateException
* @see com.jfl.base.BaseService#del(java.util.List, java.lang.Long)
*/
@Override
@Transactional
public void del(List<Long> ids, Long userId) throws BusinessException, ValidateException
{
// lamda表達式 JDK1.8才支持
ids.forEach(id -> del(id, userId));
}
/**
* 邏輯刪除
* @param id
* @param userId
* @throws BusinessException
* @throws ValidateException
* @see com.jfl.base.BaseService#del(java.lang.Long, java.lang.Long)
*/
@Override
@Transactional
public void del(Long id, Long userId) throws BusinessException, ValidateException
{
try
{
T record = this.queryById(id);
record.setEnable(0);
record.setUpdateBy(userId);
record.setUpdateTime(new Date());
this.mapper.updateById(record);
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* 物理刪除
* @param id
* @throws BusinessException
* @throws ValidateException
* @see com.jfl.base.BaseService#delete(java.lang.Long)
*/
@Override
@Transactional
public void delete(Long id) throws BusinessException, ValidateException
{
try
{
this.mapper.deleteById(id);
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* 物理刪除
* @param entity
* @return
* @throws BusinessException
* @throws ValidateException
* @see com.jfl.base.BaseService#deleteByEntity(com.jfl.base.BaseModel)
*/
@Override
@Transactional
public Integer deleteByEntity(T entity) throws BusinessException, ValidateException
{
Wrapper<T> wrapper = new UpdateWrapper<T>(entity);
return this.mapper.delete(wrapper);
}
/**
* 物理刪除
* @param columnMap
* @return
* @throws BusinessException
* @throws ValidateException
* @see com.jfl.base.BaseService#deleteByMap(java.util.Map)
*/
@Override
@Transactional
public Integer deleteByMap(Map<String, Object> columnMap) throws BusinessException, ValidateException
{
return this.mapper.deleteByMap(columnMap);
}
/**
* 根據(jù)Id查詢
* @param id
* @return
* @see com.jfl.base.BaseService#queryById(java.lang.Long)
*/
@Override
public T queryById(Long id)
{
return this.mapper.selectById(id);
}
/**
* 分頁查詢
* @param params 其中params必須為數(shù)據(jù)庫中字段
* @return
* @see com.jfl.base.BaseService#query(java.util.Map)
*/
@Override
public PageInfo<T> query(Map<String, Object> params)
{
// 默認當前頁為1
int pageNum = 1;
// 默認頁碼大小為10
int pageSize = 10;
// 默認計算count
String orderBy = null;
if(params.get("pageNum") != null && StringUtils.isNotBlank(params.get("pageNum") + ""))
{
pageNum = Integer.valueOf(params.get("pageNum").toString());
params.remove("pageNum");
}
if(params.get("pageSize") != null && StringUtils.isNotBlank(params.get("pageSize") + ""))
{
pageSize = Integer.valueOf(params.get("pageSize").toString());
params.remove("pageSize");
}
if(params.get("orderBy")!= null && StringUtils.isNotBlank(params.get("orderBy") + ""))
{
orderBy = params.get("orderBy").toString();
params.remove("orderBy");
}
// 設置分頁的參數(shù)
PageHelper.startPage(pageNum, pageSize, orderBy);
// 有效數(shù)據(jù)
params.put("enable", 1);
// 根據(jù)條件查詢
List<T> list = this.mapper.selectByMap(params);
// 分裝成分頁對象
return new PageInfo<T>(list);
}
/**
* 根據(jù)實體參數(shù)分頁查詢
* @param entity
* @param rowBounds
* @return
* @see com.jfl.base.BaseService#query(com.jfl.base.BaseModel, com.github.pagehelper.PageInfo)
*/
@Override
public PageInfo<T> query(T entity, PageInfo<T> rowBounds)
{
Page<T> page = new Page<T>();
try
{
BeanUtils.copyProperties(page, rowBounds);
}
catch (Exception e)
{
logger.error(ExceptionUtil.getStackTraceAsString(e));
}
// List<Long> ids = this.mapper.selectIdPage(page,entity);
return new PageInfo<T>(null);
}
/**
* 根據(jù)參數(shù)查詢
* @param params
* @return
* @see com.jfl.base.BaseService#queryList(java.util.Map)
*/
@Override
public List<T> queryList(Map<String, Object> params)
{
// 根據(jù)參數(shù)獲取全部數(shù)據(jù)的Id 從DB中查詢
List<Long> ids = this.mapper.selectIdPage(params);
List<T> list = queryList(ids);
return list;
}
/**
* 根據(jù)Id查詢 如果緩存中有則從緩存中獲取赵辕,否則從DB中獲取
* @param ids
* @return
* @see com.jfl.base.BaseService#queryList(java.util.List)
*/
@Override
public List<T> queryList(List<Long> ids)
{
final List<T> list = Lists.newArrayList();
if (ids != null)
{
// lamda表達式
ids.forEach(id -> list.add(queryById(id)));
}
return list;
}
@Override
public <K> List<K> queryList(List<Long> ids, Class<K> clazz)
{
final List<K> list = Lists.newArrayList();
if(ids != null)
{
for (int i = 0; i < ids.size(); i++)
{
T t = queryById(ids.get(i));
K k = InstanceUtil.to(t, clazz);
list.set(i, k);
}
}
return list;
}
/**
* 根據(jù)實體參數(shù)查詢
* @param entity
* @return
* @see com.jfl.base.BaseService#queryList(com.jfl.base.BaseModel)
*/
@Override
public List<T> queryList(T entity)
{
// 先查出所有有關的id
List<Long> ids = this.mapper.selectIdPage(entity);
// 緩存中有則從緩存中取值既绩,否則從數(shù)據(jù)庫取值
List<T> list = queryList(ids);
return list;
}
/**
* 從數(shù)據(jù)庫中查詢
* @param params
* @return
* @see com.jfl.base.BaseService#queryFromDB(java.util.Map)
*/
@Override
public PageInfo<T> queryFromDB(Map<String, Object> params)
{
return null;
}
@Override
public PageInfo<T> queryFromDB(T entity, PageInfo<T> rowBounds)
{
return null;
}
/**
* 從數(shù)據(jù)庫中查詢
* @param params 表字段
* @return
* @see com.jfl.base.BaseService#queryListFromDB(java.util.Map)
*/
@Override
public List<T> queryListFromDB(Map<String, Object> params)
{
return this.mapper.selectByMap(params);
}
@Override
public PageInfo<T> selectList(PageRequest request, T record)
{
PageHelper.startPage(request.getPageNum(), request.getPageSize(), request.getOrderBy());
QueryWrapper<T> wrapper = new QueryWrapper<T>();
if (record != null)
{
wrapper = tranform(record);
if(record.getParams() != null)
{
if(StringUtils.isNotBlank(record.getParams().get("beginTime") + "") && StringUtils.isNotBlank(record.getParams().get("endTime") + ""))
{
wrapper.between("create_time", record.getParams().get("beginTime") , record.getParams().get("endTime"));
}
}
}
wrapper.eq("enable", 1);
List<T> list = this.mapper.selectList(wrapper);
return new PageInfo<T>(list);
}
/**
* 轉(zhuǎn)換查詢
* @param record
* @return
* @see [類、類#方法还惠、類#成員]
*/
private QueryWrapper<T> tranform(T record)
{
QueryWrapper<T> wrapper = new QueryWrapper<T>();
Field[] fields = record.getClass().getDeclaredFields();
try
{
for (Field field : fields)
{
field.setAccessible(true);
String fieldName = field.getName();
String clazz = field.getType().getTypeName();
Method method = record.getClass().getDeclaredMethod("get"+ fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
Object obj = method.invoke(record);
if(obj != null && StringUtils.isNotBlank(obj + ""))
{
if ("java.lang.String".equals(clazz))
{
if("status".equals(fieldName))
{
wrapper.eq(ConvertUtil.underLine2Camel(fieldName), obj);
}
else
{
wrapper.like(ConvertUtil.underLine2Camel(fieldName), obj);
}
}
else if ("java.lang.Integer".equals(clazz) || "java.lang.Short".equals(clazz) || "java.lang.Long".equals(clazz))
{
wrapper.eq(ConvertUtil.underLine2Camel(fieldName), obj);
}
}
}
}
catch (Exception e)
{
logger.error("轉(zhuǎn)換異常", e);
}
return wrapper;
}
/**
* 唯一性統(tǒng)一返回
* @param record 參數(shù)對象
* @param id 數(shù)據(jù)庫中數(shù)據(jù)Id
* @return "0":存在 "1":唯一
*/
public String result(T record, Long id)
{
if(record != null && record.getId().longValue() != id.longValue())
{
return Constants.DATA_NOT_UNIQUE;
}
return Constants.DATA_UNIQUE;
}
}
主要注意分頁動態(tài)sql的拼接問題饲握,比如精確查詢,模糊查詢等蚕键,這個也可以轉(zhuǎn)化為動態(tài)***Mapper.xml
文件救欧。
5.控制器
@Controller
@RequestMapping("${jfl.module.system}/user")
public class SysUserController extends AbstractController
{
/**
* dubbo接口 @Reference 通過配置文件連接服務
*/
@Reference(version = "${jfl.version}")
private SysUserService sysUserService;
@Reference(version = "${jfl.version}")
private SysDeptService sysDeptService;
@Reference(version = "${jfl.version}")
private SysRoleService sysRoleService;
@Reference(version = "${jfl.version}")
private SysPostService sysPostService;
/**
* 分隔符
*/
private static final String SEG_CHAR = ",";
/**
* 用戶管理界面
*
* @param modelMap
* @return
*/
@RequiresPermissions("system:user:view")
@GetMapping
public String user(ModelMap modelMap)
{
modelMap.put("user", ShiroUtils.getCurrentUser());
return Constants.MODULE_SYS_USER_PREFIX + "user";
}
/**
* 跳轉(zhuǎn)用戶添加頁面
*
* @param modelMap
* @return
*/
@GetMapping("/add")
public String add(ModelMap modelMap)
{
modelMap.put("roles", this.sysRoleService.queryList(Maps.newHashMap()));
modelMap.put("posts", this.sysPostService.queryList(Maps.newHashMap()));
return Constants.MODULE_SYS_USER_PREFIX + "add";
}
/**
* 添加用戶
*
* @param user
* @return
*/
@Log(module = Module.ROLE, value = "添加用戶", type = LogType.INSERT)
@RequiresPermissions("system:user:add")
@PostMapping("/add")
@ResponseBody
public ResponseEntity<ModelMap> addSave(SysUser user)
{
user.setSalt(EncryptUtils.randomSalt());
user.setPassword(EncryptUtils.encryptPassword(user.getUserName(), user.getPassword(), user.getSalt()));
user.setCreateBy(ShiroUtils.getCurrentUserId());
this.sysUserService.saveUser(user);
return setSuccessModelMap();
}
/**
* 分頁查詢
*
* @param sysUser
* @return
* @see [類、類#方法锣光、類#成員]
*/
@RequiresPermissions("system:user:list")
@PostMapping("/list")
@ResponseBody
public ResponseEntity<ModelMap> list(SysUser sysUser)
{
PageInfo<SysUser> pageInfo = this.sysUserService.selectList(ConvertRequestUtil.pageRequest(), sysUser);
return setSuccessModelMap(pageInfo);
}
/**
* 跳轉(zhuǎn)用戶編輯頁面
*
* @param userId
* @param modelMap
* @return
*/
@GetMapping("/edit/{userId}")
public String edit(@PathVariable("userId") Long userId, ModelMap modelMap)
{
modelMap.put("user", this.sysUserService.queryById(userId));
modelMap.put("roles", this.sysRoleService.selectRolesByUserId(userId));
modelMap.put("posts", this.sysPostService.selectPostsByUserId(userId));
return Constants.MODULE_SYS_USER_PREFIX + "edit";
}
/**
* 修改保存用戶
*
* @param user
* @return
*/
@Log(module = Module.ROLE, value = "修改用戶", type = LogType.UPDATE)
@RequiresPermissions("system:user:edit")
@PostMapping("/edit")
@ResponseBody
public ResponseEntity<ModelMap> editSave(SysUser user)
{
if (user.getId() != null && user.getId().longValue() == 1)
{
throw new BusinessException("管理員用戶笆怠,不支持修改!");
}
return setSuccessModelMap(this.sysUserService.updateUser(user));
}
/**
* 跳轉(zhuǎn)用戶重置密碼頁面
*
* @param userId
* @param modelMap
* @return
*/
@RequiresPermissions("system:user:resetPwd")
@GetMapping("/resetPwd/{userId}")
public String resetPwd(@PathVariable("userId") Long userId, ModelMap modelMap)
{
modelMap.put("user", this.sysUserService.queryById(userId));
return Constants.MODULE_SYS_USER_PREFIX + "resetPwd";
}
/**
* 保存密碼操作
*
* @param user
* @return
*/
@Log(module = Module.ROLE, value = "修改密碼", type = LogType.UPDATE)
@RequiresPermissions("system:user:resetPwd")
@PostMapping("/resetPwd")
@ResponseBody
public ResponseEntity<ModelMap> resetPwdSave(SysUser user)
{
// 密碼加密
user.setSalt(EncryptUtils.randomSalt());
user.setPassword(EncryptUtils.encryptPassword(user.getUserName(), user.getPassword(), user.getSalt()));
this.sysUserService.update(user);
return setSuccessModelMap();
}
/**
* 刪除用戶 支持批量刪除
*
* @param ids
* @return
*/
@Log(module = Module.ROLE, value = "刪除用戶", type = LogType.DELETE)
@RequiresPermissions("system:user:remove")
@PostMapping("/remove")
@ResponseBody
public ResponseEntity<ModelMap> remove(String ids)
{
String[] idAttr = ids.split(SEG_CHAR);
List<Long> list = Lists.newArrayList();
for (String id : idAttr)
{
list.add(Long.valueOf(id));
}
// 邏輯刪除
this.sysUserService.deleteUsers(list, ShiroUtils.getCurrentUserId());
return setSuccessModelMap();
}
/**
* 校驗用戶名是否重復
*
* @param user
* @return
*/
@PostMapping("/checkUserNameUnique")
@ResponseBody
public String checkUserNameUnique(SysUser user)
{
return String.valueOf(this.sysUserService.countByUserName(user));
}
/**
* 校驗郵箱是否重復
*
* @param user
* @return
*/
@PostMapping("/checkEmailUnique")
@ResponseBody
public String checkEmailUnique(SysUser user)
{
return this.sysUserService.countByEmail(user);
}
/**
* 校驗郵箱是否重復
*
* @param user
* @return
*/
@PostMapping("/checkPhoneUnique")
@ResponseBody
public String checkPhoneUnique(SysUser user)
{
return this.sysUserService.countByPhone(user);
}
}
上述以系統(tǒng)用戶控制器為例子誊爹,其中Service
都是dubbo
的接口骑疆。注意shiro
權限的配置以及日志的配置。
6.國際化的配置
主要是一些異常信息的配置message_*.properties
文件
7.頁面
主要知道頁面模板的配置替废,以及相應的shiro
權限控制的按鈕狀態(tài)的控制箍铭,注意分頁查詢,頁面數(shù)據(jù)渲染等,都可以按照其他已有模塊拷貝修改即可椎镣。