注:使用代碼生成器生成代碼后會(huì)創(chuàng)建model、dao、service、web等包。

統(tǒng)一響應(yīng)結(jié)果封裝及生成工具

/**
* 統(tǒng)一API響應(yīng)結(jié)果封裝
*/
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方法
}
/**
* 響應(yīng)碼枚舉,參考HTTP狀態(tài)碼的語(yǔ)義
*/
public enum ResultCode {
SUCCESS(200),//成功
FAIL(400),//失敗
UNAUTHORIZED(401),//未認(rèn)證(簽名錯(cuò)誤)
NOT_FOUND(404),//接口不存在
INTERNAL_SERVER_ERROR(500);//服務(wù)器內(nèi)部錯(cuò)誤

public int code;

ResultCode(int code) {
this.code = code;
}
}
/**
* 響應(yīng)結(jié)果生成工具
*/
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);
}
}

統(tǒng)一異常處理

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) {//業(yè)務(wù)失敗的異常,如“賬號(hào)或密碼錯(cuò)誤”
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() + "] 內(nèi)部錯(cuò)誤,請(qǐng)聯(lián)系管理員");
String message;
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
message = String.format("接口 [%s] 出現(xiàn)異常,方法:%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();
}

});
}

常用基礎(chǔ)方法抽象封裝

public interface Service<T> {
void save(T model);//持久化
void save(List<T> models);//批量持久化
void deleteById(Integer id);//通過(guò)主鍵刪除
void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4”
void update(T model);//更新
T findById(Integer id);//通過(guò)ID查找
T findBy(String fieldName, Object value) throws TooManyResultsException; //通過(guò)Model中某個(gè)成員變量名稱(非數(shù)據(jù)表中column的名稱)查找,value需符合unique約束
List<T> findByIds(String ids);//通過(guò)多個(gè)ID查找//eg:ids -> “1,2,3,4”
List<T> findByCondition(Condition condition);//根據(jù)條件查找
List<T> findAll();//獲取所有
}

提供代碼生成器來(lái)生成基礎(chǔ)代碼

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

CodeGenerator 可根據(jù)表名生成對(duì)應(yīng)的Model、Mapper、MapperXML、Service、ServiceImpl、Controller(默認(rèn)提供POST和RESTful兩套Controller模板,根據(jù)需要在 genController(tableName)方法中自己選擇,默認(rèn)是純POST的),代碼模板可根據(jù)實(shí)際項(xiàng)目的需求來(lái)定制,以便漸少重復(fù)勞動(dòng)。

由于每個(gè)公司業(yè)務(wù)都不太一樣,所以只提供了一些簡(jiǎn)單的通用方法模板,主要是提供一個(gè)思路來(lái)減少重復(fù)代碼的編寫。在我們公司的實(shí)際使用中,其實(shí)根據(jù)業(yè)務(wù)的抽象編寫了大量的代碼模板。擴(kuò)展:優(yōu)秀的代碼都是如何分層的?

提供簡(jiǎn)單的接口簽名認(rèn)證

public void addInterceptors(InterceptorRegistry registry) {
//接口簽名認(rèn)證攔截器,該簽名認(rèn)證比較簡(jiǎn)單,實(shí)際項(xiàng)目中可以使用Json Web Token或其他更好的方式替代。
if (!"dev".equals(env)) { //開發(fā)環(huán)境忽略簽名認(rèn)證
registry.addInterceptor(new HandlerInterceptorAdapter() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//驗(yàn)證簽名
boolean pass = validateSign(request);
if (pass) {
return true;
} else {
logger.warn("簽名認(rèn)證失敗,請(qǐng)求接口:{},請(qǐng)求IP:{},請(qǐng)求參數(shù):{}",
request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap()));

Result result = new Result();
result.setCode(ResultCode.UNAUTHORIZED).setMessage("簽名認(rèn)證失敗");
responseResult(response, result);
return false;
}
}
});
}
}
/**
* 一個(gè)簡(jiǎn)單的簽名認(rèn)證,規(guī)則:
* 1. 將請(qǐng)求參數(shù)按ascii碼排序
* 2. 拼接為a=value&b=value...這樣的字符串(不包含sign)
* 3. 混合密鑰(secret)進(jìn)行md5獲得簽名,與請(qǐng)求的簽名進(jìn)行比較
*/
private boolean validateSign(HttpServletRequest request) {
String requestSign = request.getParameter("sign");//獲得請(qǐng)求簽名,如sign=19e907700db7ad91318424a97c54ed57
if (StringUtils.isEmpty(requestSign)) {
return false;
}
List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
keys.remove("sign");//排除sign參數(shù)
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);//去除最后一個(gè)'&'

String secret = "Potato";//密鑰,自己修改
String sign = DigestUtils.md5Hex(linkString + secret);//混合密鑰md5

return StringUtils.equals(sign, requestSign);//比較
}

集成MyBatis、通用Mapper插件、PageHelper分頁(yè)插件,實(shí)現(xiàn)單表業(yè)務(wù)零SQL

使用Druid Spring Boot Starter 集成Druid數(shù)據(jù)庫(kù)連接池與監(jiān)控

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

技術(shù)選型&文檔

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分頁(yè)插件: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

本文章轉(zhuǎn)載微信公眾號(hào)@方志朋

上一篇:

14個(gè)讓你驚艷的JavaScript Web API

下一篇:

22種使你的API設(shè)計(jì)技能更上一層樓的最佳實(shí)踐方案
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)