Spring-boot集成swagger以及MapStruct简单使用

1)添加依赖,我使用3.0.0版本时会出现swagger-ui页面404的问题,所以改成2.9.2,使用默认版本swagger-model会出现判空异常。

<!--        swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <exclusions>
                <exclusion>
                    <groupId>io.swagger</groupId>
                    <artifactId>swagger-models</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

2)swagger注入配置

         要分多少类别就注入多少个Docket,enable使用配置文件,根据运行环境来决定是否启用,一般生产环境不要开启swagger。

package com.example.jiakao.common.config;

import com.example.jiakao.common.prop.ProjProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;

@Configuration
@EnableSwagger2
public class SwaggerCfg {
    private static final String VERSION = "1.0.0";
    @Autowired
    private ProjProperties properties;
    @Bean
    public Docket docket(){
        return basicDocket("all")
                .apiInfo(apiInfo("接口文档","详细接口文档"))
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
                .build();
    }
    @Bean
    public Docket dictDocket(){
        return basicDocket("dict","/(dict.*)")
                .apiInfo(apiInfo("dict接口文档","dict详细接口文档"));
    }

    private ApiInfo apiInfo(String title, String description){
        ApiInfoBuilder builder = new ApiInfoBuilder();
        builder.title(title);
        builder.description(description);
        builder.version(VERSION);
        return builder.build();
    }
    private Docket basicDocket(String name){
        Parameter token = new ParameterBuilder()
                .name("Token")
                .description("用户登录令牌")
                .parameterType("header")
                .modelRef(new ModelRef("String"))
                .build();
        return new Docket(DocumentationType.SWAGGER_2)
                .ignoredParameterTypes(HttpSession.class, HttpServletRequest.class, HttpServletResponse.class)
                .groupName(name)
                .enable(properties.getSwagger());
//                .globalOperationParameters(List.of(token));
    }
    private Docket basicDocket(String name, String regex){
        return basicDocket(name)
                .select()
                .paths(PathSelectors.regex(regex))
                .build();
    }
}

3)常用注解

4)项目结构完善

        数据库po对象应该与vo对象分离开,对于swagger的配置应该标注在vo对象上,而不应该与po对象混在一起。

po对象,用于数据库操作

package com.example.jiakao.pojo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import javax.persistence.*;

@Entity
@Data
@TableName("plate_region")
@Table(name="plate_region")
public class PlateRegionPo {
    @Id
    @TableId(type = IdType.AUTO)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column( columnDefinition = "int4" )
    private Integer id;
    @Column( columnDefinition = "varchar(64)" )
    private String name;
    @Column( columnDefinition = "varchar(64)" )
    private String plate;
    @Column( columnDefinition = "int4 default 0 " )
    private Integer parentId;
}

 vo对象,用于保存时传参

package com.example.jiakao.pojo.vo.req.save;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("保存一个省份或者城市信息的参数")
public class PlateRegionReqVo {
    @ApiModelProperty(value = "省份或者城市的id")
    private Integer id;
    @ApiModelProperty(value = "省份或者城市的名称", required = true)
    private String name;
    @ApiModelProperty(value = "省份或者城市的代号", required = true)
    private String plate;
    @ApiModelProperty(value = "城市所属省份的id,省份为0,默认值为0", required = true)
    private Integer parentId = 0;
}

        因为将将参数与po对象分开了,所以会射涉及大量vo转po,这里可以使用mapstruct来简化转化过程。

<!--        对象转换,编译期间存在-->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.5.3.Final</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.5.3.Final</version>
            <scope>provided</scope>
        </dependency>

        在做vo和po之间相互转换时,我们有时候会有将一个类型转为其他类型或者字段名不一致的情况,这时候我们可以使用MapStrcut的Mapping注解。

@Mapping(source = "createTime",target="createTime",qualifiedBy = MapStructFormatter.Date2Millis.class)

qualifiedBy属性指定类型转换使用的方法,该方法拥有一个Date2Millis注解。注解和转换方法定义如下。规定注解必须要使用@Qualifier注解标注。@Retention(RetentionPolicy.CLASS)代表该注解只在编译期间起作用。@Target(ElementType.METHOD)代表该注解应标注在方法上。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Date;

public class MapStructFormatter {
    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.CLASS)
    public @interface Date2Millis {
    }
    @Date2Millis
    public static Long date2millis(Date date){
        if(date == null) return null;
        return date.getTime();
    }
    @Qualifier
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.CLASS)
    public @interface Millis2Date {
    }
    @Millis2Date
    public static Date millis2date(Long timeStamp){
        if(timeStamp == null) return null;
        return new Date(timeStamp);
    }
}

        使用方式,用不了泛型。@Mapper(uses = {MapStructFormatter.class})代表应在哪个类中寻找转换方法。qualifiedBy = MapStructFormatter.Date2Millis.class)代表应该使用被Date2Millis注解标注的方法进行类型转换。

package com.example.jiakao.common.mapStruct;

import com.example.jiakao.pojo.entity.*;
import com.example.jiakao.pojo.vo.list.UserVo;
import com.example.jiakao.pojo.vo.req.save.*;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper(uses = {
       MapStructFormatter.class
})
public interface MapStructs {
    // 接口中的属性只能是public static,可以省略
    MapStructs INSTANCE = Mappers.getMapper(MapStructs.class);

    @Mapping(source = "createTime",target="createTime",qualifiedBy = MapStructFormatter.Date2Millis.class)
    @Mapping(source = "updateTime",target="updateTime",qualifiedBy = MapStructFormatter.Date2Millis.class)
    UserVo po2vo(UsersPo po);

    ExamPlacePo reqVo2po(ExamPlaceReqVo vo);
    PlateRegionPo reqVo2po(PlateRegionReqVo vo);
    ExamCoursePo reqVo2po(ExamCourseReqVo po);
    UsersPo reqVo2po(UsersReqVo po);
    RolesPo reqVo2po(RolesReqVo po);
    ResourcePo reqVo2po(ResourceReqVo po);
}

         同时我们可以抽离一个BaseController的抽象类,实现一些基础接口。

package com.example.jiakao.controller;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.jiakao.common.constant.ResultCode;
import com.example.jiakao.exception.http.ArgumentsException;
import com.example.jiakao.common.util.Vos;
import com.example.jiakao.pojo.vo.json.JsonVo;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Arrays;

/**
 *
 * @param <Po> 数据库entity类
 * @param <ReqVo> pojo.vo.req.save中的类,用于插入数据库的请求参数,非entity
 */
public abstract class BaseController<Po, ReqVo> {
    protected abstract IService<Po> getService();
    protected abstract Po reqVo2Po(ReqVo reqVo);
    @ApiOperation("删除一条数据或多条数据")
    @PostMapping("/remove")
    public JsonVo remove(
            @ApiParam(value = "一个或多个id,以逗号分割",required = true)
            @RequestParam String id){
        String[] ids = id.split(",");
        if(getService().removeByIds(Arrays.asList(ids))){
            return Vos.ok();
        } else{
            throw new ArgumentsException(ResultCode.ARGUMENTS_ERROR);
        }
    }
    @ApiOperation("保存一条数据")
    @PostMapping("/save")
    public JsonVo save(@RequestBody ReqVo vo) {
        Po entity = reqVo2Po(vo);
        if(getService().saveOrUpdate(entity)){
            return Vos.ok();
        } else{
            throw new ArgumentsException(ResultCode.ARGUMENTS_ERROR);
        }
    }
}

 目录结构

猜你喜欢

转载自blog.csdn.net/qq_33235279/article/details/130339338