0、寫在前面的話
一直想能仿公司框架的形式,着手做一個簡單的腳手架,一來是帶着目標性能更好地學習,接觸新的技術,另外自己如果有什么想要實現的簡單需求,就可以進行快速開發,主要還是希望能在權限上有所控制,所以最花時間的還是在Shiro上。
其實目標在github已經有不少大佬的參考物了:
- zheng 基於Spring+SpringMVC+Mybatis分布式敏捷開發系統架構,提供整套公共微服務服務模塊
- ES JavaEE企業級項目的快速開發的腳手架,提供了底層抽象和通用功能,拿來即用
- renren-security 輕量級權限管理系統
- lenos 快速開發模塊化腳手架
我自己也試着搭建了最簡單的包含權限的后端,主要是為了走通整個流程,之后也會慢慢試着參考大佬們做一款自己的架子。在整個集成過程中,當然不免遇到了各種奇奇怪怪的問題,這里做一些簡單的經驗記錄,避免舊坑重踩。
1、技術框架整合
1.1 Maven多模塊項目的搭建
參考鏈接:
1.2 SpringBoot-MyBatis集成
參考鏈接:
1.3 SpringBoot-Shiro集成
參考鏈接:
2、踩坑警告
- SpringBoot 版本:2.0.3.RELEASE
- JUnit 版本:4.12
- SpringBoot-MyBatis 版本:1.3.2
- SpringBoot-Shiro 版本:1.4.0-RC2
2.1 多模塊帶來的注意事項
SpringBoot 多模塊的單元測試需要指定注解 @SpringBootTest(classes = {Application.class}),這里的 Application.class 即你的SpringBoot啟動類,這也就意味着你其他模塊的測試也只能在 Application.class 所在的模塊中進行,否則編譯無法通過因為其他模塊找不到 Application.class,當然這是因為其他模塊中的依賴問題導致的。

另外需要注意的是,SpringBoot中 的 Bean 掃描默認為 Application.java 所在包及子包,所以哪怕是多模塊,也請注意包名的問題,並調整 Application.java 的位置,否則很容易出現找不到 Bean 注入的情況。

如果你還使用了 MyBatis-generator,同樣其對於數據源的配置文件,因為多模塊的緣故,你可能也無法直接使用 SpringBoot 中 application.properties 的配置,需要單獨寫一個配置文件在 MyBatis-generator 使用的那個模塊下。

2.2 SpringBoot+MyBatis與單元測試
如果在單元測試時發現 xxxMapper 或 xxxDao 的 Bean 無法注入,那么請注意你使用的注解了。在持久層接口上注解使用 @Mapper,而不是僅僅使用 @Repository。實際上哪怕不使用 @Repository 也可以注入持久層的 Bean,但是IDE會在Service類中報紅提醒 xxxDao 沒有注冊 Bean,所以最好還是加上 @Repository,盡管去掉也沒有什么影響。
@Repository
@Mapper
public interface RoleDao {
int deleteByPrimaryKey(Long id);
int insert(Role record);
int insertSelective(Role record);
Role selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(Role record);
int updateByPrimaryKey(Role record);
Set<Role> findAll();
Set<Role> findByUserId(Long userId);
}
x
20
1
2
3
public interface RoleDao {
4
5
int deleteByPrimaryKey(Long id);
6
int insert(Role record);
7
int insertSelective(Role record);
8
Role selectByPrimaryKey(Long id);
9
int updateByPrimaryKeySelective(Role record);
10
int updateByPrimaryKey(Role record);
11
Set<Role> findAll();
12
Set<Role> findByUserId(Long userId);
13
}
2.3 Shiro中自定義Realm的Bean注冊
在 SpringBoot 和 Shiro 的集成中,Shiro的配置通常是使用一個自定義配置類,通過在方法上使用 @Bean 注解來將配置注冊成 Bean,如下:
@Configuration
public class ShiroConfig {
@Bean
public Realm realm() {
return new MyRealm();
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
//todo "/anon" not useful
chain.addPathDefinition("/anon/*", "anon");
chain.addPathDefinition("/authc/*", "authc");
return chain;
}
}
x
1
2
public class ShiroConfig {
3
4
5
public Realm realm() {
6
return new MyRealm();
7
}
8
9
10
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
11
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
12
//todo "/anon" not useful
13
chain.addPathDefinition("/anon/*", "anon");
14
chain.addPathDefinition("/authc/*", "authc");
15
return chain;
16
}
17
18
}
那么在自定義的Realm中還需要單獨的注解(如 @Component)標記嗎?答案是不需要。如下,哪怕它之中還需要用到其他的 Bean 組件,也不需要再單獨做組件注解了(加上反而因為和 @Bean 的方式沖突報錯):
//無需 @Component
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//...
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//...
return null;
}
}
x
1
//無需 @Component
2
public class MyRealm extends AuthorizingRealm {
3
4
5
private UserService userService;
6
7
8
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
9
//...
10
return null;
11
}
12
13
14
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
15
//...
16
return null;
17
}
18
19
}
另外需要注意的是,在配置url訪問權限時,如下兩種寫法請注意:
- chain.addPathDefinition("/anon", "anon"); //無效
- chain.addPathDefinition("/anon/*", "anon"); //有效