分享一个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 ...
随机推荐
- .net System.Web.Mail发送邮件 (设置发件人 只显示用户名)
http://blog.163.com/hao_2468/blog/static/130881568201141251642215/ .net System.Web.Mail发送邮件 2011-05- ...
- Spring JSR-250 注释
Spring还使用基于 JSR-250 注释,它包括 @PostConstruct 注释 @PreDestroy 注释 @Resource 注释 @PostConstruct 和 @PreDestro ...
- Windows系统下Git的下载和配置
简介:Git是一款免费.开源的分布式版本控制系统,可记录文件每次改动,便于多人协作编辑. 下载:git-for-windows下载地址https://git-for-windows.github.io ...
- 【Java】手把手模拟CAS,瞬间理解CAS的机制
话不多少,先看个案例,[模拟100个用户,每个用户访问10次网站]”: public class ThreadDemo1 { //总访问量 ; //模拟访问的方法 public static void ...
- 如何快速全面掌握Kafka?这篇文章总结了
Kafka 是目前主流的分布式消息引擎及流处理平台,经常用做企业的消息总线.实时数据管道,本文挑选了 Kafka 的几个核心话题,帮助大家快速掌握 Kafka,包括: Kafka 体系架构 Kafka ...
- Java——动态创建Class(不写入文件,直接从内存中创建class)
原文:https://blog.csdn.net/zhao_xinhu/article/details/82499062#commentsedit 参考:https://www.cnblogs.com ...
- 快服务常见TOP3审核雷区,再不过审就要崩溃啦!
仰天大笑出门去,审核提交很神气. 垂死病中惊坐起,突然驳回伤不起. 江州司马青衫湿,重新修改苦自知. 梦里花落知多少,回复马上就改好. 审批被驳回可能是最常见的令开发者头大的问题了,明明看起来&quo ...
- MySQL8多实例安装与mycat连接,最详细版本。
[版权所有,转载请注明出处!违者必究!] 最近在搞mycat去实现主从库读写分离,所以博主就在自己的windows机器上进行了环境的搭建,在搭建MySQL多实例的时候还算顺利,就是mysql8和myc ...
- 使用flask实现简单的文件上传
from flask import Flask, redirect, render_template, request, url_forfrom werkzeug.utils import secur ...
- python 比较常见的工具方法
下面是一些工作过程中比较常见的工具方法,但不代表最终答案.希望能对你有所帮助,如果您有更好更多的方法工具,欢迎推荐! 1. 按行读取带json字符串的文件 # -*- coding:utf-8 -*- ...