Spring-boot integrates swagger and MapStruct for simple use

1) Add dependencies. When I use the 3.0.0 version, the swagger-ui page 404 problem will occur, so I changed it to 2.9.2. Using the default version swagger-model will cause an empty judgment exception.

<!--        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 injection configuration

         Inject as many Dockets as you want, use the configuration file for enable, and decide whether to enable it according to the operating environment. Generally, swagger should not be enabled in the production environment.

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) Common annotations

4) The project structure is perfect

        The database po object should be separated from the vo object, and the swagger configuration should be marked on the vo object instead of being mixed with the po object.

po object, used for database operations

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 object, used to pass parameters when saving

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;
}

        Because the parameters will be separated from the po object, it will involve a large number of vo to po conversions. Here you can use mapstruct to simplify the conversion process.

<!--        对象转换,编译期间存在-->
        <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>

        When converting between vo and po, ​​we sometimes convert one type to another type or the field names are inconsistent. At this time, we can use the Mapping annotation of MapStrcut.

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

The qualifiedBy attribute specifies the method used for type conversion, which has a Date2Millis annotation. Annotations and conversion methods are defined below. It is stipulated that annotations must be annotated with @Qualifier annotation. @Retention(RetentionPolicy.CLASS) means that the annotation only works during compilation. @Target(ElementType.METHOD) indicates that the annotation should be marked on the 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);
    }
}

        The way to use it, you can't use generics. @Mapper(uses = {MapStructFormatter.class}) represents in which class the conversion method should be looked for. qualifiedBy = MapStructFormatter.Date2Millis.class) indicates that the method marked with the Date2Millis annotation should be used for type conversion.

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);
}

         At the same time, we can extract an abstract class of BaseController to implement some basic interfaces.

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);
        }
    }
}

 Directory Structure

Guess you like

Origin blog.csdn.net/qq_33235279/article/details/130339338