Spring开发中的异常处理
来源:互联网 发布:监控数据恢复软件 编辑:程序博客网 时间:2024/05/16 02:38
1.经常会出现@Autowired注入失败,说什么依赖找不到,原因之一是注入依赖对象存在错误,另外一个就是依赖对象确实是不存在
例如看到官网直接注入RestTemplate,如下
@Autowired
private RestTemplate restTemplate;
按照这个写法,我嫩是注入不成功,http://stackoverflow.com/questions/36151421/could-not-autowire-fieldresttemplate-in-spring-boot-application
解决方法一种是添加下面的代码,我在application中加的
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
2.spring boot使用redis存储spring session
.maximumSessions(1).maxSessionsPreventsLogin(false).invalidSessionStrategy(new SimpleInvalidSessionStrategy())
在一个浏览器登录成功以后,在另一个浏览器登录会把第一个浏览器登录的session覆盖掉,在第一个浏览器接着点击链接地址却发现并没有进入SimpleInvalidSessionStrategy,仍然校验通过,问题目前还没有解决。
网上的说法是当使用SessionManagementConfigurer的maximumSession(int)时不用忘记为应用配置HttpSessionEventPublisher,这样能保证过期的session能够被清除。发现session确实被清理掉了,但是查看ConcurrentSessionFilter类的源代码doFilter函数在没有session的时候并没有做限制判断,浏览器再次请求的时候有session==null和info==null两种情况
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res; HttpSession session = request.getSession(false); if(session != null) { SessionInformation info = this.sessionRegistry.getSessionInformation(session.getId()); if(info != null) { if(info.isExpired()) { this.doLogout(request, response); String targetUrl = this.determineExpiredUrl(request, info); if(targetUrl != null) { this.redirectStrategy.sendRedirect(request, response, targetUrl); return; } response.getWriter().print("This session has been expired (possibly due to multiple concurrent logins being attempted as the same user)."); response.flushBuffer(); return; } this.sessionRegistry.refreshLastRequest(info.getSessionId()); } } chain.doFilter(request, response);}
暂时找不到配置文件哪里有问题,两种临时解决方案
1).拦截器拦截所有的web请求检测是否有登录信息,没有则拒绝
2).在AbstractSecurityInterceptor的doFilter中过滤
在自定义AbstractSecurityInterceptor类的doFilter判断在下面三种情况下拒绝请求
a.session不存在; b:session存在sessionInformation不存在;c:访问路径需要session校验,如获取校验码不需要session校验,/error系统自带的异常处理路径不需要拒绝
自定义SessionRegistryImpl,在新建session时根据用户名把同用户名的session删除这样被挤掉的用户就不需要二次请求才提示session过期,这种方案暂时发现了问题
下面是方案一的实现代码
HttpSessionInterceptora.java
import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.stereotype.Component;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.PrintWriter;@Slf4j@Componentpublic class HttpSessionInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String method = request.getMethod(); boolean flag = false; if(!StringUtils.equalsIgnoreCase(method,"GET")&&StringUtils.equalsIgnoreCase(method,"POST") &&StringUtils.equalsIgnoreCase(method,"PUT") &&StringUtils.equalsIgnoreCase(method,"DELETE")){ return true; } flag = checkHttpSession(response, request); return flag; } private boolean checkHttpSession(HttpServletResponse response, HttpServletRequest request) throws IOException, HCBusinessException { HttpSession session = request.getSession(false); if (session==null||session.getAttribute("SPRING_SECURITY_CONTEXT") == null) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); response.setStatus(HttpServletResponse.SC_FORBIDDEN); PrintWriter out; out = response.getWriter(); out.append("{\"success\":false,\"value\":null,\"message\":\"unauthorized\"}"); out.close(); } return Boolean.TRUE; }}WebAppConfig.java
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configurationpublic class WebAppConfig extends WebMvcConfigurerAdapter { @Bean public HttpSessionInterceptor httpSessionInterceptor(){ return new HttpSessionInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(httpSessionInterceptor()).excludePathPatterns("/login","/logout","/getcode","/checkCode"); super.addInterceptors(registry); }}
下面列出方案二的实现代码
MyFilterSecurityInterceptor.java
import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.security.SecurityProperties;import org.springframework.context.annotation.Configuration;import org.springframework.core.annotation.Order;import org.springframework.security.access.SecurityMetadataSource;import org.springframework.security.access.intercept.AbstractSecurityInterceptor;import org.springframework.security.access.intercept.InterceptorStatusToken;import org.springframework.security.core.session.SessionInformation;import org.springframework.security.core.session.SessionRegistry;import org.springframework.security.web.FilterInvocation;import javax.servlet.*;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@Slf4j@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptorimplements Filter {private SecurityMetadataSource securityMetadataSource;@Autowiredprivate SessionRegistry sessionRegistryBean;public void setSecurityMetadataSource(SecurityMetadataSource securityMetadataSource) {this.securityMetadataSource = securityMetadataSource;}@Overridepublic Class<? extends Object> getSecureObjectClass() {//beforeInvocation需要判断它是否属于FilterInvocation类型return FilterInvocation.class;}@Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() {return this.securityMetadataSource;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.debug("------------MyFilterSecurityInterceptor.doFilter()-----------开始了....");FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}public void invoke(FilterInvocation fi) throws IOException, ServletException {InterceptorStatusToken token = super.beforeInvocation(fi);try{String requestUrl=fi.getRequestUrl();if((fi.getRequest().getSession(false)!=null&&sessionRegistryBean.getSessionInformation(fi.getRequest().getSession(false).getId())!=null)||requestUrl.startsWith("/getcode")||requestUrl.startsWith("/checkCode")||requestUrl.startsWith("/error")){fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else{HttpServletResponse httpServletResponse=fi.getResponse();httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json; charset=utf-8");httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);PrintWriter out;out = httpServletResponse.getWriter();out.append("{\"success\":false,\"value\":null,\"message\":\"unauthorized\"}");out.close();}}finally{super.afterInvocation(token, null);}log.debug("-----------MyFilterSecurityInterceptor.doFilter()-----------拦截器该方法结束了....");}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}}MySessionRegistryImpl.java
import org.MyUser;//自己的UserDetail信息存储类import org.springframework.security.core.session.SessionRegistryImpl;import org.springframework.security.core.userdetails.UserDetails;public class MySessionRegistryImpl extends SessionRegistryImpl { public MySessionRegistryImpl() { } public void expireUserSessions(UserDetails newPrincipal) { if (newPrincipal instanceof MyUser) { int userKeyId = ((MyUser) newPrincipal).getUserKeyId(); getAllPrincipals().stream() .filter(principal -> (principal instanceof MyUser) && (userKeyId == ((MyUser) principal).getUserKeyId())) .forEach(principal -> getAllSessions(principal, true).stream() .forEach(information ->//information.expireNow()) removeSessionInformation(information.getSessionId()) ); } } @Override public void registerNewSession(String sessionId, Object principal) { expireUserSessions((UserDetails) principal); super.registerNewSession(sessionId, principal); }}使用代码片段
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.security.SecurityProperties;import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.annotation.Order;import org.springframework.core.env.Environment;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;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.config.http.SessionCreationPolicy;import org.springframework.security.core.session.SessionRegistry;import org.springframework.security.core.session.SessionRegistryImpl;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.AuthenticationEntryPoint;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;import org.springframework.security.web.authentication.AuthenticationFailureHandler;import org.springframework.security.web.authentication.AuthenticationSuccessHandler;import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;import org.springframework.security.web.session.HttpSessionEventPublisher;public abstract class AbstractSecurityConfig extends WebSecurityConfigurerAdapter { ... @Autowired private SessionRegistry sessionRegistryBean; @Override protected void configure(HttpSecurity http) throws Exception { ... //session管理 http.sessionManagement().sessionFixation().newSession().maximumSessions(1).maxSessionsPreventsLogin(false).expiredUrl("/login").sessionRegistry(sessionRegistryBean) .and().invalidSessionStrategy(new SimpleInvalidSessionStrategy()); } //显式声明SessionRegistry,解决maxSessionPreventsLogin无效的问题 @Bean public SessionRegistry sessionRegistryBean(){ return new MySessionRegistryImpl(); } ...}
- Spring开发中的异常处理
- spring中的异常处理
- 游戏开发中的异常处理
- java开发中的异常处理
- Spring-Web项目中的异常处理
- Spring MVC 中的异常处理 (handling exceptions)
- Eclipse插件开发中的异常处理?
- Struts开发过程中的异常处理机制
- J2EE开发过程中的异常处理
- ASP.NET项目开发中的异常处理
- ASP.NET项目开发中的异常处理
- CS应用程序开发中的异常处理
- CS应用程序开发中的异常处理
- ASP.NET项目开发中的异常处理
- 企业级开发中的异常处理与日志
- Android开发中的异常统一处理
- spring AOP中的AfterThrowing增强处理不能完全处理异常
- 项目开发经验-ASP.NET项目开发中的异常处理
- wx的分享界面带图片和文字
- Android横向ListView实现
- 简单自定义可变长度数组ArrayList
- windwos操作系统版本
- objective-C 编程全解-第15章 消息发送模式 中
- Spring开发中的异常处理
- 根据日期计算是星期几
- Linux安装svn并添加用户权限
- 5.0获取当前打开的应用信息
- Swift - 自定义tabbar的封装
- jQuery的选择器中的通配符[id^='code'](
- iOS 无线打印功能(AirPrint)
- IOS Top100的第三方库整理
- JavaScript表单序列化