分享一个springboot脚手架
项目介绍
在我们开发项目的时候各个项目之间总有一些可共用的代码或者配置,如果我们每新建一个项目就把代码复制粘贴再修改就显得很没有必要。于是我就做了一个 poseidon-boot-starter
该项目是基于 spring-boot
的 starter 功能开发的,因此只适用于 spring-boot
项目。该项目集成了如下功能:
- 异常通知
- 权限配置
- 幂等锁
- 日志配置
- 用户操作日志记录
- 查询接口通用化
项目地址:https://github.com/muggle0/poseidon-boot-starter
下面介绍该组件如何在我们的 spring-boot 项目中使用。
首先我们需要下载下来这个项目:
git clone https://github.com/muggle0/poseidon-boot-starter.git
然后安装到我们的本地仓库或者私有云:
cd poseidon-boot-starter
mvn install
安装完成之后在spring boot 项目中引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
然后进行一些基础的配置:
poseidon.auto=true
poseidon.static-path=/**/*.*
poseidon.ignore-path=/**
logging.config=classpath:poseidon-logback.xml
log.dir=logs
logging.level.com.muggle=debug
spring.profiles.include=refresh
自动化配置默认是不开启的,我们需要使用 poseidon.auto=true
来启用相关功能,当开启自动化配置之后,我们必须要实现两个接口并注入到spring容器—— com.muggle.poseidon.store.SecurityStore
和 com.muggle.poseidon.service.TokenService
。poseidon.static-path
是 ant 匹配的静态资源路径,符合该规则的url不会被权限过滤器拦截,poseidon.ignore-path
是鉴权忽略规则,符合该规则的url不会参与鉴权,直接放行。logging.config=classpath:poseidon-logback.xml
则是采用 poseidon-boot-starter
中的logback配置策略(五彩斑斓的黑),如果采用该配置则必须指定 log.dir
日志文件输出路径。logging.level.com.muggle=debug
是指定包名以debug的级别输出,方便看一些日志调试。spring.profiles.include=refresh
当指定这个 profile
的时候,会去获取当前项目的所有url并交给 tokenService
去处理。还有其他默认不开启的功能,在源码解读中介绍。
源码解读
前文我们提到过,该项目是基于 springboot 的 starter 功能开发的,其原理就是一个 springboot 定制版的 spi 这里不做太多介绍,这里我主要介绍如何在项目中使用的。
首先在 META-INF/spring.factories
,中指定了要注入的类有哪些:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.muggle.poseidon.auto.ExpansibilityConfig,\
com.muggle.poseidon.auto.SecurityAutoConfig,\
com.muggle.poseidon.handler.web.WebUrlHandler,\
com.muggle.poseidon.handler.web.WebResultHandler
ExpansibilityConfig
是预留的配置类,实际未使用,SecurityAutoConfig
是整合 spring-security
相关的配置。WebUrlHandler
是处理一些特殊的url的。WebResultHandler
是统一异常处理配置。这几个类都通过 @ConditionalOnProperty(prefix = "poseidon", name = "auto", havingValue = "true", matchIfMissing = false)
来控制是否自动配置。配置类具体的源码细节这里就不介绍了。下面对各个功能的源码进行解读。
security
项目集成了security,并重写了处理器和鉴权相关的类,改造成了纯返回json,并从请求头中获取token的方式。首先我们看重写了哪些处理器:
com.muggle.poseidon.handler.security.PoseidonAccessDeniedHandler
鉴权失败处理器;com.muggle.poseidon.handler.security.PoseidonAuthenticationFailureHandler
登录失败处理器;com.muggle.poseidon.handler.security.PoseidonAuthenticationSuccessHandler
登录成功处理器;com.muggle.poseidon.handler.security.PoseidonLoginUrlAuthenticationEntryPoint
未登录处理器;com.muggle.poseidon.handler.security.PoseidonLogoutSuccessHandler
登出成功处理器。
以上几个处理器都是返回json的数据,如果需要修改json格式或者需要改成重定向的方式,需要手动去找到相关处理器去修改;因为这部分相关工作(比如重定向或者提示信息)都可以在前端解决,所以这里未做扩展处理。
然后是 token过滤器 com.muggle.poseidon.filter.SecurityTokenFilter
,该过滤器会首先从请求头中获取token,如果获取失败则会从cookie 中获取token,key都是 token,获取到token后调用 securityStore.getUserdetail(String token)
得到一个 UserDetails
,因此,怎么通过token获取用户信息需要使用者自己去扩展,你可以直接从数据库中读,或者从缓存中读,或者直接就像jwt那样,通过解析token生成。在接下来的鉴权流程中。会从该 UserDetails
中获取 GrantedAuthority
集合 和 url 一并传递给 rooleMatch(Collection<? extends GrantedAuthority> authorities, String path)
去鉴权(如果匹配为 IgnorePath 则不鉴权直接通过)。这里的鉴权方案也是需要使用者去自己实现,鉴权方案肯定是通过匹配url来实现,那么怎么去匹配设计方案就很多了,这里提供几个思路:
- 当配置
spring.profiles.include=refresh
的时候会去获取项目中的所有url和相关的swagger注释。交给TokenService.processUrl(List<AuthUrlPathDO> list)
去处理,你可以保存到数据库,为后续鉴权提供依据。 - 你可以制定一套url的命名规则,当鉴权的时候和
GrantedAuthority
进行直接匹配,通过规则我们就能直接判断哪些用户是有权限访问的了。 - 前端发请求的时候,在url末尾带上一个参数来指定哪些角色可访问(不安全,可通过伪造请求跳过鉴权)。
在 TokenService
和 SecurityStore
中还有其他相关的方法,如登入登出等,这里不做介绍了,请参看源码注释。
统一异常处理
统一异常处理相关的类是 WebResultHandler
它定义了一些异常信息的处理策略。如果你不想要这些策略可以直接删掉它,或者自己重新注入一个异常处理器,如果你想扩展它,那么你可以参考项目中readme.md文档中的案例:
@RestControllerAdvice
@Configuration
public class MyWebResultHandler extends WebResultHandler {
private static final Logger log = LoggerFactory.getLogger(OAwebResultHandler.class);
@ExceptionHandler({ConstraintViolationException.class})
public ResultBean methodArgumentNotValidException(ConstraintViolationException e, HttpServletRequest req) {
log.error("参数未通过校验", e);
ResultBean error = ResultBean.error(e.getConstraintViolations().iterator().next().getMessage());
return error;
}
}
需要注意的一个地方,如果我们项目中出现了未知的异常,应该要引起重视,因此当发生未知异常的时候会抛出一个事件。使用者可以注册监听器来监听这个事件,当发生未知的异常的时候可以及时的通知到开发人员,示例:
@Component
public class ExceptionListener implements ApplicationListener<ExceptionEvent> {
@Override
public void onApplicationEvent(ExceptionEvent event) {
String message = event.getMessage();
// TODO 将异常信息投递到邮箱等,通知开发人员系统异常,尽快处理。
}
}
请求日志及幂等锁
想要使用请求日志的功能需要实现 DistributedLocker
接口并注册到spring容器中以激活日志切面。然后再需要拦截的方法上加上 @InterfaceAction
当我们请求这个方法时就会以info级别将请求参数输入到日志中,目前日志格式是写死的,格式形如:
INFO com.muggle.poseidon.aop.RequestAspect - 》》》》》》 请求日志 用户名:用户未登录 url=/user/regester.jsonmethod=POSTip=127.0.0.1host=127.0.0.1port=57180classMethod=com.muggle.poseidon.oa.controller.UserController.regesterparamters [ (OaUserVO(gender=1, username=muggle, password=xxxxxx, email=null, imgUrl=null)) ]
如果想做幂等拦截 则需要在注解上添加参数 @InterfaceAction(Idempotent = true,message = "请求太频繁,请稍后再试")
,Idempotent
是否开启幂等拦截,
message
是 被拦截后的提示信息,expertime
是幂等锁时长 。开启拦截后会 拼接一个 key String key = "lock:idempotent:" + request.getRequestURI() + ":" + username + ":" + RequestUtils.getIP(request);
然后调用 DistributedLocker.trylock(String key, Long express)
方法进行上锁,express
参数就是注解上配置 expertime
,上锁方式需要使用者自己实现,你可以用redis,zookeeper,或者缓存来上锁。
部分使用者可能希望能把请求相关的信息存储到数据库,我也提供了扩展接口:RequestLogProcessor
只要实现该接口并注册到 spring 你就能在recordBefore
方法中拿到 请求相关信息 ,在recordAfterReturning
方法中拿到返回值,注意如果方法抛出异常,是不会拿到返回值的,需要自己去修改源码添加异常切面方法,异常切面方法的注解是 @AfterThrowing
。
日志配置
日志配置主要是两个地方,一个是 banner.txt
另外一个是 poseidon-logback.xml
如果小伙伴不喜欢这个banner想去掉,只需要在自己的项目中添加一个 banner.txt
进行覆盖就行了。
poseidon-logback.xml
是对日志格式等的配置,通过 logging.config=classpath:poseidon-logback.xml
来启用该配置,同时需要指定日志文件输出路径 log.dir=/temp/xxx
,启用该配置后你就可以在控制台上看到五彩斑斓的黑,如果小伙伴不喜欢这个配色,可以根据配置文件中的注释去修改。
查询配置
做出查询配置这个功能是为了减少平时开发写查询接口的开发成本,这个功能本身是结合 mybatis 的 pagehelper
插件使用的,如果你没有用这个插件,那就享受不到这个福利了。
由于各个公司或者的查询要求不尽相同,所以这里我也只做了一个顶层抽象。具体查询策略还是需要开发者去实现,将扩展性预留了出来。下面介绍这个功能的思路。
查询bean的 顶层抽象为 com.muggle.poseidon.base.BaseQuery
,这里面定义查询的一些通用属性。然后在 com.muggle.poseidon.aop.QueryAspect
中拦截查询方法,拦截规则是类名必须要以 Controller
结尾,入参必须是 BaseQuery
的子类。
这个切面是没有注册的,需要手动注册一下:
@Bean
QueryAspect getQueryAspect(){
return new QueryAspect();
}
在切面的 doBefore(JoinPoint joinPoint)
中 对查询参数进行转化,在doAfterReturning(JoinPoint joinPoint, Object result)
对查询的返回值进行再次处理。实际使用中小伙伴就根据项目需求进行扩展吧。
一些基础类的封装
com.muggle.poseidon.util
收集了一些工具类,小伙伴们请按需增删。com.muggle.poseidon.base
包下的 com.muggle.poseidon.base.ResultBean
是对 controller
层的返回值的bean的封装。exception
包下是自定义异常的顶层抽象类。
结语
目前项目只发布了 BETA 版,后续不会再在这个版本上加新功能,当版本稳定后,我会在这个版本基础上发布一个 REALSE 版本。如果小伙伴发现bug,或者有改进意见,或者对这个项目有新的需求请务必联系我,撸码不易,点个star支持一下吧,球球了。
分享一个springboot脚手架的更多相关文章
- 看了 Spring 官网脚手架真香,也撸一个 SpringBoot DDD 微服务的脚手架!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 为什么我们要去造轮子? 造轮子的核心目的,是为了解决通用共性问题的凝练和复用. 虽然 ...
- 基于IDEA Plugin插件开发,撸一个DDD脚手架
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 最近很感兴趣结合 IDEA Plugin 开发能力,扩展各项功能.也基于此使用不同的案例,探索 ...
- Eclipse 创建第一个 springboot 应用
1.前言 一直想把笔记整理出来,分享一下 springboot 的搭建: 因为私下 idea 用的比较多,使用比较方便,但恰逢小伙伴问起 eclipse 怎么搭建的问题, 顾整理以记之. 2.spri ...
- 整理代码,将一些曾经用过的功能整合进一个spring-boot
一 由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面. 附上自己的项目地址https://github.com/247292980/spring-boot 功能 1. ...
- springboot脚手架liugh-parent源码研究参考
1. liugh-parent源码研究参考 1.1. 前言 这也是个开源的springboot脚手架项目,这里研究记录一些该框架写的比较好的代码段和功能 脚手架地址 1.2. 功能 1.2.1. 当前 ...
- 完成一个springboot项目的完整总结一
一. 项目的基础环境的搭建 1.javaJDK的安装和配置环境变量 2.mysql 3.eclipse 二.项目高级环境的搭建 使用maven前,一定要先安装JDK 1) 解压maven到briup目 ...
- 手撸一个SpringBoot的Starter,简单易上手
前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发S ...
- 5分钟快速搭建一个springboot的项目
现在开发中90%的人都在使用springboot进行开发,你有没有这样的苦恼,如果让你新建一个springboot开发环境的项目,总是很苦恼,需要花费很长时间去调试.今天来分享下如何快速搭建. 一 ...
- 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)
分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...
随机推荐
- 导出word excel 方法
---导出excel public static void DataTableToExcelXjd(DataTable dt, string Title, string TmpColsName) { ...
- C# 数据操作系列 - 12 NHibernate的增删改查
0. 前言 上一篇<C# 数据操作系列 - 11 NHibernate 配置和结构介绍> 介绍了Nhibernate里的配置内容.这一篇将带领大家了解一下如何使用NHIbernate.之前 ...
- 使用盒子定位布局时margin和padding使用
首先说的是区别: 如图所示,黄色padding,绿色margin,中间的content是内容,margin和padding的值是不计算在内容高宽的.这里补充的是在实际情况中边框宽度也是不计算在内的.这 ...
- 浅谈SIEM
一.概念 SIEM ( Security Information Event Management,安全信息与事件管理) Gartner的定义:安全信息和事件管理(SIEM)技术通过对来自各种事件和上 ...
- 50个SQL语句(MySQL版) 问题十四
--------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...
- 学Linux驱动: 应该先了解驱动模型
[导读] Linux设备林林总总,嵌入式开发一个绕不开的话题就是设备驱动开发,在做具体设备驱动开发之前,有必要对Linux设驱动模型有一个相对清晰的认识,将会帮助驱动开发,明白具体驱动接口操作符相应都 ...
- 数据库之 MySQL --- 下载、安装 及 概述(一)
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一 . MySql数据库的安装 1.图解MySQL程序结构 2.双击运行安装程序:以Win32位为例 ...
- Java实现 蓝桥杯 算法提高 概率计算
算法提高 概率计算 时间限制:1.0s 内存限制:256.0MB 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出 ...
- Java实现 蓝桥杯 算法提高 队列操作
算法提高 队列操作 时间限制:1.0s 内存限制:256.0MB 提交此题 问题描述 队列操作题.根据输入的操作命令,操作队列(1)入队.(2)出队并输出.(3)计算队中元素个数并输出. 输入格式 ...
- Java实现 LeetCode 405 数字转换为十六进制数
405. 数字转换为十六进制数 给定一个整数,编写一个算法将这个数转换为十六进制数.对于负整数,我们通常使用 补码运算 方法. 注意: 十六进制中所有字母(a-f)都必须是小写. 十六进制字符串中不能 ...