正好这几天不是那么忙,所以就研究了一下Spring Security的使用,为了以后方便写篇帖子记录一下。
1.什么是Spring Security?
我想关于什么是Spring Security我都不需要在这里赘述,大家可以到网上百度一下,但是问了大家能快速的融入还是贴一下
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency
Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
2.Spring Security有什么?
我们可以使用Spring Security做基于表单的登录认证(form-login)、弹窗的登录认证(http-basic)、对受保护资源的访问控制、单点登录等等。
3.要怎么使用Spring Security?
对于SpringSecurity的登录认证和密码加密等现在都不做讨论,主要说一下对受保护资源的访问控制。
在Spring Security中最做URL权限鉴定最关键的一个类就是FilterSecurityInterceptor,FilterSecurityInterceptor中还需要2个关键的类AccessDecisionManager 和SecurityMetadataSource,这是2个接口类,我们主要的的是他们的实现类。
他们的作用分别是:
AccessDecisionManager做权限的验证
主要方法就是:
void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) ,
SecurityMetadataSource是注入元数据
主要方法是:
public Collection<ConfigAttribute> getAttributes(Object object)
public Collection<ConfigAttribute> getAllConfigAttributes()
开始设计了
主要的domain类
- User
- UserGroup
- Role
- Permission
- Menu
- Resource
这里重点贴一下User.java和Role.java
User.java
package org.ylez.web.domain; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import javax.persistence.*; import java.util.*; /** * @FileName: User * @Author: 唐欢 * @Date: 2016-05-09 22:14 * @Tool: IntelliJ IDEA */ @Entity @Table(name = "t_user") public class User extends SuperClass implements UserDetails { @Column(unique = true, nullable = false, length = 30) private String username; @Column(nullable = false, length = 30) private String password; private int age; @Column(unique = true) private String email; @Column(unique = true, length = 11) private String phone; @ManyToMany(targetEntity = UserGroup.class, mappedBy = "users") private Set<UserGroup> userGroup = new HashSet(); @ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER) @JoinTable(name = "m_user_role", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = {@JoinColumn(name = "role_id")}) private Set<Role> roles = new HashSet<>(); @Transient private Set<Role> authorities = new HashSet<>(); @Override public Collection<? extends GrantedAuthority> getAuthorities() { // 包裹用户单独赋予的角色 authorities.addAll(roles); return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public Set<UserGroup> getUserGroup() { return userGroup; } public void setUserGroup(Set<UserGroup> userGroup) { this.userGroup = userGroup; } public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } public void setAuthorities(Set<Role> authorities) { this.authorities = authorities; } }
Role.java
package org.ylez.web.domain; import org.springframework.security.core.GrantedAuthority; import javax.persistence.*; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @FileName: Role * @Author: 唐欢 * @Date: 2016-05-12 18:15 * @Tool: IntelliJ IDEA */ @Entity @Table(name = "t_role") public class Role extends SuperClass implements GrantedAuthority { @Column(nullable = false, length = 30) private String name; @Column(nullable = false, length = 30) private String nickName; private String comment; @ManyToMany(targetEntity = Permission.class, fetch = FetchType.EAGER) @JoinTable(name = "m_role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")}) private Set<Permission> permissions = new HashSet<>(); @ManyToMany(targetEntity = User.class, mappedBy = "roles") private Set<User> users = new HashSet<>(); @ManyToMany(targetEntity = UserGroup.class, mappedBy = "roles") private Set<UserGroup> userGroups = new HashSet<>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public Set<Permission> getPermissions() { return permissions; } public void setPermissions(Set<Permission> permissions) { this.permissions = permissions; } public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } public Set<UserGroup> getUserGroups() { return userGroups; } public void setUserGroups(Set<UserGroup> userGroups) { this.userGroups = userGroups; } @Override public String getAuthority() { return name; } }
创建UserDetailsService在登录的时候加载用户信息
package org.ylez.web.security.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.ylez.web.domain.Role; import org.ylez.web.domain.User; import org.ylez.web.domain.UserGroup; import org.ylez.web.service.UserService; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @FileName: UserDetailsServiceImpl * @Author: 唐欢 * @Date: 2016-05-10 09:39 * @Tool: IntelliJ IDEA */ public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.loadUserByUsername(username); if (user != null) { Set<UserGroup> userGroup = user.getUserGroup(); for (UserGroup group : userGroup) { Set<Role> roles = group.getRoles(); user.setAuthorities(roles); } return user; }else { throw new UsernameNotFoundException("找不到指定的用户信息!!!"); } } }
注意:
for (UserGroup group : userGroup) { Set<Role> roles = group.getRoles(); user.setAuthorities(roles); }
这里我讲用户所在的用户组所具有的角色也放置到用的authorities中
接下类创建一个AuthorizationSecurityInterceptor.java的类源码如下:
package org.ylez.web.security.interceptor; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; /** * @FileName: AuthorizationSecurityInterceptor * @Author: 唐欢 * @Date: 2016-05-12 17:24 * @Tool: IntelliJ IDEA */ public class AuthorizationSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { private static final String FILTER_APPLIED = "__Spring_Security_AuthorizationSecurityInterceptor_FilterApplied"; private FilterInvocationSecurityMetadataSource securityMetadataSource; private boolean observeOncePerRequest = true; @Override public void init(FilterConfig arg0) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return this.securityMetadataSource; } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) { this.securityMetadataSource = newSource; } @Override public Class<?> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null) && observeOncePerRequest) { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } else { if (fi.getRequest() != null) { fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.finallyInvocation(token); } super.afterInvocation(token, null); } } public boolean isObserveOncePerRequest() { return observeOncePerRequest; } public void setObserveOncePerRequest(boolean observeOncePerRequest) { this.observeOncePerRequest = observeOncePerRequest; } }
AuthorizationSecurityInterceptor的作用就是做URL的访问控制,需要注入AccessDecisionManager 和SecurityMetadataSource,可能有会奇怪为啥还要实现AuthorizationSecurityInterceptor,Spring Security不是为我们提供了FilterSecurityInterceptor吗?主要是SpringSecurity内部维护了一个FilterChain这个FilterChain是有一定的顺序的我们不能随便打乱,默认的FilterSecurityInterceptor也不太符合我们的需求,所以创建了AuthorizationSecurityInterceptor。
接下来创建AccessDecisionManagerImpl.java:
package org.ylez.web.security.accessdecisionmanager; import org.springframework.context.MessageSource; import org.springframework.context.support.MessageSourceAccessor; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.util.StringUtils; import org.ylez.web.domain.Role; import java.util.Collection; /** * @FileName: AccessDecisionManagerImpl * @Author: 唐欢 * @Date: 2016-05-12 17:27 * @Tool: IntelliJ IDEA */ public class AccessDecisionManagerImpl implements AccessDecisionManager { protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); /** * @param authentication 当前认证通过的用户的认证信息 * @param object 当前用户访问的受保护资源,如URL * @param configAttributes 当前受保护资源需要的角色,权限 * @throws AccessDeniedException * @throws InsufficientAuthenticationException */ @Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); for (GrantedAuthority authority : authorities) { // 角色名 String roleName = authority.getAuthority(); for (ConfigAttribute configAttribute : configAttributes) { if (configAttribute != null && !StringUtils.isEmpty(roleName)) { if (configAttribute.getAttribute().equals(roleName)) { return; } } } } throw new AccessDeniedException(messages.getMessage( "AbstractAccessDecisionManager.accessDenied", "Access is denied")); } public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } /** * @param attribute 权限信息 * @return */ @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class<?> clazz) { return true; } }
AccessDecisionManagerImpl中的decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)方法注入了三个参数
Authentication authentication 是用户登录成功后的认证信息包含了当前用户所具有的角色信息。
Object object 是当前用户请求的受保护的资源。
Collection<ConfigAttribute> configAttributes 是当前用户请求的受保护资源应该具备的角色。
decide方法的逻辑就是将authentication中包含的角色和configAttributes中的角色进行比较,看authentication中是否有configAttributes种需要的角色,如果有就标识权限认证成功直接return方法就好如果没有就抛出异常throw
new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));。
接下来再创建FilterInvocationSecurityMetadataSourceImpl.java:
package org.ylez.web.security.metadatasource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import org.ylez.web.domain.Permission; import org.ylez.web.domain.Resource; import org.ylez.web.domain.Role; import org.ylez.web.service.ResourceService; import java.util.*; /** * @FileName: FilterInvocationSecurityMetadataSourceImpl * @Author: 唐欢 * @Date: 2016-05-12 17:24 * @Tool: IntelliJ IDEA */ public class FilterInvocationSecurityMetadataSourceImpl implements FilterInvocationSecurityMetadataSource { @Autowired private ResourceService resourceService; private Map<String, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();; /** * @param object 当前用户访问的受保护的资源 * @return * @throws IllegalArgumentException */ @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { System.err.println("-----------------------FilterInvocationSecurityMetadataSourceImpl.getAttributes-----------------------"); String address = ((FilterInvocation) object).getRequestUrl(); Resource resource = resourceService.findByAddress(address); if (resource != null) { String resourceName = resource.getName(); Collection<ConfigAttribute> configAttributes = requestMap.get(resourceName); return configAttributes; } return new HashSet<>(); } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { System.err.println("+++++++++++++++++++FilterInvocationSecurityMetadataSourceImpl.getAllConfigAttributes+++++++++++++++++++"); Set<ConfigAttribute> allAttributes = new HashSet<>(); List<Resource> resourceList = resourceService.findAll(); for (Resource resource : resourceList) { Set<ConfigAttribute> itemAttributes = new HashSet<>(); Set<Permission> permissions = resource.getPermissions(); for (Permission permission : permissions) { Set<Role> roles = permission.getRoles(); for (Role role : roles) { ConfigAttribute ca = new SecurityConfig(role.getAuthority()); // 每一个请求资源对应的Role itemAttributes.add(ca); // 所有的Role对象 allAttributes.add(ca); } } String resourceName = resource.getName(); requestMap.put(resourceName, itemAttributes); } return allAttributes; } @Override public boolean supports(Class<?> clazz) { return true; } }
FilterInvocationSecurityMetadataSourceImpl中主要方法
public
Collection<ConfigAttribute> getAttributes(Object object)
public Collection<ConfigAttribute> getAllConfigAttributes()
getAllConfigAttributes() 是查询出所有的角色,该方法中我查询了所有的角色进行返回,该方法在程序启动的时候就会执行,所以做了一个requestMap
private Map<String, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();
来缓存请求资源和角色的对应关系。在getAttributes(Object
object)中我们就可以根据object直接从requestMap中取得。
getAttributes是根据访问的资源来查找对应所需角色,当请求过来时,我们可以根据参数object得到请求的URL去直接查询数据库,也可以在getAllConfigAttributes()查询所有做缓存我们从缓存中来查询,我这里做的还不是很好可以在优化一下。
现在就是在SecurityContext.xml中配置Spring Security了:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:settings.properties" /> <security:http pattern="/admin/login.html" security="none"/> <security:http pattern="/react/**" security="none"/> <security:http pattern="/static/**" security="none"/> <security:http auto-config="true"> <security:form-login login-page="/admin/login.html" login-processing-url="/admin/login.htm" username-parameter="username" password-parameter="password" default-target-url="/admin/index.html" always-use-default-target="true" /> <security:http-basic/> <security:remember-me remember-me-parameter="rememberMe" key="ylez-unique-key" remember-me-cookie="ylez" /> <security:logout logout-url="/logout.htm" invalidate-session="true" delete-cookies="ylez"/> <security:session-management invalid-session-url="/admin/login.html" session-fixation-protection="newSession"> <security:concurrency-control max-sessions="2" expired-url="/admin/login.html" /> </security:session-management> <security:port-mappings> <security:port-mapping http="80" https="443"/> </security:port-mappings> <security:csrf disabled="true"/> <security:custom-filter ref="authorizationSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> </security:http> <security:authentication-manager erase-credentials="false"> <security:authentication-provider user-service-ref="userDetailsService"> <security:password-encoder ref="passwordEncoder"> <security:salt-source ref="saltSource"/> </security:password-encoder> </security:authentication-provider> </security:authentication-manager> <!-- 密码加密工具,在用户注册的时候也是这个加密的工具. --> <bean id="passwordEncoder" class="org.ylez.web.security.password.PasswordEncoderImpl"> <!-- 密码加密的时候的散列算法 --> <constructor-arg name="algorithm" value="${passwordEncoder.algorithm}" /> <!-- 密码加密的时候的加密次数 --> <constructor-arg name="iterations" value="${passwordEncoder.iterations}" /> </bean> <bean id="saltSource" class="org.ylez.web.security.salt.SaltSourceImpl" /> <bean id="authorizationSecurityInterceptor" class="org.ylez.web.security.interceptor.AuthorizationSecurityInterceptor"> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="securityMetadataSource" ref="securityMetadataSource" /> </bean> <bean id="accessDecisionManager" class="org.ylez.web.security.accessdecisionmanager.AccessDecisionManagerImpl" /> <bean id="securityMetadataSource" class="org.ylez.web.security.metadatasource.FilterInvocationSecurityMetadataSourceImpl" /> <bean id="userDetailsService" class="org.ylez.web.security.service.UserDetailsServiceImpl"/> </beans>
Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="org.ylez.web.config" /> <context:component-scan base-package="org.ylez.web.service" /> <context:property-placeholder location="classpath:settings.properties" /> <aop:aspectj-autoproxy expose-proxy="true"/> <import resource="securityContext.xml" /> </beans>
web.xml的配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 处理配置了懒加载的问题 --> <filter> <filter-name>openEntityManagerInViewFilter</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openEntityManagerInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置SpringSecurity的代理过滤器 --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置SpringMVC的Servlet --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:safeApp-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Jpa的配置:
package org.ylez.web.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * @FileName: JpaConfig * @Author: 唐欢 * @Date: 2016-05-11 14:15 * @Tool: IntelliJ IDEA */ @Configuration @EnableJpaRepositories(basePackages = "org.ylez.web.repository") @EnableTransactionManagement public class JpaConfig { @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/ylez?createDatabaseIfNotExist=true"); dataSource.setUsername("root"); dataSource.setPassword("admin"); dataSource.setInitialSize(10); dataSource.setMinIdle(10); dataSource.setMaxActive(50); dataSource.setMaxWait(60000); dataSource.setTimeBetweenConnectErrorMillis(60000); dataSource.setMinEvictableIdleTimeMillis(300000); dataSource.setValidationQuery(" SELECT 'x' "); dataSource.setTestWhileIdle(true); dataSource.setTestOnBorrow(false); dataSource.setTestOnReturn(false); dataSource.setPoolPreparedStatements(false); dataSource.setMaxPoolPreparedStatementPerConnectionSize(20); return dataSource; } @Bean public EntityManagerFactory entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean(); HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); adapter.setGenerateDdl(true); adapter.setDatabase(Database.MYSQL); adapter.setShowSql(true); entityManagerFactory.setJpaVendorAdapter(adapter); entityManagerFactory.setDataSource(dataSource()); entityManagerFactory.setPackagesToScan("org.ylez.web.domain"); Map<String, Object> propsMap = new HashMap<>(); propsMap.put("hibernate.format_sql", true); propsMap.put("hibernate.dialect", "org.hibernate.dialect.MySQL57InnoDBDialect"); entityManagerFactory.setJpaPropertyMap(propsMap); entityManagerFactory.afterPropertiesSet(); return entityManagerFactory.getObject(); } @Bean public PlatformTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory()); return transactionManager; } }
SQL代码:
/* Navicat Premium Data Transfer Source Server : 127.0.0.1 Source Server Type : MySQL Source Server Version : 50711 Source Host : 127.0.0.1 Source Database : ylez Target Server Type : MySQL Target Server Version : 50711 File Encoding : utf-8 Date: 05/17/2016 00:15:22 AM */ SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `m_permission_menu` -- ---------------------------- DROP TABLE IF EXISTS `m_permission_menu`; CREATE TABLE `m_permission_menu` ( `permission_id` bigint(20) NOT NULL, `menu_id` bigint(20) NOT NULL, PRIMARY KEY (`permission_id`,`menu_id`), KEY `FKrck475a4xibvhvbipdsbml4jo` (`menu_id`), CONSTRAINT `FK892mp1voq26r0krjfnoqqfy8e` FOREIGN KEY (`permission_id`) REFERENCES `t_permission` (`id`), CONSTRAINT `FKrck475a4xibvhvbipdsbml4jo` FOREIGN KEY (`menu_id`) REFERENCES `t_menu` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `m_permission_resource` -- ---------------------------- DROP TABLE IF EXISTS `m_permission_resource`; CREATE TABLE `m_permission_resource` ( `permission_id` bigint(20) NOT NULL, `resource_id` bigint(20) NOT NULL, PRIMARY KEY (`permission_id`,`resource_id`), KEY `FKqiqcr9msd3laua6pgk03gthth` (`resource_id`), CONSTRAINT `FK5wgud3b6ohn30iix2c4dhxgmm` FOREIGN KEY (`permission_id`) REFERENCES `t_permission` (`id`), CONSTRAINT `FKqiqcr9msd3laua6pgk03gthth` FOREIGN KEY (`resource_id`) REFERENCES `t_resource` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `m_permission_resource` -- ---------------------------- BEGIN; INSERT INTO `m_permission_resource` VALUES ('1', '1'), ('2', '2'); COMMIT; -- ---------------------------- -- Table structure for `m_role_permission` -- ---------------------------- DROP TABLE IF EXISTS `m_role_permission`; CREATE TABLE `m_role_permission` ( `role_id` bigint(20) NOT NULL, `permission_id` bigint(20) NOT NULL, PRIMARY KEY (`role_id`,`permission_id`), KEY `FKjsv718s6pysaxl3hwdbh32v16` (`permission_id`), CONSTRAINT `FK71nkax6g3ndcd1q4iue3xfksb` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`), CONSTRAINT `FKjsv718s6pysaxl3hwdbh32v16` FOREIGN KEY (`permission_id`) REFERENCES `t_permission` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `m_role_permission` -- ---------------------------- BEGIN; INSERT INTO `m_role_permission` VALUES ('1', '1'), ('1', '2'), ('2', '2'); COMMIT; -- ---------------------------- -- Table structure for `m_user_role` -- ---------------------------- DROP TABLE IF EXISTS `m_user_role`; CREATE TABLE `m_user_role` ( `user_id` bigint(20) NOT NULL, `role_id` bigint(20) NOT NULL, PRIMARY KEY (`user_id`,`role_id`), KEY `FK3kaylpusfxvtsulifg7u1o0cj` (`role_id`), CONSTRAINT `FK3kaylpusfxvtsulifg7u1o0cj` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`), CONSTRAINT `FK6520i3b07huaey0kr9fw49ln` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `m_user_role` -- ---------------------------- BEGIN; INSERT INTO `m_user_role` VALUES ('1', '1'), ('2', '2'); COMMIT; -- ---------------------------- -- Table structure for `m_usergroup_role` -- ---------------------------- DROP TABLE IF EXISTS `m_usergroup_role`; CREATE TABLE `m_usergroup_role` ( `usergroup_id` bigint(20) NOT NULL, `role_id` bigint(20) NOT NULL, PRIMARY KEY (`usergroup_id`,`role_id`), KEY `FKecy0fvxdsy58ku64uhsd1y1qd` (`role_id`), CONSTRAINT `FKecy0fvxdsy58ku64uhsd1y1qd` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`), CONSTRAINT `FKksc98i8kfc50g8bo4imvep8uk` FOREIGN KEY (`usergroup_id`) REFERENCES `t_usergroup` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `m_usergroup_role` -- ---------------------------- BEGIN; INSERT INTO `m_usergroup_role` VALUES ('1', '1'), ('1', '2'); COMMIT; -- ---------------------------- -- Table structure for `m_usergroup_user` -- ---------------------------- DROP TABLE IF EXISTS `m_usergroup_user`; CREATE TABLE `m_usergroup_user` ( `usergroup_id` bigint(20) NOT NULL, `user_id` bigint(20) NOT NULL, PRIMARY KEY (`usergroup_id`,`user_id`), KEY `FKl53jhmxcy4qy79chcy26wlw4a` (`user_id`), CONSTRAINT `FKl53jhmxcy4qy79chcy26wlw4a` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`), CONSTRAINT `FKml2qomhd7tkphcypjel80kbgj` FOREIGN KEY (`usergroup_id`) REFERENCES `t_usergroup` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `m_usergroup_user` -- ---------------------------- BEGIN; INSERT INTO `m_usergroup_user` VALUES ('1', '1'); COMMIT; -- ---------------------------- -- Table structure for `t_menu` -- ---------------------------- DROP TABLE IF EXISTS `t_menu`; CREATE TABLE `t_menu` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `icon` varchar(30) DEFAULT NULL, `level` varchar(30) NOT NULL, `name` varchar(30) NOT NULL, `status` int(11) NOT NULL, `url` varchar(50) NOT NULL, `parent_id` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK4paxqyebl0scq6ur9osr0f56k` (`parent_id`), CONSTRAINT `FK4paxqyebl0scq6ur9osr0f56k` FOREIGN KEY (`parent_id`) REFERENCES `t_menu` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `t_permission` -- ---------------------------- DROP TABLE IF EXISTS `t_permission`; CREATE TABLE `t_permission` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, `name` varchar(30) NOT NULL, `nickName` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `t_permission` -- ---------------------------- BEGIN; INSERT INTO `t_permission` VALUES ('1', '2016-05-16 17:18:41.000000', b'1', '2016-05-16 17:18:47.000000', '访问管理后台', 'MANAGE_INDEX', '管理后台'), ('2', '2016-05-16 17:19:36.000000', b'1', '2016-05-16 17:19:42.000000', '网站前台', 'INDEX', '网站前台'); COMMIT; -- ---------------------------- -- Table structure for `t_resource` -- ---------------------------- DROP TABLE IF EXISTS `t_resource`; CREATE TABLE `t_resource` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `address` varchar(30) NOT NULL, `name` varchar(30) NOT NULL, `type` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `t_resource` -- ---------------------------- BEGIN; INSERT INTO `t_resource` VALUES ('1', '2016-05-16 17:35:56.000000', b'1', '2016-05-16 17:36:03.000000', '/admin/index.html', 'admin_index', 'a'), ('2', '2016-05-16 17:37:20.000000', b'1', '2016-05-16 17:37:25.000000', '/index.html', 'index', 'b'); COMMIT; -- ---------------------------- -- Table structure for `t_role` -- ---------------------------- DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, `name` varchar(30) NOT NULL, `nickName` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `t_role` -- ---------------------------- BEGIN; INSERT INTO `t_role` VALUES ('1', '2016-05-16 17:16:42.000000', b'1', '2016-05-16 17:16:48.000000', '管理员', 'ADMIN', '管理员'), ('2', '2016-05-16 17:17:17.000000', b'1', '2016-05-16 17:17:24.000000', '普通用户', 'USER', '会员'); COMMIT; -- ---------------------------- -- Table structure for `t_user` -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `age` int(11) NOT NULL, `email` varchar(255) DEFAULT NULL, `password` varchar(30) NOT NULL, `phone` varchar(11) DEFAULT NULL, `username` varchar(30) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_jhib4legehrm4yscx9t3lirqi` (`username`), UNIQUE KEY `UK_i6qjjoe560mee5ajdg7v1o6mi` (`email`), UNIQUE KEY `UK_m5bu5erj83eubjsa1nyms0t89` (`phone`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `t_user` -- ---------------------------- BEGIN; INSERT INTO `t_user` VALUES ('1', '2016-05-16 17:14:58.000000', b'1', '2016-05-16 17:15:04.000000', '23', '[email protected]', 'tanghuan', '18280206033', 'tanghuan'), ('2', '2016-05-16 17:15:43.000000', b'1', '2016-05-16 17:15:50.000000', '22', '[email protected]', 'xuran', '12345678987', 'xuran'); COMMIT; -- ---------------------------- -- Table structure for `t_usergroup` -- ---------------------------- DROP TABLE IF EXISTS `t_usergroup`; CREATE TABLE `t_usergroup` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `createTime` datetime(6) DEFAULT NULL, `enabled` bit(1) NOT NULL, `updateTime` datetime(6) DEFAULT NULL, `comment` varchar(255) DEFAULT NULL, `groupNum` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_daw8uwu1enonbvfjg2oau9gdm` (`groupNum`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `t_usergroup` -- ---------------------------- BEGIN; INSERT INTO `t_usergroup` VALUES ('1', '2016-05-16 23:53:32.000000', b'1', '2016-05-16 23:53:40.000000', '管理员组', '123456789', 'MANAGER_GROUP'); COMMIT; SET FOREIGN_KEY_CHECKS = 1;
附项目的结构图:
演示效果图:
欢迎大家吐槽