(一)SpringBoot基本操作——环境搭建及项目创建(有demo)
(二)SpringBoot基本操作——使用IDEA打war包发布及测试
(三)SpringBoot基本操作——SpringBoot整合SpringDataJpa(有demo)
(四)SpringBoot基本操作——SpringBoot使用RedisTemplate整合Redis(有demo)
(五)SpringBoot基本操作——SpringBoot使用Jedis整合Redis(有demo)
(六)SpringBoot基本操作——SpringBoot使用Junit4单元测试(有demo)
(七)SpringBoot基本操作——SpringBoot整合Shiro权限管理(完整demo+界面)
这篇花了我挺久的时间做整合,因为包含了最完整的示例,很早之前我就准备做一个整合shiro的示例出来,为什么呢?因为我自己在开发中遇到了权限管理的需求,但是我在网上参考了很多大牛的文章,发现并没有一个完整的示例可以给出来的,所以我曾经自己手写了一个基于RBAC的权限管理功能,详见这里,这个模块目前也在我们的系统中运行着,但是随着系统越来越庞大,我发现这个东西没那么好用了,很多我并不需要加入权限的操作受限于白名单管理,维护变得麻烦起来,现在我以shiro替换掉了,以下我给出的这个demo是从我们目前的项目中抽离开出来的,配合我之前发布的springboot2.0基础demo做了精简整合,这个模块可以直接嵌入你的springboot项目系统中。本篇部分参考了纯洁的微笑大大的文章。
本文使用idea工具构建Springboot2.0+SpringMvc+Thymeleaf+SpringDataJPA+MySql+Shiro项目
GitHub地址:https://github.com/jwwam/springbootShiro.git
1.登录模块,包含注册功能,动态GIF验证码
2.管理员登录后台界面,包含权限模块最基本的用户管理、角色管理、资源管理。
3.用户管理包括最基本的增删改查+角色分配+状态修改
4.添加用户界面
5.为用户分配角色
6.为角色分配资源
7.资源的新建删除及修改
以上就是整个权限管理系统的界面浏览,下面将整理出完整的实现代码。
关键maven依赖
org.apache.shiro
shiro-core
1.2.2
org.apache.shiro
shiro-spring
1.2.2
org.apache.shiro
shiro-ehcache
1.2.2
net.sf.json-lib
json-lib
2.4
jdk15
首先需要一个用户实体UserInfo.java
package com.springboot.demo.base.entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Table(name="user_info")
@SuppressWarnings("serial")
@Entity
public class UserInfo implements Serializable {
@Id
@GeneratedValue
private Integer uid=1;
@Column(unique =true)
private String username;//帐号
private String name;//名称(昵称或者真实姓名,不同系统不同定义)
private String password; //密码;
private String salt= "8d78869f470951332959580424d4bf4f";//加密密码的盐
private int state=0;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.3: 已上传认证资料未审核. 4: 已上传认证资料审核未通过
@Column(name= "create_date") //创建时间
Date createDate = new Date();
@Column(name= "update_date")//修改时间
Date updateDate = new Date();
@Column(name= "remarks")
private String remarks;//描述
private String phone;//手机
private String reason;//审核原因
@ManyToMany(fetch= FetchType.EAGER)//立即从数据库中进行加载数据;
@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })
private List roleList;// 一个用户具有多个角色
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public List getRoleList() {
return roleList;
}
public void setRoleList(List roleList) {
this.roleList = roleList;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public String getRemarks() {
return remarks;
}
public void setRemarks(String remarks) {
this.remarks = remarks;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
/**
* 密码盐.
* @return
*/
public String getCredentialsSalt(){
return this.username+this.salt;
}
//重新对盐重新进行了定义,用户名+salt,这样就更加不容易被破解
}
添加ShiroConfig.java
这里需要配置shiro的过滤规则
package com.springboot.demo.base.config;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//拦截器.
Map filterChainDefinitionMap = new LinkedHashMap();
// 配置不会被拦截的链接 顺序判断
//filterChainDefinitionMap.put("/static/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
//:这是一个坑呢,一不小心代码就不好使了;
//
filterChainDefinitionMap.put("/static/templates/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login/loginUser");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/login/home");
//未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/base/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* )
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}
@Bean
public ShiroRealm myShiroRealm(){
ShiroRealm myShiroRealm = new ShiroRealm();
myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver
createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "/base/databaseError");//数据库异常处理
mappings.setProperty("UnauthorizedException","/base/error");
r.setExceptionMappings(mappings); // None by default
//r.setDefaultErrorView("error"); // No default
r.setDefaultErrorView("/base/login"); // 访问错误,直接访问登录页面
r.setExceptionAttribute("ex"); // Default is "exception"
//r.setWarnLogCategory("example.MvcLogger"); // No default
return r;
}
}
ShiroRealm.java
这里主要进行用户身份的校验
package com.springboot.demo.base.config;
import javax.annotation.Resource;
import com.springboot.demo.base.entity.SysPermission;
import com.springboot.demo.base.entity.SysRole;
import com.springboot.demo.base.entity.UserInfo;
import com.springboot.demo.base.service.UserInfoService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
public class ShiroRealm extends AuthorizingRealm {
@Resource
private UserInfoService userInfoService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
UserInfo userInfo = (UserInfo)principals.getPrimaryPrincipal();
for(SysRole role:userInfo.getRoleList()){
authorizationInfo.addRole(role.getRole());
for(SysPermission p:role.getPermissions()){
authorizationInfo.addStringPermission(p.getPermission());
}
}
//CacheUntil.setCacheTree(authorizationInfo);
return authorizationInfo;
}
/*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
System.out.println("ShiroRealm.doGetAuthenticationInfo()");
//获取用户的输入的账号.
String username = (String)token.getPrincipal();
//通过username从数据库中查找 User对象,如果找到,没找到.
//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
UserInfo userInfo = userInfoService.findByUsername(username);
if(userInfo == null){
return null;
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户名
userInfo.getPassword(), //密码
ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt
getName() //realm name
);
return authenticationInfo;
}
}
LoginController.java
loginUser方法进行登录信息的校验,根据shiro返回的不同异常进行提示
package com.springboot.demo.base.controller;
import com.springboot.demo.base.entity.UserInfo;
import com.springboot.demo.base.utils.Captcha;
import com.springboot.demo.base.utils.GifCaptcha;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.io.IOException;
import java.util.Random;
@Controller
@RequestMapping("/login")
public class LoginController extends BaseController{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 获取验证码(Gif版本)
* @param response
*/
@RequestMapping(value="getGifCode",method = RequestMethod.GET)
public void getGifCode(HttpServletResponse response,HttpServletRequest request){
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/gif");
/**
* gif格式动画验证码
* 宽,高,位数。
*/
HttpSession session = request.getSession(true);
Captcha captcha = new GifCaptcha(146,33,4);
/* 输出 */
captcha.out(response.getOutputStream());
String vcodeText = captcha.text().toLowerCase();
//存入Session
session.setAttribute("_code",vcodeText);
logger.info("保存vcode:"+vcodeText);
System.out.println("------"+session.getAttribute("_code"));
} catch (Exception e) {
e.printStackTrace();
System.err.println("获取验证码异常:"+e.getMessage());
}
}
@RequestMapping("")
public String index(){
logger.info("初始化登录页面....");
return"/base/login";
}
@RequestMapping("/home")
public String home(HttpServletResponse response){
UserInfo ui = this.getCurrentUser();
if( ui == null ){
try {
response.sendRedirect("../login");
} catch (IOException e) {
e.printStackTrace();
}
}
logger.info("初始化home页面....");
return"/base/home";
}
@RequestMapping("/loginUser")
public String loginUser(HttpServletRequest request,String username,String password,String vcode) {
HttpSession session = request.getSession();
//转化成小写字母
vcode = vcode.toLowerCase();
String v = (String)session.getAttribute("_code");//还可以读取一次后把验证码清空,这样每次登录都必须获取验证码;
logger.info("获取保存vcode:"+v);
logger.info("验证vcode:"+vcode);
if(!vcode.equals(v)){
logger.info("对用户[" + username + "]验证码不通过");
request.setAttribute("message", "验证码不正确");
return "/base/login";//返回登录页面
}
logger.info("进行账号"+username+",密码验证"+password+".....");
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(usernamePasswordToken); //完成登录
UserInfo user=(UserInfo) subject.getPrincipal();
session.setAttribute("user", user);
session.setAttribute("clickId","home");
return "/base/loadHome";
}catch(UnknownAccountException uae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,未知账户");
request.setAttribute("message", "未知账户");
return "/base/login";//返回登录页面
}catch(IncorrectCredentialsException ice){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");
request.setAttribute("message", "密码不正确");
return "/base/login";//返回登录页面
}catch(LockedAccountException lae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");
request.setAttribute("message", "账户已锁定");
return "/base/login";//返回登录页面
}catch(ExcessiveAttemptsException eae){
logger.info("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");
request.setAttribute("message", "用户名或密码错误次数过多");
return "/base/login";//返回登录页面
}catch(AuthenticationException ae){
//通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
logger.info("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");
ae.printStackTrace();
request.setAttribute("message", "用户名或密码不正确");
return "/base/login";//返回登录页面
}
}
@RequestMapping("/logOut")
public String logOut(HttpSession session) {
Subject subject = SecurityUtils.getSubject();
subject.logout();
session.removeAttribute("user");
return "/base/login";
}
@RequestMapping("/403")
public String unauthorizedRole(){
System.out.println("------没有权限-------");
return "403";
}
/**
* 给定范围获得随机颜色
* @param fc
* @param bc
* @return
*/
private Color getRandColor(int fc, int bc) {
Random random = new Random();
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
}
在ShiroConfig.java中我们开启了shiro鉴权的aop支持,下面我们看如何使用它,关于用户UserInfo的增删改查及service、dao不再列出。
新建StudentController.java,配置一个访问路径RequestMapping为student/studentView,在方法上加入shiro鉴权注解@RequiresPermissions("student:view"),这里注意,在界面上的配置如下图,和权限字符串保持一致即可。
这样我们就添加了一个学生管理菜单,后面将其分配给不同角色,那么属于该角色的用户将能够访问student/studentView的内容。
注意application.properties需配置静态资源的路径,否则会获取不到静态文件。
#数据源
spring.datasource.url=jdbc:mysql://localhost:3306/demo_test?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#热部署生效
spring.devtools.restart.enabled=true
#mvc静态文件配置
#/css/**,/js/**,/componets/**,/images/**
spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/static/,classpath:/templates/
最后给出完整的表结构和pom包
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50717
Source Host : localhost:3306
Source Database : demo_test
Target Server Type : MYSQL
Target Server Version : 50717
File Encoding : 65001
Date: 2018-09-01 20:17:12
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for hibernate_sequence
-- ----------------------------
DROP TABLE IF EXISTS `hibernate_sequence`;
CREATE TABLE `hibernate_sequence` (
`next_val` bigint(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of hibernate_sequence
-- ----------------------------
INSERT INTO `hibernate_sequence` VALUES ('10');
INSERT INTO `hibernate_sequence` VALUES ('10');
INSERT INTO `hibernate_sequence` VALUES ('10');
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` int(11) NOT NULL,
`available` bit(1) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`number_sort` datetime DEFAULT NULL,
`parent_id` bigint(20) DEFAULT NULL,
`parent_ids` varchar(255) DEFAULT NULL,
`permission` varchar(255) DEFAULT NULL,
`resource_type` enum('menu','button') DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', '\0', '用户管理', '2018-06-25 11:30:51', '0', '0/', 'userInfo:view', 'menu', 'userInfo/userView');
INSERT INTO `sys_permission` VALUES ('2', '\0', '用户添加', '2018-06-25 11:34:51', '1', '0/1', 'userInfo:add', 'button', 'userInfo/userAdd');
INSERT INTO `sys_permission` VALUES ('3', '\0', '用户禁用', '2018-06-25 11:35:51', '1', '0/1', 'userInfo:del', 'button', 'userInfo/updateState');
INSERT INTO `sys_permission` VALUES ('4', '\0', '角色管理', '2018-06-25 11:40:51', '0', null, 'roleInfo:view', 'menu', 'roleInfo/roleView');
INSERT INTO `sys_permission` VALUES ('5', '\0', '资源管理', '2018-06-25 11:40:51', '0', null, 'sysPermission:view', 'menu', 'sysPermission/permissionView');
INSERT INTO `sys_permission` VALUES ('9', '\0', '学生管理', '2018-09-01 20:08:46', '0', null, 'student:view', 'menu', 'student/studentView');
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(11) NOT NULL,
`available` bit(1) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`role` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('2', '\0', '新注册用户', '新用户');
INSERT INTO `sys_role` VALUES ('1', '\0', '管理员', 'admin');
-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
`permission_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
KEY `FK9q28ewrhntqeipl1t04kh1be7` (`role_id`),
KEY `FKomxrs8a388bknvhjokh440waq` (`permission_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES ('5', '1');
INSERT INTO `sys_role_permission` VALUES ('4', '1');
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('3', '1');
INSERT INTO `sys_role_permission` VALUES ('2', '1');
INSERT INTO `sys_role_permission` VALUES ('6', '1');
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`uid` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
KEY `FKhh52n8vd4ny9ff4x9fb8v65qx` (`role_id`),
KEY `FKgkmyslkrfeyn9ukmolvek8b8f` (`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(255) NOT NULL,
`create_date` datetime DEFAULT NULL,
`update_date` datetime DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('56a514fc657d4dc09cb12b09f39d6846', '2018-08-28 01:42:20', '2018-08-28 01:42:20', '0', '老王的儿子');
INSERT INTO `user` VALUES ('c9e56bc8d15c45bb838a63786f931908', '2018-08-28 15:07:32', null, '25', '老王');
INSERT INTO `user` VALUES ('739086403d084de397282e8173d29f73', '2018-08-28 15:35:44', null, '22', '老王2');
INSERT INTO `user` VALUES ('c6bae69dad8c4b538ad4bafd435837c3', '2018-08-28 16:46:02', null, '18', '老王4');
-- ----------------------------
-- Table structure for user_info
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`uid` int(11) NOT NULL,
`create_date` datetime DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`reason` varchar(255) DEFAULT NULL,
`remarks` varchar(255) DEFAULT NULL,
`salt` varchar(255) DEFAULT NULL,
`state` int(11) NOT NULL,
`update_date` datetime DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY `UK_f2ksd6h8hsjtd57ipfq9myr64` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES ('1', '2018-06-23 17:07:40', '管理员', 'd3c59d25033dbf980d29554025c23a75', null, null, null, '8d78869f470951332959580424d4bf4f', '1', '2018-08-31 15:56:33', 'admin');
INSERT INTO `user_info` VALUES ('3', '2018-08-31 16:13:53', '张三', '79332ad51f315fdcdaaa0394c46ffcd7', null, null, '', '8d78869f470951332959580424d4bf4f', '0', '2018-08-31 16:13:53', 'zhangsan');
4.0.0
com.springboot
springbootJpa
0.0.1-SNAPSHOT
war
springbootJpa
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-tomcat
org.springframework.boot
spring-boot-starter-data-jpa
org.hibernate
hibernate-entitymanager
org.hibernate
hibernate-core
org.hibernate
hibernate-core
5.2.10.Final
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-mail
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.shiro
shiro-core
1.2.2
org.apache.shiro
shiro-spring
1.2.2
org.apache.shiro
shiro-ehcache
1.2.2
net.sf.json-lib
json-lib
2.4
jdk15
org.springframework.boot
spring-boot-devtools
true
org.springframework.boot
spring-boot-maven-plugin
全文完,2018/9/1
写博文不易,转载请注明出处。