一、预览,这是一个怎样的项目
1.登录模块,包含注册功能,动态GIF验证码
2.管理员登录后台界面,包含权限模块最基本的用户管理、角色管理、资源管理。
3.用户管理包括最基本的增删改查+角色分配+状态修改
4.添加用户界面
5.为用户分配角色
6.为角色分配资源
7.资源的新建删除及修改
以上就是整个权限管理系统的界面浏览,下面将整理出完整的实现代码。
二、项目构建目录和maven依赖
关键maven依赖
<!-- shiro spring. -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- shiro ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
三、Shiro配置
首先需要一个用户实体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<SysRole> 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<SysRole> getRoleList() {
return roleList;
}
public void setRoleList(List<SysRole> 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<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
// 配置不会被拦截的链接 顺序判断
//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
<groupId>com.springboot</groupId>
<artifactId>springbootJpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springbootJpa</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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>
<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-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- shiro spring. -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- shiro ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>