点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试文章

作者:简单的土豆

www.jianshu.com/p/99fcead32d35

前言

最近使用Spring Boot 配合 MyBatis 、通用Mapper插件、PageHelper分页插件 连做了几个中小型API项目,做下来觉得这套框架、工具搭配起来开发这种项目确实非常舒服,团队的反响也不错。在项目搭建和开发的过程中也总结了一些小经验,与大家分享一下。

在开发一个API项目之前,搭建项目、引入依赖、配置框架这些基础活自然不用多说,通常为了加快项目的开发进度(早点回家)还需要封装一些常用的类和工具,比如统一的响应结果封装、统一的异常处理、接口签名认证、基础的增删改差方法封装、基础代码生成工具等等,有了这些项目才能开工。

然而,下次再做类似的项目上述那些步骤可能还要搞一遍,虽然通常是拿过来改改,但是还是比较浪费时间。所以,可以利用面向对象抽象、封装的思想,抽取这类项目的共同之处封装成了一个种子项目(估计大部分公司都会有很多类似的种子项目),这样的话下次再开发类似的项目直接在该种子项目上迭代就可以了,减少无意义的重复工作。

在相关项目上线之后,我花了点时间对该种子项目做了一些精简,并且已经把该项目分享到GitHub上面了,如果你正准备做类似项目的话,可以去克隆下来试试。

项目地址&使用文档:https://github.com/lihengming/spring-boot-api-project-seed 。

如果在使用中发现问题或者有什么好建议的话欢迎提issue或pr一起来完善它。

特征&提供

最佳实践的项目结构、配置文件、精简的POM

注:使用代码生成器生成代码后会创建model、dao、service、web等包。

统一响应结果封装及生成工具

/*** 统一API响应结果封装*/
public class Result {private int code;private String message;private Object data;public Result setCode(ResultCode resultCode) {this.code = resultCode.code;return this;}//省略getter、setter方法
}
/*** 响应码枚举,参考HTTP状态码的语义*/
public enum ResultCode {SUCCESS(200),//成功FAIL(400),//失败UNAUTHORIZED(401),//未认证(签名错误)NOT_FOUND(404),//接口不存在INTERNAL_SERVER_ERROR(500);//服务器内部错误public int code;ResultCode(int code) {this.code = code;}
}
/*** 响应结果生成工具*/
public class ResultGenerator {private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";public static Result genSuccessResult() {return new Result().setCode(ResultCode.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE);}public static Result genSuccessResult(Object data) {return new Result().setCode(ResultCode.SUCCESS).setMessage(DEFAULT_SUCCESS_MESSAGE).setData(data);}public static Result genFailResult(String message) {return new Result().setCode(ResultCode.FAIL).setMessage(message);}
}

统一异常处理

  public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {exceptionResolvers.add(new HandlerExceptionResolver() {public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {Result result = new Result();if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误”result.setCode(ResultCode.FAIL).setMessage(e.getMessage());logger.info(e.getMessage());} else if (e instanceof NoHandlerFoundException) {result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在");} else if (e instanceof ServletException) {result.setCode(ResultCode.FAIL).setMessage(e.getMessage());} else {result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员");String message;if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",request.getRequestURI(),handlerMethod.getBean().getClass().getName(),handlerMethod.getMethod().getName(),e.getMessage());} else {message = e.getMessage();}logger.error(message, e);}responseResult(response, result);return new ModelAndView();}});}

常用基础方法抽象封装

public interface Service<T> {void save(T model);//持久化void save(List<T> models);//批量持久化void deleteById(Integer id);//通过主鍵刪除void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4”void update(T model);//更新T findById(Integer id);//通过ID查找T findBy(String fieldName, Object value) throws TooManyResultsException; //通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束List<T> findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4”List<T> findByCondition(Condition condition);//根据条件查找List<T> findAll();//获取所有
}

提供代码生成器来生成基础代码

public abstract class CodeGenerator {...public static void main(String[] args) {genCode("输入表名");}public static void genCode(String... tableNames) {for (String tableName : tableNames) {//根据需求生成,不需要的注掉,模板有问题的话可以自己修改。genModelAndMapper(tableName);genService(tableName);genController(tableName);}}...
}

CodeGenerator 可根据表名生成对应的Model、Mapper、MapperXML、Service、ServiceImpl、Controller(默认提供POST和RESTful两套Controller模板,根据需要在 genController(tableName)方法中自己选择,默认是纯POST的),代码模板可根据实际项目的需求来定制,以便渐少重复劳动。

由于每个公司业务都不太一样,所以只提供了一些简单的通用方法模板,主要是提供一个思路来减少重复代码的编写。在我们公司的实际使用中,其实根据业务的抽象编写了大量的代码模板。扩展:优秀的代码都是如何分层的?

提供简单的接口签名认证

public void addInterceptors(InterceptorRegistry registry) {//接口签名认证拦截器,该签名认证比较简单,实际项目中可以使用Json Web Token或其他更好的方式替代。if (!"dev".equals(env)) { //开发环境忽略签名认证registry.addInterceptor(new HandlerInterceptorAdapter() {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//验证签名boolean pass = validateSign(request);if (pass) {return true;} else {logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}",request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap()));Result result = new Result();result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败");responseResult(response, result);return false;}}});}
}
/*** 一个简单的签名认证,规则:* 1. 将请求参数按ascii码排序* 2. 拼接为a=value&b=value...这样的字符串(不包含sign)* 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较*/
private boolean validateSign(HttpServletRequest request) {String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57if (StringUtils.isEmpty(requestSign)) {return false;}List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());keys.remove("sign");//排除sign参数Collections.sort(keys);//排序StringBuilder sb = new StringBuilder();for (String key : keys) {sb.append(key).append("=").append(request.getParameter(key)).append("&");//拼接字符串}String linkString = sb.toString();linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);//去除最后一个'&'String secret = "Potato";//密钥,自己修改String sign = DigestUtils.md5Hex(linkString + secret);//混合密钥md5return StringUtils.equals(sign, requestSign);//比较
}

集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL

使用Druid Spring Boot Starter 集成Druid数据库连接池与监控

使用FastJsonHttpMessageConverter,提高JSON序列化速度

技术选型&文档

Spring Boot:https://www.jianshu.com/p/1a9fd8936bd8
MyBatis:http://www.mybatis.org/mybatis-3/zh/index.html
MyBatisb通用Mapper插件:https://mapperhelper.github.io/docs/
MyBatis PageHelper分页插件:https://pagehelper.github.io/
Druid Spring Boot Starter:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/
Fastjson:https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5

热门内容:你能说出多线程中 sleep、yield、join 的用法及 sleep与wait区别吗?
试试 IntelliJ IDEA 自带的高能神器!我去,你写的 switch 语句也太老土了吧硬核干货:一位码农的架构师封神之路!
阿里问题定位神器 Arthas 的骚操作,定位线上BUG,超给力
用好idea这几款插件,可以帮你少写30%的代码!最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。

一个基于Spring Boot的API、RESTful API项目骨架相关推荐

  1. 一个基于Spring极度简单的Restful API工具

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 作者:小 ...

  2. 保姆级的一个基于spring boot开发的前后端分离商城教程

    前言 推荐一个基于spring boot开发前后端分离商城,有完整的代码笔记和视频教程,希望对正在找项目练手的同学有所帮助 本文资料文档领取(在文末) 一.项目背景 5中常见的电商模式 B2B .B2 ...

  3. 一个基于 Spring Boot 的开源社区

    一款基于 Spring Boot 的开源社区:forum-java,类似于微信开放社区.头条开发者社区等等.forum-java 是一个 100% 开源的面向内容的社区论坛. 开源社区有用户端和管理端 ...

  4. 自荐Mall4j项目一个基于spring boot的Java开源商城系统

    前言 Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样 ...

  5. java restful接口开发实例_实战:基于Spring Boot快速开发RESTful风格API接口

    写在前面的话 这篇文章计划是在过年期间完成的,示例代码都写好了,结果亲戚来我家做客,文章没来得及写.已经很久没有更新文章了,小伙伴们,有没有想我啊.言归正传,下面开始,今天的话题. 目标 写一套符合规 ...

  6. 推荐一个基于 Spring Boot+MyBatis Plus+JWT 的问卷系统!

    你好呀,我是 Guide!这里是 JavaGuide 的「优质开源项目推荐」第 8 期,每一期我都会精选 5 个高质量的 Java 开源项目. 时间过的真快,不知不觉「优质开源项目推荐」系列已经持续半 ...

  7. 你值得拥有!一个基于 Spring Boot 的API、RESTful API 的项目

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:腾讯推出高性能 RPC 开发框架 个人原创100W+访问量博客:点击前往,查看更多 前言 最近使用Spring ...

  8. 一个mapper接口有多个mapper.xml 文件_爱了!分享一个基于Spring Boot的API、RESTful API项目种子(骨架)!...

    点击上方"Java专栏",选择"置顶或者星标" 第一时间阅读精彩文章! 1.☞ 程序员进阶必备资源免费送「21种技术方向!」 点击查看☜ 2.☞ <Jav ...

  9. 使用Spring Rest和Spring Data JPA和H2以及Spring Boot示例的Restful API

    你好朋友, 在本教程中,您将学习以下内容: 1.在Spring Boot中配置Spring Rest,Spring Data JPA和H2 2.使用Spring Boot创建Springful服务端点 ...

最新文章

  1. quick-cocos2dx在eclipse下的lua调试
  2. 大学生一定记得要做的十八件事情
  3. 数据结构算法 二进制转十进制_数据结构 - 栈
  4. Win10 + Python + MXNet + VS2015配置
  5. c语言 两条线段位置,C++/STL实现判断平面内两条线段的位置关系代码示例
  6. 【2050 Programming Competition - 2050 一万人码 】非官方部分题解(HDU)
  7. LeetCode MySQL 1853. 转换日期格式(日期格式化)
  8. SpringBoot2.1.5 (22)--- SpringBoot设置支持跨域请求
  9. android工程的建立,第一个Android项目HelloWorld的建立及剖析
  10. android studio gradle 更新方法。
  11. 开课吧课堂:C++开发语言的应用方向有哪些?
  12. php连接oracle设定字符集,避免乱码
  13. mysql中like,limit,union及union all查询
  14. 色彩的对比度和饱和度_使用高色彩对比度进行更方便的设计
  15. 默纳克系统用服务器呼梯设定,默纳克系统常见问题之四如何区分3000与3000new _ 默者_h...
  16. 判断一个点是否在矩形内PtInRegion-解决PtInRect不能正确判断不同形式TRent的情况
  17. 补充:混淆矩阵、图像分割指标计算
  18. java 数据库 事务 只读_Spring 事务 readOnly 到底是怎么回事?
  19. 全国计算机等级考试excel公式,全国计算机等级考试Excell公式大全
  20. Gitlab两个项目代码合并

热门文章

  1. 关于 MongoDB 与 SQL Server 通过本身自带工具实现数据快速迁移 及 注意事项 的探究...
  2. oracle数据库增加新字段
  3. 老王Python-进阶篇4-异常处理1.3(周末习题)
  4. JAVA实现长连接(含心跳检测)Demo
  5. Effective Java:对于全部对象都通用的方法
  6. Hadoop学习笔记(1) ——菜鸟入门
  7. word表格自动编号
  8. 【直播】黎佳佳:音频数据分析以及特征提取
  9. LeetCode实战:最长公共前缀
  10. 【怎样写代码】向现有类型“添加”方法 -- 扩展方法(二):扩展方法的实现与调用