如果本文对您有所帮助,动动小手,点赞不迷路~

每次新建一个项目时,大量工作需要重复,所以做了一个基于springboot的脚手架项目。

springboot项目脚手架

  • JWT token
  • swagger
  • 代码生成器
  • 统一返回格式封装
  • 常用工具类
  • 全局异常配置
    • 自定义异常拦截处理
  • 多环境配置文件
  • 日志配置

一个成熟的springboot项目应该包含哪些基本内容?

  • token校验:对接口的安全性进行一定的保障;
  • swagger文档:方便前后端联调;
  • 代码生成器:减轻开发中POJO类、CRUD工作量,加快开发速度;
  • 统一返回格式封装:包含基础返回数据格式和分页返回数据格式;
  • 常用工具类:看业务需求和工作中遇见比较好的工具类;
  • 全局异常配置:将错误信息返回给用户时便于理解。具体应包含:错误枚举和自定义异常;
  • 多环境配置文件
  • 日志配置:出现问题时便于查找。具体应包含:日志文件名按日期创建、统一打印接口出入参等。

JWT token

token主要是对访问资源做一定的保护,防止受到攻击,以下示例中只进行了登录校验,并未对资源访问角色做验证,部分配置和业务代码未贴出。

@Configuration
public class WebConfiguration implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new AuthenticationInterceptor()).excludePathPatterns("/user/login").excludePathPatterns("/user/sendSms")// 开放swagger.excludePathPatterns("/swagger-ui.html").excludePathPatterns("/webjars/**").excludePathPatterns("/v2/**").excludePathPatterns("/swagger-resources/**").addPathPatterns("/**");}
}
@Slf4j
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {public static AuthenticationInterceptor interceptor;@Resourceprivate UserService userService;@Resourceprivate SysConfig sysConfig;@Resourceprivate JwtUtil jwtUtil;@PostConstructpublic void init() {interceptor = this;interceptor.sysConfig = this.sysConfig;interceptor.userService = this.userService;interceptor.jwtUtil = this.jwtUtil;}@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws BusinessException {String token = httpServletRequest.getHeader(interceptor.sysConfig.getHeaderToken());// 如果不是映射到方法直接通过if (!(object instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) object;Method method = handlerMethod.getMethod();if (method.isAnnotationPresent(ValidUser.class)) {ValidUser validUser = method.getAnnotation(ValidUser.class);if (!validUser.value()) {return true;}}// 执行认证if (token == null) {throw new BusinessException(ResponseCode.UN_AUTHENTICATION);}// 获取token中的userIdLong userId;try {userId = interceptor.jwtUtil.getUserIdByToken(token);} catch (JWTDecodeException j) {throw new BusinessException(ResponseCode.UN_AUTHENTICATION);}LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();wrapper.eq(User::getStatus, 1);wrapper.eq(User::getId, userId);User user = interceptor.userService.getBaseMapper().selectOne(wrapper);if (user == null) {throw new BusinessException(ResponseCode.USER_NOT_EXIST);}if (user.getStatus() == 0) {throw new BusinessException(ResponseCode.USER_IS_DISABLED);}// 验证 tokeninterceptor.jwtUtil.validateToken(user, token);return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {}
}
@Slf4j
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {public static AuthenticationInterceptor interceptor;@Resourceprivate UserService userService;@Resourceprivate SysConfig sysConfig;@Resourceprivate JwtUtil jwtUtil;@PostConstructpublic void init() {interceptor = this;interceptor.sysConfig = this.sysConfig;interceptor.userService = this.userService;interceptor.jwtUtil = this.jwtUtil;}@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws BusinessException {String token = httpServletRequest.getHeader(interceptor.sysConfig.getHeaderToken());// 如果不是映射到方法直接通过if (!(object instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) object;Method method = handlerMethod.getMethod();if (method.isAnnotationPresent(ValidUser.class)) {ValidUser validUser = method.getAnnotation(ValidUser.class);if (!validUser.value()) {return true;}}// 执行认证if (token == null) {throw new BusinessException(ResponseCode.UN_AUTHENTICATION);}// 获取token中的userIdLong userId;try {userId = interceptor.jwtUtil.getUserIdByToken(token);} catch (JWTDecodeException j) {throw new BusinessException(ResponseCode.UN_AUTHENTICATION);}LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();wrapper.eq(User::getStatus, 1);wrapper.eq(User::getId, userId);User user = interceptor.userService.getBaseMapper().selectOne(wrapper);if (user == null) {throw new BusinessException(ResponseCode.USER_NOT_EXIST);}if (user.getStatus() == 0) {throw new BusinessException(ResponseCode.USER_IS_DISABLED);}// 验证 tokeninterceptor.jwtUtil.validateToken(user, token);return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {}
}

swagger

swagger配置较为简单:引入依赖、初始化配置即可。

 //模块创建示例@Beanpublic Docket createUserRestApi() {return new Docket(DocumentationType.SWAGGER_2).groupName("用户").apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.abab.common.controller")).paths(PathSelectors.regex("/user/.*")).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("springboot项目基础框架").description("springboot项目脚手架").version("1.0").contact(new Contact("alex","url","123@idwarf.cn")).build();}

我的项目中使用了两套swaggerUI,一套是springfox-swagger-ui,另一套是swagger-bootstrap-ui。界面如下:

代码生成器

项目中常使用的代码生成器有:lombok注解(构造方法,setter,getter,hashcode,toString等),mybatis-plus(可直接使用CRUD的SQL,无需自己开发)。
以上详情请自行百度。

统一返回格式封装

可根据业务需求自行定义,示例仅供参考。示例中ResponseCode.java为错误码枚举类。

@Data
@ApiModel("统一封装返回数据格式")
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {@ApiModelProperty("错误码")private Integer code;@ApiModelProperty("错误信息")private String message;@ApiModelProperty("返回数据")private Object data;public static Result<Void> error(String message) {return new Result(ResponseCode.SERVER_EXCEPTION.getCode(), message, null);}public static Result<Void> error(Integer code, String message) {return new Result(code, message, null);}public static Result<Void> error(ResponseCode responseCode) {return new Result(responseCode.getCode(), responseCode.getMessage(), null);}public static <T> Result<T> success(T data) {return new Result<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), data);}public static <T> Result<T> success() {return new Result<T>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), null);}@JsonIgnorepublic boolean isFailed() {return !ResponseCode.SUCCESS.getCode().equals(this.code);}@JsonIgnorepublic boolean isSucceed() {return ResponseCode.SUCCESS.getCode().equals(this.code);}
}

分页返回格式:

@Data
public class Page<T> {/*** 分页数据*/@ApiModelProperty(value = "返回数据")private List<T> records;/*** 总条数*/@ApiModelProperty(value = "返回数据总数")private Integer total;/*** 总页数*/@ApiModelProperty(value = "总页数")private Integer pages;/*** 当前页*/@ApiModelProperty(value = "当前页码")@Min(value = 1, message = "请输入正确的页码")private Integer current;/*** 每页显示数量*/@ApiModelProperty(value = "每页显示数量")@Min(value = 1, message = "请输入正确的数量")private Integer size;/*** 设置MySQL查询中 limit offset*/@ApiModelProperty(hidden = true)@JsonIgnorepublic Integer getStart() {return (this.current - 1) * size;}/*** 设置总记录数和页面总数** @param total 总记录数*/@ApiModelProperty(hidden = true)public void setTotal(Integer total) {this.total = total;this.setPages(this.total % this.size > 0 ? this.total / this.size + 1 : this.total / this.size);}
}

常用工具类

靠开发中的积累。

全局异常配置

自定义异常拦截处理

此节需配合统一返回格式封装一起看,此处只例举部分异常,根据自定义异常和业务需求可自行删减,需注意:子异常需放在父异常上面

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@Resourceprivate HttpServletRequest request;@ExceptionHandler(TokenExpiredException.class)@ResponseBodypublic Result<Void> tokenExpiredHandler(TokenExpiredException e) {log.info("accessToken已失效:", e.getMessage());return Result.error(ResponseCode.INVALID_TOKEN);}@ExceptionHandler(JWTVerificationException.class)@ResponseBodypublic Result<Void> jwtVerificationException(JWTVerificationException e) {log.info("accessToken校验失败:", e.getMessage());return Result.error(ResponseCode.UN_AUTHENTICATION);}@ExceptionHandler(Exception.class)@ResponseBodypublic Result<Void> unchangedExceptionHandler(Exception e) {log.error("请求url[{}],发生[{}]异常: ", request.getRequestURL(), e.getClass().getName(), e);return Result.error(ResponseCode.SERVER_EXCEPTION.getCode(), e.getMessage());}}

多环境配置文件

针对不同的环境需要有不同的配置,最为显著的就是数据库配置(上面的swagger也只在devuat中配置),springboot中可以创建多个配置文件,根据环境去读取指定配置。
在application.properties中指定环境(启动脚本中也可指定):

spring.profiles.active=dev

日志配置

对日志输出配置可自行百度,本次配置主要是使用AOP对用户的出参和入参进行打印,以便查找并修复线上问题。

@Slf4j
@Aspect
@Component
public class AspectLog {/*** 换行符*/private static final String LINE_SEPARATOR = System.lineSeparator();@Around("execution( * com.abab.common.controller..*.*(..))")public Object accountController(ProceedingJoinPoint joinPoint) throws Throwable {return doAround(joinPoint);}public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {// 开始打印请求日志ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();// 获取 @WebLog 注解的描述信息/*String methodDescription = getAspectLogDescription(joinPoint);*/// 打印请求相关参数log.info("========================================== Start ==========================================");// 打印请求 urllog.info("URL            : {}", request.getRequestURL().toString());// 打印描述信息/*log.info("Description    : {}", methodDescription);*/// 打印 Http methodlog.info("HTTP Method    : {}", request.getMethod());// 打印调用 controller 的全路径以及执行方法log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());// 打印请求的 IPlog.info("IP             : {}", request.getRemoteAddr());// 打印请求入参log.info("Request Args   : {}", getParams(joinPoint));long startTime = System.currentTimeMillis();Object result = null;try {result = joinPoint.proceed();// 打印出参log.info("Response Data  : {}", JSONObject.toJSONString(result));} catch (Throwable throwable) {//throwable.printStackTrace();log.info("Response ERROR : {}", throwable);throw throwable;} finally {// 执行耗时log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);log.info("=========================================== End ===========================================" + LINE_SEPARATOR);}return result;}private String getParams(JoinPoint joinPoint) {JSONObject params = new JSONObject();// 参数名String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();// 参数值Object[] args = joinPoint.getArgs();if (args != null && args.length > 0) {for (int i = 0; i < args.length; i++) {Object arg = args[i];if ((arg instanceof HttpServletResponse) || (arg instanceof HttpServletRequest)|| (arg instanceof MultipartFile) || (arg instanceof MultipartFile[])) {continue;}try {params.put(argNames[i], args[i]);} catch (Exception e1) {log.error(e1.getMessage());}}}return params.toJSONString();}}

springboot项目脚手架相关推荐

  1. docker 搭建指定版本的cas_Docker搭建-生成SpringBoot项目脚手架-各版本

    start.spring.io是用来生成SpringBoot项目脚手架的,因为网络的原因,某些情况下无法正常访问.有时候我们也需要一些历史的版本.基于这两个原因,我们可以将它的代码拉下来,在本地打包, ...

  2. SpringBoot项目之自定义Maven脚手架快速开发构建工程

    一.前言 在我们日常开发过程中,经常需要新建一些工程去处理相应模块的业务,同时也为了更好的区分模块边界,所以我们需要构建一些符合当前公司代码模块风格的自定义工程.下面是我供职于某互联网公司搭建脚手架的 ...

  3. agilebpm脑图_干货基于SpringBoot2开发的Activiti引擎流程管理项目脚手架

    干货基于SpringBoot2开发的Activiti引擎流程管理项目脚手架 [干货]基于SpringBoot2开发的Activiti引擎流程管理项目脚手架 前言 在工作中,难免会遇到需要开发基于流程管 ...

  4. 这 5 个能挣钱的 SpringBoot 项目,真TMD香!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:又一程序员进了ICU:压垮一个家庭,一张结算单就够 个人原创100W+访问量博客:点击前往,查看更多 不得不佩服 ...

  5. 补习系列(1)-springboot项目基础搭建课

    目录 前言 一.基础结构 二.添加代码 三.应用配置 四.日志配置 五.打包部署 小结 前言 springboot 最近火的不行,目前几乎已经是 spring 家族最耀眼的项目了.抛开微服务.技术社区 ...

  6. SpringBoot+vue仿网易云音乐网站(三)- Springboot项目以及前端vue基础搭建

    一.基础项目搭建 1. 新建springboot项目 在搭建Springboot项目之前,需要的基础环境:JDK(8).Maven,工具Idea.项目就新建一个简单的springboot项目就行了,具 ...

  7. Java中如何快速构建项目脚手架

    文章目录 1 前言 2 微服务项目准备 3 脚手架构建 3.1 项目正常启动 && 测试用例正常 3.2 在项目的根pom中加入以下maven插件配置 3.3 执行archetype插 ...

  8. IDEA创建springboot项目

    1.新建springboot项目 2.选择版本依赖 3.maven配置 4.yml文件配置 # YML文件的语法 # 1.数据结构 key-value结构 # 2.写法: key:(空格)value ...

  9. 物联网云平台设计与开发:springboot项目搭建与开发(后端)

    目录 实验目的 实验内容 具体实验步骤 第一步:构建springboot项目 第二步:项目集成spring-web.Mysql驱动.Mybatis等框架. 第三步:安装Mysql软件,使用Navica ...

最新文章

  1. 2014年02月16日
  2. linux~mysql安装、卸载及使用命令
  3. xjtlu mac mail 绑定
  4. [置顶] C/C++超级大火锅
  5. ml是什么_ML,ML,谁是所有人的冠军?
  6. 上海女白领吃火锅碰瓷,支付宝口碑居然真的要赔?
  7. 新法案下 苹果或被禁止在设备上预装自家应用
  8. 浏览器是否支持Html5
  9. 安装命令提示符版CentOS6.5
  10. Unity3d Network 局域网多人对战之游戏大厅
  11. 微信小程序chooseMedia应用
  12. VUE图片裁剪,打码,旋转功能
  13. Lonlife-ACM 1014 - Absolute Defeat [差分]
  14. openwrt默认mac地址配置(MT7620a)
  15. 高分一号PMS相机多光谱和全色数据预处理
  16. iif能用到mysql中吗_数据库iif
  17. 山东计算机技校排名,山东技校排名前十 山东有什么好的技校
  18. 方法重写的两同两小一大原则
  19. 医疗管理系统-预约管理
  20. Remove WebCakeDesktop

热门文章

  1. DNA序列 UVa1368
  2. 知道创宇区块链安全实验室|二月安全事件总结与回顾
  3. Spring Boot SSL证书验证的问题
  4. 直播app源代码,手机屏幕截取并保存到手机相册
  5. 关于定义二维数组时为什么可以省略行,而不可以省略列
  6. 周鸿袆:360回归A股不是为炒股 是出于国家安全考虑
  7. matlab标准化和反标准化——zscore
  8. PHP中curl的CURLOPT_POSTFIELDS请求时,Content-Type多出boundary=------------------------
  9. 安卓7.0 申请相机及读写权限
  10. 重现CD情怀——飞利浦复古桌面音响臻选上市