SSM框架整合SpringSecurity實現權限管理實例 javaconfig配置方式

1.前言

本文講述使用javaconfig的方式整合SpringMVC+Mybatis+SpringSecurity實現基於數據庫的權限系統,包括對按鈕的權限控制。

使用技術: springMVC、springsecurity4、mybatis、ehcache、前端使用dataTables表格、ztree。

2.表結構介紹

SSM框架整合SpringSecurity實現權限管理實例 javaconfig配置方式

標準的五張表結構。其中t_resources包含了後臺系統的菜單

SSM框架整合SpringSecurity實現權限管理實例 javaconfig配置方式

五張表分別為用戶表,角色表,資源表,用戶角色表,角色資源表。
給用戶分配角色,給角色配置權限。形成動態的權限控制。一個用戶可以擁有多個角色,一個角色也可以擁有多個資源(即權限)。

3.mavne配置

<properties> /<properties>

<spring.version>4.3.5.RELEASE/<spring.version>

<springsecurity.version>4.2.1.RELEASE/<springsecurity.version>

<dependencies>

<dependency>

<groupid>org.springframework/<groupid>

<artifactid>spring-webmvc/<artifactid>

<version>${spring.version}/<version>

<dependency>

<groupid>org.springframework/<groupid>

<artifactid>spring-context-support/<artifactid>

<version>${spring.version}/<version>

<dependency>

<groupid>org.springframework.security/<groupid>

<artifactid>spring-security-web/<artifactid>

<version>${springsecurity.version}/<version>

<dependency>

<groupid>org.springframework.security/<groupid>

<artifactid>spring-security-config/<artifactid>

<version>${springsecurity.version}/<version>

<dependency>

<groupid>org.springframework.security/<groupid>

<artifactid>spring-security-taglibs/<artifactid>

<version>${springsecurity.version}/<version>

<dependency>

<groupid>mysql/<groupid>

<artifactid>mysql-connector-java/<artifactid>

<version>5.1.27/<version>

<type>jar/<type>

<scope>compile/<scope>

<dependency>

<groupid>javax.servlet/<groupid>

<artifactid>javax.servlet-api/<artifactid>

<version>3.1.0/<version>

<scope>provided/<scope>

<dependency>

<groupid>jstl/<groupid>

<artifactid>jstl/<artifactid>

<version>1.2/<version>

<dependency>

<groupid>javax.servlet/<groupid>

<artifactid>jsp-api/<artifactid>

<version>2.0/<version>

<scope>provided/<scope>

<dependency>

<groupid>commons-logging/<groupid>

<artifactid>commons-logging/<artifactid>

<version>1.2/<version>

<dependency>

<groupid>org.mybatis/<groupid>

<artifactid>mybatis/<artifactid>

<version>3.3.0/<version>

<dependency> /<dependency>

<groupid>org.mybatis/<groupid>

<artifactid>mybatis-spring/<artifactid>

<version>1.2.2/<version>

<dependency>

<groupid>junit/<groupid>

<artifactid>junit/<artifactid>

<version>4.12/<version>

<scope>test/<scope>

<dependency>

<groupid>org.springframework/<groupid>

<artifactid>spring-test/<artifactid>

<version>${spring.version}/<version>

<scope>test/<scope>

<dependency>

<groupid>com.alibaba/<groupid>

<artifactid>fastjson/<artifactid>

<version>1.2.15/<version>

<dependency> /<dependency>

<groupid>com.github.pagehelper/<groupid>

<artifactid>pagehelper/<artifactid>

<version>4.1.4/<version>

<dependency>

<groupid>commons-dbcp/<groupid>

<artifactid>commons-dbcp/<artifactid>

<version>1.4/<version>

<dependency>

<groupid>net.sf.ehcache/<groupid>

<artifactid>ehcache/<artifactid>

<version>2.7.5/<version>

<dependency>

<groupid>org.slf4j/<groupid>

<artifactid>slf4j-api/<artifactid>

<version>1.7.18/<version>

<dependency>

<groupid>org.slf4j/<groupid>

<artifactid>slf4j-log4j12/<artifactid>

<version>1.7.18/<version>

<dependency>

<groupid>org.apache.logging.log4j/<groupid>

<artifactid>log4j-core/<artifactid>

<version>2.5/<version>

4.搭建SpringMVC

首先配置DispatcherServlet:

package com.study.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebProjectConfigInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

/**

* 加載驅動應用後端的中間層和數據層組件

*/

@Override

protected Class>[] getRootConfigClasses() {

return new Class[]{RootConfig.class};

}

/** 指定配置類

* 加載包含web組件的bean,如控制機器、視圖解析器以及映射處理器

*/

@Override

protected Class>[] getServletConfigClasses() {

return new Class[]{WebConfig.class};

}

//將DispatcherServlet 映射到“/”

@Override

protected String[] getServletMappings() {

return new String[] { "/" };

}

}

WebConfig:

主要加載包含WEB的組件bean。如控制器、視圖解析器以及處理映射處理器

package com.study.config;

import java.util.List;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.http.converter.HttpMessageConverter;

import org.springframework.web.servlet.ViewResolver;

import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.servlet.view.InternalResourceViewResolver;

import org.springframework.web.servlet.view.JstlView;

import com.alibaba.fastjson.serializer.SerializerFeature;

import com.alibaba.fastjson.support.config.FastJsonConfig;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;

@Configuration

@EnableWebMvc

@ComponentScan("com.study.controller")

public class WebConfig extends WebMvcConfigurerAdapter {

@Bean

public ViewResolver viewResolver(){

InternalResourceViewResolver resolver = new InternalResourceViewResolver();

resolver.setPrefix("/jsp/");

resolver.setSuffix(".jsp");

resolver.setExposeContextBeansAsAttributes(true);

resolver.setViewClass(JstlView.class);

return resolver;

}

//配置靜態資源的處理 使DispatcherServlet對靜態資源的請求轉發到Servlet容器默認的Servlet上,而不是使用DispatcherServlet本身來處理此類請求

@Override

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

configurer.enable();

}

/* @Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css");

registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js");

registry.addResourceHandler("/img/**").addResourceLocations("classpath:/img");

}*/

@Override

public void configureMessageConverters(List<httpmessageconverter>> converters) {/<httpmessageconverter>

super.configureMessageConverters(converters);

FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

FastJsonConfig fastJsonConfig = new FastJsonConfig();

fastJsonConfig.setSerializerFeatures(

SerializerFeature.PrettyFormat

);

fastConverter.setFastJsonConfig(fastJsonConfig);

converters.add(fastConverter);

}

}

RootConfig:

主要加載應用中其他bean。這些bean通常是驅動應用後端的中間層和數據層組件。

package com.study.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.ComponentScan.Filter;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.FilterType;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration

@ComponentScan(basePackages={"com.study"},excludeFilters={@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)})

public class RootConfig {

}

5.配置Spring Security

配置Delegating-FilterProxy

package com.study.config;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

/**

* 配置Delegating-FilterProxy

* 繼承AbstractSecurityWebApplicationInitializer會自動註冊DelegatingFilterProxy

* 等價於xml配置

* <filter>

<filter-name>springSecurityFilterChain/<filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy/<filter-class>

*

*

*/

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer{

}

Spring Security 安全配置

package com.study.config;

import javax.annotation.Resource;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.encoding.Md5PasswordEncoder;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.builders.WebSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.study.security.MyFilterSecurityInterceptor;

@Configuration

@EnableWebSecurity

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

// @Resource

// private DataSource dataSource;

@Resource(name="myUserDetailService")

private UserDetailsService myUserDetailService;

@Resource

private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

// @Override

// public AuthenticationManager authenticationManagerBean() throws Exception {

// return super.authenticationManagerBean();

// }

@Override

public void configure(WebSecurity web)throws Exception {

// 設置不攔截規則

web.ignoring().antMatchers("/css/**","/js/**","/img/**","/font-awesome/**");

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http

.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)//在正確的位置添加我們自定義的過濾器

.authorizeRequests()

.anyRequest().authenticated()

// .and().formLogin().and()

// .httpBasic();

// 自定義登錄頁面

.and()

.formLogin().loginPage("/jsp/login.jsp")

.failureUrl("/jsp/login.jsp?error=1")

.loginProcessingUrl("/spring_security_check")

.usernameParameter("username")

.passwordParameter("password").permitAll().defaultSuccessUrl("/index.do");

//如果開啟了CSRF 退出則需要使用POST訪問,可以使用以下方式解決,但並不推薦

http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))

// 登陸成功後跳轉的地址,以及刪除的cookie名稱

.logoutSuccessUrl("/jsp/login.jsp?error=logout")

.invalidateHttpSession(true);

}

@Override

protected void configure(AuthenticationManagerBuilder auth)

throws Exception {

//啟用內存用戶存儲

/*auth.inMemoryAuthentication()

.withUser("user1").password("123456").roles("USER").and()

.withUser("admin").password("admin").roles("USER","ADMIN");*/

//

//給予數據庫表認證

/*auth.jdbcAuthentication().dataSource(dataSource)

.usersByUsernameQuery("select username,password,enable from t_user where username=?")

.authoritiesByUsernameQuery("select username,rolename from t_role where username=?");

*/

//配置自定義的用戶服務

auth.userDetailsService(myUserDetailService).passwordEncoder(new Md5PasswordEncoder());

}

}

解釋:以上代碼實現了Spring Security 安全配置。其中@EnableWebSecurity註解將會啟用WEB安全功能。

configure(WebSecurity web) 通過重載,配置Spring Security 的Filter鏈。

configure(HttpSecurity http)通過重載,配置如何通過攔截器保護請求。以上代碼配置了自定義的過濾器 、自定義登錄頁面、和退出功能。其中自定義的過濾器相當於配置了對資源的授權。

configure(AuthenticationManagerBuilder auth)通過重載,配置user_detail服務,其中可以使用基於內存用戶存儲、基於數據庫表進行認證、基於LDAP進行認證,以及自定義的用戶服務。以上代碼沒註釋的就是本文基於數據庫的自定義權限認證。

自定義認證:

就是在登錄時的認證操作交給Spring Security.在此處需要提供給當前登錄用戶所擁有的權限。即根據用戶名查詢上面t_resources表中的resKey 拼湊成”ROLE_XXX“ 這樣形式的字符串所組成的list ,交給spirngSecurity。

package com.study.security;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import javax.annotation.Resource;

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.springframework.stereotype.Component;

import com.study.model.Resources;

import com.study.model.User;

import com.study.service.ResourcesService;

import com.study.service.UserService;

@Component("myUserDetailService")

public class MyUserDetailServiceImpl implements UserDetailsService{

@Resource

private UserService userService;

@Resource

private ResourcesService resourcesService;

@Override

public UserDetails loadUserByUsername(String username)

throws UsernameNotFoundException {

User user = userService.findUserByName(username);

if(user ==null)

throw new UsernameNotFoundException(username+" not exist!");

Set<grantedauthority> authSet = new HashSet<grantedauthority>();/<grantedauthority>/<grantedauthority>

Resources resources = new Resources();

resources.setUsername(username);

List<resources> list = resourcesService.loadMenu(resources);/<resources>

for (Resources r : list) {

authSet.add(new SimpleGrantedAuthority("ROLE_" +r.getResKey()));

}

return new org.springframework.security.core.userdetails.User(user.getUsername(),

user.getPassword(),

user.getEnable()==1?true:false,

true,

true,

true,

authSet);

}

}

自定義過濾器

使訪問程序時,檢查當前用戶是否擁有當前url的權限

package com.study.security;

import java.io.IOException;

import javax.annotation.PostConstruct;

import javax.annotation.Resource;

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.beans.factory.annotation.Autowired;

import org.springframework.security.access.SecurityMetadataSource;

import org.springframework.security.access.intercept.AbstractSecurityInterceptor;

import org.springframework.security.access.intercept.InterceptorStatusToken;

import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;

import org.springframework.security.web.FilterInvocation;

import org.springframework.stereotype.Component;

@Component

public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

@Autowired

private MySecurityMetadataSource securityMetadataSource;

@Autowired

private MyAccessDecisionManager accessDecisionManager;

// @Resource(name="myAuthenticationManager")

// private AuthenticationManager authenticationManager;

@Resource

private AuthenticationConfiguration authenticationConfiguration;

// @Autowired

// public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {

// this.authenticationConfiguration = authenticationConfiguration;

// }

@PostConstruct

public void init() throws Exception{

super.setAccessDecisionManager(accessDecisionManager);

super.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());

}

@Override

public SecurityMetadataSource obtainSecurityMetadataSource() {

return this.securityMetadataSource;

}

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

FilterInvocation fi = new FilterInvocation(request, response, chain);

invoke(fi);

}

private void invoke(FilterInvocation fi) throws IOException, ServletException {

// object為FilterInvocation對象

//super.beforeInvocation(fi);源碼

//1.獲取請求資源的權限

//執行Collection<configattribute> attributes = SecurityMetadataSource.getAttributes(object);/<configattribute>

//2.是否擁有權限

//this.accessDecisionManager.decide(authenticated, object, attributes);

// System.err.println(" --------------- MySecurityFilter invoke--------------- ");

InterceptorStatusToken token = super.beforeInvocation(fi);

try {

fi.getChain().doFilter(fi.getRequest(), fi.getResponse());

} finally {

super.afterInvocation(token, null);

}

}

public void init(FilterConfig arg0) throws ServletException {

}

public void destroy() {

}

@Override

public Class extends Object> getSecureObjectClass() {

//下面的MyAccessDecisionManager的supports方面必須放回true,否則會提醒類型錯誤

return FilterInvocation.class;

}

}

以上代碼涉及到MySecurityMetadataSource和MyAccessDecisionManager

MyAccessDecisionManager

package com.study.security;

import java.util.Collection;

import java.util.Iterator;

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.stereotype.Component;

/**

*

*

*/

@Component

public class MyAccessDecisionManager implements AccessDecisionManager {

public void decide(Authentication authentication, Object object, Collection<configattribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {/<configattribute>

if(configAttributes == null) {

return;

}

//所請求的資源擁有的權限(一個資源對多個權限)

Iterator<configattribute> iterator = configAttributes.iterator();/<configattribute>

while(iterator.hasNext()) {

ConfigAttribute configAttribute = iterator.next();

//訪問所請求資源所需要的權限

String needPermission = configAttribute.getAttribute();

System.out.println("needPermission is " + needPermission);

//用戶所擁有的權限authentication

for(GrantedAuthority ga : authentication.getAuthorities()) {

if(needPermission.equals(ga.getAuthority())) {

return;

}

}

}

//沒有權限

throw new AccessDeniedException(" 沒有權限訪問或未重新登錄! ");

}

public boolean supports(ConfigAttribute attribute) {

// TODO Auto-generated method stub

return true;

}

public boolean supports(Class> clazz) {

// TODO Auto-generated method stub

return true;

}

}

MySecurityMetadataSource

需要加載所有資源與權限的關係,即查詢t_resources表中所有resKey與resUrl的對應關係。

package com.study.security;

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.annotation.PostConstruct;

import javax.annotation.Resource;

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.springframework.stereotype.Component;

import com.study.dao.ResourcesDao;

import com.study.model.Resources;

/**

* 加載資源與權限的對應關係

*/

@Component

public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

@Resource

private ResourcesDao resourcesDao;

private static Map<string>> resourceMap = null;/<string>

public Collection<configattribute> getAllConfigAttributes() {/<configattribute>

return null;

}

public boolean supports(Class> clazz) {

return true;

}

/**

* @PostConstruct是Java EE 5引入的註解,

* Spring允許開發者在受管Bean中使用它。當DI容器實例化當前受管Bean時,

* @PostConstruct註解的方法會被自動觸發,從而完成一些初始化工作,

*

* //加載所有資源與權限的關係

*/

@PostConstruct

private void loadResourceDefine() {

if (resourceMap == null) {

resourceMap = new HashMap<string>>();/<string>

List<resources> list = resourcesDao.queryAll(new Resources());/<resources>

for (Resources resources : list) {

Collection<configattribute> configAttributes = new ArrayList<configattribute>();/<configattribute>/<configattribute>

// 通過資源名稱來表示具體的權限 注意:必須"ROLE_"開頭

ConfigAttribute configAttribute = new SecurityConfig("ROLE_" + resources.getResKey());

configAttributes.add(configAttribute);

resourceMap.put(resources.getResUrl(), configAttributes);

}

}

}

//返回所請求資源所需要的權限

public Collection<configattribute> getAttributes(Object object) throws IllegalArgumentException {/<configattribute>

String requestUrl = ((FilterInvocation) object).getRequestUrl();

// System.out.println("requestUrl is " + requestUrl);

if(resourceMap == null) {

loadResourceDefine();

}

//System.err.println("resourceMap.get(requestUrl); "+resourceMap.get(requestUrl));

if(requestUrl.indexOf("?")>-1){

requestUrl=requestUrl.substring(0,requestUrl.indexOf("?"));

}

Collection<configattribute> configAttributes = resourceMap.get(requestUrl);/<configattribute>

return configAttributes;

}

}

6.配置對按鈕的前臺顯示控制

因為基於了數據庫的權限控制,無法通過使用Spring Security的標籤來控制對按鈕的條件性渲染。不過其實可以通過,來控制顯示。但是按鈕所對應的Role_XXX就被限定死,而無法修改了。但是在開發階段,只有按鈕所對應操作的url是可以確定的。於是採用自定義標籤,使當前的按鈕根據按鈕的url來確定當前用戶是否擁有該url的權限,進而控制按鈕的顯示。自定義標籤如下所示:

AuthorizeTag

package com.study.tag;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.jsp.tagext.BodyTagSupport;

import org.springframework.security.core.context.SecurityContextImpl;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import com.study.model.Resources;

import com.study.service.ResourcesService;

import com.study.util.SpringWiredBean;

/**

* 自定義標籤 用於前臺判斷按鈕權限

* @author A

*

*/

public class AuthorizeTag extends BodyTagSupport {

private static final long serialVersionUID = 1L;

private String buttonUrl;

public String getButtonUrl() {

return buttonUrl;

}

public void setButtonUrl(String buttonUrl) {

this.buttonUrl = buttonUrl;

}

@SuppressWarnings("static-access")

@Override

public int doStartTag() {

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

SecurityContextImpl securityContextImpl = (SecurityContextImpl) request

.getSession().getAttribute("SPRING_SECURITY_CONTEXT");

//獲取當前登錄名

String name = securityContextImpl.getAuthentication().getName();

//如果數據庫裡有該鏈接,並且該用戶的權限擁有該鏈接,則顯示 。如果數據庫沒有該鏈接則不顯示

ResourcesService resourcesService= (ResourcesService) SpringWiredBean.getInstance().getBeanById("resourcesService");

List<resources> queryAll = resourcesService.queryAll();/<resources>

boolean flag = true;

for (Resources resources : queryAll) {

if(resources.getResUrl().equals(buttonUrl))

flag = false;

}

if(flag) //數據庫中沒有該鏈接,直接顯示

return EVAL_BODY_INCLUDE;

else{

Resources resources = new Resources();

resources.setUsername(name);

resources.setResUrl(buttonUrl);

List<resources> resourcesList = resourcesService.loadMenu(resources);/<resources>

if(resourcesList.size()>0) return EVAL_BODY_INCLUDE;//數據庫中有該鏈接,並且該用戶擁有該角色,顯示

}

return this.SKIP_BODY; //不顯示

}

}

以上帶有用到SpringWiredBean

SpringWiredBean

package com.study.util;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.context.support.SpringBeanAutowiringSupport;

public class SpringWiredBean extends SpringBeanAutowiringSupport {

/**

* 自動裝配註解會讓Spring通過類型匹配為beanFactory注入示例

*/

@Autowired

private BeanFactory beanFactory;

private SpringWiredBean() {

}

private static SpringWiredBean instance;

static {

// 靜態塊,初始化實例

instance = new SpringWiredBean();

}

/**

* 實例方法

* 使用的時候先通過getInstance方法獲取實例

*

* @param beanId

* @return

*/

public Object getBeanById(String beanId) {

return beanFactory.getBean(beanId);

}

public static SpringWiredBean getInstance() {

return instance;

}

}

在WEB-INF下加入authorize.tld

authorize.tld

<taglib>

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"

version="2.1">

<description> /<description>

<tlib-version>1.0/<tlib-version>

<short-name>security/<short-name>

http://www.springsecurity.org/jsp

<description> /<description>

<name>authorize/<name>

<tag-class> /<tag-class>

com.study.tag.AuthorizeTag

<body-content>JSP/<body-content>

<attribute> /<attribute>

<name>buttonUrl/<name>

<required>false/<required>

<rtexprvalue>true/<rtexprvalue>

<type>java.lang.String/<type>

/<taglib>

則在前端使用時,引入上面定義的標籤:

然後頁面上控制:

<authorize>

<button>新增/<button>

7.配置Mybatis

package com.study.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;

import org.apache.ibatis.plugin.Interceptor;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.log4j.Logger;

import org.mybatis.spring.SqlSessionFactoryBean;

import org.mybatis.spring.annotation.MapperScan;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.PropertySource;

import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import org.springframework.transaction.PlatformTransactionManager;

import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.github.pagehelper.PageHelper;

@Configuration

//加載資源文件

@PropertySource({"classpath:jdbc.properties"})

//加上這個註解,使得支持事務

@EnableTransactionManagement

@MapperScan(basePackages = {"com.study.dao"})

public class DataSourceConfig {

private static final Logger logger = Logger.getLogger(DataSourceConfig.class);

/*

* 綁定資源屬性

*/

@Value("${jdbc.driver}")

private String driverClass;

@Value("${jdbc.url}")

private String url;

@Value("${jdbc.username}")

private String userName;

@Value("${jdbc.password}")

private String passWord;

@Value("${maxActive}")

private int maxActive;

@Value("${maxIdle}")

private int maxIdle;

@Value("${maxWait}")

private long maxWait;

/**

* 必須加上static

*/

public static PropertySourcesPlaceholderConfigurer placehodlerConfigurer() {

logger.info("PropertySourcesPlaceholderConfigurer");

return new PropertySourcesPlaceholderConfigurer();

}

@Bean(destroyMethod="close")

public BasicDataSource dataSource() {

logger.info("DataSource");

BasicDataSource dataSource = new BasicDataSource();

dataSource.setDriverClassName(driverClass);

dataSource.setUrl(url);

dataSource.setUsername(userName);

dataSource.setPassword(passWord);

dataSource.setMaxActive(maxActive);

dataSource.setMaxIdle(maxIdle);

dataSource.setMaxWait(maxWait);

return dataSource;

}

@Bean

public PlatformTransactionManager txManager(DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

@Bean

public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {

SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();

sessionFactory.setDataSource(dataSource);

PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

sessionFactory.setMapperLocations(resolver.getResources("classpath:mapping/*Mapping.xml"));

//配置pageHelper

sessionFactory.setPlugins(new Interceptor[]{pageHelper()});

return sessionFactory.getObject();

}

/*@Bean

public MapperScannerConfigurer scannerConfigurer(){

MapperScannerConfigurer configurer = new MapperScannerConfigurer();

configurer.setBasePackage("com.study.dao");

configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");

return configurer;

}*/

/**

* mybatis 分頁插件配置

* @return

*/

@Bean

public PageHelper pageHelper() {

logger.info("MyBatisConfiguration.pageHelper()");

PageHelper pageHelper = new PageHelper();

Properties p = new Properties();

p.setProperty("offsetAsPageNum", "true");

p.setProperty("rowBoundsWithCount", "true");

p.setProperty("reasonable", "true");

pageHelper.setProperties(p);

return pageHelper;

}

}

以上代碼,配置了dataSource、sqlSessionFactory、txManager。還配置了mybatis的分頁插件pageHelper。

需要注意的是:上面代碼註釋了的部分,配置的MapperScannerConfigurer。當寫上這段代碼後,就會使因為@PropertySource注入的jdbc配置獲取的值為null,導致datasource無法配置成功,後來找了一些資料,改成@MapperScan(basePackages = {“com.study.dao”})就可以了。但還在沒找到原因,希望哪個大牛看到後可以給我解答,還有因為這個只是一個練習的項目,可能存在很多不妥或者欠缺的地方,各位對這個項目有建議的地方,希望留言或者發送到郵箱

[email protected],在此先謝謝大家。

再附上CachingConfig

CachingConfig

package com.study.config;

import org.apache.log4j.Logger;

import org.springframework.cache.CacheManager;

import org.springframework.cache.annotation.EnableCaching;

import org.springframework.cache.ehcache.EhCacheCacheManager;

import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.io.ClassPathResource;

@Configuration

@EnableCaching//

public class CachingConfig {

private static final Logger logger = Logger.getLogger(CachingConfig.class);

@Bean

public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {

EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();

ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource(

"ehcache.xml"));

return ehCacheManagerFactoryBean;

}

@Bean

public CacheManager cacheManager() {

logger.info("EhCacheCacheManager");

EhCacheCacheManager cacheManager = new EhCacheCacheManager();

cacheManager.setCacheManager(ehCacheManagerFactoryBean().getObject());

return cacheManager;

}

}

8.效果圖

從圖中可以看到,當勾選相應的權限後,界面上的按鈕也跟著消失了。

套了模板,但是界面還是很醜,對前臺操作不太擅長,就先這樣了,還有對所有的修改操作都沒有做,就做了增加和刪除(好吧,有點懶的)。

第一次使用時導入mytest.sql

admin 的密碼為admin ,因為密碼的加密是後面加入的,所以現在庫裡只有admin可以登錄。要想使用其他用戶登錄,請使用admin用戶重新創建用戶,

並分配相應的權限。

————————————————


分享到:


相關文章: