【swagger】2.swagger提供開發者文檔--返回統一格式篇【spring mvc】【spring boot】

接着上一篇來講,html

無論正常返回結果仍是後臺出現異常,應該返回給前臺統一的響應格式。java

因此這一篇就爲了應對解決這個問題。mysql

========================================================================web

1.首先,定義一個統一返回類【全部返回的格式都是這個類的格式】redis

package com.sxd.sweeping.response;

import com.alibaba.fastjson.JSON;
import lombok.*;

import java.io.Serializable;
import java.util.Objects;

/**
 * 統一JSON返回類
 * @author sxd
 * @since 2018/4/1
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GenericResponse implements Serializable{


    /**
     * 程序定義狀態碼
     */
    private int code;
    /**
     * 必要的提示信息
     */
    private String message;
    /**
     * 業務數據
     */
    private Object datas;

    /**
     * 對業務數據單獨處理
     * @return
     */
    @Override
    public String toString() {
        if(Objects.isNull(this.datas)){
            this.setDatas(new Object());
        }
        return JSON.toJSONString(this);
    }
}
View Code

2.定義統一返回數據格式【這裏定義了一些經常使用返回code+msg,用於填充上面的統一格式】spring

package com.sxd.sweeping.response;

import com.google.common.collect.Maps;

import java.util.Map;

/**
 * 統一返回客戶端數據格式
 * @author sxd
 * @since 2018/4/1
 */
public class ResponseFormat {

    private static Map<Integer,String> messageMap = Maps.newHashMap();
    //初始化狀態碼與文字說明
    static {
        /* 成功狀態碼 */
        messageMap.put(200, "成功");

        /* 服務器錯誤 */
        messageMap.put(1000,"服務器錯誤");

        /* 參數錯誤:10001-19999 */
        messageMap.put(10001, "參數無效");
        messageMap.put(10002, "參數爲空");
        messageMap.put(10003, "參數類型錯誤");
        messageMap.put(10004, "參數缺失");

        /* 用戶錯誤:20001-29999*/
        messageMap.put(20001, "用戶未登陸");
        messageMap.put(20002, "帳號不存在或密碼錯誤");
        messageMap.put(20003, "帳號已被禁用");
        messageMap.put(20004, "用戶不存在");
        messageMap.put(20005, "用戶已存在");

        /* 業務錯誤:30001-39999 */
        messageMap.put(30001, "某業務出現問題");

        /* 系統錯誤:40001-49999 */
        messageMap.put(40001, "系統繁忙,請稍後重試");

        /* 數據錯誤:50001-599999 */
        messageMap.put(50001, "數據未找到");
        messageMap.put(50002, "數據有誤");
        messageMap.put(50003, "數據已存在");
        messageMap.put(50004,"查詢出錯");

        /* 接口錯誤:60001-69999 */
        messageMap.put(60001, "內部系統接口調用異常");
        messageMap.put(60002, "外部系統接口調用異常");
        messageMap.put(60003, "該接口禁止訪問");
        messageMap.put(60004, "接口地址無效");
        messageMap.put(60005, "接口請求超時");
        messageMap.put(60006, "接口負載太高");

        /* 權限錯誤:70001-79999 */
        messageMap.put(70001, "無權限訪問");
    }
    public static GenericResponse retParam(Integer status,Object data) {
        GenericResponse json = new GenericResponse(status, messageMap.get(status), data);
        return json;
    }
}
View Code

3.定義本身的異常類 由於spring 對於 RuntimeException 異常纔會進行事務回滾,因此繼承的是RuntimeException【可用於代碼中本身throw異常】sql

package com.sxd.sweeping.handler;

import lombok.Getter;
import lombok.Setter;


/**
 * spring 對於 RuntimeException 異常纔會進行事務回滾。
 * @author sxd
 * @since 2018/4/1
 */
@Getter
@Setter
public class MyException extends RuntimeException {

    public MyException(Integer code, Exception exception) {
        this.code = code;
        this.exception = exception;
    }

    private Integer code;
    private Exception exception;
}
View Code

4.定義Controller加強器,使用註解@ControllerAdvice,具體使用說明查看代碼【對異常進行統一攔截,而後配置返回格式】mongodb

package com.sxd.sweeping.handler;

import com.sxd.sweeping.response.GenericResponse;
import com.sxd.sweeping.response.ResponseFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;


/**
 * controller 加強器 原理是使用AOP對Controller控制器進行加強(前置加強、後置加強、環繞加強)
 * 啓動應用後,被 @ExceptionHandler、@InitBinder、@ModelAttribute 註解的方法,都會做用在 被 @RequestMapping 註解的方法上。
 * @ModelAttribute:在Model上設置的值,對於全部被 @RequestMapping 註解的方法中,均可以經過 ModelMap獲取,或者經過@ModelAttribute("author")也能夠獲取
 * @ExceptionHandler 攔截了異常,咱們能夠經過該註解實現自定義異常處理。其中,@ExceptionHandler 配置的 value 指定須要攔截的異常類型,下面攔截了 Exception.class 這種異常。
 * @author sxd
 * @since 2018/4/1
 */
@ControllerAdvice
public class MyControllerAdvice {

    Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 應用到全部@RequestMapping註解方法,在其執行以前初始化數據綁定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * 把值綁定到Model中,使全局@RequestMapping能夠獲取到該值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "sxd");
    }

    /**
     * 全局異常捕捉處理
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public GenericResponse errorHandler(Exception ex) {
        ex.printStackTrace();
        return ResponseFormat.retParam(1000,null);
    }

    /**
     * 攔截捕捉自定義異常 MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MyException.class)
    public GenericResponse myErrorHandler(MyException ex) {
        ex.getException().printStackTrace();
        logger.error(ex.getException().toString());
        return  ResponseFormat.retParam(ex.getCode(),null);
    }
}
View Code

5.Swagger類json

package com.sxd.sweeping;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2 {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sxd.sweeping.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2構建RESTful APIs")
                .description("更多精彩博客請關注:http://www.cnblogs.com/sxdcgaq8080/")
                .termsOfServiceUrl("http://www.cnblogs.com/sxdcgaq8080/")
                .contact("Angel擠一擠")
                .version("1.0")
                .build();
    }
}
View Code

6.api

  6.1 Controller類

package com.sxd.sweeping.controller;

import com.sxd.sweeping.entity.User;
import com.sxd.sweeping.handler.MyException;
import com.sxd.sweeping.repository.UserRepository;
import com.sxd.sweeping.response.GenericResponse;
import com.sxd.sweeping.response.ResponseFormat;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.sql.Date;
import java.util.UUID;

@Api(value = "userController",description = "用戶相關操做",tags = {"用戶"})
@RestController
@RequestMapping("users")
public class UserController {

    @Autowired
    private UserRepository userRepository;


    @ApiOperation(value = "獲取用戶詳細信息", notes = "根據url的id來獲取用戶的詳細信息")
    @ApiImplicitParam(name = "id", value = "用戶ID", required = true,dataType = "Long",paramType = "path")
//    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    @GetMapping(value = "/{id}")
    public GenericResponse get(@PathVariable Long id){
        User user;
        try{
            user = userRepository.findUserById(id);
        }catch(Exception e){
            user = null;
            throw new MyException(50004,e);
        }
        return ResponseFormat.retParam(200,user);
    }

    @ApiOperation(value = "增長用戶", notes = "根據user對象建立用戶")
    @ApiImplicitParam(name = "user", value = "用戶詳細信息User", required = true,dataType = "User")
//    @RequestMapping(method = RequestMethod.POST)
    @PostMapping()
    public GenericResponse add(@RequestBody User user){
        String password = UUID.randomUUID().toString();
        user.setPassword(password);
        user =  userRepository.save(user);

        return ResponseFormat.retParam(200,user);
    }


    @ApiOperation(value = "刪除用戶", notes = "根據url的id來刪除用戶")
    @ApiImplicitParam(name = "id", value = "用戶ID", required = true,dataType = "Long",paramType = "path")
//    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    @DeleteMapping(value = "/{id}")
    @ResponseBody
    public GenericResponse delete(@PathVariable Long id){
        userRepository.deleteById(id);
        return ResponseFormat.retParam(200,"ID爲"+id+"的用戶刪除成功");
    }

    @ApiOperation(value = "更新用戶", notes = "根據url的id來更新用戶信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用戶ID", required = true, dataType = "Long", paramType = "path"),
            @ApiImplicitParam(name = "user", value = "用戶實體user", required = true,dataType = "User")
    })
//    @RequestMapping(value = "/{id}",method = RequestMethod.PUT)
    @PutMapping(value = "/{id}")
    public GenericResponse update(@PathVariable Long id, @RequestBody  User user){
        User user1 = userRepository.findUserById(id);
        user1.setGender(user.getGender());
        user1.setMobile(user.getMobile());
        user1.setRealname(user.getRealname());
        user1.setUpdateAt(new Date(System.currentTimeMillis()));

        return  ResponseFormat.retParam(200,user1);
    }

    @ApiOperation(value = "更新用戶局部信息", notes = "根據url的id來更新用戶局部信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用戶ID", required = true, dataType = "Long", paramType = "path"),
            @ApiImplicitParam(name = "realname", value = "用戶名", required = true,dataType = "String"),
            @ApiImplicitParam(name = "mobile", value = "聯繫方式", required = true,dataType = "String")
    })
//    @RequestMapping(value = "/{id}",method = RequestMethod.PATCH)
    @PatchMapping(value = "/{id}")
    public GenericResponse patch(@PathVariable Long id, String realname, String mobile){
        User user = userRepository.findUserById(id);
        user.setRealname(realname);
        user.setMobile(mobile);

        return ResponseFormat.retParam(200,userRepository.saveAndFlush(user));
    }

    @ApiOperation(value = "獲取用戶信息列表", notes = "獲取用戶信息列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "頁碼", required = true,dataType = "int"),
            @ApiImplicitParam(name = "size", value = "單頁條數", required = true,dataType = "int")
    })
    @GetMapping()
    public GenericResponse list(
            @RequestParam(name = "page",defaultValue = "1") int page,
            @RequestParam(name = "size",defaultValue = "10") int size){
        Pageable pageable = new PageRequest(page-1,size);
        Page<User> pageList = userRepository.findAll(pageable);
        return  ResponseFormat.retParam(200,pageList);
    }


    @ApiOperation(value = "篩選獲取用戶信息列表", notes = "篩選獲取用戶信息列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "key", value = "關鍵字", required = true,dataType = "String"),
            @ApiImplicitParam(name = "startDate", value = "開始時間", required = true,dataType = "Date"),
            @ApiImplicitParam(name = "endDate", value = "結束時間", required = true,dataType = "Date"),
            @ApiImplicitParam(name = "page", value = "頁碼", required = true,dataType = "int"),
            @ApiImplicitParam(name = "size", value = "單頁條數", required = true,dataType = "int")
    })
    @GetMapping(value = "/pageList")
    public GenericResponse pageList(
            @RequestParam(name = "key") String key,
            @RequestParam(name = "startDate") Date startDate,
            @RequestParam(name = "endDate") Date endDate,
            @RequestParam(name = "page",defaultValue = "1") int page,
            @RequestParam(name = "size",defaultValue = "10") int size){
        Pageable pageable = new PageRequest(page-1,size);
        Page<User> pageList = userRepository.pageList(key,startDate,endDate,pageable);
        return  ResponseFormat.retParam(200,pageList);
    }




}
View Code

  6.2 Repository接口

package com.sxd.sweeping.repository;

import com.sxd.sweeping.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;


import java.sql.Date;


public interface UserRepository extends JpaRepository<User,Long> {

    User findUserById(Long id);

    @Query(value = "select u from User u " +
            "where :keyword is null or u.realname like %:keyword% " +
            "and (u.updateAt between :startDate and :endDate)")
    Page<User> pageList(
            @Param("keyword") String keyword,
            @Param("startDate") Date startDate,
            @Param("endDate") Date endDate,
            Pageable pageable);
}
View Code

 

 

7.對於異常處理,異常日誌的記錄,因此還須要配置logback日誌配置

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <contextName>logback</contextName>
    <!--定義日誌文件的存儲地址 勿在 LogBack 的配置中使用相對路徑-->
    <property name="log.path" value="/Users/sxd/IdeaProjects/A/sweeping.log" />

    <!--輸出到控制檯-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>
            <!--<pattern>%d %p (%file:%line\)- %m%n</pattern>-->
            <!--格式化輸出:%d:表示日期    %thread:表示線程名     %-5level:級別從左顯示5個字符寬度  %msg:日誌消息    %n:是換行符-->
            <pattern>%black(控制檯-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger) - %cyan(%msg%n)</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--輸出到文件-->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logback.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <!--格式化輸出:%d:表示日期    %thread:表示線程名     %-5level:級別從左顯示5個字符寬度  %msg:日誌消息    %n:是換行符-->
            <pattern>文件記錄-%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <root level="info">
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>

</configuration>
View Code

8.application.properties文件

spring.datasource.url = jdbc:postgresql://127.0.0.1:54320/ctgs
spring.datasource.username = homestead
spring.datasource.password = secret
spring.datasource.driver-class-name = org.postgresql.Driver


spring.jpa.database=postgresql
spring.jpa.show-sql=true

debug=true
View Code

9.build.gradle依賴

buildscript {
    ext {
        springBootVersion = '2.0.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.sxd'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
    maven { url 'https://repo.spring.io/plugins-release' }
    maven { url 'https://jitpack.io' }
    mavenCentral()
}


dependencies {
    compile('org.springframework.boot:spring-boot-starter-activemq')
    compile('org.springframework.boot:spring-boot-starter-amqp')
    compile('org.springframework.boot:spring-boot-starter-aop')
    compile('org.springframework.boot:spring-boot-starter-cache')
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-data-mongodb')
    compile('org.springframework.boot:spring-boot-starter-data-redis')
    compile('org.springframework.boot:spring-boot-starter-data-solr')
    compile('org.springframework.boot:spring-boot-starter-freemarker')
    compile('org.springframework.boot:spring-boot-starter-jdbc')
    compile('org.springframework.boot:spring-boot-starter-validation')
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
    runtime('com.microsoft.sqlserver:mssql-jdbc')
    runtime('mysql:mysql-connector-java')
    runtime('org.postgresql:postgresql')
    compileOnly('org.projectlombok:lombok')
    testCompile('org.springframework.boot:spring-boot-starter-test')

    // https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui
    compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.8.0'
    // https://mvnrepository.com/artifact/io.springfox/springfox-swagger2
    compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.8.0'
    // https://mvnrepository.com/artifact/com.alibaba/fastjson
    compile group: 'com.alibaba', name: 'fastjson', version: '1.2.47'






}
View Code

 

最後 啓動項目,訪問地址:http://localhost:8080/swagger-ui.html#/

 

請求操做

 

正常狀況下請求:

錯誤狀況下:

 

查看日誌文件:

相關文章
相關標籤/搜索