zoukankan      html  css  js  c++  java
  • 【swagger】2.swagger提供开发者文档--返回统一格式篇【spring mvc】【spring boot】

    接着上一篇来说,

    不管正常返回结果还是后台出现异常,应该返回给前台统一的响应格式。

    所以这一篇就为了应对解决这个问题。

    ========================================================================

    1.首先,定义一个统一返回类【所有返回的格式都是这个类的格式】

    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,用于填充上面的统一格式】

    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异常】

    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,具体使用说明查看代码【对异常进行统一拦截,然后配置返回格式】

    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类

    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.

      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#/

    请求操作

    正常情况下请求:

    错误情况下:

     

    查看日志文件:

  • 相关阅读:
    UUID含义及ubuntu配置系统默认JDK
    MYSQL 问题小总结
    纯CSS3实现常见多种相册效果
    Docker Api 实测
    Dijkstra with priority queue 分类: ACM TYPE 2015-07-23 20:12 4人阅读 评论(0) 收藏
    hash值的计算与转换 分类: ACM TYPE 2015-05-07 17:49 36人阅读 评论(0) 收藏
    NYOJ
    进制转换函数 2015-02-15 09:41 32人阅读 评论(0) 收藏
    操作系统图解 2015-02-03 23:44 71人阅读 评论(0) 收藏
    [kuangbin带你飞]专题一 简单搜索
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/8797318.html
Copyright © 2011-2022 走看看