文章目录
1.懒加载(no Session错误)
为Employee的部门字段添加懒加载
产生no session异常
问题分析:
错误原因:
设置懒加载,会报no Session 错误,原因是EntityManager关闭早了
解决方法:
配置一个openEntityManagerInViewFilter过滤器,这个过滤器是Spring准备好的
过滤器:请求的时候创建EntityManager,响应后关闭EntityManager
<!--no session解决(Spring准备好的过滤器)-->
<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>
2.No serializer(不是序列化)
虽然no session错误解决了,但是还有No serializer found for class 错误,前台数据显示不能正确展示
产生原因:
- 因为前台展示的数据是json格式,以往是SpringMVC帮我们把Employee变成json格式数据,但是前提是Employee的所有字段都必须是可序列化的
- 但是设置懒加载的department,Spring会创建代理对象,它为了实现代理通知,会自主添加一些属性,这些属性不支持序列化
问题分析:
解决方法①:
通过@JsonIgnoreProperties注解,在转换为json数据时,忽略掉这些不支持序化的属性(每次懒加载都需要加该注解)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"})
private Department department;
解决方法②:
自定义映射,解决Serializa的问题(一劳永逸)
- 创建CustomMapper自定义映射类
public class CustomMapper extends ObjectMapper {
public CustomMapper() {
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 设置 SerializationFeature.FAIL_ON_EMPTY_BEANS 为 false
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
}
}
- 配置applicationContext-mvc.xml
<!--2.注解支持-->
<!-- Spring MVC 配置 -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json; charset=UTF-8</value>
<value>application/x-www-form-urlencoded; charset=UTF-8</value>
</list>
</property>
<!-- No serializer:配置 objectMapper 为我们自定义扩展后的 CustomMapper,解决了返回对象有关系对象的报错问题 -->
<property name="objectMapper">
<bean class="com.luo.aisell.common.CustomMapper"></bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
3.n to n(修改oid错误)
错误原因:
不能修改持久化对象的id,一旦修改,就会报 n-to-n错误
图中Department是持久化对象,修改持久化id报错
解决方式:
就是,将department持久化对象设为null,他就不是持久化对象了,然后修改id就不会报错了。
4.权限
- 权限分为:登录和授权
- 游客:当你没有登录系统时,你的身份为游客
- 令牌:一般是用户名和密码组成令牌,通过令牌可以登录系统
用户登录图
角色就是一组权限的集合
5.Shiro(权限框架)
shiro是一个轻量级强大且易用的java安全框架
RBAC:权限(登录,授权) 用户(n)-角色(n)-权限(n)(资源)
①面试题:shiro和Spring security的区别?
主要是控制权限的粒度不同
- Spring security:细粒度,重量级安全框架
- shiro:粗粒度,轻量级安全框
②shiro的四大基石
- 身份认证(登录) Authentication
- 授权(权限) Authorization
- 密码学 Cryptography
- 会话管理 Session Management
四大基石图解
③shiro架构
宏观角度
微观角度
6.shiro(Hello案例)
①导包
<!--使用shiro需要先导包-->
<dependencies>
<!--shiro的核心包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!--日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
</dependencies>
②配置ini文件
文件中配置用户名,密码和角色权限
# -----------------------------------------------------------------------------
# users:代表下面都是用户
# root:用户名,123456:密码,admin:角色
#
#
# -----------------------------------------------------------------------------
[users]
root = 123456, admin
guest = 123, gg
gu = 2333,it
# -----------------------------------------------------------------------------
#roles:下面代表角色
# admin = *:表示admin角色可以做任何事
# guest = employee:*:表示gg角色可以对员工进行任何操作
# gu = employee:save:表示it角色只能对员工进行添加
# -----------------------------------------------------------------------------
[roles]
admin = *
gg = employee:*
it = employee:save
③测试登录
想要使用shiro必须先获取权限管理对象SecurityManager
- UnknownAccountException 不知道用户异常(用户名不存在)
- IncorrectCredentialsException(不正确凭证(密码错误)异常)
@Test
public class ShiroTest {
@Test
public void test() throws Exception{
//获取权限管理器工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//通过工厂获取权限管理器对象
SecurityManager securityManager = factory.getInstance();
/*
*将权限管理器对象放入工具类,不然工具类功能用不了(放进来securityManager才可以在整个项目中都使用)
* 所有功能都在权限管理器中,所以我要把这个管理器交给工具类
* 工具类就可以直接实现相应的功能
**/
SecurityUtils.setSecurityManager(securityManager);
//获取当前用户
Subject subject = SecurityUtils.getSubject();
//判断当前用户是否登录
System.out.println("用户是否登录:"+subject.isAuthenticated());
//如果用户没有登录,让他登录
if(!subject.isAuthenticated()){
try {
//登录需要令牌(准备用户名密码令牌)
AuthenticationToken token = new UsernamePasswordToken("root","123456");
//用户登录
subject.login(token);
//判断用户是否有该角色
System.out.println("判断用户是否有该角色"+subject.hasRole("admin"));
//判断是否有某个权限
System.out.println("判断用户是否有employee:save权限"+subject.isPermitted("employee:save"));
System.out.println("判断用户是否有employee:update权限"+subject.isPermitted("employee:update"));
System.out.println("判断用户是否有employee:delete权限"+subject.isPermitted("employee:delete"));
System.out.println("判断用户是否有department:save权限"+subject.isPermitted("department:save"));
} catch (UnknownAccountException e) {
//UnknownAccountException(不知道用户异常)
System.out.println("用户名错误!!!");
e.printStackTrace();
}catch (IncorrectCredentialsException e){
//IncorrectCredentialsException(不正确凭证(密码错误)异常)
System.out.println("密码错误!!!");
e.printStackTrace();
}catch (AuthenticationException e){
System.out.println("sorry!!!");
e.printStackTrace();
}
}
//判断当前用户是否登录
System.out.println("用户是否登录:"+subject.isAuthenticated());
}
}