本文主要介绍下,SpringBoot的web项目中,
使用redis保存并共享session,可以实现集群内的登录信息共享。SpringBoot项目中,通过在 application.yml 增加redis的配置,即可实现对session的存储和修改。
那么session是在何时被处理的?session的key又是如何生成的呢?这里实际使用了web项目中的过滤器。
在SpringBoot的web项目中,启动的tomcat在处理http请求时,有一个很重要的类: ApplicationFilterChain 。每个http请求在处理时都会通过这个类。这个类负责按顺序处理全部已注册的 Filter ,也就是过滤器。通过实现tomcat中的 Filter 接口,就可以定义一个过滤器。
在SpringBoot中的web项目中,有几个默认的过滤器,其中一个就是用来处理session的: SessionRepositoryFilter
SessionRepositoryFilter 主要的成员是两个接口,都有多个可选的实现类,通过这两个成员就实现了对session的解析。
当然也可以实现一个自己的过滤器,主要有两种方式:
下面我们使用第一种方式实现一个限制指定IP的过滤器:
通过过滤器解析session后,就可以根据session中保存的内容,判断当前登录的用户权限。
这里是通过一个拦截器实现的,在拦截器中可以直接通过 HttpServletRequest.getSession() 方法直接获取session的信息。
一个简单的拦截器实现如下:
定义之后要注册到处理流程中:
先来看下过滤器和拦截器的执行顺序,通过debug得到的执行顺序如下图:
在大部分场景中,过滤器和拦截器都是可互换的,使用哪个都可以。
过滤器和拦截器也有些区别,这里不谈实现和规范的差异,就说下使用中可能涉及的区别:
最后对于过滤器和拦截器的应用场景,说下个人的总结。基于执行顺序,方法参数和SpringBoot中的一些实现类来看。
以上内容属个人学习总结,如有不当之处,欢迎在评论中指正
对于日志和事件的记录在每个项目中都会用到,如果在每个manager层中触发时间记录的话,会比较难以扩展和维护,所以可配置的日志和事件记录在项目中会用到!首先在spring的配置文件中加入hibernate拦截器
Java代码
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property
name="entityInterceptor">
<ref
bean="myInterceptor"/>
</property>
</bean>
<bean
id="myInterceptor"
class="com.creawor.cbsms.util.MyInterceptor"
/>
MyInterceptor拦截器为:
Java代码
package
com.creawor.cbsms.util
import
java.io.Serializable
import
java.lang.reflect.InvocationTargetExceptio
n
import
java.lang.reflect.Method
import
java.util.Iterator
import
javacommon.util.ApplicationContextHolder
import
org.hibernate.CallbackException
import
org.hibernate.EntityMode
import
org.hibernate.Interceptor
import
org.hibernate.Transaction
import
org.hibernate.type.Type
import
com.creawor.cbsms.event.EventRecord
import
com.creawor.cbsms.model.CbsChannel
import
com.creawor.cbsms.model.CbsMessage
public
class
MyInterceptor
implements
Interceptor{
//删除时记录时间
public
void
onDelete(Object
obj,
Serializable
arg1,
Object[]
arg2,
String[]
arg3,
Type[]
arg4)
throws
CallbackException
{
//
TODO
Auto-generated
method
stub
String[]
entitys
=
EventRecord.getDeleteEntitysFireEven
t()
for
(String
entityName
:
entitys)
{
if
(entityName.equals(obj.getClass().getSimpleName()))
{
getEventRecordMethod(entityName,
obj,EventRecord.getDeleteInfo())
}
}
}
//修改时记录事件
public
boolean
onFlushDirty(Object
obj,
Serializable
id,
Object[]
currentState,
Object[]
previousState
,
String[]
propertyNames,
Type[]
types){
String[]
entitys
=
EventRecord.getUpdateEntitysFireEven
t()
for
(String
entityName
:
entitys)
{
if
(entityName.equals(obj.getClass().getSimpleName()))
{
getEventRecordMethod(entityName,
obj,
EventRecord.getUpdateInfo())
}
}
return
false
}
public
String
onPrepareStatement(String
arg0)
{
//
TODO
Auto-generated
method
stub
return
arg0
}
//保存时记录事件
public
boolean
onSave(Object
obj,
Serializable
arg1,
Object[]
arg2,
String[]
arg3,
Type[]
arg4)
throws
CallbackException
{
//
TODO
Auto-generated
method
stub
String[]
entitys
=
EventRecord.getSaveEntitysFireEvent()
for
(String
entityName
:
entitys)
{
if
(entityName.equals(obj.getClass().getSimpleName()))
{
getEventRecordMethod(entityName,
obj,EventRecord.getSaveInfo())
}
}
return
false
}
//根据反射机制执行事件记录类中相应的函数
public
void
getEventRecordMethod(String
entityName,Object
obj,String
info){
try
{
Class[]
parameterTypes
=
{String.class,Class.forName(EventRecord.getPrefixPackageName()+entityName)}
Method
method
=
EventRecord.class.getMethod(EventRecord.getPrefixMethodName()+entityName,
parameterTypes)
Object[]
objs
=
{info,
Class.forName(EventRecord.getPrefixPackageName()+entityName).cast(obj)}
method.invoke((EventRecord)ApplicationContextHolder
.getBean("eventRecord"),objs)
}
catch
(Exception
e)
{
//
TODO
Auto-generated
catch
block
e.printStackTrace()
}
}
事件记录类:
Java代码
package
com.creawor.cbsms.event
import
java.sql.Timestamp
import
javacommon.util.ApplicationContextHolder
import
com.creawor.cbsms.dao.CbsEventDao
import
com.creawor.cbsms.model.CbsBsc
import
com.creawor.cbsms.model.CbsBscCells
import
com.creawor.cbsms.model.CbsChannel
import
com.creawor.cbsms.model.CbsEvent
import
com.creawor.cbsms.model.CbsUserRegister
import
com.creawor.cbsms.service.CbsEventManager
import
com.creawor.security.model.PermUser
public
class
EventRecord
{
//
保存时要记录事件的对象
private
static
String[]
saveEntitysFireEvent
=
{
"CbsBscCells",
"CbsChannel",
"CbsBsc"
}
//
删除时要记录事件的对象
private
static
String[]
deleteEntitysFireEvent
=
{
"CbsBscCells",
"CbsChannel",
"CbsBsc"
}
//
更新时要记录事件的对象
private
static
String[]
updateEntitysFireEvent
=
{
"CbsBscCells",
"CbsChannel",
"CbsBsc"
}
//
包的前缀,反射得到类时使用
private
static
String
prefixPackageName
=
"com.creawor.cbsms.model."
//
记录该次 *** 作的登录用户名:EventRecord为session范围
private
String
userName
//
调用函数的前缀,反射执行函数时使用
private
static
String
prefixMethodName
=
"recordFor"
//
执行save时,事件描述
private
static
String
saveInfo
=
"创建"
//
执行delete时,事件描述
private
static
String
deleteInfo
=
"删除"
//
执行update时,事件描述
private
static
String
updateInfo
=
"修改"
private
CbsEventManager
cbsEventManager
//
spring自动注入
public
void
setCbsEventManager(CbsEventManager
cbsEventManager)
{
this.cbsEventManager
=
cbsEventManager
}
public
void
recordForCbsChannel(String
desc,
CbsChannel
channel)
{
StringBuffer
eventDesc
=
new
StringBuffer(desc)
eventDesc.append("频道"
+
channel.getChannelName()).append("[").append(
channel.getChannelNum()).append("]")
record(eventDesc.toString(),
null)
}
public
void
recordForCbsBscCells(String
desc,
CbsBscCells
cell)
{
StringBuffer
eventDesc
=
new
StringBuffer(desc)
eventDesc.append("小区"+cell.getCellName()).append("[").append(
cell.getCellId()).append("]")
record(eventDesc.toString(),
null)
}
public
void
record(String
eventDesc,
String
eventOrigin)
{
CbsEvent
event
=
new
CbsEvent()
event.setEventDesc(userName
+
"
"
+
eventDesc)
event.setEventOrigin(eventOrigin)
event.setStartTime(new
Timestamp(System.currentTimeMillis()))
cbsEventManager.save(event)
}
public
void
setUserName(String
userName)
{
this.userName
=
userName
}
public
static
String[]
getDeleteEntitysFireEven
t()
{
return
deleteEntitysFireEvent
}
public
static
String[]
getSaveEntitysFireEvent()
{
return
saveEntitysFireEvent
}
public
static
String[]
getUpdateEntitysFireEven
t()
{
return
updateEntitysFireEvent
}
public
static
String
getPrefixPackageName()
{
return
prefixPackageName
}
public
static
void
setPrefixPackageName(String
prefixPackageName)
{
EventRecord.prefixPackageName
=
prefixPackageName
}
public
static
String
getPrefixMethodName()
{
return
prefixMethodName
}
public
static
String
getDeleteInfo()
{
return
deleteInfo
}
public
static
String
getSaveInfo()
{
return
saveInfo
}
public
static
String
getUpdateInfo()
{
return
updateInfo
}
}
其中EventRecord 在spring中的配置为:
Java代码
<bean
id="eventRecord"
class="com.creawor.cbsms.event.EventRecord"
scope="session"
autowire="byName"/>
EventRecord 为session范围可以使字段userName记录每次登录人员的姓名
具体在每次登录后从spring容器中得到EventRecord然后set其userName即可!
最后一步要想让session范围生效还要在web.xml中添加配置:
Java代码
<web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
这样如果想要记录一个业务bean增删改的 *** 作只需在EventRecord中设置saveEntitysFireEvent,deleteEntitysFireEvent,updateEntitysFireEvent属性即可,同样也可使用配置文件配置,这样都可以使日志和事件的记录变得很简单!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)