Security:權限管理
- 常用權限攔截器
- SecurityContextPersistenceFilter
- 以前是HttpSesstionContextIntegrationFilter,位於過濾器的頂端,是第一個起作用的過濾器
- 第一個用途:在執行其他過濾器之前,率先判斷用户的session是否已經存在了一個spring security上下文的securityContext,如果存在,就把securityContext拿出來,放在securityContextHolder中,供security的其他部分使用。如果不存在,就創建一個securityContext出來,放在securityContextHolder中,供security的其他部分使用。
- 第二個用途:在所有過濾器執行完畢後,清空securityContextHolder中的內容,因為securityContextHolder是基於ThreadLocal的,如果不清空,會受到服務器線程池機制的影響。
- ThreadLocal存放的值是線程內共享的,線程間互斥的,主要用於線程內共享一些數據,避免通過參數來傳遞。這樣處理後,能夠解決實際中的一些併發問題。ThreadLocalMap是ThreadLocal的一個內部類,是不對外使用的。當使用ThreadLocal存值時,首先獲取到當前線程對象,然後獲取到當前線程本地對象,本地變量map,最後將當前使用的所有local和傳入的值放在map中。也就是説ThreadLocalMap中的key是ThreadLocal對象。這樣,每個線程都對應一個本地的map,所以,一個線程可以存在多個線程本地變量。
- ThreadLocal是解決線程併發問題的一個很好的思路,通過對每個線程提供一個獨立的變量副本,解決線程併發訪問變量的一個衝突問題
- 當一個線程結束的時候,記得把ThreadLocal裏的變量移除掉remove();
- LogoutFilter
- 只處理註銷請求。在用户發送註銷請求時,銷燬用户的session,清空securityContextHolder,重定向到註銷成功頁面
- AbstractAuthenticationProcessingFilter
- 處理form登錄的過濾器,與form登錄有關的操作都在此進行。
- DefaultLoginPageGeneratingFilter
- 用來生成一個默認的登錄頁面,默認的訪問地址為spring_security_login,這個登錄頁面雖然支持用户輸入用户名密碼,也支持remember me等功能,但是因為太難看了,只能在演示時做個樣子,不能直接在實際項目中使用
- BasicAutenticationFilter
- 用來進行basic驗證
- SecurityContextHolderAwareRequestFilter
- 用來包裝客户的請求,目的是在原來請求的基礎上,為後續程序提供一些額外的數據,比如getRomoteUser時,直接返回當前登錄的用户名
- RememberMeAuthenticationFilter
- 實現Remember me功能,當用户cookie中存在remember me標記時,它會根據標記自動實現用户登錄,並創建securityContext,授予對應的權限。spring security中的remember me依賴cookie實現,用户在登錄時選擇remember me,系統就會在登錄成功後為用户生成一個唯一的標識,並將這個標識保存進cookie中,我們可以通過瀏覽器查看用户電腦中的cookie
- AnonymousAutenticationFilter
- 當用户沒有登錄時,默認為用户分配匿名用户的權限
- ExceptionTranslationFilter
- 處理filterSecurityInterceptor中拋出的異常,然後將請求重定向到對應頁面,或返回應用的錯誤代碼
- SessionManagementFilter
- 在用户登錄成功之後,銷燬用户的當前session,並重新生成一個session
- filterSecurityInterceptor
- 用户的權限控制都包含在這個過濾器中
- 第一個功能,如果用户尚未登錄,拋出尚未認證的異常
- 第二個功能,如果用户已登錄,但是沒有訪問當前資源的權限,會拋出拒絕訪問的異常
- 第三個功能,如果用户已登錄,也具有訪問當前資源的權限,那麼放行
- FilterChainProxy
- 按照順序調用一組filter,使他們既能完成驗證授權的本職工作,又能相應spring Ioc的功能來很方便地得到其他依賴的資源
- 將用户、權限、資源(url)採用數據庫存儲
- 自定義過濾器,代替原有的 FilterSecurityInterceptor
- 自定義實現 UserDetailsService、AccessDecisionManager和InvocationSecurityMetadataSourceService,並在配置文件進行相應的配置
- 用户表(base_user)
|
code
|
type
|
length
|
|
ID
|
varchar
|
32
|
|
USER_NAME
|
varchar
|
50
|
|
USER_PASSWORD
|
varchar
|
100
|
|
NIKE_NAME
|
varchar
|
50
|
|
STATUS
|
int
|
11
|
- 用户角色表(base_user_role)
|
code
|
type
|
length
|
|
ID
|
varchar
|
32
|
|
USER_ID
|
varchar
|
32
|
|
ROLE_ID
|
varchar
|
32
|
- 角色表(base_role)
|
code
|
type
|
length
|
|
ID
|
varchar
|
32
|
|
ROLE_CODE
|
varchar
|
32
|
|
ROLE_NAME
|
varchar
|
64
|
- 角色菜單表(base_role_menu)
|
code
|
type
|
length
|
|
ID
|
varchar
|
32
|
|
ROLE_ID
|
varchar
|
32
|
|
MENU_ID
|
varchar
|
32
|
- 菜單表(base_menu)
|
code
|
type
|
length
|
|
ID
|
varchar
|
32
|
|
MENU_URL
|
varchar
|
120
|
|
MENU_SEQ
|
varchar
|
120
|
|
MENU_PARENT_ID
|
varchar
|
32
|
|
MENU_NAME
|
varchar
|
50
|
|
MENU_ICON
|
varchar
|
20
|
|
MENU_ORDER
|
int
|
11
|
|
IS_LEAF
|
varchar
|
20
|
實現主要配置類
實現AbstractAuthenticationProcessingFilter
用於用户表單驗證,內部調用了authenticationManager完成認證,根據認證結果執行successfulAuthentication或者unsuccessfulAuthentication,無論成功失敗,一般的實現都是轉發或者重定向等處理。
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
//獲取表單中的用户名和密碼
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
//組裝成username+password形式的token
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
//交給內部的AuthenticationManager去認證,並返回認證信息
return this.getAuthenticationManager().authenticate(authRequest);
}
AuthenticationManager
AuthenticationManager是一個用來處理認證(Authentication)請求的接口。在其中只定義了一個方法authenticate(),該方法只接收一個代表認證請求的Authentication對象作為參數,如果認證成功,則會返回一個封裝了當前用户權限等信息的Authentication對象進行返回。
Authentication authenticate(Authentication authentication) throws AuthenticationException;在Spring Security中,AuthenticationManager的默認實現是ProviderManager,而且它不直接自己處理認證請求,而是委託給其所配置的AuthenticationProvider列表,然後會依次使用每一個AuthenticationProvider進行認證,如果有一個AuthenticationProvider認證後的結果不為null,則表示該AuthenticationProvider已經認證成功,之後的AuthenticationProvider將不再繼續認證。然後直接以該AuthenticationProvider的認證結果作為ProviderManager的認證結果。如果所有的AuthenticationProvider的認證結果都為null,則表示認證失敗,將拋出一個ProviderNotFoundException。
校驗認證請求最常用的方法是根據請求的用户名加載對應的UserDetails,然後比對UserDetails的密碼與認證請求的密碼是否一致,一致則表示認證通過。
Spring Security內部的DaoAuthenticationProvider就是使用的這種方式。其內部使用UserDetailsService來負責加載UserDetails。在認證成功以後會使用加載的UserDetails來封裝要返回的Authentication對象,加載的UserDetails對象是包含用户權限等信息的。認證成功返回的Authentication對象將會保存在當前的SecurityContext中。
實現UserDetailsService
UserDetailsService只定義了一個方法 loadUserByUsername,根據用户名可以查到用户並返回的方法。
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.debug("權限框架-加載用户");
List<GrantedAuthority> auths = new ArrayList<>();
BaseUser baseUser = new BaseUser();
baseUser.setUserName(username);
baseUser = baseUserService.selectOne(baseUser);
if (baseUser == null) {
logger.debug("找不到該用户 用户名:{}", username);
throw new UsernameNotFoundException("找不到該用户!");
}
if(baseUser.getStatus()==2)
{
logger.debug("用户被禁用,無法登陸 用户名:{}", username);
throw new UsernameNotFoundException("用户被禁用!");
}
List<BaseRole> roles = baseRoleService.selectRolesByUserId(baseUser.getId());
if (roles != null) {
//設置角色名稱
for (BaseRole role : roles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleCode());
auths.add(authority);
}
}
return new org.springframework.security.core.userdetails.User(baseUser.getUserName(), baseUser.getUserPassword(), true, true, true, true, auths);
}
實現AbstractSecurityInterceptor
訪問url時,會被AbstractSecurityInterceptor攔截器攔截,然後調用FilterInvocationSecurityMetadataSource的方法來獲取被攔截url所需的全部權限,再調用授權管理器AccessDecisionManager鑑權。
public class CustomSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
@Override
public void destroy() {
}
@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
public void invoke(FilterInvocation fi) throws IOException {
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} catch (ServletException e) {
super.afterInvocation(token, null);
}
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
}
FilterInvocationSecurityMetadataSource 獲取所需權限
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
//獲取當前訪問url
String url = ((FilterInvocation) object).getRequestUrl();
int firstQuestionMarkIndex = url.indexOf("?");
if (firstQuestionMarkIndex != -1) {
url = url.substring(0, firstQuestionMarkIndex);
}
List<ConfigAttribute> result = new ArrayList<>();
try {
//設置不攔截
if (propertySourceBean.getProperty("security.ignoring") != null) {
String[] paths = propertySourceBean.getProperty("security.ignoring").toString().split(",");
//判斷是否符合規則
for (String path: paths) {
String temp = StringUtil.clearSpace(path);
if (matcher.match(temp, url)) {
return SecurityConfig.createList("ROLE_ANONYMOUS");
}
}
}
//如果不是攔截列表裏的, 默認需要ROLE_ANONYMOUS權限
if (!isIntercept(url)) {
return SecurityConfig.createList("ROLE_ANONYMOUS");
}
//查詢數據庫url匹配的菜單
List<BaseMenu> menuList = baseMenuService.selectMenusByUrl(url);
if (menuList != null && menuList.size() > 0) {
for (BaseMenu menu : menuList) {
//查詢擁有該菜單權限的角色列表
List<BaseRole> roles = baseRoleService.selectRolesByMenuId(menu.getId());
if (roles != null && roles.size() > 0) {
for (BaseRole role : roles) {
ConfigAttribute conf = new SecurityConfig(role.getRoleCode());
result.add(conf);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 判斷是否需要過濾
* @param url
* @return
*/
public boolean isIntercept(String url) {
String[] filterPaths = propertySourceBean.getProperty("security.intercept").toString().split(",");
for (String filter: filterPaths) {
if (matcher.match(StringUtil.clearSpace(filter), url) & !matcher.match(indexUrl, url)) {
return true;
}
}
return false;
}
AccessDecisionManager 鑑權
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
if (collection == null) {
return;
}
for (ConfigAttribute configAttribute : collection) {
String needRole = configAttribute.getAttribute();
for (GrantedAuthority ga : authentication.getAuthorities()) {
if (needRole.trim().equals(ga.getAuthority().trim()) || needRole.trim().equals("ROLE_ANONYMOUS")) {
return;
}
}
}
throw new AccessDeniedException("無權限!");
}
配置 WebSecurityConfigurerAdapter
/**
* spring-security配置
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PropertySource propertySourceBean;
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.debug("權限框架配置");
String[] paths = null;
//設置不攔截
if (propertySourceBean.getProperty("security.ignoring") != null) {
paths = propertySourceBean.getProperty("security.ignoring").toString().split(",");
paths = StringUtil.clearSpace(paths);
}
//設置過濾器
http // 根據配置文件放行無需驗證的url
.authorizeRequests().antMatchers(paths).permitAll()
.and()
.httpBasic()
// 配置驗證異常處理
.authenticationEntryPoint(getCustomLoginAuthEntryPoint())
// 配置登陸過濾器
.and().addFilterAt(getCustomLoginFilter(), UsernamePasswordAuthenticationFilter.class)
// 配置 AbstractSecurityInterceptor
.addFilterAt(getCustomSecurityInterceptor(), FilterSecurityInterceptor.class)
// 登出成功處理
.logout().logoutSuccessHandler(getCustomLogoutSuccessHandler())
// 關閉csrf
.and().csrf().disable()
// 其他所有請求都需要驗證
.authorizeRequests().anyRequest().authenticated()
// 配置登陸url, 登陸頁面並無需驗證
.and().formLogin().loginProcessingUrl("/login").loginPage("/login.ftl").permitAll()
// 登出
.and().logout().logoutUrl("/logout").permitAll();
logger.debug("配置忽略驗證url");
}
@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getDaoAuthenticationProvider());
}
/**
* spring security 配置
* @return
*/
@Bean
public CustomLoginAuthEntryPoint getCustomLoginAuthEntryPoint() {
return new CustomLoginAuthEntryPoint();
}
/**
* 用户驗證
* @return
*/
@Bean
public DaoAuthenticationProvider getDaoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setHideUserNotFoundExceptions(false);
provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
/**
* 登陸
* @return
*/
@Bean
public CustomLoginFilter getCustomLoginFilter() {
CustomLoginFilter filter = new CustomLoginFilter();
try {
filter.setAuthenticationManager(this.authenticationManagerBean());
} catch (Exception e) {
e.printStackTrace();
}
filter.setAuthenticationSuccessHandler(getCustomLoginAuthSuccessHandler());
filter.setAuthenticationFailureHandler(new CustomLoginAuthFailureHandler());
return filter;
}
@Bean
public CustomLoginAuthSuccessHandler getCustomLoginAuthSuccessHandler() {
CustomLoginAuthSuccessHandler handler = new CustomLoginAuthSuccessHandler();
if (propertySourceBean.getProperty("security.successUrl")!=null){
handler.setAuthSuccessUrl(propertySourceBean.getProperty("security.successUrl").toString());
}
return handler;
}
/**
* 登出
* @return
*/
@Bean
public CustomLogoutSuccessHandler getCustomLogoutSuccessHandler() {
CustomLogoutSuccessHandler handler = new CustomLogoutSuccessHandler();
if (propertySourceBean.getProperty("security.logoutSuccessUrl")!=null){
handler.setLoginUrl(propertySourceBean.getProperty("security.logoutSuccessUrl").toString());
}
return handler;
}
/**
* 過濾器
* @return
*/
@Bean
public CustomSecurityInterceptor getCustomSecurityInterceptor() {
CustomSecurityInterceptor interceptor = new CustomSecurityInterceptor();
interceptor.setAccessDecisionManager(new CustomAccessDecisionManager());
interceptor.setSecurityMetadataSource(getCustomMetadataSourceService());
try {
interceptor.setAuthenticationManager(this.authenticationManagerBean());
} catch (Exception e) {
e.printStackTrace();
}
return interceptor;
}
@Bean
public CustomMetadataSourceService getCustomMetadataSourceService() {
CustomMetadataSourceService sourceService = new CustomMetadataSourceService();
if (propertySourceBean.getProperty("security.successUrl")!=null){
sourceService.setIndexUrl(propertySourceBean.getProperty("security.successUrl").toString());
}
return sourceService;
}
}
spring boot 攔截器、過濾器、監聽器、定時器使用
一、application.java中配置
@EnableTransactionManagement
自動啓用事務
@SpringBootApplication
@MapperScan(basePackages={"com.hxkj.waychat.dao"})
@ServletComponentScan
攔截器、過濾器、監聽器的註解配置
二、監聽器配置
package com.hxkj.waychat.intercept.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hxkj.waychat.core.config.Constant;
import com.hxkj.waychat.core.utils.PropertiesUtils;
@WebListener
public class ThymeleafServletContextListener implements ServletContextListener {
private static Logger logger = LoggerFactory.getLogger(ThymeleafServletContextListener.class);
@Override
public void contextDestroyed(ServletContextEvent arg0) {
logger.info("----------:ServletContext銷燬");
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
logger.info("----------:ServletContext初始化");
logger.info("----------:baseUrl:"+PropertiesUtils.getPropertiesValue(Constant.BASE_URL)+";fileUrl:"+PropertiesUtils.getPropertiesValue(Constant.FILE_URL));
arg0.getServletContext().setAttribute("baseUrl", PropertiesUtils.getPropertiesValue(Constant.BASE_URL));
arg0.getServletContext().setAttribute("fileUrl", PropertiesUtils.getPropertiesValue(Constant.FILE_URL));
}
}
三、過濾器配置
package com.hxkj.waychat.intercept.fliter;
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 javax.servlet.annotation.WebFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*@WebFilter(filterName="MyFilter",urlPatterns="/*")*/
public class MyFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(MyFilter.class);
@Override
public void destroy() {
logger.info("----------:過濾器銷燬");
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
logger.info("----------:過濾器執行內容");
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
logger.info("----------:過濾器初始化");
}
}
四、攔截器配置
1.spring boot攔截器默認有
HandlerInterceptorAdapter
AbstractHandlerMapping
UserRoleAuthorizationInterceptor
LocaleChangeInterceptor
ThemeChangeInterceptor
2.配置spring mvc的攔截器WebMvcConfigurerAdapter
public class WebAppConfig extends WebMvcConfigurerAdapter
3.實現添加攔截器方法
public void addInterceptors(InterceptorRegistry registry){
}
registry.addInterceptor可以通過此方法添加攔截器, 可以是spring提供的或者自己添加的
4.實例部分
public class WebAppConfig extends WebMvcConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(WebAppConfig.class, args);
}
/**
* 配置攔截器
* @author lance
* @param registry
*/
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserSecurityInterceptor()).addPathPatterns("/user/**");
}
}
UserSecurityInterceptor代碼
public class UserSecurityInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
五、定時器使用
@Component
public class Scheduler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Scheduled(cron="0 0/1 * * * ?") //每分鐘執行一次
public void statusCheck() {
logger.info("每分鐘執行一次。開始……");
//statusTask.healthCheck();
logger.info("每分鐘執行一次。結束。");
}
@Scheduled(fixedRate=20000)
public void testTasks() {
logger.info("每20秒執行一次。開始……");
//statusTask.healthCheck();
logger.info("每20秒執行一次。結束。");
}
}
六、全局異常處理器使用
package com.hxkj.fsslr.controller;
import java.io.FileNotFoundException;
import javax.lang.model.type.UnknownTypeException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hxkj.fsslr.core.utils.PageReturnUtils;
/**
* @ClassName: GlobalExceptionHandler
* @Description: 全局異常處理
* @author huzhihui_c@qq.com
* @date 2016年7月18日 下午1:17:59
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value=Exception.class)
@ResponseBody
public Object errorHandler(HttpServletRequest request,Exception e){
logger.info("-----捕獲到異常-----");
//ajax請求異常返回
if(null != request.getHeader("X-Requested-With") && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString())){
if (e instanceof NullPointerException) {
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "數據參數傳入錯誤");
} else if (e instanceof FileNotFoundException) {
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "數據文件上傳出錯");
} else if (e instanceof ClassNotFoundException) {
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "系統未找到該jar包");
} else if (e instanceof UnknownTypeException) {
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "未知錯誤");
} else{
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, e.toString());
}
}
return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, e.toString());
}
}
一、application.java中配置 @EnableTransactionManagement 自動啓用事務 @SpringBootApplication@MapperScan(basePackages={"com.hxkj.waychat.dao"}) @ServletComponentScan 攔截器、過濾器、監聽器的註解配置 二、監聽器配置 package com.hxkj.waychat.intercept.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.hxkj.waychat.core.config.Constant; import com.hxkj.waychat.core.utils.PropertiesUtils; @WebListenerpublicclass ThymeleafServletContextListener implements ServletContextListener{ privatestatic Logger logger = LoggerFactory.getLogger(ThymeleafServletContextListener.class); @Overridepublic void contextDestroyed(ServletContextEvent arg0){ logger.info("----------:ServletContext銷燬"); } @Overridepublic void contextInitialized(ServletContextEvent arg0){ logger.info("----------:ServletContext初始化"); logger.info("----------:baseUrl:"+PropertiesUtils.getPropertiesValue(Constant.BASE_URL)+";fileUrl:"+PropertiesUtils.getPropertiesValue(Constant.FILE_URL)); arg0.getServletContext().setAttribute("baseUrl", PropertiesUtils.getPropertiesValue(Constant.BASE_URL)); arg0.getServletContext().setAttribute("fileUrl", PropertiesUtils.getPropertiesValue(Constant.FILE_URL)); } } 三、過濾器配置 package com.hxkj.waychat.intercept.fliter; 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 javax.servlet.annotation.WebFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /*@WebFilter(filterName="MyFilter",urlPatterns="/*")*/publicclass MyFilter implements Filter{ privatestatic Logger logger = LoggerFactory.getLogger(MyFilter.class); @Overridepublic void destroy(){ logger.info("----------:過濾器銷燬"); } @Overridepublic void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws{ logger.info("----------:過濾器執行內容"); arg2.doFilter(arg0, arg1); } @Overridepublic void init(FilterConfig arg0) throws{ logger.info("----------:過濾器初始化"); } } 四、攔截器配置 1.spring boot攔截器默認有 HandlerInterceptorAdapter AbstractHandlerMapping UserRoleAuthorizationInterceptor LocaleChangeInterceptor ThemeChangeInterceptor 2.配置spring mvc的攔截器WebMvcConfigurerAdapter publicclass WebAppConfig extends WebMvcConfigurerAdapter 3.實現添加攔截器方法 public void addInterceptors(InterceptorRegistry registry){ } registry.addInterceptor可以通過此方法添加攔截器, 可以是spring提供的或者自己添加的 4.實例部分 publicclass WebAppConfig extends WebMvcConfigurerAdapter{ public static void main(String[] args){ SpringApplication.run(WebAppConfig.class, args); } /** * 配置攔截器 * @author lance * @parampublic void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(new UserSecurityInterceptor()).addPathPatterns("/user/**"); } } UserSecurityInterceptor代碼 publicclass UserSecurityInterceptor implements HandlerInterceptor{ @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws{ returntrue; } @Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws{ } @Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws{ } } 五、定時器使用 @Componentpublicclass Scheduler{ privatefinal Logger logger = LoggerFactory.getLogger(this.getClass()); @Scheduled(cron="0 0/1 * * * ?") //每分鐘執行一次 public void statusCheck(){ logger.info("每分鐘執行一次。開始……"); //statusTask.healthCheck(); logger.info("每分鐘執行一次。結束。"); } @Scheduled(fixedRate=20000) public void testTasks(){ logger.info("每20秒執行一次。開始……"); //statusTask.healthCheck(); logger.info("每20秒執行一次。結束。"); } } 六、全局異常處理器使用 package com.hxkj.fsslr.controller; import java.io.FileNotFoundException; import javax.lang.model.type.UnknownTypeException; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import com.hxkj.fsslr.core.utils.PageReturnUtils; /** * @ClassName: GlobalExceptionHandler * @Description: 全局異常處理 * @author huzhihui_c@qq.com * @date@ControllerAdvicepublicclass GlobalExceptionHandler{ privatestatic Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler(value=Exception.class) @ResponseBodypublic Object errorHandler(HttpServletRequest request,Exception e){ logger.info("-----捕獲到異常-----"); //ajax請求異常返回if(null != request.getHeader("X-Requested-With") && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString())){ if (e instanceof NullPointerException) { return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "數據參數傳入錯誤"); } elseif (e instanceof FileNotFoundException) { return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "數據文件上傳出錯"); } elseif (e instanceof ClassNotFoundException) { return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "系統未找到該jar包"); } elseif (e instanceof UnknownTypeException) { return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, "未知錯誤"); } else{ return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, e.toString()); } } return PageReturnUtils.formatNormal("", PageReturnUtils.MSG_CODE_111111, PageReturnUtils.MSG_STATE_FALSE, e.toString()); } }
如果你能掌握命運,那你就是神!使生如夏花之絢爛,死如秋葉之靜美!