一个基于Spring Boot的API、RESTful API项目种子(骨架)

本文分享了使用SpringBoot结合MyBatis等工具快速搭建API项目的实践经验,包括统一响应封装、异常处理、基础代码生成等内容。

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

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

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

特征&提供 最佳实践的项目结构、配置文件、精简的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 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 { void save(T model);//持久化 void save(List 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 findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4” List findByCondition(Condition condition);//根据条件查找 List 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() { @Override public 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码排序
    1. 拼接为a=value&b=value...这样的字符串(不包含sign)
    1. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较 */ private boolean validateSign(HttpServletRequest request) { String requestSign = request.getParameter("sign");//获得请求签名,如sign=19e907700db7ad91318424a97c54ed57 if (StringUtils.isEmpty(requestSign)) { return false; } List keys = new ArrayList(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);//混合密钥md5

      return StringUtils.equals(sign, requestSign);//比较 } 集成MyBatis、通用Mapper插件、PageHelper分页插件,实现单表业务零SQL

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

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

修改application-dev.yml中的数据库配置环境 * 继承通用接口直接使用,或根据业务在基础代码上扩展 * 代码生成:在CodeGenerator的main方法中修改需要生成的表名,运行即可 ## 代码结构 ```bash ├── README.md ├── pom.xml ├── springboot-seedproject.iml ├── src │   ├── main │   │   ├── java │   │   │   └── pers │   │   │   └── hong │   │   │   └── project │ │ │ ├── SpringbootSeedprojectApplication.java 启动类 │ │ │ ├── common │ │ │ │ ├── Constants.java 常量 │ │ │ │ ├── Result.java 结果集 │ │ │ │ ├── ResultGenerator.java 响应结果生成工具 │ │ │ │ └── ServiceException.java 业务异常 │ │ │ ├── config │ │ │ │ ├── MybatisConfig.java Mybatis配置 │ │ │ │ └── WebMvcConfig.java MVC配置 │ │ │ ├── core │ │ │ │ ├── AbstractService.java service实现 │ │ │ │ ├── Mapper.java 通用mapper │ │ │ │ └── Service.java 通用service │ │ │ └── generator │ │ │ └── CodeGenerator.java 代码生成器 │ │ └── resources │ │ ├── application-dev.yml 开发环境 │ │ ├── application-pro.yml 生产环境 │ │ ├── application-test.yml 测试环境 │ │ ├── application.yml 配置文件 │ │ ├── banner.txt banner │ │ ├── mapper │ │ └── template ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值