CRM管理系统开发总结:
技术选型:Spring+SpringMVC+easyUI+jQuery+mybatis+layUI+shiro+多模块+Maven
负责模块:部门、权限资源、shiro验证
1.部门模块(easyUI)
1.基础组件的创建
1.使用代码生成器逆向生成domain,mapper及mapper.xml
2.然后自己创建service层及controller层
3.最后创建JS及jsp
2.高级查询及分页
1.创建查询对象
public class BaseQueryObject { private Integer page = 1; private Integer rows = 10; public Integer getPage() { return page; } public void setPage(Integer page) { this.page = page; } public Integer getRows() { return rows; } public void setRows(Integer rows) { this.rows = rows; } }
public class PageResult {
private long total = 0;
private List rows = new ArrayList();
public PageResult() {
}
public PageResult(long total, List rows) {
this.total = total;
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List getRows() {
return rows;
}
public void setRows(List rows) {
this.rows = rows;
} }
public class DepartmentQueryObject extends BaseQueryObject {
//关键字查询
private String keyword;
public String getKeyword() {
if(StringUtils.hasLength(keyword)){
return keyword.trim();
}
return null;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
} }@Service @Transactional
public class DepartmentServiceImpl extends
BaseServiceImpl implements IDepartmentService {
@Autowired
private DepartmentMapper departmentMapper;
@Override
public void updateStateToDisable(Long id) {
//1.查询对象
Department department = departmentMapper.selectByPrimaryKey(id);
//判断状态
if(department.getState() == Employee.STATE_NORMAL){
//2.修改状态 department.setState(Department.STATE_DISABLED);
updateByPrimaryKey(department);
}
} }
3.编写高级查询分页的sql
and name like concat("%",#{keyword},"%")
4.创建controller层方法(CRUD)
@Controller @RequestMapping("/department") public class
DepartmentController {
@Autowired
private IDepartmentService departmentService;
//根据id查询部门
@RequestMapping("/getById")
@ResponseBody
public Department getById(Long id){
return departmentService.selectByPrimaryKey(id);
}
//部门主页面
@RequestMapping("/index")
public String index(Model model){
return “department”;
}
//部门列表数据
@RequestMapping("/list")
@ResponseBody
public PageResult list(DepartmentQueryObject qo){
return departmentService.selectForList(qo);
}
@RequestMapping("/findAll")
@ResponseBody
public List findAll(){
return departmentService.selectAll();
}
//部门添加/修改
@RequestMapping("/saveOrUpdate")
@ResponseBody
public AjaxResult saveOrUpdate(Department department){
try {
if(department.getId() == null){
departmentService.insert(department);
}else{
departmentService.updateByPrimaryKey(department);
}
return AjaxResult.success();
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error(“啊,系统异常啦,我们正在殴打程序员O(∩_∩)O~”);
}
}
//部门删除
@RequestMapping("/delete")
@ResponseBody
public AjaxResult remove(Long id){
try {
departmentService.deleteByPrimaryKey(id);
return AjaxResult.success();
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error(“啊,系统异常啦,我们正在殴打程序员O(∩_∩)O~”);
}
} }
3.前台页面对功能的实现(jsp,js)及其sql
1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
部门管理
<%--工具条--%>
<%--员工管理表格--%>
<%--添加/编辑 的弹出窗口--%>
<%--添加/编辑 的弹出窗口的按钮组--%>
2.js
function stateFormatter(value,row,index){
return value == 1 ? "禁用" : "正常";
}
$(function () {
var departmentDataGrid = $('#departmentDataGrid');
var departmentAddDialog = $("#departmentAddDialog");
var departmentAddDialogForm = $("#departmentAddDialogForm");
//统一绑定方法
var methodObj = {
search:function () {
//获取关键字
var keyword = $("#keyword").val();
//查询
departmentDataGrid.datagrid("load",{"keyword":keyword});
},
add:function () {
//弹出添加的dialog
departmentAddDialogForm.form("clear");
departmentAddDialog.dialog("open");
},
edit:function () {
//获取选中行
var row = departmentDataGrid.datagrid("getSelected");
if(row){
//表单数据回显
departmentAddDialogForm.form("clear");
departmentAddDialogForm.form('load',row);
//弹出编辑框
departmentAddDialog.dialog("open");
}else{
//给出提示
$.messager.alert("提示","你不选择数据我怎么给你修改?","error");
}
},
remove:function () {
//获取选中行
var row = departmentDataGrid.datagrid("getSelected");
if(row){
var id = row.id;
var state = row.state;
if(state == 1){
$.messager.alert("提示","状态已经是删除","error");
}else{
//删除请求ajax
$.post("department/remove",{"id":id},function (data) {
if(data.success){
//列表刷新
$.messager.alert("提示","恭喜您,提交成功,列表已经刷新","info");
methodObj.reload();
}else{
$.messager.alert("提示","恭喜您,提交失败,错误原因:"+data.msg,"error");
}
});
}
}else{
//给出提示
$.messager.alert("提示","你不选择数据我怎么给你删除?","error");
}
},
reload:function () {
departmentDataGrid.datagrid("reload");
},
save:function () {
//获取表单
//提交表单
departmentAddDialogForm.form('submit', {
url:"department/saveOrUpdate",
success:function(data){
data = $.parseJSON(data);
if(data.success){
//列表刷新
$.messager.alert("提示","恭喜您,提交成功,列表已经刷新","info");
methodObj.close();
methodObj.reload();
}else{
$.messager.alert("提示","恭喜您,提交失败,错误原因:"+data.msg,"error");
}
}
});
},
close:function () {
departmentAddDialog.dialog("close");
}
};
//统一绑定事件
$("a[data-method]").click(function () {
var method = $(this).data("method");
methodObj[method]();
});
//渲染表格
departmentDataGrid.datagrid({
url:'department/list',
fit:true,
fitColumns:true,
singleSelect:true,
pagination:true,
toolbar:"#departmentDataGridToolbar",
columns:[[
{field:'id',title:'ID',width:100},
{field:'sn',title:'部门编号',width:100},
{field:'name',title:'部门名称',width:100},
{field:'manager',title:'部门经理',width:100},
{field:'parent',title:'上级部门',width:100},
{field:'children',title:'子部门',width:100},
{field:'dirpath',title:'路径',width:100},
{field:'state',title:'状态',width:100,formatter:stateFormatter},
{field:'tenant',title:'所属租户',width:100}
]]
});
//添加的dialog
departmentAddDialog.dialog({
closed: true,
modal: true,
buttons:"#departmentAddDialogButtons"
});
departmentAddDialog.dialog({
left:650,
top:50
})
});
3.sql
delete from department
where id = #{id,jdbcType=BIGINT}
insert into department (sn, name, manager,
parent, children, dirPath,
state, tenant)
values (#{sn,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{manager,jdbcType=VARCHAR},
#{parent,jdbcType=VARCHAR}, #{children,jdbcType=VARCHAR}, #{dirpath,jdbcType=VARCHAR},
#{state,jdbcType=INTEGER}, #{tenant,jdbcType=VARCHAR})
update department
set sn = #{sn,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
manager = #{manager,jdbcType=VARCHAR},
parent = #{parent,jdbcType=VARCHAR},
children = #{children,jdbcType=VARCHAR},
dirPath = #{dirpath,jdbcType=VARCHAR},
state = #{state,jdbcType=INTEGER},
tenant = #{tenant,jdbcType=VARCHAR}
where id = #{id,jdbcType=BIGINT}
select id, sn, name, manager, parent, children, dirPath, state, tenant
from department
where id = #{id,jdbcType=BIGINT}
2.权限模块-资源模块等同(layUI)
1.基础组件的创建
2.高级查询及分页
1.查询对象(这是属于layUI的,所以跟前面的不一样)
public class BaseQuery { private int page = 1;//当前页数 private int limit = 10;//每页显示条数 pageSize public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getLimit() { return limit; } public void setLimit(int limit) { this.limit = limit; } }
public class PageResult {
private long total = 0;
private List rows = new ArrayList();
public PageResult() {
}
public PageResult(long total, List rows) {
this.total = total;
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public List getRows() {
return rows;
}
public void setRows(List rows) {
this.rows = rows;
} }
2.service层
public class RoleQuery extends BaseQuery { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } @Service @Transactional public class RoleServiceImpl extends BaseServiceImpl
implements IRoleService { @Autowired private RoleMapper roleMapper; //根据名字查询角色 @Override public Role selectByName(String name) { return roleMapper.selectByName(name); } @Override public PageList selectByQuery(BaseQuery baseQuery) { PageList pageList = new PageList<>(); //maBatis 分页 PageHelper.startPage(baseQuery.getPage(),baseQuery.getLimit()); Page page = (roleMapper.selectByQuery(baseQuery)); //设置总数量 pageList.setCount(page.getTotal()); //设置总数据 pageList.setData(page.getResult()); return pageList; } }
3.sql的编写
4.控制层controller功能CRUD
@Controller
@RequestMapping("/role")
public class RoleController {
@Autowired
private IRoleService roleService;
@Autowired
private IPermissionService permissionService;
@Autowired
private IRolePermissionService rolePermissionService;
@Autowired
private IRoleMenuService roleMenuService;
@Autowired
private ISystemMenuService systemMenuService;
@RequestMapping("/index")
public String index() {
return "role";
}
@RequestMapping("/list")
@ResponseBody//json
public PageList list(RoleQuery roleQuery) {
return roleService.selectByQuery(roleQuery);
}
// role/delete?id
@RequestMapping("/delete")
@ResponseBody//json
public AjaxResult delete(Long[] ids) {
try {
//删除先把中间表删除
for (Long id : ids) {
rolePermissionService.deleteByRoleId(id);
}
for (Long id : ids){
roleMenuService.deleteByRoleId(id);
}
for (Long id : ids) {
roleService.deleteByPrimaryKey(id);
}
return AjaxResult.success();
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("删除失败!!!");
}
}
@RequestMapping("/saveOrUpdate")
@ResponseBody//json
public AjaxResult saveOrUpdate(Role role) {
//将获取到的权限封装到角色对象里面
List permissions = new ArrayList<>();
for (Permission permission : role.getSn()) {
Permission permission1 = permissionService.selectByPrimaryKey(permission.getId());
permissions.add(permission1);
}
role.setSn(permissions);
//获取到菜单,封装的角色对象里面
List systemMenus = new ArrayList<>();
for (SystemMenu menu : role.getSystemMenus()) {
systemMenuService.selectByPrimaryKey(menu.getId());
systemMenus.add(systemMenuService.selectByPrimaryKey(menu.getId()));
}
if (role != null) {
try {
//判断是否有id,有就是修改,没有就是添加
if (role.getId() != null) {
//这个是当前角色未被修改的权限
List list = rolePermissionService.selectByRoleId(role.getId());
//这是当前角色未被修改的菜单
List roleMenus = roleMenuService.selectByRoleId(role.getId());
for (SystemMenu systemMenu : systemMenus) {
roleMenuService.deleteByRoleId(role.getId());
}
for (int i = 0; i < systemMenus.size(); i++) {
RoleMenu roleMenu = new RoleMenu();
roleMenu.setRoleId(role.getId());
roleMenu.setMenuId(systemMenus.get(i).getId());
roleMenuService.insert(roleMenu);
}
for (RolePermission permission : list) {
/* System.out.println("这个是当前角色未被修改的权限------------"+permission);*/
//删除所有的
rolePermissionService.deleteByRoleId(role.getId());
}
//这是修改我们选中的权限
for (int i = 0; i < permissions.size(); i++) {
RolePermission rolePermission = new RolePermission();
rolePermission.setRoleId(role.getId());
rolePermission.setPermissionId(permissions.get(i).getId());
/* System.out.println("这是修改我们选中的权限"+rolePermission);*/
//在添加
rolePermissionService.insert(rolePermission);
}
//修改 清空
role.setSn(null);
role.setSystemMenus(null);
roleService.updateByPrimaryKey(role);
} else {
//添加
Role role1 = new Role();
role1.setName(role.getName());
//在角色表里添加
roleService.insert(role1);
//在搜索出我们刚才添加对象
Role roleId = roleService.selectByName(role1.getName());
//id是空的啊 因为我在添加啊 所以先添加角色表内容在搜索出刚才添加的对象id
//向角色id里面添加所有的权限id
for (int i = 0; i < permissions.size(); i++) {
RolePermission rolePermission = new RolePermission();
rolePermission.setRoleId(roleId.getId());
rolePermission.setPermissionId(permissions.get(i).getId());
rolePermissionService.insert(rolePermission);
}
for (int i = 0; i findPermissionAll() {
return permissionService.selectAll();
}
//动态的获取所有的菜单
@RequestMapping("findMenuAll")
@ResponseBody
public List findMenuAll(){
return systemMenuService.selectAll();
}
}
3.前台页面对功能的实现及其sql
1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
角色管理
<%--引入自己封装的公共代码,依赖于layui和jquery--%>
<%@include file="/static/common/head.jsp" %>
<%--头部工具栏--%>
<%--头部高级查询的form表单--%>
立即提交
<%--数据表单--%>
<%--弹出框的form--%>
2.js
layui.config({
base: '/static/js/'
}).extend({
selectN: './layui_extends/selectN',
selectM: './layui_extends/selectM',
}).use(['jquery', 'table', 'form', 'layer', 'selectN', 'selectM'], function () {
var selectN = layui.selectN
var selectM = layui.selectM;
var table = layui.table; //数据表格对象
var form = layui.form;//头部form表单对象
var layer = layui.layer;//弹出层对象
var $ = layui.jquery;//加载jquery对象
var emp = {};
// 创建数据表格
table.render({
elem: '#roleTable'
,id: '#roleTable'
, url: '/role/list'
, title: '员工信息'
, even: true //开启隔行背景
, toolbar: '#toolbarDemo'
, cols: [[
{type: 'checkbox', fixed: 'left'},
{field: 'id', title: '编号', align: 'center'},
{field: 'name', title: '角色名', align: 'center'},
{
field: 'sn', title: '权限', align: 'center', templet: function (d) {
var permissions = [];
if (d.sn.length) {
$.each(d.sn, function (index, obj) {
permissions.push(obj.name);
})
}
return permissions;
}
},{
field:'systemMenus',title:'菜单',align:'center',templet:function (d) {
var systemMenus = [];
if (d.systemMenus.length) {
$.each(d.systemMenus, function (index, obj) {
systemMenus.push(obj.name);
})
}
return systemMenus;
}
}
]]
, page: true
});
var p = []
var r=[]
//多选标签-基本配置权限下拉框
var permissions = selectM({
//元素容器【必填】
elem: '#allPermission'
//候选数据【必填】
, data: "/role/findPermissionAll"
, max: 100
, width: 400
//添加验证
, verify: 'required'
,selected:p
});
//多选标签-基本配置菜单下拉框
var allMenu = selectM({
//元素容器【必填】
elem: '#allMenu'
//候选数据【必填】
, data: "/role/findMenuAll"
, max: 100
, width: 400
//添加验证
, verify: 'required'
,selected:r
});
//高级查询提交
form.on("submit(serch)", function (data) {
var serchdate = data.field;
console.debug(serchdate.roleName);
table.reload('#roleTable', {
url:"/role/list"
,where: { //设定异步数据接口的额外参数,任意设
name:serchdate.roleName
}
,page: {
curr: 1 //重新从第 1 页开始
}
});
});
//监听事件
table.on('toolbar(roleTable)', function(obj){
var checkStatus = table.checkStatus(obj.config.id);
switch(obj.event){
case 'add':
// 弹出添加框
layer.open({
type: 1,
title: "添加",
closeBtn: false,
shift: 2,
area: ['600px', '500px'],
shadeClose: true,
btn: ['取消'],
offset: '100px',
// btnAlign: 'c',
content: $("#roleFormDlog"),
//弹出成功后的回调
success: function (layero, index) {
form.val("roleFormDlog", {"id": ""});
form.val("roleFormDlog", {"name": ""});
}
});
break;
case 'delete':
var id = table.checkStatus("#roleTable");
var ids = [];
$.each(id.data, function (index, obj) {
ids.push(obj.id);
});
if (ids.length) {
$.get("/role/delete", {"ids": ids.toString()}, function (res) {
if (res.success) {
//数据表格刷新
$(".layui-laypage-btn")[0].click();
layer.msg("删除成功", {
time: 2000, //20s后自动关闭
});
//当前页数据条数 table.cache.test
var count = (table.cache.length) - (ids.length);
//删除后如果当前页没有数据了就跳到上一页
if (count == 0) {
//当前页码值
var current = $(".layui-laypage-em").next().html();
$(".layui-laypage-skip").find("input").val(current - 1);
$(".layui-laypage-btn").click();
}
} else {
layer.msg("删除失败" + res.mag, {
time: 2000 //20s后自动关闭
});
}
});
} else {
layer.msg("请选择后删除", {
icon: 0,
time: 2000
});
}
break;
case 'update':
var id = table.checkStatus("#roleTable");
var p = []
var r=[]
var ids = [];
$.each(id.data, function (index, obj) {
ids.push(obj.id);
if((obj.sn).length){
$.each(obj.sn,function (i,o) {
//将选中的放入数组。后面默认选中
p.push(o.id)
})
}
if((obj.systemMenus).length){
$.each(obj.systemMenus,function (i,o) {
r.push(o.id)
})
}
});
//多选标签-基本配置 回显下拉框
var p1 = selectM({
//元素容器【必填】
elem: '#allPermission'
//候选数据【必填】
, data: "/role/findPermissionAll"
, max: 100
, width: 400
//添加验证
, verify: 'required'
,selected:p
});
var p2 = selectM({
//元素容器【必填】
elem: '#allMenu'
//候选数据【必填】
, data: "/role/findMenuAll"
, max: 100
, width: 400
//添加验证
, verify: 'required'
,selected:r
});
if (ids.length) {
layer.open({
type: 1,
title: "修改",
closeBtn: false,
shift: 2,
area: ['600px', '500px'],
shadeClose: true,
btn: ['取消'],
//form表单回显
offset: '100px',
// btnAlign: 'c',
content: $("#roleFormDlog"),
//弹出成功后的回调
success: function (layero, index) {
var obj = table.checkStatus("#roleTable");
$.each(obj.data, function (i, o) {
form.val("roleFormDlog", {"id": o.id});
form.val("roleFormDlog", {"name": o.name});
})
}
})
}
else {
layer.msg("请选择后修改", {
icon: 0,
time: 2000
});
}
break;
};
});
//添加与删除事件
$("a").on("click", function () {
var cmd = $(this).data("cmd");
if (cmd) {
itsource[cmd]();
}
});
var itsource = {
//重置搜索框
"reset": function () {
document.getElementById("roleFormDlog").reset();
//多选标签-基本配置 回显下拉框
var p1 = selectM({
//元素容器【必填】
elem: '#allPermission'
//候选数据【必填】
, data: "/role/findPermissionAll"
, max: 100
, width: 400
//添加验证
, verify: 'required',
selected:[]
});
}
};
//弹出框提交
form.on("submit(save)", function (data) {
var setted = data.field;
//sn[0].id=1
for (var i = 0; i < (permissions.values).length; i++) {
// (permissions.values)[i];
//动态的拼接传参 权限
setted["sn[" + i + "].id"] = (permissions.values)[i]
}
for (var i = 0; i < (allMenu.values).length; i++) {
//动态的拼接传参 菜单
setted["systemMenus[" + i + "].id"] = (allMenu.values)[i]
}
console.debug(56465);
var url = "/role/saveOrUpdate";
$.ajax({
url: url,
type: 'post',
data: setted,
success: function (res) {
if (res.success) {
//关闭弹出框
layer.closeAll();
//数据表格刷新
$(".layui-laypage-btn")[0].click();
layer.msg("操作成功", {
time: 2000, //20s后自动关闭
});
} else {
layer.closeAll();
layer.msg("操作失败" + res.mag, {
time: 2000 //20s后自动关闭
});
}
}
});
return false;//防止页面跳转,进行局部刷新
});
});
3.sql
delete from role
where id = #{id,jdbcType=BIGINT}
insert into role (`name`, tenant
)
values ( #{name,jdbcType=VARCHAR}, #{tenant,jdbcType=INTEGER}
)
update role
set
`name` = #{name,jdbcType=VARCHAR},
tenant = #{tenant,jdbcType=INTEGER}
where id = #{id,jdbcType=BIGINT}
3.shiro模块
1.首先导入shiro及与Spring的依赖
2.创建一个myrealm去继承AuthorizingRealm,然后覆写它的两个方法
public class ItsourceRealm extends AuthorizingRealm {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IPermissionService permissionService;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Employee employee = UserContext.getUser();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set permissions = permissionService.findPermissionSnByEmployee(employee);
info.setStringPermissions(permissions);
return info;
}
//身份认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws
AuthenticationException {
String username = (String)token.getPrincipal();
Employee employee = employeeService.selectByUserName(username);
if(employee == null){
return null;
}
ByteSource salt = ByteSource.Util.bytes(MD5Util.SALT);
return new SimpleAuthenticationInfo(employee,employee.getPassword(),salt,getName());
} }
3.创建applicationContext-shiro.xml配置文件
4.创建一个加密类 public class MD5Util {//公共对密码加密的类
//加密方式
public static final String ALGORITHMNAME = “MD5”;
//盐值
public static final String SALT = “kaley”;
//加密次数
public static final int HASHITERATIONS = 10;
//MD5加密
public static String createMd5(String source){//加密的方法
SimpleHash hash = new SimpleHash(ALGORITHMNAME,source,SALT,HASHITERATIONS);
return hash.toString();
} }
5.创建一个权限监听类
public class FilterChainDefinitionMapFactory {
@Autowired
private IPermissionService permissionService;
public MapcreateMap(){
List permissions = permissionService.selectAll();
Mapmap = new LinkedHashMap<>();
map.put("/static/", “anon”);
map.put("/login", “anon”);
map.put("/logout", “logout”);
map.put(".css", “anon”);
map.put(".js", “anon”);
map.put("/logout", “logout”);
for (Permission permission : permissions) {
map.put(permission.getUrl(), “itsourcePerms[”+permission.getSn()+"]");
}
map.put("/", “authc”);
return map;
} }
6.web读取配置文件及shiro过滤器
contextConfigLocation
classpath:applicationContext.xml
classpath:applicationContext-shiro.xml
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
shiroFilter
/*
7.最后前台页面实现功能