1. 项目简介及系统架构
提供系统管理功能,包括用户管理、菜单管理、角色管理模块
1.1 系统功能介绍
用户管理:添加用户、查询用户、删除用户、修改用户、激活或冻结用户状态。
菜单管理:添加菜单、删除菜单、修改菜单、查看下级菜单。
角色管理:添加角色、删除角色、修改角色、绑定用户(赋予用户角色)、绑定用户操作(赋予用户可操作的功能模块)
1.2 采用技术
spring、spring MVC、JPA、jQuery、BootStrap、JSP
1.3 系统结构
- 表现层:JSP页面
- 控制层:SpringMVC
- 业务层:主要由SpringIoC容器管理的业务逻辑组件组成
- 持久层:由6个Repository组件组成
- 领域对象层:由6个Domain Object对象组成
- 数据库服务层:MySQL
2. 配置文件
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.oa</groupId>
<artifactId>oa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>oa</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 添加 spring-boot-starter-web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 添加 spring-boot-starter-tomcat 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 添加MySQL 数据库依赖 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 添加 spring-boot-starter-data-jpa 依赖 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 添加 servlet 依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- 添加 JSTL 依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 添加使用jsp必须的 tomcat-embed-jasper 依赖 -->
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- 常用工具类 -->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- 不需要生成get/set方法 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<finalName>oa</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties:
####################################################################
### 数据源信息配置
####################################################################
# 数据库地址
spring.datasource.url= jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=GMT%2B8
# 用户名
spring.datasource.username= root
# 密码
spring.datasource.password= 123456
# 数据库驱动
spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver
# 指定连接池中最大的活跃连接数
spring.datasource.tomcat.max-active= 20
# 指定连接池中最大的空闲连接数
spring.datasource.tomcat.max-idle= 8
# 指定连接池中最小的空闲连接数
spring.datasource.tomcat.min-idle= 8
# 指定启动连接池时,初识建立的连接数量
spring.datasource.tomcat.initial-size= 10
####################################################################
### JPA持久化配置
####################################################################
# 指定数据库的类型
spring.jpa.database= MYSQL
# 指定是否需要再日志中显示SQL语句
spring.jpa.show-sql= true
# 指定自动创建|更新|验证数据库表结构等配置,配置成update
# 表示如果数据库中存在持久化对应的表就不创建,不存在就创建对应的表
spring.jpa.hibernate.ddl-auto= update
# 指定命名策略 - 在大写字母前加下划线,将大写字母变为小写:LoginName --> login_name
spring.jpa.hibernate.naming.physical-strategy= org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
# 指定数据库方言
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL55Dialect
spring.mvc.view.prefix= /WEB-INF/jsp/
spring.mvc.view.suffix= .jsp
3. 持久化类
3.1 持久化实体
共有6个持久化类(PO):
- User:用户,包括所属部门及职位。
- Dept:部门
- Job:职位
- Module:模块
- Role:角色
- Popedom:权限,包括权限对应的模块和角色
这6个PO的关系如下:
- Dept和User存在1-N的关系,即一个Dept(部门)可以有多个User(用户)
- User和Dept存在N-1的关系,即一个User(用户)只属于一个Dept(部门)
- User和Job存在N-1的关系,即一个User(用户)只能有一个Job(职位)
- Module和Role是N-N的关系,即一个Module(模块)可以属于多个Role(角色),一个Role(角色)中也可以有多个Module(模块),他们的关系通过Popedom关联
- User和Role是N-N的关系,即一个User(用户)可以分配多个Role(角色),一个Role(角色)可以分配给多个用户(User),它们的关系通过中间表关联
3.2 创建持久化实体类
3.2.1 实体类父类 - BaseEntity
/**
* Copyright © 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
*/
package org.oa.common.domain;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import lombok.Data;
/**
* Entity支持类
*/
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Data
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
// ID PK主键自增
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
// NAME VARCHAR(50) 名称
@Column(name = "NAME", length = 50)
private String name;
@Column(name = "MODIFY_DATE")
@LastModifiedDate
private Date modifyDate;
@Column(name = "CREATE_DATE")
@CreatedDate
private Date createDate;
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}
3.2.2 部门 - Dept
package org.oa.sys.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_DEPT")
public class Dept extends BaseEntity {
private static final long serialVersionUID = 650869023393097574L;
// REMARK VARCHAR(500) 备注
@Column(name = "REMARK", length = 500)
private String remark;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_DEPT_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_DEPT_CREATER"))
private User creater;
}
3.2.3 职位 - Job
package org.oa.sys.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_JOB")
public class Job extends BaseEntity {
private static final long serialVersionUID = 6217008478303289267L;
// CODE 代码
@Column(name = "CODE", length = 100)
private String code;
// REMARK VARCHAR(500) 备注
@Column(name = "REMARK", length = 500)
private String remark;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_JOB_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_JOB_CREATER"))
private User creater;
}
3.2.4 模块 - Module
package org.oa.sys.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_MODULE")
public class Module extends BaseEntity {
private static final long serialVersionUID = -9061932230116610720L;
// CODE 代码
@Column(name = "CODE", length = 100)
private String code;
// URL VARCHAR(50) 模块链接
@Column(name = "URL", length = 50)
private String url;
// REMARK VARCHAR(500) 备注
@Column(name = "REMARK", length = 500)
private String remark;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_MODULE_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_MODULE_CREATER"))
private User creater;
}
3.2.5 模块内的操作权限 - Popedom
package org.oa.sys.domain;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 模块内的权限
*
* @author LiangJiawen
*
*/
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_POPEDOM")
public class Popedom extends BaseEntity {
private static final long serialVersionUID = -3217924244773768143L;
// 权限与模块存在多对一的关系
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Module.class)
@JoinColumn(name = "MODULE_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_POPEDOM_MODULE"))
private Module module;
// 权限与操作是多对一的关系
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Module.class)
@JoinColumn(name = "OPERA_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_POPEDOM_OPERA"))
private Module opera;
// 权限与角色是多对一的关系
// 权限与操作是多对一的关系
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Role.class)
@JoinColumn(name = "ROLE_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_POPEDOM_ROLE"))
private Role role;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_POPEDOM_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_POPEDOM_CREATER"))
private User creater;
}
3.2.6 角色 - Role
package org.oa.sys.domain;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_ROLE")
public class Role extends BaseEntity {
private static final long serialVersionUID = 4740271295896021748L;
// REMARK VARCHAR(500) 备注
@Column(name = "REMARK", length = 500)
private String remark;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_ROLE_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_ROLE_CREATER"))
private User creater;
// 角色与用户存在多对多的关联关系
@ManyToMany(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinTable(name = "OA_USER_ROLE", joinColumns = @JoinColumn(name = "ROLE_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_ROLE_ID")), inverseJoinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_ID")))
private Set<User> users = new HashSet<>();
}
3.2.7 用户 - User
package org.oa.sys.domain;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import org.oa.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Entity
@Data
@EqualsAndHashCode(callSuper = false)
@Table(name = "OA_USER", indexes = {
@Index(columnList = "NAME", name = "IDX_USER_NAME") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"MOBILE" }, name = "UQ_USER_MOBILE"))
public class User extends BaseEntity {
private static final long serialVersionUID = -6649598873548648860L;
// 手机号
@Column(name = "MOBILE")
private String mobile;
// 密码 md5加密
@Column(name = "PASSWORD", length = 50)
private String password;
// 性别
@Column(name = "SEX")
private short sex;
// 用户与部门存在多对一的关系 FK(OA_DEPT)
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Dept.class)
@JoinColumn(name = "DEPT_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_DEPT"))
private Dept dept;
// 用户与职业存在多对一的关系 FK(OA_JOB)
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Job.class)
@JoinColumn(name = "JOB_ID", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_JOB"))
private Job job;
// 状态:0-新建 1-审核 2-审核不通过 3-冻结
@Column(name = "STATUS")
private short status;
// MODIFIER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "MODIFIER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_MODIFIER"))
private User modifier;
// CREATER VARCHAR(50) 修改人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CREATER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_CREATER"))
private User creater;
// CHECKER VARCHAR(50) 审核人
@ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
@JoinColumn(name = "CHECKER", referencedColumnName = "ID", foreignKey = @ForeignKey(name = "FK_USER_CHECKER"))
private User checker;
// CHECK_DATA 审核时间
@Column(name = "CHECK_DATE")
@Temporal(TemporalType.TIMESTAMP)
private Date checkDate;
// 用户与角色存在多对多的关系
@ManyToMany(fetch = FetchType.LAZY, targetEntity = Role.class, mappedBy = "users")
private Set<Role> roles = new HashSet<>();
}
3.3 生成的表
具体的表结构就不粘贴了,可以自己在数据库中查看,采用JPA自动生成表结构