1 package cn.home1.oss.lib.security.swagger;
2
3 import static com.google.common.collect.Sets.newHashSet;
4 import static springfox.documentation.schema.ResolvedTypes.modelRefFactory;
5
6 import cn.home1.oss.lib.errorhandle.api.ResolvedError;
7 import cn.home1.oss.lib.swagger.ManualRequestHandler;
8 import cn.home1.oss.lib.swagger.model.ApiOperationInfo;
9
10 import com.fasterxml.classmate.TypeResolver;
11
12 import lombok.extern.slf4j.Slf4j;
13
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.http.HttpStatus;
16
17 import springfox.documentation.RequestHandler;
18 import springfox.documentation.builders.OperationBuilder;
19 import springfox.documentation.builders.ResponseMessageBuilder;
20 import springfox.documentation.schema.ModelReference;
21 import springfox.documentation.schema.TypeNameExtractor;
22 import springfox.documentation.service.ResponseMessage;
23 import springfox.documentation.spi.DocumentationType;
24 import springfox.documentation.spi.schema.contexts.ModelContext;
25 import springfox.documentation.spi.service.OperationBuilderPlugin;
26 import springfox.documentation.spi.service.contexts.OperationContext;
27 import springfox.documentation.spi.service.contexts.RequestMappingContext;
28
29 import java.lang.reflect.Field;
30 import java.util.Set;
31
32
33
34
35 @Slf4j
36 abstract public class AbstractAfterOperationBuilderBuildPlugin implements OperationBuilderPlugin {
37
38 private static final String MANUAL_REQUEST_HANDLER = ManualRequestHandler.class.getSimpleName();
39
40 @Autowired
41 private TypeNameExtractor nameExtractor;
42
43 @Autowired
44 protected TypeResolver typeResolver;
45
46 @Override
47 public void apply(final OperationContext context) {
48 try {
49
50 if (MANUAL_REQUEST_HANDLER.equals(context.getName())) {
51
52
53 Field privateStringField = OperationContext.class.getDeclaredField("requestContext");
54 privateStringField.setAccessible(true);
55 final RequestMappingContext requestMappingContext =
56 (RequestMappingContext) privateStringField.get(context);
57
58
59 privateStringField = RequestMappingContext.class.getDeclaredField("handler");
60 privateStringField.setAccessible(true);
61 final RequestHandler requestHandler = (RequestHandler) privateStringField.get(requestMappingContext);
62
63 if (requestHandler instanceof ManualRequestHandler) {
64 this.processRequestHandler(context, (ManualRequestHandler) requestHandler);
65 }
66 }
67
68
69 processResponseModel(context);
70 } catch (final ReflectiveOperationException ex) {
71 log.error("swagger plugin error.", ex);
72 }
73 }
74
75 private void processRequestHandler(final OperationContext context, final ManualRequestHandler manualRequestHandler) {
76 final ApiOperationInfo apiOperationInfo = manualRequestHandler.getApiOperationInfo();
77
78 if (apiOperationInfo != null) {
79
80 context.operationBuilder().notes(apiOperationInfo.getNotes());
81
82 if (apiOperationInfo.getApiRequest().getParameters() != null) {
83 context.operationBuilder().parameters(apiOperationInfo.getApiRequest().getParameters());
84 }
85 }
86 }
87
88
89
90
91 private void processResponseModel(final OperationContext context) {
92 try {
93 final OperationBuilder operationBuilder = context.operationBuilder();
94 final Field privateStringField = OperationBuilder.class.getDeclaredField("responseMessages");
95 privateStringField.setAccessible(true);
96 final Set<ResponseMessage> responseMessages = (Set<ResponseMessage>) privateStringField.get(operationBuilder);
97
98 final ModelContext modelContext = this.modelContext(context);
99 final ModelReference responseModel = modelRefFactory(modelContext, this.nameExtractor)
100 .apply(context.alternateFor(this.typeResolver.resolve(ResolvedError.class)));
101
102 final Set<ResponseMessage> responseMessagesProcessed = newHashSet();
103 responseMessages.forEach(responseMessage -> {
104 if (!isSuccessful(responseMessage.getCode())) {
105 responseMessagesProcessed.add(new ResponseMessageBuilder()
106 .code(responseMessage.getCode())
107 .message(responseMessage.getMessage())
108 .responseModel(responseModel)
109 .build());
110 }
111 });
112 if (!responseMessagesProcessed.isEmpty()) {
113 context.operationBuilder().responseMessages(responseMessagesProcessed);
114 }
115 } catch (final NoSuchFieldException | IllegalAccessException ex) {
116 log.info("error processResponseModel.", ex);
117 }
118 }
119
120 abstract protected ModelContext modelContext(OperationContext context);
121
122
123
124
125 private static boolean isSuccessful(final int code) {
126 boolean result;
127 try {
128 result = HttpStatus.Series.SUCCESSFUL.equals(HttpStatus.Series.valueOf(code));
129 } catch (final Exception ignored) {
130 log.info("error check httpStatus {}.", code, ignored);
131 result = false;
132 }
133 return result;
134 }
135
136 @Override
137 public boolean supports(final DocumentationType delimiter) {
138 return DocumentationType.SWAGGER_2.equals(delimiter);
139 }
140 }