SpringBoot Web应用范例

本文主要是介绍一个基于SpringBoot的Web应用范例,范例中根据自己多年的工作经验及总结提供了一些使用建议,希望对大家有所启发

  • 代码结构概览
    代码结构很简单,就是很常见的三层架构,通过包名来清晰的展现该种层次结构:


    image.png
  • Web API封装
    Web API层主要是给前端提供web api接口,我们规定了,所有的api接口响应报文必须是如下结构体:

public class Response<T> {

    private int status;
    private String msg;
    private T data;

    public Response() {
    }

    public Response(int status, String msg, T data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

其中 status表明接口状态码(成功/失败/其他...,0表示成功), msg是对状态码的简单文字描述(比如:success、失败原因 等等), data是接口返回的具体数据

对返回报文格式进行统一规定,有利于前端做一些公共逻辑:比如对非0状态码记录console日志、对一些特定状态码执行一些统一逻辑等等

返回统一报文格式是通过AOP来实现的,并不需要在业务代码中转换成Response实体,封装代码如下:

  1. 接口正常返回的情况:
@Order(1)
@ControllerAdvice(basePackages = AppContants.API_BASE_PACKAGE)
public class ApiResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    private static final Logger logger = LoggerFactory.getLogger(ApiResponseBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                    Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                    ServerHttpResponse response) {
        Response<Object> resp = new Response<>();
        resp.setStatus(0);
        resp.setMsg("success");
        resp.setData(body);

        if(returnType.getMethod().getReturnType() == String.class){
            return JSON.toJSONString(resp);
        }else{
            return resp;
        }
    }
}
  1. 接口抛异常的情况:
@ControllerAdvice(basePackages = AppContants.API_BASE_PACKAGE)
public class ApiExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final int UNKNOWN_EXCEPTION_STATUS = -2;
    private static final int ILLEGAL_ARGUMENT_STATUS = -1;

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Response defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        Response response = new Response();
        if (e instanceof AppException) {
            response.setStatus(((AppException) e).getCode());
            response.setMsg(e.getMessage());
        } else if (e instanceof IllegalArgumentException) {
            response.setStatus(ILLEGAL_ARGUMENT_STATUS);
            response.setMsg(e.getMessage());
        } else {
            logger.error("Got exception,url=" + req.getRequestURI(), e);
            response.setStatus(UNKNOWN_EXCEPTION_STATUS);
            response.setMsg("接口异常");
        }
        return response;
    }
}

经过这样的封装后,业务代码中不再涉及Response实体的转换,如下例子所示:

@RestController
@Api(description = "用户相关接口")
@RequestMapping("/api/user")
public class UserEndpoint {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private UserService userService;

    @ApiOperation(value = "查询用户", notes = "根据用户id查询用户详情")
    @GetMapping("/{userId}")
    public User getUser(@PathVariable("userId") Integer userId) {
        Preconditions.checkNotNull(userId, "user id not provided");
        Preconditions.checkArgument(userId > 0, "user id must greater than 0");

        return this.userService.getUser(userId);
    }

    @ApiOperation(value = "更新用户信息")
    @PostMapping("/update")
    public void updateUser(@RequestBody User user) {
        logger.info("User:{}", user);
    }
}

在这里简单说一下,上面代码有几句关于参数校验的代码(如下所示),我们只需要简单用Preconditions工具类来进行判断,如果条件不满足将会抛出IllegalArgumentException,这个未捕获的异常将会在ApiExceptionHandler得到处理 并将返回status设置为-1,msg设置为异常信息。这样处理后显得代码特别简洁 有木有~

Preconditions.checkNotNull(userId, "user id not provided");
Preconditions.checkArgument(userId > 0, "user id must greater than 0");
  • Swagger API文档
    关于Swagger的介绍,网上有很多,不了解的可以看看:Spring Boot中使用Swagger2构建强大的RESTful API文档

    Springboot 可以很简单地就把swagger 集成到应用中,通过swagger api文档,可以减少前后端的沟通成本,并且也给后端人员提供了便捷的调试接口的方式,非常推荐使用

  • Github 源代码
    本文中所涉及的完整的代码已经放到github上,有兴趣的童鞋可以看看:springboot-web-showcase

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 我想, 开成一枝海棠, 在赏花的人群里, 偷看你的模样。 我想, 开成一缕阳光, 透过半开的窗帘, 亲吻你的脸庞。...
    梦见月光阅读 231评论 0 2
  • 我的内心充斥着孤独。Sorrow. I am so sorrowful.
    我叫王小丫阅读 350评论 0 0
  • 孟子曰:仁义礼智。后经董仲舒发展成了:仁义礼智信。也就是我们后来讲的“五常”。这五常贯穿于中国民族伦理发展中...
    98波妞阅读 222评论 0 0